Author: damjan Date: Tue Sep 6 17:16:48 2016 New Revision: 1759460 URL: http://svn.apache.org/viewvc?rev=1759460&view=rev Log: IMAGING-172: Microsoft tags are not seen in MS Windows Properties/Details dialog
Null-terminate the XpString tag, and store it in the root directory where Windows looks for it instead of the EXIF directory. Also deletes the IPTC and XMP metadata which contains conflicting tags which Windows uses instead when present. Modified: commons/proper/imaging/trunk/src/changes/changes.xml commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/taginfos/TagInfoXpString.java commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/MicrosoftTagTest.java Modified: commons/proper/imaging/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/changes/changes.xml?rev=1759460&r1=1759459&r2=1759460&view=diff ============================================================================== --- commons/proper/imaging/trunk/src/changes/changes.xml (original) +++ commons/proper/imaging/trunk/src/changes/changes.xml Tue Sep 6 17:16:48 2016 @@ -46,6 +46,9 @@ The <action> type attribute can be add,u <body> <release version="1.0" date="TBA" description="First major release"> + <action issue="IMAGING-172" dev="damjan" type="fix"> + Microsoft tags are not seen in MS Windows Properties/Details dialog. + </action> <action issue="IMAGING-186" dev="britter" type="update" due-to="Ric Emery"> Add sCAL support to PNG reading and writing. </action> Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/taginfos/TagInfoXpString.java URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/taginfos/TagInfoXpString.java?rev=1759460&r1=1759459&r2=1759460&view=diff ============================================================================== --- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/taginfos/TagInfoXpString.java (original) +++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/tiff/taginfos/TagInfoXpString.java Tue Sep 6 17:16:48 2016 @@ -43,7 +43,10 @@ public class TagInfoXpString extends Tag } final String s = (String) value; try { - return s.getBytes("UTF-16LE"); + final byte[] bytes = s.getBytes("UTF-16LE"); + final byte[] paddedBytes = new byte[bytes.length + 2]; + System.arraycopy(bytes, 0, paddedBytes, 0, bytes.length); + return paddedBytes; } catch (final UnsupportedEncodingException cannotHappen) { return null; } @@ -55,7 +58,14 @@ public class TagInfoXpString extends Tag throw new ImageReadException("Text field not encoded as bytes."); } try { - return new String(entry.getByteArrayValue(), "UTF-16LE"); + final byte[] bytes = entry.getByteArrayValue(); + final int length; + if (bytes.length >= 2 && bytes[bytes.length - 1] == 0 && bytes[bytes.length - 2] == 0) { + length = bytes.length - 2; + } else { + length = bytes.length; + } + return new String(bytes, 0, length, "UTF-16LE"); } catch (final UnsupportedEncodingException cannotHappen) { return null; } Modified: commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/MicrosoftTagTest.java URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/MicrosoftTagTest.java?rev=1759460&r1=1759459&r2=1759460&view=diff ============================================================================== --- commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/MicrosoftTagTest.java (original) +++ commons/proper/imaging/trunk/src/test/java/org/apache/commons/imaging/formats/jpeg/exif/MicrosoftTagTest.java Tue Sep 6 17:16:48 2016 @@ -21,19 +21,27 @@ import static org.junit.Assert.assertTru import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.apache.commons.imaging.ImageFormats; +import org.apache.commons.imaging.ImageReadException; +import org.apache.commons.imaging.ImageWriteException; import org.apache.commons.imaging.Imaging; import org.apache.commons.imaging.ImagingConstants; import org.apache.commons.imaging.common.ImageMetadata; import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata; +import org.apache.commons.imaging.formats.jpeg.iptc.JpegIptcRewriter; +import org.apache.commons.imaging.formats.jpeg.xmp.JpegXmpRewriter; import org.apache.commons.imaging.formats.tiff.TiffDirectory; import org.apache.commons.imaging.formats.tiff.TiffImageMetadata; import org.apache.commons.imaging.formats.tiff.constants.MicrosoftTagConstants; +import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants; import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory; import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet; import org.junit.Test; @@ -48,11 +56,11 @@ public class MicrosoftTagTest extends Ex public void testWrite() throws Exception { final BufferedImage image = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB); final TiffOutputSet exifSet = new TiffOutputSet(); - final TiffOutputDirectory exif = exifSet.getOrCreateExifDirectory(); - exif.add(MicrosoftTagConstants.EXIF_TAG_XPAUTHOR, AUTHOR); - exif.add(MicrosoftTagConstants.EXIF_TAG_XPCOMMENT, COMMENT); - exif.add(MicrosoftTagConstants.EXIF_TAG_XPSUBJECT, SUBJECT); - exif.add(MicrosoftTagConstants.EXIF_TAG_XPTITLE, TITLE); + final TiffOutputDirectory root = exifSet.getOrCreateRootDirectory(); + root.add(MicrosoftTagConstants.EXIF_TAG_XPAUTHOR, AUTHOR); + root.add(MicrosoftTagConstants.EXIF_TAG_XPCOMMENT, COMMENT); + root.add(MicrosoftTagConstants.EXIF_TAG_XPSUBJECT, SUBJECT); + root.add(MicrosoftTagConstants.EXIF_TAG_XPTITLE, TITLE); final Map<String, Object> params = new TreeMap<>(); params.put(ImagingConstants.PARAM_KEY_EXIF, exifSet); final byte[] bytes = Imaging.writeImageToBytes(image, ImageFormats.TIFF, params); @@ -69,17 +77,32 @@ public class MicrosoftTagTest extends Ex } } + private byte[] cleanImage(File imageWithExif) throws ImageReadException, ImageWriteException, IOException { + // Windows doesn't show XP tags if same-meaning tags exist in IPTC or XMP. Remove them: + final ByteArrayOutputStream noXmp = new ByteArrayOutputStream(); + new JpegXmpRewriter().removeXmpXml(imageWithExif, noXmp); + final ByteArrayOutputStream noXmpNoIptc = new ByteArrayOutputStream(); + new JpegIptcRewriter().removeIPTC(noXmp.toByteArray(), noXmpNoIptc); + return noXmpNoIptc.toByteArray(); + } + @Test public void testRewrite() throws Exception { - final File imageWithExif = getImageWithExifData(); + final byte[] imageWithExif = cleanImage(getImageWithExifData()); + final TiffImageMetadata metadata = toTiffMetadata(Imaging.getMetadata(imageWithExif)); final ExifRewriter rewriter = new ExifRewriter(); final TiffOutputSet outputSet = metadata.getOutputSet(); - final TiffOutputDirectory exif = outputSet.getOrCreateExifDirectory(); - exif.add(MicrosoftTagConstants.EXIF_TAG_XPAUTHOR, AUTHOR); - exif.add(MicrosoftTagConstants.EXIF_TAG_XPCOMMENT, COMMENT); - exif.add(MicrosoftTagConstants.EXIF_TAG_XPSUBJECT, SUBJECT); - exif.add(MicrosoftTagConstants.EXIF_TAG_XPTITLE, TITLE); + final TiffOutputDirectory root = outputSet.getOrCreateRootDirectory(); + + // In Windows these will also hide XP fields: + root.removeField(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION); + root.removeField(TiffTagConstants.TIFF_TAG_ARTIST); + + root.add(MicrosoftTagConstants.EXIF_TAG_XPAUTHOR, AUTHOR); + root.add(MicrosoftTagConstants.EXIF_TAG_XPCOMMENT, COMMENT); + root.add(MicrosoftTagConstants.EXIF_TAG_XPSUBJECT, SUBJECT); + root.add(MicrosoftTagConstants.EXIF_TAG_XPTITLE, TITLE); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); rewriter.updateExifMetadataLossy(imageWithExif, baos, outputSet); checkFields(baos.toByteArray());