2 * Copyright (C)2009-2014, 2017-2018 D. R. Commander. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
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.
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.
30 * This program tests the various code paths in the TurboJPEG C Wrapper
38 #include "turbojpeg.h"
43 #define random() rand()
49 void usage(char *progName)
51 printf("\nUSAGE: %s [options]\n\n", progName);
53 printf("-yuv = test YUV encoding/decoding support\n");
54 printf("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest\n");
55 printf(" 4-byte boundary\n");
56 printf("-alloc = test automatic buffer allocation\n");
57 printf("-bmp = tjLoadImage()/tjSaveImage() unit test\n\n");
62 #define _throwtj() { \
63 printf("TurboJPEG ERROR:\n%s\n", tjGetErrorStr()); \
66 #define _tj(f) { if ((f) == -1) _throwtj(); }
67 #define _throw(m) { printf("ERROR: %s\n", m); bailout() }
68 #define _throwmd5(filename, md5sum, ref) { \
69 printf("\n%s has an MD5 sum of %s.\n Should be %s.\n", filename, md5sum, \
74 const char *subNameLong[TJ_NUMSAMP] = {
75 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
77 const char *subName[TJ_NUMSAMP] = {
78 "444", "422", "420", "GRAY", "440", "411"
81 const char *pixFormatStr[TJ_NUMPF] = {
82 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
83 "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
86 const int _3byteFormats[] = { TJPF_RGB, TJPF_BGR };
87 const int _4byteFormats[] = {
88 TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_CMYK
90 const int _onlyGray[] = { TJPF_GRAY };
91 const int _onlyRGB[] = { TJPF_RGB };
93 int doYUV = 0, alloc = 0, pad = 4;
96 #define bailout() { exitStatus = -1; goto bailout; }
99 void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
101 int roffset = tjRedOffset[pf];
102 int goffset = tjGreenOffset[pf];
103 int boffset = tjBlueOffset[pf];
104 int ps = tjPixelSize[pf];
105 int index, row, col, halfway = 16;
107 if (pf == TJPF_GRAY) {
108 memset(buf, 0, w * h * ps);
109 for (row = 0; row < h; row++) {
110 for (col = 0; col < w; col++) {
111 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
112 else index = row * w + col;
113 if (((row / 8) + (col / 8)) % 2 == 0)
114 buf[index] = (row < halfway) ? 255 : 0;
115 else buf[index] = (row < halfway) ? 76 : 226;
118 } else if (pf == TJPF_CMYK) {
119 memset(buf, 255, w * h * ps);
120 for (row = 0; row < h; row++) {
121 for (col = 0; col < w; col++) {
122 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
123 else index = row * w + col;
124 if (((row / 8) + (col / 8)) % 2 == 0) {
125 if (row >= halfway) buf[index * ps + 3] = 0;
127 buf[index * ps + 2] = 0;
128 if (row < halfway) buf[index * ps + 1] = 0;
133 memset(buf, 0, w * h * ps);
134 for (row = 0; row < h; row++) {
135 for (col = 0; col < w; col++) {
136 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
137 else index = row * w + col;
138 if (((row / 8) + (col / 8)) % 2 == 0) {
140 buf[index * ps + roffset] = 255;
141 buf[index * ps + goffset] = 255;
142 buf[index * ps + boffset] = 255;
145 buf[index * ps + roffset] = 255;
146 if (row >= halfway) buf[index * ps + goffset] = 255;
154 #define checkval(v, cv) { \
155 if (v < cv - 1 || v > cv + 1) { \
156 printf("\nComp. %s at %d,%d should be %d, not %d\n", #v, row, col, cv, \
158 retval = 0; exitStatus = -1; goto bailout; \
162 #define checkval0(v) { \
164 printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, row, col, v); \
165 retval = 0; exitStatus = -1; goto bailout; \
169 #define checkval255(v) { \
171 printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, row, col, v); \
172 retval = 0; exitStatus = -1; goto bailout; \
177 int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
178 tjscalingfactor sf, int flags)
180 int roffset = tjRedOffset[pf];
181 int goffset = tjGreenOffset[pf];
182 int boffset = tjBlueOffset[pf];
183 int aoffset = tjAlphaOffset[pf];
184 int ps = tjPixelSize[pf];
185 int index, row, col, retval = 1;
186 int halfway = 16 * sf.num / sf.denom;
187 int blocksize = 8 * sf.num / sf.denom;
189 if (pf == TJPF_GRAY) roffset = goffset = boffset = 0;
191 if (pf == TJPF_CMYK) {
192 for (row = 0; row < h; row++) {
193 for (col = 0; col < w; col++) {
194 unsigned char c, m, y, k;
196 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
197 else index = row * w + col;
199 m = buf[index * ps + 1];
200 y = buf[index * ps + 2];
201 k = buf[index * ps + 3];
202 if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
203 checkval255(c); checkval255(m); checkval255(y);
204 if (row < halfway) checkval255(k)
207 checkval255(c); checkval0(y); checkval255(k);
208 if (row < halfway) checkval0(m)
216 for (row = 0; row < h; row++) {
217 for (col = 0; col < w; col++) {
218 unsigned char r, g, b, a;
220 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
221 else index = row * w + col;
222 r = buf[index * ps + roffset];
223 g = buf[index * ps + goffset];
224 b = buf[index * ps + boffset];
225 a = aoffset >= 0 ? buf[index * ps + aoffset] : 0xFF;
226 if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
228 checkval255(r); checkval255(g); checkval255(b);
230 checkval0(r); checkval0(g); checkval0(b);
233 if (subsamp == TJSAMP_GRAY) {
235 checkval(r, 76); checkval(g, 76); checkval(b, 76);
237 checkval(r, 226); checkval(g, 226); checkval(b, 226);
241 checkval255(r); checkval0(g); checkval0(b);
243 checkval255(r); checkval255(g); checkval0(b);
253 for (row = 0; row < h; row++) {
254 for (col = 0; col < w; col++) {
256 printf("%.3d/%.3d/%.3d/%.3d ", buf[(row * w + col) * ps],
257 buf[(row * w + col) * ps + 1], buf[(row * w + col) * ps + 2],
258 buf[(row * w + col) * ps + 3]);
260 printf("%.3d/%.3d/%.3d ", buf[(row * w + col) * ps + roffset],
261 buf[(row * w + col) * ps + goffset],
262 buf[(row * w + col) * ps + boffset]);
271 #define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
273 int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
277 int hsf = tjMCUWidth[subsamp] / 8, vsf = tjMCUHeight[subsamp] / 8;
278 int pw = PAD(w, hsf), ph = PAD(h, vsf);
279 int cw = pw / hsf, ch = ph / vsf;
280 int ypitch = PAD(pw, pad), uvpitch = PAD(cw, pad);
282 int halfway = 16 * sf.num / sf.denom;
283 int blocksize = 8 * sf.num / sf.denom;
285 for (row = 0; row < ph; row++) {
286 for (col = 0; col < pw; col++) {
287 unsigned char y = buf[ypitch * row + col];
289 if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
290 if (row < halfway) checkval255(y)
293 if (row < halfway) checkval(y, 76)
294 else checkval(y, 226);
298 if (subsamp != TJSAMP_GRAY) {
299 int halfway = 16 / vsf * sf.num / sf.denom;
301 for (row = 0; row < ch; row++) {
302 for (col = 0; col < cw; col++) {
303 unsigned char u = buf[ypitch * ph + (uvpitch * row + col)],
304 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
306 if (((row * vsf / blocksize) + (col * hsf / blocksize)) % 2 == 0) {
307 checkval(u, 128); checkval(v, 128);
310 checkval(u, 85); checkval255(v);
312 checkval0(u); checkval(v, 149);
321 for (row = 0; row < ph; row++) {
322 for (col = 0; col < pw; col++)
323 printf("%.3d ", buf[ypitch * row + col]);
327 for (row = 0; row < ch; row++) {
328 for (col = 0; col < cw; col++)
329 printf("%.3d ", buf[ypitch * ph + (uvpitch * row + col)]);
333 for (row = 0; row < ch; row++) {
334 for (col = 0; col < cw; col++)
336 buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]);
345 void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize, char *filename)
347 FILE *file = fopen(filename, "wb");
349 if (!file || fwrite(jpegBuf, jpegSize, 1, file) != 1) {
352 strerror_r(errno, err_str, 256);
353 printf("ERROR: Could not write to %s.\n%s\n", filename, err_str);
355 printf("ERROR: Could not write to %s.\n%s\n", filename, strerror(errno));
361 if (file) fclose(file);
365 void compTest(tjhandle handle, unsigned char **dstBuf, unsigned long *dstSize,
366 int w, int h, int pf, char *basename, int subsamp, int jpegQual,
370 unsigned char *srcBuf = NULL, *yuvBuf = NULL;
371 const char *pfStr = pixFormatStr[pf];
372 const char *buStrLong =
373 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ";
374 const char *buStr = (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD";
376 if ((srcBuf = (unsigned char *)malloc(w * h * tjPixelSize[pf])) == NULL)
377 _throw("Memory allocation failure");
378 initBuf(srcBuf, w, h, pf, flags);
380 if (*dstBuf && *dstSize > 0) memset(*dstBuf, 0, *dstSize);
382 if (!alloc) flags |= TJFLAG_NOREALLOC;
384 unsigned long yuvSize = tjBufSizeYUV2(w, pad, h, subsamp);
385 tjscalingfactor sf = { 1, 1 };
386 tjhandle handle2 = tjInitCompress();
388 if (!handle2) _throwtj();
390 if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
391 _throw("Memory allocation failure");
392 memset(yuvBuf, 0, yuvSize);
394 printf("%s %s -> YUV %s ... ", pfStr, buStrLong, subNameLong[subsamp]);
395 _tj(tjEncodeYUV3(handle2, srcBuf, w, 0, h, pf, yuvBuf, pad, subsamp,
398 if (checkBufYUV(yuvBuf, w, h, subsamp, sf)) printf("Passed.\n");
399 else printf("FAILED!\n");
401 printf("YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp], buStrLong,
403 _tj(tjCompressFromYUV(handle, yuvBuf, w, pad, h, subsamp, dstBuf, dstSize,
406 printf("%s %s -> %s Q%d ... ", pfStr, buStrLong, subNameLong[subsamp],
408 _tj(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
412 snprintf(tempStr, 1024, "%s_enc_%s_%s_%s_Q%d.jpg", basename, pfStr, buStr,
413 subName[subsamp], jpegQual);
414 writeJPEG(*dstBuf, *dstSize, tempStr);
415 printf("Done.\n Result in %s\n", tempStr);
418 if (yuvBuf) free(yuvBuf);
419 if (srcBuf) free(srcBuf);
423 void _decompTest(tjhandle handle, unsigned char *jpegBuf,
424 unsigned long jpegSize, int w, int h, int pf, char *basename,
425 int subsamp, int flags, tjscalingfactor sf)
427 unsigned char *dstBuf = NULL, *yuvBuf = NULL;
428 int _hdrw = 0, _hdrh = 0, _hdrsubsamp = -1;
429 int scaledWidth = TJSCALED(w, sf);
430 int scaledHeight = TJSCALED(h, sf);
431 unsigned long dstSize = 0;
433 _tj(tjDecompressHeader2(handle, jpegBuf, jpegSize, &_hdrw, &_hdrh,
435 if (_hdrw != w || _hdrh != h || _hdrsubsamp != subsamp)
436 _throw("Incorrect JPEG header");
438 dstSize = scaledWidth * scaledHeight * tjPixelSize[pf];
439 if ((dstBuf = (unsigned char *)malloc(dstSize)) == NULL)
440 _throw("Memory allocation failure");
441 memset(dstBuf, 0, dstSize);
444 unsigned long yuvSize = tjBufSizeYUV2(scaledWidth, pad, scaledHeight,
446 tjhandle handle2 = tjInitDecompress();
448 if (!handle2) _throwtj();
450 if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
451 _throw("Memory allocation failure");
452 memset(yuvBuf, 0, yuvSize);
454 printf("JPEG -> YUV %s ", subNameLong[subsamp]);
455 if (sf.num != 1 || sf.denom != 1)
456 printf("%d/%d ... ", sf.num, sf.denom);
458 _tj(tjDecompressToYUV2(handle, jpegBuf, jpegSize, yuvBuf, scaledWidth, pad,
459 scaledHeight, flags));
460 if (checkBufYUV(yuvBuf, scaledWidth, scaledHeight, subsamp, sf))
462 else printf("FAILED!\n");
464 printf("YUV %s -> %s %s ... ", subNameLong[subsamp], pixFormatStr[pf],
465 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
466 _tj(tjDecodeYUV(handle2, yuvBuf, pad, subsamp, dstBuf, scaledWidth, 0,
467 scaledHeight, pf, flags));
470 printf("JPEG -> %s %s ", pixFormatStr[pf],
471 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
472 if (sf.num != 1 || sf.denom != 1)
473 printf("%d/%d ... ", sf.num, sf.denom);
475 _tj(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth, 0,
476 scaledHeight, pf, flags));
479 if (checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, flags))
481 else printf("FAILED!");
485 if (yuvBuf) free(yuvBuf);
486 if (dstBuf) free(dstBuf);
490 void decompTest(tjhandle handle, unsigned char *jpegBuf,
491 unsigned long jpegSize, int w, int h, int pf, char *basename,
492 int subsamp, int flags)
495 tjscalingfactor *sf = tjGetScalingFactors(&n);
497 if (!sf || !n) _throwtj();
499 for (i = 0; i < n; i++) {
500 if (subsamp == TJSAMP_444 || subsamp == TJSAMP_GRAY ||
501 (subsamp == TJSAMP_411 && sf[i].num == 1 &&
502 (sf[i].denom == 2 || sf[i].denom == 1)) ||
503 (subsamp != TJSAMP_411 && sf[i].num == 1 &&
504 (sf[i].denom == 4 || sf[i].denom == 2 || sf[i].denom == 1)))
505 _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
514 void doTest(int w, int h, const int *formats, int nformats, int subsamp,
517 tjhandle chandle = NULL, dhandle = NULL;
518 unsigned char *dstBuf = NULL;
519 unsigned long size = 0;
523 size = tjBufSize(w, h, subsamp);
525 if ((dstBuf = (unsigned char *)tjAlloc(size)) == NULL)
526 _throw("Memory allocation failure.");
528 if ((chandle = tjInitCompress()) == NULL ||
529 (dhandle = tjInitDecompress()) == NULL)
532 for (pfi = 0; pfi < nformats; pfi++) {
533 for (i = 0; i < 2; i++) {
536 if (subsamp == TJSAMP_422 || subsamp == TJSAMP_420 ||
537 subsamp == TJSAMP_440 || subsamp == TJSAMP_411)
538 flags |= TJFLAG_FASTUPSAMPLE;
539 if (i == 1) flags |= TJFLAG_BOTTOMUP;
541 compTest(chandle, &dstBuf, &size, w, h, pf, basename, subsamp, 100,
543 decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp, flags);
544 if (pf >= TJPF_RGBX && pf <= TJPF_XRGB) {
546 decompTest(dhandle, dstBuf, size, w, h, pf + (TJPF_RGBA - TJPF_RGBX),
547 basename, subsamp, flags);
552 printf("--------------------\n\n");
555 if (chandle) tjDestroy(chandle);
556 if (dhandle) tjDestroy(dhandle);
557 if (dstBuf) tjFree(dstBuf);
561 void bufSizeTest(void)
563 int w, h, i, subsamp;
564 unsigned char *srcBuf = NULL, *dstBuf = NULL;
565 tjhandle handle = NULL;
566 unsigned long dstSize = 0;
568 if ((handle = tjInitCompress()) == NULL) _throwtj();
570 printf("Buffer size regression test\n");
571 for (subsamp = 0; subsamp < TJ_NUMSAMP; subsamp++) {
572 for (w = 1; w < 48; w++) {
573 int maxh = (w == 1) ? 2048 : 48;
575 for (h = 1; h < maxh; h++) {
576 if (h % 100 == 0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
577 if ((srcBuf = (unsigned char *)malloc(w * h * 4)) == NULL)
578 _throw("Memory allocation failure");
579 if (!alloc || doYUV) {
580 if (doYUV) dstSize = tjBufSizeYUV2(w, pad, h, subsamp);
581 else dstSize = tjBufSize(w, h, subsamp);
582 if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
583 _throw("Memory allocation failure");
586 for (i = 0; i < w * h * 4; i++) {
587 if (random() < RAND_MAX / 2) srcBuf[i] = 0;
588 else srcBuf[i] = 255;
592 _tj(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf, pad,
595 _tj(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
596 &dstSize, subsamp, 100,
597 alloc ? 0 : TJFLAG_NOREALLOC));
599 free(srcBuf); srcBuf = NULL;
600 if (!alloc || doYUV) {
601 tjFree(dstBuf); dstBuf = NULL;
604 if ((srcBuf = (unsigned char *)malloc(h * w * 4)) == NULL)
605 _throw("Memory allocation failure");
606 if (!alloc || doYUV) {
607 if (doYUV) dstSize = tjBufSizeYUV2(h, pad, w, subsamp);
608 else dstSize = tjBufSize(h, w, subsamp);
609 if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
610 _throw("Memory allocation failure");
613 for (i = 0; i < h * w * 4; i++) {
614 if (random() < RAND_MAX / 2) srcBuf[i] = 0;
615 else srcBuf[i] = 255;
619 _tj(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf, pad,
622 _tj(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
623 &dstSize, subsamp, 100,
624 alloc ? 0 : TJFLAG_NOREALLOC));
626 free(srcBuf); srcBuf = NULL;
627 if (!alloc || doYUV) {
628 tjFree(dstBuf); dstBuf = NULL;
636 if (srcBuf) free(srcBuf);
637 if (dstBuf) tjFree(dstBuf);
638 if (handle) tjDestroy(handle);
642 void initBitmap(unsigned char *buf, int width, int pitch, int height, int pf,
645 int roffset = tjRedOffset[pf];
646 int goffset = tjGreenOffset[pf];
647 int boffset = tjBlueOffset[pf];
648 int ps = tjPixelSize[pf];
651 for (j = 0; j < height; j++) {
652 int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
654 for (i = 0; i < width; i++) {
655 unsigned char r = (i * 256 / width) % 256;
656 unsigned char g = (j * 256 / height) % 256;
657 unsigned char b = (j * 256 / height + i * 256 / width) % 256;
659 memset(&buf[row * pitch + i * ps], 0, ps);
660 if (pf == TJPF_GRAY) buf[row * pitch + i * ps] = b;
661 else if (pf == TJPF_CMYK)
662 rgb_to_cmyk(r, g, b, &buf[row * pitch + i * ps + 0],
663 &buf[row * pitch + i * ps + 1],
664 &buf[row * pitch + i * ps + 2],
665 &buf[row * pitch + i * ps + 3]);
667 buf[row * pitch + i * ps + roffset] = r;
668 buf[row * pitch + i * ps + goffset] = g;
669 buf[row * pitch + i * ps + boffset] = b;
676 int cmpBitmap(unsigned char *buf, int width, int pitch, int height, int pf,
677 int flags, int gray2rgb)
679 int roffset = tjRedOffset[pf];
680 int goffset = tjGreenOffset[pf];
681 int boffset = tjBlueOffset[pf];
682 int aoffset = tjAlphaOffset[pf];
683 int ps = tjPixelSize[pf];
686 for (j = 0; j < height; j++) {
687 int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
689 for (i = 0; i < width; i++) {
690 unsigned char r = (i * 256 / width) % 256;
691 unsigned char g = (j * 256 / height) % 256;
692 unsigned char b = (j * 256 / height + i * 256 / width) % 256;
694 if (pf == TJPF_GRAY) {
695 if (buf[row * pitch + i * ps] != b)
697 } else if (pf == TJPF_CMYK) {
698 unsigned char rf, gf, bf;
700 cmyk_to_rgb(buf[row * pitch + i * ps + 0],
701 buf[row * pitch + i * ps + 1],
702 buf[row * pitch + i * ps + 2],
703 buf[row * pitch + i * ps + 3], &rf, &gf, &bf);
705 if (rf != b || gf != b || bf != b)
707 } else if (rf != r || gf != g || bf != b) return 0;
710 if (buf[row * pitch + i * ps + roffset] != b ||
711 buf[row * pitch + i * ps + goffset] != b ||
712 buf[row * pitch + i * ps + boffset] != b)
714 } else if (buf[row * pitch + i * ps + roffset] != r ||
715 buf[row * pitch + i * ps + goffset] != g ||
716 buf[row * pitch + i * ps + boffset] != b)
718 if (aoffset >= 0 && buf[row * pitch + i * ps + aoffset] != 0xFF)
727 int doBmpTest(const char *ext, int width, int align, int height, int pf,
730 char filename[80], *md5sum, md5buf[65];
731 int ps = tjPixelSize[pf], pitch = PAD(width * ps, align), loadWidth = 0,
732 loadHeight = 0, retval = 0, pixelFormat = pf;
733 unsigned char *buf = NULL;
736 if (pf == TJPF_GRAY) {
737 md5ref = !strcasecmp(ext, "ppm") ? "112c682e82ce5de1cca089e20d60000b" :
738 "51976530acf75f02beddf5d21149101d";
740 md5ref = !strcasecmp(ext, "ppm") ? "c0c9f772b464d1896326883a5c79c545" :
741 "6d659071b9bfcdee2def22cb58ddadca";
744 if ((buf = (unsigned char *)tjAlloc(pitch * height)) == NULL)
745 _throw("Could not allocate memory");
746 initBitmap(buf, width, pitch, height, pf, flags);
748 snprintf(filename, 80, "test_bmp_%s_%d_%s.%s", pixFormatStr[pf], align,
749 (flags & TJFLAG_BOTTOMUP) ? "bu" : "td", ext);
750 _tj(tjSaveImage(filename, buf, width, pitch, height, pf, flags));
751 md5sum = MD5File(filename, md5buf);
752 if (strcasecmp(md5sum, md5ref))
753 _throwmd5(filename, md5sum, md5ref);
755 tjFree(buf); buf = NULL;
756 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
759 if (width != loadWidth || height != loadHeight) {
760 printf("\n Image dimensions of %s are bogus\n", filename);
761 retval = -1; goto bailout;
763 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 0)) {
764 printf("\n Pixel data in %s is bogus\n", filename);
765 retval = -1; goto bailout;
767 if (pf == TJPF_GRAY) {
768 tjFree(buf); buf = NULL;
770 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
773 pitch = PAD(width * tjPixelSize[pf], align);
774 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 1)) {
775 printf("\n Converting %s to RGB failed\n", filename);
776 retval = -1; goto bailout;
779 tjFree(buf); buf = NULL;
781 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
784 pitch = PAD(width * tjPixelSize[pf], align);
785 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 1)) {
786 printf("\n Converting %s to CMYK failed\n", filename);
787 retval = -1; goto bailout;
790 /* Verify that tjLoadImage() returns the proper "preferred" pixel format for
792 tjFree(buf); buf = NULL;
794 pixelFormat = TJPF_UNKNOWN;
795 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight,
796 &pixelFormat, flags)) == NULL)
798 if ((pf == TJPF_GRAY && pixelFormat != TJPF_GRAY) ||
799 (pf != TJPF_GRAY && !strcasecmp(ext, "bmp") &&
800 pixelFormat != TJPF_BGR) ||
801 (pf != TJPF_GRAY && !strcasecmp(ext, "ppm") &&
802 pixelFormat != TJPF_RGB)) {
803 printf("\n tjLoadImage() returned unexpected pixel format: %s\n",
804 pixFormatStr[pixelFormat]);
810 if (buf) tjFree(buf);
811 if (exitStatus < 0) return exitStatus;
818 int align, width = 35, height = 39, format;
820 for (align = 1; align <= 8; align *= 2) {
821 for (format = 0; format < TJ_NUMPF; format++) {
822 printf("%s Top-Down BMP (row alignment = %d bytes) ... ",
823 pixFormatStr[format], align);
824 if (doBmpTest("bmp", width, align, height, format, 0) == -1)
828 printf("%s Top-Down PPM (row alignment = %d bytes) ... ",
829 pixFormatStr[format], align);
830 if (doBmpTest("ppm", width, align, height, format,
831 TJFLAG_BOTTOMUP) == -1)
835 printf("%s Bottom-Up BMP (row alignment = %d bytes) ... ",
836 pixFormatStr[format], align);
837 if (doBmpTest("bmp", width, align, height, format, 0) == -1)
841 printf("%s Bottom-Up PPM (row alignment = %d bytes) ... ",
842 pixFormatStr[format], align);
843 if (doBmpTest("ppm", width, align, height, format,
844 TJFLAG_BOTTOMUP) == -1)
854 int main(int argc, char *argv[])
859 srand((unsigned int)time(NULL));
862 for (i = 1; i < argc; i++) {
863 if (!strcasecmp(argv[i], "-yuv")) doYUV = 1;
864 else if (!strcasecmp(argv[i], "-noyuvpad")) pad = 1;
865 else if (!strcasecmp(argv[i], "-alloc")) alloc = 1;
866 else if (!strcasecmp(argv[i], "-bmp")) return bmpTest();
870 if (alloc) printf("Testing automatic buffer allocation\n");
871 if (doYUV) num4bf = 4;
872 doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
873 doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
874 doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
875 doTest(35, 39, _4byteFormats, num4bf, TJSAMP_422, "test");
876 doTest(39, 41, _3byteFormats, 2, TJSAMP_420, "test");
877 doTest(41, 35, _4byteFormats, num4bf, TJSAMP_420, "test");
878 doTest(35, 39, _3byteFormats, 2, TJSAMP_440, "test");
879 doTest(39, 41, _4byteFormats, num4bf, TJSAMP_440, "test");
880 doTest(41, 35, _3byteFormats, 2, TJSAMP_411, "test");
881 doTest(35, 39, _4byteFormats, num4bf, TJSAMP_411, "test");
882 doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
883 doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
884 doTest(35, 39, _4byteFormats, 4, TJSAMP_GRAY, "test");
887 printf("\n--------------------\n\n");
888 doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
889 doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
890 doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
891 doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
892 doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
893 doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
894 doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");