static void lcms_image_transform_indexed (gint32 image, cmsHPROFILE src_profile, cmsHPROFILE dest_profile, GimpColorRenderingIntent intent, gboolean bpc) { cmsHTRANSFORM transform; guchar *cmap; gint n_cmap_bytes; cmsUInt32Number format = TYPE_RGB_8; cmap = gimp_image_get_colormap (image, &n_cmap_bytes); transform = cmsCreateTransform (src_profile, format, dest_profile, format, intent, cmsFLAGS_NOOPTIMIZE | bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0); if (transform) { cmsDoTransform (transform, cmap, cmap, n_cmap_bytes / 3); cmsDeleteTransform (transform); } else { g_warning ("cmsCreateTransform() failed!"); } gimp_image_set_colormap (image, cmap, n_cmap_bytes); }
/* Have the CMS release the link */ void gscms_release_link(gsicc_link_t *icclink) { if (icclink->link_handle !=NULL ) cmsDeleteTransform(icclink->link_handle); icclink->link_handle = NULL; }
void gui_cleanup(struct dt_iop_module_t *self) { dt_iop_colortransfer_gui_data_t *g = (dt_iop_colortransfer_gui_data_t *)self->gui_data; dt_colorspaces_cleanup_profile(g->hsRGB); dt_colorspaces_cleanup_profile(g->hLab); cmsDeleteTransform(g->xform); free(self->gui_data); self->gui_data = NULL; }
static int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags) { cmsHTRANSFORM xform; int i, nColors, nColorant; cmsUInt32Number OutputFormat; char ColorName[32]; char Colorant[128]; cmsNAMEDCOLORLIST* NamedColorList; OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE); nColorant = T_CHANNELS(OutputFormat); xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags); if (xform == NULL) return 0; NamedColorList = cmsGetNamedColorList(xform); if (NamedColorList == NULL) return 0; _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile"); _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); nColors = cmsNamedColorCount(NamedColorList); for (i=0; i < nColors; i++) { cmsUInt16Number In[1]; cmsUInt16Number Out[cmsMAXCHANNELS]; In[0] = (cmsUInt16Number) i; if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) continue; cmsDoTransform(xform, In, Out, 1); BuildColorantList(Colorant, nColorant, Out); _cmsIOPrintf(m, " (%s) [ %s ]\n", ColorName, Colorant); } _cmsIOPrintf(m, " >>"); if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n"); } cmsDeleteTransform(xform); return 1; }
static void gimp_view_renderer_transform_free (GimpViewRenderer *renderer) { if (renderer->profile_transform) { cmsDeleteTransform (renderer->profile_transform); renderer->profile_transform = NULL; renderer->profile_src_format = NULL; renderer->profile_dest_format = NULL; } }
void gui_cleanup(struct dt_iop_module_t *self) { dt_iop_colorzones_gui_data_t *c = (dt_iop_colorzones_gui_data_t *)self->gui_data; dt_conf_set_int("plugins/darkroom/colorzones/gui_channel", c->channel); dt_colorspaces_cleanup_profile(c->hsRGB); dt_colorspaces_cleanup_profile(c->hLab); cmsDeleteTransform(c->xform); dt_draw_curve_destroy(c->minmax_curve); free(self->gui_data); self->gui_data = NULL; }
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_colorout_data_t *d = (dt_iop_colorout_data_t *)piece->data; if(d->xform) { cmsDeleteTransform(d->xform); d->xform = NULL; } free(piece->data); piece->data = NULL; }
static void cdisplay_lcms_finalize (GObject *object) { CdisplayLcms *lcms = CDISPLAY_LCMS (object); if (lcms->transform) { cmsDeleteTransform (lcms->transform); lcms->transform = NULL; } G_OBJECT_CLASS (cdisplay_lcms_parent_class)->finalize (object); }
void cleanup_pipe (struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_colorout_data_t *d = (dt_iop_colorout_data_t *)piece->data; if(d->output) dt_colorspaces_cleanup_profile(d->output); dt_colorspaces_cleanup_profile(d->Lab); if (d->xform) { cmsDeleteTransform(d->xform); d->xform = 0; } free(piece->data); }
void* convert_space (const void *source_data_ptr, int width, int height) { // Assign the memory for the transform void *YourOutputBuffer = malloc(sizeof(void)*width*height*4); // Create the required variables cmsHPROFILE hInProfile, hOutProfile; cmsHTRANSFORM hTransform; // Load the colour profiles hInProfile = cmsOpenProfileFromFile("/Library/Application Support/Nikon/Profiles/NKAdobe.icm", "r"); hOutProfile = cmsCreate_sRGBProfile(); // Create the transform matrix hTransform = cmsCreateTransform(hInProfile, TYPE_RGBA_8, hOutProfile, TYPE_RGBA_8, INTENT_PERCEPTUAL, 0); // Convert the image colours cmsDoTransform(hTransform, source_data_ptr, YourOutputBuffer, width*height); // Delete the opened stuff cmsDeleteTransform(hTransform); cmsCloseProfile(hInProfile); cmsCloseProfile(hOutProfile); // Create the return data object // CFDataRef ret_val = CFDataCreate (NULL, YourOutputBuffer, height * width * 4); // release the old image // CFRelease (source_data_ptr); // Null the pointer after releasing source_data_ptr = NULL; // NULL the pointer source_data_ptr = NULL; // Free the temp buffer for the colour space image // free(YourOutputBuffer); fprintf(stdout, "Colour space converted."); // return the new image return YourOutputBuffer; }
static void gcm_cell_renderer_set_color (GcmCellRendererColor *renderer) { CdColorRGB8 rgb; GdkPixbuf *pixbuf = NULL; gint height = 26; /* TODO: needs to be a property */ gint width = 400; /* TODO: needs to be a property */ gint x, y; guchar *pixels; guint pos; cmsHPROFILE profile_srgb = NULL; cmsHPROFILE profile_lab = NULL; cmsHTRANSFORM xform = NULL; /* nothing set yet */ if (renderer->color == NULL) goto out; /* convert the color to sRGB */ profile_lab = cmsCreateLab2Profile (NULL); profile_srgb = cmsCreate_sRGBProfile (); xform = cmsCreateTransform (profile_lab, TYPE_Lab_DBL, profile_srgb, TYPE_RGB_8, INTENT_ABSOLUTE_COLORIMETRIC, 0); cmsDoTransform (xform, renderer->color, &rgb, 1); /* create a pixbuf of the right size */ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); pixels = gdk_pixbuf_get_pixels (pixbuf); for (y=0; y<height; y++) { for (x=0; x<width; x++) { pos = (y*width+x) * 3; pixels[pos+0] = rgb.R; pixels[pos+1] = rgb.G; pixels[pos+2] = rgb.B; } } out: g_object_set (renderer, "pixbuf", pixbuf, NULL); if (profile_srgb != NULL) cmsCloseProfile (profile_srgb); if (profile_lab != NULL) cmsCloseProfile (profile_lab); if (xform != NULL) cmsDeleteTransform (xform); if (pixbuf != NULL) g_object_unref (pixbuf); }
void IccColorProfile::calculateFloatUIMinMax(void) { QVector<KoChannelInfo::DoubleRange> &ret = d->shared->uiMinMaxes; cmsHPROFILE cprofile = d->shared->lcmsProfile->lcmsProfile(); Q_ASSERT(cprofile); cmsColorSpaceSignature color_space_sig = cmsGetColorSpace(cprofile); unsigned int num_channels = cmsChannelsOf(color_space_sig); unsigned int color_space_mask = _cmsLCMScolorSpace(color_space_sig); Q_ASSERT(num_channels>=1 && num_channels <=4); // num_channels==1 is for grayscale, we need to handle it Q_ASSERT(color_space_mask); // to try to find the max range of float/doubles for this profile, // pass in min/max int and make the profile convert that // this is far from perfect, we need a better way, if possible to get the "bounds" of a profile uint16_t in_min_pixel[4] = {0,0,0,0}; uint16_t in_max_pixel[4] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF}; double out_min_pixel[4] = {0,0,0,0}; double out_max_pixel[4] = {0,0,0,0}; cmsHTRANSFORM trans = cmsCreateTransform( cprofile, (COLORSPACE_SH(color_space_mask)|CHANNELS_SH(num_channels)|BYTES_SH(2)), cprofile, (COLORSPACE_SH(color_space_mask)|FLOAT_SH(1)|CHANNELS_SH(num_channels)|BYTES_SH(0)), //NOTE THAT 'BYTES' FIELD IS SET TO ZERO ON DLB because 8 bytes overflows the bitfield INTENT_PERCEPTUAL, 0); // does the intent matter in this case? if (trans) { cmsDoTransform(trans, in_min_pixel, out_min_pixel, 1); cmsDoTransform(trans, in_max_pixel, out_max_pixel, 1); cmsDeleteTransform(trans); }//else, we'll just default to [0..1] below ret.resize(num_channels); for (unsigned int i=0; i<num_channels; ++i) { if (out_min_pixel[i] < out_max_pixel[i]) { ret[i].minVal = out_min_pixel[i]; ret[i].maxVal = out_max_pixel[i]; } else { // aparently we can't even guarentee that converted_to_double(0x0000) < converted_to_double(0xFFFF) // assume [0..1] in such cases // we need to find a really solid way of determining the bounds of a profile, if possible ret[i].minVal = 0; ret[i].maxVal = 1; } } }
static KoCIExyY RGB2xyY(cmsHPROFILE RGBProfile, qreal red, qreal green, qreal blue) { cmsHPROFILE XYZProfile = cmsCreateXYZProfile(); const cmsUInt32Number inputFormat = TYPE_RGB_DBL; const cmsUInt32Number outputFormat = TYPE_XYZ_DBL; const cmsUInt32Number transformFlags = cmsFLAGS_LOWRESPRECALC; cmsHTRANSFORM transform = cmsCreateTransform(RGBProfile, inputFormat, XYZProfile, outputFormat, INTENT_ABSOLUTE_COLORIMETRIC, transformFlags); struct XYZPixel { qreal X; qreal Y; qreal Z; }; struct RGBPixel { qreal red; qreal green; qreal blue; }; XYZPixel xyzPixel; RGBPixel rgbPixel; rgbPixel.red = red; rgbPixel.green = green; rgbPixel.blue = blue; const unsigned int numPixelsToTransform = 1; cmsDoTransform(transform, &rgbPixel, &xyzPixel, numPixelsToTransform); cmsCIEXYZ xyzPixelXYZ; xyzPixelXYZ.X = xyzPixel.X; xyzPixelXYZ.Y = xyzPixel.Y; xyzPixelXYZ.Z = xyzPixel.Z; cmsCIExyY xyzPixelxyY; cmsXYZ2xyY(&xyzPixelxyY, &xyzPixelXYZ); cmsDeleteTransform(transform); cmsCloseProfile(XYZProfile); KoCIExyY res; lcmsToPigmentViceVersaStructureCopy(res, xyzPixelxyY); return res; }
int main(int argc, char* argv[]) { int r, g, b; cmsUInt8Number RGB[3], RGB_OUT[3]; cmsHTRANSFORM xform; cmsHPROFILE hProfile; double err, SumX=0, SumX2=0, Peak = 0, n = 0; if (argc != 2) { printf("roundtrip <RGB icc profile>\n"); return 1; } hProfile = cmsOpenProfileFromFile(argv[1], "r"); xform = cmsCreateTransform(hProfile,TYPE_RGB_8, hProfile, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE); for (r=0; r< 256; r++) { printf("%d \r", r); for (g=0; g < 256; g++) { for (b=0; b < 256; b++) { RGB[0] = r; RGB[1] = g; RGB[2] = b; cmsDoTransform(xform, RGB, RGB_OUT, 1); err = VecDist(RGB, RGB_OUT); SumX += err; SumX2 += err * err; n += 1.0; if (err > Peak) Peak = err; } } } printf("Average %g\n", SumX / n); printf("Max %g\n", Peak); printf("Std %g\n", sqrt((n*SumX2 - SumX * SumX) / (n*(n-1)))); cmsCloseProfile(hProfile); cmsDeleteTransform(xform); return 0; }
static void CloseTransforms(void) { int i; if (hColorTransform) cmsDeleteTransform(hColorTransform); if (hInput) cmsCloseProfile(hInput); if (hOutput) cmsCloseProfile(hOutput); if (hProof) cmsCloseProfile(hProof); for (i=0; i < nProfiles; i++) cmsCloseProfile(hProfiles[i]); hColorTransform = NULL; hInput = NULL; hOutput = NULL; hProof = NULL; }
// Detect Total area coverage of the profile cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) { cmsTACestimator bp; cmsUInt32Number dwFormatter; cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS]; cmsHPROFILE hLab; cmsContext ContextID = cmsGetProfileContextID(hProfile); // TAC only works on output profiles if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) { return 0; } // Create a fake formatter for result dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE); bp.nOutputChans = T_CHANNELS(dwFormatter); bp.MaxTAC = 0; // Initial TAC is 0 // for safety if (bp.nOutputChans >= cmsMAXCHANNELS) return 0; hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); if (hLab == NULL) return 0; // Setup a roundtrip on perceptual intent in output profile for TAC estimation bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16, hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); cmsCloseProfile(hLab); if (bp.hRoundTrip == NULL) return 0; // For L* we only need black and white. For C* we need many points GridPoints[0] = 6; GridPoints[1] = 74; GridPoints[2] = 74; if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) { bp.MaxTAC = 0; } cmsDeleteTransform(bp.hRoundTrip); // Results in % return bp.MaxTAC; }
static void color_man_cache_unref(ColorManCache *cc) { if (!cc) return; cc->refcount--; if (cc->refcount < 1) { if (cc->transform) cmsDeleteTransform(cc->transform); if (cc->profile_in) cmsCloseProfile(cc->profile_in); if (cc->profile_out) cmsCloseProfile(cc->profile_out); g_free(cc->profile_in_file); g_free(cc->profile_out_file); g_free(cc); } }
static int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent) { cmsHTRANSFORM xform; cmsHPROFILE hLab; int i, nColors; char ColorName[32]; cmsNAMEDCOLORLIST* NamedColorList; hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0); if (xform == NULL) return 0; NamedColorList = cmsGetNamedColorList(xform); if (NamedColorList == NULL) return 0; _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA"); _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); nColors = cmsNamedColorCount(NamedColorList); for (i=0; i < nColors; i++) { cmsUInt16Number In[1]; cmsCIELab Lab; In[0] = (cmsUInt16Number) i; if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) continue; cmsDoTransform(xform, In, &Lab, 1); _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b); } _cmsIOPrintf(m, ">>\n"); cmsDeleteTransform(xform); cmsCloseProfile(hLab); return 1; }
static void cdisplay_proof_finalize (GObject *object) { CdisplayProof *proof = CDISPLAY_PROOF (object); if (proof->profile) { g_free (proof->profile); proof->profile = NULL; } if (proof->transform) { cmsDeleteTransform (proof->transform); proof->transform = NULL; } G_OBJECT_CLASS (cdisplay_proof_parent_class)->finalize (object); }
// Compute K -> L* relationship. Flags may include black point compensation. In this case, // the relationship is assumed from the profile with BPC to a black point zero. static cmsToneCurve* ComputeKToLstar(cmsContext ContextID, cmsUInt32Number nPoints, cmsUInt32Number nProfiles, const cmsUInt32Number Intents[], const cmsHPROFILE hProfiles[], const cmsBool BPC[], const cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) { cmsToneCurve* out = NULL; cmsUInt32Number i; cmsHTRANSFORM xform; cmsCIELab Lab; cmsFloat32Number cmyk[4]; cmsFloat32Number* SampledPoints; xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags); if (xform == NULL) return NULL; SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number)); if (SampledPoints == NULL) goto Error; for (i=0; i < nPoints; i++) { cmyk[0] = 0; cmyk[1] = 0; cmyk[2] = 0; cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1)); cmsDoTransform(xform, cmyk, &Lab, 1); SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation } out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints); Error: cmsDeleteTransform(xform); if (SampledPoints) _cmsFree(ContextID, SampledPoints); return out; }
BOOL close_transform( HTRANSFORM handle ) { DWORD_PTR index; struct transform *transform; EnterCriticalSection( &MSCMS_handle_cs ); index = (DWORD_PTR)handle - 1; if (index > num_transform_handles) { LeaveCriticalSection( &MSCMS_handle_cs ); return FALSE; } transform = &transformtable[index]; cmsDeleteTransform( transform->cmstransform ); memset( transform, 0, sizeof(struct transform) ); LeaveCriticalSection( &MSCMS_handle_cs ); return TRUE; }
static void gimp_image_convert_profile_indexed (GimpImage *image, GimpColorProfile *src_profile, GimpColorProfile *dest_profile, GimpColorRenderingIntent intent, gboolean bpc, GimpProgress *progress) { cmsHPROFILE src_lcms; cmsHPROFILE dest_lcms; guchar *cmap; gint n_colors; GimpColorTransform transform; src_lcms = gimp_color_profile_get_lcms_profile (src_profile); dest_lcms = gimp_color_profile_get_lcms_profile (dest_profile); n_colors = gimp_image_get_colormap_size (image); cmap = g_memdup (gimp_image_get_colormap (image), n_colors * 3); transform = cmsCreateTransform (src_lcms, TYPE_RGB_8, dest_lcms, TYPE_RGB_8, intent, cmsFLAGS_NOOPTIMIZE | (bpc ? cmsFLAGS_BLACKPOINTCOMPENSATION : 0)); if (transform) { cmsDoTransform (transform, cmap, cmap, n_colors); cmsDeleteTransform (transform); gimp_image_set_colormap (image, cmap, n_colors, TRUE); } else { g_warning ("cmsCreateTransform() failed!"); } g_free (cmap); }
static void cdisplay_proof_changed (GimpColorDisplay *display) { CdisplayProof *proof = CDISPLAY_PROOF (display); cmsHPROFILE rgbProfile; cmsHPROFILE proofProfile; if (proof->transform) { cmsDeleteTransform (proof->transform); proof->transform = NULL; } if (! proof->profile) return; rgbProfile = cmsCreate_sRGBProfile (); proofProfile = cmsOpenProfileFromFile (proof->profile, "r"); if (proofProfile) { DWORD flags = cmsFLAGS_SOFTPROOFING; if (proof->bpc) flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; proof->transform = cmsCreateProofingTransform (rgbProfile, TYPE_RGB_8, rgbProfile, TYPE_RGB_8, proofProfile, proof->intent, proof->intent, flags); cmsCloseProfile (proofProfile); } cmsCloseProfile (rgbProfile); }
static cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent) { cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); cmsHPROFILE hXYZ = cmsCreateXYZProfile(); cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE); int i; for (i=0; i < 256; i++) { cmsUInt8Number Gray = (cmsUInt8Number) i; cmsCIEXYZ XYZ; cmsDoTransform(xform, &Gray, &XYZ, 1); Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0); } cmsDeleteTransform(xform); cmsCloseProfile(hXYZ); return Out; }
// Get a black point of output CMYK profile, discounting any ink-limiting embedded // in the profile. For doing that, we use perceptual intent in input direction: // Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab static cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile) { cmsHTRANSFORM hRoundTrip; cmsCIELab LabIn, LabOut; cmsCIEXYZ BlackXYZ; // Is the intent supported by the profile? if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return TRUE; } hRoundTrip = CreateRoundtripXForm(hProfile, INTENT_PERCEPTUAL); if (hRoundTrip == NULL) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } LabIn.L = LabIn.a = LabIn.b = 0; cmsDoTransform(hRoundTrip, &LabIn, &LabOut, 1); // Clip Lab to reasonable limits if (LabOut.L > 50) LabOut.L = 50; LabOut.a = LabOut.b = 0; cmsDeleteTransform(hRoundTrip); // Convert it to XYZ cmsLab2XYZ(NULL, &BlackXYZ, &LabOut); if (BlackPoint != NULL) *BlackPoint = BlackXYZ; return TRUE; }
void CorrectImage(wxImage& image, const vigra::ImageImportInfo::ICCProfile& iccProfile, const cmsHPROFILE& monitorProfile) { cmsHPROFILE inputICC = NULL; if (!iccProfile.empty()) { inputICC = cmsOpenProfileFromMem(iccProfile.data(), iccProfile.size()); }; // check type of input profile if (inputICC != NULL) { if (cmsGetColorSpace(inputICC) != cmsSigRgbData) { cmsCloseProfile(inputICC); inputICC = NULL; }; }; // if there is no icc profile in file fall back to sRGB if (inputICC == NULL) { inputICC = cmsCreate_sRGBProfile(); }; // now build transform cmsHTRANSFORM transform = cmsCreateTransform(inputICC, TYPE_RGB_8, monitorProfile, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_BLACKPOINTCOMPENSATION); unsigned char* imgData = image.GetData(); const int imgWidth = image.GetWidth(); const int imgHeight = image.GetHeight(); #pragma omp parallel for for (int y = 0; y < imgHeight; ++y) { cmsDoTransform(transform, imgData + 3 * y * imgWidth, imgData + 3 * y * imgWidth, imgWidth); }; cmsDeleteTransform(transform); cmsCloseProfile(inputICC); };
cmsBool GetProfileRGBPrimaries(cmsHPROFILE hProfile, cmsCIEXYZTRIPLE* const result, cmsUInt32Number intent) { cmsHPROFILE hXYZ; cmsHTRANSFORM hTransform; cmsFloat64Number rgb[3][3] = {{1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}}; hXYZ = cmsCreateXYZProfile(); if (hXYZ == NULL) return FALSE; hTransform = cmsCreateTransform(hProfile, TYPE_RGB_DBL, hXYZ, TYPE_XYZ_DBL, intent, cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE); cmsCloseProfile(hXYZ); if (hTransform == NULL) return FALSE; cmsDoTransform(hTransform, rgb, result, 3); cmsDeleteTransform(hTransform); return TRUE; }
static void gimp_image_convert_profile_rgb (GimpImage *image, GimpColorProfile *src_profile, GimpColorProfile *dest_profile, GimpColorRenderingIntent intent, gboolean bpc, GimpProgress *progress) { GList *layers; GList *list; gint n_drawables; gint nth_drawable; layers = gimp_image_get_layer_list (image); n_drawables = g_list_length (layers); for (list = layers, nth_drawable = 0; list; list = g_list_next (list), nth_drawable++) { GimpDrawable *drawable = list->data; cmsHPROFILE src_lcms; cmsHPROFILE dest_lcms; const Babl *iter_format; cmsUInt32Number lcms_format; cmsUInt32Number flags; cmsHTRANSFORM transform; if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable))) continue; src_lcms = gimp_color_profile_get_lcms_profile (src_profile); dest_lcms = gimp_color_profile_get_lcms_profile (dest_profile); iter_format = gimp_color_profile_get_format (gimp_drawable_get_format (drawable), &lcms_format); flags = cmsFLAGS_NOOPTIMIZE; if (bpc) flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; transform = cmsCreateTransform (src_lcms, lcms_format, dest_lcms, lcms_format, intent, flags); if (transform) { GeglBuffer *buffer; GeglBufferIterator *iter; buffer = gimp_drawable_get_buffer (drawable); gimp_drawable_push_undo (drawable, NULL, NULL, 0, 0, gegl_buffer_get_width (buffer), gegl_buffer_get_height (buffer)); iter = gegl_buffer_iterator_new (buffer, NULL, 0, iter_format, GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { cmsDoTransform (transform, iter->data[0], iter->data[0], iter->length); } gimp_drawable_update (drawable, 0, 0, gegl_buffer_get_width (buffer), gegl_buffer_get_height (buffer)); cmsDeleteTransform (transform); } if (progress) gimp_progress_set_value (progress, (gdouble) nth_drawable / (gdouble) n_drawables); } g_list_free (layers); }
static int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags) { cmsHPROFILE hLab; cmsHTRANSFORM xform; cmsUInt32Number nChannels; cmsUInt32Number InputFormat; int rc; cmsHPROFILE Profiles[2]; cmsCIEXYZ BlackPointAdaptedToD50; // Does create a device-link based transform. // The DeviceLink is next dumped as working CSA. InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); nChannels = T_CHANNELS(InputFormat); cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); // Adjust output to Lab4 hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); Profiles[0] = hProfile; Profiles[1] = hLab; xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0); cmsCloseProfile(hLab); if (xform == NULL) { cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab"); return 0; } // Only 1, 3 and 4 channels are allowed switch (nChannels) { case 1: { cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50); cmsFreeToneCurve(Gray2Y); } break; case 3: case 4: { cmsUInt32Number OutFrm = TYPE_Lab_16; cmsPipeline* DeviceLink; _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; DeviceLink = cmsPipelineDup(v ->Lut); if (DeviceLink == NULL) return 0; dwFlags |= cmsFLAGS_FORCE_CLUT; _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); cmsPipelineFree(DeviceLink); } break; default: cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels); return 0; } cmsDeleteTransform(xform); return 1; }
static int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags) { cmsHPROFILE hLab; cmsHTRANSFORM xform; int i, nChannels; cmsUInt32Number OutputFormat; _cmsTRANSFORM* v; cmsPipeline* DeviceLink; cmsHPROFILE Profiles[3]; cmsCIEXYZ BlackPointAdaptedToD50; cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP); cmsUInt32Number InFrm = TYPE_Lab_16; int RelativeEncodingIntent; cmsColorSpaceSignature ColorSpace; hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); if (hLab == NULL) return 0; OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); nChannels = T_CHANNELS(OutputFormat); ColorSpace = cmsGetColorSpace(hProfile); // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision. RelativeEncodingIntent = Intent; if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; // Use V4 Lab always Profiles[0] = hLab; Profiles[1] = hProfile; xform = cmsCreateMultiprofileTransformTHR(m ->ContextID, Profiles, 2, TYPE_Lab_DBL, OutputFormat, RelativeEncodingIntent, 0); cmsCloseProfile(hLab); if (xform == NULL) { cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); return 0; } // Get a copy of the internal devicelink v = (_cmsTRANSFORM*) xform; DeviceLink = cmsPipelineDup(v ->Lut); if (DeviceLink == NULL) return 0; // We need a CLUT dwFlags |= cmsFLAGS_FORCE_CLUT; _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "/ColorRenderingType 1\n"); cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); // Emit headers, etc. EmitWhiteBlackD50(m, &BlackPointAdaptedToD50); EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); EmitXYZ2Lab(m); // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127, // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to // zero. This would sacrifice a bit of highlights, but failure to do so would cause // scum dot. Ouch. if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) lFixWhite = FALSE; _cmsIOPrintf(m, "/RenderTable "); WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace); _cmsIOPrintf(m, " %d {} bind ", nChannels); for (i=1; i < nChannels; i++) _cmsIOPrintf(m, "dup "); _cmsIOPrintf(m, "]\n"); EmitIntent(m, Intent); _cmsIOPrintf(m, ">>\n"); if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n"); } cmsPipelineFree(DeviceLink); cmsDeleteTransform(xform); return 1; }