Home | History | Annotate | Download | only in libjpeg_turbo
      1 /* Copyright (C)2004 Landmark Graphics Corporation
      2  * Copyright (C)2005 Sun Microsystems, Inc.
      3  * Copyright (C)2009 D. R. Commander
      4  *
      5  * This library is free software and may be redistributed and/or modified under
      6  * the terms of the wxWindows Library License, Version 3.1 or (at your option)
      7  * any later version.  The full license is in the LICENSE.txt file included
      8  * with this distribution.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * wxWindows Library License for more details.
     14  */
     15 
     16 #include <stdio.h>
     17 #include <stdlib.h>
     18 #include <string.h>
     19 #include "./rrtimer.h"
     20 #include "./turbojpeg.h"
     21 
     22 #define _catch(f) {if((f)==-1) {printf("TJPEG: %s\n", tjGetErrorStr());  bailout();}}
     23 
     24 const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
     25 const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
     26 
     27 int exitstatus=0;
     28 #define bailout() {exitstatus=-1;  goto finally;}
     29 
     30 int pixels[9][3]=
     31 {
     32 	{0, 255, 0},
     33 	{255, 0, 255},
     34 	{255, 255, 0},
     35 	{0, 0, 255},
     36 	{0, 255, 255},
     37 	{255, 0, 0},
     38 	{255, 255, 255},
     39 	{0, 0, 0},
     40 	{255, 0, 0}
     41 };
     42 
     43 void initbuf(unsigned char *buf, int w, int h, int ps, int flags)
     44 {
     45 	int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
     46 		_i, j;
     47 	if(flags&TJ_ALPHAFIRST) {roffset++;  goffset++;  boffset++;}
     48 	memset(buf, 0, w*h*ps);
     49 	for(_i=0; _i<16; _i++)
     50 	{
     51 		if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
     52 		for(j=0; j<w; j++)
     53 		{
     54 			buf[(w*i+j)*ps+roffset]=255;
     55 			if(((_i/8)+(j/8))%2==0)
     56 			{
     57 				buf[(w*i+j)*ps+goffset]=255;
     58 				buf[(w*i+j)*ps+boffset]=255;
     59 			}
     60 		}
     61 	}
     62 	for(_i=16; _i<h; _i++)
     63 	{
     64 		if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
     65 		for(j=0; j<w; j++)
     66 		{
     67 			if(((_i/8)+(j/8))%2!=0)
     68 			{
     69 				buf[(w*i+j)*ps+roffset]=255;
     70 				buf[(w*i+j)*ps+goffset]=255;
     71 			}
     72 		}
     73 	}
     74 }
     75 
     76 void dumpbuf(unsigned char *buf, int w, int h, int ps, int flags)
     77 {
     78 	int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
     79 		j;
     80 	for(i=0; i<h; i++)
     81 	{
     82 		for(j=0; j<w; j++)
     83 		{
     84 			printf("%.3d/%.3d/%.3d ", buf[(w*i+j)*ps+roffset],
     85 				buf[(w*i+j)*ps+roffset], buf[(w*i+j)*ps+roffset]);
     86 		}
     87 		printf("\n");
     88 	}
     89 }
     90 
     91 int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
     92 {
     93 	int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
     94 		_i, j;
     95 	if(flags&TJ_ALPHAFIRST) {roffset++;  goffset++;  boffset++;}
     96 	if(subsamp==TJ_GRAYSCALE)
     97 	{
     98 		for(_i=0; _i<16; _i++)
     99 		{
    100 			if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
    101 			for(j=0; j<w; j++)
    102 			{
    103 				unsigned char r=buf[(w*i+j)*ps+roffset],
    104 					g=buf[(w*i+j)*ps+goffset],
    105 					b=buf[(w*i+j)*ps+boffset];
    106 				if(((_i/8)+(j/8))%2==0)
    107 				{
    108 					if(r<253 || g<253 || b<253) return 0;
    109 				}
    110 				else
    111 				{
    112 					if(r<74 || r>78 || g<74 || g>78 || b<74 || b>78) return 0;
    113 				}
    114 			}
    115 		}
    116 		for(_i=16; _i<h; _i++)
    117 		{
    118 			if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
    119 			for(j=0; j<w; j++)
    120 			{
    121 				unsigned char r=buf[(w*i+j)*ps+roffset],
    122 					g=buf[(w*i+j)*ps+goffset],
    123 					b=buf[(w*i+j)*ps+boffset];
    124 				if(((_i/8)+(j/8))%2==0)
    125 				{
    126 					if(r>2 || g>2 || b>2) return 0;
    127 				}
    128 				else
    129 				{
    130 					if(r<224 || r>228 || g<224 || g>228 || b<224 || b>228) return 0;
    131 				}
    132 			}
    133 		}
    134 	}
    135 	else
    136 	{
    137 		for(_i=0; _i<16; _i++)
    138 		{
    139 			if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
    140 			for(j=0; j<w; j++)
    141 			{
    142 				if(buf[(w*i+j)*ps+roffset]<253) return 0;
    143 				if(((_i/8)+(j/8))%2==0)
    144 				{
    145 					if(buf[(w*i+j)*ps+goffset]<253) return 0;
    146 					if(buf[(w*i+j)*ps+boffset]<253) return 0;
    147 				}
    148 				else
    149 				{
    150 					if(buf[(w*i+j)*ps+goffset]>2) return 0;
    151 					if(buf[(w*i+j)*ps+boffset]>2) return 0;
    152 				}
    153 			}
    154 		}
    155 		for(_i=16; _i<h; _i++)
    156 		{
    157 			if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
    158 			for(j=0; j<w; j++)
    159 			{
    160 				if(buf[(w*i+j)*ps+boffset]>2) return 0;
    161 				if(((_i/8)+(j/8))%2==0)
    162 				{
    163 					if(buf[(w*i+j)*ps+roffset]>2) return 0;
    164 					if(buf[(w*i+j)*ps+goffset]>2) return 0;
    165 				}
    166 				else
    167 				{
    168 					if(buf[(w*i+j)*ps+roffset]<253) return 0;
    169 					if(buf[(w*i+j)*ps+goffset]<253) return 0;
    170 				}
    171 			}
    172 		}
    173 	}
    174 	return 1;
    175 }
    176 
    177 void writejpeg(unsigned char *jpegbuf, unsigned long jpgbufsize, char *filename)
    178 {
    179 	FILE *outfile=NULL;
    180 	if((outfile=fopen(filename, "wb"))==NULL)
    181 	{
    182 		printf("ERROR: Could not open %s for writing.\n", filename);
    183 		bailout();
    184 	}
    185 	if(fwrite(jpegbuf, jpgbufsize, 1, outfile)!=1)
    186 	{
    187 		printf("ERROR: Could not write to %s.\n", filename);
    188 		bailout();
    189 	}
    190 
    191 	finally:
    192 	if(outfile) fclose(outfile);
    193 }
    194 
    195 void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
    196 	int w, int h, int ps, char *basefilename, int subsamp, int qual, int flags)
    197 {
    198 	char tempstr[1024];  unsigned char *bmpbuf=NULL;
    199 	const char *pixformat;  double t;
    200 
    201 	if(flags&TJ_BGR)
    202 	{
    203 		if(ps==3) pixformat="BGR";
    204 		else {if(flags&TJ_ALPHAFIRST) pixformat="ABGR";  else pixformat="BGRA";}
    205 	}
    206 	else
    207 	{
    208 		if(ps==3) pixformat="RGB";
    209 		else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB";  else pixformat="RGBA";}
    210 	}
    211 	printf("%s %s -> %s Q%d ... ", pixformat,
    212 		(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp], qual);
    213 
    214 	if((bmpbuf=(unsigned char *)malloc(w*h*ps+1))==NULL)
    215 	{
    216 		printf("ERROR: Could not allocate buffer\n");  bailout();
    217 	}
    218 	initbuf(bmpbuf, w, h, ps, flags);
    219 	memset(jpegbuf, 0, TJBUFSIZE(w, h));
    220 
    221 	t=rrtime();
    222 	_catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual, flags));
    223 	t=rrtime()-t;
    224 
    225 	sprintf(tempstr, "%s_enc_%s_%s_%sQ%d.jpg", basefilename, pixformat,
    226 		(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp], qual);
    227 	writejpeg(jpegbuf, *size, tempstr);
    228 	printf("Done.  %f ms\n  Result in %s\n", t*1000., tempstr);
    229 
    230 	finally:
    231 	if(bmpbuf) free(bmpbuf);
    232 }
    233 
    234 void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
    235 	int w, int h, int ps, char *basefilename, int subsamp, int qual, int flags)
    236 {
    237 	unsigned char *bmpbuf=NULL;
    238 	const char *pixformat;  int _w=0, _h=0;  double t;
    239 
    240 	if(flags&TJ_BGR)
    241 	{
    242 		if(ps==3) pixformat="BGR";
    243 		else {if(flags&TJ_ALPHAFIRST) pixformat="ABGR";  else pixformat="BGRA";}
    244 	}
    245 	else
    246 	{
    247 		if(ps==3) pixformat="RGB";
    248 		else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB";  else pixformat="RGBA";}
    249 	}
    250 	printf("JPEG -> %s %s ... ", pixformat, (flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
    251 
    252 	_catch(tjDecompressHeader(hnd, jpegbuf, jpegsize, &_w, &_h));
    253 	if(_w!=w || _h!=h)
    254 	{
    255 		printf("Incorrect JPEG header\n");  bailout();
    256 	}
    257 
    258 	if((bmpbuf=(unsigned char *)malloc(w*h*ps+1))==NULL)
    259 	{
    260 		printf("ERROR: Could not allocate buffer\n");  bailout();
    261 	}
    262 	memset(bmpbuf, 0, w*ps*h);
    263 
    264 	t=rrtime();
    265 	_catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
    266 	t=rrtime()-t;
    267 
    268 	if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
    269 	else {printf("FAILED!");  dumpbuf(bmpbuf, w, h, ps, flags);}
    270 
    271 	printf("  %f ms\n\n", t*1000.);
    272 
    273 	finally:
    274 	if(bmpbuf) free(bmpbuf);
    275 }
    276 
    277 void dotest(int w, int h, int ps, int subsamp, char *basefilename)
    278 {
    279 	tjhandle hnd=NULL, dhnd=NULL;  unsigned char *jpegbuf=NULL;
    280 	unsigned long size;
    281 
    282 	if((jpegbuf=(unsigned char *)malloc(TJBUFSIZE(w, h))) == NULL)
    283 	{
    284 		puts("ERROR: Could not allocate buffer.");  bailout();
    285 	}
    286 
    287 	if((hnd=tjInitCompress())==NULL)
    288 		{printf("Error in tjInitCompress():\n%s\n", tjGetErrorStr());  bailout();}
    289 	if((dhnd=tjInitDecompress())==NULL)
    290 		{printf("Error in tjInitDecompress():\n%s\n", tjGetErrorStr());  bailout();}
    291 
    292 	gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, 0);
    293 	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, 0);
    294 
    295 	gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
    296 	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
    297 
    298 	gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
    299 	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
    300 
    301 	gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
    302 	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
    303 
    304 	if(ps==4)
    305 	{
    306 		gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
    307 		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
    308 
    309 		gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
    310 		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
    311 
    312 		gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
    313 		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
    314 
    315 		gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
    316 		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
    317 	}
    318 
    319 	finally:
    320 	if(hnd) tjDestroy(hnd);
    321 	if(dhnd) tjDestroy(dhnd);
    322 
    323 	if(jpegbuf) free(jpegbuf);
    324 }
    325 
    326 #define MAXLENGTH 2048
    327 
    328 void dotest1(void)
    329 {
    330 	int i, j, i2;  unsigned char *bmpbuf=NULL, *jpgbuf=NULL;
    331 	tjhandle hnd=NULL;  unsigned long size;
    332 	if((hnd=tjInitCompress())==NULL)
    333 		{printf("Error in tjInitCompress():\n%s\n", tjGetErrorStr());  bailout();}
    334 	printf("Buffer size regression test\n");
    335 	for(j=1; j<48; j++)
    336 	{
    337 		for(i=1; i<(j==1?MAXLENGTH:48); i++)
    338 		{
    339 			if(i%100==0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", i, j);
    340 			if((bmpbuf=(unsigned char *)malloc(i*j*4))==NULL
    341 			|| (jpgbuf=(unsigned char *)malloc(TJBUFSIZE(i, j)))==NULL)
    342 			{
    343 				printf("Memory allocation failure\n");  bailout();
    344 			}
    345 			memset(bmpbuf, 0, i*j*4);
    346 			for(i2=0; i2<i*j; i2++)
    347 			{
    348 				bmpbuf[i2*4]=pixels[i2%9][2];
    349 				bmpbuf[i2*4+1]=pixels[i2%9][1];
    350 				bmpbuf[i2*2+2]=pixels[i2%9][0];
    351 			}
    352 			_catch(tjCompress(hnd, bmpbuf, i, i*4, j, 4,
    353 				jpgbuf, &size, TJ_444, 100, TJ_BGR));
    354 			free(bmpbuf);  bmpbuf=NULL;  free(jpgbuf);  jpgbuf=NULL;
    355 
    356 			if((bmpbuf=(unsigned char *)malloc(j*i*4))==NULL
    357 			|| (jpgbuf=(unsigned char *)malloc(TJBUFSIZE(j, i)))==NULL)
    358 			{
    359 				printf("Memory allocation failure\n");  bailout();
    360 			}
    361 			for(i2=0; i2<j*i*4; i2++)
    362 			{
    363 				if(i2%2==0) bmpbuf[i2]=0xFF;
    364 				else bmpbuf[i2]=0;
    365 			}
    366 			_catch(tjCompress(hnd, bmpbuf, j, j*4, i, 4,
    367 				jpgbuf, &size, TJ_444, 100, TJ_BGR));
    368 			free(bmpbuf);  bmpbuf=NULL;  free(jpgbuf);  jpgbuf=NULL;
    369 		}
    370 	}
    371 	printf("Done.      \n");
    372 
    373 	finally:
    374 	if(bmpbuf) free(bmpbuf);  if(jpgbuf) free(jpgbuf);
    375 	if(hnd) tjDestroy(hnd);
    376 }
    377 
    378 int main(int argc, char *argv[])
    379 {
    380 	dotest(35, 41, 3, TJ_444, "test");
    381 	dotest(35, 41, 4, TJ_444, "test");
    382 	dotest(35, 41, 3, TJ_GRAYSCALE, "test");
    383 	dotest(35, 41, 4, TJ_GRAYSCALE, "test");
    384 	dotest1();
    385 
    386 	return exitstatus;
    387 }
    388