/* * BMP image routines for CUPS. * * Copyright 2007-2011 by Apple Inc. * Copyright 1993-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright * law. Distribution and use rights are outlined in the file "COPYING" * which should have been included with this file. * * Contents: * * _cupsImageReadBMP() - Read a BMP image file. * read_word() - Read a 16-bit unsigned integer. * read_dword() - Read a 32-bit unsigned integer. * read_long() - Read a 32-bit signed integer. */ /* * Include necessary headers... */ #include "image-private.h" /* * Constants for the bitmap compression... */ # define BI_RGB 0 /* No compression - straight BGR data */ # define BI_RLE8 1 /* 8-bit run-length compression */ # define BI_RLE4 2 /* 4-bit run-length compression */ # define BI_BITFIELDS 3 /* RGB bitmap with RGB masks */ /* * Local functions... */ static unsigned short read_word(FILE *fp); static unsigned int read_dword(FILE *fp); static int read_long(FILE *fp); /* * '_cupsImageReadBMP()' - Read a BMP image file. */ int /* O - Read status */ _cupsImageReadBMP( cups_image_t *img, /* IO - cupsImage */ FILE *fp, /* I - cupsImage file */ cups_icspace_t primary, /* I - Primary choice for colorspace */ cups_icspace_t secondary, /* I - Secondary choice for colorspace */ int saturation, /* I - Color saturation (%) */ int hue, /* I - Color hue (degrees) */ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ { int offset, /* Offset to bitmap data */ info_size, /* Size of info header */ planes, /* Number of planes (always 1) */ depth, /* Depth of image (bits) */ compression, /* Type of compression */ image_size, /* Size of image in bytes */ colors_used, /* Number of colors used */ colors_important, /* Number of important colors */ bpp, /* Bytes per pixel */ x, y, /* Looping vars */ color, /* Color of RLE pixel */ count, /* Number of times to repeat */ temp, /* Temporary color */ align; /* Alignment bytes */ cups_ib_t bit, /* Bit in image */ byte; /* Byte in image */ cups_ib_t *in, /* Input pixels */ *out, /* Output pixels */ *ptr; /* Pointer into pixels */ cups_ib_t colormap[256][4]; /* Colormap */ (void)secondary; /* * Get the header... */ getc(fp); /* Skip "BM" sync chars */ getc(fp); read_dword(fp); /* Skip size */ read_word(fp); /* Skip reserved stuff */ read_word(fp); offset = read_dword(fp); fprintf(stderr, "DEBUG: offset = %d\n", offset); if (offset < 0) { fprintf(stderr, "DEBUG: Bad BMP offset %d\n", offset); fclose(fp); return (1); } /* * Then the bitmap information... */ info_size = read_dword(fp); img->xsize = read_long(fp); img->ysize = read_long(fp); planes = read_word(fp); depth = read_word(fp); compression = read_dword(fp); image_size = read_dword(fp); img->xppi = read_long(fp) * 0.0254 + 0.5; img->yppi = read_long(fp) * 0.0254 + 0.5; colors_used = read_dword(fp); colors_important = read_dword(fp); if (img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH || img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT || (depth != 1 && depth != 4 && depth != 8 && depth != 24)) { fprintf(stderr, "DEBUG: Bad BMP dimensions %ux%ux%d\n", img->xsize, img->ysize, depth); fclose(fp); return (1); } if (colors_used < 0 || colors_used > 256) { fprintf(stderr, "DEBUG: Bad BMP colormap size %d\n", colors_used); fclose(fp); return (1); } if (img->xppi == 0 || img->yppi == 0) { fprintf(stderr, "DEBUG: Bad BMP resolution %dx%d PPI.\n", img->xppi, img->yppi); img->xppi = img->yppi = 200; } /* * Make sure the resolution info is valid... */ fprintf(stderr, "info_size = %d, xsize = %d, ysize = %d, planes = %d, depth = %d\n", info_size, img->xsize, img->ysize, planes, depth); fprintf(stderr, "compression = %d, image_size = %d, xppi = %d, yppi = %d\n", compression, image_size, img->xppi, img->yppi); fprintf(stderr, "colors_used = %d, colors_important = %d\n", colors_used, colors_important); if (info_size > 40) for (info_size -= 40; info_size > 0; info_size --) getc(fp); /* * Get colormap... */ if (colors_used == 0 && depth <= 8) colors_used = 1 << depth; if (colors_used > 0) { if (fread(colormap, colors_used, 4, fp) == 0 && ferror(fp)) DEBUG_printf(("Error reading file!")); } else memset(colormap, 0, sizeof(colormap)); /* * Setup image and buffers... */ img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; cupsImageSetMaxTiles(img, 0); bpp = cupsImageGetDepth(img); if ((in = malloc(img->xsize * 3)) == NULL) { fputs("DEBUG: Unable to allocate memory!\n", stderr); fclose(fp); return (1); } if ((out = malloc(img->xsize * bpp)) == NULL) { fputs("DEBUG: Unable to allocate memory!\n", stderr); free(in); fclose(fp); return (1); } /* * Read the image data... */ color = 0; count = 0; align = 0; for (y = img->ysize - 1; y >= 0; y --) { ptr = in; switch (depth) { case 1 : /* Bitmap */ for (x = img->xsize, bit = 128, byte = 0; x > 0; x --) { if (bit == 128) byte = getc(fp); if (byte & bit) { *ptr++ = colormap[1][2]; *ptr++ = colormap[1][1]; *ptr++ = colormap[1][0]; } else { *ptr++ = colormap[0][2]; *ptr++ = colormap[0][1]; *ptr++ = colormap[0][0]; } if (bit > 1) bit >>= 1; else bit = 128; } /* * Read remaining bytes to align to 32 bits... */ for (temp = (img->xsize + 7) / 8; temp & 3; temp ++) getc(fp); break; case 4 : /* 16-color */ for (x = img->xsize, bit = 0xf0, temp = 0; x > 0; x --) { /* * Get a new count as needed... */ if (compression != BI_RLE4 && count == 0) { count = 2; color = -1; } if (count == 0) { while (align > 0) { align --; getc(fp); } if ((count = getc(fp)) == 0) { if ((count = getc(fp)) == 0) { /* * End of line... */ x ++; continue; } else if (count == 1) { /* * End of image... */ break; } else if (count == 2) { /* * Delta... */ count = getc(fp) * getc(fp) * img->xsize; color = 0; } else { /* * Absolute... */ color = -1; align = ((4 - (count & 3)) / 2) & 1; } } else color = getc(fp); } /* * Get a new color as needed... */ count --; if (bit == 0xf0) { if (color < 0) temp = getc(fp); else temp = color; /* * Copy the color value... */ *ptr++ = colormap[temp >> 4][2]; *ptr++ = colormap[temp >> 4][1]; *ptr++ = colormap[temp >> 4][0]; bit = 0x0f; } else { /* * Copy the color value... */ *ptr++ = colormap[temp & 15][2]; *ptr++ = colormap[temp & 15][1]; *ptr++ = colormap[temp & 15][0]; bit = 0xf0; } } break; case 8 : /* 256-color */ for (x = img->xsize; x > 0; x --) { /* * Get a new count as needed... */ if (compression != BI_RLE8) { count = 1; color = -1; } if (count == 0) { while (align > 0) { align --; getc(fp); } if ((count = getc(fp)) == 0) { if ((count = getc(fp)) == 0) { /* * End of line... */ x ++; continue; } else if (count == 1) { /* * End of image... */ break; } else if (count == 2) { /* * Delta... */ count = getc(fp) * getc(fp) * img->xsize; color = 0; } else { /* * Absolute... */ color = -1; align = (2 - (count & 1)) & 1; } } else color = getc(fp); } /* * Get a new color as needed... */ if (color < 0) temp = getc(fp); else temp = color; count --; /* * Copy the color value... */ *ptr++ = colormap[temp][2]; *ptr++ = colormap[temp][1]; *ptr++ = colormap[temp][0]; } break; case 24 : /* 24-bit RGB */ for (x = img->xsize; x > 0; x --, ptr += 3) { ptr[2] = getc(fp); ptr[1] = getc(fp); ptr[0] = getc(fp); } /* * Read remaining bytes to align to 32 bits... */ for (temp = img->xsize * 3; temp & 3; temp ++) getc(fp); break; } if (saturation != 100 || hue != 0) cupsImageRGBAdjust(in, img->xsize, saturation, hue); switch (img->colorspace) { default : break; case CUPS_IMAGE_WHITE : cupsImageRGBToWhite(in, out, img->xsize); break; case CUPS_IMAGE_RGB : cupsImageRGBToRGB(in, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageRGBToBlack(in, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageRGBToCMY(in, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageRGBToCMYK(in, out, img->xsize); break; } if (lut) cupsImageLut(out, img->xsize * bpp, lut); _cupsImagePutRow(img, 0, y, img->xsize, out); } fclose(fp); free(in); free(out); return (0); } /* * 'read_word()' - Read a 16-bit unsigned integer. */ static unsigned short /* O - 16-bit unsigned integer */ read_word(FILE *fp) /* I - File to read from */ { unsigned char b0, b1; /* Bytes from file */ b0 = getc(fp); b1 = getc(fp); return ((b1 << 8) | b0); } /* * 'read_dword()' - Read a 32-bit unsigned integer. */ static unsigned int /* O - 32-bit unsigned integer */ read_dword(FILE *fp) /* I - File to read from */ { unsigned char b0, b1, b2, b3; /* Bytes from file */ b0 = getc(fp); b1 = getc(fp); b2 = getc(fp); b3 = getc(fp); return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0); } /* * 'read_long()' - Read a 32-bit signed integer. */ static int /* O - 32-bit signed integer */ read_long(FILE *fp) /* I - File to read from */ { unsigned char b0, b1, b2, b3; /* Bytes from file */ b0 = getc(fp); b1 = getc(fp); b2 = getc(fp); b3 = getc(fp); return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0); }