static cmsUInt32Number determine_lcms_format (const Babl *babl, cmsHPROFILE profile) { cmsUInt32Number format = COLORSPACE_SH (PT_ANY); gint channels, bpc, alpha; const Babl *type; channels = cmsChannelsOf (cmsGetColorSpace (profile)); alpha = babl_format_get_n_components (babl) - channels; bpc = babl_format_get_bytes_per_pixel (babl) / babl_format_get_n_components (babl); type = babl_format_get_type (babl, 0); if (type == babl_type ("half") || type == babl_type ("float") || type == babl_type ("double")) format |= FLOAT_SH (1); /* bpc == 8 overflows the bitfield otherwise */ bpc &= 0x07; /* * This is needed so the alpha component lines up with RGBA float * for our memcpy hack later on. */ if (alpha > 1 || (alpha && channels != 3)) return 0; format |= EXTRA_SH (alpha) | CHANNELS_SH (channels) | BYTES_SH (bpc); return format; }
static cmsUInt32Number GetInputPixelType(void) { int space, bps, extra, ColorChannels, Flavor; lIsITUFax = IsITUFax(Decompressor.marker_list); lIsPhotoshopApp13 = HandlePhotoshopAPP13(Decompressor.marker_list); lIsEXIF = HandleEXIF(&Decompressor); ColorChannels = Decompressor.num_components; extra = 0; // Alpha = None bps = 1; // 8 bits Flavor = 0; // Vanilla if (lIsITUFax) { space = PT_Lab; Decompressor.out_color_space = JCS_YCbCr; // Fake to don't touch } else switch (Decompressor.jpeg_color_space) { case JCS_GRAYSCALE: // monochrome space = PT_GRAY; Decompressor.out_color_space = JCS_GRAYSCALE; break; case JCS_RGB: // red/green/blue space = PT_RGB; Decompressor.out_color_space = JCS_RGB; break; case JCS_YCbCr: // Y/Cb/Cr (also known as YUV) space = PT_RGB; // Let IJG code to do the conversion Decompressor.out_color_space = JCS_RGB; break; case JCS_CMYK: // C/M/Y/K space = PT_CMYK; Decompressor.out_color_space = JCS_CMYK; if (Decompressor.saw_Adobe_marker) // Adobe keeps CMYK inverted, so change flavor Flavor = 1; // from vanilla to chocolate break; case JCS_YCCK: // Y/Cb/Cr/K space = PT_CMYK; Decompressor.out_color_space = JCS_CMYK; if (Decompressor.saw_Adobe_marker) // ditto Flavor = 1; break; default: FatalError("Unsupported color space (0x%x)", Decompressor.jpeg_color_space); return 0; } return (EXTRA_SH(extra)|CHANNELS_SH(ColorChannels)|BYTES_SH(bps)|COLORSPACE_SH(space)|FLAVOR_SH(Flavor)); }
DWORD ScLcmsColorMgmtEngineImpl::translateFormatToLcmsFormat(eColorFormat format) { DWORD lFormat = 0; if (format == Format_RGB_8) lFormat = TYPE_RGB_8; if (format == Format_RGB_16) lFormat = TYPE_RGB_16; if (format == Format_RGBA_8) lFormat = TYPE_RGBA_8; if (format == Format_RGBA_16) lFormat = TYPE_RGBA_16; if (format == Format_ARGB_8) lFormat = TYPE_ARGB_8; if (format == Format_ARGB_16) lFormat = TYPE_ARGB_16; if (format == Format_BGRA_8) lFormat = TYPE_BGRA_8; if (format == Format_BGRA_16) lFormat = TYPE_BGRA_16; if (format == Format_CMYK_8) lFormat = TYPE_CMYK_8; if (format == Format_CMYK_16) lFormat = TYPE_CMYK_16; if (format == Format_CMYKA_8) lFormat = (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(1)); if (format == Format_CMYKA_16) lFormat = (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(2)); if (format == Format_YMCK_8) lFormat = (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)); if (format == Format_YMCK_16) lFormat = (COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)); if (format == Format_GRAY_8) lFormat = TYPE_GRAY_8; if (format == Format_GRAY_16) lFormat = TYPE_GRAY_16; if (format == Format_LabA_8) lFormat = COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1); return lFormat; }
static cmsUInt32Number findLCMStype(char* PILmode) { if (strcmp(PILmode, "RGB") == 0) { return TYPE_RGBA_8; } else if (strcmp(PILmode, "RGBA") == 0) { return TYPE_RGBA_8; } else if (strcmp(PILmode, "RGBX") == 0) { return TYPE_RGBA_8; } else if (strcmp(PILmode, "RGBA;16B") == 0) { return TYPE_RGBA_16; } else if (strcmp(PILmode, "CMYK") == 0) { return TYPE_CMYK_8; } else if (strcmp(PILmode, "L") == 0) { return TYPE_GRAY_8; } else if (strcmp(PILmode, "L;16") == 0) { return TYPE_GRAY_16; } else if (strcmp(PILmode, "L;16B") == 0) { return TYPE_GRAY_16_SE; } else if (strcmp(PILmode, "YCCA") == 0) { return TYPE_YCbCr_8; } else if (strcmp(PILmode, "YCC") == 0) { return TYPE_YCbCr_8; } else if (strcmp(PILmode, "LAB") == 0) { // LabX equvalent like ALab, but not reversed -- no #define in lcms2 return (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)); } else { /* take a wild guess... but you probably should fail instead. */ return TYPE_GRAY_8; /* so there's no buffer overrun... */ } }
/* Transform an entire buffer */ void gscms_transform_color_buffer(gsicc_link_t *icclink, gsicc_bufferdesc_t *input_buff_desc, gsicc_bufferdesc_t *output_buff_desc, void *inputbuffer, void *outputbuffer) { cmsHTRANSFORM hTransform = (cmsHTRANSFORM) icclink->link_handle; DWORD dwInputFormat,dwOutputFormat,curr_input,curr_output; int planar,numbytes,big_endian,hasalpha,k; unsigned char *inputpos, *outputpos; int numchannels; #if DUMP_CMS_BUFFER FILE *fid_in, *fid_out; #endif /* Although little CMS does make assumptions about data types in its transformations you can change it after the fact. */ /* Set us to the proper output type */ /* Note, we could speed this up by passing back the encoded data type to the caller so that we could avoid having to go through this computation each time if they are doing multiple calls to this operation */ _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) (LPSTR) hTransform; curr_input = p->InputFormat; curr_output = p->OutputFormat; /* Color space MUST be the same */ dwInputFormat = COLORSPACE_SH(T_COLORSPACE(curr_input)); dwOutputFormat = COLORSPACE_SH(T_COLORSPACE(curr_output)); /* Now set if we have planar, num bytes, endian case, and alpha data to skip */ /* Planar -- pdf14 case for example */ planar = input_buff_desc->is_planar; dwInputFormat = dwInputFormat | PLANAR_SH(planar); planar = output_buff_desc->is_planar; dwOutputFormat = dwOutputFormat | PLANAR_SH(planar); /* 8 or 16 byte input and output */ numbytes = input_buff_desc->bytes_per_chan; if (numbytes>2) numbytes = 0; /* littleCMS encodes float with 0 ToDO. */ dwInputFormat = dwInputFormat | BYTES_SH(numbytes); numbytes = output_buff_desc->bytes_per_chan; if (numbytes>2) numbytes = 0; dwOutputFormat = dwOutputFormat | BYTES_SH(numbytes); /* endian */ big_endian = !input_buff_desc->little_endian; dwInputFormat = dwInputFormat | ENDIAN16_SH(big_endian); big_endian = !output_buff_desc->little_endian; dwOutputFormat = dwOutputFormat | ENDIAN16_SH(big_endian); /* number of channels */ numchannels = input_buff_desc->num_chan; dwInputFormat = dwInputFormat | CHANNELS_SH(numchannels); numchannels = output_buff_desc->num_chan; dwOutputFormat = dwOutputFormat | CHANNELS_SH(numchannels); /* alpha, which is passed through unmolested */ /* ToDo: Right now we always must have alpha last */ /* This is really only going to be an issue when we have interleaved alpha data */ hasalpha = input_buff_desc->has_alpha; dwInputFormat = dwInputFormat | EXTRA_SH(hasalpha); dwOutputFormat = dwOutputFormat | EXTRA_SH(hasalpha); /* Change the formaters */ cmsChangeBuffersFormat(hTransform,dwInputFormat,dwOutputFormat); /* littleCMS knows nothing about word boundarys. As such, we need to do this row by row adjusting for our stride. Output buffer must already be allocated. ToDo: Check issues with plane and row stride and word boundry */ inputpos = (unsigned char *) inputbuffer; outputpos = (unsigned char *) outputbuffer; if(input_buff_desc->is_planar){ /* Do entire buffer. Care must be taken here with respect to row stride, word boundry and number of source versus output channels. We may need to take a closer look at this. */ cmsDoTransform(hTransform,inputpos,outputpos, input_buff_desc->plane_stride); } else { /* Do row by row. */ for(k = 0; k < input_buff_desc->num_rows ; k++){ cmsDoTransform(hTransform,inputpos,outputpos, input_buff_desc->pixels_per_row); inputpos += input_buff_desc->row_stride; outputpos += output_buff_desc->row_stride; } } #if DUMP_CMS_BUFFER fid_in = fopen("CM_Input.raw","ab"); fid_out = fopen("CM_Output.raw","ab"); fwrite((unsigned char*) inputbuffer,sizeof(unsigned char), input_buff_desc->row_stride,fid_in); fwrite((unsigned char*) outputbuffer,sizeof(unsigned char), output_buff_desc->row_stride,fid_out); fclose(fid_in); fclose(fid_out); #endif }
static DWORD GetInputPixelType(TIFF *Bank) { uint16 Photometric, bps, spp, extra, PlanarConfig, *info; uint16 Compression, reverse = 0; int ColorChannels, IsPlanar = 0, pt = 0; TIFFGetField(Bank, TIFFTAG_PHOTOMETRIC, &Photometric); TIFFGetFieldDefaulted(Bank, TIFFTAG_BITSPERSAMPLE, &bps); if (bps == 1) FatalError("Sorry, bilevel TIFFs has nothig to do with ICC profiles"); if (bps != 8 && bps != 16) FatalError("Sorry, 8 or 16 bits per sample only"); TIFFGetFieldDefaulted(Bank, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetFieldDefaulted(Bank, TIFFTAG_PLANARCONFIG, &PlanarConfig); switch (PlanarConfig) { case PLANARCONFIG_CONTIG: IsPlanar = 0; break; case PLANARCONFIG_SEPARATE: IsPlanar = 1; break; default: FatalError("Unsupported planar configuration (=%d) ", (int) PlanarConfig); } // If Samples per pixel == 1, PlanarConfiguration is irrelevant and need // not to be included. if (spp == 1) IsPlanar = 0; // Any alpha? TIFFGetFieldDefaulted(Bank, TIFFTAG_EXTRASAMPLES, &extra, &info); // Read alpha channels as colorant if (StoreAsAlpha) { ColorChannels = spp; extra = 0; } else ColorChannels = spp - extra; switch (Photometric) { case PHOTOMETRIC_MINISWHITE: reverse = 1; case PHOTOMETRIC_MINISBLACK: pt = PT_GRAY; break; case PHOTOMETRIC_RGB: pt = PT_RGB; break; case PHOTOMETRIC_PALETTE: FatalError("Sorry, palette images not supported (at least on this version)"); case PHOTOMETRIC_SEPARATED: if (ColorChannels == 4) pt = PT_CMYK; else if (ColorChannels == 3) pt = PT_CMY; else if (ColorChannels == 6) pt = PT_HiFi; else if (ColorChannels == 7) pt = PT_HiFi7; else if (ColorChannels == 8) pt = PT_HiFi8; else if (ColorChannels == 9) pt = PT_HiFi9; else if (ColorChannels == 10) pt = PT_HiFi10; else if (ColorChannels == 11) pt = PT_HiFi11; else if (ColorChannels == 12) pt = PT_HiFi8; else if (ColorChannels == 13) pt = PT_HiFi13; else if (ColorChannels == 14) pt = PT_HiFi14; else if (ColorChannels == 15) pt = PT_HiFi15; else FatalError("What a weird separation of %d channels?!?!", ColorChannels); break; case PHOTOMETRIC_YCBCR: TIFFGetField(Bank, TIFFTAG_COMPRESSION, &Compression); { uint16 subx, suby; pt = PT_YCbCr; TIFFGetFieldDefaulted(Bank, TIFFTAG_YCBCRSUBSAMPLING, &subx, &suby); if (subx != 1 || suby != 1) FatalError("Sorry, subsampled images not supported"); } break; case 9: pt = PT_Lab; InputLabUsingICC = TRUE; break; case PHOTOMETRIC_CIELAB: pt = PT_Lab; InputLabUsingICC = FALSE; break; case PHOTOMETRIC_LOGLUV: /* CIE Log2(L) (u',v') */ TIFFSetField(Bank, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_16BIT); pt = PT_YUV; // *ICCSpace = icSigLuvData; bps = 16; // 16 bits forced by LibTiff break; default: FatalError("Unsupported TIFF color space (Photometric %d)", Photometric); } // Convert bits per sample to bytes per sample bps >>= 3; return (COLORSPACE_SH(pt)|PLANAR_SH(IsPlanar)|EXTRA_SH(extra)|CHANNELS_SH(ColorChannels)|BYTES_SH(bps)|FLAVOR_SH(reverse)); }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); cmsHTRANSFORM transform; const Babl *in_format, *out_format; gboolean alpha; gint bpp; in_format = babl_format_n (babl_type ("float"), babl_format_get_n_components (gegl_buffer_get_format (input))); bpp = babl_format_get_bytes_per_pixel (in_format); /* create the transformation */ { cmsHPROFILE in_profile, out_profile; cmsUInt32Number format; in_profile = o->src_profile; format = determine_lcms_format (in_format, in_profile); if (format == 0) return FALSE; if (format & EXTRA_SH (1)) alpha = TRUE; else alpha = FALSE; out_profile = create_lcms_linear_rgb_profile (); transform = cmsCreateTransform (in_profile, format, out_profile, alpha ? TYPE_RGBA_FLT : TYPE_RGB_FLT, o->intent, o->black_point_compensation ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0); cmsCloseProfile (out_profile); } out_format = alpha ? babl_format ("RGBA float") : babl_format ("RGB float"); /* iterate over the pixels */ { GeglBufferIterator *gi; gi = gegl_buffer_iterator_new (input, result, 0, in_format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (gi, output, result, 0, out_format, GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (gi)) { if (alpha) memcpy (gi->data[1], gi->data[0], bpp * gi->length); cmsDoTransform (transform, gi->data[0], gi->data[1], gi->length); } } cmsDeleteTransform (transform); return TRUE; }
/* Transform an entire buffer */ void gscms_transform_color_buffer(gx_device *dev, gsicc_link_t *icclink, gsicc_bufferdesc_t *input_buff_desc, gsicc_bufferdesc_t *output_buff_desc, void *inputbuffer, void *outputbuffer) { cmsHTRANSFORM hTransform = (cmsHTRANSFORM)icclink->link_handle; cmsUInt32Number dwInputFormat, dwOutputFormat, num_src_lcms, num_des_lcms; int planar,numbytes, big_endian, hasalpha, k; unsigned char *inputpos, *outputpos; #if DUMP_CMS_BUFFER FILE *fid_in, *fid_out; #endif /* Although little CMS does make assumptions about data types in its transformations you can change it after the fact. */ /* Set us to the proper output type */ /* Note, we could speed this up by passing back the encoded data type to the caller so that we could avoid having to go through this computation each time if they are doing multiple calls to this operation */ /* Color space MUST be the same */ dwInputFormat = COLORSPACE_SH(T_COLORSPACE(cmsGetTransformInputFormat(hTransform))); dwOutputFormat = COLORSPACE_SH(T_COLORSPACE(cmsGetTransformOutputFormat(hTransform))); /* Now set if we have planar, num bytes, endian case, and alpha data to skip */ /* Planar -- pdf14 case for example */ planar = input_buff_desc->is_planar; dwInputFormat = dwInputFormat | PLANAR_SH(planar); planar = output_buff_desc->is_planar; dwOutputFormat = dwOutputFormat | PLANAR_SH(planar); /* 8 or 16 byte input and output */ numbytes = input_buff_desc->bytes_per_chan; if (numbytes>2) numbytes = 0; /* littleCMS encodes float with 0 ToDO. */ dwInputFormat = dwInputFormat | BYTES_SH(numbytes); numbytes = output_buff_desc->bytes_per_chan; if (numbytes>2) numbytes = 0; dwOutputFormat = dwOutputFormat | BYTES_SH(numbytes); /* endian */ big_endian = !input_buff_desc->little_endian; dwInputFormat = dwInputFormat | ENDIAN16_SH(big_endian); big_endian = !output_buff_desc->little_endian; dwOutputFormat = dwOutputFormat | ENDIAN16_SH(big_endian); /* number of channels. This should not really be changing! */ num_src_lcms = T_CHANNELS(cmsGetTransformInputFormat(hTransform)); num_des_lcms = T_CHANNELS(cmsGetTransformOutputFormat(hTransform)); if (num_src_lcms != input_buff_desc->num_chan || num_des_lcms != output_buff_desc->num_chan) { /* We can't transform this. Someone is doing something odd */ return; } dwInputFormat = dwInputFormat | CHANNELS_SH(num_src_lcms); dwOutputFormat = dwOutputFormat | CHANNELS_SH(num_des_lcms); /* alpha, which is passed through unmolested */ /* ToDo: Right now we always must have alpha last */ /* This is really only going to be an issue when we have interleaved alpha data */ hasalpha = input_buff_desc->has_alpha; dwInputFormat = dwInputFormat | EXTRA_SH(hasalpha); dwOutputFormat = dwOutputFormat | EXTRA_SH(hasalpha); /* Change the formatters */ cmsChangeBuffersFormat(hTransform,dwInputFormat,dwOutputFormat); /* littleCMS knows nothing about word boundarys. As such, we need to do this row by row adjusting for our stride. Output buffer must already be allocated. ToDo: Check issues with plane and row stride and word boundry */ inputpos = (byte *) inputbuffer; outputpos = (byte *) outputbuffer; if(input_buff_desc->is_planar) { /* Determine if we can do this in one operation or if we have to break it up. Essentially if the width * height = plane_stride then yes. If we are doing some subsection of a plane then no. */ if (input_buff_desc->num_rows * input_buff_desc->pixels_per_row == input_buff_desc->plane_stride && output_buff_desc->num_rows * output_buff_desc->pixels_per_row == output_buff_desc->plane_stride) { /* Do entire buffer.*/ cmsDoTransform(hTransform, inputpos, outputpos, input_buff_desc->plane_stride); } else { /* We have to do this row by row, with memory transfers */ byte *temp_des, *temp_src; int source_size = input_buff_desc->bytes_per_chan * input_buff_desc->pixels_per_row; int des_size = output_buff_desc->bytes_per_chan * output_buff_desc->pixels_per_row; int y, i; temp_src = (byte*) gs_alloc_bytes(icclink->icc_link_cache->memory, source_size * input_buff_desc->num_chan, "gscms_transform_color_buffer"); if (temp_src == NULL) return; temp_des = (byte*) gs_alloc_bytes(icclink->icc_link_cache->memory, des_size * output_buff_desc->num_chan, "gscms_transform_color_buffer"); if (temp_des == NULL) return; for (y = 0; y < input_buff_desc->num_rows; y++) { byte *src_cm = temp_src; byte *src_buff = inputpos; byte *des_cm = temp_des; byte *des_buff = outputpos; /* Put into planar temp buffer */ for (i = 0; i < input_buff_desc->num_chan; i ++) { memcpy(src_cm, src_buff, source_size); src_cm += source_size; src_buff += input_buff_desc->plane_stride; } /* Transform */ cmsDoTransform(hTransform, temp_src, temp_des, input_buff_desc->pixels_per_row); /* Get out of temp planar buffer */ for (i = 0; i < output_buff_desc->num_chan; i ++) { memcpy(des_buff, des_cm, des_size); des_cm += des_size; des_buff += output_buff_desc->plane_stride; } inputpos += input_buff_desc->row_stride; outputpos += output_buff_desc->row_stride; } gs_free_object(icclink->icc_link_cache->memory, temp_src, "gscms_transform_color_buffer"); gs_free_object(icclink->icc_link_cache->memory, temp_des, "gscms_transform_color_buffer"); } } else { /* Do row by row. */ for(k = 0; k < input_buff_desc->num_rows ; k++) { cmsDoTransform(hTransform, inputpos, outputpos, input_buff_desc->pixels_per_row); inputpos += input_buff_desc->row_stride; outputpos += output_buff_desc->row_stride; } } #if DUMP_CMS_BUFFER fid_in = gp_fopen("CM_Input.raw","ab"); fid_out = gp_fopen("CM_Output.raw","ab"); fwrite((unsigned char*) inputbuffer,sizeof(unsigned char), input_buff_desc->row_stride,fid_in); fwrite((unsigned char*) outputbuffer,sizeof(unsigned char), output_buff_desc->row_stride,fid_out); fclose(fid_in); fclose(fid_out); #endif }