blob: af409a5608c5d516c32333ad85e00051e0bd41cd [file] [log] [blame]
hbono@chromium.org98626972011-08-03 03:13:08 +00001/*
Jonathan Wrightdb870df2020-08-05 11:42:22 +01002 * Copyright (C)2009-2014, 2017-2019 D. R. Commander. All Rights Reserved.
hbono@chromium.org98626972011-08-03 03:13:08 +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/*
30 * This program tests the various code paths in the TurboJPEG C Wrapper
31 */
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
Chris Blumecca8c4d2019-03-01 01:09:50 -080037#include "tjutil.h"
38#include "turbojpeg.h"
39#include "md5/md5.h"
40#include "cmyk.h"
hbono@chromium.org98626972011-08-03 03:13:08 +000041#ifdef _WIN32
Chris Blumecca8c4d2019-03-01 01:09:50 -080042#include <time.h>
43#define random() rand()
44#else
45#include <unistd.h>
hbono@chromium.org98626972011-08-03 03:13:08 +000046#endif
47
48
Jonathan Wright6cb95b82020-06-11 16:10:15 +010049#ifndef GTEST
50static void usage(char *progName)
hbono@chromium.org98626972011-08-03 03:13:08 +000051{
Chris Blumecca8c4d2019-03-01 01:09:50 -080052 printf("\nUSAGE: %s [options]\n\n", progName);
53 printf("Options:\n");
54 printf("-yuv = test YUV encoding/decoding support\n");
55 printf("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest\n");
56 printf(" 4-byte boundary\n");
57 printf("-alloc = test automatic buffer allocation\n");
58 printf("-bmp = tjLoadImage()/tjSaveImage() unit test\n\n");
59 exit(1);
hbono@chromium.org98626972011-08-03 03:13:08 +000060}
Jonathan Wright6cb95b82020-06-11 16:10:15 +010061#endif
hbono@chromium.org98626972011-08-03 03:13:08 +000062
63
Jonathan Wrightdb870df2020-08-05 11:42:22 +010064#define THROW_TJ() { \
Jonathan Wrighta145af12020-06-11 23:22:17 +010065 fprintf(stderr, "TurboJPEG ERROR:\n%s\n", tjGetErrorStr()); \
Jonathan Wrightdb870df2020-08-05 11:42:22 +010066 BAILOUT() \
Chris Blumecca8c4d2019-03-01 01:09:50 -080067}
Jonathan Wrightdb870df2020-08-05 11:42:22 +010068#define TRY_TJ(f) { if ((f) == -1) THROW_TJ(); }
69#define THROW(m) { printf("ERROR: %s\n", m); BAILOUT() }
70#define THROW_MD5(filename, md5sum, ref) { \
Jonathan Wrighta145af12020-06-11 23:22:17 +010071 fprintf(stderr, "\n%s has an MD5 sum of %s.\n Should be %s.\n", filename, \
72 md5sum, ref); \
Jonathan Wrightdb870df2020-08-05 11:42:22 +010073 BAILOUT() \
Chris Blumecca8c4d2019-03-01 01:09:50 -080074}
hbono@chromium.org98626972011-08-03 03:13:08 +000075
Jonathan Wright6cb95b82020-06-11 16:10:15 +010076static const char *subNameLong[TJ_NUMSAMP] = {
Chris Blumecca8c4d2019-03-01 01:09:50 -080077 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
hbono@chromium.org98626972011-08-03 03:13:08 +000078};
Jonathan Wright6cb95b82020-06-11 16:10:15 +010079static const char *subName[TJ_NUMSAMP] = {
Chris Blumecca8c4d2019-03-01 01:09:50 -080080 "444", "422", "420", "GRAY", "440", "411"
hbono@chromium.org98626972011-08-03 03:13:08 +000081};
82
Jonathan Wrightdb870df2020-08-05 11:42:22 +010083static const char *pixFormatStr[TJ_NUMPF] = {
Chris Blumecca8c4d2019-03-01 01:09:50 -080084 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
85 "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
86};
hbono@chromium.orgc6beb742011-11-29 05:16:26 +000087
Jonathan Wright6cb95b82020-06-11 16:10:15 +010088static const int _3byteFormats[] = { TJPF_RGB, TJPF_BGR };
89static const int _4byteFormats[] = {
Chris Blumecca8c4d2019-03-01 01:09:50 -080090 TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_CMYK
91};
Jonathan Wright6cb95b82020-06-11 16:10:15 +010092static const int _onlyGray[] = { TJPF_GRAY };
93static const int _onlyRGB[] = { TJPF_RGB };
hbono@chromium.org98626972011-08-03 03:13:08 +000094
Jonathan Wright6cb95b82020-06-11 16:10:15 +010095static int doYUV = 0, alloc = 0, pad = 4;
hbono@chromium.org98626972011-08-03 03:13:08 +000096
Jonathan Wright6cb95b82020-06-11 16:10:15 +010097static int exitStatus = 0;
Jonathan Wrightdb870df2020-08-05 11:42:22 +010098#define BAILOUT() { exitStatus = -1; goto bailout; }
hbono@chromium.org98626972011-08-03 03:13:08 +000099
Jonathan Wright85252fa2020-06-19 16:07:07 +0100100static const size_t filePathSize = 1024;
101
hbono@chromium.org98626972011-08-03 03:13:08 +0000102
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100103static void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000104{
Chris Blumecca8c4d2019-03-01 01:09:50 -0800105 int roffset = tjRedOffset[pf];
106 int goffset = tjGreenOffset[pf];
107 int boffset = tjBlueOffset[pf];
108 int ps = tjPixelSize[pf];
109 int index, row, col, halfway = 16;
hbono@chromium.org98626972011-08-03 03:13:08 +0000110
Chris Blumecca8c4d2019-03-01 01:09:50 -0800111 if (pf == TJPF_GRAY) {
112 memset(buf, 0, w * h * ps);
113 for (row = 0; row < h; row++) {
114 for (col = 0; col < w; col++) {
115 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
116 else index = row * w + col;
117 if (((row / 8) + (col / 8)) % 2 == 0)
118 buf[index] = (row < halfway) ? 255 : 0;
119 else buf[index] = (row < halfway) ? 76 : 226;
120 }
121 }
122 } else if (pf == TJPF_CMYK) {
123 memset(buf, 255, w * h * ps);
124 for (row = 0; row < h; row++) {
125 for (col = 0; col < w; col++) {
126 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
127 else index = row * w + col;
128 if (((row / 8) + (col / 8)) % 2 == 0) {
129 if (row >= halfway) buf[index * ps + 3] = 0;
130 } else {
131 buf[index * ps + 2] = 0;
132 if (row < halfway) buf[index * ps + 1] = 0;
133 }
134 }
135 }
136 } else {
137 memset(buf, 0, w * h * ps);
138 for (row = 0; row < h; row++) {
139 for (col = 0; col < w; col++) {
140 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
141 else index = row * w + col;
142 if (((row / 8) + (col / 8)) % 2 == 0) {
143 if (row < halfway) {
144 buf[index * ps + roffset] = 255;
145 buf[index * ps + goffset] = 255;
146 buf[index * ps + boffset] = 255;
147 }
148 } else {
149 buf[index * ps + roffset] = 255;
150 if (row >= halfway) buf[index * ps + goffset] = 255;
151 }
152 }
153 }
154 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000155}
156
157
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100158#define CHECKVAL(v, cv) { \
Chris Blumecca8c4d2019-03-01 01:09:50 -0800159 if (v < cv - 1 || v > cv + 1) { \
Jonathan Wrighta145af12020-06-11 23:22:17 +0100160 fprintf(stderr, "\nComp. %s at %d,%d should be %d, not %d\n", #v, row, \
161 col, cv, v); \
Chris Blumecca8c4d2019-03-01 01:09:50 -0800162 retval = 0; exitStatus = -1; goto bailout; \
163 } \
164}
hbono@chromium.org98626972011-08-03 03:13:08 +0000165
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100166#define CHECKVAL0(v) { \
Chris Blumecca8c4d2019-03-01 01:09:50 -0800167 if (v > 1) { \
Jonathan Wrighta145af12020-06-11 23:22:17 +0100168 fprintf(stderr, "\nComp. %s at %d,%d should be 0, not %d\n", #v, row, \
169 col, v); \
Chris Blumecca8c4d2019-03-01 01:09:50 -0800170 retval = 0; exitStatus = -1; goto bailout; \
171 } \
172}
hbono@chromium.org98626972011-08-03 03:13:08 +0000173
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100174#define CHECKVAL255(v) { \
Chris Blumecca8c4d2019-03-01 01:09:50 -0800175 if (v < 254) { \
Jonathan Wrighta145af12020-06-11 23:22:17 +0100176 fprintf(stderr, "\nComp. %s at %d,%d should be 255, not %d\n", #v, row, \
177 col, v); \
Chris Blumecca8c4d2019-03-01 01:09:50 -0800178 retval = 0; exitStatus = -1; goto bailout; \
179 } \
hbono@chromium.org98626972011-08-03 03:13:08 +0000180}
181
182
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100183static int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
184 tjscalingfactor sf, int flags)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800185{
186 int roffset = tjRedOffset[pf];
187 int goffset = tjGreenOffset[pf];
188 int boffset = tjBlueOffset[pf];
189 int aoffset = tjAlphaOffset[pf];
190 int ps = tjPixelSize[pf];
191 int index, row, col, retval = 1;
192 int halfway = 16 * sf.num / sf.denom;
193 int blocksize = 8 * sf.num / sf.denom;
194
195 if (pf == TJPF_GRAY) roffset = goffset = boffset = 0;
196
197 if (pf == TJPF_CMYK) {
198 for (row = 0; row < h; row++) {
199 for (col = 0; col < w; col++) {
200 unsigned char c, m, y, k;
201
202 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
203 else index = row * w + col;
204 c = buf[index * ps];
205 m = buf[index * ps + 1];
206 y = buf[index * ps + 2];
207 k = buf[index * ps + 3];
208 if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100209 CHECKVAL255(c); CHECKVAL255(m); CHECKVAL255(y);
210 if (row < halfway) CHECKVAL255(k)
211 else CHECKVAL0(k)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800212 } else {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100213 CHECKVAL255(c); CHECKVAL0(y); CHECKVAL255(k);
214 if (row < halfway) CHECKVAL0(m)
215 else CHECKVAL255(m)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800216 }
217 }
218 }
219 return 1;
220 }
221
222 for (row = 0; row < h; row++) {
223 for (col = 0; col < w; col++) {
224 unsigned char r, g, b, a;
225
226 if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
227 else index = row * w + col;
228 r = buf[index * ps + roffset];
229 g = buf[index * ps + goffset];
230 b = buf[index * ps + boffset];
231 a = aoffset >= 0 ? buf[index * ps + aoffset] : 0xFF;
232 if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
233 if (row < halfway) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100234 CHECKVAL255(r); CHECKVAL255(g); CHECKVAL255(b);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800235 } else {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100236 CHECKVAL0(r); CHECKVAL0(g); CHECKVAL0(b);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800237 }
238 } else {
239 if (subsamp == TJSAMP_GRAY) {
240 if (row < halfway) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100241 CHECKVAL(r, 76); CHECKVAL(g, 76); CHECKVAL(b, 76);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800242 } else {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100243 CHECKVAL(r, 226); CHECKVAL(g, 226); CHECKVAL(b, 226);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800244 }
245 } else {
246 if (row < halfway) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100247 CHECKVAL255(r); CHECKVAL0(g); CHECKVAL0(b);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800248 } else {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100249 CHECKVAL255(r); CHECKVAL255(g); CHECKVAL0(b);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800250 }
251 }
252 }
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100253 CHECKVAL255(a);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800254 }
255 }
256
257bailout:
258 if (retval == 0) {
259 for (row = 0; row < h; row++) {
260 for (col = 0; col < w; col++) {
261 if (pf == TJPF_CMYK)
Jonathan Wrighta145af12020-06-11 23:22:17 +0100262 fprintf(stderr, "%.3d/%.3d/%.3d/%.3d ", buf[(row * w + col) * ps],
263 buf[(row * w + col) * ps + 1], buf[(row * w + col) * ps + 2],
264 buf[(row * w + col) * ps + 3]);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800265 else
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100266 fprintf(stderr, "%.3d/%.3d/%.3d ",
267 buf[(row * w + col) * ps + roffset],
Jonathan Wrighta145af12020-06-11 23:22:17 +0100268 buf[(row * w + col) * ps + goffset],
269 buf[(row * w + col) * ps + boffset]);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800270 }
Jonathan Wrighta145af12020-06-11 23:22:17 +0100271 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800272 }
273 }
274 return retval;
275}
276
277
278#define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
hbono@chromium.org98626972011-08-03 03:13:08 +0000279
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100280static int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
281 tjscalingfactor sf)
hbono@chromium.org98626972011-08-03 03:13:08 +0000282{
Chris Blumecca8c4d2019-03-01 01:09:50 -0800283 int row, col;
284 int hsf = tjMCUWidth[subsamp] / 8, vsf = tjMCUHeight[subsamp] / 8;
285 int pw = PAD(w, hsf), ph = PAD(h, vsf);
286 int cw = pw / hsf, ch = ph / vsf;
287 int ypitch = PAD(pw, pad), uvpitch = PAD(cw, pad);
288 int retval = 1;
289 int halfway = 16 * sf.num / sf.denom;
290 int blocksize = 8 * sf.num / sf.denom;
hbono@chromium.org98626972011-08-03 03:13:08 +0000291
Chris Blumecca8c4d2019-03-01 01:09:50 -0800292 for (row = 0; row < ph; row++) {
293 for (col = 0; col < pw; col++) {
294 unsigned char y = buf[ypitch * row + col];
hbono@chromium.org98626972011-08-03 03:13:08 +0000295
Chris Blumecca8c4d2019-03-01 01:09:50 -0800296 if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100297 if (row < halfway) CHECKVAL255(y)
298 else CHECKVAL0(y);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800299 } else {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100300 if (row < halfway) CHECKVAL(y, 76)
301 else CHECKVAL(y, 226);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800302 }
303 }
304 }
305 if (subsamp != TJSAMP_GRAY) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100306 halfway = 16 / vsf * sf.num / sf.denom;
hbono@chromium.org98626972011-08-03 03:13:08 +0000307
Chris Blumecca8c4d2019-03-01 01:09:50 -0800308 for (row = 0; row < ch; row++) {
309 for (col = 0; col < cw; col++) {
310 unsigned char u = buf[ypitch * ph + (uvpitch * row + col)],
311 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
312
313 if (((row * vsf / blocksize) + (col * hsf / blocksize)) % 2 == 0) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100314 CHECKVAL(u, 128); CHECKVAL(v, 128);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800315 } else {
316 if (row < halfway) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100317 CHECKVAL(u, 85); CHECKVAL255(v);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800318 } else {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100319 CHECKVAL0(u); CHECKVAL(v, 149);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800320 }
321 }
322 }
323 }
324 }
325
326bailout:
327 if (retval == 0) {
328 for (row = 0; row < ph; row++) {
329 for (col = 0; col < pw; col++)
Jonathan Wrighta145af12020-06-11 23:22:17 +0100330 fprintf(stderr, "%.3d ", buf[ypitch * row + col]);
331 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800332 }
Jonathan Wrighta145af12020-06-11 23:22:17 +0100333 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800334 for (row = 0; row < ch; row++) {
335 for (col = 0; col < cw; col++)
Jonathan Wrighta145af12020-06-11 23:22:17 +0100336 fprintf(stderr, "%.3d ", buf[ypitch * ph + (uvpitch * row + col)]);
337 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800338 }
Jonathan Wrighta145af12020-06-11 23:22:17 +0100339 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800340 for (row = 0; row < ch; row++) {
341 for (col = 0; col < cw; col++)
Jonathan Wrighta145af12020-06-11 23:22:17 +0100342 fprintf(stderr, "%.3d ",
343 buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]);
344 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800345 }
346 }
347
348 return retval;
hbono@chromium.org98626972011-08-03 03:13:08 +0000349}
350
351
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100352static void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize,
353 char *filename)
hbono@chromium.org98626972011-08-03 03:13:08 +0000354{
Jonathan Wright85252fa2020-06-19 16:07:07 +0100355#if defined(ANDROID) && defined(GTEST)
356 char path[filePathSize];
357 snprintf(path, filePathSize, "/sdcard/%s", filename);
358 FILE *file = fopen(path, "wb");
359#else
Chris Blumecca8c4d2019-03-01 01:09:50 -0800360 FILE *file = fopen(filename, "wb");
Jonathan Wright85252fa2020-06-19 16:07:07 +0100361#endif
Chris Blumecca8c4d2019-03-01 01:09:50 -0800362 if (!file || fwrite(jpegBuf, jpegSize, 1, file) != 1) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100363 fprintf(stderr, "ERROR: Could not write to %s.\n%s\n", filename,
364 strerror(errno));
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100365 BAILOUT()
Chris Blumecca8c4d2019-03-01 01:09:50 -0800366 }
367
368bailout:
369 if (file) fclose(file);
hbono@chromium.org98626972011-08-03 03:13:08 +0000370}
371
372
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100373static void compTest(tjhandle handle, unsigned char **dstBuf,
374 unsigned long *dstSize, int w, int h, int pf,
375 char *basename, int subsamp, int jpegQual, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000376{
Jonathan Wright85252fa2020-06-19 16:07:07 +0100377 char tempStr[filePathSize];
Chris Blumecca8c4d2019-03-01 01:09:50 -0800378 unsigned char *srcBuf = NULL, *yuvBuf = NULL;
379 const char *pfStr = pixFormatStr[pf];
380 const char *buStrLong =
381 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ";
382 const char *buStr = (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD";
hbono@chromium.org98626972011-08-03 03:13:08 +0000383
Chris Blumecca8c4d2019-03-01 01:09:50 -0800384 if ((srcBuf = (unsigned char *)malloc(w * h * tjPixelSize[pf])) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100385 THROW("Memory allocation failure");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800386 initBuf(srcBuf, w, h, pf, flags);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400387
Chris Blumecca8c4d2019-03-01 01:09:50 -0800388 if (*dstBuf && *dstSize > 0) memset(*dstBuf, 0, *dstSize);
hbono@chromium.org98626972011-08-03 03:13:08 +0000389
Chris Blumecca8c4d2019-03-01 01:09:50 -0800390 if (!alloc) flags |= TJFLAG_NOREALLOC;
391 if (doYUV) {
392 unsigned long yuvSize = tjBufSizeYUV2(w, pad, h, subsamp);
393 tjscalingfactor sf = { 1, 1 };
394 tjhandle handle2 = tjInitCompress();
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400395
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100396 if (!handle2) THROW_TJ();
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400397
Chris Blumecca8c4d2019-03-01 01:09:50 -0800398 if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100399 THROW("Memory allocation failure");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800400 memset(yuvBuf, 0, yuvSize);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400401
Jonathan Wrighta145af12020-06-11 23:22:17 +0100402 fprintf(stderr, "%s %s -> YUV %s ... ", pfStr, buStrLong,
403 subNameLong[subsamp]);
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100404 TRY_TJ(tjEncodeYUV3(handle2, srcBuf, w, 0, h, pf, yuvBuf, pad, subsamp,
405 flags));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800406 tjDestroy(handle2);
Jonathan Wrighta145af12020-06-11 23:22:17 +0100407 if (checkBufYUV(yuvBuf, w, h, subsamp, sf)) fprintf(stderr, "Passed.\n");
408 else fprintf(stderr, "FAILED!\n");
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400409
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100410 fprintf(stderr, "YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp],
411 buStrLong, jpegQual);
412 TRY_TJ(tjCompressFromYUV(handle, yuvBuf, w, pad, h, subsamp, dstBuf,
413 dstSize, jpegQual, flags));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800414 } else {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100415 fprintf(stderr, "%s %s -> %s Q%d ... ", pfStr, buStrLong,
416 subNameLong[subsamp], jpegQual);
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100417 TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
418 jpegQual, flags));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800419 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000420
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100421 snprintf(tempStr, filePathSize, "%s_enc_%s_%s_%s_Q%d.jpg", basename, pfStr,
422 buStr, subName[subsamp], jpegQual);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800423 writeJPEG(*dstBuf, *dstSize, tempStr);
Jonathan Wrighta145af12020-06-11 23:22:17 +0100424 fprintf(stderr, "Done.\n Result in %s\n", tempStr);
hbono@chromium.org98626972011-08-03 03:13:08 +0000425
Chris Blumecca8c4d2019-03-01 01:09:50 -0800426bailout:
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100427 free(yuvBuf);
428 free(srcBuf);
hbono@chromium.org98626972011-08-03 03:13:08 +0000429}
430
431
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100432static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
433 unsigned long jpegSize, int w, int h, int pf,
434 char *basename, int subsamp, int flags,
435 tjscalingfactor sf)
hbono@chromium.org98626972011-08-03 03:13:08 +0000436{
Chris Blumecca8c4d2019-03-01 01:09:50 -0800437 unsigned char *dstBuf = NULL, *yuvBuf = NULL;
438 int _hdrw = 0, _hdrh = 0, _hdrsubsamp = -1;
439 int scaledWidth = TJSCALED(w, sf);
440 int scaledHeight = TJSCALED(h, sf);
441 unsigned long dstSize = 0;
hbono@chromium.org98626972011-08-03 03:13:08 +0000442
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100443 TRY_TJ(tjDecompressHeader2(handle, jpegBuf, jpegSize, &_hdrw, &_hdrh,
444 &_hdrsubsamp));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800445 if (_hdrw != w || _hdrh != h || _hdrsubsamp != subsamp)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100446 THROW("Incorrect JPEG header");
hbono@chromium.org98626972011-08-03 03:13:08 +0000447
Chris Blumecca8c4d2019-03-01 01:09:50 -0800448 dstSize = scaledWidth * scaledHeight * tjPixelSize[pf];
449 if ((dstBuf = (unsigned char *)malloc(dstSize)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100450 THROW("Memory allocation failure");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800451 memset(dstBuf, 0, dstSize);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400452
Chris Blumecca8c4d2019-03-01 01:09:50 -0800453 if (doYUV) {
454 unsigned long yuvSize = tjBufSizeYUV2(scaledWidth, pad, scaledHeight,
455 subsamp);
456 tjhandle handle2 = tjInitDecompress();
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400457
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100458 if (!handle2) THROW_TJ();
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400459
Chris Blumecca8c4d2019-03-01 01:09:50 -0800460 if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100461 THROW("Memory allocation failure");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800462 memset(yuvBuf, 0, yuvSize);
Tom Hudson0d47d2d2016-05-04 13:22:56 -0400463
Jonathan Wrighta145af12020-06-11 23:22:17 +0100464 fprintf(stderr, "JPEG -> YUV %s ", subNameLong[subsamp]);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800465 if (sf.num != 1 || sf.denom != 1)
Jonathan Wrighta145af12020-06-11 23:22:17 +0100466 fprintf(stderr, "%d/%d ... ", sf.num, sf.denom);
467 else fprintf(stderr, "... ");
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100468 TRY_TJ(tjDecompressToYUV2(handle, jpegBuf, jpegSize, yuvBuf, scaledWidth,
469 pad, scaledHeight, flags));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800470 if (checkBufYUV(yuvBuf, scaledWidth, scaledHeight, subsamp, sf))
Jonathan Wrighta145af12020-06-11 23:22:17 +0100471 fprintf(stderr, "Passed.\n");
472 else fprintf(stderr, "FAILED!\n");
hbono@chromium.org98626972011-08-03 03:13:08 +0000473
Jonathan Wrighta145af12020-06-11 23:22:17 +0100474 fprintf(stderr, "YUV %s -> %s %s ... ", subNameLong[subsamp],
475 pixFormatStr[pf],
476 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100477 TRY_TJ(tjDecodeYUV(handle2, yuvBuf, pad, subsamp, dstBuf, scaledWidth, 0,
478 scaledHeight, pf, flags));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800479 tjDestroy(handle2);
480 } else {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100481 fprintf(stderr, "JPEG -> %s %s ", pixFormatStr[pf],
482 (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800483 if (sf.num != 1 || sf.denom != 1)
Jonathan Wrighta145af12020-06-11 23:22:17 +0100484 fprintf(stderr, "%d/%d ... ", sf.num, sf.denom);
485 else fprintf(stderr, "... ");
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100486 TRY_TJ(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth, 0,
487 scaledHeight, pf, flags));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800488 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000489
Chris Blumecca8c4d2019-03-01 01:09:50 -0800490 if (checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, flags))
Jonathan Wrighta145af12020-06-11 23:22:17 +0100491 fprintf(stderr, "Passed.");
492 else fprintf(stderr, "FAILED!");
493 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800494
495bailout:
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100496 free(yuvBuf);
497 free(dstBuf);
hbono@chromium.org98626972011-08-03 03:13:08 +0000498}
499
500
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100501static void decompTest(tjhandle handle, unsigned char *jpegBuf,
502 unsigned long jpegSize, int w, int h, int pf,
503 char *basename, int subsamp, int flags)
hbono@chromium.org98626972011-08-03 03:13:08 +0000504{
Chris Blumecca8c4d2019-03-01 01:09:50 -0800505 int i, n = 0;
506 tjscalingfactor *sf = tjGetScalingFactors(&n);
hbono@chromium.org98626972011-08-03 03:13:08 +0000507
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100508 if (!sf || !n) THROW_TJ();
hbono@chromium.org98626972011-08-03 03:13:08 +0000509
Chris Blumecca8c4d2019-03-01 01:09:50 -0800510 for (i = 0; i < n; i++) {
511 if (subsamp == TJSAMP_444 || subsamp == TJSAMP_GRAY ||
512 (subsamp == TJSAMP_411 && sf[i].num == 1 &&
513 (sf[i].denom == 2 || sf[i].denom == 1)) ||
514 (subsamp != TJSAMP_411 && sf[i].num == 1 &&
515 (sf[i].denom == 4 || sf[i].denom == 2 || sf[i].denom == 1)))
516 _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
517 flags, sf[i]);
518 }
519
520bailout:
521 return;
hbono@chromium.org98626972011-08-03 03:13:08 +0000522}
523
524
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100525static void doTest(int w, int h, const int *formats, int nformats, int subsamp,
526 char *basename)
hbono@chromium.org98626972011-08-03 03:13:08 +0000527{
Chris Blumecca8c4d2019-03-01 01:09:50 -0800528 tjhandle chandle = NULL, dhandle = NULL;
529 unsigned char *dstBuf = NULL;
530 unsigned long size = 0;
531 int pfi, pf, i;
hbono@chromium.org98626972011-08-03 03:13:08 +0000532
Chris Blumecca8c4d2019-03-01 01:09:50 -0800533 if (!alloc)
534 size = tjBufSize(w, h, subsamp);
535 if (size != 0)
536 if ((dstBuf = (unsigned char *)tjAlloc(size)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100537 THROW("Memory allocation failure.");
hbono@chromium.org98626972011-08-03 03:13:08 +0000538
Chris Blumecca8c4d2019-03-01 01:09:50 -0800539 if ((chandle = tjInitCompress()) == NULL ||
540 (dhandle = tjInitDecompress()) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100541 THROW_TJ();
hbono@chromium.org98626972011-08-03 03:13:08 +0000542
Chris Blumecca8c4d2019-03-01 01:09:50 -0800543 for (pfi = 0; pfi < nformats; pfi++) {
544 for (i = 0; i < 2; i++) {
545 int flags = 0;
hbono@chromium.org98626972011-08-03 03:13:08 +0000546
Chris Blumecca8c4d2019-03-01 01:09:50 -0800547 if (subsamp == TJSAMP_422 || subsamp == TJSAMP_420 ||
548 subsamp == TJSAMP_440 || subsamp == TJSAMP_411)
549 flags |= TJFLAG_FASTUPSAMPLE;
550 if (i == 1) flags |= TJFLAG_BOTTOMUP;
551 pf = formats[pfi];
552 compTest(chandle, &dstBuf, &size, w, h, pf, basename, subsamp, 100,
553 flags);
554 decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp, flags);
555 if (pf >= TJPF_RGBX && pf <= TJPF_XRGB) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100556 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800557 decompTest(dhandle, dstBuf, size, w, h, pf + (TJPF_RGBA - TJPF_RGBX),
558 basename, subsamp, flags);
559 }
Jonathan Wrighta145af12020-06-11 23:22:17 +0100560 fprintf(stderr, "\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800561 }
562 }
Jonathan Wrighta145af12020-06-11 23:22:17 +0100563 fprintf(stderr, "--------------------\n\n");
hbono@chromium.org98626972011-08-03 03:13:08 +0000564
Chris Blumecca8c4d2019-03-01 01:09:50 -0800565bailout:
566 if (chandle) tjDestroy(chandle);
567 if (dhandle) tjDestroy(dhandle);
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100568 tjFree(dstBuf);
hbono@chromium.org98626972011-08-03 03:13:08 +0000569}
570
571
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100572#if SIZEOF_SIZE_T == 8
573#define CHECKSIZE(function) { \
574 if ((unsigned long long)size < (unsigned long long)0xFFFFFFFF) \
575 THROW(#function " overflow"); \
576}
577#else
578#define CHECKSIZE(function) { \
579 if (size != (unsigned long)(-1) || \
580 !strcmp(tjGetErrorStr2(NULL), "No error")) \
581 THROW(#function " overflow"); \
582}
583#endif
584
585#ifndef GTEST
586static void overflowTest(void)
587{
588 /* Ensure that the various buffer size functions don't overflow */
589 unsigned long size;
590
591 size = tjBufSize(26755, 26755, TJSAMP_444);
592 CHECKSIZE(tjBufSize());
593 size = TJBUFSIZE(26755, 26755);
594 CHECKSIZE(TJBUFSIZE());
595 size = tjBufSizeYUV2(37838, 1, 37838, TJSAMP_444);
596 CHECKSIZE(tjBufSizeYUV2());
597 size = TJBUFSIZEYUV(37838, 37838, TJSAMP_444);
598 CHECKSIZE(TJBUFSIZEYUV());
599 size = tjBufSizeYUV(37838, 37838, TJSAMP_444);
600 CHECKSIZE(tjBufSizeYUV());
601 size = tjPlaneSizeYUV(0, 65536, 0, 65536, TJSAMP_444);
602 CHECKSIZE(tjPlaneSizeYUV());
603
604bailout:
605 return;
606}
607#endif
608
609
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100610static void bufSizeTest(void)
hbono@chromium.org98626972011-08-03 03:13:08 +0000611{
Chris Blumecca8c4d2019-03-01 01:09:50 -0800612 int w, h, i, subsamp;
613 unsigned char *srcBuf = NULL, *dstBuf = NULL;
614 tjhandle handle = NULL;
615 unsigned long dstSize = 0;
hbono@chromium.org98626972011-08-03 03:13:08 +0000616
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100617 if ((handle = tjInitCompress()) == NULL) THROW_TJ();
hbono@chromium.org98626972011-08-03 03:13:08 +0000618
Jonathan Wrighta145af12020-06-11 23:22:17 +0100619 fprintf(stderr, "Buffer size regression test\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800620 for (subsamp = 0; subsamp < TJ_NUMSAMP; subsamp++) {
621 for (w = 1; w < 48; w++) {
622 int maxh = (w == 1) ? 2048 : 48;
hbono@chromium.org98626972011-08-03 03:13:08 +0000623
Chris Blumecca8c4d2019-03-01 01:09:50 -0800624 for (h = 1; h < maxh; h++) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100625 if (h % 100 == 0)
626 fprintf(stderr, "%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800627 if ((srcBuf = (unsigned char *)malloc(w * h * 4)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100628 THROW("Memory allocation failure");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800629 if (!alloc || doYUV) {
630 if (doYUV) dstSize = tjBufSizeYUV2(w, pad, h, subsamp);
631 else dstSize = tjBufSize(w, h, subsamp);
632 if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100633 THROW("Memory allocation failure");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800634 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000635
Chris Blumecca8c4d2019-03-01 01:09:50 -0800636 for (i = 0; i < w * h * 4; i++) {
637 if (random() < RAND_MAX / 2) srcBuf[i] = 0;
638 else srcBuf[i] = 255;
639 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000640
Chris Blumecca8c4d2019-03-01 01:09:50 -0800641 if (doYUV) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100642 TRY_TJ(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf, pad,
643 subsamp, 0));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800644 } else {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100645 TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
646 &dstSize, subsamp, 100,
647 alloc ? 0 : TJFLAG_NOREALLOC));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800648 }
649 free(srcBuf); srcBuf = NULL;
650 if (!alloc || doYUV) {
651 tjFree(dstBuf); dstBuf = NULL;
652 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000653
Chris Blumecca8c4d2019-03-01 01:09:50 -0800654 if ((srcBuf = (unsigned char *)malloc(h * w * 4)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100655 THROW("Memory allocation failure");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800656 if (!alloc || doYUV) {
657 if (doYUV) dstSize = tjBufSizeYUV2(h, pad, w, subsamp);
658 else dstSize = tjBufSize(h, w, subsamp);
659 if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100660 THROW("Memory allocation failure");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800661 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000662
Chris Blumecca8c4d2019-03-01 01:09:50 -0800663 for (i = 0; i < h * w * 4; i++) {
664 if (random() < RAND_MAX / 2) srcBuf[i] = 0;
665 else srcBuf[i] = 255;
666 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000667
Chris Blumecca8c4d2019-03-01 01:09:50 -0800668 if (doYUV) {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100669 TRY_TJ(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf, pad,
670 subsamp, 0));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800671 } else {
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100672 TRY_TJ(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
673 &dstSize, subsamp, 100,
674 alloc ? 0 : TJFLAG_NOREALLOC));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800675 }
676 free(srcBuf); srcBuf = NULL;
677 if (!alloc || doYUV) {
678 tjFree(dstBuf); dstBuf = NULL;
679 }
680 }
681 }
682 }
Jonathan Wrighta145af12020-06-11 23:22:17 +0100683 fprintf(stderr, "Done. \n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800684
685bailout:
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100686 free(srcBuf);
687 tjFree(dstBuf);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800688 if (handle) tjDestroy(handle);
689}
690
691
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100692static void initBitmap(unsigned char *buf, int width, int pitch, int height,
693 int pf, int flags)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800694{
695 int roffset = tjRedOffset[pf];
696 int goffset = tjGreenOffset[pf];
697 int boffset = tjBlueOffset[pf];
698 int ps = tjPixelSize[pf];
699 int i, j;
700
701 for (j = 0; j < height; j++) {
702 int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
703
704 for (i = 0; i < width; i++) {
705 unsigned char r = (i * 256 / width) % 256;
706 unsigned char g = (j * 256 / height) % 256;
707 unsigned char b = (j * 256 / height + i * 256 / width) % 256;
708
709 memset(&buf[row * pitch + i * ps], 0, ps);
710 if (pf == TJPF_GRAY) buf[row * pitch + i * ps] = b;
711 else if (pf == TJPF_CMYK)
712 rgb_to_cmyk(r, g, b, &buf[row * pitch + i * ps + 0],
713 &buf[row * pitch + i * ps + 1],
714 &buf[row * pitch + i * ps + 2],
715 &buf[row * pitch + i * ps + 3]);
716 else {
717 buf[row * pitch + i * ps + roffset] = r;
718 buf[row * pitch + i * ps + goffset] = g;
719 buf[row * pitch + i * ps + boffset] = b;
720 }
721 }
722 }
723}
724
725
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100726static int cmpBitmap(unsigned char *buf, int width, int pitch, int height,
727 int pf, int flags, int gray2rgb)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800728{
729 int roffset = tjRedOffset[pf];
730 int goffset = tjGreenOffset[pf];
731 int boffset = tjBlueOffset[pf];
732 int aoffset = tjAlphaOffset[pf];
733 int ps = tjPixelSize[pf];
734 int i, j;
735
736 for (j = 0; j < height; j++) {
737 int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
738
739 for (i = 0; i < width; i++) {
740 unsigned char r = (i * 256 / width) % 256;
741 unsigned char g = (j * 256 / height) % 256;
742 unsigned char b = (j * 256 / height + i * 256 / width) % 256;
743
744 if (pf == TJPF_GRAY) {
745 if (buf[row * pitch + i * ps] != b)
746 return 0;
747 } else if (pf == TJPF_CMYK) {
748 unsigned char rf, gf, bf;
749
750 cmyk_to_rgb(buf[row * pitch + i * ps + 0],
751 buf[row * pitch + i * ps + 1],
752 buf[row * pitch + i * ps + 2],
753 buf[row * pitch + i * ps + 3], &rf, &gf, &bf);
754 if (gray2rgb) {
755 if (rf != b || gf != b || bf != b)
756 return 0;
757 } else if (rf != r || gf != g || bf != b) return 0;
758 } else {
759 if (gray2rgb) {
760 if (buf[row * pitch + i * ps + roffset] != b ||
761 buf[row * pitch + i * ps + goffset] != b ||
762 buf[row * pitch + i * ps + boffset] != b)
763 return 0;
764 } else if (buf[row * pitch + i * ps + roffset] != r ||
765 buf[row * pitch + i * ps + goffset] != g ||
766 buf[row * pitch + i * ps + boffset] != b)
767 return 0;
768 if (aoffset >= 0 && buf[row * pitch + i * ps + aoffset] != 0xFF)
769 return 0;
770 }
771 }
772 }
773 return 1;
774}
775
776
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100777static int doBmpTest(const char *ext, int width, int align, int height, int pf,
778 int flags)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800779{
Jonathan Wright85252fa2020-06-19 16:07:07 +0100780 const size_t filenameSize = 80;
781 char filename[filenameSize], *md5sum, md5buf[65];
Chris Blumecca8c4d2019-03-01 01:09:50 -0800782 int ps = tjPixelSize[pf], pitch = PAD(width * ps, align), loadWidth = 0,
783 loadHeight = 0, retval = 0, pixelFormat = pf;
784 unsigned char *buf = NULL;
785 char *md5ref;
786
787 if (pf == TJPF_GRAY) {
788 md5ref = !strcasecmp(ext, "ppm") ? "112c682e82ce5de1cca089e20d60000b" :
789 "51976530acf75f02beddf5d21149101d";
790 } else {
791 md5ref = !strcasecmp(ext, "ppm") ? "c0c9f772b464d1896326883a5c79c545" :
792 "6d659071b9bfcdee2def22cb58ddadca";
793 }
794
795 if ((buf = (unsigned char *)tjAlloc(pitch * height)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100796 THROW("Could not allocate memory");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800797 initBitmap(buf, width, pitch, height, pf, flags);
798
Jonathan Wright85252fa2020-06-19 16:07:07 +0100799#if defined(ANDROID) && defined(GTEST)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100800 snprintf(filename, filenameSize, "/sdcard/test_bmp_%s_%d_%s.%s",
801 pixFormatStr[pf], align, (flags & TJFLAG_BOTTOMUP) ? "bu" : "td",
802 ext);
Jonathan Wright85252fa2020-06-19 16:07:07 +0100803#else
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100804 snprintf(filename, filenameSize, "test_bmp_%s_%d_%s.%s", pixFormatStr[pf],
805 align, (flags & TJFLAG_BOTTOMUP) ? "bu" : "td", ext);
Jonathan Wright85252fa2020-06-19 16:07:07 +0100806#endif
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100807 TRY_TJ(tjSaveImage(filename, buf, width, pitch, height, pf, flags));
Chris Blumecca8c4d2019-03-01 01:09:50 -0800808 md5sum = MD5File(filename, md5buf);
809 if (strcasecmp(md5sum, md5ref))
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100810 THROW_MD5(filename, md5sum, md5ref);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800811
812 tjFree(buf); buf = NULL;
813 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
814 flags)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100815 THROW_TJ();
Chris Blumecca8c4d2019-03-01 01:09:50 -0800816 if (width != loadWidth || height != loadHeight) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100817 fprintf(stderr, "\n Image dimensions of %s are bogus\n", filename);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800818 retval = -1; goto bailout;
819 }
820 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 0)) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100821 fprintf(stderr, "\n Pixel data in %s is bogus\n", filename);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800822 retval = -1; goto bailout;
823 }
824 if (pf == TJPF_GRAY) {
825 tjFree(buf); buf = NULL;
826 pf = TJPF_XBGR;
827 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
828 flags)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100829 THROW_TJ();
Chris Blumecca8c4d2019-03-01 01:09:50 -0800830 pitch = PAD(width * tjPixelSize[pf], align);
831 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 1)) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100832 fprintf(stderr, "\n Converting %s to RGB failed\n", filename);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800833 retval = -1; goto bailout;
834 }
835
836 tjFree(buf); buf = NULL;
837 pf = TJPF_CMYK;
838 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
839 flags)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100840 THROW_TJ();
Chris Blumecca8c4d2019-03-01 01:09:50 -0800841 pitch = PAD(width * tjPixelSize[pf], align);
842 if (!cmpBitmap(buf, width, pitch, height, pf, flags, 1)) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100843 fprintf(stderr, "\n Converting %s to CMYK failed\n", filename);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800844 retval = -1; goto bailout;
845 }
846 }
847 /* Verify that tjLoadImage() returns the proper "preferred" pixel format for
848 the file type. */
849 tjFree(buf); buf = NULL;
850 pf = pixelFormat;
851 pixelFormat = TJPF_UNKNOWN;
852 if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight,
853 &pixelFormat, flags)) == NULL)
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100854 THROW_TJ();
Chris Blumecca8c4d2019-03-01 01:09:50 -0800855 if ((pf == TJPF_GRAY && pixelFormat != TJPF_GRAY) ||
856 (pf != TJPF_GRAY && !strcasecmp(ext, "bmp") &&
857 pixelFormat != TJPF_BGR) ||
858 (pf != TJPF_GRAY && !strcasecmp(ext, "ppm") &&
859 pixelFormat != TJPF_RGB)) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100860 fprintf(stderr,
861 "\n tjLoadImage() returned unexpected pixel format: %s\n",
862 pixFormatStr[pixelFormat]);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800863 retval = -1;
864 }
865 unlink(filename);
866
867bailout:
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100868 tjFree(buf);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800869 if (exitStatus < 0) return exitStatus;
870 return retval;
871}
872
873
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100874static int bmpTest(void)
Chris Blumecca8c4d2019-03-01 01:09:50 -0800875{
876 int align, width = 35, height = 39, format;
877
878 for (align = 1; align <= 8; align *= 2) {
879 for (format = 0; format < TJ_NUMPF; format++) {
Jonathan Wrighta145af12020-06-11 23:22:17 +0100880 fprintf(stderr, "%s Top-Down BMP (row alignment = %d bytes) ... ",
881 pixFormatStr[format], align);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800882 if (doBmpTest("bmp", width, align, height, format, 0) == -1)
883 return -1;
Jonathan Wrighta145af12020-06-11 23:22:17 +0100884 fprintf(stderr, "OK.\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800885
Jonathan Wrighta145af12020-06-11 23:22:17 +0100886 fprintf(stderr, "%s Top-Down PPM (row alignment = %d bytes) ... ",
887 pixFormatStr[format], align);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800888 if (doBmpTest("ppm", width, align, height, format,
889 TJFLAG_BOTTOMUP) == -1)
890 return -1;
Jonathan Wrighta145af12020-06-11 23:22:17 +0100891 fprintf(stderr, "OK.\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800892
Jonathan Wrighta145af12020-06-11 23:22:17 +0100893 fprintf(stderr, "%s Bottom-Up BMP (row alignment = %d bytes) ... ",
894 pixFormatStr[format], align);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800895 if (doBmpTest("bmp", width, align, height, format, 0) == -1)
896 return -1;
Jonathan Wrighta145af12020-06-11 23:22:17 +0100897 fprintf(stderr, "OK.\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800898
Jonathan Wrighta145af12020-06-11 23:22:17 +0100899 fprintf(stderr, "%s Bottom-Up PPM (row alignment = %d bytes) ... ",
900 pixFormatStr[format], align);
Chris Blumecca8c4d2019-03-01 01:09:50 -0800901 if (doBmpTest("ppm", width, align, height, format,
902 TJFLAG_BOTTOMUP) == -1)
903 return -1;
Jonathan Wrighta145af12020-06-11 23:22:17 +0100904 fprintf(stderr, "OK.\n");
Chris Blumecca8c4d2019-03-01 01:09:50 -0800905 }
906 }
907
908 return 0;
hbono@chromium.org98626972011-08-03 03:13:08 +0000909}
910
Jonathan Wrightdb870df2020-08-05 11:42:22 +0100911
Jonathan Wright6cb95b82020-06-11 16:10:15 +0100912#ifdef GTEST
913static void initTJUnitTest(int yuv, int noyuvpad, int autoalloc)
914{
915 doYUV = yuv ? 1 : 0;
916 pad = noyuvpad ? 1 : 4;
917 alloc = autoalloc ? 1 : 0;
918
919 exitStatus = 0;
920}
921
922
923int testBmp(int yuv, int noyuvpad, int autoalloc)
924{
925 initTJUnitTest(yuv, noyuvpad, autoalloc);
926
927 return bmpTest();
928}
929
930
931int testThreeByte444(int yuv, int noyuvpad, int autoalloc)
932{
933 initTJUnitTest(yuv, noyuvpad, autoalloc);
934
935 doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
936 return exitStatus;
937}
938
939
940int testFourByte444(int yuv, int noyuvpad, int autoalloc)
941{
942 initTJUnitTest(yuv, noyuvpad, autoalloc);
943
944 int num4bf = doYUV ? 4 : 5;
945 doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
946 return exitStatus;
947}
948
949
950int testThreeByte422(int yuv, int noyuvpad, int autoalloc)
951{
952 initTJUnitTest(yuv, noyuvpad, autoalloc);
953
954 doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
955 return exitStatus;
956}
957
958
959int testFourByte422(int yuv, int noyuvpad, int autoalloc)
960{
961 initTJUnitTest(yuv, noyuvpad, autoalloc);
962
963 int num4bf = doYUV ? 4 : 5;
964 doTest(35, 39, _4byteFormats, num4bf, TJSAMP_422, "test");
965 return exitStatus;
966}
967
968
969int testThreeByte420(int yuv, int noyuvpad, int autoalloc)
970{
971 initTJUnitTest(yuv, noyuvpad, autoalloc);
972
973 doTest(39, 41, _3byteFormats, 2, TJSAMP_420, "test");
974 return exitStatus;
975}
976
977
978int testFourByte420(int yuv, int noyuvpad, int autoalloc)
979{
980 initTJUnitTest(yuv, noyuvpad, autoalloc);
981
982 int num4bf = doYUV ? 4 : 5;
983 doTest(41, 35, _4byteFormats, num4bf, TJSAMP_420, "test");
984 return exitStatus;
985}
986
987
988int testThreeByte440(int yuv, int noyuvpad, int autoalloc)
989{
990 initTJUnitTest(yuv, noyuvpad, autoalloc);
991
992 doTest(35, 39, _3byteFormats, 2, TJSAMP_440, "test");
993 return exitStatus;
994}
995
996
997int testFourByte440(int yuv, int noyuvpad, int autoalloc)
998{
999 initTJUnitTest(yuv, noyuvpad, autoalloc);
1000
1001 int num4bf = doYUV ? 4 : 5;
1002 doTest(39, 41, _4byteFormats, num4bf, TJSAMP_440, "test");
1003 return exitStatus;
1004}
1005
1006
1007int testThreeByte411(int yuv, int noyuvpad, int autoalloc)
1008{
1009 initTJUnitTest(yuv, noyuvpad, autoalloc);
1010
1011 doTest(41, 35, _3byteFormats, 2, TJSAMP_411, "test");
1012 return exitStatus;
1013}
1014
1015
1016int testFourByte411(int yuv, int noyuvpad, int autoalloc)
1017{
1018 initTJUnitTest(yuv, noyuvpad, autoalloc);
1019
1020 int num4bf = doYUV ? 4 : 5;
1021 doTest(35, 39, _4byteFormats, num4bf, TJSAMP_411, "test");
1022 return exitStatus;
1023}
1024
1025
1026int testOnlyGray(int yuv, int noyuvpad, int autoalloc)
1027{
1028 initTJUnitTest(yuv, noyuvpad, autoalloc);
1029
1030 doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
1031 return exitStatus;
1032}
1033
1034
1035int testThreeByteGray(int yuv, int noyuvpad, int autoalloc)
1036{
1037 initTJUnitTest(yuv, noyuvpad, autoalloc);
1038
1039 doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
1040 return exitStatus;
1041}
1042
1043
1044int testFourByteGray(int yuv, int noyuvpad, int autoalloc)
1045{
1046 initTJUnitTest(yuv, noyuvpad, autoalloc);
1047
1048 doTest(35, 39, _4byteFormats, 4, TJSAMP_GRAY, "test");
1049 return exitStatus;
1050}
1051
1052
1053int testBufSize(int yuv, int noyuvpad, int autoalloc)
1054{
1055 initTJUnitTest(yuv, noyuvpad, autoalloc);
1056
1057 bufSizeTest();
1058 return exitStatus;
1059}
1060
1061
1062int testYUVOnlyRGB444(int noyuvpad, int autoalloc)
1063{
1064 initTJUnitTest(1, noyuvpad, autoalloc);
1065
1066 doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
1067 return exitStatus;
1068}
1069
1070
1071int testYUVOnlyRGB422(int noyuvpad, int autoalloc)
1072{
1073 initTJUnitTest(1, noyuvpad, autoalloc);
1074
1075 doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
1076 return exitStatus;
1077}
1078
1079
1080int testYUVOnlyRGB420(int noyuvpad, int autoalloc)
1081{
1082 initTJUnitTest(1, noyuvpad, autoalloc);
1083
1084 doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
1085 return exitStatus;
1086}
1087
1088
1089int testYUVOnlyRGB440(int noyuvpad, int autoalloc)
1090{
1091 initTJUnitTest(1, noyuvpad, autoalloc);
1092
1093 doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
1094 return exitStatus;
1095}
1096
1097
1098int testYUVOnlyRGB411(int noyuvpad, int autoalloc)
1099{
1100 initTJUnitTest(1, noyuvpad, autoalloc);
1101
1102 doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
1103 return exitStatus;
1104}
1105
1106
1107int testYUVOnlyRGBGray(int noyuvpad, int autoalloc)
1108{
1109 initTJUnitTest(1, noyuvpad, autoalloc);
1110
1111 doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
1112 return exitStatus;
1113}
1114
1115
1116int testYUVOnlyGrayGray(int noyuvpad, int autoalloc)
1117{
1118 initTJUnitTest(1, noyuvpad, autoalloc);
1119
1120 doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");
1121 return exitStatus;
1122}
1123
1124#else
hbono@chromium.org98626972011-08-03 03:13:08 +00001125
1126int main(int argc, char *argv[])
1127{
Chris Blumecca8c4d2019-03-01 01:09:50 -08001128 int i, num4bf = 5;
hbono@chromium.org98626972011-08-03 03:13:08 +00001129
Chris Blumecca8c4d2019-03-01 01:09:50 -08001130#ifdef _WIN32
1131 srand((unsigned int)time(NULL));
1132#endif
1133 if (argc > 1) {
1134 for (i = 1; i < argc; i++) {
1135 if (!strcasecmp(argv[i], "-yuv")) doYUV = 1;
1136 else if (!strcasecmp(argv[i], "-noyuvpad")) pad = 1;
1137 else if (!strcasecmp(argv[i], "-alloc")) alloc = 1;
1138 else if (!strcasecmp(argv[i], "-bmp")) return bmpTest();
1139 else usage(argv[0]);
1140 }
1141 }
1142 if (alloc) printf("Testing automatic buffer allocation\n");
1143 if (doYUV) num4bf = 4;
Jonathan Wrightdb870df2020-08-05 11:42:22 +01001144 overflowTest();
Chris Blumecca8c4d2019-03-01 01:09:50 -08001145 doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
1146 doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
1147 doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
1148 doTest(35, 39, _4byteFormats, num4bf, TJSAMP_422, "test");
1149 doTest(39, 41, _3byteFormats, 2, TJSAMP_420, "test");
1150 doTest(41, 35, _4byteFormats, num4bf, TJSAMP_420, "test");
1151 doTest(35, 39, _3byteFormats, 2, TJSAMP_440, "test");
1152 doTest(39, 41, _4byteFormats, num4bf, TJSAMP_440, "test");
1153 doTest(41, 35, _3byteFormats, 2, TJSAMP_411, "test");
1154 doTest(35, 39, _4byteFormats, num4bf, TJSAMP_411, "test");
1155 doTest(39, 41, _onlyGray, 1, TJSAMP_GRAY, "test");
1156 doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
1157 doTest(35, 39, _4byteFormats, 4, TJSAMP_GRAY, "test");
1158 bufSizeTest();
1159 if (doYUV) {
1160 printf("\n--------------------\n\n");
1161 doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
1162 doTest(48, 48, _onlyRGB, 1, TJSAMP_422, "test_yuv0");
1163 doTest(48, 48, _onlyRGB, 1, TJSAMP_420, "test_yuv0");
1164 doTest(48, 48, _onlyRGB, 1, TJSAMP_440, "test_yuv0");
1165 doTest(48, 48, _onlyRGB, 1, TJSAMP_411, "test_yuv0");
1166 doTest(48, 48, _onlyRGB, 1, TJSAMP_GRAY, "test_yuv0");
1167 doTest(48, 48, _onlyGray, 1, TJSAMP_GRAY, "test_yuv0");
1168 }
1169
1170 return exitStatus;
hbono@chromium.org98626972011-08-03 03:13:08 +00001171}
Jonathan Wright6cb95b82020-06-11 16:10:15 +01001172#endif