| /* |
| * Raster file routines for CUPS. |
| * |
| * Copyright 2007-2019 by Apple Inc. |
| * Copyright 1997-2006 by Easy Software Products. |
| * |
| * This file is part of the CUPS Imaging library. |
| * |
| * Licensed under Apache License v2.0. See the file "LICENSE" for more |
| * information. |
| */ |
| |
| /* |
| * Include necessary headers... |
| */ |
| |
| #include "raster-private.h" |
| #include "debug-internal.h" |
| #ifdef HAVE_STDINT_H |
| # include <stdint.h> |
| #endif /* HAVE_STDINT_H */ |
| |
| |
| /* |
| * Private structures... |
| */ |
| |
| typedef void (*_cups_copyfunc_t)(void *dst, const void *src, size_t bytes); |
| |
| |
| /* |
| * Local globals... |
| */ |
| |
| static const char * const apple_media_types[] = |
| { /* media-type values for Apple Raster */ |
| "auto", |
| "stationery", |
| "transparency", |
| "envelope", |
| "cardstock", |
| "labels", |
| "stationery-letterhead", |
| "disc", |
| "photographic-matte", |
| "photographic-satin", |
| "photographic-semi-gloss", |
| "photographic-glossy", |
| "photographic-high-gloss", |
| "other" |
| }; |
| |
| #ifdef DEBUG |
| static const char * const cups_modes[] = |
| { /* Open modes */ |
| "CUPS_RASTER_READ", |
| "CUPS_RASTER_WRITE", |
| "CUPS_RASTER_WRITE_COMPRESSED", |
| "CUPS_RASTER_WRITE_PWG", |
| "CUPS_RASTER_WRITE_APPLE" |
| }; |
| #endif /* DEBUG */ |
| |
| |
| /* |
| * Local functions... |
| */ |
| |
| static ssize_t cups_raster_io(cups_raster_t *r, unsigned char *buf, size_t bytes); |
| static ssize_t cups_raster_read(cups_raster_t *r, unsigned char *buf, size_t bytes); |
| static int cups_raster_update(cups_raster_t *r); |
| static ssize_t cups_raster_write(cups_raster_t *r, const unsigned char *pixels); |
| static void cups_swap(unsigned char *buf, size_t bytes); |
| static void cups_swap_copy(unsigned char *dst, const unsigned char *src, size_t bytes); |
| |
| |
| /* |
| * '_cupsRasterColorSpaceString()' - Return the colorspace name for a |
| * cupsColorSpace value. |
| */ |
| |
| const char * |
| _cupsRasterColorSpaceString( |
| cups_cspace_t cspace) /* I - cupsColorSpace value */ |
| { |
| static const char * const cups_color_spaces[] = |
| { /* Color spaces */ |
| "W", |
| "RGB", |
| "RGBA", |
| "K", |
| "CMY", |
| "YMC", |
| "CMYK", |
| "YMCK", |
| "KCMY", |
| "KCMYcm", |
| "GMCK", |
| "GMCS", |
| "WHITE", |
| "GOLD", |
| "SILVER", |
| "CIEXYZ", |
| "CIELab", |
| "RGBW", |
| "SW", |
| "SRGB", |
| "ADOBERGB", |
| "21", |
| "22", |
| "23", |
| "24", |
| "25", |
| "26", |
| "27", |
| "28", |
| "29", |
| "30", |
| "31", |
| "ICC1", |
| "ICC2", |
| "ICC3", |
| "ICC4", |
| "ICC5", |
| "ICC6", |
| "ICC7", |
| "ICC8", |
| "ICC9", |
| "ICCA", |
| "ICCB", |
| "ICCC", |
| "ICCD", |
| "ICCE", |
| "ICCF", |
| "47", |
| "DEVICE1", |
| "DEVICE2", |
| "DEVICE3", |
| "DEVICE4", |
| "DEVICE5", |
| "DEVICE6", |
| "DEVICE7", |
| "DEVICE8", |
| "DEVICE9", |
| "DEVICEA", |
| "DEVICEB", |
| "DEVICEC", |
| "DEVICED", |
| "DEVICEE", |
| "DEVICEF" |
| }; |
| |
| if (cspace < CUPS_CSPACE_W || cspace > CUPS_CSPACE_DEVICEF) |
| return ("Unknown"); |
| else |
| return (cups_color_spaces[cspace]); |
| } |
| |
| |
| /* |
| * '_cupsRasterDelete()' - Free a raster stream. |
| * |
| * The file descriptor associated with the raster stream must be closed |
| * separately as needed. |
| */ |
| |
| void |
| _cupsRasterDelete(cups_raster_t *r) /* I - Stream to free */ |
| { |
| if (r != NULL) |
| { |
| if (r->buffer) |
| free(r->buffer); |
| |
| if (r->pixels) |
| free(r->pixels); |
| |
| free(r); |
| } |
| } |
| |
| |
| /* |
| * '_cupsRasterInitPWGHeader()' - Initialize a page header for PWG Raster output. |
| * |
| * The "media" argument specifies the media to use. |
| * |
| * The "type" argument specifies a "pwg-raster-document-type-supported" value |
| * that controls the color space and bit depth of the raster data. |
| * |
| * The "xres" and "yres" arguments specify the raster resolution in dots per |
| * inch. |
| * |
| * The "sheet_back" argument specifies a "pwg-raster-document-sheet-back" value |
| * to apply for the back side of a page. Pass @code NULL@ for the front side. |
| * |
| * @since CUPS 2.2/macOS 10.12@ |
| */ |
| |
| int /* O - 1 on success, 0 on failure */ |
| _cupsRasterInitPWGHeader( |
| cups_page_header2_t *h, /* I - Page header */ |
| pwg_media_t *media, /* I - PWG media information */ |
| const char *type, /* I - PWG raster type string */ |
| int xdpi, /* I - Cross-feed direction (horizontal) resolution */ |
| int ydpi, /* I - Feed direction (vertical) resolution */ |
| const char *sides, /* I - IPP "sides" option value */ |
| const char *sheet_back) /* I - Transform for back side or @code NULL@ for none */ |
| { |
| if (!h || !media || !type || xdpi <= 0 || ydpi <= 0) |
| { |
| _cupsRasterAddError("%s", strerror(EINVAL)); |
| return (0); |
| } |
| |
| /* |
| * Initialize the page header... |
| */ |
| |
| memset(h, 0, sizeof(cups_page_header2_t)); |
| |
| strlcpy(h->cupsPageSizeName, media->pwg, sizeof(h->cupsPageSizeName)); |
| |
| h->PageSize[0] = (unsigned)(72 * media->width / 2540); |
| h->PageSize[1] = (unsigned)(72 * media->length / 2540); |
| |
| /* This never gets written but is needed for some applications */ |
| h->cupsPageSize[0] = 72.0f * media->width / 2540.0f; |
| h->cupsPageSize[1] = 72.0f * media->length / 2540.0f; |
| |
| h->ImagingBoundingBox[2] = h->PageSize[0]; |
| h->ImagingBoundingBox[3] = h->PageSize[1]; |
| |
| h->HWResolution[0] = (unsigned)xdpi; |
| h->HWResolution[1] = (unsigned)ydpi; |
| |
| h->cupsWidth = (unsigned)(media->width * xdpi / 2540); |
| h->cupsHeight = (unsigned)(media->length * ydpi / 2540); |
| |
| if (h->cupsWidth > 0x00ffffff || h->cupsHeight > 0x00ffffff) |
| { |
| _cupsRasterAddError("Raster dimensions too large."); |
| return (0); |
| } |
| |
| h->cupsInteger[CUPS_RASTER_PWG_ImageBoxRight] = h->cupsWidth; |
| h->cupsInteger[CUPS_RASTER_PWG_ImageBoxBottom] = h->cupsHeight; |
| |
| /* |
| * Colorspace and bytes per line... |
| */ |
| |
| if (!strcmp(type, "adobe-rgb_8")) |
| { |
| h->cupsBitsPerColor = 8; |
| h->cupsBitsPerPixel = 24; |
| h->cupsColorSpace = CUPS_CSPACE_ADOBERGB; |
| } |
| else if (!strcmp(type, "adobe-rgb_16")) |
| { |
| h->cupsBitsPerColor = 16; |
| h->cupsBitsPerPixel = 48; |
| h->cupsColorSpace = CUPS_CSPACE_ADOBERGB; |
| } |
| else if (!strcmp(type, "black_1")) |
| { |
| h->cupsBitsPerColor = 1; |
| h->cupsBitsPerPixel = 1; |
| h->cupsColorSpace = CUPS_CSPACE_K; |
| } |
| else if (!strcmp(type, "black_8")) |
| { |
| h->cupsBitsPerColor = 8; |
| h->cupsBitsPerPixel = 8; |
| h->cupsColorSpace = CUPS_CSPACE_K; |
| } |
| else if (!strcmp(type, "black_16")) |
| { |
| h->cupsBitsPerColor = 16; |
| h->cupsBitsPerPixel = 16; |
| h->cupsColorSpace = CUPS_CSPACE_K; |
| } |
| else if (!strcmp(type, "cmyk_8")) |
| { |
| h->cupsBitsPerColor = 8; |
| h->cupsBitsPerPixel = 32; |
| h->cupsColorSpace = CUPS_CSPACE_CMYK; |
| } |
| else if (!strcmp(type, "cmyk_16")) |
| { |
| h->cupsBitsPerColor = 16; |
| h->cupsBitsPerPixel = 64; |
| h->cupsColorSpace = CUPS_CSPACE_CMYK; |
| } |
| else if (!strncmp(type, "device", 6) && type[6] >= '1' && type[6] <= '9') |
| { |
| int ncolors, bits; /* Number of colors and bits */ |
| |
| |
| if (sscanf(type, "device%d_%d", &ncolors, &bits) != 2 || ncolors > 15 || (bits != 8 && bits != 16)) |
| { |
| _cupsRasterAddError("Unsupported raster type \'%s\'.", type); |
| return (0); |
| } |
| |
| h->cupsBitsPerColor = (unsigned)bits; |
| h->cupsBitsPerPixel = (unsigned)(ncolors * bits); |
| h->cupsColorSpace = (cups_cspace_t)(CUPS_CSPACE_DEVICE1 + ncolors - 1); |
| } |
| else if (!strcmp(type, "rgb_8")) |
| { |
| h->cupsBitsPerColor = 8; |
| h->cupsBitsPerPixel = 24; |
| h->cupsColorSpace = CUPS_CSPACE_RGB; |
| } |
| else if (!strcmp(type, "rgb_16")) |
| { |
| h->cupsBitsPerColor = 16; |
| h->cupsBitsPerPixel = 48; |
| h->cupsColorSpace = CUPS_CSPACE_RGB; |
| } |
| else if (!strcmp(type, "sgray_1")) |
| { |
| h->cupsBitsPerColor = 1; |
| h->cupsBitsPerPixel = 1; |
| h->cupsColorSpace = CUPS_CSPACE_SW; |
| } |
| else if (!strcmp(type, "sgray_8")) |
| { |
| h->cupsBitsPerColor = 8; |
| h->cupsBitsPerPixel = 8; |
| h->cupsColorSpace = CUPS_CSPACE_SW; |
| } |
| else if (!strcmp(type, "sgray_16")) |
| { |
| h->cupsBitsPerColor = 16; |
| h->cupsBitsPerPixel = 16; |
| h->cupsColorSpace = CUPS_CSPACE_SW; |
| } |
| else if (!strcmp(type, "srgb_8")) |
| { |
| h->cupsBitsPerColor = 8; |
| h->cupsBitsPerPixel = 24; |
| h->cupsColorSpace = CUPS_CSPACE_SRGB; |
| } |
| else if (!strcmp(type, "srgb_16")) |
| { |
| h->cupsBitsPerColor = 16; |
| h->cupsBitsPerPixel = 48; |
| h->cupsColorSpace = CUPS_CSPACE_SRGB; |
| } |
| else |
| { |
| _cupsRasterAddError("Unsupported raster type \'%s\'.", type); |
| return (0); |
| } |
| |
| h->cupsColorOrder = CUPS_ORDER_CHUNKED; |
| h->cupsNumColors = h->cupsBitsPerPixel / h->cupsBitsPerColor; |
| h->cupsBytesPerLine = (h->cupsWidth * h->cupsBitsPerPixel + 7) / 8; |
| |
| /* |
| * Duplex support... |
| */ |
| |
| h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 1; |
| h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 1; |
| |
| if (sides) |
| { |
| if (!strcmp(sides, "two-sided-long-edge")) |
| { |
| h->Duplex = 1; |
| } |
| else if (!strcmp(sides, "two-sided-short-edge")) |
| { |
| h->Duplex = 1; |
| h->Tumble = 1; |
| } |
| else if (strcmp(sides, "one-sided")) |
| { |
| _cupsRasterAddError("Unsupported sides value \'%s\'.", sides); |
| return (0); |
| } |
| |
| if (sheet_back) |
| { |
| if (!strcmp(sheet_back, "flipped")) |
| { |
| if (h->Tumble) |
| h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU; |
| else |
| h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU; |
| } |
| else if (!strcmp(sheet_back, "manual-tumble")) |
| { |
| if (h->Tumble) |
| { |
| h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU; |
| h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU; |
| } |
| } |
| else if (!strcmp(sheet_back, "rotated")) |
| { |
| if (!h->Tumble) |
| { |
| h->cupsInteger[CUPS_RASTER_PWG_CrossFeedTransform] = 0xffffffffU; |
| h->cupsInteger[CUPS_RASTER_PWG_FeedTransform] = 0xffffffffU; |
| } |
| } |
| else if (strcmp(sheet_back, "normal")) |
| { |
| _cupsRasterAddError("Unsupported sheet_back value \'%s\'.", sheet_back); |
| return (0); |
| } |
| } |
| } |
| |
| return (1); |
| } |
| |
| |
| /* |
| * '_cupsRasterNew()' - Create a raster stream using a callback function. |
| * |
| * This function associates a raster stream with the given callback function and |
| * context pointer. |
| * |
| * When writing raster data, the @code CUPS_RASTER_WRITE@, |
| * @code CUPS_RASTER_WRITE_COMPRESS@, or @code CUPS_RASTER_WRITE_PWG@ mode can |
| * be used - compressed and PWG output is generally 25-50% smaller but adds a |
| * 100-300% execution time overhead. |
| */ |
| |
| cups_raster_t * /* O - New stream */ |
| _cupsRasterNew( |
| cups_raster_iocb_t iocb, /* I - Read/write callback */ |
| void *ctx, /* I - Context pointer for callback */ |
| cups_mode_t mode) /* I - Mode - @code CUPS_RASTER_READ@, |
| @code CUPS_RASTER_WRITE@, |
| @code CUPS_RASTER_WRITE_COMPRESSED@, |
| or @code CUPS_RASTER_WRITE_PWG@ */ |
| { |
| cups_raster_t *r; /* New stream */ |
| |
| |
| DEBUG_printf(("_cupsRasterOpenIO(iocb=%p, ctx=%p, mode=%s)", (void *)iocb, ctx, cups_modes[mode])); |
| |
| _cupsRasterClearError(); |
| |
| if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL) |
| { |
| _cupsRasterAddError("Unable to allocate memory for raster stream: %s\n", |
| strerror(errno)); |
| DEBUG_puts("1_cupsRasterOpenIO: Returning NULL."); |
| return (NULL); |
| } |
| |
| r->ctx = ctx; |
| r->iocb = iocb; |
| r->mode = mode; |
| |
| if (mode == CUPS_RASTER_READ) |
| { |
| /* |
| * Open for read - get sync word... |
| */ |
| |
| if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) != |
| sizeof(r->sync)) |
| { |
| _cupsRasterAddError("Unable to read header from raster stream: %s\n", |
| strerror(errno)); |
| free(r); |
| DEBUG_puts("1_cupsRasterOpenIO: Unable to read header, returning NULL."); |
| return (NULL); |
| } |
| |
| if (r->sync != CUPS_RASTER_SYNC && |
| r->sync != CUPS_RASTER_REVSYNC && |
| r->sync != CUPS_RASTER_SYNCv1 && |
| r->sync != CUPS_RASTER_REVSYNCv1 && |
| r->sync != CUPS_RASTER_SYNCv2 && |
| r->sync != CUPS_RASTER_REVSYNCv2 && |
| r->sync != CUPS_RASTER_SYNCapple && |
| r->sync != CUPS_RASTER_REVSYNCapple) |
| { |
| _cupsRasterAddError("Unknown raster format %08x!\n", r->sync); |
| free(r); |
| DEBUG_puts("1_cupsRasterOpenIO: Unknown format, returning NULL."); |
| return (NULL); |
| } |
| |
| if (r->sync == CUPS_RASTER_SYNCv2 || |
| r->sync == CUPS_RASTER_REVSYNCv2 || |
| r->sync == CUPS_RASTER_SYNCapple || |
| r->sync == CUPS_RASTER_REVSYNCapple) |
| r->compressed = 1; |
| |
| DEBUG_printf(("1_cupsRasterOpenIO: sync=%08x", r->sync)); |
| |
| if (r->sync == CUPS_RASTER_REVSYNC || |
| r->sync == CUPS_RASTER_REVSYNCv1 || |
| r->sync == CUPS_RASTER_REVSYNCv2 || |
| r->sync == CUPS_RASTER_REVSYNCapple) |
| r->swapped = 1; |
| |
| if (r->sync == CUPS_RASTER_SYNCapple || |
| r->sync == CUPS_RASTER_REVSYNCapple) |
| { |
| unsigned char header[8]; /* File header */ |
| |
| if (cups_raster_io(r, (unsigned char *)header, sizeof(header)) != |
| sizeof(header)) |
| { |
| _cupsRasterAddError("Unable to read header from raster stream: %s\n", |
| strerror(errno)); |
| free(r); |
| DEBUG_puts("1_cupsRasterOpenIO: Unable to read header, returning NULL."); |
| return (NULL); |
| } |
| } |
| |
| #ifdef DEBUG |
| r->iostart = r->iocount; |
| #endif /* DEBUG */ |
| } |
| else |
| { |
| /* |
| * Open for write - put sync word... |
| */ |
| |
| switch (mode) |
| { |
| default : |
| case CUPS_RASTER_WRITE : |
| r->sync = CUPS_RASTER_SYNC; |
| break; |
| |
| case CUPS_RASTER_WRITE_COMPRESSED : |
| r->compressed = 1; |
| r->sync = CUPS_RASTER_SYNCv2; |
| break; |
| |
| case CUPS_RASTER_WRITE_PWG : |
| r->compressed = 1; |
| r->sync = htonl(CUPS_RASTER_SYNC_PWG); |
| r->swapped = r->sync != CUPS_RASTER_SYNC_PWG; |
| break; |
| |
| case CUPS_RASTER_WRITE_APPLE : |
| r->compressed = 1; |
| r->sync = htonl(CUPS_RASTER_SYNCapple); |
| r->swapped = r->sync != CUPS_RASTER_SYNCapple; |
| r->apple_page_count = 0xffffffffU; |
| break; |
| } |
| |
| if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) < (ssize_t)sizeof(r->sync)) |
| { |
| _cupsRasterAddError("Unable to write raster stream header: %s\n", |
| strerror(errno)); |
| free(r); |
| DEBUG_puts("1_cupsRasterOpenIO: Unable to write header, returning NULL."); |
| return (NULL); |
| } |
| } |
| |
| DEBUG_printf(("1_cupsRasterOpenIO: compressed=%d, swapped=%d, returning %p", r->compressed, r->swapped, (void *)r)); |
| |
| return (r); |
| } |
| |
| |
| /* |
| * '_cupsRasterReadHeader()' - Read a raster page header. |
| */ |
| |
| unsigned /* O - 1 on success, 0 on fail */ |
| _cupsRasterReadHeader( |
| cups_raster_t *r) /* I - Raster stream */ |
| { |
| size_t len; /* Length for read/swap */ |
| |
| |
| DEBUG_printf(("3_cupsRasterReadHeader(r=%p), r->mode=%s", (void *)r, r ? cups_modes[r->mode] : "")); |
| |
| if (r == NULL || r->mode != CUPS_RASTER_READ) |
| return (0); |
| |
| DEBUG_printf(("4_cupsRasterReadHeader: r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount)); |
| |
| memset(&(r->header), 0, sizeof(r->header)); |
| |
| /* |
| * Read the header... |
| */ |
| |
| switch (r->sync) |
| { |
| default : |
| /* |
| * Get the length of the raster header... |
| */ |
| |
| if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1) |
| len = sizeof(cups_page_header_t); |
| else |
| len = sizeof(cups_page_header2_t); |
| |
| DEBUG_printf(("4_cupsRasterReadHeader: len=%d", (int)len)); |
| |
| /* |
| * Read it... |
| */ |
| |
| if (cups_raster_read(r, (unsigned char *)&(r->header), len) < (ssize_t)len) |
| { |
| DEBUG_printf(("4_cupsRasterReadHeader: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount)); |
| return (0); |
| } |
| |
| /* |
| * Swap bytes as needed... |
| */ |
| |
| if (r->swapped) |
| { |
| unsigned *s, /* Current word */ |
| temp; /* Temporary copy */ |
| |
| |
| DEBUG_puts("4_cupsRasterReadHeader: Swapping header bytes."); |
| |
| for (len = 81, s = &(r->header.AdvanceDistance); |
| len > 0; |
| len --, s ++) |
| { |
| temp = *s; |
| *s = ((temp & 0xff) << 24) | |
| ((temp & 0xff00) << 8) | |
| ((temp & 0xff0000) >> 8) | |
| ((temp & 0xff000000) >> 24); |
| |
| DEBUG_printf(("4_cupsRasterReadHeader: %08x => %08x", temp, *s)); |
| } |
| } |
| break; |
| |
| case CUPS_RASTER_SYNCapple : |
| case CUPS_RASTER_REVSYNCapple : |
| { |
| unsigned char appleheader[32]; /* Raw header */ |
| static const unsigned rawcspace[] = |
| { |
| CUPS_CSPACE_SW, |
| CUPS_CSPACE_SRGB, |
| CUPS_CSPACE_CIELab, |
| CUPS_CSPACE_ADOBERGB, |
| CUPS_CSPACE_W, |
| CUPS_CSPACE_RGB, |
| CUPS_CSPACE_CMYK |
| }; |
| static const unsigned rawnumcolors[] = |
| { |
| 1, |
| 3, |
| 3, |
| 3, |
| 1, |
| 3, |
| 4 |
| }; |
| |
| if (cups_raster_read(r, appleheader, sizeof(appleheader)) < (ssize_t)sizeof(appleheader)) |
| { |
| DEBUG_printf(("4_cupsRasterReadHeader: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount)); |
| return (0); |
| } |
| |
| strlcpy(r->header.MediaClass, "PwgRaster", sizeof(r->header.MediaClass)); |
| /* PwgRaster */ |
| r->header.cupsBitsPerPixel = appleheader[0]; |
| r->header.cupsColorSpace = appleheader[1] >= (sizeof(rawcspace) / sizeof(rawcspace[0])) ? CUPS_CSPACE_DEVICE1 : rawcspace[appleheader[1]]; |
| r->header.cupsNumColors = appleheader[1] >= (sizeof(rawnumcolors) / sizeof(rawnumcolors[0])) ? 1 : rawnumcolors[appleheader[1]]; |
| r->header.cupsBitsPerColor = r->header.cupsBitsPerPixel / r->header.cupsNumColors; |
| r->header.cupsWidth = ((((((unsigned)appleheader[12] << 8) | (unsigned)appleheader[13]) << 8) | (unsigned)appleheader[14]) << 8) | (unsigned)appleheader[15]; |
| r->header.cupsHeight = ((((((unsigned)appleheader[16] << 8) | (unsigned)appleheader[17]) << 8) | (unsigned)appleheader[18]) << 8) | (unsigned)appleheader[19]; |
| r->header.cupsBytesPerLine = r->header.cupsWidth * r->header.cupsBitsPerPixel / 8; |
| r->header.cupsColorOrder = CUPS_ORDER_CHUNKED; |
| r->header.HWResolution[0] = r->header.HWResolution[1] = ((((((unsigned)appleheader[20] << 8) | (unsigned)appleheader[21]) << 8) | (unsigned)appleheader[22]) << 8) | (unsigned)appleheader[23]; |
| |
| if (r->header.HWResolution[0] > 0) |
| { |
| r->header.PageSize[0] = (unsigned)(r->header.cupsWidth * 72 / r->header.HWResolution[0]); |
| r->header.PageSize[1] = (unsigned)(r->header.cupsHeight * 72 / r->header.HWResolution[1]); |
| r->header.cupsPageSize[0] = (float)(r->header.cupsWidth * 72.0 / r->header.HWResolution[0]); |
| r->header.cupsPageSize[1] = (float)(r->header.cupsHeight * 72.0 / r->header.HWResolution[1]); |
| } |
| |
| r->header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = r->apple_page_count; |
| r->header.cupsInteger[CUPS_RASTER_PWG_AlternatePrimary] = 0xffffff; |
| r->header.cupsInteger[CUPS_RASTER_PWG_PrintQuality] = appleheader[3]; |
| |
| if (appleheader[2] >= 2) |
| r->header.Duplex = 1; |
| if (appleheader[2] == 2) |
| r->header.Tumble = 1; |
| |
| r->header.MediaPosition = appleheader[5]; |
| |
| if (appleheader[4] < (int)(sizeof(apple_media_types) / sizeof(apple_media_types[0]))) |
| strlcpy(r->header.MediaType, apple_media_types[appleheader[4]], sizeof(r->header.MediaType)); |
| else |
| strlcpy(r->header.MediaType, "other", sizeof(r->header.MediaType)); |
| } |
| break; |
| } |
| |
| /* |
| * Update the header and row count... |
| */ |
| |
| if (!cups_raster_update(r)) |
| return (0); |
| |
| DEBUG_printf(("4_cupsRasterReadHeader: cupsColorSpace=%s", _cupsRasterColorSpaceString(r->header.cupsColorSpace))); |
| DEBUG_printf(("4_cupsRasterReadHeader: cupsBitsPerColor=%u", r->header.cupsBitsPerColor)); |
| DEBUG_printf(("4_cupsRasterReadHeader: cupsBitsPerPixel=%u", r->header.cupsBitsPerPixel)); |
| DEBUG_printf(("4_cupsRasterReadHeader: cupsBytesPerLine=%u", r->header.cupsBytesPerLine)); |
| DEBUG_printf(("4_cupsRasterReadHeader: cupsWidth=%u", r->header.cupsWidth)); |
| DEBUG_printf(("4_cupsRasterReadHeader: cupsHeight=%u", r->header.cupsHeight)); |
| DEBUG_printf(("4_cupsRasterReadHeader: r->bpp=%d", r->bpp)); |
| |
| return (r->header.cupsBitsPerPixel > 0 && r->header.cupsBitsPerPixel <= 240 && r->header.cupsBitsPerColor > 0 && r->header.cupsBitsPerColor <= 16 && r->header.cupsBytesPerLine > 0 && r->header.cupsBytesPerLine <= 0x7fffffff && r->header.cupsHeight != 0 && (r->header.cupsBytesPerLine % r->bpp) == 0); |
| } |
| |
| |
| /* |
| * '_cupsRasterReadPixels()' - Read raster pixels. |
| * |
| * For best performance, filters should read one or more whole lines. |
| * The "cupsBytesPerLine" value from the page header can be used to allocate |
| * the line buffer and as the number of bytes to read. |
| */ |
| |
| unsigned /* O - Number of bytes read */ |
| _cupsRasterReadPixels( |
| cups_raster_t *r, /* I - Raster stream */ |
| unsigned char *p, /* I - Pointer to pixel buffer */ |
| unsigned len) /* I - Number of bytes to read */ |
| { |
| ssize_t bytes; /* Bytes read */ |
| unsigned cupsBytesPerLine; /* cupsBytesPerLine value */ |
| unsigned remaining; /* Bytes remaining */ |
| unsigned char *ptr, /* Pointer to read buffer */ |
| byte, /* Byte from file */ |
| *temp; /* Pointer into buffer */ |
| unsigned count; /* Repetition count */ |
| |
| |
| DEBUG_printf(("_cupsRasterReadPixels(r=%p, p=%p, len=%u)", (void *)r, (void *)p, len)); |
| |
| if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0 || |
| r->header.cupsBytesPerLine == 0) |
| { |
| DEBUG_puts("1_cupsRasterReadPixels: Returning 0."); |
| return (0); |
| } |
| |
| DEBUG_printf(("1_cupsRasterReadPixels: compressed=%d, remaining=%u", r->compressed, r->remaining)); |
| |
| if (!r->compressed) |
| { |
| /* |
| * Read without compression... |
| */ |
| |
| r->remaining -= len / r->header.cupsBytesPerLine; |
| |
| if (cups_raster_io(r, p, len) < (ssize_t)len) |
| { |
| DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0."); |
| return (0); |
| } |
| |
| /* |
| * Swap bytes as needed... |
| */ |
| |
| if (r->swapped && |
| (r->header.cupsBitsPerColor == 16 || |
| r->header.cupsBitsPerPixel == 12 || |
| r->header.cupsBitsPerPixel == 16)) |
| cups_swap(p, len); |
| |
| /* |
| * Return... |
| */ |
| |
| DEBUG_printf(("1_cupsRasterReadPixels: Returning %u", len)); |
| |
| return (len); |
| } |
| |
| /* |
| * Read compressed data... |
| */ |
| |
| remaining = len; |
| cupsBytesPerLine = r->header.cupsBytesPerLine; |
| |
| while (remaining > 0 && r->remaining > 0) |
| { |
| if (r->count == 0) |
| { |
| /* |
| * Need to read a new row... |
| */ |
| |
| if (remaining == cupsBytesPerLine) |
| ptr = p; |
| else |
| ptr = r->pixels; |
| |
| /* |
| * Read using a modified PackBits compression... |
| */ |
| |
| if (!cups_raster_read(r, &byte, 1)) |
| { |
| DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0."); |
| return (0); |
| } |
| |
| r->count = (unsigned)byte + 1; |
| |
| if (r->count > 1) |
| ptr = r->pixels; |
| |
| temp = ptr; |
| bytes = (ssize_t)cupsBytesPerLine; |
| |
| while (bytes > 0) |
| { |
| /* |
| * Get a new repeat count... |
| */ |
| |
| if (!cups_raster_read(r, &byte, 1)) |
| { |
| DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0."); |
| return (0); |
| } |
| |
| if (byte == 128) |
| { |
| /* |
| * Clear to end of line... |
| */ |
| |
| switch (r->header.cupsColorSpace) |
| { |
| case CUPS_CSPACE_W : |
| case CUPS_CSPACE_RGB : |
| case CUPS_CSPACE_SW : |
| case CUPS_CSPACE_SRGB : |
| case CUPS_CSPACE_RGBW : |
| case CUPS_CSPACE_ADOBERGB : |
| memset(temp, 0xff, (size_t)bytes); |
| break; |
| default : |
| memset(temp, 0x00, (size_t)bytes); |
| break; |
| } |
| |
| temp += bytes; |
| bytes = 0; |
| } |
| else if (byte & 128) |
| { |
| /* |
| * Copy N literal pixels... |
| */ |
| |
| count = (unsigned)(257 - byte) * r->bpp; |
| |
| if (count > (unsigned)bytes) |
| count = (unsigned)bytes; |
| |
| if (!cups_raster_read(r, temp, count)) |
| { |
| DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0."); |
| return (0); |
| } |
| |
| temp += count; |
| bytes -= (ssize_t)count; |
| } |
| else |
| { |
| /* |
| * Repeat the next N bytes... |
| */ |
| |
| count = ((unsigned)byte + 1) * r->bpp; |
| if (count > (unsigned)bytes) |
| count = (unsigned)bytes; |
| |
| if (count < r->bpp) |
| break; |
| |
| bytes -= (ssize_t)count; |
| |
| if (!cups_raster_read(r, temp, r->bpp)) |
| { |
| DEBUG_puts("1_cupsRasterReadPixels: Read error, returning 0."); |
| return (0); |
| } |
| |
| temp += r->bpp; |
| count -= r->bpp; |
| |
| while (count > 0) |
| { |
| memcpy(temp, temp - r->bpp, r->bpp); |
| temp += r->bpp; |
| count -= r->bpp; |
| } |
| } |
| } |
| |
| /* |
| * Swap bytes as needed... |
| */ |
| |
| if ((r->header.cupsBitsPerColor == 16 || |
| r->header.cupsBitsPerPixel == 12 || |
| r->header.cupsBitsPerPixel == 16) && |
| r->swapped) |
| { |
| DEBUG_puts("1_cupsRasterReadPixels: Swapping bytes."); |
| cups_swap(ptr, (size_t)cupsBytesPerLine); |
| } |
| |
| /* |
| * Update pointers... |
| */ |
| |
| if (remaining >= cupsBytesPerLine) |
| { |
| bytes = (ssize_t)cupsBytesPerLine; |
| r->pcurrent = r->pixels; |
| r->count --; |
| r->remaining --; |
| } |
| else |
| { |
| bytes = (ssize_t)remaining; |
| r->pcurrent = r->pixels + bytes; |
| } |
| |
| /* |
| * Copy data as needed... |
| */ |
| |
| if (ptr != p) |
| memcpy(p, ptr, (size_t)bytes); |
| } |
| else |
| { |
| /* |
| * Copy fragment from buffer... |
| */ |
| |
| if ((unsigned)(bytes = (int)(r->pend - r->pcurrent)) > remaining) |
| bytes = (ssize_t)remaining; |
| |
| memcpy(p, r->pcurrent, (size_t)bytes); |
| r->pcurrent += bytes; |
| |
| if (r->pcurrent >= r->pend) |
| { |
| r->pcurrent = r->pixels; |
| r->count --; |
| r->remaining --; |
| } |
| } |
| |
| remaining -= (unsigned)bytes; |
| p += bytes; |
| } |
| |
| DEBUG_printf(("1_cupsRasterReadPixels: Returning %u", len)); |
| |
| return (len); |
| } |
| |
| |
| /* |
| * '_cupsRasterWriteHeader()' - Write a raster page header. |
| */ |
| |
| unsigned /* O - 1 on success, 0 on failure */ |
| _cupsRasterWriteHeader( |
| cups_raster_t *r) /* I - Raster stream */ |
| { |
| DEBUG_printf(("_cupsRasterWriteHeader(r=%p)", (void *)r)); |
| |
| DEBUG_printf(("1_cupsRasterWriteHeader: cupsColorSpace=%s", _cupsRasterColorSpaceString(r->header.cupsColorSpace))); |
| DEBUG_printf(("1_cupsRasterWriteHeader: cupsBitsPerColor=%u", r->header.cupsBitsPerColor)); |
| DEBUG_printf(("1_cupsRasterWriteHeader: cupsBitsPerPixel=%u", r->header.cupsBitsPerPixel)); |
| DEBUG_printf(("1_cupsRasterWriteHeader: cupsBytesPerLine=%u", r->header.cupsBytesPerLine)); |
| DEBUG_printf(("1_cupsRasterWriteHeader: cupsWidth=%u", r->header.cupsWidth)); |
| DEBUG_printf(("1_cupsRasterWriteHeader: cupsHeight=%u", r->header.cupsHeight)); |
| |
| /* |
| * Compute the number of raster lines in the page image... |
| */ |
| |
| if (!cups_raster_update(r)) |
| { |
| DEBUG_puts("1_cupsRasterWriteHeader: Unable to update parameters, returning 0."); |
| return (0); |
| } |
| |
| if (r->mode == CUPS_RASTER_WRITE_APPLE) |
| { |
| r->rowheight = r->header.HWResolution[0] / r->header.HWResolution[1]; |
| |
| if (r->header.HWResolution[0] != (r->rowheight * r->header.HWResolution[1])) |
| return (0); |
| } |
| else |
| r->rowheight = 1; |
| |
| /* |
| * Write the raster header... |
| */ |
| |
| if (r->mode == CUPS_RASTER_WRITE_PWG) |
| { |
| /* |
| * PWG raster data is always network byte order with much of the page header |
| * zeroed. |
| */ |
| |
| cups_page_header2_t fh; /* File page header */ |
| |
| memset(&fh, 0, sizeof(fh)); |
| strlcpy(fh.MediaClass, "PwgRaster", sizeof(fh.MediaClass)); |
| strlcpy(fh.MediaColor, r->header.MediaColor, sizeof(fh.MediaColor)); |
| strlcpy(fh.MediaType, r->header.MediaType, sizeof(fh.MediaType)); |
| strlcpy(fh.OutputType, r->header.OutputType, sizeof(fh.OutputType)); |
| strlcpy(fh.cupsRenderingIntent, r->header.cupsRenderingIntent, |
| sizeof(fh.cupsRenderingIntent)); |
| strlcpy(fh.cupsPageSizeName, r->header.cupsPageSizeName, |
| sizeof(fh.cupsPageSizeName)); |
| |
| fh.CutMedia = htonl(r->header.CutMedia); |
| fh.Duplex = htonl(r->header.Duplex); |
| fh.HWResolution[0] = htonl(r->header.HWResolution[0]); |
| fh.HWResolution[1] = htonl(r->header.HWResolution[1]); |
| fh.ImagingBoundingBox[0] = htonl(r->header.ImagingBoundingBox[0]); |
| fh.ImagingBoundingBox[1] = htonl(r->header.ImagingBoundingBox[1]); |
| fh.ImagingBoundingBox[2] = htonl(r->header.ImagingBoundingBox[2]); |
| fh.ImagingBoundingBox[3] = htonl(r->header.ImagingBoundingBox[3]); |
| fh.InsertSheet = htonl(r->header.InsertSheet); |
| fh.Jog = htonl(r->header.Jog); |
| fh.LeadingEdge = htonl(r->header.LeadingEdge); |
| fh.ManualFeed = htonl(r->header.ManualFeed); |
| fh.MediaPosition = htonl(r->header.MediaPosition); |
| fh.MediaWeight = htonl(r->header.MediaWeight); |
| fh.NumCopies = htonl(r->header.NumCopies); |
| fh.Orientation = htonl(r->header.Orientation); |
| fh.PageSize[0] = htonl(r->header.PageSize[0]); |
| fh.PageSize[1] = htonl(r->header.PageSize[1]); |
| fh.Tumble = htonl(r->header.Tumble); |
| fh.cupsWidth = htonl(r->header.cupsWidth); |
| fh.cupsHeight = htonl(r->header.cupsHeight); |
| fh.cupsBitsPerColor = htonl(r->header.cupsBitsPerColor); |
| fh.cupsBitsPerPixel = htonl(r->header.cupsBitsPerPixel); |
| fh.cupsBytesPerLine = htonl(r->header.cupsBytesPerLine); |
| fh.cupsColorOrder = htonl(r->header.cupsColorOrder); |
| fh.cupsColorSpace = htonl(r->header.cupsColorSpace); |
| fh.cupsNumColors = htonl(r->header.cupsNumColors); |
| fh.cupsInteger[0] = htonl(r->header.cupsInteger[0]); |
| fh.cupsInteger[1] = htonl(r->header.cupsInteger[1]); |
| fh.cupsInteger[2] = htonl(r->header.cupsInteger[2]); |
| fh.cupsInteger[3] = htonl((unsigned)(r->header.cupsImagingBBox[0] * r->header.HWResolution[0] / 72.0)); |
| fh.cupsInteger[4] = htonl((unsigned)(r->header.cupsImagingBBox[1] * r->header.HWResolution[1] / 72.0)); |
| fh.cupsInteger[5] = htonl((unsigned)(r->header.cupsImagingBBox[2] * r->header.HWResolution[0] / 72.0)); |
| fh.cupsInteger[6] = htonl((unsigned)(r->header.cupsImagingBBox[3] * r->header.HWResolution[1] / 72.0)); |
| fh.cupsInteger[7] = htonl(0xffffff); |
| |
| return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh)); |
| } |
| else if (r->mode == CUPS_RASTER_WRITE_APPLE) |
| { |
| /* |
| * Raw raster data is always network byte order with most of the page header |
| * zeroed. |
| */ |
| |
| int i; /* Looping var */ |
| unsigned char appleheader[32];/* Raw page header */ |
| unsigned height = r->header.cupsHeight * r->rowheight; |
| /* Computed page height */ |
| |
| if (r->apple_page_count == 0xffffffffU) |
| { |
| /* |
| * Write raw page count from raster page header... |
| */ |
| |
| r->apple_page_count = r->header.cupsInteger[0]; |
| |
| appleheader[0] = 'A'; |
| appleheader[1] = 'S'; |
| appleheader[2] = 'T'; |
| appleheader[3] = 0; |
| appleheader[4] = (unsigned char)(r->apple_page_count >> 24); |
| appleheader[5] = (unsigned char)(r->apple_page_count >> 16); |
| appleheader[6] = (unsigned char)(r->apple_page_count >> 8); |
| appleheader[7] = (unsigned char)(r->apple_page_count); |
| |
| if (cups_raster_io(r, appleheader, 8) != 8) |
| return (0); |
| } |
| |
| memset(appleheader, 0, sizeof(appleheader)); |
| |
| appleheader[0] = (unsigned char)r->header.cupsBitsPerPixel; |
| appleheader[1] = r->header.cupsColorSpace == CUPS_CSPACE_SRGB ? 1 : |
| r->header.cupsColorSpace == CUPS_CSPACE_CIELab ? 2 : |
| r->header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ? 3 : |
| r->header.cupsColorSpace == CUPS_CSPACE_W ? 4 : |
| r->header.cupsColorSpace == CUPS_CSPACE_RGB ? 5 : |
| r->header.cupsColorSpace == CUPS_CSPACE_CMYK ? 6 : 0; |
| appleheader[2] = r->header.Duplex ? (r->header.Tumble ? 2 : 3) : 1; |
| appleheader[3] = (unsigned char)(r->header.cupsInteger[CUPS_RASTER_PWG_PrintQuality]); |
| appleheader[5] = (unsigned char)(r->header.MediaPosition); |
| appleheader[12] = (unsigned char)(r->header.cupsWidth >> 24); |
| appleheader[13] = (unsigned char)(r->header.cupsWidth >> 16); |
| appleheader[14] = (unsigned char)(r->header.cupsWidth >> 8); |
| appleheader[15] = (unsigned char)(r->header.cupsWidth); |
| appleheader[16] = (unsigned char)(height >> 24); |
| appleheader[17] = (unsigned char)(height >> 16); |
| appleheader[18] = (unsigned char)(height >> 8); |
| appleheader[19] = (unsigned char)(height); |
| appleheader[20] = (unsigned char)(r->header.HWResolution[0] >> 24); |
| appleheader[21] = (unsigned char)(r->header.HWResolution[0] >> 16); |
| appleheader[22] = (unsigned char)(r->header.HWResolution[0] >> 8); |
| appleheader[23] = (unsigned char)(r->header.HWResolution[0]); |
| |
| for (i = 0; i < (int)(sizeof(apple_media_types) / sizeof(apple_media_types[0])); i ++) |
| { |
| if (!strcmp(r->header.MediaType, apple_media_types[i])) |
| { |
| appleheader[4] = (unsigned char)i; |
| break; |
| } |
| } |
| |
| return (cups_raster_io(r, appleheader, sizeof(appleheader)) == sizeof(appleheader)); |
| } |
| else |
| return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header)) |
| == sizeof(r->header)); |
| } |
| |
| |
| /* |
| * '_cupsRasterWritePixels()' - Write raster pixels. |
| * |
| * For best performance, filters should write one or more whole lines. |
| * The "cupsBytesPerLine" value from the page header can be used to allocate |
| * the line buffer and as the number of bytes to write. |
| */ |
| |
| unsigned /* O - Number of bytes written */ |
| _cupsRasterWritePixels( |
| cups_raster_t *r, /* I - Raster stream */ |
| unsigned char *p, /* I - Bytes to write */ |
| unsigned len) /* I - Number of bytes to write */ |
| { |
| ssize_t bytes; /* Bytes read */ |
| unsigned remaining; /* Bytes remaining */ |
| |
| |
| DEBUG_printf(("_cupsRasterWritePixels(r=%p, p=%p, len=%u), remaining=%u", (void *)r, (void *)p, len, r->remaining)); |
| |
| if (r == NULL || r->mode == CUPS_RASTER_READ || r->remaining == 0) |
| return (0); |
| |
| if (!r->compressed) |
| { |
| /* |
| * Without compression, just write the raster data raw unless the data needs |
| * to be swapped... |
| */ |
| |
| r->remaining -= len / r->header.cupsBytesPerLine; |
| |
| if (r->swapped && |
| (r->header.cupsBitsPerColor == 16 || |
| r->header.cupsBitsPerPixel == 12 || |
| r->header.cupsBitsPerPixel == 16)) |
| { |
| unsigned char *bufptr; /* Pointer into write buffer */ |
| |
| /* |
| * Allocate a write buffer as needed... |
| */ |
| |
| if ((size_t)len > r->bufsize) |
| { |
| if (r->buffer) |
| bufptr = realloc(r->buffer, len); |
| else |
| bufptr = malloc(len); |
| |
| if (!bufptr) |
| return (0); |
| |
| r->buffer = bufptr; |
| r->bufsize = len; |
| } |
| |
| /* |
| * Byte swap the pixels and write them... |
| */ |
| |
| cups_swap_copy(r->buffer, p, len); |
| |
| bytes = cups_raster_io(r, r->buffer, len); |
| } |
| else |
| bytes = cups_raster_io(r, p, len); |
| |
| if (bytes < (ssize_t)len) |
| return (0); |
| else |
| return (len); |
| } |
| |
| /* |
| * Otherwise, compress each line... |
| */ |
| |
| for (remaining = len; remaining > 0; remaining -= (unsigned)bytes, p += bytes) |
| { |
| /* |
| * Figure out the number of remaining bytes on the current line... |
| */ |
| |
| if ((bytes = (ssize_t)remaining) > (ssize_t)(r->pend - r->pcurrent)) |
| bytes = (ssize_t)(r->pend - r->pcurrent); |
| |
| if (r->count > 0) |
| { |
| /* |
| * Check to see if this line is the same as the previous line... |
| */ |
| |
| if (memcmp(p, r->pcurrent, (size_t)bytes)) |
| { |
| if (cups_raster_write(r, r->pixels) <= 0) |
| return (0); |
| |
| r->count = 0; |
| } |
| else |
| { |
| /* |
| * Mark more bytes as the same... |
| */ |
| |
| r->pcurrent += bytes; |
| |
| if (r->pcurrent >= r->pend) |
| { |
| /* |
| * Increase the repeat count... |
| */ |
| |
| r->count += r->rowheight; |
| r->pcurrent = r->pixels; |
| |
| /* |
| * Flush out this line if it is the last one... |
| */ |
| |
| r->remaining --; |
| |
| if (r->remaining == 0) |
| { |
| if (cups_raster_write(r, r->pixels) <= 0) |
| return (0); |
| else |
| return (len); |
| } |
| else if (r->count > (256 - r->rowheight)) |
| { |
| if (cups_raster_write(r, r->pixels) <= 0) |
| return (0); |
| |
| r->count = 0; |
| } |
| } |
| |
| continue; |
| } |
| } |
| |
| if (r->count == 0) |
| { |
| /* |
| * Copy the raster data to the buffer... |
| */ |
| |
| memcpy(r->pcurrent, p, (size_t)bytes); |
| |
| r->pcurrent += bytes; |
| |
| if (r->pcurrent >= r->pend) |
| { |
| /* |
| * Increase the repeat count... |
| */ |
| |
| r->count += r->rowheight; |
| r->pcurrent = r->pixels; |
| |
| /* |
| * Flush out this line if it is the last one... |
| */ |
| |
| r->remaining --; |
| |
| if (r->remaining == 0) |
| { |
| if (cups_raster_write(r, r->pixels) <= 0) |
| return (0); |
| } |
| } |
| } |
| } |
| |
| return (len); |
| } |
| |
| |
| /* |
| * 'cups_raster_io()' - Read/write bytes from a context, handling interruptions. |
| */ |
| |
| static ssize_t /* O - Bytes read/write or -1 */ |
| cups_raster_io(cups_raster_t *r, /* I - Raster stream */ |
| unsigned char *buf, /* I - Buffer for read/write */ |
| size_t bytes) /* I - Number of bytes to read/write */ |
| { |
| ssize_t count, /* Number of bytes read/written */ |
| total; /* Total bytes read/written */ |
| |
| |
| DEBUG_printf(("5cups_raster_io(r=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)r, (void *)buf, CUPS_LLCAST bytes)); |
| |
| for (total = 0; total < (ssize_t)bytes; total += count, buf += count) |
| { |
| count = (*r->iocb)(r->ctx, buf, bytes - (size_t)total); |
| |
| DEBUG_printf(("6cups_raster_io: count=%d, total=%d", (int)count, (int)total)); |
| if (count == 0) |
| break; |
| // { |
| // DEBUG_puts("6cups_raster_io: Returning 0."); |
| // return (0); |
| // } |
| else if (count < 0) |
| { |
| DEBUG_puts("6cups_raster_io: Returning -1 on error."); |
| return (-1); |
| } |
| |
| #ifdef DEBUG |
| r->iocount += (size_t)count; |
| #endif /* DEBUG */ |
| } |
| |
| DEBUG_printf(("6cups_raster_io: iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount)); |
| DEBUG_printf(("6cups_raster_io: Returning " CUPS_LLFMT ".", CUPS_LLCAST total)); |
| |
| return (total); |
| } |
| |
| |
| /* |
| * 'cups_raster_read()' - Read through the raster buffer. |
| */ |
| |
| static ssize_t /* O - Number of bytes read */ |
| cups_raster_read(cups_raster_t *r, /* I - Raster stream */ |
| unsigned char *buf, /* I - Buffer */ |
| size_t bytes) /* I - Number of bytes to read */ |
| { |
| ssize_t count, /* Number of bytes read */ |
| remaining, /* Remaining bytes in buffer */ |
| total; /* Total bytes read */ |
| |
| |
| DEBUG_printf(("4cups_raster_read(r=%p, buf=%p, bytes=" CUPS_LLFMT "), offset=" CUPS_LLFMT, (void *)r, (void *)buf, CUPS_LLCAST bytes, CUPS_LLCAST (r->iostart + r->bufptr - r->buffer))); |
| |
| if (!r->compressed) |
| return (cups_raster_io(r, buf, bytes)); |
| |
| /* |
| * Allocate a read buffer as needed... |
| */ |
| |
| count = (ssize_t)(2 * r->header.cupsBytesPerLine); |
| if (count < 65536) |
| count = 65536; |
| |
| if ((size_t)count > r->bufsize) |
| { |
| ssize_t offset = r->bufptr - r->buffer; |
| /* Offset to current start of buffer */ |
| ssize_t end = r->bufend - r->buffer;/* Offset to current end of buffer */ |
| unsigned char *rptr; /* Pointer in read buffer */ |
| |
| if (r->buffer) |
| rptr = realloc(r->buffer, (size_t)count); |
| else |
| rptr = malloc((size_t)count); |
| |
| if (!rptr) |
| return (0); |
| |
| r->buffer = rptr; |
| r->bufptr = rptr + offset; |
| r->bufend = rptr + end; |
| r->bufsize = (size_t)count; |
| } |
| |
| /* |
| * Loop until we have read everything... |
| */ |
| |
| for (total = 0, remaining = (int)(r->bufend - r->bufptr); |
| total < (ssize_t)bytes; |
| total += count, buf += count) |
| { |
| count = (ssize_t)bytes - total; |
| |
| DEBUG_printf(("5cups_raster_read: count=" CUPS_LLFMT ", remaining=" CUPS_LLFMT ", buf=%p, bufptr=%p, bufend=%p", CUPS_LLCAST count, CUPS_LLCAST remaining, (void *)buf, (void *)r->bufptr, (void *)r->bufend)); |
| |
| if (remaining == 0) |
| { |
| if (count < 16) |
| { |
| /* |
| * Read into the raster buffer and then copy... |
| */ |
| |
| #ifdef DEBUG |
| r->iostart += (size_t)(r->bufend - r->buffer); |
| #endif /* DEBUG */ |
| |
| remaining = (*r->iocb)(r->ctx, r->buffer, r->bufsize); |
| if (remaining <= 0) |
| return (0); |
| |
| r->bufptr = r->buffer; |
| r->bufend = r->buffer + remaining; |
| |
| #ifdef DEBUG |
| r->iocount += (size_t)remaining; |
| #endif /* DEBUG */ |
| } |
| else |
| { |
| /* |
| * Read directly into "buf"... |
| */ |
| |
| count = (*r->iocb)(r->ctx, buf, (size_t)count); |
| |
| if (count <= 0) |
| return (0); |
| |
| #ifdef DEBUG |
| r->iostart += (size_t)count; |
| r->iocount += (size_t)count; |
| #endif /* DEBUG */ |
| |
| continue; |
| } |
| } |
| |
| /* |
| * Copy bytes from raster buffer to "buf"... |
| */ |
| |
| if (count > remaining) |
| count = remaining; |
| |
| if (count == 1) |
| { |
| /* |
| * Copy 1 byte... |
| */ |
| |
| *buf = *(r->bufptr)++; |
| remaining --; |
| } |
| else if (count < 128) |
| { |
| /* |
| * Copy up to 127 bytes without using memcpy(); this is |
| * faster because it avoids an extra function call and is |
| * often further optimized by the compiler... |
| */ |
| |
| unsigned char *bufptr; /* Temporary buffer pointer */ |
| |
| remaining -= count; |
| |
| for (bufptr = r->bufptr; count > 0; count --, total ++) |
| *buf++ = *bufptr++; |
| |
| r->bufptr = bufptr; |
| } |
| else |
| { |
| /* |
| * Use memcpy() for a large read... |
| */ |
| |
| memcpy(buf, r->bufptr, (size_t)count); |
| r->bufptr += count; |
| remaining -= count; |
| } |
| } |
| |
| DEBUG_printf(("5cups_raster_read: Returning %ld", (long)total)); |
| |
| return (total); |
| } |
| |
| |
| /* |
| * 'cups_raster_update()' - Update the raster header and row count for the |
| * current page. |
| */ |
| |
| static int /* O - 1 on success, 0 on failure */ |
| cups_raster_update(cups_raster_t *r) /* I - Raster stream */ |
| { |
| if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1 || |
| r->header.cupsNumColors == 0) |
| { |
| /* |
| * Set the "cupsNumColors" field according to the colorspace... |
| */ |
| |
| switch (r->header.cupsColorSpace) |
| { |
| case CUPS_CSPACE_W : |
| case CUPS_CSPACE_K : |
| case CUPS_CSPACE_WHITE : |
| case CUPS_CSPACE_GOLD : |
| case CUPS_CSPACE_SILVER : |
| case CUPS_CSPACE_SW : |
| r->header.cupsNumColors = 1; |
| break; |
| |
| case CUPS_CSPACE_RGB : |
| case CUPS_CSPACE_CMY : |
| case CUPS_CSPACE_YMC : |
| case CUPS_CSPACE_CIEXYZ : |
| case CUPS_CSPACE_CIELab : |
| case CUPS_CSPACE_SRGB : |
| case CUPS_CSPACE_ADOBERGB : |
| case CUPS_CSPACE_ICC1 : |
| case CUPS_CSPACE_ICC2 : |
| case CUPS_CSPACE_ICC3 : |
| case CUPS_CSPACE_ICC4 : |
| case CUPS_CSPACE_ICC5 : |
| case CUPS_CSPACE_ICC6 : |
| case CUPS_CSPACE_ICC7 : |
| case CUPS_CSPACE_ICC8 : |
| case CUPS_CSPACE_ICC9 : |
| case CUPS_CSPACE_ICCA : |
| case CUPS_CSPACE_ICCB : |
| case CUPS_CSPACE_ICCC : |
| case CUPS_CSPACE_ICCD : |
| case CUPS_CSPACE_ICCE : |
| case CUPS_CSPACE_ICCF : |
| r->header.cupsNumColors = 3; |
| break; |
| |
| case CUPS_CSPACE_RGBA : |
| case CUPS_CSPACE_RGBW : |
| case CUPS_CSPACE_CMYK : |
| case CUPS_CSPACE_YMCK : |
| case CUPS_CSPACE_KCMY : |
| case CUPS_CSPACE_GMCK : |
| case CUPS_CSPACE_GMCS : |
| r->header.cupsNumColors = 4; |
| break; |
| |
| case CUPS_CSPACE_KCMYcm : |
| if (r->header.cupsBitsPerPixel < 8) |
| r->header.cupsNumColors = 6; |
| else |
| r->header.cupsNumColors = 4; |
| break; |
| |
| case CUPS_CSPACE_DEVICE1 : |
| case CUPS_CSPACE_DEVICE2 : |
| case CUPS_CSPACE_DEVICE3 : |
| case CUPS_CSPACE_DEVICE4 : |
| case CUPS_CSPACE_DEVICE5 : |
| case CUPS_CSPACE_DEVICE6 : |
| case CUPS_CSPACE_DEVICE7 : |
| case CUPS_CSPACE_DEVICE8 : |
| case CUPS_CSPACE_DEVICE9 : |
| case CUPS_CSPACE_DEVICEA : |
| case CUPS_CSPACE_DEVICEB : |
| case CUPS_CSPACE_DEVICEC : |
| case CUPS_CSPACE_DEVICED : |
| case CUPS_CSPACE_DEVICEE : |
| case CUPS_CSPACE_DEVICEF : |
| r->header.cupsNumColors = r->header.cupsColorSpace - |
| CUPS_CSPACE_DEVICE1 + 1; |
| break; |
| |
| default : |
| /* Unknown color space */ |
| return (0); |
| } |
| } |
| |
| /* |
| * Set the number of bytes per pixel/color... |
| */ |
| |
| if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED) |
| r->bpp = (r->header.cupsBitsPerPixel + 7) / 8; |
| else |
| r->bpp = (r->header.cupsBitsPerColor + 7) / 8; |
| |
| if (r->bpp == 0) |
| r->bpp = 1; |
| |
| /* |
| * Set the number of remaining rows... |
| */ |
| |
| if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR) |
| r->remaining = r->header.cupsHeight * r->header.cupsNumColors; |
| else |
| r->remaining = r->header.cupsHeight; |
| |
| /* |
| * Allocate the compression buffer... |
| */ |
| |
| if (r->compressed) |
| { |
| if (r->pixels != NULL) |
| free(r->pixels); |
| |
| if ((r->pixels = calloc(r->header.cupsBytesPerLine, 1)) == NULL) |
| { |
| r->pcurrent = NULL; |
| r->pend = NULL; |
| r->count = 0; |
| |
| return (0); |
| } |
| |
| r->pcurrent = r->pixels; |
| r->pend = r->pixels + r->header.cupsBytesPerLine; |
| r->count = 0; |
| } |
| |
| return (1); |
| } |
| |
| |
| /* |
| * 'cups_raster_write()' - Write a row of compressed raster data... |
| */ |
| |
| static ssize_t /* O - Number of bytes written */ |
| cups_raster_write( |
| cups_raster_t *r, /* I - Raster stream */ |
| const unsigned char *pixels) /* I - Pixel data to write */ |
| { |
| const unsigned char *start, /* Start of sequence */ |
| *ptr, /* Current pointer in sequence */ |
| *pend, /* End of raster buffer */ |
| *plast; /* Pointer to last pixel */ |
| unsigned char *wptr; /* Pointer into write buffer */ |
| unsigned bpp, /* Bytes per pixel */ |
| count; /* Count */ |
| _cups_copyfunc_t cf; /* Copy function */ |
| |
| |
| DEBUG_printf(("3cups_raster_write(r=%p, pixels=%p)", (void *)r, (void *)pixels)); |
| |
| /* |
| * Determine whether we need to swap bytes... |
| */ |
| |
| if (r->swapped && (r->header.cupsBitsPerColor == 16 || r->header.cupsBitsPerPixel == 12 || r->header.cupsBitsPerPixel == 16)) |
| { |
| DEBUG_puts("4cups_raster_write: Swapping bytes when writing."); |
| cf = (_cups_copyfunc_t)cups_swap_copy; |
| } |
| else |
| cf = (_cups_copyfunc_t)memcpy; |
| |
| /* |
| * Allocate a write buffer as needed... |
| */ |
| |
| count = r->header.cupsBytesPerLine * 2; |
| if (count < 65536) |
| count = 65536; |
| |
| if ((size_t)count > r->bufsize) |
| { |
| if (r->buffer) |
| wptr = realloc(r->buffer, count); |
| else |
| wptr = malloc(count); |
| |
| if (!wptr) |
| { |
| DEBUG_printf(("4cups_raster_write: Unable to allocate " CUPS_LLFMT " bytes for raster buffer: %s", CUPS_LLCAST count, strerror(errno))); |
| return (-1); |
| } |
| |
| r->buffer = wptr; |
| r->bufsize = count; |
| } |
| |
| /* |
| * Write the row repeat count... |
| */ |
| |
| bpp = r->bpp; |
| pend = pixels + r->header.cupsBytesPerLine; |
| plast = pend - bpp; |
| wptr = r->buffer; |
| *wptr++ = (unsigned char)(r->count - 1); |
| |
| /* |
| * Write using a modified PackBits compression... |
| */ |
| |
| for (ptr = pixels; ptr < pend;) |
| { |
| start = ptr; |
| ptr += bpp; |
| |
| if (ptr == pend) |
| { |
| /* |
| * Encode a single pixel at the end... |
| */ |
| |
| *wptr++ = 0; |
| (*cf)(wptr, start, bpp); |
| wptr += bpp; |
| } |
| else if (!memcmp(start, ptr, bpp)) |
| { |
| /* |
| * Encode a sequence of repeating pixels... |
| */ |
| |
| for (count = 2; count < 128 && ptr < plast; count ++, ptr += bpp) |
| if (memcmp(ptr, ptr + bpp, bpp)) |
| break; |
| |
| *wptr++ = (unsigned char)(count - 1); |
| (*cf)(wptr, ptr, bpp); |
| wptr += bpp; |
| ptr += bpp; |
| } |
| else |
| { |
| /* |
| * Encode a sequence of non-repeating pixels... |
| */ |
| |
| for (count = 1; count < 128 && ptr < plast; count ++, ptr += bpp) |
| if (!memcmp(ptr, ptr + bpp, bpp)) |
| break; |
| |
| if (ptr >= plast && count < 128) |
| { |
| count ++; |
| ptr += bpp; |
| } |
| |
| *wptr++ = (unsigned char)(257 - count); |
| |
| count *= bpp; |
| (*cf)(wptr, start, count); |
| wptr += count; |
| } |
| } |
| |
| DEBUG_printf(("4cups_raster_write: Writing " CUPS_LLFMT " bytes.", CUPS_LLCAST (wptr - r->buffer))); |
| |
| return (cups_raster_io(r, r->buffer, (size_t)(wptr - r->buffer))); |
| } |
| |
| |
| /* |
| * 'cups_swap()' - Swap bytes in raster data... |
| */ |
| |
| static void |
| cups_swap(unsigned char *buf, /* I - Buffer to swap */ |
| size_t bytes) /* I - Number of bytes to swap */ |
| { |
| unsigned char even, odd; /* Temporary variables */ |
| |
| |
| bytes /= 2; |
| |
| while (bytes > 0) |
| { |
| even = buf[0]; |
| odd = buf[1]; |
| buf[0] = odd; |
| buf[1] = even; |
| |
| buf += 2; |
| bytes --; |
| } |
| } |
| |
| |
| /* |
| * 'cups_swap_copy()' - Copy and swap bytes in raster data... |
| */ |
| |
| static void |
| cups_swap_copy( |
| unsigned char *dst, /* I - Destination */ |
| const unsigned char *src, /* I - Source */ |
| size_t bytes) /* I - Number of bytes to swap */ |
| { |
| bytes /= 2; |
| |
| while (bytes > 0) |
| { |
| dst[0] = src[1]; |
| dst[1] = src[0]; |
| |
| dst += 2; |
| src += 2; |
| bytes --; |
| } |
| } |