Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TIFF CCITT T.6 - WRITING - IIOMetadataNode PHOTOMETRIC_INTERPRETATION = WhiteIsZero seems not working. #478

Closed
agharta opened this issue Mar 18, 2019 · 8 comments
Assignees

Comments

@agharta
Copy link

agharta commented Mar 18, 2019

Hi all,
Writing a tiff metadata many attributes will be applied to output tiff, like TAG_RESOLUTION_UNIT & TAG_X/Y_RESOLUTION....but TAG_PHOTOMETRIC_INTERPRETATION doesn't works!

The output tiff's TAG_PHOTOMETRIC_INTERPRETATION is always Black is Zero!

Try it.

bi = scaleImage(bi, BufferedImage.TYPE_BYTE_BINARY, (int) d.getWidth(), (int) d.getHeight());
TIFFImageWriter writer = getImageWriter();//load tiff writer
TIFFImageWriteParam writeParams = (TIFFImageWriteParam) writer.getDefaultWriteParam();
writeParams.setCompressionMode(TIFFImageWriteParam.MODE_EXPLICIT);
writeParams.setCompressionType("CCITT T.6");
 //set METADATA
IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(writeParams);
ImageTypeSpecifier imageTypeS = ImageTypeSpecifier.createFromRenderedImage(bi);
IIOMetadata imageMetadata = writer.getDefaultImageMetadata(imageTypeS, writeParams);
//
String nativeFormat = "com_sun_media_imageio_plugins_tiff_image_1.0";
IIOMetadataNode customMeta = new IIOMetadataNode(nativeFormat);
IIOMetadataNode ifd = new IIOMetadataNode("TIFFIFD");
customMeta.appendChild(ifd);
createTIFFFieldNode(ifd, TIFF.TAG_PHOTOMETRIC_INTERPRETATION, TIFF.TYPE_SHORT, (short) 0); /*0 = WhiteIsZero, 1 = BlackIsZero*/
imageMetadata.mergeTree(nativeFormat, customMeta);
//
//write output
File fx = new File(toDir + "/" + f.getName());
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(new FileOutputStream(fx));
writer.setOutput(imageOutputStream);
writer.write(streamMetadata, new IIOImage(bi, null, imageMetadata), writeParams);
writer.dispose();
imageOutputStream.close();




static void createTIFFFieldNode(final IIOMetadataNode parentIFDNode, int tag, short type, Object value) {
        IIOMetadataNode fieldNode = new IIOMetadataNode("TIFFField");
        parentIFDNode.appendChild(fieldNode);

        fieldNode.setAttribute("number", String.valueOf(tag));

        switch (type) {
            case TIFF.TYPE_ASCII:
                createTIFFFieldContainerNode(fieldNode, "Ascii", value);
                break;
            case TIFF.TYPE_BYTE:
                createTIFFFieldContainerNode(fieldNode, "Byte", value);
                break;
            case TIFF.TYPE_SHORT:
                createTIFFFieldContainerNode(fieldNode, "Short", value);
                break;
            case TIFF.TYPE_RATIONAL:
                createTIFFFieldContainerNode(fieldNode, "Rational", value);
                break;
            default:
                throw new IllegalArgumentException("Unsupported type: " + type);
        }
    }

static void createTIFFFieldContainerNode(final IIOMetadataNode fieldNode, final String type, final Object value) {
        IIOMetadataNode containerNode = new IIOMetadataNode("TIFF" + type + "s");
        fieldNode.appendChild(containerNode);

        IIOMetadataNode valueNode = new IIOMetadataNode("TIFF" + type);
        valueNode.setAttribute("value", String.valueOf(value));
        containerNode.appendChild(valueNode);
    }

@haraldk
Copy link
Owner

haraldk commented Mar 18, 2019

Hi,

This is as expected. Currently, only a subset of values are kept from the metadata. There are some related issues open already, regarding adding support for more values from metadata, see #412 and #416.

Other values are always taken from the actual image, like width, height and photometric interpretation, to make sure the data written is consistent.

It should be possible to write image with photometric interpretation WhiteIsZero (0), though. You just need to invert the colors in the color map (the IndexColorModel) and invert your data to match so that the image data is indeed 0 for white and 1 for black (ie. the same way the TIFFImageReader reads WhiteIsZero).

It could be possible to add support for letting the metadata decide, if the value from the metadata is compatible with the actual image. But what would you expect the output to be, if your image data is BlackIsZero and your metadata is WhiteIsZero? Should it look the same (ie. inverting the color values while writing)? Or should it look inverted (ie. write the values as is, with the opposite interpretation)? It's not really obvious which solution is the correct one in this case...

Anyway, hope that helps!

--
Harald K

@haraldk haraldk self-assigned this Mar 18, 2019
@haraldk
Copy link
Owner

haraldk commented Mar 22, 2019

Hi @agharta

Have you had any time to look into the suggestions above? Is the suggested solution/workaround satisfactory, or do you have any input on how this feature should be implemented?

Best regards,

--
Harald K

@agharta
Copy link
Author

agharta commented Mar 22, 2019 via email

@haraldk
Copy link
Owner

haraldk commented Mar 22, 2019

Just to make some clarifications, photometric interpretation isn't really meta data, it is used to instruct a TIFF reader/viewer how the image data is to be interpreted. Similarly there's no way to know for sure what interpretation should be used by just looking at the image data.

However, there is a known issue that some common TIFF software infers the photometric interpretation from the compression value, and ignore the value of photometric interpretation. This is of course because CCITT encodings originates from the fax world, where the paper is blank (0) and ink is the "value" (1). I don't believe it's correct, but I know it's common (this kind of explains your points 2 and 3).

So, perhaps we should always write CCITT encodings (or even bi-level b/w in general) in WhiteIsZero, because it is more compatible?

I need to think more about the implications of such a change.

Still, if your image is WhiteIsZero, there is code in the reader to preserve it, so I think your point 1 is incorrect. At least I cannot reproduce it, and my tests shows it's kept as is. Please show me your code, if you want me to look further into that.

Best regards,

--
Harald K

@agharta
Copy link
Author

agharta commented Mar 22, 2019 via email

@haraldk
Copy link
Owner

haraldk commented Mar 22, 2019

No worries! We all make mistakes. I've made quite a few myself... ;-)

I've added special test case for preserving WhiteIsZero is the TIFFImageWriterTest but I also think we should make it the default for FAX encodings. I'll keep this issue open as a reminder.

--
Harald K

@karthick89cpt
Copy link

Hi Harald,

Can you please let us know if this issue WhiteIsZero resolved

Thanks
Karthick Kathiresan

@haraldk
Copy link
Owner

haraldk commented Mar 2, 2020

@karthick89cpt

Hi Karthick,

This issue is based on a misunderstanding, so there's nothing to resolve really.


I've left it open, as I consider making WhiteIsZero the default for all FAX encodings, this is not yet done. But it doesn't stop you from reading/writing images with WhiteIsZero photometric interpretation.

Best regards,

--
Harald K

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants