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 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 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 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 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 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 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 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 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 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