Skip to main content

Read Tiff, Write Tiff... why are the files different sizes?

22 replies [Last post]
chickiboo
Offline
Joined: 2006-06-07
Points: 0

I am working on some code to read one or more single-page tiff images and write them out to a multipage tiff file. The files may have different compression types, some will be JPEG in TIFF and some will be G4 FAX.

I am reading the metadata and using that to write out the image to the new file. So I would have liked to think that if I read only one image and write it back out again, the files would be identical. That unfortunately is not true if the image is using the JPEG in TIFF compression, but is true for an image with G4 FAX compression.

I believe the issue for those files is related to a previous question about converting JPEG images to TIFF, where I was seeing a 3-4x size file because I was not explicitly setting the compression quality. tiffWriteParam.setCompressionQuality(Float.parseFloat("0.75")); However, in order to set the compression quality, I must set the compression mode to explicit, which means that I would have to read and write all the compression information myself.

If anyone can offer a generic way to capture and set this information from the metadata I would be extremely grateful.

My code follows, as a side note, I have commented out the line to read the first image's stream metadata and use that as the multi-page tiffs stream metadata... It seemed a little arbitrary to me to do that, since that first image really has little to do with the new multipage image. Should default values here be sufficient? I did not notice a difference with that line in or out, but I really have only a vague idea what to look for.

public static void mergeTIFFs(List singleTiffs, File newMultiPageTIFF) throws IOException {

//Get iterator for input images
Iterator iterator = singleTiffs.iterator();

//Get tif writer and set output to file
Iterator writers = ImageIO.getImageWritersByFormatName("tif");
ImageWriter writer = (ImageWriter)writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(newMultiPageTIFF);
writer.setOutput(ios);

//Write each image out to the new file
boolean firstImage = true;
while (iterator.hasNext()) {

File imageFile = (File) iterator.next();
ImageInputStream iis = ImageIO.createImageInputStream(imageFile);

//Get a reader for the stream
Iterator readers = ImageIO.getImageReaders(iis);
ImageReader reader = (ImageReader)readers.next();
reader.setInput(iis);

//Read the stream metadata
//IIOMetadata streamMetadata = reader.getStreamMetadata();

//Read the image metadata - we are assuming there is only one image in the tiff
IIOMetadata imageMetadata = reader.getImageMetadata(0);

//Set up the writeParam
TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam(Locale.US);
tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_COPY_FROM_METADATA);

BufferedImage bi = reader.read(0, null);
IIOImage image = new IIOImage(bi, null, imageMetadata);
if(firstImage==false)
writer.writeInsert(-1,image, tiffWriteParam);
else {
writer.write(null, image, tiffWriteParam);
firstImage = false;
}

//Done writing all images for this image
reader.dispose();
}

//End writing of all files
writer.dispose();
}

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Andrey Kuznetsov

Bob Deen schrieb:

> I wonder if any research has been done on re-compressing images with
> compression artifacts, in order to minimize the carryover of the
first stage
> artifacts. That would be useful for image editing programs, if you,
say,
> adjust the contrast or brightness... you have to rewrite the compressed
> stream in that case, but at a significant quality loss.

But why re-compress?!
The advantage of JPEG is that you can rotate, crop,
adjust contrast, brightness, color, etc. in DCT domain
and save it back without quality loss.

-Andrey

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

robert engels

I think a common problem is you want to add a watermark (or labeling,
etc.) to the image. I don't think JPEG supports annotations, so you
need to manipulate the pixels.

At this point when you recompress you will get quality loss.

On Nov 7, 2007, at 5:39 PM, Andrey Kuznetsov wrote:

> Bob Deen schrieb:
>
> > I wonder if any research has been done on re-compressing images with
> > compression artifacts, in order to minimize the carryover of the
> first stage
> > artifacts. That would be useful for image editing programs, if
> you, say,
> > adjust the contrast or brightness... you have to rewrite the
> compressed
> > stream in that case, but at a significant quality loss.
>
> But why re-compress?!
> The advantage of JPEG is that you can rotate, crop,
> adjust contrast, brightness, color, etc. in DCT domain
> and save it back without quality loss.
>
> -Andrey
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

Andrey Kuznetsov

robert engels schrieb:
> I think a common problem is you want to add a watermark (or labeling,
> etc.) to the image. I don't think JPEG supports annotations, so you
> need to manipulate the pixels.
>
> At this point when you recompress you will get quality loss.
>
Only one step in JPEG compression causes quality loss - quantization.
So, if you don't reapply quantization you don't lose quality.

Usual way is:
compress:
source image data -> FDCT -> quantizer -> entropy coder -> compressed
image data
decompress:
compressed image data -> entropy decoder -> dequantizer ->IDCT -
reconstructed image data

However to manipulate image you don't need to go all way back:
compressed image data -> entropy decoder -> DCT image -> add watermark
-> entropy coder -> compressed image data

-Andrey

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

robert engels

True, but when then the entropy coder will be no where near as
efficient, so the file size will become much larger.

On Nov 7, 2007, at 6:21 PM, Andrey Kuznetsov wrote:

> robert engels schrieb:
>> I think a common problem is you want to add a watermark (or
>> labeling, etc.) to the image. I don't think JPEG supports
>> annotations, so you need to manipulate the pixels.
>>
>> At this point when you recompress you will get quality loss.
>>
> Only one step in JPEG compression causes quality loss - quantization.
> So, if you don't reapply quantization you don't lose quality.
>
> Usual way is:
> compress:
> source image data -> FDCT -> quantizer -> entropy coder ->
> compressed image data
> decompress:
> compressed image data -> entropy decoder -> dequantizer ->IDCT -
> reconstructed image data
>
> However to manipulate image you don't need to go all way back:
> compressed image data -> entropy decoder -> DCT image -> add
> watermark -> entropy coder -> compressed image data
>
> -Andrey
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

Bob Deen

> If you use similar JPEG compression ratio's I think you might end up
> getting similar (although not exact) images. Because the source image
> is already compression, it has already reduced the frequencies in the
> image, so when the image is compressed again, the image is already at
> that frequency level.

I don't think that works. While the useful high frequencies are gone, I
don't
think the result is devoid of high frequencies... they still exist, as
compression
artifacts. The second compressor doesn't know it should ignore those bogus
high frequencies and attempts to preserve them as much as it can... so you
have the second stage working hard to preserve the first-stage
artifacts. ;-)

Perhaps a low-pass filter might help... but the best bet by far is to
maintain
the original compressed stream.

I wonder if any research has been done on re-compressing images with
compression artifacts, in order to minimize the carryover of the first stage
artifacts. That would be useful for image editing programs, if you, say,
adjust the contrast or brightness... you have to rewrite the compressed
stream in that case, but at a significant quality loss.

-Bob

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

robert engels

as my later email shows, this does in fact work with JPEG2000, since
it compresses to a bit rate, and if the source is already at that bit
rate, it doesn't need to do anything...

On Nov 7, 2007, at 4:52 PM, Bob Deen wrote:

>> If you use similar JPEG compression ratio's I think you might end
>> up getting similar (although not exact) images. Because the
>> source image is already compression, it has already reduced the
>> frequencies in the image, so when the image is compressed again,
>> the image is already at that frequency level.
>
> I don't think that works. While the useful high frequencies are
> gone, I don't
> think the result is devoid of high frequencies... they still exist,
> as compression
> artifacts. The second compressor doesn't know it should ignore
> those bogus
> high frequencies and attempts to preserve them as much as it can...
> so you
> have the second stage working hard to preserve the first-stage
> artifacts. ;-)
>
> Perhaps a low-pass filter might help... but the best bet by far is
> to maintain
> the original compressed stream.
>
> I wonder if any research has been done on re-compressing images with
> compression artifacts, in order to minimize the carryover of the
> first stage
> artifacts. That would be useful for image editing programs, if
> you, say,
> adjust the contrast or brightness... you have to rewrite the
> compressed
> stream in that case, but at a significant quality loss.
>
> -Bob
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

robert engels

Although,

If you use similar JPEG compression ratio's I think you might end up
getting similar (although not exact) images. Because the source
image is already compression, it has already reduced the frequencies
in the image, so when the image is compressed again, the image is
already at that frequency level.

On Nov 7, 2007, at 9:54 AM, jai-imageio@javadesktop.org wrote:

>> It is my understanding:
>>
>> if you open a JPEG file, AND either
>>
>> 1. write it as a TIFF (using JPEG in TIFF
>> compression, with
>> compression turned on), you are going to get a TIFF
>> that looks much
>> worse than the original JPEG
>> 2. write it as a TIFF with compression turned off,
>> you are going to
>> get a file that is much larger than the original
>> JPEG.
>>
>>
> In this case the original file is a TIFF though... Can I somehow
> insert that "as is" into a new mulipage TIFF without having to deal
> with making any changes to the way it was originally compressed in
> the single page TIFF?
>
> -Mary
> [Message sent by forum member 'chickiboo' (chickiboo)]
>
> http://forums.java.net/jive/thread.jspa?messageID=244306
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

robert engels

Sadly, this is not true....

I used the following test program:

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import junit.framework.TestCase;

public class TestWriteImage extends TestCase {
public static void main(String[] args) throws Exception {
BufferedImage img = ImageIO.read(new File("painting.jpg"));
for(int i=0;i<20;i++) {
ImageIO.write(img,"jpeg",new File("painting0.jpg"));
img = ImageIO.read(new File("painting.jpg"));
}
}
}

The resulting 'painting0.jpg' image is all black...

BUT, if you use JPEG2000, you can set the "bit rate", so that
repeated compressions result in the same size/quality file...

Using the following code:

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.*;
import javax.imageio.stream.ImageOutputStream;

import com.sun.media.imageio.plugins.jpeg2000.J2KImageWriteParam;

import junit.framework.TestCase;

public class TestWriteImage extends TestCase {
public static void main(String[] args) throws Exception {
BufferedImage img = ImageIO.read(new File("painting.jpg"));
File f0 = new File("painting0.jpg");
for(int i=0;i<20;i++) {
System.out.println("invocation "+i);
J2KImageWriteParam p = new J2KImageWriteParam();
p.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
p.setEncodingRate(.5);
f0.delete();
ImageWriter w = ImageIO.getImageWritersByFormatName
("jpeg2000").next();
ImageOutputStream ios =ImageIO.createImageOutputStream(f0);
w.setOutput(ios);
w.write(null,new IIOImage(img,null,null),p);
w.dispose();
ios.close();
img = ImageIO.read(f0);
}
}
}

At some point the
On Nov 7, 2007, at 9:57 AM, robert engels wrote:

> Although,
>
> If you use similar JPEG compression ratio's I think you might end
> up getting similar (although not exact) images. Because the source
> image is already compression, it has already reduced the
> frequencies in the image, so when the image is compressed again,
> the image is already at that frequency level.
>
> On Nov 7, 2007, at 9:54 AM, jai-imageio@javadesktop.org wrote:
>
>>> It is my understanding:
>>>
>>> if you open a JPEG file, AND either
>>>
>>> 1. write it as a TIFF (using JPEG in TIFF
>>> compression, with
>>> compression turned on), you are going to get a TIFF
>>> that looks much
>>> worse than the original JPEG
>>> 2. write it as a TIFF with compression turned off,
>>> you are going to
>>> get a file that is much larger than the original
>>> JPEG.
>>>
>>>
>> In this case the original file is a TIFF though... Can I somehow
>> insert that "as is" into a new mulipage TIFF without having to
>> deal with making any changes to the way it was originally
>> compressed in the single page TIFF?
>>
>> -Mary
>> [Message sent by forum member 'chickiboo' (chickiboo)]
>>
>> http://forums.java.net/jive/thread.jspa?messageID=244306
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
>> For additional commands, e-mail: interest-help@jai-
>> imageio.dev.java.net
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

Andrey Kuznetsov

Robert,

if I understood you right, your intent was to recompress image 20 times.
However, to achieve it you should read painting0.jpg in the loop, not
painting.jpg.
So, your result image is black due to something else.

HTH

-Andrey

robert engels schrieb:
> Sadly, this is not true....
>
> I used the following test program:
>
> import java.awt.image.BufferedImage;
> import java.io.File;
>
> import javax.imageio.ImageIO;
>
> import junit.framework.TestCase;
>
> public class TestWriteImage extends TestCase {
> public static void main(String[] args) throws Exception {
> BufferedImage img = ImageIO.read(new File("painting.jpg"));
> for(int i=0;i<20;i++) {
> ImageIO.write(img,"jpeg",new File("painting0.jpg"));
> img = ImageIO.read(new File("painting.jpg"));
> }
> }
> }
>
> The resulting 'painting0.jpg' image is all black...

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

robert engels

That was a typo from early post.... sorry. The correct code is below
- and the resulting image is still black.

import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

import junit.framework.TestCase;

public class TestWriteImage extends TestCase {
public static void main(String[] args) throws Exception {
BufferedImage img = ImageIO.read(new File("painting.jpg"));
File f0 = new File("painting0.jpg");
for(int i=0;i<20;i++) {
ImageIO.write(img,"jpeg",f0);
img = ImageIO.read(f0);
}
}
}

On Nov 7, 2007, at 6:01 PM, Andrey Kuznetsov wrote:

> Robert,
>
> if I understood you right, your intent was to recompress image 20
> times.
> However, to achieve it you should read painting0.jpg in the loop,
> not painting.jpg.
> So, your result image is black due to something else.
>
> HTH
>
> -Andrey
>
>
> robert engels schrieb:
>> Sadly, this is not true....
>>
>> I used the following test program:
>>
>> import java.awt.image.BufferedImage;
>> import java.io.File;
>>
>> import javax.imageio.ImageIO;
>>
>> import junit.framework.TestCase;
>>
>> public class TestWriteImage extends TestCase {
>> public static void main(String[] args) throws Exception {
>> BufferedImage img = ImageIO.read(new File("painting.jpg"));
>> for(int i=0;i<20;i++) {
>> ImageIO.write(img,"jpeg",new File("painting0.jpg"));
>> img = ImageIO.read(new File("painting.jpg"));
>> }
>> }
>> }
>>
>> The resulting 'painting0.jpg' image is all black...
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

[att1.html]

chickiboo
Offline
Joined: 2006-06-07
Points: 0

> > This question brings up a good point... I don't
> think
> > it is possible
> > to read an image that uses lossly compression, and
> > rewrite it
> > changing some of the metadata - if you don't set
> the
> > compression, the
> > file will become large, if you set the compression
> > then the image is
> > compressed again (multiplying the error).
>
> Exactly.
>
> > It seems you would need to be able to extract the
> > compressed stream
> > from the original image, and write it out
> verbatim.
> >
> > Any ideas?
>
> There is API for doing this stuff in Java Image I/O
> but nothing implements it at the moment:
>
> http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/
> ImageWriter.html#canReplaceImageMetadata(int)
> http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/
> ImageWriter.html#replaceImageMetadata(int,%20javax.ima
> geio.metadata.IIOMetadata)
>
> If it were implemented say for the TIFF writer what
> would happen is that an ImageOutputStream would be
> opened on an existing TIFF file and then the metadata
> would be replaced. Probably the way the
> implementation would have to work would be to copy
> the old IFD to a new one taking account of the
> updated metadata and then replace the old IFD in the
> linked list of IFDs with the new one. This would in
> effect "orphan" the old IFD and result in a file
> containing unused space.
>
> Once again, I suggest that an ENHANCEMENT request be
> filed in the jai-imageio-core project to track this.
>
> Brian

I thought I was following ... but now I'm a little unsure. It makes sense to me that what I would want to write the image from the original JPEG-in-TIFF image file to the new multipage TIFF verbatim - to eliminate the additional loss of compressing again. The part that confuses me is the need to change the metadata.

The only change to the file is that it is now inside a multipage TIFF. I assume that the writeInsert() method takes care of adding in the information for the next IFD when I add a new page, so what part of the metadata would I need to change or replace?

Is there a way to read and write out that compressed JPEG stream exactly as is?

And thanks so much everyone for your help!
-Mary

robert engels

It is my understanding:

if you open a JPEG file, AND either

1. write it as a TIFF (using JPEG in TIFF compression, with
compression turned on), you are going to get a TIFF that looks much
worse than the original JPEG
2. write it as a TIFF with compression turned off, you are going to
get a file that is much larger than the original JPEG.

On Nov 7, 2007, at 9:30 AM, jai-imageio@javadesktop.org wrote:

>>> This question brings up a good point... I don't
>> think
>>> it is possible
>>> to read an image that uses lossly compression, and
>>> rewrite it
>>> changing some of the metadata - if you don't set
>> the
>>> compression, the
>>> file will become large, if you set the compression
>>> then the image is
>>> compressed again (multiplying the error).
>>
>> Exactly.
>>
>>> It seems you would need to be able to extract the
>>> compressed stream
>>> from the original image, and write it out
>> verbatim.
>>>
>>> Any ideas?
>>
>> There is API for doing this stuff in Java Image I/O
>> but nothing implements it at the moment:
>>
>> http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/
>> ImageWriter.html#canReplaceImageMetadata(int)
>> http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/
>> ImageWriter.html#replaceImageMetadata(int,%20javax.ima
>> geio.metadata.IIOMetadata)
>>
>> If it were implemented say for the TIFF writer what
>> would happen is that an ImageOutputStream would be
>> opened on an existing TIFF file and then the metadata
>> would be replaced. Probably the way the
>> implementation would have to work would be to copy
>> the old IFD to a new one taking account of the
>> updated metadata and then replace the old IFD in the
>> linked list of IFDs with the new one. This would in
>> effect "orphan" the old IFD and result in a file
>> containing unused space.
>>
>> Once again, I suggest that an ENHANCEMENT request be
>> filed in the jai-imageio-core project to track this.
>>
>> Brian
>
> I thought I was following ... but now I'm a little unsure. It
> makes sense to me that what I would want to write the image from
> the original JPEG-in-TIFF image file to the new multipage TIFF
> verbatim - to eliminate the additional loss of compressing again.
> The part that confuses me is the need to change the metadata.
>
> The only change to the file is that it is now inside a multipage
> TIFF. I assume that the writeInsert() method takes care of adding
> in the information for the next IFD when I add a new page, so what
> part of the metadata would I need to change or replace?
>
> Is there a way to read and write out that compressed JPEG stream
> exactly as is?
>
> And thanks so much everyone for your help!
> -Mary
> [Message sent by forum member 'chickiboo' (chickiboo)]
>
> http://forums.java.net/jive/thread.jspa?messageID=244302
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

chickiboo
Offline
Joined: 2006-06-07
Points: 0

> It is my understanding:
>
> if you open a JPEG file, AND either
>
> 1. write it as a TIFF (using JPEG in TIFF
> compression, with
> compression turned on), you are going to get a TIFF
> that looks much
> worse than the original JPEG
> 2. write it as a TIFF with compression turned off,
> you are going to
> get a file that is much larger than the original
> JPEG.
>
>
In this case the original file is a TIFF though... Can I somehow insert that "as is" into a new mulipage TIFF without having to deal with making any changes to the way it was originally compressed in the single page TIFF?

-Mary

robert engels

Not sure, but I don't think so... :( Not without using the API Brian
mentioned, which is not supported...

On Nov 7, 2007, at 9:54 AM, jai-imageio@javadesktop.org wrote:

>> It is my understanding:
>>
>> if you open a JPEG file, AND either
>>
>> 1. write it as a TIFF (using JPEG in TIFF
>> compression, with
>> compression turned on), you are going to get a TIFF
>> that looks much
>> worse than the original JPEG
>> 2. write it as a TIFF with compression turned off,
>> you are going to
>> get a file that is much larger than the original
>> JPEG.
>>
>>
> In this case the original file is a TIFF though... Can I somehow
> insert that "as is" into a new mulipage TIFF without having to deal
> with making any changes to the way it was originally compressed in
> the single page TIFF?
>
> -Mary
> [Message sent by forum member 'chickiboo' (chickiboo)]
>
> http://forums.java.net/jive/thread.jspa?messageID=244306
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

bpb
Offline
Joined: 2004-06-23
Points: 0

> I am reading the metadata and using that to write out
> the image to the new file. So I would have liked to
> think that if I read only one image and write it back
> out again, the files would be identical. That
> unfortunately is not true if the image is using the
> JPEG in TIFF compression, but is true for an image
> with G4 FAX compression.

This is because (as Robert noted) G4 is lossless but JPEG is not.

> I believe the issue for those files is related to a
> previous question about converting JPEG images to
> TIFF, where I was seeing a 3-4x size file because I
> was not explicitly setting the compression quality.
> tiffWriteParam.setCompressionQuality(Float.parseFloat
> "0.75")); However, in order to set the compression
> quality, I must set the compression mode to explicit,
> which means that I would have to read and write all
> the compression information myself.
>
> If anyone can offer a generic way to capture and set
> this information from the metadata I would be
> extremely grateful.

The question would be whether the information is even present in the metadata. The JPEG quality setting is not. That is merely a convenience which used to initialize the various tables used in JPEG compression. The actual quality value is never stored. As for the tables, those could be stored in various places depending on the JPEG-in-TIFF variant.

> My code follows, as a side note, I have commented out
> the line to read the first image's stream metadata
> and use that as the multi-page tiffs stream
> metadata... It seemed a little arbitrary to me to do
> that, since that first image really has little to do
> with the new multipage image. Should default values
> here be sufficient? I did not notice a difference
> with that line in or out, but I really have only a
> vague idea what to look for.

In TIFF the stream metadata only sets the byte order (little or big endian).

> public static void mergeTIFFs(List singleTiffs,
> File newMultiPageTIFF) throws IOException {
>
> //Get iterator for input images
> Iterator iterator = singleTiffs.iterator();
>
> //Get tif writer and set output to file
> Iterator writers =
> ImageIO.getImageWritersByFormatName("tif");
> ImageWriter writer = (ImageWriter)writers.next();
> ImageOutputStream ios =
> ImageIO.createImageOutputStream(newMultiPageTIFF);
> writer.setOutput(ios);
> //Write each image out to the new file
> boolean firstImage = true;
> while (iterator.hasNext()) {
> File imageFile = (File) iterator.next();
> ImageInputStream iis =
> ImageIO.createImageInputStream(imageFile);
>
> //Get a reader for the stream
> Iterator readers = ImageIO.getImageReaders(iis);
> ImageReader reader =
> (ImageReader)readers.next();
> reader.setInput(iis);
> //Read the stream metadata
> //IIOMetadata streamMetadata =
> reader.getStreamMetadata();
>
> //Read the image metadata - we are assuming
> there is only one image in the tiff
> IIOMetadata imageMetadata =
> reader.getImageMetadata(0);
>
> //Set up the writeParam
> TIFFImageWriteParam tiffWriteParam = new
> TIFFImageWriteParam(Locale.US);
>
> iffWriteParam.setCompressionMode(ImageWriteParam.MODE_
> COPY_FROM_METADATA);
>
> BufferedImage bi = reader.read(0, null);
> IIOImage image = new IIOImage(bi, null,
> imageMetadata);
> if(firstImage==false)
> writer.writeInsert(-1,image, tiffWriteParam);
> else {
> writer.write(null, image, tiffWriteParam);
> firstImage = false;
> }
> //Done writing all images for this image
> reader.dispose();
> }
> //End writing of all files
> writer.dispose();
> }

chickiboo
Offline
Joined: 2006-06-07
Points: 0

> > My code follows, as a side note, I have commented
> out
> > the line to read the first image's stream metadata
> > and use that as the multi-page tiffs stream
> > metadata... It seemed a little arbitrary to me to
> do
> > that, since that first image really has little to
> do
> > with the new multipage image. Should default
> values
> > here be sufficient? I did not notice a difference
> > with that line in or out, but I really have only a
> > vague idea what to look for.
>
> In TIFF the stream metadata only sets the byte order
> (little or big endian).
>

Thanks much for that pointer!

robert engels

This question brings up a good point... I don't think it is possible
to read an image that uses lossly compression, and rewrite it
changing some of the metadata - if you don't set the compression, the
file will become large, if you set the compression then the image is
compressed again (multiplying the error).

It seems you would need to be able to extract the compressed stream
from the original image, and write it out verbatim.

Any ideas?

On Nov 6, 2007, at 5:39 PM, jai-imageio@javadesktop.org wrote:

> I am working on some code to read one or more single-page tiff
> images and write them out to a multipage tiff file. The files may
> have different compression types, some will be JPEG in TIFF and
> some will be G4 FAX.
>
> I am reading the metadata and using that to write out the image to
> the new file. So I would have liked to think that if I read only
> one image and write it back out again, the files would be
> identical. That unfortunately is not true if the image is using
> the JPEG in TIFF compression, but is true for an image with G4 FAX
> compression.
>
> I believe the issue for those files is related to a previous
> question about converting JPEG images to TIFF, where I was seeing a
> 3-4x size file because I was not explicitly setting the compression
> quality. tiffWriteParam.setCompressionQuality(Float.parseFloat
> ("0.75")); However, in order to set the compression quality, I
> must set the compression mode to explicit, which means that I would
> have to read and write all the compression information myself.
>
> If anyone can offer a generic way to capture and set this
> information from the metadata I would be extremely grateful.
>
> My code follows, as a side note, I have commented out the line to
> read the first image's stream metadata and use that as the multi-
> page tiffs stream metadata... It seemed a little arbitrary to me to
> do that, since that first image really has little to do with the
> new multipage image. Should default values here be sufficient? I
> did not notice a difference with that line in or out, but I really
> have only a vague idea what to look for.
>
> public static void mergeTIFFs(List singleTiffs, File
> newMultiPageTIFF) throws IOException {
>
> //Get iterator for input images
> Iterator iterator = singleTiffs.iterator();
>
> //Get tif writer and set output to file
> Iterator writers = ImageIO.getImageWritersByFormatName("tif");
> ImageWriter writer = (ImageWriter)writers.next();
> ImageOutputStream ios = ImageIO.createImageOutputStream
> (newMultiPageTIFF);
> writer.setOutput(ios);
>
> //Write each image out to the new file
> boolean firstImage = true;
> while (iterator.hasNext()) {
>
> File imageFile = (File) iterator.next();
> ImageInputStream iis = ImageIO.createImageInputStream
> (imageFile);
>
> //Get a reader for the stream
> Iterator readers = ImageIO.getImageReaders(iis);
> ImageReader reader = (ImageReader)readers.next();
> reader.setInput(iis);
>
> //Read the stream metadata
> //IIOMetadata streamMetadata = reader.getStreamMetadata();
>
> //Read the image metadata - we are assuming there is only one
> image in the tiff
> IIOMetadata imageMetadata = reader.getImageMetadata(0);
>
> //Set up the writeParam
> TIFFImageWriteParam tiffWriteParam = new TIFFImageWriteParam
> (Locale.US);
> tiffWriteParam.setCompressionMode
> (ImageWriteParam.MODE_COPY_FROM_METADATA);
>
> BufferedImage bi = reader.read(0, null);
> IIOImage image = new IIOImage(bi, null, imageMetadata);
> if(firstImage==false)
> writer.writeInsert(-1,image, tiffWriteParam);
> else {
> writer.write(null, image, tiffWriteParam);
> firstImage = false;
> }
>
> //Done writing all images for this image
> reader.dispose();
> }
>
> //End writing of all files
> writer.dispose();
> }
> [Message sent by forum member 'chickiboo' (chickiboo)]
>
> http://forums.java.net/jive/thread.jspa?messageID=244185
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
> For additional commands, e-mail: interest-help@jai-
> imageio.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai-imageio.dev.java.net
For additional commands, e-mail: interest-help@jai-imageio.dev.java.net

bpb
Offline
Joined: 2004-06-23
Points: 0

> This question brings up a good point... I don't think
> it is possible
> to read an image that uses lossly compression, and
> rewrite it
> changing some of the metadata - if you don't set the
> compression, the
> file will become large, if you set the compression
> then the image is
> compressed again (multiplying the error).

Exactly.

> It seems you would need to be able to extract the
> compressed stream
> from the original image, and write it out verbatim.
>
> Any ideas?

There is API for doing this stuff in Java Image I/O but nothing implements it at the moment:

http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/ImageWriter.html#canReplaceImageMetadata(int)
http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/ImageWriter.html#replaceImageMetadata(int,%20javax.imageio.metadata.IIOMetadata)

If it were implemented say for the TIFF writer what would happen is that an ImageOutputStream would be opened on an existing TIFF file and then the metadata would be replaced. Probably the way the implementation would have to work would be to copy the old IFD to a new one taking account of the updated metadata and then replace the old IFD in the linked list of IFDs with the new one. This would in effect "orphan" the old IFD and result in a file containing unused space.

Once again, I suggest that an ENHANCEMENT request be filed in the jai-imageio-core project to track this.

Brian

stolsvik
Offline
Joined: 2006-09-17
Points: 0

> > It seems you would need to be able to extract the
> > compressed stream
> > from the original image, and write it out
> verbatim.
> >
> > Any ideas?
>
> There is API for doing this stuff in Java Image I/O
> but nothing implements it at the moment:
>
> http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/
> ImageWriter.html#canReplaceImageMetadata(int)
> http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/
> ImageWriter.html#replaceImageMetadata(int,%20javax.ima
> geio.metadata.IIOMetadata)
>
> If it were implemented say for the TIFF writer what
> would happen is that an ImageOutputStream would be
> opened on an existing TIFF file and then the metadata
> would be replaced. Probably the way the
> implementation would have to work would be to copy
> the old IFD to a new one taking account of the
> updated metadata and then replace the old IFD in the
> linked list of IFDs with the new one. This would in
> effect "orphan" the old IFD and result in a file
> containing unused space.

If anyone come up with anything here, I would be very happy.

I need to inject and change metadata (change, add to EXIF and IPTC, possibly XMP) into digital photos (you know, the ones you take with your Canon 40D and such), without changing ANYTHING of the rest of the file, obviously in particular the image data.

I need this to be possible somehow! Any pointers would be great.

(I know that Sanselan (http://www.fightingquaker.com/sanselan/) is aiming to do just this at some point. Do you have other pointers? I find this ability a rather obvious feature, but haven't found any library that does it yet..)

imagero
Offline
Joined: 2003-11-18
Points: 0

> > > It seems you would need to be able to extract the
> > > compressed stream from the original image, and write it out verbatim.
> > >
> > > Any ideas?
> >
> > There is API for doing this stuff in Java Image I/O
> > but nothing implements it at the moment:
> >
> >
> http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/
>
> > ImageWriter.html#canReplaceImageMetadata(int)
> >
> http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/
> >
> ImageWriter.html#replaceImageMetadata(int,%20javax.imageio.metadata.IIOMetadata)
> >
> > If it were implemented say for the TIFF writer what would happen is that an ImageOutputStream would be
> > opened on an existing TIFF file and then the metadata would be replaced.
> > Probably the way the implementation would have to work would be to copy
> > the old IFD to a new one taking account of the updated metadata and then replace the old IFD in the
> > linked list of IFDs with the new one. This would in effect "orphan" the old IFD and result in a file
> > containing unused space.
>
> If anyone come up with anything here, I would be very happy.
>
> I need to inject and change metadata (change, add to EXIF and IPTC, possibly XMP)
> into digital photos (you know, the ones you take with your Canon 40D and
> such), without changing ANYTHING of the rest of the file, obviously in particular the image data.
>
> I need this to be possible somehow! Any pointers would be great.
>
> (I know that Sanselan
> (http://www.fightingquaker.com/sanselan/) is aiming
> to do just this at some point. Do you have other
> pointers? I find this ability a rather obvious
> feature, but haven't found any library that does it yet..)

You may find Imagero useful:
http://reader.imagero.com

Andrey

stolsvik
Offline
Joined: 2006-09-17
Points: 0

> > I need to inject and change metadata (change, add
> to EXIF and IPTC, possibly XMP)
> > into digital photos (you know, the ones you take
> with your Canon 40D and
> > such), without changing ANYTHING of the rest of the
> file, obviously in particular the image data.
>
> I need this to be possible somehow! Any pointers
> would be great.
>
> (I know that Sanselan
> (http://www.fightingquaker.com/sanselan/) is aiming
> to do just this at some point. Do you have other
> pointers? I find this ability a rather obvious
> feature, but haven't found any library that does it
> yet..)
>
> You may find Imagero useful:
> http://reader.imagero.com

I know about this - It has the unfortunate feature of having a commercial license, though, so I haven't even bookmarked it..

However, it if actually can change metadata on different types of images, at least JPEG, without altering _anything else_ in the file, I'd be willing to fork out the money, given that no other library can do this damn obvious thing.

The license page was a bit confusing: I'm obviously a "small company" (given that it is me only) - will _one_ such license enable me to make and sell a product (hopefully in thousands!) embedding Imagero's named abilities?

imagero
Offline
Joined: 2003-11-18
Points: 0

> > I need this to be possible somehow! Any pointers would be great.
> >
> > (I know that Sanselan
> > (http://www.fightingquaker.com/sanselan/) is
> aiming
> > to do just this at some point. Do you have other
> > pointers? I find this ability a rather obvious
> > feature, but haven't found any library that does it yet..)
> >
> > You may find Imagero useful:
> > http://reader.imagero.com
>
> I know about this - It has the unfortunate feature of
> having a commercial license, though, so I haven't
> even bookmarked it..
>
> However, it if actually can change metadata on
> different types of images, at least JPEG, without
> altering _anything else_ in the file, I'd be willing
> to fork out the money, given that no other library
> can do this damn obvious thing.
>
> The license page was a bit confusing: I'm obviously a
> "small company" (given that it is me only) - will
> _one_ such license enable me to make and sell a
> product (hopefully in thousands!) embedding Imagero's
> named abilities?

this is surely wrong place for such questions.