1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.imaging.formats.png.chunks;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.IOException;
21 import java.nio.charset.StandardCharsets;
22 import java.util.zip.InflaterInputStream;
23
24 import org.apache.commons.imaging.ImagingException;
25 import org.apache.commons.imaging.common.Allocator;
26 import org.apache.commons.imaging.common.BinaryFunctions;
27 import org.apache.commons.imaging.formats.png.AbstractPngText;
28 import org.apache.commons.imaging.formats.png.PngConstants;
29 import org.apache.commons.io.IOUtils;
30
31 public final class PngChunkItxt extends AbstractPngTextChunk {
32
33 private final String keyword;
34 private final String text;
35
36
37
38
39
40
41
42 private final String languageTag;
43
44 private final String translatedKeyword;
45
46
47
48
49
50
51
52
53
54
55
56
57 public PngChunkItxt(final int length, final int chunkType, final int crc, final byte[] bytes) throws ImagingException, IOException {
58 super(length, chunkType, crc, bytes);
59 int terminator = BinaryFunctions.indexOf0(bytes, "PNG iTXt chunk keyword is not terminated.");
60
61 keyword = new String(bytes, 0, terminator, StandardCharsets.ISO_8859_1);
62 int index = terminator + 1;
63
64 final int compressionFlag = bytes[index++];
65 if (compressionFlag != 0 && compressionFlag != 1) {
66 throw new ImagingException("PNG iTXt chunk has invalid compression flag: " + compressionFlag);
67 }
68
69 final boolean compressed = compressionFlag == 1;
70
71 final int compressionMethod = bytes[index++];
72 if (compressed && compressionMethod != PngConstants.COMPRESSION_DEFLATE_INFLATE) {
73 throw new ImagingException("PNG iTXt chunk has unexpected compression method: " + compressionMethod);
74 }
75
76 terminator = BinaryFunctions.indexOf0(bytes, index, "PNG iTXt chunk language tag is not terminated.");
77 languageTag = new String(bytes, index, terminator - index, StandardCharsets.ISO_8859_1);
78 index = terminator + 1;
79
80 terminator = BinaryFunctions.indexOf0(bytes, index, "PNG iTXt chunk translated keyword is not terminated.");
81 translatedKeyword = new String(bytes, index, terminator - index, StandardCharsets.UTF_8);
82 index = terminator + 1;
83
84 if (compressed) {
85 final int compressedTextLength = bytes.length - index;
86
87 final byte[] compressedText = Allocator.byteArray(compressedTextLength);
88 System.arraycopy(bytes, index, compressedText, 0, compressedTextLength);
89
90 text = new String(IOUtils.toByteArray(new InflaterInputStream(new ByteArrayInputStream(compressedText))), StandardCharsets.UTF_8);
91
92 } else {
93 text = new String(bytes, index, bytes.length - index, StandardCharsets.UTF_8);
94 }
95 }
96
97 @Override
98 public AbstractPngText getContents() {
99 return new AbstractPngText.Itxt(keyword, text, languageTag, translatedKeyword);
100 }
101
102
103
104
105 @Override
106 public String getKeyword() {
107 return keyword;
108 }
109
110
111
112
113 @Override
114 public String getText() {
115 return text;
116 }
117
118 public String getTranslatedKeyword() {
119 return translatedKeyword;
120 }
121 }