b88b28edd5bb3f24901d4a942d83c008374aea05
[platform/upstream/libjpeg-turbo.git] / java / TJUnitTest.java
1 /*
2  * Copyright (C)2011-2012 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
33 import java.io.*;
34 import java.util.*;
35 import java.awt.image.*;
36 import javax.imageio.*;
37 import java.nio.*;
38 import org.libjpegturbo.turbojpeg.*;
39
40 public class TJUnitTest {
41
42   private static final String classname =
43     new TJUnitTest().getClass().getName();
44
45   private static void usage() {
46     System.out.println("\nUSAGE: java " + classname + " [options]\n");
47     System.out.println("Options:\n");
48     System.out.println("-yuv = test YUV encoding/decoding support\n");
49     System.out.println("-bi = test BufferedImage support\n");
50     System.exit(1);
51   }
52
53   private final static String subNameLong[] = {
54     "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0"
55   };
56   private final static String subName[] = {
57     "444", "422", "420", "GRAY", "440"
58   };
59
60   private final static String pixFormatStr[] = {
61     "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
62     "RGBA", "BGRA", "ABGR", "ARGB"
63   };
64
65   private final static int alphaOffset[] = {
66     -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0
67   };
68
69   private final static int _3byteFormats[] = {
70     TJ.PF_RGB, TJ.PF_BGR
71   };
72   private final static int _3byteFormatsBI[] = {
73     BufferedImage.TYPE_3BYTE_BGR
74   };
75   private final static int _4byteFormats[] = {
76     TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB
77   };
78   private final static int _4byteFormatsBI[] = {
79     BufferedImage.TYPE_INT_BGR, BufferedImage.TYPE_INT_RGB,
80     BufferedImage.TYPE_4BYTE_ABGR, BufferedImage.TYPE_4BYTE_ABGR_PRE,
81     BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_INT_ARGB_PRE
82   };
83   private final static int onlyGray[] = {
84     TJ.PF_GRAY
85   };
86   private final static int onlyGrayBI[] = {
87     BufferedImage.TYPE_BYTE_GRAY
88   };
89   private final static int onlyRGB[] = {
90     TJ.PF_RGB
91   };
92
93   private final static int YUVENCODE = 1;
94   private final static int YUVDECODE = 2;
95   private static int yuv = 0;
96   private static boolean bi = false;
97
98   private static int exitStatus = 0;
99
100   private static int biTypePF(int biType) {
101     ByteOrder byteOrder = ByteOrder.nativeOrder();
102     switch(biType) {
103       case BufferedImage.TYPE_3BYTE_BGR:
104         return TJ.PF_BGR;
105       case BufferedImage.TYPE_4BYTE_ABGR:
106       case BufferedImage.TYPE_4BYTE_ABGR_PRE:
107         return TJ.PF_XBGR;
108       case BufferedImage.TYPE_BYTE_GRAY:
109         return TJ.PF_GRAY;
110       case BufferedImage.TYPE_INT_BGR:
111         if(byteOrder == ByteOrder.BIG_ENDIAN)
112           return TJ.PF_XBGR;
113         else
114           return TJ.PF_RGBX;
115       case BufferedImage.TYPE_INT_RGB:
116         if(byteOrder == ByteOrder.BIG_ENDIAN)
117           return TJ.PF_XRGB;
118         else
119           return TJ.PF_BGRX;
120       case BufferedImage.TYPE_INT_ARGB:
121       case BufferedImage.TYPE_INT_ARGB_PRE:
122         if(byteOrder == ByteOrder.BIG_ENDIAN)
123           return TJ.PF_ARGB;
124         else
125           return TJ.PF_BGRA;
126     }
127     return 0;
128   }
129
130   private static String biTypeStr(int biType) {
131     switch(biType) {
132       case BufferedImage.TYPE_3BYTE_BGR:
133         return "3BYTE_BGR";
134       case BufferedImage.TYPE_4BYTE_ABGR:
135         return "4BYTE_ABGR";
136       case BufferedImage.TYPE_4BYTE_ABGR_PRE:
137         return "4BYTE_ABGR_PRE";
138       case BufferedImage.TYPE_BYTE_GRAY:
139         return "BYTE_GRAY";
140       case BufferedImage.TYPE_INT_BGR:
141         return "INT_BGR";
142       case BufferedImage.TYPE_INT_RGB:
143         return "INT_RGB";
144       case BufferedImage.TYPE_INT_ARGB:
145         return "INT_ARGB";
146       case BufferedImage.TYPE_INT_ARGB_PRE:
147         return "INT_ARGB_PRE";
148     }
149     return "Unknown";
150   }
151   
152
153   private static double getTime() {
154     return (double)System.nanoTime() / 1.0e9;
155   }
156
157   private static void initBuf(byte[] buf, int w, int pitch, int h, int pf,
158     int flags) throws Exception {
159     int roffset = TJ.getRedOffset(pf);
160     int goffset = TJ.getGreenOffset(pf);
161     int boffset = TJ.getBlueOffset(pf);
162     int aoffset = alphaOffset[pf];
163     int ps = TJ.getPixelSize(pf);
164     int index, row, col, halfway = 16;
165
166     Arrays.fill(buf, (byte)0);
167     if(pf == TJ.PF_GRAY) {
168       for(row = 0; row < h; row++) {
169         for(col = 0; col < w; col++) {
170           if((flags & TJ.FLAG_BOTTOMUP) != 0)
171             index = pitch * (h - row - 1) + col;
172           else index = pitch * row + col;
173           if(((row / 8) + (col / 8)) % 2 == 0)
174             buf[index] = (row < halfway) ? (byte)255 : 0;
175           else buf[index] = (row < halfway) ? 76 : (byte)226;
176         }
177       }
178       return;
179     }
180     for(row = 0; row < h; row++) {
181       for(col = 0; col < w; col++) {
182         if((flags & TJ.FLAG_BOTTOMUP) != 0)
183           index = pitch * (h - row - 1) + col * ps;
184         else index = pitch * row + col * ps;
185         if(((row / 8) + (col / 8)) % 2 == 0) {
186           if(row < halfway) {
187             buf[index + roffset] = (byte)255;
188             buf[index + goffset] = (byte)255;
189             buf[index + boffset] = (byte)255;
190           }
191         }
192         else {
193           buf[index + roffset] = (byte)255;
194           if(row >= halfway) buf[index + goffset] = (byte)255;
195         }
196         if (aoffset >= 0) buf[index + aoffset] = (byte)255;
197       }
198     }
199   }
200
201   private static void initIntBuf(int[] buf, int w, int pitch, int h, int pf,
202     int flags) throws Exception {
203     int rshift = TJ.getRedOffset(pf) * 8;
204     int gshift = TJ.getGreenOffset(pf) * 8;
205     int bshift = TJ.getBlueOffset(pf) * 8;
206     int ashift = alphaOffset[pf] * 8;
207     int index, row, col, halfway = 16;
208
209     Arrays.fill(buf, 0);
210     for(row = 0; row < h; row++) {
211       for(col = 0; col < w; col++) {
212         if((flags & TJ.FLAG_BOTTOMUP) != 0)
213           index = pitch * (h - row - 1) + col;
214         else index = pitch * row + col;
215         if(((row / 8) + (col / 8)) % 2 == 0) {
216           if(row < halfway) {
217             buf[index] |= (255 << rshift);
218             buf[index] |= (255 << gshift);
219             buf[index] |= (255 << bshift);
220           }
221         }
222         else {
223           buf[index] |= (255 << rshift);
224           if(row >= halfway) buf[index] |= (255 << gshift);
225         }
226         if (ashift >= 0) buf[index] |= (255 << ashift);
227       }
228     }
229   }
230
231   private static void initImg(BufferedImage img, int pf, int flags)
232     throws Exception {
233     WritableRaster wr = img.getRaster();
234     int imgType = img.getType();
235     if(imgType == BufferedImage.TYPE_INT_RGB
236       || imgType == BufferedImage.TYPE_INT_BGR
237       || imgType == BufferedImage.TYPE_INT_ARGB
238       || imgType == BufferedImage.TYPE_INT_ARGB_PRE) {
239       SinglePixelPackedSampleModel sm =
240         (SinglePixelPackedSampleModel)img.getSampleModel();
241       int pitch = sm.getScanlineStride();
242       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
243       int[] buf = db.getData();
244       initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
245     }
246     else {
247       ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
248       int pitch = sm.getScanlineStride();
249       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
250       byte[] buf = db.getData();
251       initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
252     }
253   }
254
255   private static void checkVal(int row, int col, int v, String vname, int cv)
256     throws Exception {
257     v = (v < 0) ? v + 256 : v;
258     if(v < cv - 1 || v > cv + 1) {
259       throw new Exception("\nComp. " + vname + " at " + row + "," + col
260         + " should be " + cv + ", not " + v + "\n");
261     }
262   }
263
264   private static void checkVal0(int row, int col, int v, String vname)
265     throws Exception {
266     v = (v < 0) ? v + 256 : v;
267     if(v > 1) {
268       throw new Exception("\nComp. " + vname + " at " + row + "," + col
269         + " should be 0, not " + v + "\n");
270     }
271   }
272
273   private static void checkVal255(int row, int col, int v, String vname)
274     throws Exception {
275     v = (v < 0) ? v + 256 : v;
276     if(v < 254) {
277       throw new Exception("\nComp. " + vname + " at " + row + "," + col
278         + " should be 255, not " + v + "\n");
279     }
280   }
281
282   private static int checkBuf(byte[] buf, int w, int pitch, int h, int pf,
283     int subsamp, TJScalingFactor sf, int flags) throws Exception {
284     int roffset = TJ.getRedOffset(pf);
285     int goffset = TJ.getGreenOffset(pf);
286     int boffset = TJ.getBlueOffset(pf);
287     int aoffset = alphaOffset[pf];
288     int ps = TJ.getPixelSize(pf);
289     int index, row, col, retval = 1;
290     int halfway = 16 * sf.getNum() / sf.getDenom();
291     int blockSize = 8 * sf.getNum() / sf.getDenom();
292
293     try {
294       for(row = 0; row < halfway; row++) {
295         for(col = 0; col < w; col++) {
296           if((flags & TJ.FLAG_BOTTOMUP) != 0)
297             index = pitch * (h - row - 1) + col * ps;
298           else index = pitch * row + col * ps;
299           byte r = buf[index + roffset];
300           byte g = buf[index + goffset];
301           byte b = buf[index + boffset];
302           byte a = aoffset >= 0 ? buf[index + aoffset] : (byte)255;
303           if(((row / blockSize) + (col / blockSize)) % 2 == 0) {
304             if(row < halfway) {
305               checkVal255(row, col, r, "R");
306               checkVal255(row, col, g, "G");
307               checkVal255(row, col, b, "B");
308             }
309             else {
310               checkVal0(row, col, r, "R");
311               checkVal0(row, col, g, "G");
312               checkVal0(row, col, b, "B");
313             }
314           }
315           else {
316             if(subsamp == TJ.SAMP_GRAY) {
317               if(row < halfway) {
318                 checkVal(row, col, r, "R", 76);
319                 checkVal(row, col, g, "G", 76);
320                 checkVal(row, col, b, "B", 76);
321               }
322               else {
323                 checkVal(row, col, r, "R", 226);
324                 checkVal(row, col, g, "G", 226);
325                 checkVal(row, col, b, "B", 226);
326               }
327             }
328             else {
329               checkVal255(row, col, r, "R");
330               if(row < halfway) {
331                 checkVal0(row, col, g, "G");
332               }
333               else {
334                 checkVal255(row, col, g, "G");
335               }
336               checkVal0(row, col, b, "B");                                                      
337             }
338           }
339           checkVal255(row, col, a, "A");
340         }
341       }
342     }
343     catch(Exception e) {
344       System.out.println(e);
345       retval = 0;
346     }
347
348     if(retval == 0) {
349       System.out.print("\n");
350       for(row = 0; row < h; row++) {
351         for(col = 0; col < w; col++) {
352           int r = buf[pitch * row + col * ps + roffset];
353           int g = buf[pitch * row + col * ps + goffset];
354           int b = buf[pitch * row + col * ps + boffset];
355           if(r < 0) r += 256;  if(g < 0) g += 256;  if(b < 0) b += 256;
356           System.out.format("%3d/%3d/%3d ", r, g, b);
357         }
358         System.out.print("\n");
359       }
360     }
361     return retval;
362   }
363
364   private static int checkIntBuf(int[] buf, int w, int pitch, int h, int pf,
365     int subsamp, TJScalingFactor sf, int flags) throws Exception {
366     int rshift = TJ.getRedOffset(pf) * 8;
367     int gshift = TJ.getGreenOffset(pf) * 8;
368     int bshift = TJ.getBlueOffset(pf) * 8;
369     int ashift = alphaOffset[pf] * 8;
370     int index, row, col, retval = 1;
371     int halfway = 16 * sf.getNum() / sf.getDenom();
372     int blockSize = 8 * sf.getNum() / sf.getDenom();
373
374     try {
375       for(row = 0; row < halfway; row++) {
376         for(col = 0; col < w; col++) {
377           if((flags & TJ.FLAG_BOTTOMUP) != 0)
378             index = pitch * (h - row - 1) + col;
379           else index = pitch * row + col;
380           int r = (buf[index] >> rshift) & 0xFF;
381           int g = (buf[index] >> gshift) & 0xFF;
382           int b = (buf[index] >> bshift) & 0xFF;
383           int a = ashift >= 0 ? (buf[index] >> ashift) & 0xFF : 255;
384           if(((row / blockSize) + (col / blockSize)) % 2 == 0) {
385             if(row < halfway) {
386               checkVal255(row, col, r, "R");
387               checkVal255(row, col, g, "G");
388               checkVal255(row, col, b, "B");
389             }
390             else {
391               checkVal0(row, col, r, "R");
392               checkVal0(row, col, g, "G");
393               checkVal0(row, col, b, "B");
394             }
395           }
396           else {
397             if(subsamp == TJ.SAMP_GRAY) {
398               if(row < halfway) {
399                 checkVal(row, col, r, "R", 76);
400                 checkVal(row, col, g, "G", 76);
401                 checkVal(row, col, b, "B", 76);
402               }
403               else {
404                 checkVal(row, col, r, "R", 226);
405                 checkVal(row, col, g, "G", 226);
406                 checkVal(row, col, b, "B", 226);
407               }
408             }
409             else {
410               checkVal255(row, col, r, "R");
411               if(row < halfway) {
412                 checkVal0(row, col, g, "G");
413               }
414               else {
415                 checkVal255(row, col, g, "G");
416               }
417               checkVal0(row, col, b, "B");
418             }
419           }
420           checkVal255(row, col, a, "A");
421         }
422       }
423     }
424     catch(Exception e) {
425       System.out.println(e);
426       retval = 0;
427     }
428
429     if(retval == 0) {
430       System.out.print("\n");
431       for(row = 0; row < h; row++) {
432         for(col = 0; col < w; col++) {
433           int r = (buf[pitch * row + col] >> rshift) & 0xFF;
434           int g = (buf[pitch * row + col] >> gshift) & 0xFF;
435           int b = (buf[pitch * row + col] >> bshift) & 0xFF;
436           if(r < 0) r += 256;  if(g < 0) g += 256;  if(b < 0) b += 256;
437           System.out.format("%3d/%3d/%3d ", r, g, b);
438         }
439         System.out.print("\n");
440       }
441     }
442     return retval;
443   }
444
445   private static int checkImg(BufferedImage img, int pf,
446     int subsamp, TJScalingFactor sf, int flags) throws Exception {
447     WritableRaster wr = img.getRaster();
448     int imgType = img.getType();
449     if(imgType == BufferedImage.TYPE_INT_RGB
450       || imgType == BufferedImage.TYPE_INT_BGR
451       || imgType == BufferedImage.TYPE_INT_ARGB
452       || imgType == BufferedImage.TYPE_INT_ARGB_PRE) {
453        SinglePixelPackedSampleModel sm =
454         (SinglePixelPackedSampleModel)img.getSampleModel();
455       int pitch = sm.getScanlineStride();
456       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
457       int[] buf = db.getData();
458       return checkIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf,
459         subsamp, sf, flags);
460     }
461     else {
462       ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
463       int pitch = sm.getScanlineStride();
464       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
465       byte[] buf = db.getData();
466       return checkBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp,
467         sf, flags);
468     }
469   }
470
471   private static int PAD(int v, int p) {
472     return ((v + (p) - 1) & (~((p) - 1)));
473   }
474
475   private static int checkBufYUV(byte[] buf, int size, int w, int h,
476     int subsamp) throws Exception {
477     int row, col;
478     int hsf = TJ.getMCUWidth(subsamp)/8, vsf = TJ.getMCUHeight(subsamp)/8;
479     int pw = PAD(w, hsf), ph = PAD(h, vsf);
480     int cw = pw / hsf, ch = ph / vsf;
481     int ypitch = PAD(pw, 4), uvpitch = PAD(cw, 4);
482     int retval = 1;
483     int correctsize = ypitch * ph
484       + (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2);
485     int halfway = 16;
486
487     try {
488       if(size != correctsize)
489         throw new Exception("\nIncorrect size " + size + ".  Should be "
490           + correctsize);
491
492       for(row = 0; row < ph; row++) {
493         for(col = 0; col < pw; col++) {
494           byte y = buf[ypitch * row + col];
495           if(((row / 8) + (col / 8)) % 2 == 0) {
496             if(row < halfway) checkVal255(row, col, y, "Y");
497             else checkVal0(row, col, y, "Y");
498           }
499           else {
500             if(row < halfway) checkVal(row, col, y, "Y", 76);
501             else checkVal(row, col, y, "Y", 226);
502           }
503         }
504       }
505       if(subsamp != TJ.SAMP_GRAY) {
506         halfway = 16 / vsf;
507         for(row = 0; row < ch; row++) {
508           for(col = 0; col < cw; col++) {
509             byte u = buf[ypitch * ph + (uvpitch * row + col)],
510               v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
511             if(((row * vsf / 8) + (col * hsf / 8)) % 2 == 0) {
512               checkVal(row, col, u, "U", 128);
513               checkVal(row, col, v, "V", 128);
514             }
515             else {
516               if(row < halfway) {
517                 checkVal(row, col, u, "U", 85);
518                 checkVal255(row, col, v, "V");
519               }
520               else {
521                 checkVal0(row, col, u, "U");
522                 checkVal(row, col, v, "V", 149);
523               }
524             }
525           }
526         }
527       }
528     }
529     catch(Exception e) {
530       System.out.println(e);
531       retval = 0;
532     }
533
534     if(retval == 0) {
535       for(row = 0; row < ph; row++) {
536         for(col = 0; col < pw; col++) {
537           int y = buf[ypitch * row + col];
538           if(y < 0) y += 256;
539           System.out.format("%3d ", y);
540         }
541         System.out.print("\n");
542       }
543       System.out.print("\n");
544       for(row = 0; row < ch; row++) {
545         for(col = 0; col < cw; col++) {
546           int u = buf[ypitch * ph + (uvpitch * row + col)];
547           if(u < 0) u += 256;
548           System.out.format("%3d ", u);
549         }
550         System.out.print("\n");
551       }
552       System.out.print("\n");
553       for(row = 0; row < ch; row++) {
554         for(col = 0; col < cw; col++) {
555           int v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
556           if(v < 0) v += 256;
557           System.out.format("%3d ", v);
558         }
559         System.out.print("\n");
560       }
561       System.out.print("\n");
562     }
563
564     return retval;
565   }
566
567   private static void writeJPEG(byte[] jpegBuf, int jpegBufSize,
568     String filename) throws Exception {
569     File file = new File(filename);
570     FileOutputStream fos = new FileOutputStream(file);
571     fos.write(jpegBuf, 0, jpegBufSize);
572     fos.close();
573   }
574
575   private static int compTest(TJCompressor tjc, byte[] dstBuf, int w,
576     int h, int pf, String baseName, int subsamp, int jpegQual,
577     int flags) throws Exception {
578     String tempstr;
579     byte[] srcBuf = null;
580     BufferedImage img = null;
581     String pfStr;
582     double t;
583     int size = 0, ps, imgType = pf;
584
585     if (bi) {
586       pf = biTypePF(imgType);
587       pfStr = biTypeStr(imgType);
588     }
589     else pfStr = pixFormatStr[pf];
590     ps =  TJ.getPixelSize(pf);
591
592     System.out.print(pfStr + " ");
593     if(bi) System.out.print("(" + pixFormatStr[pf] + ") ");
594     if((flags & TJ.FLAG_BOTTOMUP) != 0) System.out.print("Bottom-Up");
595     else System.out.print("Top-Down ");
596     System.out.print(" -> " + subNameLong[subsamp] + " ");
597     if(yuv == YUVENCODE) System.out.print("YUV ... ");
598     else System.out.print("Q" + jpegQual + " ... ");
599
600     if(bi) {
601       img = new BufferedImage(w, h, imgType);
602       initImg(img, pf, flags);
603       tempstr = baseName + "_enc_" + pfStr + "_"
604         + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
605         + subName[subsamp] + "_Q" + jpegQual + ".png";
606       File file = new File(tempstr);
607       ImageIO.write(img, "png", file);
608     }
609     else {
610       srcBuf = new byte[w * h * ps + 1];
611       initBuf(srcBuf, w, w * ps, h, pf, flags);
612     }
613     Arrays.fill(dstBuf, (byte)0);
614
615     t = getTime();
616     tjc.setSubsamp(subsamp);
617     tjc.setJPEGQuality(jpegQual);
618     if(bi) {
619       if(yuv == YUVENCODE) tjc.encodeYUV(img, dstBuf, flags);
620       else tjc.compress(img, dstBuf, flags);
621     }
622     else {
623       tjc.setSourceImage(srcBuf, w, 0, h, pf);
624       if(yuv == YUVENCODE) tjc.encodeYUV(dstBuf, flags);
625       else tjc.compress(dstBuf, flags);
626     }
627     size = tjc.getCompressedSize();
628     t = getTime() - t;
629
630     if(yuv == YUVENCODE)
631       tempstr = baseName + "_enc_" + pfStr + "_"
632         + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
633         + subName[subsamp] + ".yuv";
634     else
635       tempstr = baseName + "_enc_" + pfStr + "_"
636         + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
637         + subName[subsamp] + "_Q" + jpegQual + ".jpg";
638     writeJPEG(dstBuf, size, tempstr);
639
640     if(yuv == YUVENCODE) {
641       if(checkBufYUV(dstBuf, size, w, h, subsamp) == 1)
642         System.out.print("Passed.");
643       else {
644         System.out.print("FAILED!");  exitStatus = -1;
645       }
646     }
647     else System.out.print("Done.");
648     System.out.format("  %.6f ms\n", t * 1000.);
649     System.out.println("  Result in " + tempstr);
650
651     return size;
652   }
653
654   private static void decompTest(TJDecompressor tjd, byte[] jpegBuf,
655     int jpegSize, int w, int h, int pf, String baseName, int subsamp,
656     int flags, TJScalingFactor sf) throws Exception {
657     String pfStr, tempstr;
658     double t;
659     int scaledWidth = sf.getScaled(w);
660     int scaledHeight = sf.getScaled(h);
661     int temp1, temp2, imgType = pf;
662     BufferedImage img = null;
663     byte[] dstBuf = null;
664
665     if(yuv == YUVENCODE) return;
666
667     if (bi) {
668       pf = biTypePF(imgType);
669       pfStr = biTypeStr(imgType);
670     }
671     else pfStr = pixFormatStr[pf];
672
673     System.out.print("JPEG -> ");
674     if(yuv == YUVDECODE)
675       System.out.print("YUV " + subName[subsamp] + " ... ");
676     else {
677       System.out.print(pfStr + " ");
678       if(bi) System.out.print("(" + pixFormatStr[pf] + ") ");
679       if((flags & TJ.FLAG_BOTTOMUP) != 0) System.out.print("Bottom-Up ");
680       else System.out.print("Top-Down  ");
681       if(!sf.isOne())
682         System.out.print(sf.getNum() + "/" + sf.getDenom() + " ... ");
683       else System.out.print("... ");
684     }
685
686     t = getTime();
687     tjd.setJPEGImage(jpegBuf, jpegSize);
688     if(tjd.getWidth() != w || tjd.getHeight() != h
689       || tjd.getSubsamp() != subsamp)
690       throw new Exception("Incorrect JPEG header");
691
692     temp1 = scaledWidth;
693     temp2 = scaledHeight;
694     temp1 = tjd.getScaledWidth(temp1, temp2);
695     temp2 = tjd.getScaledHeight(temp1, temp2);
696     if(temp1 != scaledWidth || temp2 != scaledHeight)
697       throw new Exception("Scaled size mismatch");
698
699     if(yuv == YUVDECODE) dstBuf = tjd.decompressToYUV(flags);
700     else {
701       if(bi)
702         img = tjd.decompress(scaledWidth, scaledHeight, imgType, flags);
703       else dstBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags);
704     }
705     t = getTime() - t;
706
707     if(bi) {
708       tempstr = baseName + "_dec_" + pfStr + "_"
709         + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
710         + subName[subsamp] + "_" + (double)sf.getNum() / (double)sf.getDenom()
711         + "x" + ".png";
712       File file = new File(tempstr);
713       ImageIO.write(img, "png", file);
714     }
715
716     if(yuv == YUVDECODE) {
717       if(checkBufYUV(dstBuf, dstBuf.length, w, h, subsamp) == 1)
718         System.out.print("Passed.");
719       else {
720         System.out.print("FAILED!");  exitStatus = -1;
721       }
722     }
723     else {
724       if((bi && checkImg(img, pf, subsamp, sf, flags) == 1)
725         || (!bi && checkBuf(dstBuf, scaledWidth, scaledWidth
726           * TJ.getPixelSize(pf), scaledHeight, pf, subsamp, sf, flags) == 1))
727         System.out.print("Passed.");
728       else {
729         System.out.print("FAILED!");  exitStatus = -1;
730       }
731     }
732     System.out.format("  %.6f ms\n", t * 1000.);
733   }
734
735   private static void decompTest(TJDecompressor tjd, byte[] jpegBuf,
736     int jpegSize, int w, int h, int pf, String baseName, int subsamp,
737     int flags) throws Exception {
738     int i;
739     if((subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY) && yuv == 0) {
740       TJScalingFactor sf[] = TJ.getScalingFactors();
741       for(i = 0; i < sf.length; i++)
742         decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp,
743           flags, sf[i]);
744     }
745     else
746       decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp,
747         flags, new TJScalingFactor(1, 1));
748     System.out.print("\n");
749   }
750
751   private static void doTest(int w, int h, int[] formats, int subsamp,
752     String baseName) throws Exception {
753     TJCompressor tjc = null;
754     TJDecompressor tjd = null;
755     int size;
756     byte[] dstBuf;
757
758     if(yuv == YUVENCODE) dstBuf = new byte[TJ.bufSizeYUV(w, h, subsamp)];
759     else dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
760
761     try {
762       tjc = new TJCompressor();
763       tjd = new TJDecompressor();  
764
765       for(int pf : formats) {
766         for(int i = 0; i < 2; i++) {
767           int flags = 0;
768           if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420
769             || subsamp == TJ.SAMP_440)
770             flags |= TJ.FLAG_FASTUPSAMPLE;
771           if(i == 1) {
772             if(yuv == YUVDECODE) {
773               tjc.close();  tjd.close();  return;
774             }
775             else flags |= TJ.FLAG_BOTTOMUP;
776           }
777           size = compTest(tjc, dstBuf, w, h, pf, baseName, subsamp, 100,
778             flags);
779           decompTest(tjd, dstBuf, size, w, h, pf, baseName, subsamp, flags);
780           if(pf >= TJ.PF_RGBX && pf <= TJ.PF_XRGB && !bi)
781             decompTest(tjd, dstBuf, size, w, h, pf + (TJ.PF_RGBA - TJ.PF_RGBX),
782               baseName, subsamp, flags);
783         }
784       }
785     }
786     catch(Exception e) {
787       if(tjc != null) tjc.close();
788       if(tjd != null) tjd.close();
789       throw e;
790     }
791     if(tjc != null) tjc.close();
792     if(tjd != null) tjd.close();
793   }
794
795   private static void bufSizeTest() throws Exception {
796     int w, h, i, subsamp;
797     byte[] srcBuf, jpegBuf;
798     TJCompressor tjc = null;
799     Random r = new Random();
800
801     try {
802       tjc = new TJCompressor();
803       System.out.println("Buffer size regression test");
804       for(subsamp = 0; subsamp < TJ.NUMSAMP; subsamp++) {
805         for(w = 1; w < 48; w++) {
806           int maxh = (w == 1) ? 2048 : 48;
807           for(h = 1; h < maxh; h++) {
808             if(h % 100 == 0)
809               System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h);
810             srcBuf = new byte[w * h * 4];
811             jpegBuf = new byte[TJ.bufSize(w, h, subsamp)];
812             for(i = 0; i < w * h * 4; i++) {
813               srcBuf[i] = (byte)(r.nextInt(2) * 255);
814             }
815             tjc.setSourceImage(srcBuf, w, 0, h, TJ.PF_BGRX);
816             tjc.setSubsamp(subsamp);
817             tjc.setJPEGQuality(100);
818             tjc.compress(jpegBuf, 0);
819
820             srcBuf = new byte[h * w * 4];
821             jpegBuf = new byte[TJ.bufSize(h, w, subsamp)];
822             for(i = 0; i < h * w * 4; i++) {
823               srcBuf[i] = (byte)(r.nextInt(2) * 255);
824             }
825             tjc.setSourceImage(srcBuf, h, 0, w, TJ.PF_BGRX);
826             tjc.compress(jpegBuf, 0);
827           }
828         }
829       }
830       System.out.println("Done.      ");
831     }
832     catch(Exception e) {
833       if(tjc != null) tjc.close();
834       throw e;
835     }
836     if(tjc != null) tjc.close();
837   }
838
839   public static void main(String argv[]) {
840     try {
841       String testName = "javatest";
842       boolean doyuv = false;
843       for(int i = 0; i < argv.length; i++) {
844         if(argv[i].equalsIgnoreCase("-yuv")) doyuv = true;
845         if(argv[i].substring(0, 1).equalsIgnoreCase("-h")
846           || argv[i].equalsIgnoreCase("-?"))
847           usage();
848         if(argv[i].equalsIgnoreCase("-bi")) {
849           bi = true;
850           testName = "javabitest";
851         }
852       }
853       if(doyuv) yuv = YUVENCODE;
854       doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_444, testName);
855       doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_444, testName);
856       doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_422,
857         testName);
858       doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_422,
859         testName);
860       doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_420,
861         testName);
862       doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_420,
863         testName);
864       doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_440,
865         testName);
866       doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_440,
867         testName);
868       doTest(35, 39, bi ? onlyGrayBI : onlyGray, TJ.SAMP_GRAY, testName);
869       doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_GRAY,
870         testName);
871       doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY,
872         testName);
873       if(!doyuv && !bi) bufSizeTest();
874       if(doyuv && !bi) {
875         yuv = YUVDECODE;
876         doTest(48, 48, onlyRGB, TJ.SAMP_444, "javatest_yuv0");
877         doTest(35, 39, onlyRGB, TJ.SAMP_444, "javatest_yuv1");
878         doTest(48, 48, onlyRGB, TJ.SAMP_422, "javatest_yuv0");
879         doTest(39, 41, onlyRGB, TJ.SAMP_422, "javatest_yuv1");
880         doTest(48, 48, onlyRGB, TJ.SAMP_420, "javatest_yuv0");
881         doTest(41, 35, onlyRGB, TJ.SAMP_420, "javatest_yuv1");
882         doTest(48, 48, onlyRGB, TJ.SAMP_440, "javatest_yuv0");
883         doTest(35, 39, onlyRGB, TJ.SAMP_440, "javatest_yuv1");
884         doTest(48, 48, onlyRGB, TJ.SAMP_GRAY, "javatest_yuv0");
885         doTest(35, 39, onlyRGB, TJ.SAMP_GRAY, "javatest_yuv1");
886         doTest(48, 48, onlyGray, TJ.SAMP_GRAY, "javatest_yuv0");
887         doTest(39, 41, onlyGray, TJ.SAMP_GRAY, "javatest_yuv1");
888       }
889     }
890     catch(Exception e) {
891       e.printStackTrace();
892       exitStatus = -1;
893     }
894     System.exit(exitStatus);
895   }
896 }