blob: da7c6ffabbfbf3616beafb0592c8114b9c0cfb54 [file] [log] [blame]
DRCb8b359a2011-05-25 03:54:56 +00001/*
DRC6399d0a2019-04-23 14:10:04 -05002 * Copyright (C)2009-2014, 2017-2019 D. R. Commander. All Rights Reserved.
DRCb8b359a2011-05-25 03:54:56 +00003 *
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/*
DRCc52c5562011-06-15 02:43:42 +000030 * This program tests the various code paths in the TurboJPEG C Wrapper
DRCb8b359a2011-05-25 03:54:56 +000031 */
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
DRCaa745902017-11-16 18:09:07 -060037#include "tjutil.h"
38#include "turbojpeg.h"
39#include "md5/md5.h"
40#include "cmyk.h"
DRCe835ee32011-07-15 10:06:56 +000041#ifdef _WIN32
DRC19c791c2018-03-08 10:55:20 -060042#include <time.h>
DRCdc9bdf12018-04-12 17:02:10 -050043#define random() rand()
DRCaa745902017-11-16 18:09:07 -060044#else
DRC19c791c2018-03-08 10:55:20 -060045#include <unistd.h>
DRCe835ee32011-07-15 10:06:56 +000046#endif
DRCb8b359a2011-05-25 03:54:56 +000047
48
DRC6399d0a2019-04-23 14:10:04 -050049static void usage(char *progName)
DRCb8b359a2011-05-25 03:54:56 +000050{
DRC19c791c2018-03-08 10:55:20 -060051 printf("\nUSAGE: %s [options]\n\n", progName);
52 printf("Options:\n");
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");
58 exit(1);
DRCb8b359a2011-05-25 03:54:56 +000059}
60
61
DRCbce58f42019-04-12 07:49:35 -050062#define THROW_TJ() { \
DRC19c791c2018-03-08 10:55:20 -060063 printf("TurboJPEG ERROR:\n%s\n", tjGetErrorStr()); \
DRCbce58f42019-04-12 07:49:35 -050064 BAILOUT() \
DRC19c791c2018-03-08 10:55:20 -060065}
DRCbce58f42019-04-12 07:49:35 -050066#define TRY_TJ(f) { if ((f) == -1) THROW_TJ(); }
67#define THROW(m) { printf("ERROR: %s\n", m); BAILOUT() }
68#define THROW_MD5(filename, md5sum, ref) { \
DRC19c791c2018-03-08 10:55:20 -060069 printf("\n%s has an MD5 sum of %s.\n Should be %s.\n", filename, md5sum, \
70 ref); \
DRCbce58f42019-04-12 07:49:35 -050071 BAILOUT() \
DRCaa745902017-11-16 18:09:07 -060072}
73
DRC19c791c2018-03-08 10:55:20 -060074const char *subNameLong[TJ_NUMSAMP] = {
75 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
DRCb8b359a2011-05-25 03:54:56 +000076};
DRC19c791c2018-03-08 10:55:20 -060077const char *subName[TJ_NUMSAMP] = {
78 "444", "422", "420", "GRAY", "440", "411"
DRCb8b359a2011-05-25 03:54:56 +000079};
80
DRC19c791c2018-03-08 10:55:20 -060081const char *pixFormatStr[TJ_NUMPF] = {
82 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
83 "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
84};
DRCb8b359a2011-05-25 03:54:56 +000085
DRC19c791c2018-03-08 10:55:20 -060086const int _3byteFormats[] = { TJPF_RGB, TJPF_BGR };
87const int _4byteFormats[] = {
88 TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_CMYK
89};
90const int _onlyGray[] = { TJPF_GRAY };
91const int _onlyRGB[] = { TJPF_RGB };
DRCb8b359a2011-05-25 03:54:56 +000092
DRC19c791c2018-03-08 10:55:20 -060093int doYUV = 0, alloc = 0, pad = 4;
94
95int exitStatus = 0;
DRCbce58f42019-04-12 07:49:35 -050096#define BAILOUT() { exitStatus = -1; goto bailout; }
DRCb8b359a2011-05-25 03:54:56 +000097
DRCb8b359a2011-05-25 03:54:56 +000098
DRC6399d0a2019-04-23 14:10:04 -050099static void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
DRCb8b359a2011-05-25 03:54:56 +0000100{
DRC19c791c2018-03-08 10:55:20 -0600101 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;
DRCb8b359a2011-05-25 03:54:56 +0000106
DRC19c791c2018-03-08 10:55:20 -0600107 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;
116 }
117 }
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;
126 } else {
127 buf[index * ps + 2] = 0;
128 if (row < halfway) buf[index * ps + 1] = 0;
129 }
130 }
131 }
132 } else {
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) {
139 if (row < halfway) {
140 buf[index * ps + roffset] = 255;
141 buf[index * ps + goffset] = 255;
142 buf[index * ps + boffset] = 255;
143 }
144 } else {
145 buf[index * ps + roffset] = 255;
146 if (row >= halfway) buf[index * ps + goffset] = 255;
147 }
148 }
149 }
150 }
DRCb8b359a2011-05-25 03:54:56 +0000151}
152
153
DRCbce58f42019-04-12 07:49:35 -0500154#define CHECKVAL(v, cv) { \
DRC19c791c2018-03-08 10:55:20 -0600155 if (v < cv - 1 || v > cv + 1) { \
156 printf("\nComp. %s at %d,%d should be %d, not %d\n", #v, row, col, cv, \
157 v); \
158 retval = 0; exitStatus = -1; goto bailout; \
159 } \
160}
DRCb8b359a2011-05-25 03:54:56 +0000161
DRCbce58f42019-04-12 07:49:35 -0500162#define CHECKVAL0(v) { \
DRC19c791c2018-03-08 10:55:20 -0600163 if (v > 1) { \
164 printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, row, col, v); \
165 retval = 0; exitStatus = -1; goto bailout; \
166 } \
167}
DRCb8b359a2011-05-25 03:54:56 +0000168
DRCbce58f42019-04-12 07:49:35 -0500169#define CHECKVAL255(v) { \
DRC19c791c2018-03-08 10:55:20 -0600170 if (v < 254) { \
171 printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, row, col, v); \
172 retval = 0; exitStatus = -1; goto bailout; \
173 } \
DRCb8b359a2011-05-25 03:54:56 +0000174}
175
176
DRC6399d0a2019-04-23 14:10:04 -0500177static int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
178 tjscalingfactor sf, int flags)
DRC19c791c2018-03-08 10:55:20 -0600179{
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;
188
189 if (pf == TJPF_GRAY) roffset = goffset = boffset = 0;
190
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;
195
196 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
197 else index = row * w + col;
198 c = buf[index * ps];
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) {
DRCbce58f42019-04-12 07:49:35 -0500203 CHECKVAL255(c); CHECKVAL255(m); CHECKVAL255(y);
204 if (row < halfway) CHECKVAL255(k)
205 else CHECKVAL0(k)
DRC19c791c2018-03-08 10:55:20 -0600206 } else {
DRCbce58f42019-04-12 07:49:35 -0500207 CHECKVAL255(c); CHECKVAL0(y); CHECKVAL255(k);
208 if (row < halfway) CHECKVAL0(m)
209 else CHECKVAL255(m)
DRC19c791c2018-03-08 10:55:20 -0600210 }
211 }
212 }
213 return 1;
214 }
215
216 for (row = 0; row < h; row++) {
217 for (col = 0; col < w; col++) {
218 unsigned char r, g, b, a;
219
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) {
227 if (row < halfway) {
DRCbce58f42019-04-12 07:49:35 -0500228 CHECKVAL255(r); CHECKVAL255(g); CHECKVAL255(b);
DRC19c791c2018-03-08 10:55:20 -0600229 } else {
DRCbce58f42019-04-12 07:49:35 -0500230 CHECKVAL0(r); CHECKVAL0(g); CHECKVAL0(b);
DRC19c791c2018-03-08 10:55:20 -0600231 }
232 } else {
233 if (subsamp == TJSAMP_GRAY) {
234 if (row < halfway) {
DRCbce58f42019-04-12 07:49:35 -0500235 CHECKVAL(r, 76); CHECKVAL(g, 76); CHECKVAL(b, 76);
DRC19c791c2018-03-08 10:55:20 -0600236 } else {
DRCbce58f42019-04-12 07:49:35 -0500237 CHECKVAL(r, 226); CHECKVAL(g, 226); CHECKVAL(b, 226);
DRC19c791c2018-03-08 10:55:20 -0600238 }
239 } else {
240 if (row < halfway) {
DRCbce58f42019-04-12 07:49:35 -0500241 CHECKVAL255(r); CHECKVAL0(g); CHECKVAL0(b);
DRC19c791c2018-03-08 10:55:20 -0600242 } else {
DRCbce58f42019-04-12 07:49:35 -0500243 CHECKVAL255(r); CHECKVAL255(g); CHECKVAL0(b);
DRC19c791c2018-03-08 10:55:20 -0600244 }
245 }
246 }
DRCbce58f42019-04-12 07:49:35 -0500247 CHECKVAL255(a);
DRC19c791c2018-03-08 10:55:20 -0600248 }
249 }
250
251bailout:
252 if (retval == 0) {
253 for (row = 0; row < h; row++) {
254 for (col = 0; col < w; col++) {
255 if (pf == TJPF_CMYK)
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]);
259 else
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]);
263 }
264 printf("\n");
265 }
266 }
267 return retval;
268}
269
270
DRC293263c2018-03-17 15:14:35 -0500271#define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
DRCb8b359a2011-05-25 03:54:56 +0000272
DRC6399d0a2019-04-23 14:10:04 -0500273static int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
274 tjscalingfactor sf)
DRCb8b359a2011-05-25 03:54:56 +0000275{
DRC19c791c2018-03-08 10:55:20 -0600276 int row, col;
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);
281 int retval = 1;
282 int halfway = 16 * sf.num / sf.denom;
283 int blocksize = 8 * sf.num / sf.denom;
DRCb8b359a2011-05-25 03:54:56 +0000284
DRC19c791c2018-03-08 10:55:20 -0600285 for (row = 0; row < ph; row++) {
286 for (col = 0; col < pw; col++) {
287 unsigned char y = buf[ypitch * row + col];
DRCb8b359a2011-05-25 03:54:56 +0000288
DRC19c791c2018-03-08 10:55:20 -0600289 if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
DRCbce58f42019-04-12 07:49:35 -0500290 if (row < halfway) CHECKVAL255(y)
291 else CHECKVAL0(y);
DRC19c791c2018-03-08 10:55:20 -0600292 } else {
DRCbce58f42019-04-12 07:49:35 -0500293 if (row < halfway) CHECKVAL(y, 76)
294 else CHECKVAL(y, 226);
DRC19c791c2018-03-08 10:55:20 -0600295 }
296 }
297 }
298 if (subsamp != TJSAMP_GRAY) {
DRC6399d0a2019-04-23 14:10:04 -0500299 halfway = 16 / vsf * sf.num / sf.denom;
DRCb8b359a2011-05-25 03:54:56 +0000300
DRC19c791c2018-03-08 10:55:20 -0600301 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)];
305
306 if (((row * vsf / blocksize) + (col * hsf / blocksize)) % 2 == 0) {
DRCbce58f42019-04-12 07:49:35 -0500307 CHECKVAL(u, 128); CHECKVAL(v, 128);
DRC19c791c2018-03-08 10:55:20 -0600308 } else {
309 if (row < halfway) {
DRCbce58f42019-04-12 07:49:35 -0500310 CHECKVAL(u, 85); CHECKVAL255(v);
DRC19c791c2018-03-08 10:55:20 -0600311 } else {
DRCbce58f42019-04-12 07:49:35 -0500312 CHECKVAL0(u); CHECKVAL(v, 149);
DRC19c791c2018-03-08 10:55:20 -0600313 }
314 }
315 }
316 }
317 }
318
319bailout:
320 if (retval == 0) {
321 for (row = 0; row < ph; row++) {
322 for (col = 0; col < pw; col++)
323 printf("%.3d ", buf[ypitch * row + col]);
324 printf("\n");
325 }
326 printf("\n");
327 for (row = 0; row < ch; row++) {
328 for (col = 0; col < cw; col++)
329 printf("%.3d ", buf[ypitch * ph + (uvpitch * row + col)]);
330 printf("\n");
331 }
332 printf("\n");
333 for (row = 0; row < ch; row++) {
334 for (col = 0; col < cw; col++)
335 printf("%.3d ",
336 buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]);
337 printf("\n");
338 }
339 }
340
341 return retval;
DRCb8b359a2011-05-25 03:54:56 +0000342}
343
344
DRC6399d0a2019-04-23 14:10:04 -0500345static void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize,
346 char *filename)
DRCb8b359a2011-05-25 03:54:56 +0000347{
DRC19c791c2018-03-08 10:55:20 -0600348 FILE *file = fopen(filename, "wb");
DRCb8b359a2011-05-25 03:54:56 +0000349
DRC19c791c2018-03-08 10:55:20 -0600350 if (!file || fwrite(jpegBuf, jpegSize, 1, file) != 1) {
351 printf("ERROR: Could not write to %s.\n%s\n", filename, strerror(errno));
DRCbce58f42019-04-12 07:49:35 -0500352 BAILOUT()
DRC19c791c2018-03-08 10:55:20 -0600353 }
354
355bailout:
356 if (file) fclose(file);
DRCb8b359a2011-05-25 03:54:56 +0000357}
358
359
DRC6399d0a2019-04-23 14:10:04 -0500360static void compTest(tjhandle handle, unsigned char **dstBuf,
361 unsigned long *dstSize, int w, int h, int pf,
362 char *basename, int subsamp, int jpegQual, int flags)
DRCb8b359a2011-05-25 03:54:56 +0000363{
DRC19c791c2018-03-08 10:55:20 -0600364 char tempStr[1024];
365 unsigned char *srcBuf = NULL, *yuvBuf = NULL;
366 const char *pfStr = pixFormatStr[pf];
367 const char *buStrLong =
368 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ";
369 const char *buStr = (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD";
DRCb8b359a2011-05-25 03:54:56 +0000370
DRC19c791c2018-03-08 10:55:20 -0600371 if ((srcBuf = (unsigned char *)malloc(w * h * tjPixelSize[pf])) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500372 THROW("Memory allocation failure");
DRC19c791c2018-03-08 10:55:20 -0600373 initBuf(srcBuf, w, h, pf, flags);
DRCb8b359a2011-05-25 03:54:56 +0000374
DRC19c791c2018-03-08 10:55:20 -0600375 if (*dstBuf && *dstSize > 0) memset(*dstBuf, 0, *dstSize);
DRCb8b359a2011-05-25 03:54:56 +0000376
DRC19c791c2018-03-08 10:55:20 -0600377 if (!alloc) flags |= TJFLAG_NOREALLOC;
378 if (doYUV) {
379 unsigned long yuvSize = tjBufSizeYUV2(w, pad, h, subsamp);
380 tjscalingfactor sf = { 1, 1 };
381 tjhandle handle2 = tjInitCompress();
DRCb8b359a2011-05-25 03:54:56 +0000382
DRCbce58f42019-04-12 07:49:35 -0500383 if (!handle2) THROW_TJ();
DRC34dca052014-02-28 09:17:14 +0000384
DRC19c791c2018-03-08 10:55:20 -0600385 if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500386 THROW("Memory allocation failure");
DRC19c791c2018-03-08 10:55:20 -0600387 memset(yuvBuf, 0, yuvSize);
DRC34dca052014-02-28 09:17:14 +0000388
DRC19c791c2018-03-08 10:55:20 -0600389 printf("%s %s -> YUV %s ... ", pfStr, buStrLong, subNameLong[subsamp]);
DRCbce58f42019-04-12 07:49:35 -0500390 TRY_TJ(tjEncodeYUV3(handle2, srcBuf, w, 0, h, pf, yuvBuf, pad, subsamp,
391 flags));
DRC19c791c2018-03-08 10:55:20 -0600392 tjDestroy(handle2);
393 if (checkBufYUV(yuvBuf, w, h, subsamp, sf)) printf("Passed.\n");
394 else printf("FAILED!\n");
DRC34dca052014-02-28 09:17:14 +0000395
DRC19c791c2018-03-08 10:55:20 -0600396 printf("YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp], buStrLong,
397 jpegQual);
DRCbce58f42019-04-12 07:49:35 -0500398 TRY_TJ(tjCompressFromYUV(handle, yuvBuf, w, pad, h, subsamp, dstBuf,
399 dstSize, jpegQual, flags));
DRC19c791c2018-03-08 10:55:20 -0600400 } else {
401 printf("%s %s -> %s Q%d ... ", pfStr, buStrLong, subNameLong[subsamp],
402 jpegQual);
DRCbce58f42019-04-12 07:49:35 -0500403 TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
404 jpegQual, flags));
DRC19c791c2018-03-08 10:55:20 -0600405 }
DRC34dca052014-02-28 09:17:14 +0000406
DRC19c791c2018-03-08 10:55:20 -0600407 snprintf(tempStr, 1024, "%s_enc_%s_%s_%s_Q%d.jpg", basename, pfStr, buStr,
408 subName[subsamp], jpegQual);
409 writeJPEG(*dstBuf, *dstSize, tempStr);
410 printf("Done.\n Result in %s\n", tempStr);
DRCb8b359a2011-05-25 03:54:56 +0000411
DRC19c791c2018-03-08 10:55:20 -0600412bailout:
413 if (yuvBuf) free(yuvBuf);
414 if (srcBuf) free(srcBuf);
DRCb8b359a2011-05-25 03:54:56 +0000415}
416
417
DRC6399d0a2019-04-23 14:10:04 -0500418static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
419 unsigned long jpegSize, int w, int h, int pf,
420 char *basename, int subsamp, int flags,
421 tjscalingfactor sf)
DRCb8b359a2011-05-25 03:54:56 +0000422{
DRC19c791c2018-03-08 10:55:20 -0600423 unsigned char *dstBuf = NULL, *yuvBuf = NULL;
424 int _hdrw = 0, _hdrh = 0, _hdrsubsamp = -1;
425 int scaledWidth = TJSCALED(w, sf);
426 int scaledHeight = TJSCALED(h, sf);
427 unsigned long dstSize = 0;
DRCb8b359a2011-05-25 03:54:56 +0000428
DRCbce58f42019-04-12 07:49:35 -0500429 TRY_TJ(tjDecompressHeader2(handle, jpegBuf, jpegSize, &_hdrw, &_hdrh,
430 &_hdrsubsamp));
DRC19c791c2018-03-08 10:55:20 -0600431 if (_hdrw != w || _hdrh != h || _hdrsubsamp != subsamp)
DRCbce58f42019-04-12 07:49:35 -0500432 THROW("Incorrect JPEG header");
DRCb8b359a2011-05-25 03:54:56 +0000433
DRC19c791c2018-03-08 10:55:20 -0600434 dstSize = scaledWidth * scaledHeight * tjPixelSize[pf];
435 if ((dstBuf = (unsigned char *)malloc(dstSize)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500436 THROW("Memory allocation failure");
DRC19c791c2018-03-08 10:55:20 -0600437 memset(dstBuf, 0, dstSize);
DRCb8b359a2011-05-25 03:54:56 +0000438
DRC19c791c2018-03-08 10:55:20 -0600439 if (doYUV) {
440 unsigned long yuvSize = tjBufSizeYUV2(scaledWidth, pad, scaledHeight,
441 subsamp);
442 tjhandle handle2 = tjInitDecompress();
DRC34dca052014-02-28 09:17:14 +0000443
DRCbce58f42019-04-12 07:49:35 -0500444 if (!handle2) THROW_TJ();
DRC34dca052014-02-28 09:17:14 +0000445
DRC19c791c2018-03-08 10:55:20 -0600446 if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500447 THROW("Memory allocation failure");
DRC19c791c2018-03-08 10:55:20 -0600448 memset(yuvBuf, 0, yuvSize);
DRC34dca052014-02-28 09:17:14 +0000449
DRC19c791c2018-03-08 10:55:20 -0600450 printf("JPEG -> YUV %s ", subNameLong[subsamp]);
451 if (sf.num != 1 || sf.denom != 1)
452 printf("%d/%d ... ", sf.num, sf.denom);
453 else printf("... ");
DRCbce58f42019-04-12 07:49:35 -0500454 TRY_TJ(tjDecompressToYUV2(handle, jpegBuf, jpegSize, yuvBuf, scaledWidth,
455 pad, scaledHeight, flags));
DRC19c791c2018-03-08 10:55:20 -0600456 if (checkBufYUV(yuvBuf, scaledWidth, scaledHeight, subsamp, sf))
457 printf("Passed.\n");
458 else printf("FAILED!\n");
DRCb8b359a2011-05-25 03:54:56 +0000459
DRC19c791c2018-03-08 10:55:20 -0600460 printf("YUV %s -> %s %s ... ", subNameLong[subsamp], pixFormatStr[pf],
461 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
DRCbce58f42019-04-12 07:49:35 -0500462 TRY_TJ(tjDecodeYUV(handle2, yuvBuf, pad, subsamp, dstBuf, scaledWidth, 0,
463 scaledHeight, pf, flags));
DRC19c791c2018-03-08 10:55:20 -0600464 tjDestroy(handle2);
465 } else {
466 printf("JPEG -> %s %s ", pixFormatStr[pf],
467 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
468 if (sf.num != 1 || sf.denom != 1)
469 printf("%d/%d ... ", sf.num, sf.denom);
470 else printf("... ");
DRCbce58f42019-04-12 07:49:35 -0500471 TRY_TJ(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth, 0,
472 scaledHeight, pf, flags));
DRC19c791c2018-03-08 10:55:20 -0600473 }
DRCb8b359a2011-05-25 03:54:56 +0000474
DRC19c791c2018-03-08 10:55:20 -0600475 if (checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, flags))
476 printf("Passed.");
477 else printf("FAILED!");
478 printf("\n");
479
480bailout:
481 if (yuvBuf) free(yuvBuf);
482 if (dstBuf) free(dstBuf);
DRCb8b359a2011-05-25 03:54:56 +0000483}
484
485
DRC6399d0a2019-04-23 14:10:04 -0500486static void decompTest(tjhandle handle, unsigned char *jpegBuf,
487 unsigned long jpegSize, int w, int h, int pf,
488 char *basename, int subsamp, int flags)
DRCb8b359a2011-05-25 03:54:56 +0000489{
DRC19c791c2018-03-08 10:55:20 -0600490 int i, n = 0;
491 tjscalingfactor *sf = tjGetScalingFactors(&n);
DRCb8b359a2011-05-25 03:54:56 +0000492
DRCbce58f42019-04-12 07:49:35 -0500493 if (!sf || !n) THROW_TJ();
DRCb8b359a2011-05-25 03:54:56 +0000494
DRC19c791c2018-03-08 10:55:20 -0600495 for (i = 0; i < n; i++) {
496 if (subsamp == TJSAMP_444 || subsamp == TJSAMP_GRAY ||
497 (subsamp == TJSAMP_411 && sf[i].num == 1 &&
498 (sf[i].denom == 2 || sf[i].denom == 1)) ||
499 (subsamp != TJSAMP_411 && sf[i].num == 1 &&
500 (sf[i].denom == 4 || sf[i].denom == 2 || sf[i].denom == 1)))
501 _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
502 flags, sf[i]);
503 }
504
505bailout:
506 return;
DRCb8b359a2011-05-25 03:54:56 +0000507}
508
509
DRC6399d0a2019-04-23 14:10:04 -0500510static void doTest(int w, int h, const int *formats, int nformats, int subsamp,
511 char *basename)
DRCb8b359a2011-05-25 03:54:56 +0000512{
DRC19c791c2018-03-08 10:55:20 -0600513 tjhandle chandle = NULL, dhandle = NULL;
514 unsigned char *dstBuf = NULL;
515 unsigned long size = 0;
516 int pfi, pf, i;
DRCb8b359a2011-05-25 03:54:56 +0000517
DRC19c791c2018-03-08 10:55:20 -0600518 if (!alloc)
519 size = tjBufSize(w, h, subsamp);
520 if (size != 0)
521 if ((dstBuf = (unsigned char *)tjAlloc(size)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500522 THROW("Memory allocation failure.");
DRCb8b359a2011-05-25 03:54:56 +0000523
DRC19c791c2018-03-08 10:55:20 -0600524 if ((chandle = tjInitCompress()) == NULL ||
525 (dhandle = tjInitDecompress()) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500526 THROW_TJ();
DRCb8b359a2011-05-25 03:54:56 +0000527
DRC19c791c2018-03-08 10:55:20 -0600528 for (pfi = 0; pfi < nformats; pfi++) {
529 for (i = 0; i < 2; i++) {
530 int flags = 0;
DRCb8b359a2011-05-25 03:54:56 +0000531
DRC19c791c2018-03-08 10:55:20 -0600532 if (subsamp == TJSAMP_422 || subsamp == TJSAMP_420 ||
533 subsamp == TJSAMP_440 || subsamp == TJSAMP_411)
534 flags |= TJFLAG_FASTUPSAMPLE;
535 if (i == 1) flags |= TJFLAG_BOTTOMUP;
536 pf = formats[pfi];
537 compTest(chandle, &dstBuf, &size, w, h, pf, basename, subsamp, 100,
538 flags);
539 decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp, flags);
540 if (pf >= TJPF_RGBX && pf <= TJPF_XRGB) {
541 printf("\n");
542 decompTest(dhandle, dstBuf, size, w, h, pf + (TJPF_RGBA - TJPF_RGBX),
543 basename, subsamp, flags);
544 }
545 printf("\n");
546 }
547 }
548 printf("--------------------\n\n");
DRCb8b359a2011-05-25 03:54:56 +0000549
DRC19c791c2018-03-08 10:55:20 -0600550bailout:
551 if (chandle) tjDestroy(chandle);
552 if (dhandle) tjDestroy(dhandle);
553 if (dstBuf) tjFree(dstBuf);
DRCb8b359a2011-05-25 03:54:56 +0000554}
555
556
DRC2a9e3bd2019-07-11 15:30:04 -0500557#if SIZEOF_SIZE_T == 8
558#define CHECKSIZE(function) { \
559 if ((unsigned long long)size < (unsigned long long)0xFFFFFFFF) \
560 THROW(#function " overflow"); \
561}
562#else
563#define CHECKSIZE(function) { \
564 if (size != (unsigned long)(-1) || \
565 !strcmp(tjGetErrorStr2(NULL), "No error")) \
566 THROW(#function " overflow"); \
567}
568#endif
569
570static void overflowTest(void)
571{
572 /* Ensure that the various buffer size functions don't overflow */
573 unsigned long size;
574
575 size = tjBufSize(26755, 26755, TJSAMP_444);
576 CHECKSIZE(tjBufSize());
577 size = TJBUFSIZE(26755, 26755);
578 CHECKSIZE(TJBUFSIZE());
579 size = tjBufSizeYUV2(37838, 1, 37838, TJSAMP_444);
580 CHECKSIZE(tjBufSizeYUV2());
581 size = TJBUFSIZEYUV(37838, 37838, TJSAMP_444);
582 CHECKSIZE(TJBUFSIZEYUV());
583 size = tjBufSizeYUV(37838, 37838, TJSAMP_444);
584 CHECKSIZE(tjBufSizeYUV());
585 size = tjPlaneSizeYUV(0, 65536, 0, 65536, TJSAMP_444);
586 CHECKSIZE(tjPlaneSizeYUV());
587
588bailout:
589 return;
590}
591
592
DRC6399d0a2019-04-23 14:10:04 -0500593static void bufSizeTest(void)
DRCb8b359a2011-05-25 03:54:56 +0000594{
DRC19c791c2018-03-08 10:55:20 -0600595 int w, h, i, subsamp;
596 unsigned char *srcBuf = NULL, *dstBuf = NULL;
597 tjhandle handle = NULL;
598 unsigned long dstSize = 0;
DRCb8b359a2011-05-25 03:54:56 +0000599
DRCbce58f42019-04-12 07:49:35 -0500600 if ((handle = tjInitCompress()) == NULL) THROW_TJ();
DRCb8b359a2011-05-25 03:54:56 +0000601
DRC19c791c2018-03-08 10:55:20 -0600602 printf("Buffer size regression test\n");
603 for (subsamp = 0; subsamp < TJ_NUMSAMP; subsamp++) {
604 for (w = 1; w < 48; w++) {
605 int maxh = (w == 1) ? 2048 : 48;
DRCb8b359a2011-05-25 03:54:56 +0000606
DRC19c791c2018-03-08 10:55:20 -0600607 for (h = 1; h < maxh; h++) {
608 if (h % 100 == 0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
609 if ((srcBuf = (unsigned char *)malloc(w * h * 4)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500610 THROW("Memory allocation failure");
DRC19c791c2018-03-08 10:55:20 -0600611 if (!alloc || doYUV) {
612 if (doYUV) dstSize = tjBufSizeYUV2(w, pad, h, subsamp);
613 else dstSize = tjBufSize(w, h, subsamp);
614 if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500615 THROW("Memory allocation failure");
DRC19c791c2018-03-08 10:55:20 -0600616 }
DRCb8b359a2011-05-25 03:54:56 +0000617
DRC19c791c2018-03-08 10:55:20 -0600618 for (i = 0; i < w * h * 4; i++) {
619 if (random() < RAND_MAX / 2) srcBuf[i] = 0;
620 else srcBuf[i] = 255;
621 }
DRCb8b359a2011-05-25 03:54:56 +0000622
DRC19c791c2018-03-08 10:55:20 -0600623 if (doYUV) {
DRCbce58f42019-04-12 07:49:35 -0500624 TRY_TJ(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf, pad,
625 subsamp, 0));
DRC19c791c2018-03-08 10:55:20 -0600626 } else {
DRCbce58f42019-04-12 07:49:35 -0500627 TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
628 &dstSize, subsamp, 100,
629 alloc ? 0 : TJFLAG_NOREALLOC));
DRC19c791c2018-03-08 10:55:20 -0600630 }
631 free(srcBuf); srcBuf = NULL;
632 if (!alloc || doYUV) {
633 tjFree(dstBuf); dstBuf = NULL;
634 }
DRCb8b359a2011-05-25 03:54:56 +0000635
DRC19c791c2018-03-08 10:55:20 -0600636 if ((srcBuf = (unsigned char *)malloc(h * w * 4)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500637 THROW("Memory allocation failure");
DRC19c791c2018-03-08 10:55:20 -0600638 if (!alloc || doYUV) {
639 if (doYUV) dstSize = tjBufSizeYUV2(h, pad, w, subsamp);
640 else dstSize = tjBufSize(h, w, subsamp);
641 if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500642 THROW("Memory allocation failure");
DRC19c791c2018-03-08 10:55:20 -0600643 }
DRC724c56b2011-07-12 06:22:06 +0000644
DRC19c791c2018-03-08 10:55:20 -0600645 for (i = 0; i < h * w * 4; i++) {
646 if (random() < RAND_MAX / 2) srcBuf[i] = 0;
647 else srcBuf[i] = 255;
648 }
DRCb8b359a2011-05-25 03:54:56 +0000649
DRC19c791c2018-03-08 10:55:20 -0600650 if (doYUV) {
DRCbce58f42019-04-12 07:49:35 -0500651 TRY_TJ(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf, pad,
652 subsamp, 0));
DRC19c791c2018-03-08 10:55:20 -0600653 } else {
DRCbce58f42019-04-12 07:49:35 -0500654 TRY_TJ(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
655 &dstSize, subsamp, 100,
656 alloc ? 0 : TJFLAG_NOREALLOC));
DRC19c791c2018-03-08 10:55:20 -0600657 }
658 free(srcBuf); srcBuf = NULL;
659 if (!alloc || doYUV) {
660 tjFree(dstBuf); dstBuf = NULL;
661 }
662 }
663 }
664 }
665 printf("Done. \n");
666
667bailout:
668 if (srcBuf) free(srcBuf);
669 if (dstBuf) tjFree(dstBuf);
670 if (handle) tjDestroy(handle);
DRCb8b359a2011-05-25 03:54:56 +0000671}
672
673
DRC6399d0a2019-04-23 14:10:04 -0500674static void initBitmap(unsigned char *buf, int width, int pitch, int height,
675 int pf, int flags)
DRCaa745902017-11-16 18:09:07 -0600676{
DRC19c791c2018-03-08 10:55:20 -0600677 int roffset = tjRedOffset[pf];
678 int goffset = tjGreenOffset[pf];
679 int boffset = tjBlueOffset[pf];
680 int ps = tjPixelSize[pf];
681 int i, j;
DRCaa745902017-11-16 18:09:07 -0600682
DRC19c791c2018-03-08 10:55:20 -0600683 for (j = 0; j < height; j++) {
684 int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
685
686 for (i = 0; i < width; i++) {
687 unsigned char r = (i * 256 / width) % 256;
688 unsigned char g = (j * 256 / height) % 256;
689 unsigned char b = (j * 256 / height + i * 256 / width) % 256;
690
691 memset(&buf[row * pitch + i * ps], 0, ps);
692 if (pf == TJPF_GRAY) buf[row * pitch + i * ps] = b;
693 else if (pf == TJPF_CMYK)
694 rgb_to_cmyk(r, g, b, &buf[row * pitch + i * ps + 0],
695 &buf[row * pitch + i * ps + 1],
696 &buf[row * pitch + i * ps + 2],
697 &buf[row * pitch + i * ps + 3]);
698 else {
699 buf[row * pitch + i * ps + roffset] = r;
700 buf[row * pitch + i * ps + goffset] = g;
701 buf[row * pitch + i * ps + boffset] = b;
702 }
703 }
704 }
DRCaa745902017-11-16 18:09:07 -0600705}
706
707
DRC6399d0a2019-04-23 14:10:04 -0500708static int cmpBitmap(unsigned char *buf, int width, int pitch, int height,
709 int pf, int flags, int gray2rgb)
DRCaa745902017-11-16 18:09:07 -0600710{
DRC19c791c2018-03-08 10:55:20 -0600711 int roffset = tjRedOffset[pf];
712 int goffset = tjGreenOffset[pf];
713 int boffset = tjBlueOffset[pf];
714 int aoffset = tjAlphaOffset[pf];
715 int ps = tjPixelSize[pf];
716 int i, j;
DRCaa745902017-11-16 18:09:07 -0600717
DRC19c791c2018-03-08 10:55:20 -0600718 for (j = 0; j < height; j++) {
719 int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
720
721 for (i = 0; i < width; i++) {
722 unsigned char r = (i * 256 / width) % 256;
723 unsigned char g = (j * 256 / height) % 256;
724 unsigned char b = (j * 256 / height + i * 256 / width) % 256;
725
726 if (pf == TJPF_GRAY) {
727 if (buf[row * pitch + i * ps] != b)
728 return 0;
729 } else if (pf == TJPF_CMYK) {
730 unsigned char rf, gf, bf;
731
732 cmyk_to_rgb(buf[row * pitch + i * ps + 0],
733 buf[row * pitch + i * ps + 1],
734 buf[row * pitch + i * ps + 2],
735 buf[row * pitch + i * ps + 3], &rf, &gf, &bf);
736 if (gray2rgb) {
737 if (rf != b || gf != b || bf != b)
738 return 0;
739 } else if (rf != r || gf != g || bf != b) return 0;
740 } else {
741 if (gray2rgb) {
742 if (buf[row * pitch + i * ps + roffset] != b ||
743 buf[row * pitch + i * ps + goffset] != b ||
744 buf[row * pitch + i * ps + boffset] != b)
745 return 0;
746 } else if (buf[row * pitch + i * ps + roffset] != r ||
747 buf[row * pitch + i * ps + goffset] != g ||
748 buf[row * pitch + i * ps + boffset] != b)
749 return 0;
750 if (aoffset >= 0 && buf[row * pitch + i * ps + aoffset] != 0xFF)
751 return 0;
752 }
753 }
754 }
755 return 1;
DRCaa745902017-11-16 18:09:07 -0600756}
757
758
DRC6399d0a2019-04-23 14:10:04 -0500759static int doBmpTest(const char *ext, int width, int align, int height, int pf,
760 int flags)
DRCaa745902017-11-16 18:09:07 -0600761{
DRC19c791c2018-03-08 10:55:20 -0600762 char filename[80], *md5sum, md5buf[65];
763 int ps = tjPixelSize[pf], pitch = PAD(width * ps, align), loadWidth = 0,
764 loadHeight = 0, retval = 0, pixelFormat = pf;
765 unsigned char *buf = NULL;
766 char *md5ref;
DRCaa745902017-11-16 18:09:07 -0600767
DRC19c791c2018-03-08 10:55:20 -0600768 if (pf == TJPF_GRAY) {
769 md5ref = !strcasecmp(ext, "ppm") ? "112c682e82ce5de1cca089e20d60000b" :
770 "51976530acf75f02beddf5d21149101d";
771 } else {
772 md5ref = !strcasecmp(ext, "ppm") ? "c0c9f772b464d1896326883a5c79c545" :
773 "6d659071b9bfcdee2def22cb58ddadca";
774 }
DRCaa745902017-11-16 18:09:07 -0600775
DRC19c791c2018-03-08 10:55:20 -0600776 if ((buf = (unsigned char *)tjAlloc(pitch * height)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500777 THROW("Could not allocate memory");
DRC19c791c2018-03-08 10:55:20 -0600778 initBitmap(buf, width, pitch, height, pf, flags);
DRCaa745902017-11-16 18:09:07 -0600779
DRC19c791c2018-03-08 10:55:20 -0600780 snprintf(filename, 80, "test_bmp_%s_%d_%s.%s", pixFormatStr[pf], align,
781 (flags & TJFLAG_BOTTOMUP) ? "bu" : "td", ext);
DRCbce58f42019-04-12 07:49:35 -0500782 TRY_TJ(tjSaveImage(filename, buf, width, pitch, height, pf, flags));
DRC19c791c2018-03-08 10:55:20 -0600783 md5sum = MD5File(filename, md5buf);
784 if (strcasecmp(md5sum, md5ref))
DRCbce58f42019-04-12 07:49:35 -0500785 THROW_MD5(filename, md5sum, md5ref);
DRCaa745902017-11-16 18:09:07 -0600786
DRC19c791c2018-03-08 10:55:20 -0600787 tjFree(buf); buf = NULL;
788 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
789 flags)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500790 THROW_TJ();
DRC19c791c2018-03-08 10:55:20 -0600791 if (width != loadWidth || height != loadHeight) {
792 printf("\n Image dimensions of %s are bogus\n", filename);
793 retval = -1; goto bailout;
794 }
795 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 0)) {
796 printf("\n Pixel data in %s is bogus\n", filename);
797 retval = -1; goto bailout;
798 }
799 if (pf == TJPF_GRAY) {
800 tjFree(buf); buf = NULL;
801 pf = TJPF_XBGR;
802 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
803 flags)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500804 THROW_TJ();
DRC19c791c2018-03-08 10:55:20 -0600805 pitch = PAD(width * tjPixelSize[pf], align);
806 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 1)) {
807 printf("\n Converting %s to RGB failed\n", filename);
808 retval = -1; goto bailout;
809 }
DRCaa745902017-11-16 18:09:07 -0600810
DRC19c791c2018-03-08 10:55:20 -0600811 tjFree(buf); buf = NULL;
812 pf = TJPF_CMYK;
813 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
814 flags)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500815 THROW_TJ();
DRC19c791c2018-03-08 10:55:20 -0600816 pitch = PAD(width * tjPixelSize[pf], align);
817 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 1)) {
818 printf("\n Converting %s to CMYK failed\n", filename);
819 retval = -1; goto bailout;
820 }
821 }
822 /* Verify that tjLoadImage() returns the proper "preferred" pixel format for
823 the file type. */
824 tjFree(buf); buf = NULL;
825 pf = pixelFormat;
826 pixelFormat = TJPF_UNKNOWN;
827 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight,
828 &pixelFormat, flags)) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500829 THROW_TJ();
DRC19c791c2018-03-08 10:55:20 -0600830 if ((pf == TJPF_GRAY && pixelFormat != TJPF_GRAY) ||
831 (pf != TJPF_GRAY && !strcasecmp(ext, "bmp") &&
832 pixelFormat != TJPF_BGR) ||
833 (pf != TJPF_GRAY && !strcasecmp(ext, "ppm") &&
834 pixelFormat != TJPF_RGB)) {
835 printf("\n tjLoadImage() returned unexpected pixel format: %s\n",
836 pixFormatStr[pixelFormat]);
837 retval = -1;
838 }
839 unlink(filename);
DRCaa745902017-11-16 18:09:07 -0600840
DRC19c791c2018-03-08 10:55:20 -0600841bailout:
842 if (buf) tjFree(buf);
843 if (exitStatus < 0) return exitStatus;
844 return retval;
DRCaa745902017-11-16 18:09:07 -0600845}
846
847
DRC6399d0a2019-04-23 14:10:04 -0500848static int bmpTest(void)
DRCaa745902017-11-16 18:09:07 -0600849{
DRC19c791c2018-03-08 10:55:20 -0600850 int align, width = 35, height = 39, format;
DRCaa745902017-11-16 18:09:07 -0600851
DRC19c791c2018-03-08 10:55:20 -0600852 for (align = 1; align <= 8; align *= 2) {
853 for (format = 0; format < TJ_NUMPF; format++) {
854 printf("%s Top-Down BMP (row alignment = %d bytes) ... ",
855 pixFormatStr[format], align);
856 if (doBmpTest("bmp", width, align, height, format, 0) == -1)
857 return -1;
858 printf("OK.\n");
DRCaa745902017-11-16 18:09:07 -0600859
DRC19c791c2018-03-08 10:55:20 -0600860 printf("%s Top-Down PPM (row alignment = %d bytes) ... ",
861 pixFormatStr[format], align);
862 if (doBmpTest("ppm", width, align, height, format,
863 TJFLAG_BOTTOMUP) == -1)
864 return -1;
865 printf("OK.\n");
DRCaa745902017-11-16 18:09:07 -0600866
DRC19c791c2018-03-08 10:55:20 -0600867 printf("%s Bottom-Up BMP (row alignment = %d bytes) ... ",
868 pixFormatStr[format], align);
869 if (doBmpTest("bmp", width, align, height, format, 0) == -1)
870 return -1;
871 printf("OK.\n");
DRCaa745902017-11-16 18:09:07 -0600872
DRC19c791c2018-03-08 10:55:20 -0600873 printf("%s Bottom-Up PPM (row alignment = %d bytes) ... ",
874 pixFormatStr[format], align);
875 if (doBmpTest("ppm", width, align, height, format,
876 TJFLAG_BOTTOMUP) == -1)
877 return -1;
878 printf("OK.\n");
879 }
880 }
DRCaa745902017-11-16 18:09:07 -0600881
DRC19c791c2018-03-08 10:55:20 -0600882 return 0;
DRCaa745902017-11-16 18:09:07 -0600883}
884
885
DRCb8b359a2011-05-25 03:54:56 +0000886int main(int argc, char *argv[])
887{
DRC19c791c2018-03-08 10:55:20 -0600888 int i, num4bf = 5;
DRCb8b359a2011-05-25 03:54:56 +0000889
DRC19c791c2018-03-08 10:55:20 -0600890#ifdef _WIN32
891 srand((unsigned int)time(NULL));
892#endif
893 if (argc > 1) {
894 for (i = 1; i < argc; i++) {
895 if (!strcasecmp(argv[i], "-yuv")) doYUV = 1;
896 else if (!strcasecmp(argv[i], "-noyuvpad")) pad = 1;
897 else if (!strcasecmp(argv[i], "-alloc")) alloc = 1;
898 else if (!strcasecmp(argv[i], "-bmp")) return bmpTest();
899 else usage(argv[0]);
900 }
901 }
902 if (alloc) printf("Testing automatic buffer allocation\n");
903 if (doYUV) num4bf = 4;
DRC2a9e3bd2019-07-11 15:30:04 -0500904 overflowTest();
DRC19c791c2018-03-08 10:55:20 -0600905 doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
906 doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
907 doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
908 doTest(35, 39, _4byteFormats, num4bf, TJSAMP_422, "test");
909 doTest(39, 41, _3byteFormats, 2, TJSAMP_420, "test");
910 doTest(41, 35, _4byteFormats, num4bf, TJSAMP_420, "test");
911 doTest(35, 39, _3byteFormats, 2, TJSAMP_440, "test");
912 doTest(39, 41, _4byteFormats, num4bf, TJSAMP_440, "test");
913 doTest(41, 35, _3byteFormats, 2, TJSAMP_411, "test");
914 doTest(35, 39, _4byteFormats, num4bf, TJSAMP_411, "test");
915 doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
916 doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
917 doTest(35, 39, _4byteFormats, 4, TJSAMP_GRAY, "test");
918 bufSizeTest();
919 if (doYUV) {
920 printf("\n--------------------\n\n");
921 doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
922 doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
923 doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
924 doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
925 doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
926 doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
927 doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");
928 }
929
930 return exitStatus;
DRCb8b359a2011-05-25 03:54:56 +0000931}