Home | History | Annotate | Download | only in libjpeg-turbo
      1 /*
      2  * Copyright (C)2009-2014, 2017 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 void usage(char *progName)
     46 {
     47 	printf("\nUSAGE: %s [options]\n\n", progName);
     48 	printf("Options:\n");
     49 	printf("-yuv = test YUV encoding/decoding support\n");
     50 	printf("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest\n");
     51 	printf("            4-byte boundary\n");
     52 	printf("-alloc = test automatic buffer allocation\n\n");
     53 	exit(1);
     54 }
     55 
     56 
     57 #define _throwtj() {printf("TurboJPEG ERROR:\n%s\n", tjGetErrorStr());  \
     58 	bailout();}
     59 #define _tj(f) {if((f)==-1) _throwtj();}
     60 #define _throw(m) {printf("ERROR: %s\n", m);  bailout();}
     61 
     62 const char *subNameLong[TJ_NUMSAMP]=
     63 {
     64 	"4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
     65 };
     66 const char *subName[TJ_NUMSAMP]={"444", "422", "420", "GRAY", "440", "411"};
     67 
     68 const char *pixFormatStr[TJ_NUMPF]=
     69 {
     70 	"RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
     71 	"RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
     72 };
     73 
     74 const int alphaOffset[TJ_NUMPF] = {-1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1};
     75 
     76 const int _3byteFormats[]={TJPF_RGB, TJPF_BGR};
     77 const int _4byteFormats[]={TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB,
     78 	TJPF_CMYK};
     79 const int _onlyGray[]={TJPF_GRAY};
     80 const int _onlyRGB[]={TJPF_RGB};
     81 
     82 int doyuv=0, alloc=0, pad=4;
     83 
     84 int exitStatus=0;
     85 #define bailout() {exitStatus=-1;  goto bailout;}
     86 
     87 
     88 void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
     89 {
     90 	int roffset=tjRedOffset[pf];
     91 	int goffset=tjGreenOffset[pf];
     92 	int boffset=tjBlueOffset[pf];
     93 	int ps=tjPixelSize[pf];
     94 	int index, row, col, halfway=16;
     95 
     96 	if(pf==TJPF_GRAY)
     97 	{
     98 		memset(buf, 0, w*h*ps);
     99 		for(row=0; row<h; row++)
    100 		{
    101 			for(col=0; col<w; col++)
    102 			{
    103 				if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
    104 				else index=row*w+col;
    105 				if(((row/8)+(col/8))%2==0) buf[index]=(row<halfway)? 255:0;
    106 				else buf[index]=(row<halfway)? 76:226;
    107 			}
    108 		}
    109 	}
    110 	else if(pf==TJPF_CMYK)
    111 	{
    112 		memset(buf, 255, w*h*ps);
    113 		for(row=0; row<h; row++)
    114 		{
    115 			for(col=0; col<w; col++)
    116 			{
    117 				if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
    118 				else index=row*w+col;
    119 				if(((row/8)+(col/8))%2==0)
    120 				{
    121 					if(row>=halfway) buf[index*ps+3]=0;
    122 				}
    123 				else
    124 				{
    125 					buf[index*ps+2]=0;
    126 					if(row<halfway) buf[index*ps+1]=0;
    127 				}
    128 			}
    129 		}
    130 	}
    131 	else
    132 	{
    133 		memset(buf, 0, w*h*ps);
    134 		for(row=0; row<h; row++)
    135 		{
    136 			for(col=0; col<w; col++)
    137 			{
    138 				if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
    139 				else index=row*w+col;
    140 				if(((row/8)+(col/8))%2==0)
    141 				{
    142 					if(row<halfway)
    143 					{
    144 						buf[index*ps+roffset]=255;
    145 						buf[index*ps+goffset]=255;
    146 						buf[index*ps+boffset]=255;
    147 					}
    148 				}
    149 				else
    150 				{
    151 					buf[index*ps+roffset]=255;
    152 					if(row>=halfway) buf[index*ps+goffset]=255;
    153 				}
    154 			}
    155 		}
    156 	}
    157 }
    158 
    159 
    160 #define checkval(v, cv) { \
    161 	if(v<cv-1 || v>cv+1) { \
    162 		printf("\nComp. %s at %d,%d should be %d, not %d\n",  \
    163 			#v, row, col, cv, v); \
    164 		retval=0;  exitStatus=-1;  goto bailout; \
    165 	}}
    166 
    167 #define checkval0(v) { \
    168 	if(v>1) { \
    169 		printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, row, col, v); \
    170 		retval=0;  exitStatus=-1;  goto bailout; \
    171 	}}
    172 
    173 #define checkval255(v) { \
    174 	if(v<254) { \
    175 		printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, row, col, v); \
    176 		retval=0;  exitStatus=-1;  goto bailout; \
    177 	}}
    178 
    179 
    180 int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
    181 	tjscalingfactor sf, int flags)
    182 {
    183 	int roffset=tjRedOffset[pf];
    184 	int goffset=tjGreenOffset[pf];
    185 	int boffset=tjBlueOffset[pf];
    186 	int aoffset=alphaOffset[pf];
    187 	int ps=tjPixelSize[pf];
    188 	int index, row, col, retval=1;
    189 	int halfway=16*sf.num/sf.denom;
    190 	int blocksize=8*sf.num/sf.denom;
    191 
    192 	if(pf==TJPF_CMYK)
    193 	{
    194 		for(row=0; row<h; row++)
    195 		{
    196 			for(col=0; col<w; col++)
    197 			{
    198 				unsigned char c, m, y, k;
    199 				if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
    200 				else index=row*w+col;
    201 				c=buf[index*ps];
    202 				m=buf[index*ps+1];
    203 				y=buf[index*ps+2];
    204 				k=buf[index*ps+3];
    205 				if(((row/blocksize)+(col/blocksize))%2==0)
    206 				{
    207 					checkval255(c);  checkval255(m);  checkval255(y);
    208 					if(row<halfway) checkval255(k)
    209 					else checkval0(k)
    210 				}
    211 				else
    212 				{
    213 					checkval255(c);  checkval0(y);  checkval255(k);
    214 					if(row<halfway) checkval0(m)
    215 					else checkval255(m)
    216 				}
    217 			}
    218 		}
    219 		return 1;
    220 	}
    221 
    222 	for(row=0; row<h; row++)
    223 	{
    224 		for(col=0; col<w; col++)
    225 		{
    226 			unsigned char r, g, b, a;
    227 			if(flags&TJFLAG_BOTTOMUP) index=(h-row-1)*w+col;
    228 			else index=row*w+col;
    229 			r=buf[index*ps+roffset];
    230 			g=buf[index*ps+goffset];
    231 			b=buf[index*ps+boffset];
    232 			a=aoffset>=0? buf[index*ps+aoffset]:0xFF;
    233 			if(((row/blocksize)+(col/blocksize))%2==0)
    234 			{
    235 				if(row<halfway)
    236 				{
    237 					checkval255(r);  checkval255(g);  checkval255(b);
    238 				}
    239 				else
    240 				{
    241 					checkval0(r);  checkval0(g);  checkval0(b);
    242 				}
    243 			}
    244 			else
    245 			{
    246 				if(subsamp==TJSAMP_GRAY)
    247 				{
    248 					if(row<halfway)
    249 					{
    250 						checkval(r, 76);  checkval(g, 76);  checkval(b, 76);
    251 					}
    252 					else
    253 					{
    254 						checkval(r, 226);  checkval(g, 226);  checkval(b, 226);
    255 					}
    256 				}
    257 				else
    258 				{
    259 					if(row<halfway)
    260 					{
    261 						checkval255(r);  checkval0(g);  checkval0(b);
    262 					}
    263 					else
    264 					{
    265 						checkval255(r);  checkval255(g);  checkval0(b);
    266 					}
    267 				}
    268 			}
    269 			checkval255(a);
    270 		}
    271 	}
    272 
    273 	bailout:
    274 	if(retval==0)
    275 	{
    276 		for(row=0; row<h; row++)
    277 		{
    278 			for(col=0; col<w; col++)
    279 			{
    280 				if(pf==TJPF_CMYK)
    281 					printf("%.3d/%.3d/%.3d/%.3d ", buf[(row*w+col)*ps],
    282 						buf[(row*w+col)*ps+1], buf[(row*w+col)*ps+2],
    283 						buf[(row*w+col)*ps+3]);
    284 				else
    285 					printf("%.3d/%.3d/%.3d ", buf[(row*w+col)*ps+roffset],
    286 						buf[(row*w+col)*ps+goffset], buf[(row*w+col)*ps+boffset]);
    287 			}
    288 			printf("\n");
    289 		}
    290 	}
    291 	return retval;
    292 }
    293 
    294 
    295 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
    296 
    297 int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
    298 	tjscalingfactor sf)
    299 {
    300 	int row, col;
    301 	int hsf=tjMCUWidth[subsamp]/8, vsf=tjMCUHeight[subsamp]/8;
    302 	int pw=PAD(w, hsf), ph=PAD(h, vsf);
    303 	int cw=pw/hsf, ch=ph/vsf;
    304 	int ypitch=PAD(pw, pad), uvpitch=PAD(cw, pad);
    305 	int retval=1;
    306 	int halfway=16*sf.num/sf.denom;
    307 	int blocksize=8*sf.num/sf.denom;
    308 
    309 	for(row=0; row<ph; row++)
    310 	{
    311 		for(col=0; col<pw; col++)
    312 		{
    313 			unsigned char y=buf[ypitch*row+col];
    314 			if(((row/blocksize)+(col/blocksize))%2==0)
    315 			{
    316 				if(row<halfway) checkval255(y)  else checkval0(y);
    317 			}
    318 			else
    319 			{
    320 				if(row<halfway) checkval(y, 76)  else checkval(y, 226);
    321 			}
    322 		}
    323 	}
    324 	if(subsamp!=TJSAMP_GRAY)
    325 	{
    326 		int halfway=16/vsf*sf.num/sf.denom;
    327 		for(row=0; row<ch; row++)
    328 		{
    329 			for(col=0; col<cw; col++)
    330 			{
    331 				unsigned char u=buf[ypitch*ph + (uvpitch*row+col)],
    332 					v=buf[ypitch*ph + uvpitch*ch + (uvpitch*row+col)];
    333 				if(((row*vsf/blocksize)+(col*hsf/blocksize))%2==0)
    334 				{
    335 					checkval(u, 128);  checkval(v, 128);
    336 				}
    337 				else
    338 				{
    339 					if(row<halfway)
    340 					{
    341 						checkval(u, 85);  checkval255(v);
    342 					}
    343 					else
    344 					{
    345 						checkval0(u);  checkval(v, 149);
    346 					}
    347 				}
    348 			}
    349 		}
    350 	}
    351 
    352 	bailout:
    353 	if(retval==0)
    354 	{
    355 		for(row=0; row<ph; row++)
    356 		{
    357 			for(col=0; col<pw; col++)
    358 				printf("%.3d ", buf[ypitch*row+col]);
    359 			printf("\n");
    360 		}
    361 		printf("\n");
    362 		for(row=0; row<ch; row++)
    363 		{
    364 			for(col=0; col<cw; col++)
    365 				printf("%.3d ", buf[ypitch*ph + (uvpitch*row+col)]);
    366 			printf("\n");
    367 		}
    368 		printf("\n");
    369 		for(row=0; row<ch; row++)
    370 		{
    371 			for(col=0; col<cw; col++)
    372 				printf("%.3d ", buf[ypitch*ph + uvpitch*ch + (uvpitch*row+col)]);
    373 			printf("\n");
    374 		}
    375 	}
    376 
    377 	return retval;
    378 }
    379 
    380 
    381 void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize, char *filename)
    382 {
    383 	FILE *file=fopen(filename, "wb");
    384 	if(!file || fwrite(jpegBuf, jpegSize, 1, file)!=1)
    385 	{
    386 		printf("ERROR: Could not write to %s.\n%s\n", filename, strerror(errno));
    387 		bailout();
    388 	}
    389 
    390 	bailout:
    391 	if(file) fclose(file);
    392 }
    393 
    394 
    395 void compTest(tjhandle handle, unsigned char **dstBuf,
    396 	unsigned long *dstSize, int w, int h, int pf, char *basename,
    397 	int subsamp, int jpegQual, int flags)
    398 {
    399 	char tempStr[1024];  unsigned char *srcBuf=NULL, *yuvBuf=NULL;
    400 	const char *pfStr=pixFormatStr[pf];
    401 	const char *buStrLong=(flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ";
    402 	const char *buStr=(flags&TJFLAG_BOTTOMUP)? "BU":"TD";
    403 
    404 	if((srcBuf=(unsigned char *)malloc(w*h*tjPixelSize[pf]))==NULL)
    405 		_throw("Memory allocation failure");
    406 	initBuf(srcBuf, w, h, pf, flags);
    407 
    408 	if(*dstBuf && *dstSize>0) memset(*dstBuf, 0, *dstSize);
    409 
    410 
    411 	if(!alloc) flags|=TJFLAG_NOREALLOC;
    412 	if(doyuv)
    413 	{
    414 		unsigned long yuvSize=tjBufSizeYUV2(w, pad, h, subsamp);
    415 		tjscalingfactor sf={1, 1};
    416 		tjhandle handle2=tjInitCompress();
    417 		if(!handle2) _throwtj();
    418 
    419 		if((yuvBuf=(unsigned char *)malloc(yuvSize))==NULL)
    420 			_throw("Memory allocation failure");
    421 		memset(yuvBuf, 0, yuvSize);
    422 
    423 		printf("%s %s -> YUV %s ... ", pfStr, buStrLong, subNameLong[subsamp]);
    424 		_tj(tjEncodeYUV3(handle2, srcBuf, w, 0, h, pf, yuvBuf, pad, subsamp,
    425 			flags));
    426 		tjDestroy(handle2);
    427 		if(checkBufYUV(yuvBuf, w, h, subsamp, sf)) printf("Passed.\n");
    428 		else printf("FAILED!\n");
    429 
    430 		printf("YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp], buStrLong,
    431 			jpegQual);
    432 		_tj(tjCompressFromYUV(handle, yuvBuf, w, pad, h, subsamp, dstBuf,
    433 			dstSize, jpegQual, flags));
    434 	}
    435 	else
    436 	{
    437 		printf("%s %s -> %s Q%d ... ", pfStr, buStrLong, subNameLong[subsamp],
    438 			jpegQual);
    439 		_tj(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
    440 			jpegQual, flags));
    441 	}
    442 
    443 	snprintf(tempStr, 1024, "%s_enc_%s_%s_%s_Q%d.jpg", basename, pfStr, buStr,
    444 		subName[subsamp], jpegQual);
    445 	writeJPEG(*dstBuf, *dstSize, tempStr);
    446 	printf("Done.\n  Result in %s\n", tempStr);
    447 
    448 	bailout:
    449 	if(yuvBuf) free(yuvBuf);
    450 	if(srcBuf) free(srcBuf);
    451 }
    452 
    453 
    454 void _decompTest(tjhandle handle, unsigned char *jpegBuf,
    455 	unsigned long jpegSize, int w, int h, int pf, char *basename, int subsamp,
    456 	int flags, tjscalingfactor sf)
    457 {
    458 	unsigned char *dstBuf=NULL, *yuvBuf=NULL;
    459 	int _hdrw=0, _hdrh=0, _hdrsubsamp=-1;
    460 	int scaledWidth=TJSCALED(w, sf);
    461 	int scaledHeight=TJSCALED(h, sf);
    462 	unsigned long dstSize=0;
    463 
    464 	_tj(tjDecompressHeader2(handle, jpegBuf, jpegSize, &_hdrw, &_hdrh,
    465 		&_hdrsubsamp));
    466 	if(_hdrw!=w || _hdrh!=h || _hdrsubsamp!=subsamp)
    467 		_throw("Incorrect JPEG header");
    468 
    469 	dstSize=scaledWidth*scaledHeight*tjPixelSize[pf];
    470 	if((dstBuf=(unsigned char *)malloc(dstSize))==NULL)
    471 		_throw("Memory allocation failure");
    472 	memset(dstBuf, 0, dstSize);
    473 
    474 	if(doyuv)
    475 	{
    476 		unsigned long yuvSize=tjBufSizeYUV2(scaledWidth, pad, scaledHeight,
    477 			subsamp);
    478 		tjhandle handle2=tjInitDecompress();
    479 		if(!handle2) _throwtj();
    480 
    481 		if((yuvBuf=(unsigned char *)malloc(yuvSize))==NULL)
    482 			_throw("Memory allocation failure");
    483 		memset(yuvBuf, 0, yuvSize);
    484 
    485 		printf("JPEG -> YUV %s ", subNameLong[subsamp]);
    486 		if(sf.num!=1 || sf.denom!=1)
    487 			printf("%d/%d ... ", sf.num, sf.denom);
    488 		else printf("... ");
    489 		_tj(tjDecompressToYUV2(handle, jpegBuf, jpegSize, yuvBuf, scaledWidth,
    490 			pad, scaledHeight, flags));
    491 		if(checkBufYUV(yuvBuf, scaledWidth, scaledHeight, subsamp, sf))
    492 			printf("Passed.\n");
    493 		else printf("FAILED!\n");
    494 
    495 		printf("YUV %s -> %s %s ... ", subNameLong[subsamp], pixFormatStr[pf],
    496 			(flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ");
    497 		_tj(tjDecodeYUV(handle2, yuvBuf, pad, subsamp, dstBuf, scaledWidth, 0,
    498 			scaledHeight, pf, flags));
    499 		tjDestroy(handle2);
    500 	}
    501 	else
    502 	{
    503 		printf("JPEG -> %s %s ", pixFormatStr[pf],
    504 			(flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ");
    505 		if(sf.num!=1 || sf.denom!=1)
    506 			printf("%d/%d ... ", sf.num, sf.denom);
    507 		else printf("... ");
    508 		_tj(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth, 0,
    509 			scaledHeight, pf, flags));
    510 	}
    511 
    512 	if(checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, flags))
    513 		printf("Passed.");
    514 	else printf("FAILED!");
    515 	printf("\n");
    516 
    517 	bailout:
    518 	if(yuvBuf) free(yuvBuf);
    519 	if(dstBuf) free(dstBuf);
    520 }
    521 
    522 
    523 void decompTest(tjhandle handle, unsigned char *jpegBuf,
    524 	unsigned long jpegSize, int w, int h, int pf, char *basename, int subsamp,
    525 	int flags)
    526 {
    527 	int i, n=0;
    528 	tjscalingfactor *sf=tjGetScalingFactors(&n);
    529 	if(!sf || !n) _throwtj();
    530 
    531 	for(i=0; i<n; i++)
    532 	{
    533 		if(subsamp==TJSAMP_444 || subsamp==TJSAMP_GRAY ||
    534 			(subsamp==TJSAMP_411 && sf[i].num==1 &&
    535 				(sf[i].denom==2 || sf[i].denom==1)) ||
    536 			(subsamp!=TJSAMP_411 && sf[i].num==1 &&
    537 				(sf[i].denom==4 || sf[i].denom==2 || sf[i].denom==1)))
    538 			_decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
    539 				flags, sf[i]);
    540 	}
    541 
    542 	bailout:
    543 	return;
    544 }
    545 
    546 
    547 void doTest(int w, int h, const int *formats, int nformats, int subsamp,
    548 	char *basename)
    549 {
    550 	tjhandle chandle=NULL, dhandle=NULL;
    551 	unsigned char *dstBuf=NULL;
    552 	unsigned long size=0;  int pfi, pf, i;
    553 
    554 	if(!alloc)
    555 		size=tjBufSize(w, h, subsamp);
    556 	if(size!=0)
    557 		if((dstBuf=(unsigned char *)tjAlloc(size))==NULL)
    558 			_throw("Memory allocation failure.");
    559 
    560 	if((chandle=tjInitCompress())==NULL || (dhandle=tjInitDecompress())==NULL)
    561 		_throwtj();
    562 
    563 	for(pfi=0; pfi<nformats; pfi++)
    564 	{
    565 		for(i=0; i<2; i++)
    566 		{
    567 			int flags=0;
    568 			if(subsamp==TJSAMP_422 || subsamp==TJSAMP_420 || subsamp==TJSAMP_440 ||
    569 				subsamp==TJSAMP_411)
    570 				flags|=TJFLAG_FASTUPSAMPLE;
    571 			if(i==1) flags|=TJFLAG_BOTTOMUP;
    572 			pf=formats[pfi];
    573 			compTest(chandle, &dstBuf, &size, w, h, pf, basename, subsamp, 100,
    574 				flags);
    575 			decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp,
    576 				flags);
    577 			if(pf>=TJPF_RGBX && pf<=TJPF_XRGB)
    578 			{
    579 				printf("\n");
    580 				decompTest(dhandle, dstBuf, size, w, h, pf+(TJPF_RGBA-TJPF_RGBX),
    581 					basename, subsamp, flags);
    582 			}
    583 			printf("\n");
    584 		}
    585 	}
    586 	printf("--------------------\n\n");
    587 
    588 	bailout:
    589 	if(chandle) tjDestroy(chandle);
    590 	if(dhandle) tjDestroy(dhandle);
    591 
    592 	if(dstBuf) tjFree(dstBuf);
    593 }
    594 
    595 
    596 void bufSizeTest(void)
    597 {
    598 	int w, h, i, subsamp;
    599 	unsigned char *srcBuf=NULL, *dstBuf=NULL;
    600 	tjhandle handle=NULL;
    601 	unsigned long dstSize=0;
    602 
    603 	if((handle=tjInitCompress())==NULL) _throwtj();
    604 
    605 	printf("Buffer size regression test\n");
    606 	for(subsamp=0; subsamp<TJ_NUMSAMP; subsamp++)
    607 	{
    608 		for(w=1; w<48; w++)
    609 		{
    610 			int maxh=(w==1)? 2048:48;
    611 			for(h=1; h<maxh; h++)
    612 			{
    613 				if(h%100==0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
    614 				if((srcBuf=(unsigned char *)malloc(w*h*4))==NULL)
    615 					_throw("Memory allocation failure");
    616 				if(!alloc || doyuv)
    617 				{
    618 					if(doyuv) dstSize=tjBufSizeYUV2(w, pad, h, subsamp);
    619 					else dstSize=tjBufSize(w, h, subsamp);
    620 					if((dstBuf=(unsigned char *)tjAlloc(dstSize))==NULL)
    621 						_throw("Memory allocation failure");
    622 				}
    623 
    624 				for(i=0; i<w*h*4; i++)
    625 				{
    626 					if(random()<RAND_MAX/2) srcBuf[i]=0;
    627 					else srcBuf[i]=255;
    628 				}
    629 
    630 				if(doyuv)
    631 				{
    632 					_tj(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf, pad,
    633 						subsamp, 0));
    634 				}
    635 				else
    636 				{
    637 					_tj(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
    638 						&dstSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
    639 				}
    640 				free(srcBuf);  srcBuf=NULL;
    641 				if(!alloc || doyuv)
    642 				{
    643 					tjFree(dstBuf);  dstBuf=NULL;
    644 				}
    645 
    646 				if((srcBuf=(unsigned char *)malloc(h*w*4))==NULL)
    647 					_throw("Memory allocation failure");
    648 				if(!alloc || doyuv)
    649 				{
    650 					if(doyuv) dstSize=tjBufSizeYUV2(h, pad, w, subsamp);
    651 					else dstSize=tjBufSize(h, w, subsamp);
    652 					if((dstBuf=(unsigned char *)tjAlloc(dstSize))==NULL)
    653 						_throw("Memory allocation failure");
    654 				}
    655 
    656 				for(i=0; i<h*w*4; i++)
    657 				{
    658 					if(random()<RAND_MAX/2) srcBuf[i]=0;
    659 					else srcBuf[i]=255;
    660 				}
    661 
    662 				if(doyuv)
    663 				{
    664 					_tj(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf, pad,
    665 						subsamp, 0));
    666 				}
    667 				else
    668 				{
    669 					_tj(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
    670 						&dstSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
    671 				}
    672 				free(srcBuf);  srcBuf=NULL;
    673 				if(!alloc || doyuv)
    674 				{
    675 					tjFree(dstBuf);  dstBuf=NULL;
    676 				}
    677 			}
    678 		}
    679 	}
    680 	printf("Done.      \n");
    681 
    682 	bailout:
    683 	if(srcBuf) free(srcBuf);
    684 	if(dstBuf) tjFree(dstBuf);
    685 	if(handle) tjDestroy(handle);
    686 }
    687 
    688 
    689 int main(int argc, char *argv[])
    690 {
    691 	int i, num4bf=5;
    692 	#ifdef _WIN32
    693 	srand((unsigned int)time(NULL));
    694 	#endif
    695 	if(argc>1)
    696 	{
    697 		for(i=1; i<argc; i++)
    698 		{
    699 			if(!strcasecmp(argv[i], "-yuv")) doyuv=1;
    700 			else if(!strcasecmp(argv[i], "-noyuvpad")) pad=1;
    701 			else if(!strcasecmp(argv[i], "-alloc")) alloc=1;
    702 			else usage(argv[0]);
    703 		}
    704 	}
    705 	if(alloc) printf("Testing automatic buffer allocation\n");
    706 	if(doyuv) num4bf=4;
    707 	doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
    708 	doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
    709 	doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
    710 	doTest(35, 39, _4byteFormats, num4bf, TJSAMP_422, "test");
    711 	doTest(39, 41, _3byteFormats, 2, TJSAMP_420, "test");
    712 	doTest(41, 35, _4byteFormats, num4bf, TJSAMP_420, "test");
    713 	doTest(35, 39, _3byteFormats, 2, TJSAMP_440, "test");
    714 	doTest(39, 41, _4byteFormats, num4bf, TJSAMP_440, "test");
    715 	doTest(41, 35, _3byteFormats, 2, TJSAMP_411, "test");
    716 	doTest(35, 39, _4byteFormats, num4bf, TJSAMP_411, "test");
    717 	doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
    718 	doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
    719 	doTest(35, 39, _4byteFormats, 4, TJSAMP_GRAY, "test");
    720 	bufSizeTest();
    721 	if(doyuv)
    722 	{
    723 		printf("\n--------------------\n\n");
    724 		doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
    725 		doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
    726 		doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
    727 		doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
    728 		doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
    729 		doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
    730 		doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");
    731 	}
    732 
    733 	return exitStatus;
    734 }
    735