blob: 5a6dd4525c1a3fef74d3144a0679326bd557ec0c [file] [log] [blame]
DRC3bad53f2011-02-23 02:20:49 +00001/*
2 * Copyright (C)2011 D. R. Commander. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of the libjpeg-turbo Project nor the names of its
13 * contributors may be used to endorse or promote products derived from this
14 * software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * This program tests the various code paths in the TurboJPEG JNI Wrapper
31 */
32
33import java.io.*;
34import java.util.*;
DRC84a1bcc2011-02-23 12:09:56 +000035import java.awt.image.*;
36import javax.imageio.*;
DRC3bad53f2011-02-23 02:20:49 +000037import org.libjpegturbo.turbojpeg.*;
38
39public class TJUnitTest {
40
DRCf7f3ea42011-03-01 20:03:32 +000041 private static final String classname =
42 new TJUnitTest().getClass().getName();
DRC3bad53f2011-02-23 02:20:49 +000043
DRCf7f3ea42011-03-01 20:03:32 +000044 private static void usage() {
45 System.out.println("\nUSAGE: java " + classname + " [options]\n");
46 System.out.println("Options:\n");
47 System.out.println("-yuv = test YUV encoding/decoding support\n");
48 System.out.println("-bi = test BufferedImage support\n");
49 System.exit(1);
50 }
DRC3bad53f2011-02-23 02:20:49 +000051
DRCf7f3ea42011-03-01 20:03:32 +000052 private final static String subNameLong[] = {
DRCd0a81362011-03-04 13:04:24 +000053 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0"
DRCf7f3ea42011-03-01 20:03:32 +000054 };
55 private final static String subName[] = {
DRCd0a81362011-03-04 13:04:24 +000056 "444", "422", "420", "GRAY", "440"
DRCf7f3ea42011-03-01 20:03:32 +000057 };
DRC3bad53f2011-02-23 02:20:49 +000058
DRCf7f3ea42011-03-01 20:03:32 +000059 private final static String pixFormatStr[] = {
60 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale"
61 };
62 private final static int biType[] = {
63 0, BufferedImage.TYPE_3BYTE_BGR, BufferedImage.TYPE_INT_BGR,
64 BufferedImage.TYPE_INT_RGB, 0, 0, BufferedImage.TYPE_BYTE_GRAY
65 };
DRC3bad53f2011-02-23 02:20:49 +000066
DRCf7f3ea42011-03-01 20:03:32 +000067 private final static int _3byteFormats[] = {
68 TJ.PF_RGB, TJ.PF_BGR
69 };
70 private final static int _3byteFormatsBI[] = {
71 TJ.PF_BGR
72 };
73 private final static int _4byteFormats[] = {
74 TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB
75 };
76 private final static int _4byteFormatsBI[] = {
77 TJ.PF_RGBX, TJ.PF_BGRX
78 };
79 private final static int onlyGray[] = {
80 TJ.PF_GRAY
81 };
82 private final static int onlyRGB[] = {
83 TJ.PF_RGB
84 };
DRC3bad53f2011-02-23 02:20:49 +000085
DRCf7f3ea42011-03-01 20:03:32 +000086 private final static int YUVENCODE = 1;
87 private final static int YUVDECODE = 2;
88 private static int yuv = 0;
89 private static boolean bi = false;
DRC3bad53f2011-02-23 02:20:49 +000090
DRCf7f3ea42011-03-01 20:03:32 +000091 private static int exitStatus = 0;
DRC3bad53f2011-02-23 02:20:49 +000092
DRCf7f3ea42011-03-01 20:03:32 +000093 private static double getTime() {
94 return (double)System.nanoTime() / 1.0e9;
95 }
DRC3bad53f2011-02-23 02:20:49 +000096
DRCf7f3ea42011-03-01 20:03:32 +000097 private final static byte pixels[][] = {
98 {0, (byte)255, 0},
99 {(byte)255, 0, (byte)255},
100 {(byte)255, (byte)255, 0},
101 {0, 0, (byte)255},
102 {0, (byte)255, (byte)255},
103 {(byte)255, 0, 0},
104 {(byte)255, (byte)255, (byte)255},
105 {0, 0, 0},
106 {(byte)255, 0, 0}
107 };
DRC3bad53f2011-02-23 02:20:49 +0000108
DRCf7f3ea42011-03-01 20:03:32 +0000109 private static void initBuf(byte[] buf, int w, int pitch, int h, int pf,
110 int flags) throws Exception {
111 int roffset = TJ.getRedShift(pf) / 8;
112 int goffset = TJ.getGreenShift(pf) / 8;
113 int boffset = TJ.getBlueShift(pf) / 8;
114 int ps = TJ.getPixelSize(pf);
115 int i, _i, j;
DRC3bad53f2011-02-23 02:20:49 +0000116
DRCf7f3ea42011-03-01 20:03:32 +0000117 Arrays.fill(buf, (byte)0);
118 if(pf == TJ.PF_GRAY) {
119 for(_i = 0; _i < 16; _i++) {
DRC92549de2011-03-15 20:52:02 +0000120 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000121 else i = _i;
122 for(j = 0; j < w; j++) {
123 if(((_i / 8) + (j / 8)) % 2 == 0) buf[pitch * i + j] = (byte)255;
124 else buf[pitch * i + j] = 76;
125 }
126 }
127 for(_i = 16; _i < h; _i++) {
DRC92549de2011-03-15 20:52:02 +0000128 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000129 else i = _i;
130 for(j = 0; j < w; j++) {
131 if(((_i / 8) + (j / 8)) % 2 == 0) buf[pitch * i + j] = 0;
132 else buf[pitch * i + j] = (byte)226;
133 }
134 }
135 return;
136 }
137 for(_i = 0; _i < 16; _i++) {
DRC92549de2011-03-15 20:52:02 +0000138 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000139 else i = _i;
140 for(j = 0; j < w; j++) {
141 buf[pitch * i + j * ps + roffset] = (byte)255;
142 if(((_i / 8) + (j / 8)) % 2 == 0) {
143 buf[pitch * i + j * ps + goffset] = (byte)255;
144 buf[pitch * i + j * ps + boffset] = (byte)255;
145 }
146 }
147 }
148 for(_i = 16; _i < h; _i++) {
DRC92549de2011-03-15 20:52:02 +0000149 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000150 else i = _i;
151 for(j = 0; j < w; j++) {
152 if(((_i / 8) + (j / 8)) % 2 != 0) {
153 buf[pitch * i + j * ps + roffset] = (byte)255;
154 buf[pitch * i + j * ps + goffset] = (byte)255;
155 }
156 }
157 }
158 }
DRC3bad53f2011-02-23 02:20:49 +0000159
DRCf7f3ea42011-03-01 20:03:32 +0000160 private static void initIntBuf(int[] buf, int w, int pitch, int h, int pf,
161 int flags) throws Exception {
162 int rshift = TJ.getRedShift(pf);
163 int gshift = TJ.getGreenShift(pf);
164 int bshift = TJ.getBlueShift(pf);
165 int i, _i, j;
DRC84a1bcc2011-02-23 12:09:56 +0000166
DRCf7f3ea42011-03-01 20:03:32 +0000167 Arrays.fill(buf, 0);
168 for(_i = 0; _i < 16; _i++) {
DRC92549de2011-03-15 20:52:02 +0000169 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000170 else i = _i;
171 for(j = 0; j < w; j++) {
172 buf[pitch * i + j] = (255 << rshift);
173 if(((_i / 8) + (j / 8)) % 2 == 0) {
174 buf[pitch * i + j] |= (255 << gshift);
175 buf[pitch * i + j] |= (255 << bshift);
176 }
177 }
178 }
179 for(_i = 16; _i < h; _i++) {
DRC92549de2011-03-15 20:52:02 +0000180 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000181 else i = _i;
182 for(j = 0; j < w; j++) {
183 if(((_i / 8) + (j / 8)) % 2 != 0) {
184 buf[pitch * i + j] = (255 << rshift);
185 buf[pitch * i + j] |= (255 << gshift);
186 }
187 }
188 }
189 }
DRC84a1bcc2011-02-23 12:09:56 +0000190
DRCf7f3ea42011-03-01 20:03:32 +0000191 private static void initImg(BufferedImage img, int pf, int flags)
192 throws Exception {
193 WritableRaster wr = img.getRaster();
194 int imgtype = img.getType();
195 if(imgtype == BufferedImage.TYPE_INT_RGB
196 || imgtype == BufferedImage.TYPE_INT_BGR) {
197 SinglePixelPackedSampleModel sm =
198 (SinglePixelPackedSampleModel)img.getSampleModel();
199 int pitch = sm.getScanlineStride();
200 DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
201 int[] buf = db.getData();
202 initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
203 }
204 else {
205 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
206 int pitch = sm.getScanlineStride();
207 DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
208 byte[] buf = db.getData();
209 initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
210 }
211 }
DRC3bad53f2011-02-23 02:20:49 +0000212
DRCf7f3ea42011-03-01 20:03:32 +0000213 private static void checkVal(int i, int j, int v, String vname, int cv)
214 throws Exception {
215 v = (v < 0) ? v + 256 : v;
216 if(v < cv - 1 || v > cv + 1) {
217 throw new Exception("\nComp. " + vname + " at " + i + "," + j
218 + " should be " + cv + ", not " + v + "\n");
219 }
220 }
DRC3bad53f2011-02-23 02:20:49 +0000221
DRCf7f3ea42011-03-01 20:03:32 +0000222 private static void checkVal0(int i, int j, int v, String vname)
223 throws Exception {
224 v = (v < 0) ? v + 256 : v;
225 if(v > 1) {
226 throw new Exception("\nComp. " + vname + " at " + i + "," + j
227 + " should be 0, not " + v + "\n");
228 }
229 }
DRC3bad53f2011-02-23 02:20:49 +0000230
DRCf7f3ea42011-03-01 20:03:32 +0000231 private static void checkVal255(int i, int j, int v, String vname)
232 throws Exception {
233 v = (v < 0) ? v + 256 : v;
234 if(v < 254) {
235 throw new Exception("\nComp. " + vname + " at " + i + "," + j
236 + " should be 255, not " + v + "\n");
237 }
238 }
DRC3bad53f2011-02-23 02:20:49 +0000239
DRCf7f3ea42011-03-01 20:03:32 +0000240 private static int checkBuf(byte[] buf, int w, int pitch, int h, int pf,
241 int subsamp, int scaleNum, int scaleDenom, int flags) throws Exception {
242 int roffset = TJ.getRedShift(pf) / 8;
243 int goffset = TJ.getGreenShift(pf) / 8;
244 int boffset = TJ.getBlueShift(pf) / 8;
245 int ps = TJ.getPixelSize(pf);
246 int i, _i, j, retval = 1;
247 int halfway = 16 * scaleNum / scaleDenom;
248 int blockSize = 8 * scaleNum / scaleDenom;
DRC3bad53f2011-02-23 02:20:49 +0000249
DRCf7f3ea42011-03-01 20:03:32 +0000250 try {
251 for(_i = 0; _i < halfway; _i++) {
DRC92549de2011-03-15 20:52:02 +0000252 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000253 else i = _i;
254 for(j = 0; j < w; j++) {
255 byte r = buf[pitch * i + j * ps + roffset];
256 byte g = buf[pitch * i + j * ps + goffset];
257 byte b = buf[pitch * i + j * ps + boffset];
258 if(((_i / blockSize) + (j / blockSize)) % 2 == 0) {
259 checkVal255(_i, j, r, "R");
260 checkVal255(_i, j, g, "G");
261 checkVal255(_i, j, b, "B");
262 }
263 else {
264 if(subsamp == TJ.SAMP_GRAY) {
265 checkVal(_i, j, r, "R", 76);
266 checkVal(_i, j, g, "G", 76);
267 checkVal(_i, j, b, "B", 76);
268 }
269 else {
270 checkVal255(_i, j, r, "R");
271 checkVal0(_i, j, g, "G");
272 checkVal0(_i, j, b, "B");
273 }
274 }
275 }
276 }
277 for(_i = halfway; _i < h; _i++) {
DRC92549de2011-03-15 20:52:02 +0000278 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000279 else i = _i;
280 for(j = 0; j < w; j++) {
281 byte r = buf[pitch * i + j * ps + roffset];
282 byte g = buf[pitch * i + j * ps + goffset];
283 byte b = buf[pitch * i + j * ps + boffset];
284 if(((_i / blockSize) + (j / blockSize)) % 2 == 0) {
285 checkVal0(_i, j, r, "R");
286 checkVal0(_i, j, g, "G");
287 }
288 else {
289 if(subsamp == TJ.SAMP_GRAY) {
290 checkVal(_i, j, r, "R", 226);
291 checkVal(_i, j, g, "G", 226);
292 checkVal(_i, j, b, "B", 226);
293 }
294 else {
295 checkVal255(_i, j, r, "R");
296 checkVal255(_i, j, g, "G");
297 checkVal0(_i, j, b, "B");
298 }
299 }
300 }
301 }
302 }
303 catch(Exception e) {
304 System.out.println(e);
305 retval = 0;
306 }
DRC4f1580c2011-02-25 06:11:03 +0000307
DRCf7f3ea42011-03-01 20:03:32 +0000308 if(retval == 0) {
309 System.out.print("\n");
310 for(i = 0; i < h; i++) {
311 for(j = 0; j < w; j++) {
312 int r = buf[pitch * i + j * ps + roffset];
313 int g = buf[pitch * i + j * ps + goffset];
314 int b = buf[pitch * i + j * ps + boffset];
315 if(r < 0) r += 256; if(g < 0) g += 256; if(b < 0) b += 256;
316 System.out.format("%3d/%3d/%3d ", r, g, b);
317 }
318 System.out.print("\n");
319 }
320 }
321 return retval;
322 }
DRC4f1580c2011-02-25 06:11:03 +0000323
DRCf7f3ea42011-03-01 20:03:32 +0000324 private static int checkIntBuf(int[] buf, int w, int pitch, int h, int pf,
325 int subsamp, int scaleNum, int scaleDenom, int flags) throws Exception {
326 int rshift = TJ.getRedShift(pf);
327 int gshift = TJ.getGreenShift(pf);
328 int bshift = TJ.getBlueShift(pf);
329 int i, _i, j, retval = 1;
330 int halfway = 16 * scaleNum / scaleDenom;
331 int blockSize = 8 * scaleNum / scaleDenom;
DRC4f1580c2011-02-25 06:11:03 +0000332
DRCf7f3ea42011-03-01 20:03:32 +0000333 try {
334 for(_i = 0; _i < halfway; _i++) {
DRC92549de2011-03-15 20:52:02 +0000335 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000336 else i = _i;
337 for(j = 0; j < w; j++) {
338 int r = (buf[pitch * i + j] >> rshift) & 0xFF;
339 int g = (buf[pitch * i + j] >> gshift) & 0xFF;
340 int b = (buf[pitch * i + j] >> bshift) & 0xFF;
341 if(((_i / blockSize) + (j / blockSize)) % 2 == 0) {
342 checkVal255(_i, j, r, "R");
343 checkVal255(_i, j, g, "G");
344 checkVal255(_i, j, b, "B");
345 }
346 else {
347 if(subsamp == TJ.SAMP_GRAY) {
348 checkVal(_i, j, r, "R", 76);
349 checkVal(_i, j, g, "G", 76);
350 checkVal(_i, j, b, "B", 76);
351 }
352 else {
353 checkVal255(_i, j, r, "R");
354 checkVal0(_i, j, g, "G");
355 checkVal0(_i, j, b, "B");
356 }
357 }
358 }
359 }
360 for(_i = halfway; _i < h; _i++) {
DRC92549de2011-03-15 20:52:02 +0000361 if((flags & TJ.FLAG_BOTTOMUP) != 0) i = h - _i - 1;
DRCf7f3ea42011-03-01 20:03:32 +0000362 else i = _i;
363 for(j = 0; j < w; j++) {
364 int r = (buf[pitch * i + j] >> rshift) & 0xFF;
365 int g = (buf[pitch * i + j] >> gshift) & 0xFF;
366 int b = (buf[pitch * i + j] >> bshift) & 0xFF;
367 if(((_i / blockSize) + (j / blockSize)) % 2 == 0) {
368 checkVal0(_i, j, r, "R");
369 checkVal0(_i, j, g, "G");
370 }
371 else {
372 if(subsamp == TJ.SAMP_GRAY) {
373 checkVal(_i, j, r, "R", 226);
374 checkVal(_i, j, g, "G", 226);
375 checkVal(_i, j, b, "B", 226);
376 }
377 else {
378 checkVal255(_i, j, r, "R");
379 checkVal255(_i, j, g, "G");
380 checkVal0(_i, j, b, "B");
381 }
382 }
383 }
384 }
385 }
386 catch(Exception e) {
387 System.out.println(e);
388 retval = 0;
389 }
DRC4f1580c2011-02-25 06:11:03 +0000390
DRCf7f3ea42011-03-01 20:03:32 +0000391 if(retval == 0) {
392 System.out.print("\n");
393 for(i = 0; i < h; i++) {
394 for(j = 0; j < w; j++) {
395 int r = (buf[pitch * i + j] >> rshift) & 0xFF;
396 int g = (buf[pitch * i + j] >> gshift) & 0xFF;
397 int b = (buf[pitch * i + j] >> bshift) & 0xFF;
398 if(r < 0) r += 256; if(g < 0) g += 256; if(b < 0) b += 256;
399 System.out.format("%3d/%3d/%3d ", r, g, b);
400 }
401 System.out.print("\n");
402 }
403 }
404 return retval;
405 }
DRC3bad53f2011-02-23 02:20:49 +0000406
DRCf7f3ea42011-03-01 20:03:32 +0000407 private static int checkImg(BufferedImage img, int pf,
408 int subsamp, int scaleNum, int scaleDenom, int flags) throws Exception {
409 WritableRaster wr = img.getRaster();
410 int imgtype = img.getType();
411 if(imgtype == BufferedImage.TYPE_INT_RGB
412 || imgtype == BufferedImage.TYPE_INT_BGR) {
413 SinglePixelPackedSampleModel sm =
414 (SinglePixelPackedSampleModel)img.getSampleModel();
415 int pitch = sm.getScanlineStride();
416 DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
417 int[] buf = db.getData();
418 return checkIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf,
419 subsamp, scaleNum, scaleDenom, flags);
420 }
421 else {
422 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
423 int pitch = sm.getScanlineStride();
424 DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
425 byte[] buf = db.getData();
426 return checkBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp,
427 scaleNum, scaleDenom, flags);
428 }
429 }
DRC84a1bcc2011-02-23 12:09:56 +0000430
DRCf7f3ea42011-03-01 20:03:32 +0000431 private static int PAD(int v, int p) {
432 return ((v + (p) - 1) & (~((p) - 1)));
433 }
DRC3bad53f2011-02-23 02:20:49 +0000434
DRCf7f3ea42011-03-01 20:03:32 +0000435 private static int checkBufYUV(byte[] buf, int size, int w, int h,
DRCd0a81362011-03-04 13:04:24 +0000436 int subsamp) throws Exception {
DRCf7f3ea42011-03-01 20:03:32 +0000437 int i, j;
DRCd0a81362011-03-04 13:04:24 +0000438 int hsf = TJ.getMCUWidth(subsamp)/8, vsf = TJ.getMCUHeight(subsamp)/8;
DRCf7f3ea42011-03-01 20:03:32 +0000439 int pw = PAD(w, hsf), ph = PAD(h, vsf);
440 int cw = pw / hsf, ch = ph / vsf;
441 int ypitch = PAD(pw, 4), uvpitch = PAD(cw, 4);
442 int retval = 1;
443 int correctsize = ypitch * ph
444 + (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2);
DRC3bad53f2011-02-23 02:20:49 +0000445
DRCf7f3ea42011-03-01 20:03:32 +0000446 try {
447 if(size != correctsize)
448 throw new Exception("\nIncorrect size " + size + ". Should be "
449 + correctsize);
DRC3bad53f2011-02-23 02:20:49 +0000450
DRCf7f3ea42011-03-01 20:03:32 +0000451 for(i = 0; i < 16; i++) {
452 for(j = 0; j < pw; j++) {
453 byte y = buf[ypitch * i + j];
454 if(((i / 8) + (j / 8)) % 2 == 0) checkVal255(i, j, y, "Y");
455 else checkVal(i, j, y, "Y", 76);
456 }
457 }
458 for(i = 16; i < ph; i++) {
459 for(j = 0; j < pw; j++) {
460 byte y = buf[ypitch * i + j];
461 if(((i / 8) + (j / 8)) % 2 == 0) checkVal0(i, j, y, "Y");
462 else checkVal(i, j, y, "Y", 226);
463 }
464 }
465 if(subsamp != TJ.SAMP_GRAY) {
466 for(i = 0; i < 16 / vsf; i++) {
467 for(j = 0; j < cw; j++) {
468 byte u = buf[ypitch * ph + (uvpitch * i + j)],
469 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * i + j)];
470 if(((i * vsf / 8) + (j * hsf / 8)) % 2 == 0) {
471 checkVal(i, j, u, "U", 128); checkVal(i, j, v, "V", 128);
472 }
473 else {
474 checkVal(i, j, u, "U", 85); checkVal255(i, j, v, "V");
475 }
476 }
477 }
478 for(i = 16 / vsf; i < ch; i++) {
479 for(j = 0; j < cw; j++) {
480 byte u = buf[ypitch * ph + (uvpitch * i + j)],
481 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * i + j)];
482 if(((i * vsf / 8) + (j * hsf / 8)) % 2 == 0) {
483 checkVal(i, j, u, "U", 128); checkVal(i, j, v, "V", 128);
484 }
485 else {
486 checkVal0(i, j, u, "U"); checkVal(i, j, v, "V", 149);
487 }
488 }
489 }
490 }
491 }
492 catch(Exception e) {
493 System.out.println(e);
494 retval = 0;
495 }
DRC3bad53f2011-02-23 02:20:49 +0000496
DRCf7f3ea42011-03-01 20:03:32 +0000497 if(retval == 0) {
498 for(i = 0; i < ph; i++) {
499 for(j = 0; j < pw; j++) {
500 int y = buf[ypitch * i + j];
501 if(y < 0) y += 256;
502 System.out.format("%3d ", y);
503 }
504 System.out.print("\n");
505 }
506 System.out.print("\n");
507 for(i = 0; i < ch; i++) {
508 for(j = 0; j < cw; j++) {
509 int u = buf[ypitch * ph + (uvpitch * i + j)];
510 if(u < 0) u += 256;
511 System.out.format("%3d ", u);
512 }
513 System.out.print("\n");
514 }
515 System.out.print("\n");
516 for(i = 0; i < ch; i++) {
517 for(j = 0; j < cw; j++) {
518 int v = buf[ypitch * ph + uvpitch * ch + (uvpitch * i + j)];
519 if(v < 0) v += 256;
520 System.out.format("%3d ", v);
521 }
522 System.out.print("\n");
523 }
524 System.out.print("\n");
525 }
DRC3bad53f2011-02-23 02:20:49 +0000526
DRCf7f3ea42011-03-01 20:03:32 +0000527 return retval;
528 }
DRC3bad53f2011-02-23 02:20:49 +0000529
DRCf7f3ea42011-03-01 20:03:32 +0000530 private static void writeJPEG(byte[] jpegBuf, int jpegBufSize,
531 String filename) throws Exception {
532 File file = new File(filename);
533 FileOutputStream fos = new FileOutputStream(file);
534 fos.write(jpegBuf, 0, jpegBufSize);
535 fos.close();
536 }
DRC3bad53f2011-02-23 02:20:49 +0000537
DRCf7f3ea42011-03-01 20:03:32 +0000538 private static int genTestJPEG(TJCompressor tjc, byte[] jpegBuf, int w,
539 int h, int pf, String baseFilename, int subsamp, int qual,
540 int flags) throws Exception {
541 String tempstr;
542 byte[] bmpBuf = null;
543 BufferedImage img = null;
544 String pfStr;
545 double t;
546 int size = 0, ps = TJ.getPixelSize(pf);
DRC3bad53f2011-02-23 02:20:49 +0000547
DRCf7f3ea42011-03-01 20:03:32 +0000548 pfStr = pixFormatStr[pf];
DRC3bad53f2011-02-23 02:20:49 +0000549
DRCf7f3ea42011-03-01 20:03:32 +0000550 System.out.print(pfStr + " ");
DRC92549de2011-03-15 20:52:02 +0000551 if((flags & TJ.FLAG_BOTTOMUP) != 0) System.out.print("Bottom-Up");
DRCf7f3ea42011-03-01 20:03:32 +0000552 else System.out.print("Top-Down ");
553 System.out.print(" -> " + subNameLong[subsamp] + " ");
554 if(yuv == YUVENCODE) System.out.print("YUV ... ");
555 else System.out.print("Q" + qual + " ... ");
DRC3bad53f2011-02-23 02:20:49 +0000556
DRCf7f3ea42011-03-01 20:03:32 +0000557 if(bi) {
558 img = new BufferedImage(w, h, biType[pf]);
559 initImg(img, pf, flags);
560 tempstr = baseFilename + "_enc_" + pfStr + "_"
DRC92549de2011-03-15 20:52:02 +0000561 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
DRCf7f3ea42011-03-01 20:03:32 +0000562 + subName[subsamp] + "_Q" + qual + ".png";
563 File file = new File(tempstr);
564 ImageIO.write(img, "png", file);
565 }
566 else {
567 bmpBuf = new byte[w * h * ps + 1];
568 initBuf(bmpBuf, w, w * ps, h, pf, flags);
569 }
570 Arrays.fill(jpegBuf, (byte)0);
DRC3bad53f2011-02-23 02:20:49 +0000571
DRCf7f3ea42011-03-01 20:03:32 +0000572 t = getTime();
573 tjc.setSubsamp(subsamp);
574 tjc.setJPEGQuality(qual);
575 if(bi) {
576 if(yuv == YUVENCODE) tjc.encodeYUV(img, jpegBuf, flags);
577 else tjc.compress(img, jpegBuf, flags);
578 }
579 else {
580 tjc.setBitmapBuffer(bmpBuf, w, 0, h, pf);
581 if(yuv == YUVENCODE) tjc.encodeYUV(jpegBuf, flags);
582 else tjc.compress(jpegBuf, flags);
583 }
584 size = tjc.getCompressedSize();
585 t = getTime() - t;
DRC3bad53f2011-02-23 02:20:49 +0000586
DRCf7f3ea42011-03-01 20:03:32 +0000587 if(yuv == YUVENCODE)
588 tempstr = baseFilename + "_enc_" + pfStr + "_"
DRC92549de2011-03-15 20:52:02 +0000589 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
DRCf7f3ea42011-03-01 20:03:32 +0000590 + subName[subsamp] + ".yuv";
591 else
592 tempstr = baseFilename + "_enc_" + pfStr + "_"
DRC92549de2011-03-15 20:52:02 +0000593 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
DRCf7f3ea42011-03-01 20:03:32 +0000594 + subName[subsamp] + "_Q" + qual + ".jpg";
595 writeJPEG(jpegBuf, size, tempstr);
DRC84a1bcc2011-02-23 12:09:56 +0000596
DRCf7f3ea42011-03-01 20:03:32 +0000597 if(yuv == YUVENCODE) {
598 if(checkBufYUV(jpegBuf, size, w, h, subsamp) == 1)
599 System.out.print("Passed.");
600 else {
601 System.out.print("FAILED!"); exitStatus = -1;
602 }
603 }
604 else System.out.print("Done.");
605 System.out.format(" %.6f ms\n", t * 1000.);
606 System.out.println(" Result in " + tempstr);
DRC3bad53f2011-02-23 02:20:49 +0000607
DRCf7f3ea42011-03-01 20:03:32 +0000608 return size;
609 }
DRC3bad53f2011-02-23 02:20:49 +0000610
DRCf7f3ea42011-03-01 20:03:32 +0000611 private static void genTestBMP(TJDecompressor tjd, byte[] jpegBuf,
612 int jpegsize, int w, int h, int pf, String baseFilename, int subsamp,
613 int flags, int scaleNum, int scaleDenom) throws Exception {
614 String pfStr, tempstr;
615 double t;
616 int scaledWidth = (w * scaleNum + scaleDenom - 1) / scaleDenom;
617 int scaledHeight = (h * scaleNum + scaleDenom - 1) / scaleDenom;
618 int temp1, temp2;
619 BufferedImage img = null;
620 byte[] bmpBuf = null;
DRC3bad53f2011-02-23 02:20:49 +0000621
DRCf7f3ea42011-03-01 20:03:32 +0000622 if(yuv == YUVENCODE) return;
DRC3bad53f2011-02-23 02:20:49 +0000623
DRCf7f3ea42011-03-01 20:03:32 +0000624 pfStr = pixFormatStr[pf];
625 System.out.print("JPEG -> ");
626 if(yuv == YUVDECODE)
627 System.out.print("YUV " + subName[subsamp] + " ... ");
628 else {
629 System.out.print(pfStr + " ");
DRC92549de2011-03-15 20:52:02 +0000630 if((flags & TJ.FLAG_BOTTOMUP) != 0) System.out.print("Bottom-Up ");
DRCf7f3ea42011-03-01 20:03:32 +0000631 else System.out.print("Top-Down ");
632 if(scaleNum != 1 || scaleDenom != 1)
633 System.out.print(scaleNum + "/" + scaleDenom + " ... ");
634 else System.out.print("... ");
635 }
DRC3bad53f2011-02-23 02:20:49 +0000636
DRCf7f3ea42011-03-01 20:03:32 +0000637 t = getTime();
638 tjd.setJPEGBuffer(jpegBuf, jpegsize);
639 if(tjd.getWidth() != w || tjd.getHeight() != h
640 || tjd.getSubsamp() != subsamp)
641 throw new Exception("Incorrect JPEG header");
DRC3bad53f2011-02-23 02:20:49 +0000642
DRCf7f3ea42011-03-01 20:03:32 +0000643 temp1 = scaledWidth;
644 temp2 = scaledHeight;
645 temp1 = tjd.getScaledWidth(temp1, temp2);
646 temp2 = tjd.getScaledHeight(temp1, temp2);
647 if(temp1 != scaledWidth || temp2 != scaledHeight)
648 throw new Exception("Scaled size mismatch");
DRC3bad53f2011-02-23 02:20:49 +0000649
DRCf7f3ea42011-03-01 20:03:32 +0000650 if(yuv == YUVDECODE) bmpBuf = tjd.decompressToYUV(flags);
651 else {
652 if(bi)
653 img = tjd.decompress(scaledWidth, scaledHeight, biType[pf], flags);
654 else bmpBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags);
655 }
656 t = getTime() - t;
DRC3bad53f2011-02-23 02:20:49 +0000657
DRCf7f3ea42011-03-01 20:03:32 +0000658 if(bi) {
659 tempstr = baseFilename + "_dec_" + pfStr + "_"
DRC92549de2011-03-15 20:52:02 +0000660 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
DRCf7f3ea42011-03-01 20:03:32 +0000661 + subName[subsamp] + "_" + (double)scaleNum / (double)scaleDenom
662 + "x" + ".png";
663 File file = new File(tempstr);
664 ImageIO.write(img, "png", file);
665 }
DRC84a1bcc2011-02-23 12:09:56 +0000666
DRCf7f3ea42011-03-01 20:03:32 +0000667 if(yuv == YUVDECODE) {
668 if(checkBufYUV(bmpBuf, bmpBuf.length, w, h, subsamp) == 1)
669 System.out.print("Passed.");
670 else {
671 System.out.print("FAILED!"); exitStatus = -1;
672 }
673 }
674 else {
675 if((bi && checkImg(img, pf, subsamp, scaleNum, scaleDenom, flags) == 1)
676 || (!bi && checkBuf(bmpBuf, scaledWidth, scaledWidth
677 * TJ.getPixelSize(pf), scaledHeight, pf, subsamp, scaleNum,
678 scaleDenom, flags) == 1))
679 System.out.print("Passed.");
680 else {
681 System.out.print("FAILED!"); exitStatus = -1;
682 }
683 }
684 System.out.format(" %.6f ms\n", t * 1000.);
685 }
DRC3bad53f2011-02-23 02:20:49 +0000686
DRCf7f3ea42011-03-01 20:03:32 +0000687 private static void genTestBMP(TJDecompressor tjd, byte[] jpegBuf,
688 int jpegsize, int w, int h, int pf, String baseFilename, int subsamp,
689 int flags) throws Exception {
690 int i;
691 if((subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY) && yuv == 0) {
692 TJ.ScalingFactor sf[] = TJ.getScalingFactors();
693 for(i = 0; i < sf.length; i++)
694 genTestBMP(tjd, jpegBuf, jpegsize, w, h, pf, baseFilename, subsamp,
695 flags, sf[i].num, sf[i].denom);
696 }
697 else
698 genTestBMP(tjd, jpegBuf, jpegsize, w, h, pf, baseFilename, subsamp,
699 flags, 1, 1);
700 System.out.print("\n");
701 }
DRC3bad53f2011-02-23 02:20:49 +0000702
DRCf7f3ea42011-03-01 20:03:32 +0000703 private static void doTest(int w, int h, int[] formats, int subsamp,
704 String baseFilename) throws Exception {
705 TJCompressor tjc = null;
706 TJDecompressor tjd = null;
707 int size, pfstart, pfend;
708 byte[] jpegBuf;
DRC3bad53f2011-02-23 02:20:49 +0000709
DRCf7f3ea42011-03-01 20:03:32 +0000710 if(yuv == YUVENCODE) jpegBuf = new byte[TJ.bufSizeYUV(w, h, subsamp)];
711 else jpegBuf = new byte[TJ.bufSize(w, h)];
DRC3bad53f2011-02-23 02:20:49 +0000712
DRCf7f3ea42011-03-01 20:03:32 +0000713 try {
714 tjc = new TJCompressor();
715 tjd = new TJDecompressor();
DRC3bad53f2011-02-23 02:20:49 +0000716
DRCf7f3ea42011-03-01 20:03:32 +0000717 for(int pf : formats) {
718 for(int i = 0; i < 2; i++) {
719 int flags = 0;
720 if(i == 1) {
721 if(yuv == YUVDECODE) {
722 tjc.close(); tjd.close(); return;
723 }
DRC92549de2011-03-15 20:52:02 +0000724 else flags |= TJ.FLAG_BOTTOMUP;
DRCf7f3ea42011-03-01 20:03:32 +0000725 }
726 size = genTestJPEG(tjc, jpegBuf, w, h, pf, baseFilename, subsamp,
727 100, flags);
728 genTestBMP(tjd, jpegBuf, size, w, h, pf, baseFilename, subsamp,
729 flags);
730 }
731 }
732 }
733 catch(Exception e) {
734 if(tjc != null) tjc.close();
735 if(tjd != null) tjd.close();
736 throw e;
737 }
738 if(tjc != null) tjc.close();
739 if(tjd != null) tjd.close();
740 }
DRC3bad53f2011-02-23 02:20:49 +0000741
DRCf7f3ea42011-03-01 20:03:32 +0000742 private final static int MAXLENGTH = 2048;
DRC3bad53f2011-02-23 02:20:49 +0000743
DRCf7f3ea42011-03-01 20:03:32 +0000744 private static void doTest1() throws Exception {
745 int i, j, i2;
746 byte[] bmpBuf, jpegBuf;
747 TJCompressor tjc = null;
DRC3bad53f2011-02-23 02:20:49 +0000748
DRCf7f3ea42011-03-01 20:03:32 +0000749 try {
750 tjc = new TJCompressor();
751 System.out.println("Buffer size regression test");
752 for(j = 1; j < 48; j++) {
753 for(i = 1; i < (j == 1 ? MAXLENGTH : 48); i++) {
754 if(i % 100 == 0)
755 System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", i, j);
756 bmpBuf = new byte[i * j * 4];
757 jpegBuf = new byte[TJ.bufSize(i, j)];
758 Arrays.fill(bmpBuf, (byte)0);
759 for(i2 = 0; i2 < i * j; i2++) {
760 bmpBuf[i2 * 4] = pixels[i2 % 9][2];
761 bmpBuf[i2 * 4 + 1] = pixels[i2 % 9][1];
762 bmpBuf[i2 * 4 + 2] = pixels[i2 % 9][0];
763 }
764 tjc.setBitmapBuffer(bmpBuf, i, 0, j, TJ.PF_BGRX);
765 tjc.setSubsamp(TJ.SAMP_444);
766 tjc.setJPEGQuality(100);
767 tjc.compress(jpegBuf, 0);
DRC3bad53f2011-02-23 02:20:49 +0000768
DRCf7f3ea42011-03-01 20:03:32 +0000769 bmpBuf = new byte[j * i * 4];
770 jpegBuf = new byte[TJ.bufSize(j, i)];
771 for(i2 = 0; i2 < j * i; i2++) {
772 if(i2 % 2 == 0) bmpBuf[i2 * 4] =
773 bmpBuf[i2 * 4 + 1] = bmpBuf[i2 * 4 + 2] = (byte)0xFF;
774 else bmpBuf[i2 * 4] = bmpBuf[i2 * 4 + 1] = bmpBuf[i2 * 4 + 2] = 0;
775 }
776 tjc.setBitmapBuffer(bmpBuf, j, 0, i, TJ.PF_BGRX);
777 tjc.compress(jpegBuf, 0);
778 }
779 }
780 System.out.println("Done. ");
781 }
782 catch(Exception e) {
783 if(tjc != null) tjc.close();
784 throw e;
785 }
786 if(tjc != null) tjc.close();
787 }
DRC3bad53f2011-02-23 02:20:49 +0000788
DRCf7f3ea42011-03-01 20:03:32 +0000789 public static void main(String argv[]) {
790 try {
791 boolean doyuv = false;
792 for(int i = 0; i < argv.length; i++) {
793 if(argv[i].equalsIgnoreCase("-yuv")) doyuv = true;
794 if(argv[i].substring(0, 1).equalsIgnoreCase("-h")
795 || argv[i].equalsIgnoreCase("-?"))
796 usage();
797 if(argv[i].equalsIgnoreCase("-bi")) bi = true;
798 }
799 if(doyuv) yuv = YUVENCODE;
800 doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_444, "test");
801 doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_444, "test");
802 if(doyuv) {
803 doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_422,
804 "test");
805 doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_422,
806 "test");
807 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_420,
808 "test");
809 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_420,
810 "test");
DRCd0a81362011-03-04 13:04:24 +0000811 doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_440,
812 "test");
813 doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_440,
814 "test");
DRCf7f3ea42011-03-01 20:03:32 +0000815 }
816 doTest(35, 39, onlyGray, TJ.SAMP_GRAY, "test");
817 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_GRAY,
818 "test");
819 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY,
820 "test");
821 if(!doyuv && !bi) doTest1();
822 if(doyuv && !bi) {
823 yuv = YUVDECODE;
824 doTest(48, 48, onlyRGB, TJ.SAMP_444, "test");
825 doTest(35, 39, onlyRGB, TJ.SAMP_444, "test");
826 doTest(48, 48, onlyRGB, TJ.SAMP_422, "test");
827 doTest(39, 41, onlyRGB, TJ.SAMP_422, "test");
828 doTest(48, 48, onlyRGB, TJ.SAMP_420, "test");
829 doTest(41, 35, onlyRGB, TJ.SAMP_420, "test");
DRCd0a81362011-03-04 13:04:24 +0000830 doTest(48, 48, onlyRGB, TJ.SAMP_440, "test");
831 doTest(35, 39, onlyRGB, TJ.SAMP_440, "test");
DRCf7f3ea42011-03-01 20:03:32 +0000832 doTest(48, 48, onlyRGB, TJ.SAMP_GRAY, "test");
833 doTest(35, 39, onlyRGB, TJ.SAMP_GRAY, "test");
834 doTest(48, 48, onlyGray, TJ.SAMP_GRAY, "test");
835 doTest(39, 41, onlyGray, TJ.SAMP_GRAY, "test");
836 }
837 }
838 catch(Exception e) {
DRC2e2358e2011-03-04 09:54:59 +0000839 e.printStackTrace();
DRCf7f3ea42011-03-01 20:03:32 +0000840 exitStatus = -1;
841 }
842 System.exit(exitStatus);
843 }
DRC3bad53f2011-02-23 02:20:49 +0000844}