/* * Sun Raster image file routines for CUPS. * * Copyright 2007-2011 by Apple Inc. * Copyright 1993-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright * law. Distribution and use rights are outlined in the file "COPYING" * which should have been included with this file. * * Contents: * * _cupsImageReadSunRaster() - Read a SunRaster image file. * read_unsigned() - Read a 32-bit unsigned integer. */ /* * Include necessary headers... */ #include "image-private.h" #define RAS_MAGIC 0x59a66a95 /* Sun supported ras_type's */ #define RT_OLD 0 /* Raw pixrect image in 68000 byte order */ #define RT_STANDARD 1 /* Raw pixrect image in 68000 byte order */ #define RT_BYTE_ENCODED 2 /* Run-length compression of bytes */ #define RT_FORMAT_RGB 3 /* XRGB or RGB instead of XBGR or BGR */ #define RT_EXPERIMENTAL 0xffff /* Reserved for testing */ /* Sun registered ras_maptype's */ #define RMT_RAW 2 /* Sun supported ras_maptype's */ #define RMT_NONE 0 /* ras_maplength is expected to be 0 */ #define RMT_EQUAL_RGB 1 /* red[ras_maplength/3],green[],blue[] */ #define RAS_RLE 0x80 /* * NOTES: * Each line of the image is rounded out to a multiple of 16 bits. * This corresponds to the rounding convention used by the memory pixrect * package (/usr/include/pixrect/memvar.h) of the SunWindows system. * The ras_encoding field (always set to 0 by Sun's supported software) * was renamed to ras_length in release 2.0. As a result, rasterfiles * of type 0 generated by the old software claim to have 0 length; for * compatibility, code reading rasterfiles must be prepared to compute the * true length from the width, height, and depth fields. */ /* * Local functions... */ static unsigned read_unsigned(FILE *fp); /* * '_cupsImageReadSunRaster()' - Read a SunRaster image file. */ int /* O - Read status */ _cupsImageReadSunRaster( cups_image_t *img, /* IO - cupsImage */ FILE *fp, /* I - cupsImage file */ cups_icspace_t primary, /* I - Primary choice for colorspace */ cups_icspace_t secondary, /* I - Secondary choice for colorspace */ int saturation, /* I - Color saturation (%) */ int hue, /* I - Color hue (degrees) */ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ { int i, x, y, bpp, /* Bytes per pixel */ scanwidth, run_count, run_value; cups_ib_t *in, *out, *scanline, *scanptr, *p, bit; unsigned ras_depth, /* depth (1, 8, or 24 bits) of pixel */ ras_type, /* type of file; see RT_* below */ ras_maplength; /* length (bytes) of following map */ unsigned char cmap[3][256]; /* colormap */ /* * Read the header; we already know that this is a raster file (cupsImageOpen * checks this) so we don't need to check the magic number again. */ fputs("DEBUG: Reading Sun Raster image...\n", stderr); read_unsigned(fp); /* Skip magic */ img->xsize = read_unsigned(fp); img->ysize = read_unsigned(fp); ras_depth = read_unsigned(fp); /* ras_length */read_unsigned(fp); ras_type = read_unsigned(fp); /* ras_maptype*/read_unsigned(fp); ras_maplength = read_unsigned(fp); fprintf(stderr, "DEBUG: ras_width=%d, ras_height=%d, ras_depth=%d, ras_type=%d, ras_maplength=%d\n", img->xsize, img->ysize, ras_depth, ras_type, ras_maplength); if (ras_maplength > 768 || img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH || img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT || ras_depth == 0 || ras_depth > 32) { fputs("DEBUG: Raster image cannot be loaded!\n", stderr); fclose(fp); return (1); } if (ras_maplength > 0) { memset(cmap[0], 255, sizeof(cmap[0])); memset(cmap[1], 0, sizeof(cmap[1])); memset(cmap[2], 0, sizeof(cmap[2])); if (fread(cmap[0], 1, ras_maplength / 3, fp) == 0 && ferror(fp)) DEBUG_printf(("Error reading file!")); if (fread(cmap[1], 1, ras_maplength / 3, fp) == 0 && ferror(fp)) DEBUG_printf(("Error reading file!")); if (fread(cmap[2], 1, ras_maplength / 3, fp) == 0 && ferror(fp)) DEBUG_printf(("Error reading file!")); } /* * Compute the width of each line and allocate memory as needed... */ scanwidth = (img->xsize * ras_depth + 7) / 8; if (scanwidth & 1) scanwidth ++; if (ras_depth < 24 && ras_maplength == 0) { img->colorspace = secondary; in = malloc(img->xsize + 1); } else { img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; in = malloc(img->xsize * 3 + 1); } if (!in) { fputs("DEBUG: Unable to allocate memory!\n", stderr); fclose(fp); return (1); } bpp = cupsImageGetDepth(img); if ((out = malloc(img->xsize * bpp)) == NULL) { fputs("DEBUG: Unable to allocate memory!\n", stderr); fclose(fp); free(in); return (1); } if ((scanline = malloc(scanwidth)) == NULL) { fputs("DEBUG: Unable to allocate memory!\n", stderr); fclose(fp); free(in); free(out); return (1); } run_count = 0; run_value = 0; fprintf(stderr, "DEBUG: bpp=%d, scanwidth=%d\n", bpp, scanwidth); for (y = 0; y < img->ysize; y ++) { if ((ras_depth != 8 && ras_depth != 24) || ras_maplength > 0) p = scanline; else p = in; if (ras_type != RT_BYTE_ENCODED) { if (fread(p, scanwidth, 1, fp) == 0 && ferror(fp)) DEBUG_printf(("Error reading file!")); } else { for (i = scanwidth; i > 0; i --, p ++) { if (run_count > 0) { *p = run_value; run_count --; } else { run_value = getc(fp); if (run_value == RAS_RLE) { run_count = getc(fp); if (run_count == 0) *p = RAS_RLE; else run_value = *p = getc(fp); } else *p = run_value; } } } if (ras_depth == 1 && ras_maplength == 0) { /* * 1-bit B&W image... */ for (x = img->xsize, bit = 128, scanptr = scanline, p = in; x > 0; x --, p ++) { if (*scanptr & bit) *p = 255; else *p = 0; if (bit > 1) bit >>= 1; else { bit = 128; scanptr ++; } } } else if (ras_depth == 1) { /* * 1-bit colormapped image... */ for (x = img->xsize, bit = 128, scanptr = scanline, p = in; x > 0; x --) { if (*scanptr & bit) { *p++ = cmap[0][1]; *p++ = cmap[1][1]; *p++ = cmap[2][1]; } else { *p++ = cmap[0][0]; *p++ = cmap[1][0]; *p++ = cmap[2][0]; } if (bit > 1) bit >>= 1; else { bit = 128; scanptr ++; } } } else if (ras_depth == 8 && ras_maplength > 0) { /* * 8-bit colormapped image. */ for (x = img->xsize, scanptr = scanline, p = in; x > 0; x --) { *p++ = cmap[0][*scanptr]; *p++ = cmap[1][*scanptr]; *p++ = cmap[2][*scanptr++]; } } else if (ras_depth == 24 && ras_type != RT_FORMAT_RGB) { /* * Convert BGR to RGB... */ for (x = img->xsize, scanptr = scanline, p = in; x > 0; x --, scanptr += 3) { *p++ = scanptr[2]; *p++ = scanptr[1]; *p++ = scanptr[0]; } } if (ras_depth <= 8 && ras_maplength == 0) { if (img->colorspace == CUPS_IMAGE_WHITE) { if (lut) cupsImageLut(in, img->xsize, lut); _cupsImagePutRow(img, 0, y, img->xsize, in); } else { switch (img->colorspace) { default : break; case CUPS_IMAGE_RGB : cupsImageWhiteToRGB(in, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageWhiteToBlack(in, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageWhiteToCMY(in, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageWhiteToCMYK(in, out, img->xsize); break; } if (lut) cupsImageLut(out, img->xsize * bpp, lut); _cupsImagePutRow(img, 0, y, img->xsize, out); } } else { if ((saturation != 100 || hue != 0) && bpp > 1) cupsImageRGBAdjust(in, img->xsize, saturation, hue); switch (img->colorspace) { default : break; case CUPS_IMAGE_WHITE : cupsImageRGBToWhite(in, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageRGBToBlack(in, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageRGBToCMY(in, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageRGBToCMYK(in, out, img->xsize); break; } if (lut) cupsImageLut(out, img->xsize * bpp, lut); _cupsImagePutRow(img, 0, y, img->xsize, out); } } free(scanline); free(in); free(out); fclose(fp); return (0); } /* * 'read_unsigned()' - Read a 32-bit unsigned integer. */ static unsigned /* O - Integer from file */ read_unsigned(FILE *fp) /* I - File to read from */ { unsigned v; /* Integer from file */ v = getc(fp); v = (v << 8) | getc(fp); v = (v << 8) | getc(fp); v = (v << 8) | getc(fp); return (v); }