/* * Image file to raster filter 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: * * main() - Main entry... * blank_line() - Clear a line buffer to the blank value... * format_CMY() - Convert image data to CMY. * format_CMYK() - Convert image data to CMYK. * format_K() - Convert image data to black. * format_KCMY() - Convert image data to KCMY. * format_KCMYcm() - Convert image data to KCMYcm. * format_RGBA() - Convert image data to RGBA/RGBW. * format_W() - Convert image data to luminance. * format_YMC() - Convert image data to YMC. * format_YMCK() - Convert image data to YMCK. * make_lut() - Make a lookup table given gamma and brightness values. * raster_cb() - Validate the page header. */ /* * Include necessary headers... */ #include "common.h" #include #include #include #include #include #include #include /* * Globals... */ int Flip = 0, /* Flip/mirror pages */ XPosition = 0, /* Horizontal position on page */ YPosition = 0, /* Vertical position on page */ Collate = 0, /* Collate copies? */ Copies = 1; /* Number of copies */ int Floyd16x16[16][16] = /* Traditional Floyd ordered dither */ { { 0, 128, 32, 160, 8, 136, 40, 168, 2, 130, 34, 162, 10, 138, 42, 170 }, { 192, 64, 224, 96, 200, 72, 232, 104, 194, 66, 226, 98, 202, 74, 234, 106 }, { 48, 176, 16, 144, 56, 184, 24, 152, 50, 178, 18, 146, 58, 186, 26, 154 }, { 240, 112, 208, 80, 248, 120, 216, 88, 242, 114, 210, 82, 250, 122, 218, 90 }, { 12, 140, 44, 172, 4, 132, 36, 164, 14, 142, 46, 174, 6, 134, 38, 166 }, { 204, 76, 236, 108, 196, 68, 228, 100, 206, 78, 238, 110, 198, 70, 230, 102 }, { 60, 188, 28, 156, 52, 180, 20, 148, 62, 190, 30, 158, 54, 182, 22, 150 }, { 252, 124, 220, 92, 244, 116, 212, 84, 254, 126, 222, 94, 246, 118, 214, 86 }, { 3, 131, 35, 163, 11, 139, 43, 171, 1, 129, 33, 161, 9, 137, 41, 169 }, { 195, 67, 227, 99, 203, 75, 235, 107, 193, 65, 225, 97, 201, 73, 233, 105 }, { 51, 179, 19, 147, 59, 187, 27, 155, 49, 177, 17, 145, 57, 185, 25, 153 }, { 243, 115, 211, 83, 251, 123, 219, 91, 241, 113, 209, 81, 249, 121, 217, 89 }, { 15, 143, 47, 175, 7, 135, 39, 167, 13, 141, 45, 173, 5, 133, 37, 165 }, { 207, 79, 239, 111, 199, 71, 231, 103, 205, 77, 237, 109, 197, 69, 229, 101 }, { 63, 191, 31, 159, 55, 183, 23, 151, 61, 189, 29, 157, 53, 181, 21, 149 }, { 254, 127, 223, 95, 247, 119, 215, 87, 253, 125, 221, 93, 245, 117, 213, 85 } }; int Floyd8x8[8][8] = { { 0, 32, 8, 40, 2, 34, 10, 42 }, { 48, 16, 56, 24, 50, 18, 58, 26 }, { 12, 44, 4, 36, 14, 46, 6, 38 }, { 60, 28, 52, 20, 62, 30, 54, 22 }, { 3, 35, 11, 43, 1, 33, 9, 41 }, { 51, 19, 59, 27, 49, 17, 57, 25 }, { 15, 47, 7, 39, 13, 45, 5, 37 }, { 63, 31, 55, 23, 61, 29, 53, 21 } }; int Floyd4x4[4][4] = { { 0, 8, 2, 10 }, { 12, 4, 14, 6 }, { 3, 11, 1, 9 }, { 15, 7, 13, 5 } }; cups_ib_t OnPixels[256], /* On-pixel LUT */ OffPixels[256]; /* Off-pixel LUT */ /* * Local functions... */ static void blank_line(cups_page_header2_t *header, unsigned char *row); static void format_CMY(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); static void format_CMYK(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); static void format_K(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); static void format_KCMYcm(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); static void format_KCMY(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); #define format_RGB format_CMY static void format_RGBA(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); static void format_W(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); static void format_YMC(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); static void format_YMCK(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); static void make_lut(cups_ib_t *, int, float, float); static int raster_cb(cups_page_header2_t *header, int preferred_bits); /* * 'main()' - Main entry... */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ cups_image_t *img; /* Image to print */ float xprint, /* Printable area */ yprint, xinches, /* Total size in inches */ yinches; float xsize, /* Total size in points */ ysize, xsize2, ysize2; float aspect; /* Aspect ratio */ int xpages, /* # x pages */ ypages, /* # y pages */ xpage, /* Current x page */ ypage, /* Current y page */ xtemp, /* Bitmap width in pixels */ ytemp, /* Bitmap height in pixels */ page; /* Current page number */ int xc0, yc0, /* Corners of the page in image coords */ xc1, yc1; ppd_file_t *ppd; /* PPD file */ ppd_choice_t *choice; /* PPD option choice */ char *resolution, /* Output resolution */ *media_type; /* Media type */ ppd_profile_t *profile; /* Color profile */ ppd_profile_t userprofile; /* User-specified profile */ cups_raster_t *ras; /* Raster stream */ cups_page_header2_t header; /* Page header */ int num_options; /* Number of print options */ cups_option_t *options; /* Print options */ const char *val; /* Option value */ int slowcollate, /* Collate copies the slow way */ slowcopies; /* Make copies the "slow" way? */ float g; /* Gamma correction value */ float b; /* Brightness factor */ float zoom; /* Zoom facter */ int xppi, yppi; /* Pixels-per-inch */ int hue, sat; /* Hue and saturation adjustment */ cups_izoom_t *z; /* Image zoom buffer */ cups_iztype_t zoom_type; /* Image zoom type */ int primary, /* Primary image colorspace */ secondary; /* Secondary image colorspace */ cups_ib_t *row, /* Current row */ *r0, /* Top row */ *r1; /* Bottom row */ int y, /* Current Y coordinate on page */ iy, /* Current Y coordinate in image */ last_iy, /* Previous Y coordinate in image */ yerr0, /* Top Y error value */ yerr1; /* Bottom Y error value */ cups_ib_t lut[256]; /* Gamma/brightness LUT */ int plane, /* Current color plane */ num_planes; /* Number of color planes */ char filename[1024]; /* Name of file to print */ cm_calibration_t cm_calibrate; /* Are we color calibrating the device? */ int cm_disabled; /* Color management disabled? */ int fillprint = 0; /* print-scaling = fill */ int cropfit = 0; /* -o crop-to-fit */ /* * Make sure status messages are not buffered... */ setbuf(stderr, NULL); /* * Ignore broken pipe signals... */ signal(SIGPIPE, SIG_IGN); /* * Check command-line... */ if (argc < 6 || argc > 7) { fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", argv[0]); return (1); } options = NULL; num_options = cupsParseOptions(argv[5], 0, &options); /* * Copy stdin as needed... */ if (argc == 6) { int fd; /* File to write to */ char buffer[8192]; /* Buffer to read into */ int bytes; /* # of bytes to read */ if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) { perror("ERROR: Unable to copy print file"); return (1); } fprintf(stderr, "DEBUG: imagetoraster - copying to temp print file \"%s\".\n", filename); while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) bytes = write(fd, buffer, bytes); close(fd); } else { strncpy(filename, argv[6], sizeof(filename) - 1); filename[sizeof(filename) - 1] = '\0'; } /* * Process command-line options and write the prolog... */ zoom = 1.0; xppi = 0; yppi = 0; hue = 0; sat = 100; g = 1.0; b = 1.0; Copies = atoi(argv[4]); ppd = SetCommonOptions(num_options, options, 0); if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL) { /* * This IPP attribute is unnecessarily complicated... * * single-document, separate-documents-collated-copies, and * single-document-new-sheet all require collated copies. * * separate-documents-collated-copies allows for uncollated copies. */ Collate = strcasecmp(val, "separate-documents-collated-copies") != 0; } if ((val = cupsGetOption("Collate", num_options, options)) != NULL && strcasecmp(val, "True") == 0) Collate = 1; if ((val = cupsGetOption("gamma", num_options, options)) != NULL) { /* * Get gamma value from 1 to 10000... */ g = atoi(val) * 0.001f; if (g < 0.001f) g = 0.001f; else if (g > 10.0f) g = 10.0f; } if ((val = cupsGetOption("brightness", num_options, options)) != NULL) { /* * Get brightness value from 10 to 1000. */ b = atoi(val) * 0.01f; if (b < 0.1f) b = 0.1f; else if (b > 10.0f) b = 10.0f; } if ((val = cupsGetOption("ppi", num_options, options)) != NULL) { if (sscanf(val, "%dx%d", &xppi, &yppi) < 2) yppi = xppi; zoom = 0.0; } if ((val = cupsGetOption("position", num_options, options)) != NULL) { if (strcasecmp(val, "center") == 0) { XPosition = 0; YPosition = 0; } else if (strcasecmp(val, "top") == 0) { XPosition = 0; YPosition = 1; } else if (strcasecmp(val, "left") == 0) { XPosition = -1; YPosition = 0; } else if (strcasecmp(val, "right") == 0) { XPosition = 1; YPosition = 0; } else if (strcasecmp(val, "top-left") == 0) { XPosition = -1; YPosition = 1; } else if (strcasecmp(val, "top-right") == 0) { XPosition = 1; YPosition = 1; } else if (strcasecmp(val, "bottom") == 0) { XPosition = 0; YPosition = -1; } else if (strcasecmp(val, "bottom-left") == 0) { XPosition = -1; YPosition = -1; } else if (strcasecmp(val, "bottom-right") == 0) { XPosition = 1; YPosition = -1; } } if ((val = cupsGetOption("saturation", num_options, options)) != NULL) sat = atoi(val); if ((val = cupsGetOption("hue", num_options, options)) != NULL) hue = atoi(val); if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL) { val = choice->choice; choice->marked = 0; } else val = cupsGetOption("mirror", num_options, options); if (val && (!strcasecmp(val, "true") || !strcasecmp(val, "on") || !strcasecmp(val, "yes"))) Flip = 1; /* * Set the needed options in the page header... */ if (cupsRasterInterpretPPD(&header, ppd, num_options, options, raster_cb)) { fputs("ERROR: The page setup information was not valid.\n", stderr); fprintf(stderr, "DEBUG: %s\n", cupsRasterErrorString()); return (1); } /* * Get the media type and resolution that have been chosen... */ if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL) media_type = choice->choice; else media_type = ""; if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL) resolution = choice->choice; else resolution = ""; /* support the "cm-calibration" option */ cm_calibrate = cmGetCupsColorCalibrateMode(options, num_options); if (cm_calibrate == CM_CALIBRATION_ENABLED) cm_disabled = 1; else cm_disabled = cmIsPrinterCmDisabled(getenv("PRINTER")); /* * Choose the appropriate colorspace... */ switch (header.cupsColorSpace) { case CUPS_CSPACE_W : case CUPS_CSPACE_SW : if (header.cupsBitsPerColor >= 8) { primary = CUPS_IMAGE_WHITE; secondary = CUPS_IMAGE_WHITE; } else { primary = CUPS_IMAGE_BLACK; secondary = CUPS_IMAGE_BLACK; } break; default : case CUPS_CSPACE_RGB : case CUPS_CSPACE_RGBA : case CUPS_CSPACE_RGBW : case CUPS_CSPACE_SRGB : case CUPS_CSPACE_ADOBERGB : if (header.cupsBitsPerColor >= 8) { primary = CUPS_IMAGE_RGB; secondary = CUPS_IMAGE_RGB; } else { primary = CUPS_IMAGE_CMY; secondary = CUPS_IMAGE_CMY; } break; case CUPS_CSPACE_K : case CUPS_CSPACE_WHITE : case CUPS_CSPACE_GOLD : case CUPS_CSPACE_SILVER : primary = CUPS_IMAGE_BLACK; secondary = CUPS_IMAGE_BLACK; break; case CUPS_CSPACE_CMYK : case CUPS_CSPACE_YMCK : case CUPS_CSPACE_KCMY : case CUPS_CSPACE_KCMYcm : case CUPS_CSPACE_GMCK : case CUPS_CSPACE_GMCS : if (header.cupsBitsPerColor == 1) { primary = CUPS_IMAGE_CMY; secondary = CUPS_IMAGE_CMY; } else { primary = CUPS_IMAGE_CMYK; secondary = CUPS_IMAGE_CMYK; } break; case CUPS_CSPACE_CMY : case CUPS_CSPACE_YMC : primary = CUPS_IMAGE_CMY; secondary = CUPS_IMAGE_CMY; break; case CUPS_CSPACE_CIEXYZ : case CUPS_CSPACE_CIELab : 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 : 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 : fprintf(stderr, "DEBUG: Colorspace %d not supported.\n", header.cupsColorSpace); exit(1); break; } /* * Find a color profile matching the current options... */ if ((val = cupsGetOption("profile", num_options, options)) != NULL && !cm_disabled) { profile = &userprofile; sscanf(val, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", &(userprofile.density), &(userprofile.gamma), userprofile.matrix[0] + 0, userprofile.matrix[0] + 1, userprofile.matrix[0] + 2, userprofile.matrix[1] + 0, userprofile.matrix[1] + 1, userprofile.matrix[1] + 2, userprofile.matrix[2] + 0, userprofile.matrix[2] + 1, userprofile.matrix[2] + 2); userprofile.density *= 0.001f; userprofile.gamma *= 0.001f; userprofile.matrix[0][0] *= 0.001f; userprofile.matrix[0][1] *= 0.001f; userprofile.matrix[0][2] *= 0.001f; userprofile.matrix[1][0] *= 0.001f; userprofile.matrix[1][1] *= 0.001f; userprofile.matrix[1][2] *= 0.001f; userprofile.matrix[2][0] *= 0.001f; userprofile.matrix[2][1] *= 0.001f; userprofile.matrix[2][2] *= 0.001f; } else if (ppd != NULL && !cm_disabled) { fprintf(stderr, "DEBUG: Searching for profile \"%s/%s\"...\n", resolution, media_type); for (i = 0, profile = ppd->profiles; i < ppd->num_profiles; i ++, profile ++) { fprintf(stderr, "DEBUG: \"%s/%s\" = ", profile->resolution, profile->media_type); if ((strcmp(profile->resolution, resolution) == 0 || profile->resolution[0] == '-') && (strcmp(profile->media_type, media_type) == 0 || profile->media_type[0] == '-')) { fputs("MATCH\n", stderr); break; } else fputs("no.\n", stderr); } /* * If we found a color profile, use it! */ if (i >= ppd->num_profiles) profile = NULL; } else profile = NULL; if (profile) cupsImageSetProfile(profile->density, profile->gamma, profile->matrix); cupsImageSetRasterColorSpace(header.cupsColorSpace); /* * Create a gamma/brightness LUT... */ make_lut(lut, primary, g, b); /* * Open the input image to print... */ fputs("INFO: Loading print file.\n", stderr); if (header.cupsColorSpace == CUPS_CSPACE_CIEXYZ || header.cupsColorSpace == CUPS_CSPACE_CIELab || header.cupsColorSpace >= CUPS_CSPACE_ICC1) img = cupsImageOpen(filename, primary, secondary, sat, hue, NULL); else img = cupsImageOpen(filename, primary, secondary, sat, hue, lut); if(img!=NULL){ int margin_defined = 0; int fidelity = 0; int document_large = 0; if(ppd != NULL && (ppd->custom_margins[0]||ppd->custom_margins[1] ||ppd->custom_margins[2]||ppd->custom_margins[3])) margin_defined = 1; if(PageLength!=PageTop-PageBottom||PageWidth!=PageRight-PageLeft) { margin_defined = 1; } if((val = cupsGetOption("ipp-attribute-fidelity",num_options,options)) != NULL) { if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")|| !strcasecmp(val,"on")) { fidelity = 1; } } float w = (float)cupsImageGetWidth(img); float h = (float)cupsImageGetHeight(img); float pw = PageRight-PageLeft; float ph = PageTop-PageBottom; int tempOrientation = Orientation; if((val = cupsGetOption("orientation-requested",num_options,options))!=NULL) { tempOrientation = atoi(val); } else if((val = cupsGetOption("landscape",num_options,options))!=NULL) { if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) { tempOrientation = 4; } } if(tempOrientation==0) { if(((pw > ph) && (w < h)) || ((pw < ph) && (w > h))) { tempOrientation = 4; } } if(tempOrientation==4||tempOrientation==5) { int tmp = pw; pw = ph; ph = tmp; } if (w * 72.0 / img->xppi > pw || h * 72.0 / img->yppi > ph) document_large = 1; if((val = cupsGetOption("print-scaling",num_options,options)) != NULL) { if(!strcasecmp(val,"auto")) { if(fidelity||document_large) { if(margin_defined) zoom = 1.0; // fit method else fillprint = 1; // fill method } else cropfit = 1; // none method } else if(!strcasecmp(val,"auto-fit")) { if(fidelity||document_large) zoom = 1.0; // fit method else cropfit = 1; // none method } else if(!strcasecmp(val,"fill")) fillprint = 1; // fill method else if(!strcasecmp(val,"fit")) zoom = 1.0; // fitplot = 1 or fit method else cropfit=1; // none or crop-to-fit } else{ // print-scaling is not defined, look for alternate options. if ((val = cupsGetOption("scaling", num_options, options)) != NULL) zoom = atoi(val) * 0.01; else if (((val = cupsGetOption("fit-to-page", num_options, options)) != NULL) || ((val = cupsGetOption("fitplot", num_options, options)) != NULL)) { if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") || !strcasecmp(val, "true")) zoom = 1.0; else zoom = 0.0; } else if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL) zoom = 0.0; if((val = cupsGetOption("fill",num_options,options))!=0) { if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) { fillprint = 1; } } if((val = cupsGetOption("crop-to-fit",num_options,options))!= NULL){ if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) { cropfit=1; } } } } if(img!=NULL) { if(fillprint||cropfit) { float w = (float)cupsImageGetWidth(img); float h = (float)cupsImageGetHeight(img); /* For cropfit do the math without the unprintable margins to get correct centering, for fillprint, fill the printable area */ float pw = (cropfit ? PageWidth : PageRight-PageLeft); float ph = (cropfit ? PageLength : PageTop-PageBottom); const char *val; int tempOrientation = Orientation; int flag =3; if((val = cupsGetOption("orientation-requested",num_options,options))!=NULL) { tempOrientation = atoi(val); } else if((val = cupsGetOption("landscape",num_options,options))!=NULL) { if(!strcasecmp(val,"true")||!strcasecmp(val,"yes")) { tempOrientation = 4; } } if(tempOrientation>0) { if(tempOrientation==4||tempOrientation==5) { float temp = pw; pw = ph; ph = temp; flag = 4; } } if(tempOrientation==0) { if(((pw > ph) && (w < h)) || ((pw < ph) && (w > h))) { int temp = pw; pw = ph; ph = temp; flag = 4; } } if(fillprint) { // Final width and height of cropped image. float final_w,final_h; if(w*ph/pw <=h){ final_w =w; final_h =w*ph/pw; } else{ final_w = h*pw/ph; final_h = h; } // posw and posh are position of the cropped image along width and height. float posw=(w-final_w)/2,posh=(h-final_h)/2; posw = (1+XPosition)*posw; posh = (1-YPosition)*posh; cups_image_t *img2 = cupsImageCrop(img,posw,posh,final_w,final_h); cupsImageClose(img); img = img2; } else { float final_w=w,final_h=h; if (w > pw * img->xppi / 72.0) final_w = pw * img->xppi / 72.0; if (h > ph * img->yppi / 72.0) final_h = ph * img->yppi / 72.0; float posw=(w-final_w)/2,posh=(h-final_h)/2; posw = (1+XPosition)*posw; posh = (1-YPosition)*posh; /* Check whether the unprintable margins hide away a part of the image, if so, correct the image cut */ if(flag==4) { float margin, cutoff; margin = (PageLength - final_w * 72.0 / img->xppi) / 2; if (margin >= PageBottom) PageBottom = margin; else { cutoff = (PageBottom - margin) * img->xppi / 72.0; final_w -= cutoff; posw += cutoff; } margin = PageBottom + final_w * 72.0 / img->xppi; if (margin <= PageTop) PageTop = margin; else final_w -= (margin - PageTop) * img->xppi / 72.0; margin = (PageWidth - final_h * 72.0 / img->yppi) / 2; if (margin >= PageLeft) PageLeft = margin; else { cutoff = (PageLeft - margin) * img->yppi / 72.0; final_h -= cutoff; posh += cutoff; } margin = PageLeft + final_h * 72.0 / img->yppi; if (margin <= PageRight) PageRight = margin; else final_h -= (margin - PageRight) * img->yppi / 72.0; } else { float margin, cutoff; margin = (PageLength - final_h * 72.0 / img->yppi) / 2; if (margin >= PageBottom) PageBottom = margin; else { cutoff = (PageBottom - margin) * img->yppi / 72.0; final_h -= cutoff; posh += cutoff; } margin = PageBottom + final_h * 72.0 / img->yppi; if (margin <= PageTop) PageTop = margin; else final_h -= (margin - PageTop) * img->yppi / 72.0; margin = (PageWidth - final_w * 72.0 / img->xppi) / 2; if (margin >= PageLeft) PageLeft = margin; else { cutoff = (PageLeft - margin) * img->xppi / 72.0; final_w -= cutoff; posw += cutoff; } margin = PageLeft + final_w * 72.0 / img->xppi; if (margin <= PageRight) PageRight = margin; else final_w -= (margin - PageRight) * img->xppi / 72.0; } if(PageBottom<0) PageBottom = 0; if(PageLeft<0) PageLeft = 0; cups_image_t *img2 = cupsImageCrop(img,posw,posh,final_w,final_h); cupsImageClose(img); img = img2; } } } if (argc == 6) unlink(filename); if (img == NULL) { fputs("ERROR: The print file could not be opened.\n", stderr); ppdClose(ppd); return (1); } /* * Scale as necessary... */ if (zoom == 0.0 && xppi == 0) { xppi = img->xppi; yppi = img->yppi; } if (yppi == 0) yppi = xppi; fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n", xppi, yppi, zoom); if (xppi > 0) { /* * Scale the image as neccesary to match the desired pixels-per-inch. */ if (Orientation & 1) { xprint = (PageTop - PageBottom) / 72.0; yprint = (PageRight - PageLeft) / 72.0; } else { xprint = (PageRight - PageLeft) / 72.0; yprint = (PageTop - PageBottom) / 72.0; } fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n", xprint, yprint); xinches = (float)img->xsize / (float)xppi; yinches = (float)img->ysize / (float)yppi; fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n", xinches, yinches); if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL) { xinches = xinches * atoi(val) / 100; yinches = yinches * atoi(val) / 100; } if (cupsGetOption("orientation-requested", num_options, options) == NULL && cupsGetOption("landscape", num_options, options) == NULL) { /* * Rotate the image if it will fit landscape but not portrait... */ fputs("DEBUG: Auto orientation...\n", stderr); if ((xinches > xprint || yinches > yprint) && xinches <= yprint && yinches <= xprint) { /* * Rotate the image as needed... */ fputs("DEBUG: Using landscape orientation...\n", stderr); Orientation = (Orientation + 1) & 3; xsize = yprint; yprint = xprint; xprint = xsize; } } } else { /* * Scale percentage of page size... */ xprint = (PageRight - PageLeft) / 72.0; yprint = (PageTop - PageBottom) / 72.0; aspect = (float)img->yppi / (float)img->xppi; fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n", xprint, yprint); fprintf(stderr, "DEBUG: img->xppi = %d, img->yppi = %d, aspect = %f\n", img->xppi, img->yppi, aspect); xsize = xprint * zoom; ysize = xsize * img->ysize / img->xsize / aspect; if (ysize > (yprint * zoom)) { ysize = yprint * zoom; xsize = ysize * img->xsize * aspect / img->ysize; } xsize2 = yprint * zoom; ysize2 = xsize2 * img->ysize / img->xsize / aspect; if (ysize2 > (xprint * zoom)) { ysize2 = xprint * zoom; xsize2 = ysize2 * img->xsize * aspect / img->ysize; } fprintf(stderr, "DEBUG: Portrait size is %.2f x %.2f inches\n", xsize, ysize); fprintf(stderr, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2, ysize2); if (cupsGetOption("orientation-requested", num_options, options) == NULL && cupsGetOption("landscape", num_options, options) == NULL) { /* * Choose the rotation with the largest area, but prefer * portrait if they are equal... */ fputs("DEBUG: Auto orientation...\n", stderr); if ((xsize * ysize) < (xsize2 * ysize2)) { /* * Do landscape orientation... */ fputs("DEBUG: Using landscape orientation...\n", stderr); Orientation = 1; xinches = xsize2; yinches = ysize2; xprint = (PageTop - PageBottom) / 72.0; yprint = (PageRight - PageLeft) / 72.0; } else { /* * Do portrait orientation... */ fputs("DEBUG: Using portrait orientation...\n", stderr); Orientation = 0; xinches = xsize; yinches = ysize; } } else if (Orientation & 1) { fputs("DEBUG: Using landscape orientation...\n", stderr); xinches = xsize2; yinches = ysize2; xprint = (PageTop - PageBottom) / 72.0; yprint = (PageRight - PageLeft) / 72.0; } else { fputs("DEBUG: Using portrait orientation...\n", stderr); xinches = xsize; yinches = ysize; xprint = (PageRight - PageLeft) / 72.0; yprint = (PageTop - PageBottom) / 72.0; } } /* * Compute the number of pages to print and the size of the image on each * page... */ xpages = ceil(xinches / xprint); ypages = ceil(yinches / yprint); xprint = xinches / xpages; yprint = yinches / ypages; fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n", xpages, xprint, ypages, yprint); /* * Compute the bitmap size... */ if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL && strcasecmp(choice->choice, "Custom") == 0) { float width, /* New width in points */ length; /* New length in points */ /* * Use the correct width and length for the current orientation... */ if (Orientation & 1) { width = yprint * 72.0; length = xprint * 72.0; } else { width = xprint * 72.0; length = yprint * 72.0; } /* * Add margins to page size... */ width += ppd->custom_margins[0] + ppd->custom_margins[2]; length += ppd->custom_margins[1] + ppd->custom_margins[3]; /* * Enforce minimums... */ if (width < ppd->custom_min[0]) width = ppd->custom_min[0]; if (length < ppd->custom_min[1]) length = ppd->custom_min[1]; fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n", width / 72.0, length / 72.0); /* * Set the new custom size... */ strcpy(header.cupsPageSizeName, "Custom"); header.cupsPageSize[0] = width + 0.5; header.cupsPageSize[1] = length + 0.5; header.PageSize[0] = width + 0.5; header.PageSize[1] = length + 0.5; /* * Update page variables... */ PageWidth = width; PageLength = length; PageLeft = ppd->custom_margins[0]; PageRight = width - ppd->custom_margins[2]; PageBottom = ppd->custom_margins[1]; PageTop = length - ppd->custom_margins[3]; /* * Remove margins from page size... */ width -= ppd->custom_margins[0] + ppd->custom_margins[2]; length -= ppd->custom_margins[1] + ppd->custom_margins[3]; /* * Set the bitmap size... */ header.cupsWidth = width * header.HWResolution[0] / 72.0; header.cupsHeight = length * header.HWResolution[1] / 72.0; } else { /* * Set the bitmap size... */ header.cupsWidth = (Orientation & 1 ? yprint : xprint) * header.HWResolution[0]; header.cupsHeight = (Orientation & 1 ? xprint : yprint) * header.HWResolution[1]; } header.cupsBytesPerLine = (header.cupsBitsPerPixel * header.cupsWidth + 7) / 8; if (header.cupsColorOrder == CUPS_ORDER_BANDED) header.cupsBytesPerLine *= header.cupsNumColors; header.Margins[0] = PageLeft; header.Margins[1] = PageBottom; fprintf(stderr, "DEBUG: PageSize = [%d %d]\n", header.PageSize[0], header.PageSize[1]); fprintf(stderr, "DEBUG: PageLeft = %f, PageRight = %f, PageBottom = %f, PageTop = %f\n", PageLeft, PageRight, PageBottom, PageTop); switch (Orientation) { default : switch (XPosition) { case -1 : header.cupsImagingBBox[0] = PageLeft; header.cupsImagingBBox[2] = PageLeft + xprint * 72; break; default : header.cupsImagingBBox[0] = (PageRight + PageLeft - xprint * 72) / 2; header.cupsImagingBBox[2] = (PageRight + PageLeft + xprint * 72) / 2; break; case 1 : header.cupsImagingBBox[0] = PageRight - xprint * 72; header.cupsImagingBBox[2] = PageRight; break; } switch (YPosition) { case -1 : header.cupsImagingBBox[1] = PageBottom; header.cupsImagingBBox[3] = PageBottom + yprint * 72; break; default : header.cupsImagingBBox[1] = (PageTop + PageBottom - yprint * 72) / 2; header.cupsImagingBBox[3] = (PageTop + PageBottom + yprint * 72) / 2; break; case 1 : header.cupsImagingBBox[1] = PageTop - yprint * 72; header.cupsImagingBBox[3] = PageTop; break; } break; case 1 : switch (XPosition) { case -1 : header.cupsImagingBBox[0] = PageLeft; header.cupsImagingBBox[2] = PageLeft + yprint * 72; break; default : header.cupsImagingBBox[0] = (PageRight + PageLeft - yprint * 72) / 2; header.cupsImagingBBox[2] = (PageRight + PageLeft + yprint * 72) / 2; break; case 1 : header.cupsImagingBBox[0] = PageRight - yprint * 72; header.cupsImagingBBox[2] = PageRight; break; } switch (YPosition) { case -1 : header.cupsImagingBBox[1] = PageBottom; header.cupsImagingBBox[3] = PageBottom + xprint * 72; break; default : header.cupsImagingBBox[1] = (PageTop + PageBottom - xprint * 72) / 2; header.cupsImagingBBox[3] = (PageTop + PageBottom + xprint * 72) / 2; break; case 1 : header.cupsImagingBBox[1] = PageTop - xprint * 72; header.cupsImagingBBox[3] = PageTop; break; } break; case 2 : switch (XPosition) { case 1 : header.cupsImagingBBox[0] = PageLeft; header.cupsImagingBBox[2] = PageLeft + xprint * 72; break; default : header.cupsImagingBBox[0] = (PageRight + PageLeft - xprint * 72) / 2; header.cupsImagingBBox[2] = (PageRight + PageLeft + xprint * 72) / 2; break; case -1 : header.cupsImagingBBox[0] = PageRight - xprint * 72; header.cupsImagingBBox[2] = PageRight; break; } switch (YPosition) { case 1 : header.cupsImagingBBox[1] = PageBottom; header.cupsImagingBBox[3] = PageBottom + yprint * 72; break; default : header.cupsImagingBBox[1] = (PageTop + PageBottom - yprint * 72) / 2; header.cupsImagingBBox[3] = (PageTop + PageBottom + yprint * 72) / 2; break; case -1 : header.cupsImagingBBox[1] = PageTop - yprint * 72; header.cupsImagingBBox[3] = PageTop; break; } break; case 3 : switch (XPosition) { case 1 : header.cupsImagingBBox[0] = PageLeft; header.cupsImagingBBox[2] = PageLeft + yprint * 72; break; default : header.cupsImagingBBox[0] = (PageRight + PageLeft - yprint * 72) / 2; header.cupsImagingBBox[2] = (PageRight + PageLeft + yprint * 72) / 2; break; case -1 : header.cupsImagingBBox[0] = PageRight - yprint * 72; header.cupsImagingBBox[2] = PageRight; break; } switch (YPosition) { case 1 : header.cupsImagingBBox[1] = PageBottom; header.cupsImagingBBox[3] = PageBottom + xprint * 72; break; default : header.cupsImagingBBox[1] = (PageTop + PageBottom - xprint * 72) / 2; header.cupsImagingBBox[3] = (PageTop + PageBottom + xprint * 72) / 2; break; case -1 : header.cupsImagingBBox[1] = PageTop - xprint * 72; header.cupsImagingBBox[3] = PageTop; break; } break; } header.ImagingBoundingBox[0] = header.cupsImagingBBox[0]; header.ImagingBoundingBox[1] = header.cupsImagingBBox[1]; header.ImagingBoundingBox[2] = header.cupsImagingBBox[2]; header.ImagingBoundingBox[3] = header.cupsImagingBBox[3]; fprintf(stderr, "DEBUG: Orientation: %d, XPosition: %d, YPosition: %d, ImagingBoundingBox = [%d %d %d %d]\n", Orientation, XPosition, YPosition, header.ImagingBoundingBox[0], header.ImagingBoundingBox[1], header.ImagingBoundingBox[2], header.ImagingBoundingBox[3]); if (header.cupsColorOrder == CUPS_ORDER_PLANAR) num_planes = header.cupsNumColors; else num_planes = 1; if (header.cupsBitsPerColor >= 8) zoom_type = CUPS_IZOOM_NORMAL; else zoom_type = CUPS_IZOOM_FAST; /* * See if we need to collate, and if so how we need to do it... */ if (xpages == 1 && ypages == 1) Collate = 0; slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL; if (ppd != NULL) slowcopies = ppd->manual_copies; else slowcopies = 1; if (Copies > 1 && !slowcollate && !slowcopies) { header.Collate = (cups_bool_t)Collate; header.NumCopies = Copies; Copies = 1; } else header.NumCopies = 1; /* * Create the dithering lookup tables... */ OnPixels[0] = 0x00; OnPixels[255] = 0xff; OffPixels[0] = 0x00; OffPixels[255] = 0xff; switch (header.cupsBitsPerColor) { case 2 : for (i = 1; i < 255; i ++) { OnPixels[i] = 0x55 * (i / 85 + 1); OffPixels[i] = 0x55 * (i / 64); } break; case 4 : for (i = 1; i < 255; i ++) { OnPixels[i] = 17 * (i / 17 + 1); OffPixels[i] = 17 * (i / 16); } break; } /* * Output the pages... */ fprintf(stderr, "DEBUG: cupsWidth = %d\n", header.cupsWidth); fprintf(stderr, "DEBUG: cupsHeight = %d\n", header.cupsHeight); fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header.cupsBitsPerColor); fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header.cupsBitsPerPixel); fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header.cupsBytesPerLine); fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header.cupsColorOrder); fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header.cupsColorSpace); fprintf(stderr, "DEBUG: img->colorspace = %d\n", img->colorspace); row = malloc(2 * header.cupsBytesPerLine); ras = cupsRasterOpen(1, CUPS_RASTER_WRITE); for (i = 0, page = 1; i < Copies; i ++) for (xpage = 0; xpage < xpages; xpage ++) for (ypage = 0; ypage < ypages; ypage ++, page ++) { fprintf(stderr, "INFO: Formatting page %d.\n", page); if (Orientation & 1) { xc0 = img->xsize * ypage / ypages; xc1 = img->xsize * (ypage + 1) / ypages - 1; yc0 = img->ysize * xpage / xpages; yc1 = img->ysize * (xpage + 1) / xpages - 1; xtemp = header.HWResolution[0] * yprint; ytemp = header.HWResolution[1] * xprint; } else { xc0 = img->xsize * xpage / xpages; xc1 = img->xsize * (xpage + 1) / xpages - 1; yc0 = img->ysize * ypage / ypages; yc1 = img->ysize * (ypage + 1) / ypages - 1; xtemp = header.HWResolution[0] * xprint; ytemp = header.HWResolution[1] * yprint; } cupsRasterWriteHeader2(ras, &header); for (plane = 0; plane < num_planes; plane ++) { /* * Initialize the image "zoom" engine... */ if (Flip) z = _cupsImageZoomNew(img, xc0, yc0, xc1, yc1, -xtemp, ytemp, Orientation & 1, zoom_type); else z = _cupsImageZoomNew(img, xc0, yc0, xc1, yc1, xtemp, ytemp, Orientation & 1, zoom_type); /* * Write leading blank space as needed... */ if (header.cupsHeight > z->ysize && YPosition <= 0) { blank_line(&header, row); y = header.cupsHeight - z->ysize; if (YPosition == 0) y /= 2; fprintf(stderr, "DEBUG: Writing %d leading blank lines...\n", y); for (; y > 0; y --) { if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) < header.cupsBytesPerLine) { fputs("ERROR: Unable to send raster data to the driver.\n", stderr); cupsImageClose(img); exit(1); } } } /* * Then write image data... */ for (y = z->ysize, yerr0 = 0, yerr1 = z->ysize, iy = 0, last_iy = -2; y > 0; y --) { if (iy != last_iy) { if (zoom_type != CUPS_IZOOM_FAST && (iy - last_iy) > 1) _cupsImageZoomFill(z, iy); _cupsImageZoomFill(z, iy + z->yincr); last_iy = iy; } /* * Format this line of raster data for the printer... */ blank_line(&header, row); r0 = z->rows[z->row]; r1 = z->rows[1 - z->row]; switch (header.cupsColorSpace) { case CUPS_CSPACE_W : case CUPS_CSPACE_SW : format_W(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; default : case CUPS_CSPACE_RGB : case CUPS_CSPACE_SRGB : case CUPS_CSPACE_ADOBERGB : format_RGB(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; case CUPS_CSPACE_RGBA : case CUPS_CSPACE_RGBW : format_RGBA(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; case CUPS_CSPACE_K : case CUPS_CSPACE_WHITE : case CUPS_CSPACE_GOLD : case CUPS_CSPACE_SILVER : format_K(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; case CUPS_CSPACE_CMY : format_CMY(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; case CUPS_CSPACE_YMC : format_YMC(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; case CUPS_CSPACE_CMYK : format_CMYK(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; case CUPS_CSPACE_YMCK : case CUPS_CSPACE_GMCK : case CUPS_CSPACE_GMCS : format_YMCK(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; case CUPS_CSPACE_KCMYcm : if (header.cupsBitsPerColor == 1) { format_KCMYcm(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; } case CUPS_CSPACE_KCMY : format_KCMY(&header, row, y, plane, z->xsize, z->ysize, yerr0, yerr1, r0, r1); break; } /* * Write the raster data to the driver... */ if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) < header.cupsBytesPerLine) { fputs("ERROR: Unable to send raster data to the driver.\n", stderr); cupsImageClose(img); exit(1); } /* * Compute the next scanline in the image... */ iy += z->ystep; yerr0 += z->ymod; yerr1 -= z->ymod; if (yerr1 <= 0) { yerr0 -= z->ysize; yerr1 += z->ysize; iy += z->yincr; } } /* * Write trailing blank space as needed... */ if (header.cupsHeight > z->ysize && YPosition >= 0) { blank_line(&header, row); y = header.cupsHeight - z->ysize; if (YPosition == 0) y = y - y / 2; fprintf(stderr, "DEBUG: Writing %d trailing blank lines...\n", y); for (; y > 0; y --) { if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) < header.cupsBytesPerLine) { fputs("ERROR: Unable to send raster data to the driver.\n", stderr); cupsImageClose(img); exit(1); } } } /* * Free memory used for the "zoom" engine... */ _cupsImageZoomDelete(z); } } /* * Close files... */ free(row); cupsRasterClose(ras); cupsImageClose(img); ppdClose(ppd); return (0); } /* * 'blank_line()' - Clear a line buffer to the blank value... */ static void blank_line(cups_page_header2_t *header, /* I - Page header */ unsigned char *row) /* I - Row buffer */ { int count; /* Remaining bytes */ count = header->cupsBytesPerLine; switch (header->cupsColorSpace) { case CUPS_CSPACE_CIEXYZ : while (count > 2) { *row++ = 242; *row++ = 255; *row++ = 255; count -= 3; } break; case CUPS_CSPACE_CIELab : 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 : while (count > 2) { *row++ = 255; *row++ = 128; *row++ = 128; count -= 3; } break; case CUPS_CSPACE_K : case CUPS_CSPACE_CMY : case CUPS_CSPACE_CMYK : case CUPS_CSPACE_YMC : case CUPS_CSPACE_YMCK : case CUPS_CSPACE_KCMY : case CUPS_CSPACE_KCMYcm : case CUPS_CSPACE_GMCK : case CUPS_CSPACE_GMCS : case CUPS_CSPACE_WHITE : case CUPS_CSPACE_GOLD : case CUPS_CSPACE_SILVER : memset(row, 0, count); break; default : memset(row, 255, count); break; } } /* * 'format_CMY()' - Convert image data to CMY. */ static void format_CMY(cups_page_header2_t *header, /* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { cups_ib_t *ptr, /* Pointer into row */ *cptr, /* Pointer into cyan */ *mptr, /* Pointer into magenta */ *yptr, /* Pointer into yellow */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int bandwidth; /* Width of a color band */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; bandwidth = header->cupsBytesPerLine / 3; switch (header->cupsColorOrder) { case CUPS_ORDER_CHUNKED : switch (header->cupsBitsPerColor) { case 1 : bitmask = 64 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize ; x > 0; x --) { if (*r0++ > dither[x & 15]) *ptr ^= bitmask; bitmask >>= 1; if (*r0++ > dither[x & 15]) *ptr ^= bitmask; bitmask >>= 1; if (*r0++ > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 2; else { bitmask = 64; ptr ++; } } break; case 2 : dither = Floyd8x8[y & 7]; for (x = xsize ; x > 0; x --, r0 += 3) { if ((r0[0] & 63) > dither[x & 7]) *ptr ^= (0x30 & OnPixels[r0[0]]); else *ptr ^= (0x30 & OffPixels[r0[0]]); if ((r0[1] & 63) > dither[x & 7]) *ptr ^= (0x0c & OnPixels[r0[1]]); else *ptr ^= (0x0c & OffPixels[r0[1]]); if ((r0[2] & 63) > dither[x & 7]) *ptr++ ^= (0x03 & OnPixels[r0[2]]); else *ptr++ ^= (0x03 & OffPixels[r0[2]]); } break; case 4 : dither = Floyd4x4[y & 3]; for (x = xsize ; x > 0; x --, r0 += 3) { if ((r0[0] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[0]]); else *ptr++ ^= (0x0f & OffPixels[r0[0]]); if ((r0[1] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[1]]); else *ptr ^= (0xf0 & OffPixels[r0[1]]); if ((r0[2] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[2]]); else *ptr++ ^= (0x0f & OffPixels[r0[2]]); } break; case 8 : for (x = xsize * 3; x > 0; x --, r0 ++, r1 ++) if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; break; } break; case CUPS_ORDER_BANDED : cptr = ptr; mptr = ptr + bandwidth; yptr = ptr + 2 * bandwidth; switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { if (*r0++ > dither[x & 15]) *cptr ^= bitmask; if (*r0++ > dither[x & 15]) *mptr ^= bitmask; if (*r0++ > dither[x & 15]) *yptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; cptr ++; mptr ++; yptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; for (x = xsize; x > 0; x --) { if ((*r0 & 63) > dither[x & 7]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; cptr ++; mptr ++; yptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; for (x = xsize; x > 0; x --) { if ((*r0 & 15) > dither[x & 3]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; cptr ++; mptr ++; yptr ++; } } break; case 8 : for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) { if (r0[0] == r1[0]) *cptr++ = r0[0]; else *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[1] == r1[1]) *mptr++ = r0[1]; else *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[2] == r1[2]) *yptr++ = r0[2]; else *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; } break; } break; case CUPS_ORDER_PLANAR : switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; switch (z) { case 0 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[0] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 1 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[1] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 2 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[2] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; r0 += z; for (x = xsize; x > 0; x --, r0 += 3) { if ((*r0 & 63) > dither[x & 7]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; ptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; r0 += z; for (x = xsize; x > 0; x --, r0 += 3) { if ((*r0 & 15) > dither[x & 3]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; ptr ++; } } break; case 8 : r0 += z; r1 += z; for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) { if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; } break; } break; } } /* * 'format_CMYK()' - Convert image data to CMYK. */ static void format_CMYK(cups_page_header2_t *header,/* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { cups_ib_t *ptr, /* Pointer into row */ *cptr, /* Pointer into cyan */ *mptr, /* Pointer into magenta */ *yptr, /* Pointer into yellow */ *kptr, /* Pointer into black */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int bandwidth; /* Width of a color band */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ int pc, pm, py; /* CMY pixels */ switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; bandwidth = header->cupsBytesPerLine / 4; switch (header->cupsColorOrder) { case CUPS_ORDER_CHUNKED : switch (header->cupsBitsPerColor) { case 1 : bitmask = 128 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize ; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if (pc && pm && py) { bitmask >>= 3; *ptr ^= bitmask; } else { if (pc) *ptr ^= bitmask; bitmask >>= 1; if (pm) *ptr ^= bitmask; bitmask >>= 1; if (py) *ptr ^= bitmask; bitmask >>= 1; } if (bitmask > 1) bitmask >>= 1; else { bitmask = 128; ptr ++; } } break; case 2 : dither = Floyd8x8[y & 7]; for (x = xsize ; x > 0; x --, r0 += 4) { if ((r0[0] & 63) > dither[x & 7]) *ptr ^= (0xc0 & OnPixels[r0[0]]); else *ptr ^= (0xc0 & OffPixels[r0[0]]); if ((r0[1] & 63) > dither[x & 7]) *ptr ^= (0x30 & OnPixels[r0[1]]); else *ptr ^= (0x30 & OffPixels[r0[1]]); if ((r0[2] & 63) > dither[x & 7]) *ptr ^= (0x0c & OnPixels[r0[2]]); else *ptr ^= (0x0c & OffPixels[r0[2]]); if ((r0[3] & 63) > dither[x & 7]) *ptr++ ^= (0x03 & OnPixels[r0[3]]); else *ptr++ ^= (0x03 & OffPixels[r0[3]]); } break; case 4 : dither = Floyd4x4[y & 3]; for (x = xsize ; x > 0; x --, r0 += 4) { if ((r0[0] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[0]]); else *ptr ^= (0xf0 & OffPixels[r0[0]]); if ((r0[1] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[1]]); else *ptr++ ^= (0x0f & OffPixels[r0[1]]); if ((r0[2] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[2]]); else *ptr ^= (0xf0 & OffPixels[r0[2]]); if ((r0[3] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[3]]); else *ptr++ ^= (0x0f & OffPixels[r0[3]]); } break; case 8 : for (x = xsize * 4; x > 0; x --, r0 ++, r1 ++) if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; break; } break; case CUPS_ORDER_BANDED : cptr = ptr; mptr = ptr + bandwidth; yptr = ptr + 2 * bandwidth; kptr = ptr + 3 * bandwidth; switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if (pc && pm && py) *kptr ^= bitmask; else { if (pc) *cptr ^= bitmask; if (pm) *mptr ^= bitmask; if (py) *yptr ^= bitmask; } if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; for (x = xsize; x > 0; x --) { if ((*r0 & 63) > dither[x & 7]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *kptr ^= (bitmask & OnPixels[*r0++]); else *kptr ^= (bitmask & OffPixels[*r0++]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; for (x = xsize; x > 0; x --) { if ((*r0 & 15) > dither[x & 3]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *kptr ^= (bitmask & OnPixels[*r0++]); else *kptr ^= (bitmask & OffPixels[*r0++]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 8 : for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) { if (r0[0] == r1[0]) *cptr++ = r0[0]; else *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[1] == r1[1]) *mptr++ = r0[1]; else *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[2] == r1[2]) *yptr++ = r0[2]; else *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; if (r0[3] == r1[3]) *kptr++ = r0[3]; else *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; } break; } break; case CUPS_ORDER_PLANAR : switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if ((pc && pm && py && z == 3) || (pc && z == 0) || (pm && z == 1) || (py && z == 2)) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; r0 += z; for (x = xsize; x > 0; x --, r0 += 4) { if ((*r0 & 63) > dither[x & 7]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; ptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; r0 += z; for (x = xsize; x > 0; x --, r0 += 4) { if ((*r0 & 15) > dither[x & 3]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; ptr ++; } } break; case 8 : r0 += z; r1 += z; for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) { if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; } break; } break; } } /* * 'format_K()' - Convert image data to black. */ static void format_K(cups_page_header2_t *header, /* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { cups_ib_t *ptr, /* Pointer into row */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ (void)z; switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { if (*r0++ > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; for (x = xsize; x > 0; x --) { if ((*r0 & 63) > dither[x & 7]) *ptr ^= (bitmask & OnPixels[*r0++]); else *ptr ^= (bitmask & OffPixels[*r0++]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; ptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; for (x = xsize; x > 0; x --) { if ((*r0 & 15) > dither[x & 3]) *ptr ^= (bitmask & OnPixels[*r0++]); else *ptr ^= (bitmask & OffPixels[*r0++]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; ptr ++; } } break; case 8 : for (x = xsize; x > 0; x --, r0 ++, r1 ++) { if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; } break; } } /* * 'format_KCMY()' - Convert image data to KCMY. */ static void format_KCMY(cups_page_header2_t *header,/* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { cups_ib_t *ptr, /* Pointer into row */ *cptr, /* Pointer into cyan */ *mptr, /* Pointer into magenta */ *yptr, /* Pointer into yellow */ *kptr, /* Pointer into black */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int bandwidth; /* Width of a color band */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ int pc, pm, py; /* CMY pixels */ switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; bandwidth = header->cupsBytesPerLine / 4; switch (header->cupsColorOrder) { case CUPS_ORDER_CHUNKED : switch (header->cupsBitsPerColor) { case 1 : bitmask = 128 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize ; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if (pc && pm && py) { *ptr ^= bitmask; bitmask >>= 3; } else { bitmask >>= 1; if (pc) *ptr ^= bitmask; bitmask >>= 1; if (pm) *ptr ^= bitmask; bitmask >>= 1; if (py) *ptr ^= bitmask; } if (bitmask > 1) bitmask >>= 1; else { bitmask = 128; ptr ++; } } break; case 2 : dither = Floyd8x8[y & 7]; for (x = xsize ; x > 0; x --, r0 += 4) { if ((r0[3] & 63) > dither[x & 7]) *ptr ^= (0xc0 & OnPixels[r0[3]]); else *ptr ^= (0xc0 & OffPixels[r0[3]]); if ((r0[0] & 63) > dither[x & 7]) *ptr ^= (0x30 & OnPixels[r0[0]]); else *ptr ^= (0x30 & OffPixels[r0[0]]); if ((r0[1] & 63) > dither[x & 7]) *ptr ^= (0x0c & OnPixels[r0[1]]); else *ptr ^= (0x0c & OffPixels[r0[1]]); if ((r0[2] & 63) > dither[x & 7]) *ptr++ ^= (0x03 & OnPixels[r0[2]]); else *ptr++ ^= (0x03 & OffPixels[r0[2]]); } break; case 4 : dither = Floyd4x4[y & 3]; for (x = xsize ; x > 0; x --, r0 += 4) { if ((r0[3] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[3]]); else *ptr ^= (0xf0 & OffPixels[r0[3]]); if ((r0[0] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[0]]); else *ptr++ ^= (0x0f & OffPixels[r0[0]]); if ((r0[1] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[1]]); else *ptr ^= (0xf0 & OffPixels[r0[1]]); if ((r0[2] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[2]]); else *ptr++ ^= (0x0f & OffPixels[r0[2]]); } break; case 8 : for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) { if (r0[3] == r1[3]) *ptr++ = r0[3]; else *ptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; if (r0[0] == r1[0]) *ptr++ = r0[0]; else *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[1] == r1[1]) *ptr++ = r0[1]; else *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[2] == r1[2]) *ptr++ = r0[2]; else *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; } break; } break; case CUPS_ORDER_BANDED : kptr = ptr; cptr = ptr + bandwidth; mptr = ptr + 2 * bandwidth; yptr = ptr + 3 * bandwidth; switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if (pc && pm && py) *kptr ^= bitmask; else { if (pc) *cptr ^= bitmask; if (pm) *mptr ^= bitmask; if (py) *yptr ^= bitmask; } if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; for (x = xsize; x > 0; x --) { if ((*r0 & 63) > dither[x & 7]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *kptr ^= (bitmask & OnPixels[*r0++]); else *kptr ^= (bitmask & OffPixels[*r0++]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; for (x = xsize; x > 0; x --) { if ((*r0 & 15) > dither[x & 3]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *kptr ^= (bitmask & OnPixels[*r0++]); else *kptr ^= (bitmask & OffPixels[*r0++]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 8 : for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) { if (r0[0] == r1[0]) *cptr++ = r0[0]; else *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[1] == r1[1]) *mptr++ = r0[1]; else *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[2] == r1[2]) *yptr++ = r0[2]; else *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; if (r0[3] == r1[3]) *kptr++ = r0[3]; else *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; } break; } break; case CUPS_ORDER_PLANAR : switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if ((pc && pm && py && z == 0) || (pc && z == 1) || (pm && z == 2) || (py && z == 3)) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; if (z == 0) r0 += 3; else r0 += z - 1; for (x = xsize; x > 0; x --, r0 += 4) { if ((*r0 & 63) > dither[x & 7]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; ptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; if (z == 0) r0 += 3; else r0 += z - 1; for (x = xsize; x > 0; x --, r0 += 4) { if ((*r0 & 15) > dither[x & 3]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; ptr ++; } } break; case 8 : if (z == 0) { r0 += 3; r1 += 3; } else { r0 += z - 1; r1 += z - 1; } for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) { if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; } break; } break; } } /* * 'format_KCMYcm()' - Convert image data to KCMYcm. */ static void format_KCMYcm( cups_page_header2_t *header, /* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { int pc, pm, py, pk; /* Cyan, magenta, yellow, and black values */ cups_ib_t *ptr, /* Pointer into row */ *cptr, /* Pointer into cyan */ *mptr, /* Pointer into magenta */ *yptr, /* Pointer into yellow */ *kptr, /* Pointer into black */ *lcptr, /* Pointer into light cyan */ *lmptr, /* Pointer into light magenta */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int bandwidth; /* Width of a color band */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; bandwidth = header->cupsBytesPerLine / 6; switch (header->cupsColorOrder) { case CUPS_ORDER_CHUNKED : dither = Floyd16x16[y & 15]; for (x = xsize ; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; pk = pc && pm && py; if (pk) *ptr++ ^= 32; /* Black */ else if (pc && pm) *ptr++ ^= 17; /* Blue (cyan + light magenta) */ else if (pc && py) *ptr++ ^= 6; /* Green (light cyan + yellow) */ else if (pm && py) *ptr++ ^= 12; /* Red (magenta + yellow) */ else if (pc) *ptr++ ^= 16; else if (pm) *ptr++ ^= 8; else if (py) *ptr++ ^= 4; else ptr ++; } break; case CUPS_ORDER_BANDED : kptr = ptr; cptr = ptr + bandwidth; mptr = ptr + 2 * bandwidth; yptr = ptr + 3 * bandwidth; lcptr = ptr + 4 * bandwidth; lmptr = ptr + 5 * bandwidth; bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; pk = pc && pm && py; if (pk) *kptr ^= bitmask; /* Black */ else if (pc && pm) { *cptr ^= bitmask; /* Blue (cyan + light magenta) */ *lmptr ^= bitmask; } else if (pc && py) { *lcptr ^= bitmask; /* Green (light cyan + yellow) */ *yptr ^= bitmask; } else if (pm && py) { *mptr ^= bitmask; /* Red (magenta + yellow) */ *yptr ^= bitmask; } else if (pc) *cptr ^= bitmask; else if (pm) *mptr ^= bitmask; else if (py) *yptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; cptr ++; mptr ++; yptr ++; kptr ++; lcptr ++; lmptr ++; } } break; case CUPS_ORDER_PLANAR : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; pk = pc && pm && py; if (pk && z == 0) *ptr ^= bitmask; else if (pc && pm && (z == 1 || z == 5)) *ptr ^= bitmask; /* Blue (cyan + light magenta) */ else if (pc && py && (z == 3 || z == 4)) *ptr ^= bitmask; /* Green (light cyan + yellow) */ else if (pm && py && (z == 2 || z == 3)) *ptr ^= bitmask; /* Red (magenta + yellow) */ else if (pc && z == 1) *ptr ^= bitmask; else if (pm && z == 2) *ptr ^= bitmask; else if (py && z == 3) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; } } /* * 'format_RGBA()' - Convert image data to RGBA/RGBW. */ static void format_RGBA(cups_page_header2_t *header,/* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { cups_ib_t *ptr, /* Pointer into row */ *cptr, /* Pointer into cyan */ *mptr, /* Pointer into magenta */ *yptr, /* Pointer into yellow */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int bandwidth; /* Width of a color band */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; bandwidth = header->cupsBytesPerLine / 4; switch (header->cupsColorOrder) { case CUPS_ORDER_CHUNKED : switch (header->cupsBitsPerColor) { case 1 : bitmask = 128 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize ; x > 0; x --) { if (*r0++ > dither[x & 15]) *ptr ^= bitmask; bitmask >>= 1; if (*r0++ > dither[x & 15]) *ptr ^= bitmask; bitmask >>= 1; if (*r0++ > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 2) bitmask >>= 2; else { bitmask = 128; ptr ++; } } break; case 2 : dither = Floyd8x8[y & 7]; for (x = xsize ; x > 0; x --, r0 += 3) { if ((r0[0] & 63) > dither[x & 7]) *ptr ^= (0xc0 & OnPixels[r0[0]]); else *ptr ^= (0xc0 & OffPixels[r0[0]]); if ((r0[1] & 63) > dither[x & 7]) *ptr ^= (0x30 & OnPixels[r0[1]]); else *ptr ^= (0x30 & OffPixels[r0[1]]); if ((r0[2] & 63) > dither[x & 7]) *ptr ^= (0x0c & OnPixels[r0[2]]); else *ptr ^= (0x0c & OffPixels[r0[2]]); ptr ++; } break; case 4 : dither = Floyd4x4[y & 3]; for (x = xsize ; x > 0; x --, r0 += 3) { if ((r0[0] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[0]]); else *ptr ^= (0xf0 & OffPixels[r0[0]]); if ((r0[1] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[1]]); else *ptr++ ^= (0x0f & OffPixels[r0[1]]); if ((r0[2] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[2]]); else *ptr ^= (0xf0 & OffPixels[r0[2]]); ptr ++; } break; case 8 : for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) { if (r0[0] == r1[0]) *ptr++ = r0[0]; else *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[1] == r1[1]) *ptr++ = r0[1]; else *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[2] == r1[2]) *ptr++ = r0[2]; else *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; ptr ++; } break; } break; case CUPS_ORDER_BANDED : cptr = ptr; mptr = ptr + bandwidth; yptr = ptr + 2 * bandwidth; memset(ptr + 3 * bandwidth, 255, bandwidth); switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { if (*r0++ > dither[x & 15]) *cptr ^= bitmask; if (*r0++ > dither[x & 15]) *mptr ^= bitmask; if (*r0++ > dither[x & 15]) *yptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; cptr ++; mptr ++; yptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; for (x = xsize; x > 0; x --) { if ((*r0 & 63) > dither[x & 7]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; cptr ++; mptr ++; yptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; for (x = xsize; x > 0; x --) { if ((*r0 & 15) > dither[x & 3]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; cptr ++; mptr ++; yptr ++; } } break; case 8 : for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) { if (r0[0] == r1[0]) *cptr++ = r0[0]; else *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[1] == r1[1]) *mptr++ = r0[1]; else *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[2] == r1[2]) *yptr++ = r0[2]; else *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; } break; } break; case CUPS_ORDER_PLANAR : if (z == 3) { memset(row, 255, header->cupsBytesPerLine); break; } switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; switch (z) { case 0 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[0] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 1 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[1] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 2 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[2] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; r0 += z; for (x = xsize; x > 0; x --, r0 += 3) { if ((*r0 & 63) > dither[x & 7]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; ptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; r0 += z; for (x = xsize; x > 0; x --, r0 += 3) { if ((*r0 & 15) > dither[x & 3]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; ptr ++; } } break; case 8 : r0 += z; r1 += z; for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) { if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; } break; } break; } } /* * 'format_W()' - Convert image data to luminance. */ static void format_W(cups_page_header2_t *header, /* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { cups_ib_t *ptr, /* Pointer into row */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ (void)z; switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { if (*r0++ > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; for (x = xsize; x > 0; x --) { if ((*r0 & 63) > dither[x & 7]) *ptr ^= (bitmask & OnPixels[*r0++]); else *ptr ^= (bitmask & OffPixels[*r0++]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; ptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; for (x = xsize; x > 0; x --) { if ((*r0 & 15) > dither[x & 3]) *ptr ^= (bitmask & OnPixels[*r0++]); else *ptr ^= (bitmask & OffPixels[*r0++]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; ptr ++; } } break; case 8 : for (x = xsize; x > 0; x --, r0 ++, r1 ++) { if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; } break; } } /* * 'format_YMC()' - Convert image data to YMC. */ static void format_YMC(cups_page_header2_t *header, /* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { cups_ib_t *ptr, /* Pointer into row */ *cptr, /* Pointer into cyan */ *mptr, /* Pointer into magenta */ *yptr, /* Pointer into yellow */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int bandwidth; /* Width of a color band */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; bandwidth = header->cupsBytesPerLine / 3; switch (header->cupsColorOrder) { case CUPS_ORDER_CHUNKED : switch (header->cupsBitsPerColor) { case 1 : bitmask = 64 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize ; x > 0; x --, r0 += 3) { if (r0[2] > dither[x & 15]) *ptr ^= bitmask; bitmask >>= 1; if (r0[1] > dither[x & 15]) *ptr ^= bitmask; bitmask >>= 1; if (r0[0] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 2; else { bitmask = 64; ptr ++; } } break; case 2 : dither = Floyd8x8[y & 7]; for (x = xsize ; x > 0; x --, r0 += 3) { if ((r0[2] & 63) > dither[x & 7]) *ptr ^= (0x30 & OnPixels[r0[2]]); else *ptr ^= (0x30 & OffPixels[r0[2]]); if ((r0[1] & 63) > dither[x & 7]) *ptr ^= (0x0c & OnPixels[r0[1]]); else *ptr ^= (0x0c & OffPixels[r0[1]]); if ((r0[0] & 63) > dither[x & 7]) *ptr++ ^= (0x03 & OnPixels[r0[0]]); else *ptr++ ^= (0x03 & OffPixels[r0[0]]); } break; case 4 : dither = Floyd4x4[y & 3]; for (x = xsize ; x > 0; x --, r0 += 3) { if ((r0[2] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[2]]); else *ptr++ ^= (0x0f & OffPixels[r0[2]]); if ((r0[1] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[1]]); else *ptr ^= (0xf0 & OffPixels[r0[1]]); if ((r0[0] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[0]]); else *ptr++ ^= (0x0f & OffPixels[r0[0]]); } break; case 8 : for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) { if (r0[2] == r1[2]) *ptr++ = r0[2]; else *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; if (r0[1] == r1[1]) *ptr++ = r0[1]; else *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[0] == r1[0]) *ptr++ = r0[0]; else *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; } break; } break; case CUPS_ORDER_BANDED : yptr = ptr; mptr = ptr + bandwidth; cptr = ptr + 2 * bandwidth; switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { if (*r0++ > dither[x & 15]) *cptr ^= bitmask; if (*r0++ > dither[x & 15]) *mptr ^= bitmask; if (*r0++ > dither[x & 15]) *yptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; cptr ++; mptr ++; yptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; for (x = xsize; x > 0; x --) { if ((*r0 & 63) > dither[x & 7]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; cptr ++; mptr ++; yptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; for (x = xsize; x > 0; x --) { if ((*r0 & 15) > dither[x & 3]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; cptr ++; mptr ++; yptr ++; } } break; case 8 : for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) { if (r0[0] == r1[0]) *cptr++ = r0[0]; else *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[1] == r1[1]) *mptr++ = r0[1]; else *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[2] == r1[2]) *yptr++ = r0[2]; else *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; } break; } break; case CUPS_ORDER_PLANAR : switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; switch (z) { case 2 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[0] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 1 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[1] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 0 : for (x = xsize; x > 0; x --, r0 += 3) { if (r0[2] > dither[x & 15]) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; z = 2 - z; r0 += z; for (x = xsize; x > 0; x --, r0 += 3) { if ((*r0 & 63) > dither[x & 7]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; ptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; z = 2 - z; r0 += z; for (x = xsize; x > 0; x --, r0 += 3) { if ((*r0 & 15) > dither[x & 3]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; ptr ++; } } break; case 8 : z = 2 - z; r0 += z; r1 += z; for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) { if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; } break; } break; } } /* * 'format_YMCK()' - Convert image data to YMCK. */ static void format_YMCK(cups_page_header2_t *header,/* I - Page header */ unsigned char *row, /* IO - Bitmap data for device */ int y, /* I - Current row */ int z, /* I - Current plane */ int xsize, /* I - Width of image data */ int ysize, /* I - Height of image data */ int yerr0, /* I - Top Y error */ int yerr1, /* I - Bottom Y error */ cups_ib_t *r0, /* I - Primary image data */ cups_ib_t *r1) /* I - Image data for interpolation */ { cups_ib_t *ptr, /* Pointer into row */ *cptr, /* Pointer into cyan */ *mptr, /* Pointer into magenta */ *yptr, /* Pointer into yellow */ *kptr, /* Pointer into black */ bitmask; /* Current mask for pixel */ int bitoffset; /* Current offset in line */ int bandwidth; /* Width of a color band */ int x, /* Current X coordinate on page */ *dither; /* Pointer into dither array */ int pc, pm, py; /* CMY pixels */ switch (XPosition) { case -1 : bitoffset = 0; break; default : bitoffset = header->cupsBitsPerPixel * ((header->cupsWidth - xsize) / 2); break; case 1 : bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); break; } ptr = row + bitoffset / 8; bandwidth = header->cupsBytesPerLine / 4; switch (header->cupsColorOrder) { case CUPS_ORDER_CHUNKED : switch (header->cupsBitsPerColor) { case 1 : bitmask = 128 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize ; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if (pc && pm && py) { bitmask >>= 3; *ptr ^= bitmask; } else { if (py) *ptr ^= bitmask; bitmask >>= 1; if (pm) *ptr ^= bitmask; bitmask >>= 1; if (pc) *ptr ^= bitmask; bitmask >>= 1; } if (bitmask > 1) bitmask >>= 1; else { bitmask = 128; ptr ++; } } break; case 2 : dither = Floyd8x8[y & 7]; for (x = xsize ; x > 0; x --, r0 += 4) { if ((r0[2] & 63) > dither[x & 7]) *ptr ^= (0xc0 & OnPixels[r0[2]]); else *ptr ^= (0xc0 & OffPixels[r0[2]]); if ((r0[1] & 63) > dither[x & 7]) *ptr ^= (0x30 & OnPixels[r0[1]]); else *ptr ^= (0x30 & OffPixels[r0[1]]); if ((r0[0] & 63) > dither[x & 7]) *ptr ^= (0x0c & OnPixels[r0[0]]); else *ptr ^= (0x0c & OffPixels[r0[0]]); if ((r0[3] & 63) > dither[x & 7]) *ptr++ ^= (0x03 & OnPixels[r0[3]]); else *ptr++ ^= (0x03 & OffPixels[r0[3]]); } break; case 4 : dither = Floyd4x4[y & 3]; for (x = xsize ; x > 0; x --, r0 += 4) { if ((r0[2] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[2]]); else *ptr ^= (0xf0 & OffPixels[r0[2]]); if ((r0[1] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[1]]); else *ptr++ ^= (0x0f & OffPixels[r0[1]]); if ((r0[0] & 15) > dither[x & 3]) *ptr ^= (0xf0 & OnPixels[r0[0]]); else *ptr ^= (0xf0 & OffPixels[r0[0]]); if ((r0[3] & 15) > dither[x & 3]) *ptr++ ^= (0x0f & OnPixels[r0[3]]); else *ptr++ ^= (0x0f & OffPixels[r0[3]]); } break; case 8 : for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) { if (r0[2] == r1[2]) *ptr++ = r0[2]; else *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; if (r0[1] == r1[1]) *ptr++ = r0[1]; else *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[0] == r1[0]) *ptr++ = r0[0]; else *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[3] == r1[3]) *ptr++ = r0[3]; else *ptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; } break; } break; case CUPS_ORDER_BANDED : yptr = ptr; mptr = ptr + bandwidth; cptr = ptr + 2 * bandwidth; kptr = ptr + 3 * bandwidth; switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if (pc && pm && py) *kptr ^= bitmask; else { if (pc) *cptr ^= bitmask; if (pm) *mptr ^= bitmask; if (py) *yptr ^= bitmask; } if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; for (x = xsize; x > 0; x --) { if ((*r0 & 63) > dither[x & 7]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 63) > dither[x & 7]) *kptr ^= (bitmask & OnPixels[*r0++]); else *kptr ^= (bitmask & OffPixels[*r0++]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; for (x = xsize; x > 0; x --) { if ((*r0 & 15) > dither[x & 3]) *cptr ^= (bitmask & OnPixels[*r0++]); else *cptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *mptr ^= (bitmask & OnPixels[*r0++]); else *mptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *yptr ^= (bitmask & OnPixels[*r0++]); else *yptr ^= (bitmask & OffPixels[*r0++]); if ((*r0 & 15) > dither[x & 3]) *kptr ^= (bitmask & OnPixels[*r0++]); else *kptr ^= (bitmask & OffPixels[*r0++]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; cptr ++; mptr ++; yptr ++; kptr ++; } } break; case 8 : for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) { if (r0[0] == r1[0]) *cptr++ = r0[0]; else *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; if (r0[1] == r1[1]) *mptr++ = r0[1]; else *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; if (r0[2] == r1[2]) *yptr++ = r0[2]; else *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; if (r0[3] == r1[3]) *kptr++ = r0[3]; else *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; } break; } break; case CUPS_ORDER_PLANAR : switch (header->cupsBitsPerColor) { case 1 : bitmask = 0x80 >> (bitoffset & 7); dither = Floyd16x16[y & 15]; for (x = xsize; x > 0; x --) { pc = *r0++ > dither[x & 15]; pm = *r0++ > dither[x & 15]; py = *r0++ > dither[x & 15]; if ((pc && pm && py && z == 3) || (pc && z == 2) || (pm && z == 1) || (py && z == 0)) *ptr ^= bitmask; if (bitmask > 1) bitmask >>= 1; else { bitmask = 0x80; ptr ++; } } break; case 2 : bitmask = 0xc0 >> (bitoffset & 7); dither = Floyd8x8[y & 7]; if (z == 3) r0 += 3; else r0 += 2 - z; for (x = xsize; x > 0; x --, r0 += 4) { if ((*r0 & 63) > dither[x & 7]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask > 3) bitmask >>= 2; else { bitmask = 0xc0; ptr ++; } } break; case 4 : bitmask = 0xf0 >> (bitoffset & 7); dither = Floyd4x4[y & 3]; if (z == 3) r0 += 3; else r0 += 2 - z; for (x = xsize; x > 0; x --, r0 += 4) { if ((*r0 & 15) > dither[x & 3]) *ptr ^= (bitmask & OnPixels[*r0]); else *ptr ^= (bitmask & OffPixels[*r0]); if (bitmask == 0xf0) bitmask = 0x0f; else { bitmask = 0xf0; ptr ++; } } break; case 8 : if (z == 3) { r0 += 3; r1 += 3; } else { r0 += 2 - z; r1 += 2 - z; } for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) { if (*r0 == *r1) *ptr++ = *r0; else *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; } break; } break; } } /* * 'make_lut()' - Make a lookup table given gamma and brightness values. */ static void make_lut(cups_ib_t *lut, /* I - Lookup table */ int colorspace, /* I - Colorspace */ float g, /* I - Image gamma */ float b) /* I - Image brightness */ { int i; /* Looping var */ int v; /* Current value */ g = 1.0 / g; b = 1.0 / b; for (i = 0; i < 256; i ++) { if (colorspace < 0) v = 255.0 * b * (1.0 - pow(1.0 - (float)i / 255.0, g)) + 0.5; else v = 255.0 * (1.0 - b * (1.0 - pow((float)i / 255.0, g))) + 0.5; if (v < 0) *lut++ = 0; else if (v > 255) *lut++ = 255; else *lut++ = v; } } /* * 'raster_cb()' - Validate the page header. */ static int /* O - 0 if OK, -1 if not */ raster_cb( cups_page_header2_t *header, /* IO - Raster header */ int preferred_bits) /* I - Preferred bits per color */ { /* * Ensure that colorimetric colorspaces use at least 8 bits per * component... */ if ((header->cupsColorSpace == CUPS_CSPACE_CIEXYZ || header->cupsColorSpace == CUPS_CSPACE_CIELab || header->cupsColorSpace >= CUPS_CSPACE_ICC1) && header->cupsBitsPerColor < 8) header->cupsBitsPerColor = 8; return (0); }