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
24const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
25const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
26
27int exitstatus=0;
28#define bailout() {exitstatus=-1;  goto finally;}
29
30int 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
43void 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
76void 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
91int 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
177void 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
195void 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
234void 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
277void 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
328void 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
378int 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