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 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 public PngChunkItxt(final int length, final int chunkType, final int crc, final byte[] bytes) throws ImagingException, IOException {
47 super(length, chunkType, crc, bytes);
48 int terminator = BinaryFunctions.findNull(bytes, "PNG iTXt chunk keyword is not terminated.");
49
50 keyword = new String(bytes, 0, terminator, StandardCharsets.ISO_8859_1);
51 int index = terminator + 1;
52
53 final int compressionFlag = bytes[index++];
54 if (compressionFlag != 0 && compressionFlag != 1) {
55 throw new ImagingException("PNG iTXt chunk has invalid compression flag: " + compressionFlag);
56 }
57
58 final boolean compressed = compressionFlag == 1;
59
60 final int compressionMethod = bytes[index++];
61 if (compressed && compressionMethod != PngConstants.COMPRESSION_DEFLATE_INFLATE) {
62 throw new ImagingException("PNG iTXt chunk has unexpected compression method: " + compressionMethod);
63 }
64
65 terminator = BinaryFunctions.findNull(bytes, index, "PNG iTXt chunk language tag is not terminated.");
66 languageTag = new String(bytes, index, terminator - index, StandardCharsets.ISO_8859_1);
67 index = terminator + 1;
68
69 terminator = BinaryFunctions.findNull(bytes, index, "PNG iTXt chunk translated keyword is not terminated.");
70 translatedKeyword = new String(bytes, index, terminator - index, StandardCharsets.UTF_8);
71 index = terminator + 1;
72
73 if (compressed) {
74 final int compressedTextLength = bytes.length - index;
75
76 final byte[] compressedText = Allocator.byteArray(compressedTextLength);
77 System.arraycopy(bytes, index, compressedText, 0, compressedTextLength);
78
79 text = new String(IOUtils.toByteArray(new InflaterInputStream(new ByteArrayInputStream(compressedText))), StandardCharsets.UTF_8);
80
81 } else {
82 text = new String(bytes, index, bytes.length - index, StandardCharsets.UTF_8);
83 }
84 }
85
86 @Override
87 public AbstractPngText getContents() {
88 return new AbstractPngText.Itxt(keyword, text, languageTag, translatedKeyword);
89 }
90
91
92
93
94 @Override
95 public String getKeyword() {
96 return keyword;
97 }
98
99
100
101
102 @Override
103 public String getText() {
104 return text;
105 }
106
107 public String getTranslatedKeyword() {
108 return translatedKeyword;
109 }
110 }