1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.imaging.formats.tiff;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21
22 import java.io.ByteArrayInputStream;
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.nio.ByteOrder;
27 import java.util.ArrayList;
28 import java.util.List;
29
30 import org.apache.commons.imaging.ImageReadException;
31 import org.apache.commons.imaging.common.bytesource.ByteSource;
32 import org.apache.commons.imaging.common.bytesource.ByteSourceFile;
33 import org.apache.commons.imaging.common.mylzw.MyLzwCompressor;
34 import org.apache.commons.imaging.common.mylzw.MyLzwDecompressor;
35 import org.apache.commons.imaging.internal.Debug;
36 import org.junit.jupiter.api.Disabled;
37 import org.junit.jupiter.api.Test;
38
39 public class TiffLzwTest extends TiffBaseTest {
40
41 @Test
42 public void testTrivial() throws Exception {
43 final byte[] bytes = { 0, };
44 compressRoundtripAndValidate(bytes);
45 }
46
47 @Test
48 public void testMedium() throws Exception {
49 final int LENGTH = 1024 * 32;
50 final byte[] bytes = new byte[LENGTH];
51 for (int modulator = 1; modulator < 255; modulator += 3) {
52 for (int i = 0; i < LENGTH; i++) {
53 bytes[i] = (byte) (0xff & (i % modulator));
54 }
55
56 compressRoundtripAndValidate(bytes);
57 }
58 }
59
60 @Disabled
61 @Test
62 public void testTiffImageData() throws IOException, ImageReadException {
63 final List<File> images = getTiffImages();
64 for (final File image : images) {
65
66 Debug.debug("imageFile", image);
67
68 final ByteSource byteSource = new ByteSourceFile(image);
69 final List<byte[]> data = new TiffImageParser().collectRawImageData(byteSource, new TiffImagingParameters());
70
71 for (final byte[] bytes : data) {
72 decompressRoundtripAndValidate(bytes);
73 }
74 }
75 }
76
77 private void compressRoundtripAndValidate(final byte[] src) throws IOException, ImageReadException {
78 final boolean DEBUG = false;
79
80 if (DEBUG) {
81 Debug.debug();
82 Debug.debug("roundtripAndValidate: " + src.length);
83 Debug.debug();
84 }
85
86 final int LZW_MINIMUM_CODE_SIZE = 8;
87 final List<Integer> codes = new ArrayList<>();
88 final MyLzwCompressor.Listener compressionListener = new MyLzwCompressor.Listener() {
89 @Override
90 public void dataCode(final int code) {
91 codes.add(code);
92 }
93
94 @Override
95 public void eoiCode(final int code) {
96 codes.add(code);
97 }
98
99 @Override
100 public void clearCode(final int code) {
101 codes.add(code);
102 }
103
104 @Override
105 public void init(final int clearCode, final int eoiCode) {
106 }
107 };
108
109 final MyLzwCompressor compressor = new MyLzwCompressor(LZW_MINIMUM_CODE_SIZE,
110 ByteOrder.BIG_ENDIAN, true, compressionListener);
111 final byte[] compressed = compressor.compress(src);
112
113 final MyLzwDecompressor.Listener decompressionListener = new MyLzwDecompressor.Listener() {
114
115 int index = 0;
116 int clearCode, eoiCode;
117
118 @Override
119 public void code(final int code) {
120 if (DEBUG) {
121 if (code == clearCode) {
122 Debug.debug("clearCode: " + index + "/" + codes.size());
123 Debug.debug();
124 }
125 if (code == eoiCode) {
126 Debug.debug("eoiCode: " + index + "/" + codes.size());
127 Debug.debug();
128 }
129 }
130 final Integer expectedCode = codes.get(index++);
131 if (code != expectedCode) {
132 Debug.debug("bad code: " + index + "/" + codes.size());
133 Debug.debug("code: " + code + " (0x"
134 + Integer.toHexString(code) + ") "
135 + Integer.toBinaryString(code));
136 Debug.debug("expected: " + expectedCode + " (0x"
137 + Integer.toHexString(expectedCode)
138 + ") "
139 + Integer.toBinaryString(expectedCode));
140 Debug.debug("clearCode: " + clearCode + " (0x"
141 + Integer.toHexString(clearCode) + ") "
142 + Integer.toBinaryString(clearCode));
143 Debug.debug("eoiCode: " + eoiCode + " (0x"
144 + Integer.toHexString(eoiCode) + ") "
145 + Integer.toBinaryString(eoiCode));
146 Debug.debug();
147 }
148 }
149
150 @Override
151 public void init(final int clearCode, final int eoiCode) {
152 this.clearCode = clearCode;
153 this.eoiCode = eoiCode;
154 }
155
156 };
157 final InputStream is = new ByteArrayInputStream(compressed);
158 final MyLzwDecompressor decompressor = new MyLzwDecompressor(
159 LZW_MINIMUM_CODE_SIZE, ByteOrder.BIG_ENDIAN,
160 decompressionListener);
161 decompressor.setTiffLZWMode();
162 final byte[] decompressed = decompressor.decompress(is, src.length);
163
164 assertEquals(src.length, decompressed.length);
165 for (int i = 0; i < src.length; i++) {
166 assertEquals(src[i], decompressed[i]);
167 }
168 }
169
170 private void decompressRoundtripAndValidate(final byte[] src) throws IOException, ImageReadException {
171 Debug.debug();
172 Debug.debug("roundtripAndValidate: " + src.length);
173 Debug.debug();
174
175 final int LZW_MINIMUM_CODE_SIZE = 8;
176 final List<Integer> codes = new ArrayList<>();
177
178 final MyLzwDecompressor.Listener decompressionListener = new MyLzwDecompressor.Listener() {
179
180 @Override
181 public void code(final int code) {
182 Debug.debug("listener code: " + code + " (0x"
183 + Integer.toHexString(code) + ") "
184 + Integer.toBinaryString(code) + ", index: "
185 + codes.size());
186 codes.add(code);
187 }
188
189 @Override
190 public void init(final int clearCode, final int eoiCode) {
191 }
192
193 };
194 final InputStream is = new ByteArrayInputStream(src);
195 final MyLzwDecompressor decompressor = new MyLzwDecompressor(
196 LZW_MINIMUM_CODE_SIZE, ByteOrder.BIG_ENDIAN,
197 decompressionListener);
198 decompressor.setTiffLZWMode();
199 final byte[] decompressed = decompressor.decompress(is, src.length);
200
201 final MyLzwCompressor.Listener compressionListener = new MyLzwCompressor.Listener() {
202
203 int clearCode, eoiCode;
204
205 @Override
206 public void init(final int clearCode, final int eoiCode) {
207 this.clearCode = clearCode;
208 this.eoiCode = eoiCode;
209 }
210
211 int index = 0;
212
213 private void code(final int code) {
214
215 if (code == clearCode) {
216 Debug.debug("clearCode: " + index + "/" + codes.size());
217 Debug.debug();
218 }
219 if (code == eoiCode) {
220 Debug.debug("eoiCode: " + index + "/" + codes.size());
221 Debug.debug();
222 }
223 final Integer expectedCode = codes.get(index++);
224 if (code != expectedCode) {
225 Debug.debug("bad code: " + index + "/" + codes.size());
226 Debug.debug("code: " + code + " (0x"
227 + Integer.toHexString(code) + ") "
228 + Integer.toBinaryString(code));
229 Debug.debug("expected: " + expectedCode + " (0x"
230 + Integer.toHexString(expectedCode)
231 + ") "
232 + Integer.toBinaryString(expectedCode));
233 Debug.debug("clearCode: " + clearCode + " (0x"
234 + Integer.toHexString(clearCode) + ") "
235 + Integer.toBinaryString(clearCode));
236 Debug.debug("eoiCode: " + eoiCode + " (0x"
237 + Integer.toHexString(eoiCode) + ") "
238 + Integer.toBinaryString(eoiCode));
239 Debug.debug();
240 }
241 }
242
243 @Override
244 public void dataCode(final int code) {
245 code(code);
246 }
247
248 @Override
249 public void eoiCode(final int code) {
250 code(code);
251 }
252
253 @Override
254 public void clearCode(final int code) {
255 code(code);
256 }
257
258 };
259
260 final MyLzwCompressor compressor = new MyLzwCompressor(LZW_MINIMUM_CODE_SIZE,
261 ByteOrder.BIG_ENDIAN, true, compressionListener);
262 final byte[] compressed = compressor.compress(decompressed);
263
264 assertEquals(src.length, compressed.length);
265 for (int i = 0; i < src.length; i++) {
266 assertEquals(src[i], compressed[i]);
267 }
268 }
269
270 }