1 /*
2 * Copyright (C)2009-2019, 2021-2023 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 #ifdef _MSC_VER
30 #define _CRT_SECURE_NO_DEPRECATE
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <math.h>
38 #include <errno.h>
39 #include <limits.h>
40 #include <cdjpeg.h>
41 #include "./tjutil.h"
42 #include "./turbojpeg.h"
43
44
45 #define THROW(op, err) { \
46 fprintf(stderr, "ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \
47 retval = -1; goto bailout; \
48 }
49 #define THROW_UNIX(m) THROW(m, strerror(errno))
50
51 static char tjErrorStr[JMSG_LENGTH_MAX] = "\0",
52 tjErrorMsg[JMSG_LENGTH_MAX] = "\0";
53 static int tjErrorLine = -1, tjErrorCode = -1;
54
55 #define THROW_TJG(m) { \
56 fprintf(stderr, "ERROR in line %d while %s:\n%s\n", __LINE__, m, \
57 tjGetErrorStr2(NULL)); \
58 retval = -1; goto bailout; \
59 }
60
61 #define THROW_TJ(m) { \
62 int _tjErrorCode = tjGetErrorCode(handle); \
63 char *_tjErrorStr = tjGetErrorStr2(handle); \
64 \
65 if (!(flags & TJFLAG_STOPONWARNING) && _tjErrorCode == TJERR_WARNING) { \
66 if (strncmp(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX) || \
67 strncmp(tjErrorMsg, m, JMSG_LENGTH_MAX) || \
68 tjErrorCode != _tjErrorCode || tjErrorLine != __LINE__) { \
69 strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX); \
70 tjErrorStr[JMSG_LENGTH_MAX - 1] = '\0'; \
71 strncpy(tjErrorMsg, m, JMSG_LENGTH_MAX); \
72 tjErrorMsg[JMSG_LENGTH_MAX - 1] = '\0'; \
73 tjErrorCode = _tjErrorCode; \
74 tjErrorLine = __LINE__; \
75 fprintf(stderr, "WARNING in line %d while %s:\n%s\n", __LINE__, m, \
76 _tjErrorStr); \
77 } \
78 } else { \
79 fprintf(stderr, "%s in line %d while %s:\n%s\n", \
80 _tjErrorCode == TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, m, \
81 _tjErrorStr); \
82 retval = -1; goto bailout; \
83 } \
84 }
85
86 static int flags = TJFLAG_NOREALLOC, compOnly = 0, decompOnly = 0, doYUV = 0,
87 quiet = 0, doTile = 0, pf = TJPF_BGR, yuvAlign = 1, doWrite = 1;
88 static char *ext = "ppm";
89 static const char *pixFormatStr[TJ_NUMPF] = {
90 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "", "CMYK"
91 };
92 static const char *subNameLong[TJ_NUMSAMP] = {
93 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
94 };
95 static const char *csName[TJ_NUMCS] = {
96 "RGB", "YCbCr", "GRAY", "CMYK", "YCCK"
97 };
98 static const char *subName[TJ_NUMSAMP] = {
99 "444", "422", "420", "GRAY", "440", "411"
100 };
101 static tjscalingfactor *scalingFactors = NULL, sf = { 1, 1 };
102 static int nsf = 0, xformOp = TJXOP_NONE, xformOpt = 0;
103 static int (*customFilter) (short *, tjregion, tjregion, int, int,
104 tjtransform *);
105 static double benchTime = 5.0, warmup = 1.0;
106
107
formatName(int subsamp,int cs,char * buf)108 static char *formatName(int subsamp, int cs, char *buf)
109 {
110 if (cs == TJCS_YCbCr)
111 return (char *)subNameLong[subsamp];
112 else if (cs == TJCS_YCCK || cs == TJCS_CMYK) {
113 SNPRINTF(buf, 80, "%s %s", csName[cs], subNameLong[subsamp]);
114 return buf;
115 } else
116 return (char *)csName[cs];
117 }
118
119
sigfig(double val,int figs,char * buf,int len)120 static char *sigfig(double val, int figs, char *buf, int len)
121 {
122 char format[80];
123 int digitsAfterDecimal = figs - (int)ceil(log10(fabs(val)));
124
125 if (digitsAfterDecimal < 1)
126 SNPRINTF(format, 80, "%%.0f");
127 else
128 SNPRINTF(format, 80, "%%.%df", digitsAfterDecimal);
129 SNPRINTF(buf, len, format, val);
130 return buf;
131 }
132
133
134 /* Custom DCT filter which produces a negative of the image */
dummyDCTFilter(short * coeffs,tjregion arrayRegion,tjregion planeRegion,int componentIndex,int transformIndex,tjtransform * transform)135 static int dummyDCTFilter(short *coeffs, tjregion arrayRegion,
136 tjregion planeRegion, int componentIndex,
137 int transformIndex, tjtransform *transform)
138 {
139 int i;
140
141 for (i = 0; i < arrayRegion.w * arrayRegion.h; i++)
142 coeffs[i] = -coeffs[i];
143 return 0;
144 }
145
146
147 /* Decompression test */
decomp(unsigned char * srcBuf,unsigned char ** jpegBuf,unsigned long * jpegSize,unsigned char * dstBuf,int w,int h,int subsamp,int jpegQual,char * fileName,int tilew,int tileh)148 static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
149 unsigned long *jpegSize, unsigned char *dstBuf, int w, int h,
150 int subsamp, int jpegQual, char *fileName, int tilew,
151 int tileh)
152 {
153 char tempStr[1024], sizeStr[24] = "\0", qualStr[13] = "\0", *ptr;
154 FILE *file = NULL;
155 tjhandle handle = NULL;
156 int row, col, iter = 0, dstBufAlloc = 0, retval = 0;
157 double elapsed, elapsedDecode;
158 int ps = tjPixelSize[pf];
159 int scaledw = TJSCALED(w, sf);
160 int scaledh = TJSCALED(h, sf);
161 int pitch = scaledw * ps;
162 int ntilesw = (w + tilew - 1) / tilew, ntilesh = (h + tileh - 1) / tileh;
163 unsigned char *dstPtr, *dstPtr2, *yuvBuf = NULL;
164
165 if (jpegQual > 0) {
166 SNPRINTF(qualStr, 13, "_Q%d", jpegQual);
167 qualStr[12] = 0;
168 }
169
170 if ((handle = tjInitDecompress()) == NULL)
171 THROW_TJ("executing tjInitDecompress()");
172
173 if (dstBuf == NULL) {
174 if ((unsigned long long)pitch * (unsigned long long)scaledh >
175 (unsigned long long)((size_t)-1))
176 THROW("allocating destination buffer", "Image is too large");
177 if ((dstBuf = (unsigned char *)malloc((size_t)pitch * scaledh)) == NULL)
178 THROW_UNIX("allocating destination buffer");
179 dstBufAlloc = 1;
180 }
181 /* Set the destination buffer to gray so we know whether the decompressor
182 attempted to write to it */
183 memset(dstBuf, 127, (size_t)pitch * scaledh);
184
185 if (doYUV) {
186 int width = doTile ? tilew : scaledw;
187 int height = doTile ? tileh : scaledh;
188 unsigned long yuvSize = tjBufSizeYUV2(width, yuvAlign, height, subsamp);
189
190 if (yuvSize == (unsigned long)-1)
191 THROW_TJ("allocating YUV buffer");
192 if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
193 THROW_UNIX("allocating YUV buffer");
194 memset(yuvBuf, 127, yuvSize);
195 }
196
197 /* Benchmark */
198 iter = -1;
199 elapsed = elapsedDecode = 0.;
200 while (1) {
201 int tile = 0;
202 double start = getTime();
203
204 for (row = 0, dstPtr = dstBuf; row < ntilesh;
205 row++, dstPtr += (size_t)pitch * tileh) {
206 for (col = 0, dstPtr2 = dstPtr; col < ntilesw;
207 col++, tile++, dstPtr2 += ps * tilew) {
208 int width = doTile ? min(tilew, w - col * tilew) : scaledw;
209 int height = doTile ? min(tileh, h - row * tileh) : scaledh;
210
211 if (doYUV) {
212 double startDecode;
213
214 if (tjDecompressToYUV2(handle, jpegBuf[tile], jpegSize[tile], yuvBuf,
215 width, yuvAlign, height, flags) == -1)
216 THROW_TJ("executing tjDecompressToYUV2()");
217 startDecode = getTime();
218 if (tjDecodeYUV(handle, yuvBuf, yuvAlign, subsamp, dstPtr2, width,
219 pitch, height, pf, flags) == -1)
220 THROW_TJ("executing tjDecodeYUV()");
221 if (iter >= 0) elapsedDecode += getTime() - startDecode;
222 } else if (tjDecompress2(handle, jpegBuf[tile], jpegSize[tile],
223 dstPtr2, width, pitch, height, pf,
224 flags) == -1)
225 THROW_TJ("executing tjDecompress2()");
226 }
227 }
228 elapsed += getTime() - start;
229 if (iter >= 0) {
230 iter++;
231 if (elapsed >= benchTime) break;
232 } else if (elapsed >= warmup) {
233 iter = 0;
234 elapsed = elapsedDecode = 0.;
235 }
236 }
237 if (doYUV) elapsed -= elapsedDecode;
238
239 if (tjDestroy(handle) == -1) THROW_TJ("executing tjDestroy()");
240 handle = NULL;
241
242 if (quiet) {
243 fprintf(stderr, "%-6s%s",
244 sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
245 tempStr, 1024),
246 quiet == 2 ? "\n" : " ");
247 if (doYUV)
248 fprintf(stderr, "%s\n",
249 sigfig((double)(w * h) / 1000000. * (double)iter / elapsedDecode,
250 4, tempStr, 1024));
251 else if (quiet != 2) fprintf(stderr, "\n");
252 } else {
253 fprintf(stderr, "%s --> Frame rate: %f fps\n",
254 doYUV ? "Decomp to YUV" : "Decompress ", (double)iter / elapsed);
255 fprintf(stderr,
256 " Throughput: %f Megapixels/sec\n",
257 (double)(w * h) / 1000000. * (double)iter / elapsed);
258 if (doYUV) {
259 fprintf(stderr, "YUV Decode --> Frame rate: %f fps\n",
260 (double)iter / elapsedDecode);
261 fprintf(stderr,
262 " Throughput: %f Megapixels/sec\n",
263 (double)(w * h) / 1000000. * (double)iter / elapsedDecode);
264 }
265 }
266
267 if (!doWrite) goto bailout;
268
269 if (sf.num != 1 || sf.denom != 1)
270 SNPRINTF(sizeStr, 24, "%d_%d", sf.num, sf.denom);
271 else if (tilew != w || tileh != h)
272 SNPRINTF(sizeStr, 24, "%dx%d", tilew, tileh);
273 else SNPRINTF(sizeStr, 24, "full");
274 if (decompOnly)
275 SNPRINTF(tempStr, 1024, "%s_%s.%s", fileName, sizeStr, ext);
276 else
277 SNPRINTF(tempStr, 1024, "%s_%s%s_%s.%s", fileName, subName[subsamp],
278 qualStr, sizeStr, ext);
279
280 if (tjSaveImage(tempStr, dstBuf, scaledw, 0, scaledh, pf, flags) == -1)
281 THROW_TJG("saving output image");
282 ptr = strrchr(tempStr, '.');
283 SNPRINTF(ptr, 1024 - (ptr - tempStr), "-err.%s", ext);
284 if (srcBuf && sf.num == 1 && sf.denom == 1) {
285 if (!quiet) fprintf(stderr, "Compression error written to %s.\n", tempStr);
286 if (subsamp == TJSAMP_GRAY) {
287 unsigned long index, index2;
288
289 for (row = 0, index = 0; row < h; row++, index += pitch) {
290 for (col = 0, index2 = index; col < w; col++, index2 += ps) {
291 unsigned long rindex = index2 + tjRedOffset[pf];
292 unsigned long gindex = index2 + tjGreenOffset[pf];
293 unsigned long bindex = index2 + tjBlueOffset[pf];
294 int y = (int)((double)srcBuf[rindex] * 0.299 +
295 (double)srcBuf[gindex] * 0.587 +
296 (double)srcBuf[bindex] * 0.114 + 0.5);
297
298 if (y > 255) y = 255;
299 if (y < 0) y = 0;
300 dstBuf[rindex] = (unsigned char)abs(dstBuf[rindex] - y);
301 dstBuf[gindex] = (unsigned char)abs(dstBuf[gindex] - y);
302 dstBuf[bindex] = (unsigned char)abs(dstBuf[bindex] - y);
303 }
304 }
305 } else {
306 for (row = 0; row < h; row++)
307 for (col = 0; col < w * ps; col++)
308 dstBuf[pitch * row + col] =
309 (unsigned char)abs(dstBuf[pitch * row + col] -
310 srcBuf[pitch * row + col]);
311 }
312 if (tjSaveImage(tempStr, dstBuf, w, 0, h, pf, flags) == -1)
313 THROW_TJG("saving output image");
314 }
315
316 bailout:
317 if (file) fclose(file);
318 if (handle) tjDestroy(handle);
319 if (dstBufAlloc) free(dstBuf);
320 free(yuvBuf);
321 return retval;
322 }
323
324
fullTest(unsigned char * srcBuf,int w,int h,int subsamp,int jpegQual,char * fileName)325 static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
326 int jpegQual, char *fileName)
327 {
328 char tempStr[1024], tempStr2[80];
329 FILE *file = NULL;
330 tjhandle handle = NULL;
331 unsigned char **jpegBuf = NULL, *yuvBuf = NULL, *tmpBuf = NULL, *srcPtr,
332 *srcPtr2;
333 double start, elapsed, elapsedEncode;
334 int totalJpegSize = 0, row, col, i, tilew = w, tileh = h, retval = 0;
335 int iter;
336 unsigned long *jpegSize = NULL, yuvSize = 0;
337 int ps = tjPixelSize[pf];
338 int ntilesw = 1, ntilesh = 1, pitch = w * ps;
339 const char *pfStr = pixFormatStr[pf];
340
341 if ((unsigned long long)pitch * (unsigned long long)h >
342 (unsigned long long)((size_t)-1))
343 THROW("allocating temporary image buffer", "Image is too large");
344 if ((tmpBuf = (unsigned char *)malloc((size_t)pitch * h)) == NULL)
345 THROW_UNIX("allocating temporary image buffer");
346
347 if (!quiet)
348 fprintf(stderr, ">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", pfStr,
349 (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down",
350 subNameLong[subsamp], jpegQual);
351
352 for (tilew = doTile ? 8 : w, tileh = doTile ? 8 : h; ;
353 tilew *= 2, tileh *= 2) {
354 if (tilew > w) tilew = w;
355 if (tileh > h) tileh = h;
356 ntilesw = (w + tilew - 1) / tilew;
357 ntilesh = (h + tileh - 1) / tileh;
358
359 if ((jpegBuf = (unsigned char **)malloc(sizeof(unsigned char *) *
360 ntilesw * ntilesh)) == NULL)
361 THROW_UNIX("allocating JPEG tile array");
362 memset(jpegBuf, 0, sizeof(unsigned char *) * ntilesw * ntilesh);
363 if ((jpegSize = (unsigned long *)malloc(sizeof(unsigned long) *
364 ntilesw * ntilesh)) == NULL)
365 THROW_UNIX("allocating JPEG size array");
366 memset(jpegSize, 0, sizeof(unsigned long) * ntilesw * ntilesh);
367
368 if ((flags & TJFLAG_NOREALLOC) != 0)
369 for (i = 0; i < ntilesw * ntilesh; i++) {
370 if (tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX)
371 THROW("getting buffer size", "Image is too large");
372 if ((jpegBuf[i] = (unsigned char *)
373 tjAlloc(tjBufSize(tilew, tileh, subsamp))) == NULL)
374 THROW_UNIX("allocating JPEG tiles");
375 }
376
377 /* Compression test */
378 if (quiet == 1)
379 fprintf(stderr, "%-4s (%s) %-5s %-3d ", pfStr,
380 (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD", subNameLong[subsamp],
381 jpegQual);
382 for (i = 0; i < h; i++)
383 memcpy(&tmpBuf[pitch * i], &srcBuf[w * ps * i], w * ps);
384 if ((handle = tjInitCompress()) == NULL)
385 THROW_TJ("executing tjInitCompress()");
386
387 if (doYUV) {
388 yuvSize = tjBufSizeYUV2(tilew, yuvAlign, tileh, subsamp);
389 if (yuvSize == (unsigned long)-1)
390 THROW_TJ("allocating YUV buffer");
391 if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
392 THROW_UNIX("allocating YUV buffer");
393 memset(yuvBuf, 127, yuvSize);
394 }
395
396 /* Benchmark */
397 iter = -1;
398 elapsed = elapsedEncode = 0.;
399 while (1) {
400 int tile = 0;
401
402 totalJpegSize = 0;
403 start = getTime();
404 for (row = 0, srcPtr = srcBuf; row < ntilesh;
405 row++, srcPtr += pitch * tileh) {
406 for (col = 0, srcPtr2 = srcPtr; col < ntilesw;
407 col++, tile++, srcPtr2 += ps * tilew) {
408 int width = min(tilew, w - col * tilew);
409 int height = min(tileh, h - row * tileh);
410
411 if (doYUV) {
412 double startEncode = getTime();
413
414 if (tjEncodeYUV3(handle, srcPtr2, width, pitch, height, pf, yuvBuf,
415 yuvAlign, subsamp, flags) == -1)
416 THROW_TJ("executing tjEncodeYUV3()");
417 if (iter >= 0) elapsedEncode += getTime() - startEncode;
418 if (tjCompressFromYUV(handle, yuvBuf, width, yuvAlign, height,
419 subsamp, &jpegBuf[tile], &jpegSize[tile],
420 jpegQual, flags) == -1)
421 THROW_TJ("executing tjCompressFromYUV()");
422 } else {
423 if (tjCompress2(handle, srcPtr2, width, pitch, height, pf,
424 &jpegBuf[tile], &jpegSize[tile], subsamp, jpegQual,
425 flags) == -1)
426 THROW_TJ("executing tjCompress2()");
427 }
428 totalJpegSize += jpegSize[tile];
429 }
430 }
431 elapsed += getTime() - start;
432 if (iter >= 0) {
433 iter++;
434 if (elapsed >= benchTime) break;
435 } else if (elapsed >= warmup) {
436 iter = 0;
437 elapsed = elapsedEncode = 0.;
438 }
439 }
440 if (doYUV) elapsed -= elapsedEncode;
441
442 if (tjDestroy(handle) == -1) THROW_TJ("executing tjDestroy()");
443 handle = NULL;
444
445 if (quiet == 1) fprintf(stderr, "%-5d %-5d ", tilew, tileh);
446 if (quiet) {
447 if (doYUV)
448 fprintf(stderr, "%-6s%s",
449 sigfig((double)(w * h) / 1000000. *
450 (double)iter / elapsedEncode, 4, tempStr, 1024),
451 quiet == 2 ? "\n" : " ");
452 fprintf(stderr, "%-6s%s",
453 sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
454 tempStr, 1024),
455 quiet == 2 ? "\n" : " ");
456 fprintf(stderr, "%-6s%s",
457 sigfig((double)(w * h * ps) / (double)totalJpegSize, 4, tempStr2,
458 80),
459 quiet == 2 ? "\n" : " ");
460 } else {
461 fprintf(stderr, "\n%s size: %d x %d\n", doTile ? "Tile" : "Image", tilew,
462 tileh);
463 if (doYUV) {
464 fprintf(stderr, "Encode YUV --> Frame rate: %f fps\n",
465 (double)iter / elapsedEncode);
466 fprintf(stderr, " Output image size: %lu bytes\n",
467 yuvSize);
468 fprintf(stderr, " Compression ratio: %f:1\n",
469 (double)(w * h * ps) / (double)yuvSize);
470 fprintf(stderr,
471 " Throughput: %f Megapixels/sec\n",
472 (double)(w * h) / 1000000. * (double)iter / elapsedEncode);
473 fprintf(stderr,
474 " Output bit stream: %f Megabits/sec\n",
475 (double)yuvSize * 8. / 1000000. * (double)iter / elapsedEncode);
476 }
477 fprintf(stderr, "%s --> Frame rate: %f fps\n",
478 doYUV ? "Comp from YUV" : "Compress ",
479 (double)iter / elapsed);
480 fprintf(stderr, " Output image size: %d bytes\n",
481 totalJpegSize);
482 fprintf(stderr, " Compression ratio: %f:1\n",
483 (double)(w * h * ps) / (double)totalJpegSize);
484 fprintf(stderr,
485 " Throughput: %f Megapixels/sec\n",
486 (double)(w * h) / 1000000. * (double)iter / elapsed);
487 fprintf(stderr,
488 " Output bit stream: %f Megabits/sec\n",
489 (double)totalJpegSize * 8. / 1000000. * (double)iter / elapsed);
490 }
491 if (tilew == w && tileh == h && doWrite) {
492 SNPRINTF(tempStr, 1024, "%s_%s_Q%d.jpg", fileName, subName[subsamp],
493 jpegQual);
494 if ((file = fopen(tempStr, "wb")) == NULL)
495 THROW_UNIX("opening reference image");
496 if (fwrite(jpegBuf[0], jpegSize[0], 1, file) != 1)
497 THROW_UNIX("writing reference image");
498 fclose(file); file = NULL;
499 if (!quiet) fprintf(stderr, "Reference image written to %s\n", tempStr);
500 }
501
502 /* Decompression test */
503 if (!compOnly) {
504 if (decomp(srcBuf, jpegBuf, jpegSize, tmpBuf, w, h, subsamp, jpegQual,
505 fileName, tilew, tileh) == -1)
506 goto bailout;
507 } else if (quiet == 1) fprintf(stderr, "N/A\n");
508
509 for (i = 0; i < ntilesw * ntilesh; i++) {
510 tjFree(jpegBuf[i]);
511 jpegBuf[i] = NULL;
512 }
513 free(jpegBuf); jpegBuf = NULL;
514 free(jpegSize); jpegSize = NULL;
515 if (doYUV) {
516 free(yuvBuf); yuvBuf = NULL;
517 }
518
519 if (tilew == w && tileh == h) break;
520 }
521
522 bailout:
523 if (file) fclose(file);
524 if (jpegBuf) {
525 for (i = 0; i < ntilesw * ntilesh; i++)
526 tjFree(jpegBuf[i]);
527 }
528 free(jpegBuf);
529 free(yuvBuf);
530 free(jpegSize);
531 free(tmpBuf);
532 if (handle) tjDestroy(handle);
533 return retval;
534 }
535
536
decompTest(char * fileName)537 static int decompTest(char *fileName)
538 {
539 FILE *file = NULL;
540 tjhandle handle = NULL;
541 unsigned char **jpegBuf = NULL, *srcBuf = NULL;
542 unsigned long *jpegSize = NULL, srcSize, totalJpegSize;
543 tjtransform *t = NULL;
544 double start, elapsed;
545 int ps = tjPixelSize[pf], tile, row, col, i, iter, retval = 0, decompsrc = 0;
546 char *temp = NULL, tempStr[80], tempStr2[80];
547 /* Original image */
548 int w = 0, h = 0, tilew, tileh, ntilesw = 1, ntilesh = 1, subsamp = -1,
549 cs = -1;
550 /* Transformed image */
551 int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
552
553 if ((file = fopen(fileName, "rb")) == NULL)
554 THROW_UNIX("opening file");
555 if (fseek(file, 0, SEEK_END) < 0 ||
556 (srcSize = ftell(file)) == (unsigned long)-1)
557 THROW_UNIX("determining file size");
558 if ((srcBuf = (unsigned char *)malloc(srcSize)) == NULL)
559 THROW_UNIX("allocating memory");
560 if (fseek(file, 0, SEEK_SET) < 0)
561 THROW_UNIX("setting file position");
562 if (fread(srcBuf, srcSize, 1, file) < 1)
563 THROW_UNIX("reading JPEG data");
564 fclose(file); file = NULL;
565
566 temp = strrchr(fileName, '.');
567 if (temp != NULL) *temp = '\0';
568
569 if ((handle = tjInitTransform()) == NULL)
570 THROW_TJ("executing tjInitTransform()");
571 if (tjDecompressHeader3(handle, srcBuf, srcSize, &w, &h, &subsamp,
572 &cs) == -1)
573 THROW_TJ("executing tjDecompressHeader3()");
574 if (w < 1 || h < 1)
575 THROW("reading JPEG header", "Invalid image dimensions");
576 if (cs == TJCS_YCCK || cs == TJCS_CMYK) {
577 pf = TJPF_CMYK; ps = tjPixelSize[pf];
578 }
579
580 if (quiet == 1) {
581 fprintf(stderr, "All performance values in Mpixels/sec\n\n");
582 fprintf(stderr,
583 "Pixel JPEG JPEG %s %s Xform Comp Decomp ",
584 doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
585 if (doYUV) fprintf(stderr, "Decode");
586 fprintf(stderr, "\n");
587 fprintf(stderr,
588 "Format CS Subsamp Width Height Perf Ratio Perf ");
589 if (doYUV) fprintf(stderr, "Perf");
590 fprintf(stderr, "\n\n");
591 } else if (!quiet)
592 fprintf(stderr, ">>>>> JPEG %s --> %s (%s) <<<<<\n",
593 formatName(subsamp, cs, tempStr), pixFormatStr[pf],
594 (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down");
595
596 for (tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ;
597 tilew *= 2, tileh *= 2) {
598 if (tilew > w) tilew = w;
599 if (tileh > h) tileh = h;
600 ntilesw = (w + tilew - 1) / tilew;
601 ntilesh = (h + tileh - 1) / tileh;
602
603 if ((jpegBuf = (unsigned char **)malloc(sizeof(unsigned char *) *
604 ntilesw * ntilesh)) == NULL)
605 THROW_UNIX("allocating JPEG tile array");
606 memset(jpegBuf, 0, sizeof(unsigned char *) * ntilesw * ntilesh);
607 if ((jpegSize = (unsigned long *)malloc(sizeof(unsigned long) *
608 ntilesw * ntilesh)) == NULL)
609 THROW_UNIX("allocating JPEG size array");
610 memset(jpegSize, 0, sizeof(unsigned long) * ntilesw * ntilesh);
611
612 if ((flags & TJFLAG_NOREALLOC) != 0 &&
613 (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter))
614 for (i = 0; i < ntilesw * ntilesh; i++) {
615 if (tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX)
616 THROW("getting buffer size", "Image is too large");
617 if ((jpegBuf[i] = (unsigned char *)
618 tjAlloc(tjBufSize(tilew, tileh, subsamp))) == NULL)
619 THROW_UNIX("allocating JPEG tiles");
620 }
621
622 tw = w; th = h; ttilew = tilew; ttileh = tileh;
623 if (!quiet) {
624 fprintf(stderr, "\n%s size: %d x %d", doTile ? "Tile" : "Image", ttilew,
625 ttileh);
626 if (sf.num != 1 || sf.denom != 1)
627 fprintf(stderr, " --> %d x %d", TJSCALED(tw, sf), TJSCALED(th, sf));
628 fprintf(stderr, "\n");
629 } else if (quiet == 1) {
630 fprintf(stderr, "%-4s (%s) %-5s %-5s ", pixFormatStr[pf],
631 (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD", csName[cs],
632 subNameLong[subsamp]);
633 fprintf(stderr, "%-5d %-5d ", tilew, tileh);
634 }
635
636 tsubsamp = subsamp;
637 if (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter) {
638 if ((t = (tjtransform *)malloc(sizeof(tjtransform) * ntilesw *
639 ntilesh)) == NULL)
640 THROW_UNIX("allocating image transform array");
641
642 if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
643 xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270) {
644 tw = h; th = w; ttilew = tileh; ttileh = tilew;
645 }
646
647 if (xformOpt & TJXOPT_GRAY) tsubsamp = TJSAMP_GRAY;
648 if (xformOp == TJXOP_HFLIP || xformOp == TJXOP_ROT180)
649 tw = tw - (tw % tjMCUWidth[tsubsamp]);
650 if (xformOp == TJXOP_VFLIP || xformOp == TJXOP_ROT180)
651 th = th - (th % tjMCUHeight[tsubsamp]);
652 if (xformOp == TJXOP_TRANSVERSE || xformOp == TJXOP_ROT90)
653 tw = tw - (tw % tjMCUHeight[tsubsamp]);
654 if (xformOp == TJXOP_TRANSVERSE || xformOp == TJXOP_ROT270)
655 th = th - (th % tjMCUWidth[tsubsamp]);
656 tntilesw = (tw + ttilew - 1) / ttilew;
657 tntilesh = (th + ttileh - 1) / ttileh;
658
659 if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
660 xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270) {
661 if (tsubsamp == TJSAMP_422) tsubsamp = TJSAMP_440;
662 else if (tsubsamp == TJSAMP_440) tsubsamp = TJSAMP_422;
663 }
664
665 for (row = 0, tile = 0; row < tntilesh; row++) {
666 for (col = 0; col < tntilesw; col++, tile++) {
667 t[tile].r.w = min(ttilew, tw - col * ttilew);
668 t[tile].r.h = min(ttileh, th - row * ttileh);
669 t[tile].r.x = col * ttilew;
670 t[tile].r.y = row * ttileh;
671 t[tile].op = xformOp;
672 t[tile].options = xformOpt | TJXOPT_TRIM;
673 t[tile].customFilter = customFilter;
674 if (t[tile].options & TJXOPT_NOOUTPUT && jpegBuf[tile]) {
675 tjFree(jpegBuf[tile]); jpegBuf[tile] = NULL;
676 }
677 }
678 }
679
680 iter = -1;
681 elapsed = 0.;
682 while (1) {
683 start = getTime();
684 if (tjTransform(handle, srcBuf, srcSize, tntilesw * tntilesh, jpegBuf,
685 jpegSize, t, flags) == -1)
686 THROW_TJ("executing tjTransform()");
687 elapsed += getTime() - start;
688 if (iter >= 0) {
689 iter++;
690 if (elapsed >= benchTime) break;
691 } else if (elapsed >= warmup) {
692 iter = 0;
693 elapsed = 0.;
694 }
695 }
696
697 free(t); t = NULL;
698
699 for (tile = 0, totalJpegSize = 0; tile < tntilesw * tntilesh; tile++)
700 totalJpegSize += jpegSize[tile];
701
702 if (quiet) {
703 fprintf(stderr, "%-6s%s%-6s%s",
704 sigfig((double)(w * h) / 1000000. / elapsed, 4, tempStr, 80),
705 quiet == 2 ? "\n" : " ",
706 sigfig((double)(w * h * ps) / (double)totalJpegSize, 4,
707 tempStr2, 80),
708 quiet == 2 ? "\n" : " ");
709 } else {
710 fprintf(stderr, "Transform --> Frame rate: %f fps\n",
711 1.0 / elapsed);
712 fprintf(stderr, " Output image size: %lu bytes\n",
713 totalJpegSize);
714 fprintf(stderr, " Compression ratio: %f:1\n",
715 (double)(w * h * ps) / (double)totalJpegSize);
716 fprintf(stderr,
717 " Throughput: %f Megapixels/sec\n",
718 (double)(w * h) / 1000000. / elapsed);
719 fprintf(stderr,
720 " Output bit stream: %f Megabits/sec\n",
721 (double)totalJpegSize * 8. / 1000000. / elapsed);
722 }
723 } else {
724 if (quiet == 1) fprintf(stderr, "N/A N/A ");
725 tjFree(jpegBuf[0]);
726 jpegBuf[0] = NULL;
727 decompsrc = 1;
728 }
729
730 if (w == tilew) ttilew = tw;
731 if (h == tileh) ttileh = th;
732 if (!(xformOpt & TJXOPT_NOOUTPUT)) {
733 if (decomp(NULL, decompsrc ? &srcBuf : jpegBuf,
734 decompsrc ? &srcSize : jpegSize, NULL, tw, th, tsubsamp, 0,
735 fileName, ttilew, ttileh) == -1)
736 goto bailout;
737 } else if (quiet == 1) fprintf(stderr, "N/A\n");
738
739 for (i = 0; i < ntilesw * ntilesh; i++) {
740 tjFree(jpegBuf[i]);
741 jpegBuf[i] = NULL;
742 }
743 free(jpegBuf); jpegBuf = NULL;
744 free(jpegSize); jpegSize = NULL;
745
746 if (tilew == w && tileh == h) break;
747 }
748
749 bailout:
750 if (file) fclose(file);
751 if (jpegBuf) {
752 for (i = 0; i < ntilesw * ntilesh; i++)
753 tjFree(jpegBuf[i]);
754 }
755 free(jpegBuf);
756 free(jpegSize);
757 free(srcBuf);
758 free(t);
759 if (handle) { tjDestroy(handle); handle = NULL; }
760 return retval;
761 }
762
763
usage(char * progName)764 static void usage(char *progName)
765 {
766 int i;
767
768 printf("USAGE: %s\n", progName);
769 printf(" <Inputimage (BMP|PPM)> <Quality> [options]\n\n");
770 printf(" %s\n", progName);
771 printf(" <Inputimage (JPG)> [options]\n\n");
772 printf("Options:\n\n");
773 printf("-alloc = Dynamically allocate JPEG buffers\n");
774 printf("-bmp = Use Windows Bitmap format for output images [default = PPM]\n");
775 printf("-bottomup = Use bottom-up row order for packed-pixel source/destination buffers\n");
776 printf("-tile = Compress/transform the input image into separate JPEG tiles of varying\n");
777 printf(" sizes (useful for measuring JPEG overhead)\n");
778 printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n");
779 printf(" Use the specified pixel format for packed-pixel source/destination buffers\n");
780 printf(" [default = BGR]\n");
781 printf("-cmyk = Indirectly test YCCK JPEG compression/decompression\n");
782 printf(" (use the CMYK pixel format for packed-pixel source/destination buffers)\n");
783 printf("-fastupsample = Use the fastest chrominance upsampling algorithm available\n");
784 printf("-fastdct = Use the fastest DCT/IDCT algorithm available\n");
785 printf("-accuratedct = Use the most accurate DCT/IDCT algorithm available\n");
786 printf("-progressive = Use progressive entropy coding in JPEG images generated by\n");
787 printf(" compression and transform operations\n");
788 printf("-subsamp <s> = When compressing, use the specified level of chrominance\n");
789 printf(" subsampling (<s> = 444, 422, 440, 420, 411, or GRAY) [default = test\n");
790 printf(" Grayscale, 4:2:0, 4:2:2, and 4:4:4 in sequence]\n");
791 printf("-quiet = Output results in tabular rather than verbose format\n");
792 printf("-yuv = Compress from/decompress to intermediate planar YUV images\n");
793 printf("-yuvpad <p> = The number of bytes by which each row in each plane of an\n");
794 printf(" intermediate YUV image is evenly divisible (must be a power of 2)\n");
795 printf(" [default = 1]\n");
796 printf("-scale M/N = When decompressing, scale the width/height of the JPEG image by a\n");
797 printf(" factor of M/N (M/N = ");
798 for (i = 0; i < nsf; i++) {
799 printf("%d/%d", scalingFactors[i].num, scalingFactors[i].denom);
800 if (nsf == 2 && i != nsf - 1) printf(" or ");
801 else if (nsf > 2) {
802 if (i != nsf - 1) printf(", ");
803 if (i == nsf - 2) printf("or ");
804 }
805 if (i % 8 == 0 && i != 0) printf("\n ");
806 }
807 printf(")\n");
808 printf("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =\n");
809 printf(" Perform the specified lossless transform operation on the input image\n");
810 printf(" prior to decompression (these operations are mutually exclusive)\n");
811 printf("-grayscale = Transform the input image into a grayscale JPEG image prior to\n");
812 printf(" decompression (can be combined with the other transform operations above)\n");
813 printf("-copynone = Do not copy any extra markers (including EXIF and ICC profile data)\n");
814 printf(" when transforming the input image\n");
815 printf("-benchtime <t> = Run each benchmark for at least <t> seconds [default = 5.0]\n");
816 printf("-warmup <t> = Run each benchmark for <t> seconds [default = 1.0] prior to\n");
817 printf(" starting the timer, in order to prime the caches and thus improve the\n");
818 printf(" consistency of the benchmark results\n");
819 printf("-componly = Stop after running compression tests. Do not test decompression.\n");
820 printf("-nowrite = Do not write reference or output images (improves consistency of\n");
821 printf(" benchmark results)\n");
822 printf("-limitscans = Refuse to decompress or transform progressive JPEG images that\n");
823 printf(" have an unreasonably large number of scans\n");
824 printf("-stoponwarning = Immediately discontinue the current\n");
825 printf(" compression/decompression/transform operation if a warning (non-fatal\n");
826 printf(" error) occurs\n\n");
827 printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n");
828 printf("test will be performed for all quality values in the range.\n\n");
829 exit(1);
830 }
831
832 #ifndef GTEST
main(int argc,char * argv[])833 int main(int argc, char *argv[])
834 #else
835 int tjbench(int argc, char *argv[])
836 #endif
837 {
838 unsigned char *srcBuf = NULL;
839 int w = 0, h = 0, i, j, minQual = -1, maxQual = -1;
840 char *temp;
841 int minArg = 2, retval = 0, subsamp = -1;
842
843 if ((scalingFactors = tjGetScalingFactors(&nsf)) == NULL || nsf == 0)
844 THROW("executing tjGetScalingFactors()", tjGetErrorStr());
845
846 if (argc < minArg) usage(argv[0]);
847
848 temp = strrchr(argv[1], '.');
849 if (temp != NULL) {
850 if (!strcasecmp(temp, ".bmp")) ext = "bmp";
851 if (!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg"))
852 decompOnly = 1;
853 }
854
855 fprintf(stderr, "\n");
856
857 if (!decompOnly) {
858 minArg = 3;
859 if (argc < minArg) usage(argv[0]);
860 if ((minQual = atoi(argv[2])) < 1 || minQual > 100) {
861 puts("ERROR: Quality must be between 1 and 100.");
862 exit(1);
863 }
864 if ((temp = strchr(argv[2], '-')) != NULL && strlen(temp) > 1 &&
865 sscanf(&temp[1], "%d", &maxQual) == 1 && maxQual > minQual &&
866 maxQual >= 1 && maxQual <= 100) {}
867 else maxQual = minQual;
868 }
869
870 if (argc > minArg) {
871 for (i = minArg; i < argc; i++) {
872 if (!strcasecmp(argv[i], "-tile")) {
873 doTile = 1; xformOpt |= TJXOPT_CROP;
874 } else if (!strcasecmp(argv[i], "-fastupsample")) {
875 fprintf(stderr, "Using fastest upsampling algorithm\n\n");
876 flags |= TJFLAG_FASTUPSAMPLE;
877 } else if (!strcasecmp(argv[i], "-fastdct")) {
878 fprintf(stderr, "Using fastest DCT/IDCT algorithm\n\n");
879 flags |= TJFLAG_FASTDCT;
880 } else if (!strcasecmp(argv[i], "-accuratedct")) {
881 fprintf(stderr, "Using most accurate DCT/IDCT algorithm\n\n");
882 flags |= TJFLAG_ACCURATEDCT;
883 } else if (!strcasecmp(argv[i], "-progressive")) {
884 fprintf(stderr, "Using progressive entropy coding\n\n");
885 flags |= TJFLAG_PROGRESSIVE;
886 xformOpt |= TJXOPT_PROGRESSIVE;
887 } else if (!strcasecmp(argv[i], "-rgb"))
888 pf = TJPF_RGB;
889 else if (!strcasecmp(argv[i], "-rgbx"))
890 pf = TJPF_RGBX;
891 else if (!strcasecmp(argv[i], "-bgr"))
892 pf = TJPF_BGR;
893 else if (!strcasecmp(argv[i], "-bgrx"))
894 pf = TJPF_BGRX;
895 else if (!strcasecmp(argv[i], "-xbgr"))
896 pf = TJPF_XBGR;
897 else if (!strcasecmp(argv[i], "-xrgb"))
898 pf = TJPF_XRGB;
899 else if (!strcasecmp(argv[i], "-cmyk"))
900 pf = TJPF_CMYK;
901 else if (!strcasecmp(argv[i], "-bottomup"))
902 flags |= TJFLAG_BOTTOMUP;
903 else if (!strcasecmp(argv[i], "-quiet"))
904 quiet = 1;
905 else if (!strcasecmp(argv[i], "-qq"))
906 quiet = 2;
907 else if (!strcasecmp(argv[i], "-scale") && i < argc - 1) {
908 int temp1 = 0, temp2 = 0, match = 0;
909
910 if (sscanf(argv[++i], "%d/%d", &temp1, &temp2) == 2) {
911 for (j = 0; j < nsf; j++) {
912 if ((double)temp1 / (double)temp2 ==
913 (double)scalingFactors[j].num /
914 (double)scalingFactors[j].denom) {
915 sf = scalingFactors[j];
916 match = 1; break;
917 }
918 }
919 if (!match) usage(argv[0]);
920 } else usage(argv[0]);
921 } else if (!strcasecmp(argv[i], "-hflip"))
922 xformOp = TJXOP_HFLIP;
923 else if (!strcasecmp(argv[i], "-vflip"))
924 xformOp = TJXOP_VFLIP;
925 else if (!strcasecmp(argv[i], "-transpose"))
926 xformOp = TJXOP_TRANSPOSE;
927 else if (!strcasecmp(argv[i], "-transverse"))
928 xformOp = TJXOP_TRANSVERSE;
929 else if (!strcasecmp(argv[i], "-rot90"))
930 xformOp = TJXOP_ROT90;
931 else if (!strcasecmp(argv[i], "-rot180"))
932 xformOp = TJXOP_ROT180;
933 else if (!strcasecmp(argv[i], "-rot270"))
934 xformOp = TJXOP_ROT270;
935 else if (!strcasecmp(argv[i], "-grayscale"))
936 xformOpt |= TJXOPT_GRAY;
937 else if (!strcasecmp(argv[i], "-custom"))
938 customFilter = dummyDCTFilter;
939 else if (!strcasecmp(argv[i], "-nooutput"))
940 xformOpt |= TJXOPT_NOOUTPUT;
941 else if (!strcasecmp(argv[i], "-copynone"))
942 xformOpt |= TJXOPT_COPYNONE;
943 else if (!strcasecmp(argv[i], "-benchtime") && i < argc - 1) {
944 double tempd = atof(argv[++i]);
945
946 if (tempd > 0.0) benchTime = tempd;
947 else usage(argv[0]);
948 } else if (!strcasecmp(argv[i], "-warmup") && i < argc - 1) {
949 double tempd = atof(argv[++i]);
950
951 if (tempd >= 0.0) warmup = tempd;
952 else usage(argv[0]);
953 fprintf(stderr, "Warmup time = %.1f seconds\n\n", warmup);
954 } else if (!strcasecmp(argv[i], "-alloc"))
955 flags &= (~TJFLAG_NOREALLOC);
956 else if (!strcasecmp(argv[i], "-bmp"))
957 ext = "bmp";
958 else if (!strcasecmp(argv[i], "-yuv")) {
959 fprintf(stderr, "Testing planar YUV encoding/decoding\n\n");
960 doYUV = 1;
961 } else if (!strcasecmp(argv[i], "-yuvpad") && i < argc - 1) {
962 int tempi = atoi(argv[++i]);
963
964 if (tempi >= 1 && (tempi & (tempi - 1)) == 0) yuvAlign = tempi;
965 else usage(argv[0]);
966 } else if (!strcasecmp(argv[i], "-subsamp") && i < argc - 1) {
967 i++;
968 if (toupper(argv[i][0]) == 'G') subsamp = TJSAMP_GRAY;
969 else {
970 int tempi = atoi(argv[i]);
971
972 switch (tempi) {
973 case 444: subsamp = TJSAMP_444; break;
974 case 422: subsamp = TJSAMP_422; break;
975 case 440: subsamp = TJSAMP_440; break;
976 case 420: subsamp = TJSAMP_420; break;
977 case 411: subsamp = TJSAMP_411; break;
978 default: usage(argv[0]);
979 }
980 }
981 } else if (!strcasecmp(argv[i], "-componly"))
982 compOnly = 1;
983 else if (!strcasecmp(argv[i], "-nowrite"))
984 doWrite = 0;
985 else if (!strcasecmp(argv[i], "-limitscans"))
986 flags |= TJFLAG_LIMITSCANS;
987 else if (!strcasecmp(argv[i], "-stoponwarning"))
988 flags |= TJFLAG_STOPONWARNING;
989 else usage(argv[0]);
990 }
991 }
992
993 if ((sf.num != 1 || sf.denom != 1) && doTile) {
994 fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
995 fprintf(stderr, "work when scaled decompression is enabled.\n\n");
996 doTile = 0; xformOpt &= (~TJXOPT_CROP);
997 }
998
999 if ((flags & TJFLAG_NOREALLOC) == 0 && doTile) {
1000 fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
1001 fprintf(stderr, "work when dynamic JPEG buffer allocation is enabled.\n\n");
1002 doTile = 0; xformOpt &= (~TJXOPT_CROP);
1003 }
1004
1005 if (!decompOnly) {
1006 if ((srcBuf = tjLoadImage(argv[1], &w, 1, &h, &pf, flags)) == NULL)
1007 THROW_TJG("loading input image");
1008 temp = strrchr(argv[1], '.');
1009 if (temp != NULL) *temp = '\0';
1010 }
1011
1012 if (quiet == 1 && !decompOnly) {
1013 fprintf(stderr, "All performance values in Mpixels/sec\n\n");
1014 fprintf(stderr, "Pixel JPEG JPEG %s %s ",
1015 doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
1016 if (doYUV) fprintf(stderr, "Encode ");
1017 fprintf(stderr, "Comp Comp Decomp ");
1018 if (doYUV) fprintf(stderr, "Decode");
1019 fprintf(stderr, "\n");
1020 fprintf(stderr, "Format Subsamp Qual Width Height ");
1021 if (doYUV) fprintf(stderr, "Perf ");
1022 fprintf(stderr, "Perf Ratio Perf ");
1023 if (doYUV) fprintf(stderr, "Perf");
1024 fprintf(stderr, "\n\n");
1025 }
1026
1027 if (decompOnly) {
1028 decompTest(argv[1]);
1029 fprintf(stderr, "\n");
1030 goto bailout;
1031 }
1032 if (subsamp >= 0 && subsamp < TJ_NUMSAMP) {
1033 for (i = maxQual; i >= minQual; i--)
1034 fullTest(srcBuf, w, h, subsamp, i, argv[1]);
1035 fprintf(stderr, "\n");
1036 } else {
1037 if (pf != TJPF_CMYK) {
1038 for (i = maxQual; i >= minQual; i--)
1039 fullTest(srcBuf, w, h, TJSAMP_GRAY, i, argv[1]);
1040 fprintf(stderr, "\n");
1041 }
1042 for (i = maxQual; i >= minQual; i--)
1043 fullTest(srcBuf, w, h, TJSAMP_420, i, argv[1]);
1044 fprintf(stderr, "\n");
1045 for (i = maxQual; i >= minQual; i--)
1046 fullTest(srcBuf, w, h, TJSAMP_422, i, argv[1]);
1047 fprintf(stderr, "\n");
1048 for (i = maxQual; i >= minQual; i--)
1049 fullTest(srcBuf, w, h, TJSAMP_444, i, argv[1]);
1050 fprintf(stderr, "\n");
1051 }
1052
1053 bailout:
1054 tjFree(srcBuf);
1055 return retval;
1056 }
1057