It looks like I have found a solution, maybe it will be useful for someone, so I post it here.
Here's the line of thought which allowed me to get there:
First I remember that PImage.save() saves image to file. If it is in java, then it's most likely uses OutputStream of some kind, so I may be able to "replace" that OutputStream to my in-memory buffer.
So I looked at source ov
PImage.save() and it appears that it the method only does some error checking, but then calls
PImage.saveImageIO() to do all the "heavy-lifting" of taking PImage.pixels[] array and actually compressing it and saving it to stream.
So the natural solution was to subclass PImage and create modified version of saveImageIO() which instead of writing to file-related stream, writes to my in-memory buffer.
the method which is saving current contents of the PImage2 to outputstream is called
/** @param extension corresponding to desired compression format ie "jpg" "png" */
public
boolean
saveImageToStream
(
String
extension,
BufferedOutputStream
outStream
)
But this method will write to the output stream and I need as the result InputStream. So I wrote a wrapper, which re-wraps the memory-buffer as ByteArrayInputStream:
/**
* Returns input stream with the byte-sequence of the saved image.
*/
public ByteArrayInputStream getImageAsInputStream(String formatExtension)
But then I encountered a problem: what I am saving is actually contents of PImage2. And Processing doesn't know anything about this class and only knows about PImage. The typical usage scenario would be to use it in running sketch to save the contents of the screen. And screen is as PGraphics (PImage).
Thus I had to add a "crutch" to my class in form of method
-
public
ByteArrayInputStream getPImageAsInputStream
(PImage img,
String formatExtension
)
{
-
resize
(img.
width, img.
height
)
;
-
copy
(img,
0,
0, img.
width, img.
height,
0,
0, img.
width, img.
height
)
;
-
return getImageAsInputStream
(formatExtension
)
;
-
}
which basically takes as a parameter PImage, copies it inside itself and then already converts it to InputStream.
So if you want to use it in your sketch do 2 steps:
2) use the following code skeleton to get screen contents as PNG-compressed input stream:
- PImage2 img2;
- void setup(){
- size(800,600);
- img2 = new PImage2(100,100); // doesn't matter the size, it will be resized.
- }
- void keyPressed(){
-
- // We use processing built-in variable g which references to
- // the PGraphics (extending PImage) containing all what's on screen.
- InputStream is = img2.getPImageAsInputStream(g, "png");
- try {
- println("Available in input stream: " + is.available() );
- }
- catch(IOException ioex){
- println("Error couldn't perform check: " + ioex.getMessage());
- }
-
-
- // and this is just a debug method which directly writes contents
- // of the InputStream into file, so that we can make InputStream contains valid data.
- img2.putPImageAsInputStreamToFile("d:\\image.png", g, "png");
-
- }
- void draw(){
- fill(255);
- ellipse(mouseX, mouseY, 40, 40);
- }