void createColorTransform(const ColorProfile& colorProfile, bool hasAlpha, bool sRGB) { clearColorTransform(); if (colorProfile.isEmpty() && !sRGB) return; qcms_profile* deviceProfile = ImageDecoder::qcmsOutputDeviceProfile(); if (!deviceProfile) return; qcms_profile* inputProfile = 0; if (!colorProfile.isEmpty()) inputProfile = qcms_profile_from_memory(colorProfile.data(), colorProfile.size()); else inputProfile = qcms_profile_sRGB(); if (!inputProfile) return; // We currently only support color profiles for RGB and RGBA images. ASSERT(rgbData == qcms_profile_get_color_space(inputProfile)); if (qcms_profile_match(inputProfile, deviceProfile)) { qcms_profile_release(inputProfile); return; } // FIXME: Don't force perceptual intent if the image profile contains an intent. qcms_data_type dataFormat = hasAlpha ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_8; m_transform = qcms_transform_create(inputProfile, dataFormat, deviceProfile, dataFormat, QCMS_INTENT_PERCEPTUAL); qcms_profile_release(inputProfile); }
void ColorCodecBench::onDelayedSetup() { SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded)); fSrcData = codec->getICCData(); sk_sp<SkData> dstData = SkData::MakeFromFileName( GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str()); SkASSERT(dstData); fDstSpace = nullptr; #if defined(SK_TEST_QCMS) if (FLAGS_qcms) { fDstSpaceQCMS.reset(FLAGS_srgb ? qcms_profile_sRGB() : qcms_profile_from_memory(dstData->data(), dstData->size())); SkASSERT(fDstSpaceQCMS); // This call takes a non-trivial amount of time, but I think it's the most fair to // treat it as overhead. It only needs to happen once. qcms_profile_precache_output_transform(fDstSpaceQCMS); } else #endif { fDstSpace = FLAGS_srgb ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : SkColorSpace::MakeICC(dstData->data(), dstData->size()); SkASSERT(fDstSpace); } fSrcInfo = codec->getInfo().makeColorType(kRGBA_8888_SkColorType); fDstInfo = fSrcInfo; if (FLAGS_half) { fDstInfo = fDstInfo.makeColorType(kRGBA_F16_SkColorType); SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(fDstSpace)->type()); fDstSpace = static_cast<SkColorSpace_XYZ*>(fDstSpace.get())->makeLinearGamma(); } if (FLAGS_nonstd) { SkColorSpaceTransferFn gamma; gamma.fA = 1.0f; gamma.fB = gamma.fC = gamma.fD = gamma.fE = gamma.fF = 0.0f; gamma.fG = 4.0f; SkMatrix44 matrix = SkMatrix44(SkMatrix44::kUninitialized_Constructor); matrix.set3x3(0.30f, 0.31f, 0.28f, 0.32f, 0.33f, 0.29f, 0.27f, 0.30f, 0.30f); fDstSpace = SkColorSpace::MakeRGB(gamma, matrix); } fDstInfo = fDstInfo.makeColorSpace(fDstSpace); fDst.reset(fDstInfo.getSafeSize(fDstInfo.minRowBytes())); if (FLAGS_xform_only) { fSrc.reset(fSrcInfo.getSafeSize(fSrcInfo.minRowBytes())); codec->getPixels(fSrcInfo, fSrc.get(), fSrcInfo.minRowBytes()); } #if defined(SK_TEST_QCMS) else if (FLAGS_qcms) { // Set-up a row buffer to decode into before transforming to dst. fSrc.reset(fSrcInfo.minRowBytes()); } #endif }
TESTFUNC_TYPE LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { qcms_enable_iccv4(); qcms_profile* profile = qcms_profile_from_memory(data, size); if (!profile) { return 0; } qcms_profile* srgb_profile = qcms_profile_sRGB(); if (!srgb_profile) { qcms_profile_release(profile); return 0; } transform(profile, srgb_profile, size); // Firefox only checks the display (destination) profile. if (qcms_profile_is_bogus(profile)) { goto release_profiles; }; transform(srgb_profile, profile, size); release_profiles: qcms_profile_release(profile); qcms_profile_release(srgb_profile); return 0; }
// ----------------------------------------------------------------------------- // Color profile handling static int ApplyColorProfile(const WebPData* const profile, WebPDecBuffer* const rgba) { #ifdef WEBP_HAVE_QCMS int i, ok = 0; uint8_t* line; uint8_t major_revision; qcms_profile* input_profile = NULL; qcms_profile* output_profile = NULL; qcms_transform* transform = NULL; const qcms_data_type input_type = QCMS_DATA_RGBA_8; const qcms_data_type output_type = QCMS_DATA_RGBA_8; const qcms_intent intent = QCMS_INTENT_DEFAULT; if (profile == NULL || rgba == NULL) return 0; if (profile->bytes == NULL || profile->size < 10) return 1; major_revision = profile->bytes[8]; qcms_enable_iccv4(); input_profile = qcms_profile_from_memory(profile->bytes, profile->size); // qcms_profile_is_bogus() is broken with ICCv4. if (input_profile == NULL || (major_revision < 4 && qcms_profile_is_bogus(input_profile))) { fprintf(stderr, "Color profile is bogus!\n"); goto Error; } output_profile = qcms_profile_sRGB(); if (output_profile == NULL) { fprintf(stderr, "Error creating output color profile!\n"); goto Error; } qcms_profile_precache_output_transform(output_profile); transform = qcms_transform_create(input_profile, input_type, output_profile, output_type, intent); if (transform == NULL) { fprintf(stderr, "Error creating color transform!\n"); goto Error; } line = rgba->u.RGBA.rgba; for (i = 0; i < rgba->height; ++i, line += rgba->u.RGBA.stride) { qcms_transform_data(transform, line, line, rgba->width); } ok = 1; Error: if (input_profile != NULL) qcms_profile_release(input_profile); if (output_profile != NULL) qcms_profile_release(output_profile); if (transform != NULL) qcms_transform_release(transform); return ok; #else (void)profile; (void)rgba; return 1; #endif // WEBP_HAVE_QCMS }
qcms_profile * gfxPlatform::GetCMSsRGBProfile() { if (!gCMSsRGBProfile) { /* Create the profile using qcms. */ gCMSsRGBProfile = qcms_profile_sRGB(); } return gCMSsRGBProfile; }
void do_test(void) { unsigned char srct[4] = { 221, 79, 129, 92}; unsigned char outt[4]; qcms_transform *transform; qcms_profile *input_profile, *output_profile, *rgb; qcms_CIE_xyY white_point = { 0, 0, 1.}; qcms_CIE_xyYTRIPLE primaries = { {.9, .3, 1.}, {.2, .4, 1.}, {.7, .4, 1.}}; rgb = qcms_profile_create_rgb_with_gamma(white_point, primaries, 1.8); input_profile = qcms_profile_sRGB(); output_profile = qcms_profile_sRGB(); if (output_profile) { test_gray(output_profile); test_gray_precache(output_profile); qcms_profile_release(output_profile); } if (input_profile) qcms_profile_release(input_profile); if (rgb) qcms_profile_release(rgb); rgb = qcms_profile_from_path("sample-trunc.icc"); if (rgb) qcms_profile_release(rgb); }
static int qcms_test_internal_srgb(size_t width, size_t height, int iterations, const char *in_path, const char *out_path, const int force_software) { qcms_profile *profile = qcms_profile_sRGB(); s15Fixed16Number sRGB_internal[3][3]; s15Fixed16Number diff = 0; int i, j; printf("Test qcms internal sRGB colorant matrix against official sRGB IEC61966-2.1 color (D50) primaries\n"); sRGB_internal[0][0] = profile->redColorant.X; sRGB_internal[1][0] = profile->redColorant.Y; sRGB_internal[2][0] = profile->redColorant.Z; sRGB_internal[0][1] = profile->greenColorant.X; sRGB_internal[1][1] = profile->greenColorant.Y; sRGB_internal[2][1] = profile->greenColorant.Z; sRGB_internal[0][2] = profile->blueColorant.X; sRGB_internal[1][2] = profile->blueColorant.Y; sRGB_internal[2][2] = profile->blueColorant.Z; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { s15Fixed16Number tmp = sRGB_internal[i][j] - sRGB_reference[i][j]; printf("\t%d", tmp); diff += abs(tmp); } printf("\n"); } qcms_profile_release(profile); printf("Total error = 0x%x [%.6f]\n", diff, diff / 65536.0); return diff; }
// Adapted from http://www.littlecms.com/pngchrm.c example code static qcms_profile* PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr, int color_type, qcms_data_type* inType, uint32_t* intent) { qcms_profile* profile = nullptr; *intent = QCMS_INTENT_PERCEPTUAL; // Our default // First try to see if iCCP chunk is present if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_uint_32 profileLen; png_bytep profileData; png_charp profileName; int compression; png_get_iCCP(png_ptr, info_ptr, &profileName, &compression, &profileData, &profileLen); profile = qcms_profile_from_memory((char*)profileData, profileLen); if (profile) { uint32_t profileSpace = qcms_profile_get_color_space(profile); bool mismatch = false; if (color_type & PNG_COLOR_MASK_COLOR) { if (profileSpace != icSigRgbData) { mismatch = true; } } else { if (profileSpace == icSigRgbData) { png_set_gray_to_rgb(png_ptr); } else if (profileSpace != icSigGrayData) { mismatch = true; } } if (mismatch) { qcms_profile_release(profile); profile = nullptr; } else { *intent = qcms_profile_get_rendering_intent(profile); } } } // Check sRGB chunk if (!profile && png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { profile = qcms_profile_sRGB(); if (profile) { int fileIntent; png_set_gray_to_rgb(png_ptr); png_get_sRGB(png_ptr, info_ptr, &fileIntent); uint32_t map[] = { QCMS_INTENT_PERCEPTUAL, QCMS_INTENT_RELATIVE_COLORIMETRIC, QCMS_INTENT_SATURATION, QCMS_INTENT_ABSOLUTE_COLORIMETRIC }; *intent = map[fileIntent]; } } // Check gAMA/cHRM chunks if (!profile && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA) && png_get_valid(png_ptr, info_ptr, PNG_INFO_cHRM)) { qcms_CIE_xyYTRIPLE primaries; qcms_CIE_xyY whitePoint; png_get_cHRM(png_ptr, info_ptr, &whitePoint.x, &whitePoint.y, &primaries.red.x, &primaries.red.y, &primaries.green.x, &primaries.green.y, &primaries.blue.x, &primaries.blue.y); whitePoint.Y = primaries.red.Y = primaries.green.Y = primaries.blue.Y = 1.0; double gammaOfFile; png_get_gAMA(png_ptr, info_ptr, &gammaOfFile); profile = qcms_profile_create_rgb_with_gamma(whitePoint, primaries, 1.0/gammaOfFile); if (profile) { png_set_gray_to_rgb(png_ptr); } } if (profile) { uint32_t profileSpace = qcms_profile_get_color_space(profile); if (profileSpace == icSigGrayData) { if (color_type & PNG_COLOR_MASK_ALPHA) { *inType = QCMS_DATA_GRAYA_8; } else { *inType = QCMS_DATA_GRAY_8; } } else { if (color_type & PNG_COLOR_MASK_ALPHA || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { *inType = QCMS_DATA_RGBA_8; } else { *inType = QCMS_DATA_RGB_8; } } } return profile; }