1 /* $Id: raw_decode.c,v 1.7 2015-08-16 20:08:21 bfriesen Exp $ */
2 
3 /*
4  * Copyright (c) 2012, Frank Warmerdam <warmerdam@pobox.com>
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and
7  * its documentation for any purpose is hereby granted without fee, provided
8  * that (i) the above copyright notices and this permission notice appear in
9  * all copies of the software and related documentation, and (ii) the names of
10  * Sam Leffler and Silicon Graphics may not be used in any advertising or
11  * publicity relating to the software without the specific, prior written
12  * permission of Sam Leffler and Silicon Graphics.
13  *
14  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
16  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
17  *
18  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
19  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
20  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
22  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23  * OF THIS SOFTWARE.
24  */
25 
26 /*
27  * TIFF Library
28  *
29  * The objective of this test suite is to test the JPEGRawDecode()
30  * interface via TIFReadEncodedTile().  This function with YCbCr subsampling
31  * is a frequent source of bugs.
32  */
33 
34 #include "tif_config.h"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 
43 #include "tiffio.h"
44 
45 /*
46   Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is
47   not defined.  Unfortunately, the MinGW and Borland compilers include
48   a typedef for INT32, which causes a conflict.  MSVC does not include
49   a conficting typedef given the headers which are included.
50 */
51 #if defined(__BORLANDC__) || defined(__MINGW32__)
52 # define XMD_H 1
53 #endif
54 
55 /*
56    The windows RPCNDR.H file defines boolean, but defines it with the
57    unsigned char size.  You should compile JPEG library using appropriate
58    definitions in jconfig.h header, but many users compile library in wrong
59    way. That causes errors of the following type:
60 
61    "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432,
62    caller expects 464"
63 
64    For such users we wil fix the problem here. See install.doc file from
65    the JPEG library distribution for details.
66 */
67 
68 /* Define "boolean" as unsigned char, not int, per Windows custom. */
69 #if defined(__WIN32__) && !defined(__MINGW32__)
70 # ifndef __RPCNDR_H__            /* don't conflict if rpcndr.h already read */
71    typedef unsigned char boolean;
72 # endif
73 # define HAVE_BOOLEAN            /* prevent jmorecfg.h from redefining it */
74 #endif
75 #include "jpeglib.h" /* Needed for JPEG_LIB_VERSION */
76 
77 static unsigned char cluster_0[] = { 0, 0, 2, 0, 138, 139 };
78 static unsigned char cluster_64[] = { 0, 0, 9, 6, 134, 119 };
79 static unsigned char cluster_128[] = { 44, 40, 63, 59, 230, 95 };
80 
check_cluster(int cluster,unsigned char * buffer,unsigned char * expected_cluster)81 static int check_cluster( int cluster, unsigned char *buffer, unsigned char *expected_cluster ) {
82 	unsigned char *target = buffer + cluster*6;
83 
84 	if (memcmp(target, expected_cluster, 6) == 0) {
85 		return 0;
86 	}
87 
88 	fprintf( stderr, "Cluster %d did not match expected results.\n", cluster );
89 	fprintf( stderr,
90 		 "Expect: %3d %3d   %3d   %3d\n"
91 		 "        %3d %3d\n",
92 		 expected_cluster[0], expected_cluster[1],
93 		 expected_cluster[4], expected_cluster[5],
94 		 expected_cluster[2], expected_cluster[3] );
95 	fprintf( stderr,
96 		 "   Got: %3d %3d   %3d   %3d\n"
97 		 "        %3d %3d\n",
98 		 target[0], target[1],
99 		 target[4], target[5],
100 		 target[2], target[3] );
101 	return 1;
102 }
103 
check_rgb_pixel(int pixel,int min_red,int max_red,int min_green,int max_green,int min_blue,int max_blue,unsigned char * buffer)104 static int check_rgb_pixel( int pixel,
105 			    int min_red, int max_red,
106 			    int min_green, int max_green,
107 			    int min_blue, int max_blue,
108 			    unsigned char *buffer ) {
109 	unsigned char *rgb = buffer + 3 * pixel;
110 
111 	if( rgb[0] >= min_red && rgb[0] <= max_red &&
112 	    rgb[1] >= min_green && rgb[1] <= max_green &&
113 	    rgb[2] >= min_blue && rgb[2] <= max_blue ) {
114 		return 0;
115 	}
116 
117 	fprintf( stderr, "Pixel %d did not match expected results.\n", pixel );
118 	fprintf( stderr, "Got R=%d (expected %d..%d), G=%d (expected %d..%d), B=%d (expected %d..%d)\n",
119 		 rgb[0], min_red, max_red,
120 		 rgb[1], min_green, max_green,
121 		 rgb[2], min_blue, max_blue );
122 	return 1;
123 }
124 
check_rgba_pixel(int pixel,int min_red,int max_red,int min_green,int max_green,int min_blue,int max_blue,int min_alpha,int max_alpha,uint32 * buffer)125 static int check_rgba_pixel( int pixel,
126 			     int min_red, int max_red,
127 			     int min_green, int max_green,
128 			     int min_blue, int max_blue,
129 			     int min_alpha, int max_alpha,
130 			     uint32 *buffer ) {
131 	/* RGBA images are upside down - adjust for normal ordering */
132 	int adjusted_pixel = pixel % 128 + (127 - (pixel/128)) * 128;
133 	uint32 rgba = buffer[adjusted_pixel];
134 
135 	if( TIFFGetR(rgba) >= (uint32) min_red &&
136 	    TIFFGetR(rgba) <= (uint32) max_red &&
137 	    TIFFGetG(rgba) >= (uint32) min_green &&
138 	    TIFFGetG(rgba) <= (uint32) max_green &&
139 	    TIFFGetB(rgba) >= (uint32) min_blue &&
140 	    TIFFGetB(rgba) <= (uint32) max_blue &&
141 	    TIFFGetA(rgba) >= (uint32) min_alpha &&
142 	    TIFFGetA(rgba) <= (uint32) max_alpha ) {
143 		return 0;
144 	}
145 
146 	fprintf( stderr, "Pixel %d did not match expected results.\n", pixel );
147 	fprintf( stderr, "Got R=%d (expected %d..%d), G=%d (expected %d..%d), B=%d (expected %d..%d), A=%d (expected %d..%d)\n",
148 		 TIFFGetR(rgba), min_red, max_red,
149 		 TIFFGetG(rgba), min_green, max_green,
150 		 TIFFGetB(rgba), min_blue, max_blue,
151 		 TIFFGetA(rgba), min_alpha, max_alpha );
152 	return 1;
153 }
154 
155 int
main(int argc,char ** argv)156 main(int argc, char **argv)
157 {
158 	TIFF		*tif;
159 	static const char *srcfilerel = "images/quad-tile.jpg.tiff";
160 	char *srcdir = NULL;
161 	char srcfile[1024];
162 	unsigned short h, v;
163 	int status;
164 	unsigned char *buffer;
165 	uint32 *rgba_buffer;
166 	tsize_t sz, szout;
167 	unsigned int pixel_status = 0;
168 
169         (void) argc;
170         (void) argv;
171 
172 	if ((srcdir = getenv("srcdir")) == NULL) {
173 		srcdir = ".";
174 	}
175 	if ((strlen(srcdir) + 1 + strlen(srcfilerel)) >= sizeof(srcfile)) {
176 		fprintf( stderr, "srcdir too long %s\n", srcdir);
177 		exit( 1 );
178 	}
179 	strcpy(srcfile,srcdir);
180 	strcat(srcfile,"/");
181 	strcat(srcfile,srcfilerel);
182 
183 	tif = TIFFOpen(srcfile,"r");
184 	if ( tif == NULL ) {
185 		fprintf( stderr, "Could not open %s\n", srcfile);
186 		exit( 1 );
187 	}
188 
189 	status = TIFFGetField(tif,TIFFTAG_YCBCRSUBSAMPLING, &h, &v);
190 	if ( status == 0 || h != 2 || v != 2) {
191 		fprintf( stderr, "Could not retrieve subsampling tag.\n" );
192 		exit(1);
193 	}
194 
195 	/*
196 	 * What is the appropriate size of a YCbCr encoded tile?
197 	 */
198 	sz = TIFFTileSize(tif);
199 	if( sz != 24576) {
200 		fprintf(stderr, "tiles are %d bytes\n", (int)sz);
201 		exit(1);
202 	}
203 
204 	buffer = (unsigned char *) malloc(sz);
205 
206 	/*
207 	 * Read a tile in decompressed form, but still YCbCr subsampled.
208 	 */
209 	szout = TIFFReadEncodedTile(tif,9,buffer,sz);
210 	if (szout != sz) {
211 		fprintf( stderr,
212 			 "Did not get expected result code from TIFFReadEncodedTile()(%d instead of %d)\n",
213 			 (int) szout, (int) sz );
214 		return 1;
215 	}
216 
217 	if( check_cluster( 0, buffer, cluster_0 )
218 	    || check_cluster( 64, buffer, cluster_64 )
219 	    || check_cluster( 128, buffer, cluster_128 ) ) {
220 		exit(1);
221 	}
222 	free(buffer);
223 
224 	/*
225 	 * Read a tile using the built-in conversion to RGB format provided by the JPEG library.
226 	 */
227 	TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
228 
229 	sz = TIFFTileSize(tif);
230 	if( sz != 128*128*3) {
231 		fprintf(stderr, "tiles are %d bytes\n", (int)sz);
232 		exit(1);
233 	}
234 
235 	buffer = (unsigned char *) malloc(sz);
236 
237 	szout = TIFFReadEncodedTile(tif,9,buffer,sz);
238 	if (szout != sz) {
239 		fprintf( stderr,
240 			 "Did not get expected result code from TIFFReadEncodedTile()(%d instead of %d)\n",
241 			 (int) szout, (int) sz );
242 		return 1;
243 	}
244 
245 	/*
246 	 * JPEG decoding is inherently inexact, so we can't test for exact
247 	 * pixel values.  (Well, if we knew exactly which libjpeg version
248 	 * we were using, and with what settings, we could expect specific
249 	 * values ... but it's not worth the trouble to keep track of.)
250 	 * Hence, use ranges of expected values.  The ranges may need to be
251 	 * widened over time as more versions of libjpeg appear.
252 	 */
253 	pixel_status |= check_rgb_pixel( 0, 15, 18, 0, 0, 18, 41, buffer );
254 	pixel_status |= check_rgb_pixel( 64, 0, 0, 0, 0, 0, 2, buffer );
255 	pixel_status |= check_rgb_pixel( 512, 5, 6, 34, 36, 182, 196, buffer );
256 
257 	free( buffer );
258 
259 	TIFFClose(tif);
260 
261 	/*
262 	 * Reopen and test reading using the RGBA interface.
263 	 */
264 	tif = TIFFOpen(srcfile,"r");
265 
266 	sz = 128 * 128 * sizeof(uint32);
267 	rgba_buffer = (uint32 *) malloc(sz);
268 
269 	if (!TIFFReadRGBATile( tif, 1*128, 2*128, rgba_buffer )) {
270 		fprintf( stderr, "TIFFReadRGBATile() returned failure code.\n" );
271 		return 1;
272 	}
273 
274 	/*
275 	 * Currently TIFFReadRGBATile() just uses JPEGCOLORMODE_RGB so this
276 	 * trivally matches the last results.  Eventually we should actually
277 	 * accomplish it from the YCbCr subsampled buffer ourselves in which
278 	 * case the results may be subtly different but similar.
279 	 */
280 	pixel_status |= check_rgba_pixel( 0, 15, 18, 0, 0, 18, 41, 255, 255,
281 					  rgba_buffer );
282 	pixel_status |= check_rgba_pixel( 64, 0, 0, 0, 0, 0, 2, 255, 255,
283 					  rgba_buffer );
284 	pixel_status |= check_rgba_pixel( 512, 5, 6, 34, 36, 182, 196, 255, 255,
285 					  rgba_buffer );
286 
287 	free( rgba_buffer );
288 	TIFFClose(tif);
289 
290 	if (pixel_status) {
291 		exit(1);
292 	}
293 
294 	exit( 0 );
295 }
296 
297 /* vim: set ts=8 sts=8 sw=8 noet: */
298 /*
299  * Local Variables:
300  * mode: c
301  * c-basic-offset: 8
302  * fill-column: 78
303  * End:
304  */
305