1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.imaging.formats.jpeg.iptc;
18
19 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertTrue;
22 import static org.junit.jupiter.api.Assertions.fail;
23
24 import java.io.ByteArrayOutputStream;
25 import java.io.File;
26 import java.io.IOException;
27 import java.nio.charset.Charset;
28 import java.nio.charset.StandardCharsets;
29 import java.util.ArrayList;
30 import java.util.List;
31
32 import org.apache.commons.imaging.ImagingException;
33 import org.apache.commons.imaging.bytesource.ByteSource;
34 import org.apache.commons.imaging.common.AbstractBinaryOutputStream;
35 import org.apache.commons.imaging.common.GenericImageMetadata.GenericImageMetadataItem;
36 import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
37 import org.apache.commons.imaging.formats.jpeg.JpegImageParser;
38 import org.apache.commons.imaging.formats.jpeg.JpegImagingParameters;
39 import org.apache.commons.imaging.formats.jpeg.JpegPhotoshopMetadata;
40 import org.apache.commons.imaging.test.TestResources;
41 import org.apache.commons.lang3.ArrayUtils;
42 import org.junit.jupiter.api.Test;
43 import org.junit.jupiter.params.ParameterizedTest;
44 import org.junit.jupiter.params.provider.CsvSource;
45
46
47
48
49 public class IptcParserTest {
50
51
52
53
54
55
56
57
58
59
60
61
62 @ParameterizedTest
63 @CsvSource({ "äöü ÄÖÜß, true", "äöü ÄÖÜß €, true", "äöü ÄÖÜß, false", "äöü ÄÖÜß €, false" })
64 public void testEncoding(final String value, final boolean forceUtf8) throws IOException {
65
66 final IptcParser parser = new IptcParser();
67 final List<IptcRecord> records = new ArrayList<>();
68 records.add(new IptcRecord(IptcTypes.CAPTION_ABSTRACT, value));
69 final Charset charset;
70
71
72 final byte[] actualBytes = parser.writeIptcBlock(records, forceUtf8);
73
74
75 final byte[] prefix;
76 try (ByteArrayOutputStream envelopeRecordStream = new ByteArrayOutputStream();
77 AbstractBinaryOutputStream bos = AbstractBinaryOutputStream.create(envelopeRecordStream, parser.getByteOrder())) {
78 if (forceUtf8 || value.contains("€")) {
79
80 bos.write(IptcConstants.IPTC_RECORD_TAG_MARKER);
81 bos.write(IptcConstants.IPTC_ENVELOPE_RECORD_NUMBER);
82 bos.write(90);
83 final byte[] codedCharset = { '\u001B', '%', 'G' };
84 bos.write2Bytes(codedCharset.length);
85 bos.write(codedCharset);
86 charset = StandardCharsets.UTF_8;
87 } else {
88
89 charset = StandardCharsets.ISO_8859_1;
90 }
91
92
93 bos.write(IptcConstants.IPTC_RECORD_TAG_MARKER);
94 bos.write(IptcConstants.IPTC_APPLICATION_2_RECORD_NUMBER);
95 bos.write(IptcTypes.RECORD_VERSION.type);
96
97 bos.write2Bytes(2);
98 bos.write2Bytes(2);
99 prefix = envelopeRecordStream.toByteArray();
100 }
101
102 final byte[] applicationRecord;
103 try (ByteArrayOutputStream applicationRecordStream = new ByteArrayOutputStream();
104 AbstractBinaryOutputStream bos = AbstractBinaryOutputStream.create(applicationRecordStream, parser.getByteOrder())) {
105 bos.write(IptcConstants.IPTC_RECORD_TAG_MARKER);
106 bos.write(IptcConstants.IPTC_APPLICATION_2_RECORD_NUMBER);
107 bos.write(IptcTypes.CAPTION_ABSTRACT.type);
108 final byte[] valueBytes = value.getBytes(charset);
109 bos.write2Bytes(valueBytes.length);
110 bos.write(valueBytes);
111 applicationRecord = applicationRecordStream.toByteArray();
112 }
113
114 final byte[] actualPrefix = ArrayUtils.subarray(actualBytes, 0, prefix.length);
115 final byte[] actualApplicationRecord = ArrayUtils.subarray(actualBytes, prefix.length, prefix.length + applicationRecord.length);
116
117 assertArrayEquals(prefix, actualPrefix);
118 assertArrayEquals(applicationRecord, actualApplicationRecord);
119 }
120
121
122
123
124
125
126
127 @Test
128 public void testEncodingSupport() throws IOException, ImagingException {
129
130 final File file = TestResources.resourceToFile("/images/jpeg/iptc/IMAGING-168/111083453-c07f1880-851e-11eb-8b61-2757f7d934bf.jpg");
131 final JpegImageParser parser = new JpegImageParser();
132 final JpegImageMetadata metadata = (JpegImageMetadata) parser.getMetadata(file);
133 final JpegPhotoshopMetadata photoshopMetadata = metadata.getPhotoshop();
134 @SuppressWarnings("unchecked")
135 final List<GenericImageMetadataItem> items = (List<GenericImageMetadataItem>) photoshopMetadata.getItems();
136 final GenericImageMetadataItem thanksInMandarin = items.get(3);
137
138 assertArrayEquals("\u8c22\u8c22".getBytes(StandardCharsets.UTF_8), thanksInMandarin.getText().getBytes(StandardCharsets.UTF_8));
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 @Test
156 public void testSkipBlockTypes() throws ImagingException, IOException {
157 final File imageFile = TestResources.resourceToFile("/images/jpeg/photoshop/IMAGING-246/FallHarvestKitKat_07610.jpg");
158 final JpegImageMetadata metadata = (JpegImageMetadata) new JpegImageParser().getMetadata(ByteSource.file(imageFile), new JpegImagingParameters());
159 final JpegPhotoshopMetadata photoshopMetadata = metadata.getPhotoshop();
160 final PhotoshopApp13Data photoshopApp13Data = photoshopMetadata.photoshopApp13Data;
161 final List<IptcBlock> blocks = photoshopApp13Data.getRawBlocks();
162 assertEquals(2, blocks.size());
163 for (final IptcBlock block : blocks) {
164 if (block.getBlockType() == 1028 || block.getBlockType() == 1061) {
165
166
167 final byte[] data = block.getBlockData();
168 assertTrue(data.length > 0);
169 } else {
170 fail("Unexpected block type found: " + block.getBlockType());
171 }
172 }
173 }
174 }