5

Have been trying to convert ImageOutputStream to byte[] for a while using JAI. Any inputs are appreciated. Thanks.

Sorry here is the code snippet, I am working on. I had to post it earlier. The problem I am facing is that, I am able to get ByteArrayOutputStream from ImageOutputStream. But it always gives me zero bytes. But if I use a FileOutputStream instead of a ByteArrayOuputStream, I can write into a file which has non zero bytes. :

File file = new File("C:/TIFFImages/tiff-image.tiff");
FileInputStream in = new FileInputStream(file);
long filelength = file.length();
byte[] bytes = new byte[(int)filelength]; 
int offset = 0; 
int numRead = 0; 

while (offset < bytes.length && (numRead=in.read(bytes, offset, bytes.length-offset)) >= 0) { 
    offset += numRead; 
} 
if (offset < bytes.length) { 
    throw new IOException("Could not completely read file "+file.getName()); 
} 

ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

RenderedImage src = JAI.create("stream", SeekableStream.wrapInputStream(bais, true));
RenderedOp renderedOp = MedianFilterDescriptor.create(src, MedianFilterDescriptor.MEDIAN_MASK_SQUARE , 1, null);
BufferedImage image = renderedOp.getAsBufferedImage();

ByteArrayOutputStream baos = new ByteArrayOutputStream();

ImageOutputStream  ios =  ImageIO.createImageOutputStream(baos);
//Instead of baos if I pass a FileOutputStream to the above function. It writes non zero
//bytes to the output file

TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
ImageWriter writer = tiffspi.createWriterInstance();
RenderedImage renderedImage = PlanarImage.wrapRenderedImage(src);
writer.setOutput(ios);
writer.write(image);
writer.write(null,new IIOImage(image, null, null), param);

System.out.println("After tiff ImageIO operations" + baos.toByteArray().length);

Thanks , Vinay

Vineet Reynolds
  • 76,006
  • 17
  • 150
  • 174
vinaynag
  • 271
  • 1
  • 2
  • 10

4 Answers4

6

I got the answer for this, which is very close to what Guillaume suggested. Except that no need to write to a temp file in between. The following is the modified code to convert ImageOutputStream to byte[] :

ByteArrayOutputStream baos = new ByteArrayOutputStream(37628);
ImageOutputStream  ios =  ImageIO.createImageOutputStream(baos);

//Instead of baos if I pass a FileOutputStream to the above function. It writes non zero
//bytes to the output file

TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
ImageWriter writer = tiffspi.createWriterInstance();
RenderedImage renderedImage = PlanarImage.wrapRenderedImage(src);
writer.setOutput(ios);
writer.write(image);
writer.write(null,new IIOImage(image, null, null), param);

//Create a ByteArrayInputStream to read that ByteArrayOutputStream and read it from ImageIO

ByteArrayInputStream bai = new ByteArrayInputStream(baos.toByteArray());
RenderedImage out = ImageIO.read(bai);
int size = bos.toByteArray().length;

System.out.println(""+ size);

return bos.toByteArray
Fulvio
  • 1,615
  • 1
  • 16
  • 18
vinaynag
  • 271
  • 1
  • 2
  • 10
6

I'm pretty sure it's because you're not calling ImageOutputStream.flush() at the end of the operation - if the IOS created is a MemoryCacheOutputStream, it seems to require an explicit flush on some ImageIO implementations.

user229044
  • 232,980
  • 40
  • 330
  • 338
Nick
  • 61
  • 1
  • 1
  • You are my hero right now! - I've been trying to figure out why my underlying ByteArrayOutputStream was always empty. Flushing the ImageOutputStream fixed it all up. Thanks! – Matt MacLean Sep 14 '11 at 14:48
  • I have been struggling for a long time and somehow I reach to your answer. Flushing the ImageOutputStream fixed it. – Chanks Jan 07 '21 at 22:37
3

Create ImageOutputStream with ByteArrayOutputStream (instead of FileOutputStream)

ByteArrayOutputStream bos = new ByteArrayOutputStream(255);
ImageOutputStream ios = ImageIO.createImageOutputStream(bos);
// use "ios" for image processing

After image processing is done, image bytes would be available in the "ios" object, but the offset would be positioned at the end of the "ios" object. So we need to position the offset to the beginning of the "ios" object and then read the bytes to write to new ByteArrayOutputStream object. Finally return the toByteArray() from the new object. Like below:

        public byte[] getBytes(ImageOutputStream ios) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream(255);
            byte imageByte;
            long counter = 0; 
            try {
                    System.out.println("getStreamPosition()[BEFORE]=" + ios.getStreamPosition());
                    ios.seek(0);
                    System.out.println("getStreamPosition()[AFTER]=" + ios.getStreamPosition());
            } catch (IOException e1) {                       
                    e1.printStackTrace();
            }

            while (true) {
                    try {
                            bos.write(ios.readByte());
                            counter++;
                    } catch (EOFException e) {
                            System.out.println("End of Image Stream");
                            break;
                    } catch (IOException e) {
                            System.out.println("Error processing the Image Stream");
                            break;
                    }
            }
            System.out.println("Total bytes read=" + counter);
            byte[] retValue = bos.toByteArray();
            return retValue;
    }
sAn
  • 31
  • 2
0

Well, you won't be able to read from an output stream.

You should rather try to get an InputStream from your image object and read the necessary data from there.

However, if you gave more details about what you are actually trying to achieve we could help you more efficiently. :)

For instance if you are only willing to display the size of the images in bytes, there are several other ways.

The Mighty Rubber Duck
  • 4,388
  • 5
  • 28
  • 27
  • I am not trying to read from an output stream, rather I want the output to be written into the ByteArrayOutputStream. As I mentioned in the code comments. A FileOutputStream gives a non-zero size once written into. But ByteArrayOutputStream gives a zero size. I am trying to compress a TIFF Image and return a byte[] from this code. – vinaynag Aug 18 '10 at 01:06
  • My bad, I read your code too quickly. Did you try to step through your program on execution (ie. with Eclipse) to check the status of your ByteArrayOutputStream? At worst case, you can spit it out in a temp file and read it with a ByteArrayInputStream. Quite dirty though. – The Mighty Rubber Duck Aug 18 '10 at 02:18
  • Yup. As I step through the code in debug mode, the byte array size becomes never more than zero after it is initialized. Though the temp file creation might work, I cannot afford do that in this code. It has to return me a byte array back without any File I/O in between. I have found an alternative way of compressing the Image. However it would have been better if this approach worked. It kind of puzzles me,Thanks. – vinaynag Aug 18 '10 at 04:51