2 * Copyright (C)2009-2012 D. R. Commander. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
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.
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.
30 * This program tests the various code paths in the TurboJPEG C Wrapper
38 #include "./turbojpeg.h"
41 #define random() rand()
45 #define _throwtj() {printf("TurboJPEG ERROR:\n%s\n", tjGetErrorStr()); \
47 #define _tj(f) {if((f)==-1) _throwtj();}
48 #define _throw(m) {printf("ERROR: %s\n", m); bailout();}
50 const char *subNameLong
[TJ_NUMSAMP
]=
52 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0"
54 const char *subName
[TJ_NUMSAMP
]={"444", "422", "420", "GRAY", "440"};
56 const char *pixFormatStr
[TJ_NUMPF
]=
58 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
59 "RGBA", "BGRA", "ABGR", "ARGB"
62 const int alphaOffset
[TJ_NUMPF
] = {-1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0};
64 const int _3byteFormats
[]={TJPF_RGB
, TJPF_BGR
};
65 const int _4byteFormats
[]={TJPF_RGBX
, TJPF_BGRX
, TJPF_XBGR
, TJPF_XRGB
};
66 const int _onlyGray
[]={TJPF_GRAY
};
67 const int _onlyRGB
[]={TJPF_RGB
};
70 #define bailout() {exitStatus=-1; goto bailout;}
73 void initBuf(unsigned char *buf
, int w
, int h
, int pf
, int flags
)
75 int roffset
=tjRedOffset
[pf
];
76 int goffset
=tjGreenOffset
[pf
];
77 int boffset
=tjBlueOffset
[pf
];
78 int ps
=tjPixelSize
[pf
];
79 int index
, row
, col
, halfway
=16;
81 memset(buf
, 0, w
*h
*ps
);
84 for(row
=0; row
<h
; row
++)
86 for(col
=0; col
<w
; col
++)
88 if(flags
&TJFLAG_BOTTOMUP
) index
=(h
-row
-1)*w
+col
;
90 if(((row
/8)+(col
/8))%2==0) buf
[index
]=(row
<halfway
)? 255:0;
91 else buf
[index
]=(row
<halfway
)? 76:226;
97 for(row
=0; row
<h
; row
++)
99 for(col
=0; col
<w
; col
++)
101 if(flags
&TJFLAG_BOTTOMUP
) index
=(h
-row
-1)*w
+col
;
102 else index
=row
*w
+col
;
103 if(((row
/8)+(col
/8))%2==0)
107 buf
[index
*ps
+roffset
]=255;
108 buf
[index
*ps
+goffset
]=255;
109 buf
[index
*ps
+boffset
]=255;
114 buf
[index
*ps
+roffset
]=255;
115 if(row
>=halfway
) buf
[index
*ps
+goffset
]=255;
123 #define checkval(v, cv) { \
124 if(v<cv-1 || v>cv+1) { \
125 printf("\nComp. %s at %d,%d should be %d, not %d\n", \
126 #v, row, col, cv, v); \
127 retval=0; exitStatus=-1; goto bailout; \
130 #define checkval0(v) { \
132 printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, row, col, v); \
133 retval=0; exitStatus=-1; goto bailout; \
136 #define checkval255(v) { \
138 printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, row, col, v); \
139 retval=0; exitStatus=-1; goto bailout; \
143 int checkBuf(unsigned char *buf
, int w
, int h
, int pf
, int subsamp
,
144 tjscalingfactor sf
, int flags
)
146 int roffset
=tjRedOffset
[pf
];
147 int goffset
=tjGreenOffset
[pf
];
148 int boffset
=tjBlueOffset
[pf
];
149 int aoffset
=alphaOffset
[pf
];
150 int ps
=tjPixelSize
[pf
];
151 int index
, row
, col
, retval
=1;
152 int halfway
=16*sf
.num
/sf
.denom
;
153 int blocksize
=8*sf
.num
/sf
.denom
;
155 for(row
=0; row
<h
; row
++)
157 for(col
=0; col
<w
; col
++)
159 unsigned char r
, g
, b
, a
;
160 if(flags
&TJFLAG_BOTTOMUP
) index
=(h
-row
-1)*w
+col
;
161 else index
=row
*w
+col
;
162 r
=buf
[index
*ps
+roffset
];
163 g
=buf
[index
*ps
+goffset
];
164 b
=buf
[index
*ps
+boffset
];
165 a
=aoffset
>=0? buf
[index
*ps
+aoffset
]:0xFF;
166 if(((row
/blocksize
)+(col
/blocksize
))%2==0)
170 checkval255(r
); checkval255(g
); checkval255(b
);
174 checkval0(r
); checkval0(g
); checkval0(b
);
179 if(subsamp
==TJSAMP_GRAY
)
183 checkval(r
, 76); checkval(g
, 76); checkval(b
, 76);
187 checkval(r
, 226); checkval(g
, 226); checkval(b
, 226);
194 checkval255(r
); checkval0(g
); checkval0(b
);
198 checkval255(r
); checkval255(g
); checkval0(b
);
210 for(row
=0; row
<h
; row
++)
212 for(col
=0; col
<w
; col
++)
214 printf("%.3d/%.3d/%.3d ", buf
[(row
*w
+col
)*ps
+roffset
],
215 buf
[(row
*w
+col
)*ps
+goffset
], buf
[(row
*w
+col
)*ps
+boffset
]);
224 void writeJPEG(unsigned char *jpegBuf
, unsigned long jpegSize
, char *filename
)
226 FILE *file
=fopen(filename
, "wb");
227 if(!file
|| fwrite(jpegBuf
, jpegSize
, 1, file
)!=1)
229 printf("ERROR: Could not write to %s.\n%s\n", filename
, strerror(errno
));
234 if(file
) fclose(file
);
238 void compTest(tjhandle handle
, unsigned char **dstBuf
,
239 unsigned long *dstSize
, int w
, int h
, int pf
, char *basename
,
240 int subsamp
, int jpegQual
, int flags
)
242 char tempStr
[1024]; unsigned char *srcBuf
=NULL
;
245 printf("%s %s -> %s Q%d ... ", pixFormatStr
[pf
],
246 (flags
&TJFLAG_BOTTOMUP
)? "Bottom-Up":"Top-Down ", subNameLong
[subsamp
],
249 if((srcBuf
=(unsigned char *)malloc(w
*h
*tjPixelSize
[pf
]))==NULL
)
250 _throw("Memory allocation failure");
251 initBuf(srcBuf
, w
, h
, pf
, flags
);
252 if(*dstBuf
&& *dstSize
>0) memset(*dstBuf
, 0, *dstSize
);
255 *dstSize
=tjBufSize(w
, h
, subsamp
);
256 _tj(tjCompress2(handle
, srcBuf
, w
, 0, h
, pf
, dstBuf
, dstSize
, subsamp
,
260 snprintf(tempStr
, 1024, "%s_enc_%s_%s_%s_Q%d.jpg", basename
,
261 pixFormatStr
[pf
], (flags
&TJFLAG_BOTTOMUP
)? "BU":"TD", subName
[subsamp
],
263 writeJPEG(*dstBuf
, *dstSize
, tempStr
);
265 printf(" %f ms\n Result in %s\n", t
*1000., tempStr
);
268 if(srcBuf
) free(srcBuf
);
272 void _decompTest(tjhandle handle
, unsigned char *jpegBuf
,
273 unsigned long jpegSize
, int w
, int h
, int pf
, char *basename
, int subsamp
,
274 int flags
, tjscalingfactor sf
)
276 unsigned char *dstBuf
=NULL
;
277 int _hdrw
=0, _hdrh
=0, _hdrsubsamp
=-1; double t
;
278 int scaledWidth
=TJSCALED(w
, sf
);
279 int scaledHeight
=TJSCALED(h
, sf
);
280 unsigned long dstSize
=0;
282 printf("JPEG -> %s %s ", pixFormatStr
[pf
],
283 (flags
&TJFLAG_BOTTOMUP
)? "Bottom-Up":"Top-Down ");
284 if(sf
.num
!=1 || sf
.denom
!=1)
285 printf("%d/%d ... ", sf
.num
, sf
.denom
);
288 _tj(tjDecompressHeader2(handle
, jpegBuf
, jpegSize
, &_hdrw
, &_hdrh
,
290 if(_hdrw
!=w
|| _hdrh
!=h
|| _hdrsubsamp
!=subsamp
)
291 _throw("Incorrect JPEG header");
293 dstSize
=scaledWidth
*scaledHeight
*tjPixelSize
[pf
];
294 if((dstBuf
=(unsigned char *)malloc(dstSize
))==NULL
)
295 _throw("Memory allocation failure");
296 memset(dstBuf
, 0, dstSize
);
299 _tj(tjDecompress2(handle
, jpegBuf
, jpegSize
, dstBuf
, scaledWidth
, 0,
300 scaledHeight
, pf
, flags
));
303 if(checkBuf(dstBuf
, scaledWidth
, scaledHeight
, pf
, subsamp
, sf
, flags
))
305 else printf("FAILED!");
306 printf(" %f ms\n", t
*1000.);
309 if(dstBuf
) free(dstBuf
);
313 void decompTest(tjhandle handle
, unsigned char *jpegBuf
,
314 unsigned long jpegSize
, int w
, int h
, int pf
, char *basename
, int subsamp
,
318 tjscalingfactor
*sf
=tjGetScalingFactors(&n
), sf1
={1, 1};
319 if(!sf
|| !n
) _throwtj();
321 if((subsamp
==TJSAMP_444
|| subsamp
==TJSAMP_GRAY
))
324 _decompTest(handle
, jpegBuf
, jpegSize
, w
, h
, pf
, basename
, subsamp
,
328 _decompTest(handle
, jpegBuf
, jpegSize
, w
, h
, pf
, basename
, subsamp
, flags
,
336 void doTest(int w
, int h
, const int *formats
, int nformats
, int subsamp
,
339 tjhandle chandle
=NULL
, dhandle
=NULL
;
340 unsigned char *dstBuf
=NULL
;
341 unsigned long size
=0; int pfi
, pf
, i
;
343 size
=tjBufSize(w
, h
, subsamp
);
344 if((dstBuf
=(unsigned char *)malloc(size
))==NULL
)
345 _throw("Memory allocation failure.");
347 if((chandle
=tjInitCompress())==NULL
|| (dhandle
=tjInitDecompress())==NULL
)
350 for(pfi
=0; pfi
<nformats
; pfi
++)
355 if(subsamp
==TJSAMP_422
|| subsamp
==TJSAMP_420
|| subsamp
==TJSAMP_440
)
356 flags
|=TJFLAG_FASTUPSAMPLE
;
357 if(i
==1) flags
|=TJFLAG_BOTTOMUP
;
359 compTest(chandle
, &dstBuf
, &size
, w
, h
, pf
, basename
, subsamp
, 100,
361 decompTest(dhandle
, dstBuf
, size
, w
, h
, pf
, basename
, subsamp
,
363 if(pf
>=TJPF_RGBX
&& pf
<=TJPF_XRGB
)
364 decompTest(dhandle
, dstBuf
, size
, w
, h
, pf
+(TJPF_RGBA
-TJPF_RGBX
),
365 basename
, subsamp
, flags
);
370 if(chandle
) tjDestroy(chandle
);
371 if(dhandle
) tjDestroy(dhandle
);
373 if(dstBuf
) free(dstBuf
);
377 void bufSizeTest(void)
379 int w
, h
, i
, subsamp
;
380 unsigned char *srcBuf
=NULL
, *jpegBuf
=NULL
;
381 tjhandle handle
=NULL
;
382 unsigned long jpegSize
=0;
384 if((handle
=tjInitCompress())==NULL
) _throwtj();
386 printf("Buffer size regression test\n");
387 for(subsamp
=0; subsamp
<TJ_NUMSAMP
; subsamp
++)
391 int maxh
=(w
==1)? 2048:48;
392 for(h
=1; h
<maxh
; h
++)
394 if(h
%100==0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w
, h
);
395 if((srcBuf
=(unsigned char *)malloc(w
*h
*4))==NULL
)
396 _throw("Memory allocation failure");
397 if((jpegBuf
=(unsigned char *)malloc(tjBufSize(w
, h
, subsamp
)))
399 _throw("Memory allocation failure");
400 jpegSize
=tjBufSize(w
, h
, subsamp
);
402 for(i
=0; i
<w
*h
*4; i
++)
404 if(random()<RAND_MAX
/2) srcBuf
[i
]=0;
408 _tj(tjCompress2(handle
, srcBuf
, w
, 0, h
, TJPF_BGRX
, &jpegBuf
,
409 &jpegSize
, subsamp
, 100, 0));
410 free(srcBuf
); srcBuf
=NULL
;
411 free(jpegBuf
); jpegBuf
=NULL
;
413 if((srcBuf
=(unsigned char *)malloc(h
*w
*4))==NULL
)
414 _throw("Memory allocation failure");
415 if((jpegBuf
=(unsigned char *)malloc(tjBufSize(h
, w
, subsamp
)))
417 _throw("Memory allocation failure");
418 jpegSize
=tjBufSize(h
, w
, subsamp
);
420 for(i
=0; i
<h
*w
*4; i
++)
422 if(random()<RAND_MAX
/2) srcBuf
[i
]=0;
426 _tj(tjCompress2(handle
, srcBuf
, h
, 0, w
, TJPF_BGRX
, &jpegBuf
,
427 &jpegSize
, subsamp
, 100, 0));
428 free(srcBuf
); srcBuf
=NULL
;
429 free(jpegBuf
); jpegBuf
=NULL
;
436 if(srcBuf
) free(srcBuf
);
437 if(jpegBuf
) free(jpegBuf
);
438 if(handle
) tjDestroy(handle
);
442 int main(int argc
, char *argv
[])
445 srand((unsigned int)time(NULL
));
447 doTest(35, 39, _3byteFormats
, 2, TJSAMP_444
, "test");
448 doTest(39, 41, _4byteFormats
, 4, TJSAMP_444
, "test");
449 doTest(41, 35, _3byteFormats
, 2, TJSAMP_422
, "test");
450 doTest(35, 39, _4byteFormats
, 4, TJSAMP_422
, "test");
451 doTest(39, 41, _3byteFormats
, 2, TJSAMP_420
, "test");
452 doTest(41, 35, _4byteFormats
, 4, TJSAMP_420
, "test");
453 doTest(35, 39, _3byteFormats
, 2, TJSAMP_440
, "test");
454 doTest(39, 41, _4byteFormats
, 4, TJSAMP_440
, "test");
455 doTest(35, 39, _onlyGray
, 1, TJSAMP_GRAY
, "test");
456 doTest(39, 41, _3byteFormats
, 2, TJSAMP_GRAY
, "test");
457 doTest(41, 35, _4byteFormats
, 4, TJSAMP_GRAY
, "test");