1 /*
2 * Copyright (C)2009-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 C Wrapper
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include "./tjutil.h"
38 #include "./turbojpeg.h"
39 #ifdef _WIN32
40 #include <time.h>
41 #define random() rand()
42 #endif
43
44
45 #define _throwtj() {printf("TurboJPEG ERROR:\n%s\n", tjGetErrorStr()); \
46 bailout();}
47 #define _tj(f) {if((f)==-1) _throwtj();}
48 #define _throw(m) {printf("ERROR: %s\n", m); bailout();}
49
50 const char *subNameLong[TJ_NUMSAMP]=
51 {
52 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0"
53 };
54 const char *subName[TJ_NUMSAMP]={"444", "422", "420", "GRAY", "440"};
55
56 const char *pixFormatStr[TJ_NUMPF]=
57 {
58 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
59 "RGBA", "BGRA", "ABGR", "ARGB"
60 };
61
62 const int alphaOffset[TJ_NUMPF] = {-1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0};
63
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};
68
69 int exitStatus=0;
70 #define bailout() {exitStatus=-1; goto bailout;}
71
72
initBuf(unsigned char * buf,int w,int h,int pf,int flags)73 void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
74 {
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;
80
81 memset(buf, 0, w*h*ps);
82 if(pf==TJPF_GRAY)
83 {
84 for(row=0; row<h; row++)
85 {
86 for(col=0; col<w; col++)
87 {
88 if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
89 else index=row*w+col;
90 if(((row/8)+(col/8))%2==0) buf[index]=(row<halfway)? 255:0;
91 else buf[index]=(row<halfway)? 76:226;
92 }
93 }
94 }
95 else
96 {
97 for(row=0; row<h; row++)
98 {
99 for(col=0; col<w; col++)
100 {
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)
104 {
105 if(row<halfway)
106 {
107 buf[index*ps+roffset]=255;
108 buf[index*ps+goffset]=255;
109 buf[index*ps+boffset]=255;
110 }
111 }
112 else
113 {
114 buf[index*ps+roffset]=255;
115 if(row>=halfway) buf[index*ps+goffset]=255;
116 }
117 }
118 }
119 }
120 }
121
122
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; \
128 }}
129
130 #define checkval0(v) { \
131 if(v>1) { \
132 printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, row, col, v); \
133 retval=0; exitStatus=-1; goto bailout; \
134 }}
135
136 #define checkval255(v) { \
137 if(v<254) { \
138 printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, row, col, v); \
139 retval=0; exitStatus=-1; goto bailout; \
140 }}
141
142
checkBuf(unsigned char * buf,int w,int h,int pf,int subsamp,tjscalingfactor sf,int flags)143 int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
144 tjscalingfactor sf, int flags)
145 {
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;
154
155 for(row=0; row<h; row++)
156 {
157 for(col=0; col<w; col++)
158 {
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)
167 {
168 if(row<halfway)
169 {
170 checkval255(r); checkval255(g); checkval255(b);
171 }
172 else
173 {
174 checkval0(r); checkval0(g); checkval0(b);
175 }
176 }
177 else
178 {
179 if(subsamp==TJSAMP_GRAY)
180 {
181 if(row<halfway)
182 {
183 checkval(r, 76); checkval(g, 76); checkval(b, 76);
184 }
185 else
186 {
187 checkval(r, 226); checkval(g, 226); checkval(b, 226);
188 }
189 }
190 else
191 {
192 if(row<halfway)
193 {
194 checkval255(r); checkval0(g); checkval0(b);
195 }
196 else
197 {
198 checkval255(r); checkval255(g); checkval0(b);
199 }
200 }
201 }
202 checkval255(a);
203 }
204 }
205
206 bailout:
207 if(retval==0)
208 {
209 printf("\n");
210 for(row=0; row<h; row++)
211 {
212 for(col=0; col<w; col++)
213 {
214 printf("%.3d/%.3d/%.3d ", buf[(row*w+col)*ps+roffset],
215 buf[(row*w+col)*ps+goffset], buf[(row*w+col)*ps+boffset]);
216 }
217 printf("\n");
218 }
219 }
220 return retval;
221 }
222
223
writeJPEG(unsigned char * jpegBuf,unsigned long jpegSize,char * filename)224 void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize, char *filename)
225 {
226 FILE *file=fopen(filename, "wb");
227 if(!file || fwrite(jpegBuf, jpegSize, 1, file)!=1)
228 {
229 printf("ERROR: Could not write to %s.\n%s\n", filename, strerror(errno));
230 bailout();
231 }
232
233 bailout:
234 if(file) fclose(file);
235 }
236
237
compTest(tjhandle handle,unsigned char ** dstBuf,unsigned long * dstSize,int w,int h,int pf,char * basename,int subsamp,int jpegQual,int flags)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)
241 {
242 char tempStr[1024]; unsigned char *srcBuf=NULL;
243 double t;
244
245 printf("%s %s -> %s Q%d ... ", pixFormatStr[pf],
246 (flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ", subNameLong[subsamp],
247 jpegQual);
248
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);
253
254 t=gettime();
255 *dstSize=tjBufSize(w, h, subsamp);
256 _tj(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
257 jpegQual, flags));
258 t=gettime()-t;
259
260 snprintf(tempStr, 1024, "%s_enc_%s_%s_%s_Q%d.jpg", basename,
261 pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subName[subsamp],
262 jpegQual);
263 writeJPEG(*dstBuf, *dstSize, tempStr);
264 printf("Done.");
265 printf(" %f ms\n Result in %s\n", t*1000., tempStr);
266
267 bailout:
268 if(srcBuf) free(srcBuf);
269 }
270
271
_decompTest(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int w,int h,int pf,char * basename,int subsamp,int flags,tjscalingfactor sf)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)
275 {
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;
281
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);
286 else printf("... ");
287
288 _tj(tjDecompressHeader2(handle, jpegBuf, jpegSize, &_hdrw, &_hdrh,
289 &_hdrsubsamp));
290 if(_hdrw!=w || _hdrh!=h || _hdrsubsamp!=subsamp)
291 _throw("Incorrect JPEG header");
292
293 dstSize=scaledWidth*scaledHeight*tjPixelSize[pf];
294 if((dstBuf=(unsigned char *)malloc(dstSize))==NULL)
295 _throw("Memory allocation failure");
296 memset(dstBuf, 0, dstSize);
297
298 t=gettime();
299 _tj(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth, 0,
300 scaledHeight, pf, flags));
301 t=gettime()-t;
302
303 if(checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, flags))
304 printf("Passed.");
305 else printf("FAILED!");
306 printf(" %f ms\n", t*1000.);
307
308 bailout:
309 if(dstBuf) free(dstBuf);
310 }
311
312
decompTest(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int w,int h,int pf,char * basename,int subsamp,int flags)313 void decompTest(tjhandle handle, unsigned char *jpegBuf,
314 unsigned long jpegSize, int w, int h, int pf, char *basename, int subsamp,
315 int flags)
316 {
317 int i, n=0;
318 tjscalingfactor *sf=tjGetScalingFactors(&n), sf1={1, 1};
319 if(!sf || !n) _throwtj();
320
321 if((subsamp==TJSAMP_444 || subsamp==TJSAMP_GRAY))
322 {
323 for(i=0; i<n; i++)
324 _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
325 flags, sf[i]);
326 }
327 else
328 _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp, flags,
329 sf1);
330
331 bailout:
332 printf("\n");
333 }
334
335
doTest(int w,int h,const int * formats,int nformats,int subsamp,char * basename)336 void doTest(int w, int h, const int *formats, int nformats, int subsamp,
337 char *basename)
338 {
339 tjhandle chandle=NULL, dhandle=NULL;
340 unsigned char *dstBuf=NULL;
341 unsigned long size=0; int pfi, pf, i;
342
343 size=tjBufSize(w, h, subsamp);
344 if((dstBuf=(unsigned char *)malloc(size))==NULL)
345 _throw("Memory allocation failure.");
346
347 if((chandle=tjInitCompress())==NULL || (dhandle=tjInitDecompress())==NULL)
348 _throwtj();
349
350 for(pfi=0; pfi<nformats; pfi++)
351 {
352 for(i=0; i<2; i++)
353 {
354 int flags=0;
355 if(subsamp==TJSAMP_422 || subsamp==TJSAMP_420 || subsamp==TJSAMP_440)
356 flags|=TJFLAG_FASTUPSAMPLE;
357 if(i==1) flags|=TJFLAG_BOTTOMUP;
358 pf=formats[pfi];
359 compTest(chandle, &dstBuf, &size, w, h, pf, basename, subsamp, 100,
360 flags);
361 decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp,
362 flags);
363 if(pf>=TJPF_RGBX && pf<=TJPF_XRGB)
364 decompTest(dhandle, dstBuf, size, w, h, pf+(TJPF_RGBA-TJPF_RGBX),
365 basename, subsamp, flags);
366 }
367 }
368
369 bailout:
370 if(chandle) tjDestroy(chandle);
371 if(dhandle) tjDestroy(dhandle);
372
373 if(dstBuf) free(dstBuf);
374 }
375
376
bufSizeTest(void)377 void bufSizeTest(void)
378 {
379 int w, h, i, subsamp;
380 unsigned char *srcBuf=NULL, *jpegBuf=NULL;
381 tjhandle handle=NULL;
382 unsigned long jpegSize=0;
383
384 if((handle=tjInitCompress())==NULL) _throwtj();
385
386 printf("Buffer size regression test\n");
387 for(subsamp=0; subsamp<TJ_NUMSAMP; subsamp++)
388 {
389 for(w=1; w<48; w++)
390 {
391 int maxh=(w==1)? 2048:48;
392 for(h=1; h<maxh; h++)
393 {
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)))
398 ==NULL)
399 _throw("Memory allocation failure");
400 jpegSize=tjBufSize(w, h, subsamp);
401
402 for(i=0; i<w*h*4; i++)
403 {
404 if(random()<RAND_MAX/2) srcBuf[i]=0;
405 else srcBuf[i]=255;
406 }
407
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;
412
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)))
416 ==NULL)
417 _throw("Memory allocation failure");
418 jpegSize=tjBufSize(h, w, subsamp);
419
420 for(i=0; i<h*w*4; i++)
421 {
422 if(random()<RAND_MAX/2) srcBuf[i]=0;
423 else srcBuf[i]=255;
424 }
425
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;
430 }
431 }
432 }
433 printf("Done. \n");
434
435 bailout:
436 if(srcBuf) free(srcBuf);
437 if(jpegBuf) free(jpegBuf);
438 if(handle) tjDestroy(handle);
439 }
440
441
main(int argc,char * argv[])442 int main(int argc, char *argv[])
443 {
444 #ifdef _WIN32
445 srand((unsigned int)time(NULL));
446 #endif
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");
458 bufSizeTest();
459
460 return exitStatus;
461 }
462