Hi!
I've posted the same question on the imageio-interest mailing list, but
since that seem pretty much defunct, and our client needs a quick solution
to this problem, I'm trying my luck here as well.
I'm trying to change the DPI settings of an image (png, jpg or tiff -
using the jar from JAI for tiff decoding). I'm doing this by getting the
metadata, changing the entries in the DOM tree, and re-setting it to the
metadata. However, I don't get the expected results, so I reduced my
code to the basic part which fails, and apparently I'm having problems
with getAsTree and setFromTree. Basically, what I'm doing now is this:
// ImageReader reader = something;
IIOMetadata metaData = reader.getImageMetadata(reader.getMinIndex());
// output the old metadata to System.out (contains correct values)
Node root = metaData.getAsTree("javax_imageio_1.0"); // (still contains
correct values)
metaData.setFromTree("javax_imageio_1.0", root); // (root contains
correct values)
// output the new metadata to System.out (this has the wrong values)
For all three formats (png, jpg, tiff), I get different results.in the
Dimension nodes. The most problematic is JPEG, which can't seem to read
the node's values at all. PNG changes my pixel size values. Only TIFF
seems to keep the correct values.
Here are the contents of the Dimension nodes for the various formats:
JPEG before:
<Dimension>
<PixelAspectRatio value="1.0"/>
<ImageOrientation value="normal"/>
<HorizontalPixelSize value="0.35277778"/>
<VerticalPixelSize value="0.35277778"/>
</Dimension>
JPEG after:
<Dimension>
<PixelAspectRatio value="NaN"/>
<ImageOrientation value="normal"/>
<HorizontalPixelSize value="Infinity"/>
<VerticalPixelSize value="Infinity"/>
</Dimension>
PNG before:
<Dimension>
<PixelAspectRatio value="1.0"/>
<ImageOrientation value="Normal"/>
<HorizontalPixelSize value="0.35273367"/>
<VerticalPixelSize value="0.35273367"/>
</Dimension>
PNG after:
<Dimension>
<PixelAspectRatio value="1.0"/>
<ImageOrientation value="Normal"/>
<HorizontalPixelSize value="2.8328612"/>
<VerticalPixelSize value="2.8328612"/>
</Dimension>
TIFF before:
<Dimension>
<PixelAspectRatio value="1.0"/>
<HorizontalPixelSize value="0.35277778"/>
<VerticalPixelSize value="0.35277778"/>
<ImageOrientation value="Normal"/>
</Dimension>
TIFF after:
<Dimension>
<PixelAspectRatio value="1.0"/>
<HorizontalPixelSize value="0.3527785"/>
<VerticalPixelSize value="0.3527785"/>
<ImageOrientation value="Normal"/>
</Dimension>
Any hints on what I'm doing wrong?
Thx,
Marian.

Signature
Hofstadter's law: "It always takes longer than you think,
even when you take account of Hofstadter's law".
Andrey Kuznetsov - 27 Jul 2006 07:27 GMT
> I'm trying to change the DPI settings of an image (png, jpg or tiff -
> using the jar from JAI for tiff decoding). I'm doing this by getting the
> metadata, changing the entries in the DOM tree, and re-setting it to the
> metadata. However, I don't get the expected results
...
> PNG before:
>
[quoted text clipped - 13 lines]
> <VerticalPixelSize value="2.8328612"/>
> </Dimension>
the interest thing is that 2.8328612 x 0.35273367 = 0.9999...
May be important point: I don't see where do you specify resolution units.
note that for png you can specify only meters or undefined as units.
for jpeg and tiff - cm, inch or undefined.
The general weakness of ImageIO is that it does not allow direct access to
metadata.
So if you want just to change resolution you have to decode / encode image.
For JPEG it may cause quality lost.
For such things you may use Imagero - it allows to change any metadata
"in-place".
Andrey

Signature
http://uio.imagero.com Unified I/O for Java
http://reader.imagero.com Java image reader
http://jgui.imagero.com Java GUI components and utilities
Marian Schedenig - 30 Jul 2006 23:25 GMT
> The general weakness of ImageIO is that it does not allow direct access to
> metadata.
[quoted text clipped - 3 lines]
> For such things you may use Imagero - it allows to change any metadata
> "in-place".
Thanks for the hints. The problem was that this is a last-minute fix for our
client. I managed to get it running with JMagick now; I just hope we won't
get into too much trouble when deploying the native libs on the target
server. :)
(Regarding quality loss: I agree; however, I was the one who insisted on
changing the DPI instead of resizing the entire image on a pixel basis, so
we can live with that)
Thx,
Marian.

Signature
Hofstadter's law: "It always takes longer than you think,
even when you take account of Hofstadter's law".
dsjoblom@abo.fi - 27 Jul 2006 16:16 GMT
> Hi!
>
[quoted text clipped - 44 lines]
>
> Any hints on what I'm doing wrong?
You aren't doing anything wrong. You've found a couple of bugs in
ImageIO. I have located and identified the PNG one. Here's what happens
(you can verify this by checking out the source code for
com.sun.imageio.plugins.png.PNGMetadata):
The basic issue is a conversion error between the native PNG pHYs
metadata elements and the standard XML format. Every time you get an
XML element, the pHYs metadata is used as a source and converted to a
node, and every time you merge a node, the contents of the node are
stored internally as pHYs metadata. Ok, so I'll step through the
different stages for the horizontal pixel size case, the vertical case
is analoguous.
Step 1. You read the metadata with reader.getImageMetaData. The
metadata is stored internally in the PNGMetadata class as fields,
including fields for the pHYs elements.
Step 2. You create a standard XML tree out of the metadata using
getAsTree. The pHYs_pixelsPerUnitXAxis field is converted to a
HorizontalPixelSize node in the Dimension subtree of the XML metadata.
The HPS value is set by
node.setAttribute("value",
Float.toString(1000.0F/pHYs_pixelsPerUnitXAxis));
in method getStandardDimensionNode. So the first time you print the xML
metadata, you get "0.35273367" as HorizontalPixelSize . So, originally,
pHYs_pixelsPerUnitXAxis was about 2835.
Step 3. You merge the metadata tree using setFromTree. This time, the
values in the nodes are converted back to the pHYs_pixelsPerUnitXXX
fields. This is achieved through
pHYs_pixelsPerUnitXAxis = (int)(width*1000 + 0.5F);
in function mergeStandardTree, where width is the width read from the
node (in this case "0.35273367"). Ok. So this is where things go wrong.
Obviously, the programmer was trying to do the inverse operation of the
conversion in step 2, but the correct inverse operation is not
width*1000, but rather 1000 / width.
Step 4. You read back the merged tree again, like in step 2. But now,
because of the wrong conversion in step 3, pHYs_pixelsPerUnitXAxis
doesn't contain the same value used in step 2.
I suspect the JPEG metadata format implementation may have some similar
error, but I'm not too familiar with JPEG (the reason I happened to
find the PNG bug with relatively little effort is that I was inspecting
the PNG metadata code just last week when I found another bug which
affected me personally).
HTH,
Daniel Sjöblom
PS. You should consider reporting this bug to Sun.
Marian Schedenig - 30 Jul 2006 23:30 GMT
> You aren't doing anything wrong. You've found a couple of bugs in
> ImageIO. I have located and identified the PNG one.
Interesting. That was my first thought, but I didn't believe that both JPEG
and PNG would have so obvious problems. So the thin documentation led me to
assume I was just doing something the wrong way.
> I suspect the JPEG metadata format implementation may have some similar
> error, but I'm not too familiar with JPEG (the reason I happened to
> find the PNG bug with relatively little effort is that I was inspecting
> the PNG metadata code just last week when I found another bug which
> affected me personally).
I suspect the JPEG bit is a bug converting floating point Strings back to
float or double values. It might even be related to my locale, since the
German format switches dots and commas in floating point numbers.
> PS. You should consider reporting this bug to Sun.
I'll try to do that at work tomorrow. Thanks for your detailed info (I
didn't have time to look into the sources myself). As I already mentioned
in my other post, I switched to JMagick, which now works fine. I'll still
see if I can report that bug though.
Cheers,
Marian.

Signature
Hofstadter's law: "It always takes longer than you think,
even when you take account of Hofstadter's law".