/* * Copyright (c) 2012, Frank Warmerdam * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ /* * TIFF Library * * The objective of this test suite is to test the JPEGRawDecode() * interface via TIFReadEncodedTile(). This function with YCbCr subsampling * is a frequent source of bugs. */ #include "tif_config.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "tiffio.h" #include "jpeglib.h" /* Needed for JPEG_LIB_VERSION */ static unsigned char cluster_0[] = {0, 0, 2, 0, 138, 139}; static unsigned char cluster_64[] = {0, 0, 9, 6, 134, 119}; static unsigned char cluster_128[] = {44, 40, 63, 59, 230, 95}; static int check_cluster(int cluster, unsigned char *buffer, unsigned char *expected_cluster) { unsigned char *target = buffer + cluster * 6; if (memcmp(target, expected_cluster, 6) == 0) { return 0; } fprintf(stderr, "Cluster %d did not match expected results.\n", cluster); fprintf(stderr, "Expect: %3d %3d %3d %3d\n" " %3d %3d\n", expected_cluster[0], expected_cluster[1], expected_cluster[4], expected_cluster[5], expected_cluster[2], expected_cluster[3]); fprintf(stderr, " Got: %3d %3d %3d %3d\n" " %3d %3d\n", target[0], target[1], target[4], target[5], target[2], target[3]); return 1; } static int 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) { unsigned char *rgb = buffer + 3 * pixel; if (rgb[0] >= min_red && rgb[0] <= max_red && rgb[1] >= min_green && rgb[1] <= max_green && rgb[2] >= min_blue && rgb[2] <= max_blue) { return 0; } fprintf(stderr, "Pixel %d did not match expected results.\n", pixel); fprintf(stderr, "Got R=%d (expected %d..%d), G=%d (expected %d..%d), B=%d " "(expected %d..%d)\n", rgb[0], min_red, max_red, rgb[1], min_green, max_green, rgb[2], min_blue, max_blue); return 1; } static int 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_t *buffer) { /* RGBA images are upside down - adjust for normal ordering */ int adjusted_pixel = pixel % 128 + (127 - (pixel / 128)) * 128; uint32_t rgba = buffer[adjusted_pixel]; if (TIFFGetR(rgba) >= (uint32_t)min_red && TIFFGetR(rgba) <= (uint32_t)max_red && TIFFGetG(rgba) >= (uint32_t)min_green && TIFFGetG(rgba) <= (uint32_t)max_green && TIFFGetB(rgba) >= (uint32_t)min_blue && TIFFGetB(rgba) <= (uint32_t)max_blue && TIFFGetA(rgba) >= (uint32_t)min_alpha && TIFFGetA(rgba) <= (uint32_t)max_alpha) { return 0; } fprintf(stderr, "Pixel %d did not match expected results.\n", pixel); fprintf(stderr, "Got R=%d (expected %d..%d), G=%d (expected %d..%d), B=%d " "(expected %d..%d), A=%d (expected %d..%d)\n", TIFFGetR(rgba), min_red, max_red, TIFFGetG(rgba), min_green, max_green, TIFFGetB(rgba), min_blue, max_blue, TIFFGetA(rgba), min_alpha, max_alpha); return 1; } int main(int argc, char **argv) { TIFF *tif; static const char *srcfilerel = "images/quad-tile.jpg.tiff"; char *srcdir = NULL; char srcfile[1024]; unsigned short h, v; int status; unsigned char *buffer; uint32_t *rgba_buffer; tsize_t sz, szout; unsigned int pixel_status = 0; (void)argc; (void)argv; if ((srcdir = getenv("srcdir")) == NULL) { srcdir = "."; } if ((strlen(srcdir) + 1 + strlen(srcfilerel)) >= sizeof(srcfile)) { fprintf(stderr, "srcdir too long %s\n", srcdir); exit(1); } strcpy(srcfile, srcdir); strcat(srcfile, "/"); strcat(srcfile, srcfilerel); tif = TIFFOpen(srcfile, "r"); if (tif == NULL) { fprintf(stderr, "Could not open %s\n", srcfile); exit(1); } status = TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING, &h, &v); if (status == 0 || h != 2 || v != 2) { fprintf(stderr, "Could not retrieve subsampling tag.\n"); exit(1); } /* * What is the appropriate size of a YCbCr encoded tile? */ sz = TIFFTileSize(tif); if (sz != 24576) { fprintf(stderr, "tiles are %d bytes\n", (int)sz); exit(1); } buffer = (unsigned char *)malloc(sz); /* * Read a tile in decompressed form, but still YCbCr subsampled. */ szout = TIFFReadEncodedTile(tif, 9, buffer, sz); if (szout != sz) { fprintf(stderr, "Did not get expected result code from " "TIFFReadEncodedTile()(%d instead of %d)\n", (int)szout, (int)sz); return 1; } if (check_cluster(0, buffer, cluster_0) || check_cluster(64, buffer, cluster_64) || check_cluster(128, buffer, cluster_128)) { exit(1); } free(buffer); /* * Read a tile using the built-in conversion to RGB format provided by the * JPEG library. */ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); sz = TIFFTileSize(tif); if (sz != 128 * 128 * 3) { fprintf(stderr, "tiles are %d bytes\n", (int)sz); exit(1); } buffer = (unsigned char *)malloc(sz); szout = TIFFReadEncodedTile(tif, 9, buffer, sz); if (szout != sz) { fprintf(stderr, "Did not get expected result code from " "TIFFReadEncodedTile()(%d instead of %d)\n", (int)szout, (int)sz); return 1; } /* * JPEG decoding is inherently inexact, so we can't test for exact * pixel values. (Well, if we knew exactly which libjpeg version * we were using, and with what settings, we could expect specific * values ... but it's not worth the trouble to keep track of.) * Hence, use ranges of expected values. The ranges may need to be * widened over time as more versions of libjpeg appear. */ pixel_status |= check_rgb_pixel(0, 15, 18, 0, 0, 18, 41, buffer); pixel_status |= check_rgb_pixel(64, 0, 0, 0, 0, 0, 2, buffer); pixel_status |= check_rgb_pixel(512, 5, 6, 34, 36, 182, 196, buffer); free(buffer); TIFFClose(tif); /* * Reopen and test reading using the RGBA interface. */ tif = TIFFOpen(srcfile, "r"); sz = 128 * 128 * sizeof(uint32_t); rgba_buffer = (uint32_t *)malloc(sz); if (!TIFFReadRGBATile(tif, 1 * 128, 2 * 128, rgba_buffer)) { fprintf(stderr, "TIFFReadRGBATile() returned failure code.\n"); return 1; } /* * Currently TIFFReadRGBATile() just uses JPEGCOLORMODE_RGB so this * trivially matches the last results. Eventually we should actually * accomplish it from the YCbCr subsampled buffer ourselves in which * case the results may be subtly different but similar. */ pixel_status |= check_rgba_pixel(0, 15, 18, 0, 0, 18, 41, 255, 255, rgba_buffer); pixel_status |= check_rgba_pixel(64, 0, 0, 0, 0, 0, 2, 255, 255, rgba_buffer); pixel_status |= check_rgba_pixel(512, 5, 6, 34, 36, 182, 196, 255, 255, rgba_buffer); free(rgba_buffer); TIFFClose(tif); if (pixel_status) { exit(1); } exit(0); }