diff options
author | Matt Sarett <msarett@google.com> | 2016-11-01 12:19:50 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2016-11-01 16:45:40 +0000 |
commit | a9e9bfc6e40894c0447c044a380c74061cb9e15e (patch) | |
tree | e8753d1cb647661e5212b4208aa704499985029d | |
parent | 10d665d000cfdce693b7ca088fb2c61ed54bcdfb (diff) |
Delete qcms
This was always intended to be a temporary dependency to use for
testing. It has served its purpose.
Also, this has already been dropped (accidentally, I think) by
the new GN build.
TBR=reed@google.com
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4220
Change-Id: Ic72ee08bbfaf86ed86a4122fd38be2921eb1327e
Reviewed-on: https://skia-review.googlesource.com/4220
Reviewed-by: Matt Sarett <msarett@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
41 files changed, 33 insertions, 8539 deletions
diff --git a/bench/ColorCodecBench.cpp b/bench/ColorCodecBench.cpp index b0ae7e3730..8df7e65beb 100644 --- a/bench/ColorCodecBench.cpp +++ b/bench/ColorCodecBench.cpp @@ -13,9 +13,6 @@ #include "SkColorSpaceXform.h" #include "SkCommandLineFlags.h" -#if defined(SK_TEST_QCMS) -DEFINE_bool(qcms, false, "Bench qcms color conversion"); -#endif DEFINE_bool(xform_only, false, "Only time the color xform, do not include the decode time"); DEFINE_bool(srgb, false, "Convert to srgb dst space"); DEFINE_bool(nonstd, false, "Convert to non-standard dst space"); @@ -23,14 +20,8 @@ DEFINE_bool(half, false, "Convert to half floats"); ColorCodecBench::ColorCodecBench(const char* name, sk_sp<SkData> encoded) : fEncoded(std::move(encoded)) -#if defined(SK_TEST_QCMS) - , fDstSpaceQCMS(nullptr) -#endif { fName.appendf("Color%s", FLAGS_xform_only ? "Xform" : "Codec"); -#if defined(SK_TEST_QCMS) - fName.appendf("%s", FLAGS_qcms ? "QCMS" : ""); -#endif fName.appendf("_%s", name); } @@ -53,50 +44,8 @@ void ColorCodecBench::decodeAndXform() { SkASSERT(SkCodec::kSuccess == result); } -#if defined(SK_TEST_QCMS) -void ColorCodecBench::decodeAndXformQCMS() { - SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded)); -#ifdef SK_DEBUG - const SkCodec::Result result = -#endif - codec->startScanlineDecode(fSrcInfo); - SkASSERT(SkCodec::kSuccess == result); - - SkAutoTCallVProc<qcms_profile, qcms_profile_release> - srcSpace(qcms_profile_from_memory(fSrcData->data(), fSrcData->size())); - SkASSERT(srcSpace); - - SkAutoTCallVProc<qcms_transform, qcms_transform_release> - transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, fDstSpaceQCMS.get(), - QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL)); - SkASSERT(transform); - -#ifdef SK_PMCOLOR_IS_RGBA - qcms_output_type outType = QCMS_OUTPUT_RGBX; -#else - qcms_output_type outType = QCMS_OUTPUT_BGRX; -#endif - - void* dst = fDst.get(); - for (int y = 0; y < fSrcInfo.height(); y++) { -#ifdef SK_DEBUG - const int rows = -#endif - codec->getScanlines(fSrc.get(), 1, 0); - SkASSERT(1 == rows); - - qcms_transform_data_type(transform, fSrc.get(), dst, fSrcInfo.width(), outType); - dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes()); - } -} -#endif - void ColorCodecBench::xformOnly() { - sk_sp<SkColorSpace> srcSpace = SkColorSpace::MakeICC(fSrcData->data(), fSrcData->size()); - if (!srcSpace) { - srcSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); - } - std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace.get(), + std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(fSrcSpace.get(), fDstSpace.get()); SkASSERT(xform); @@ -111,70 +60,15 @@ void ColorCodecBench::xformOnly() { } } -#if defined(SK_TEST_QCMS) -void ColorCodecBench::xformOnlyQCMS() { - SkAutoTCallVProc<qcms_profile, qcms_profile_release> - srcSpace(qcms_profile_from_memory(fSrcData->data(), fSrcData->size())); - SkASSERT(srcSpace); - - SkAutoTCallVProc<qcms_transform, qcms_transform_release> - transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, fDstSpaceQCMS.get(), - QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL)); - SkASSERT(transform); - -#ifdef SK_PMCOLOR_IS_RGBA - qcms_output_type outType = QCMS_OUTPUT_RGBX; -#else - qcms_output_type outType = QCMS_OUTPUT_BGRX; -#endif - - void* dst = fDst.get(); - void* src = fSrc.get(); - for (int y = 0; y < fSrcInfo.height(); y++) { - // Transform in place - qcms_transform_data_type(transform, src, dst, fSrcInfo.width(), outType); - dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes()); - src = SkTAddOffset<void>(src, fSrcInfo.minRowBytes()); - } -} -#endif - 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) { + fDstSpace = nullptr; + if (FLAGS_srgb) { + fDstSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); + } else if (FLAGS_nonstd) { SkColorSpaceTransferFn gamma; gamma.fA = 1.0f; gamma.fB = gamma.fC = gamma.fD = gamma.fE = gamma.fF = 0.0f; @@ -182,48 +76,36 @@ void ColorCodecBench::onDelayedSetup() { 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); + } else { + sk_sp<SkData> dstData = SkData::MakeFromFileName( + GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str()); + SkASSERT(dstData); + fDstSpace = SkColorSpace::MakeICC(dstData->data(), dstData->size()); } - + SkASSERT(fDstSpace); fDstInfo = fDstInfo.makeColorSpace(fDstSpace); + 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(); + } + fDst.reset(fDstInfo.getSafeSize(fDstInfo.minRowBytes())); if (FLAGS_xform_only) { fSrc.reset(fSrcInfo.getSafeSize(fSrcInfo.minRowBytes())); + fSrcSpace = sk_ref_sp(codec->getInfo().colorSpace()); 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 } void ColorCodecBench::onDraw(int n, SkCanvas*) { -#if defined(SK_TEST_QCMS) - if (FLAGS_qcms && FLAGS_half) { - SkDebugf("Error: Contradicting flags.\n"); - return; - } -#endif - for (int i = 0; i < n; i++) { -#if defined(SK_TEST_QCMS) - if (FLAGS_qcms) { - if (FLAGS_xform_only) { - this->xformOnlyQCMS(); - } else { - this->decodeAndXformQCMS(); - } - } else -#endif - { - if (FLAGS_xform_only) { - this->xformOnly(); - } else { - this->decodeAndXform(); - } + if (FLAGS_xform_only) { + this->xformOnly(); + } else { + this->decodeAndXform(); } } } diff --git a/bench/ColorCodecBench.h b/bench/ColorCodecBench.h index 45bf41ec2d..9159bcf9ad 100644 --- a/bench/ColorCodecBench.h +++ b/bench/ColorCodecBench.h @@ -12,10 +12,6 @@ #include "SkData.h" #include "SkImageInfo.h" -#if defined(SK_TEST_QCMS) -#include "qcms.h" -#endif - class ColorCodecBench : public Benchmark { public: ColorCodecBench(const char* name, sk_sp<SkData> encoded); @@ -29,22 +25,15 @@ protected: private: void decodeAndXform(); void xformOnly(); -#if !defined(GOOGLE3) - void decodeAndXformQCMS(); - void xformOnlyQCMS(); -#endif - SkString fName; - sk_sp<SkData> fEncoded; - SkImageInfo fSrcInfo; - SkImageInfo fDstInfo; - SkAutoMalloc fDst; - SkAutoMalloc fSrc; - sk_sp<SkColorSpace> fDstSpace; -#if defined(SK_TEST_QCMS) - SkAutoTCallVProc<qcms_profile, qcms_profile_release> fDstSpaceQCMS; -#endif - sk_sp<SkData> fSrcData; + SkString fName; + sk_sp<SkData> fEncoded; + SkImageInfo fSrcInfo; + SkImageInfo fDstInfo; + SkAutoMalloc fDst; + SkAutoMalloc fSrc; + sk_sp<SkColorSpace> fDstSpace; + sk_sp<SkColorSpace> fSrcSpace; typedef Benchmark INHERITED; }; @@ -797,12 +797,6 @@ static bool gather_srcs() { push_src("colorImage", "color_codec_sRGB_kN32", src); src = new ColorCodecSrc(colorImage, ColorCodecSrc::kDst_sRGB_Mode, kRGBA_F16_SkColorType); push_src("colorImage", "color_codec_sRGB_kF16", src); - -#if defined(SK_TEST_QCMS) - src = new ColorCodecSrc(colorImage, ColorCodecSrc::kQCMS_HPZR30w_Mode, - kRGBA_8888_SkColorType); - push_src("colorImage", "color_codec_QCMS_HPZR30w", src); -#endif } return true; diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index 4c428a7b9c..d519860a17 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -45,10 +45,6 @@ #include "SkAutoCoInitialize.h" #endif -#if defined(SK_TEST_QCMS) - #include "qcms.h" -#endif - #if defined(SK_XML) #include "SkSVGDOM.h" #include "SkXMLWriter.h" @@ -965,10 +961,6 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const { } bool runInLegacyMode = kBaseline_Mode == fMode; -#if defined(SK_TEST_QCMS) - runInLegacyMode = runInLegacyMode || kQCMS_HPZR30w_Mode == fMode; -#endif - if (runInLegacyMode && canvas->imageInfo().colorSpace()) { return Error::Nonfatal("Skipping tests that are only interesting in legacy mode."); } else if (!runInLegacyMode && !canvas->imageInfo().colorSpace()) { @@ -1038,51 +1030,6 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const { case kDst_HPZR30w_Mode: canvas->drawBitmap(bitmap, 0, 0); break; -#if defined(SK_TEST_QCMS) - case kQCMS_HPZR30w_Mode: { - sk_sp<SkData> srcData = codec->getICCData(); - if (!srcData) { - return Error::Nonfatal("No ICC profile data. Cannot test with QCMS.\n"); - } - - SkAutoTCallVProc<qcms_profile, qcms_profile_release> - srcSpace(qcms_profile_from_memory(srcData->data(), srcData->size())); - if (!srcSpace) { - return Error::Nonfatal(SkStringPrintf("QCMS cannot create profile for %s.\n", - fPath.c_str())); - } - - SkAutoTCallVProc<qcms_profile, qcms_profile_release> - dstSpace(qcms_profile_from_memory(dstData->data(), dstData->size())); - SkASSERT(dstSpace); - - // Optimizes conversion by precomputing the inverse transformation to dst. Also - // causes QCMS to use a completely different codepath. This is how Chrome uses QCMS. - qcms_profile_precache_output_transform(dstSpace); - SkAutoTCallVProc<qcms_transform, qcms_transform_release> - transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, dstSpace, - QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL)); - if (!transform) { - return SkStringPrintf("QCMS cannot create transform for %s.\n", fPath.c_str()); - } - -#ifdef SK_PMCOLOR_IS_RGBA - qcms_output_type outType = QCMS_OUTPUT_RGBX; -#else - qcms_output_type outType = QCMS_OUTPUT_BGRX; -#endif - - // Perform color correction. - uint32_t* row = (uint32_t*) bitmap.getPixels(); - for (int y = 0; y < decodeInfo.height(); y++) { - qcms_transform_data_type(transform, row, row, decodeInfo.width(), outType); - row = SkTAddOffset<uint32_t>(row, rowBytes); - } - - canvas->drawBitmap(bitmap, 0, 0); - break; - } -#endif default: SkASSERT(false); return "Invalid fMode"; diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h index cad15c7e86..237f5d17ad 100644 --- a/dm/DMSrcSink.h +++ b/dm/DMSrcSink.h @@ -219,11 +219,6 @@ public: kDst_HPZR30w_Mode, kDst_sRGB_Mode, - -#if defined(SK_TEST_QCMS) - // Use QCMS for color correction. - kQCMS_HPZR30w_Mode, -#endif }; ColorCodecSrc(Path, Mode, SkColorType); diff --git a/gyp/common_conditions.gypi b/gyp/common_conditions.gypi index dd51277ecf..e3afd6767d 100644 --- a/gyp/common_conditions.gypi +++ b/gyp/common_conditions.gypi @@ -28,12 +28,6 @@ 'SK_CODEC_DECODES_RAW', ], }], - [ 'skia_android_framework == 0', { - 'defines': [ - # Temporarily test against the QCMS library. - 'SK_TEST_QCMS', - ], - }], ['skia_pic', { 'cflags': [ '-fPIC', diff --git a/gyp/ports.gyp b/gyp/ports.gyp index 388498317b..7bb403da57 100644 --- a/gyp/ports.gyp +++ b/gyp/ports.gyp @@ -76,10 +76,6 @@ ['exclude', 'SkFontMgr_.+_factory\\.cpp$'], ], 'conditions': [ - [ 'skia_android_framework == 0', { - 'dependencies': [ 'qcms.gyp:qcms', ], - 'export_dependent_settings': [ 'qcms.gyp:qcms', ], - }], [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris", "android"]', { 'sources': [ '../src/ports/SkFontHost_FreeType.cpp', diff --git a/gyp/qcms.gyp b/gyp/qcms.gyp deleted file mode 100644 index fc007b3eee..0000000000 --- a/gyp/qcms.gyp +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This build file has been adapted for use in Skia. The contents of third_party/qcms -# are copied directly from Chromium. -{ - 'variables': { - 'skia_warnings_as_errors': 0, - }, - 'targets': [ - { - 'target_name': 'qcms', - 'type': 'static_library', - - # Warning (sign-conversion) fixed upstream by large refactoring. Can be - # removed on next roll. - 'msvs_disabled_warnings': [ 4018 ], - - 'direct_dependent_settings': { - 'include_dirs': [ - '../third_party/qcms/src/', - ], - }, - - 'sources': [ - '../third_party/qcms/src/chain.c', - '../third_party/qcms/src/chain.h', - '../third_party/qcms/src/iccread.c', - '../third_party/qcms/src/matrix.c', - '../third_party/qcms/src/matrix.h', - '../third_party/qcms/src/qcms.h', - '../third_party/qcms/src/qcmsint.h', - '../third_party/qcms/src/qcmstypes.h', - '../third_party/qcms/src/qcms_util.c', - '../third_party/qcms/src/transform.c', - '../third_party/qcms/src/transform_util.c', - '../third_party/qcms/src/transform_util.h', - ], - 'conditions': [ - ['"x86" in skia_arch_type', { - 'defines': [ - 'SSE2_ENABLE', - ], - 'sources': [ - '../third_party/qcms/src/transform-sse2.c', - ], - }], - ['skia_os == "win"', { - 'msvs_disabled_warnings': [ - 4056, # overflow in floating-point constant arithmetic (INFINITY) - 4756, # overflow in constant arithmetic (INFINITY) - ], - }], - ], - - # Disable warnings - 'cflags': [ - '-w', - ], - 'xcode_settings': { - 'WARNING_CFLAGS': [ - '-w' - ], - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'WarningLevel': '0', - }, - }, - - }, - ], -} diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h index f2a717c716..d5280b4833 100644 --- a/include/codec/SkCodec.h +++ b/include/codec/SkCodec.h @@ -785,12 +785,6 @@ protected: return 0; } - /** - * Used for testing with qcms. - * FIXME: Remove this when we are done comparing with qcms. - */ - virtual sk_sp<SkData> getICCData() const { return nullptr; } - private: const SkEncodedInfo fEncodedInfo; const SkImageInfo fSrcInfo; @@ -867,11 +861,6 @@ private: */ virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; } - // For testing with qcms - // FIXME: Remove these when we are done comparing with qcms. - friend class DM::ColorCodecSrc; - friend class ColorCodecBench; - friend class DM::CodecSrc; // for fillIncompleteImage friend class SkSampledCodec; friend class SkIcoCodec; diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index 9f9f85c18a..1c8ace5798 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -242,7 +242,7 @@ bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, const int width = decoderMgr->dinfo()->image_width; const int height = decoderMgr->dinfo()->image_height; *codecOut = new SkJpegCodec(width, height, info, stream, decoderMgr.release(), - std::move(colorSpace), orientation, std::move(iccData)); + std::move(colorSpace), orientation); } else { SkASSERT(nullptr != decoderMgrOut); *decoderMgrOut = decoderMgr.release(); @@ -263,15 +263,13 @@ SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { } SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, - JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origin, - sk_sp<SkData> iccData) + JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origin) : INHERITED(width, height, info, stream, std::move(colorSpace), origin) , fDecoderMgr(decoderMgr) , fReadyState(decoderMgr->dinfo()->global_state) , fSwizzleSrcRow(nullptr) , fColorXformSrcRow(nullptr) , fSwizzlerSubset(SkIRect::MakeEmpty()) - , fICCData(std::move(iccData)) {} /* diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h index 402f466b79..a889a4a4c5 100644 --- a/src/codec/SkJpegCodec.h +++ b/src/codec/SkJpegCodec.h @@ -59,8 +59,6 @@ protected: bool onDimensionsSupported(const SkISize&) override; - sk_sp<SkData> getICCData() const override { return fICCData; } - private: /* @@ -95,8 +93,7 @@ private: * takes ownership */ SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, - JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origin, - sk_sp<SkData> iccData); + JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origin); /* * Checks if the conversion between the input image and the requested output @@ -137,8 +134,6 @@ private: SkAutoTDelete<SkSwizzler> fSwizzler; - sk_sp<SkData> fICCData; - typedef SkCodec INHERITED; }; diff --git a/third_party/qcms/BUILD.gn b/third_party/qcms/BUILD.gn deleted file mode 100644 index 04db5df64a..0000000000 --- a/third_party/qcms/BUILD.gn +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -config("qcms_config") { - include_dirs = [ "src" ] -} - -# Do not build QCMS on Android or iOS. (See http://crbug.com/577155) -disable_qcms = is_android || is_ios - -source_set("qcms") { - if (disable_qcms) { - sources = [ - "src/empty.c", - ] - } else { - sources = [ - "src/chain.c", - "src/chain.h", - "src/iccread.c", - "src/matrix.c", - "src/matrix.h", - "src/qcms.h", - "src/qcms_util.c", - "src/qcmsint.h", - "src/qcmstypes.h", - "src/transform.c", - "src/transform_util.c", - "src/transform_util.h", - ] - - if (current_cpu == "x86" || current_cpu == "x64") { - defines = [ "SSE2_ENABLE" ] - sources += [ "src/transform-sse2.c" ] - } - } - - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] - public_configs = [ ":qcms_config" ] - - if (is_win) { - cflags = [ - "/wd4018", # Signed/unsigned mismatch in comparison. - "/wd4056", # Overflow in floating-point constant arithmetic (INFINITY). - "/wd4756", # Overflow in constant arithmetic (INFINITY). - ] - } -} - -if (!disable_qcms) { - executable("qcms_tests") { - if (current_cpu == "x86" || current_cpu == "x64") { - defines = [ "SSE2_ENABLE" ] - } - sources = [ - "src/tests/qcms_test_internal_srgb.c", - "src/tests/qcms_test_main.c", - "src/tests/qcms_test_munsell.c", - "src/tests/qcms_test_ntsc_gamut.c", - "src/tests/qcms_test_output_trc.c", - "src/tests/qcms_test_tetra_clut_rgba.c", - "src/tests/qcms_test_util.c", - ] - - deps = [ - "//build/config/sanitizers:deps", - "//build/win:default_exe_manifest", - "//third_party/qcms", - ] - - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] - public_configs = [ ":qcms_config" ] - } -} diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium deleted file mode 100644 index b19c005820..0000000000 --- a/third_party/qcms/README.chromium +++ /dev/null @@ -1,162 +0,0 @@ -Name: Quick Color Management System -Short Name: qcms -URL: https://github.com/jrmuizel/qcms/tree/v4 -Version: v4 -Date: 2012-03-13 -License: MIT -License File: src/COPYING -Security Critical: yes - -Description: -Contains support for applying an ICC color profile to an image. The code is -originally based on tinycms, re-written by Mozilla for better security and -performance. This copy is a source-drop from Mozilla on March 13, 2012. - -Local Modifications: -Some files only have license headers in the master branch. - - Added the same license headers to the versions brought down from the 'v4' - branch src URL qcms/tree/v4 -The following changes have been made since qcms was imported: - - Add bgra output support. - - Use HAVE_POSIX_MEMALIGN instead of HAS_POSIX_MEMALIG - (https://bugzilla.mozilla.org/show_bug.cgi?id=692922) - - Applied upstream patch: - - https://bug752254.bugzilla.mozilla.org/attachment.cgi?id=626102 - - Applied upstream patch for sanitizing gamma table: - - Expanded gamma clamp range to allow 1.0. - - Do not short-circuit bogus profile check for A2B0 or B2A0 unless v4 enabled. - - Only reference code from transform-sse1.c and transform-sse2.c when SSE is - enabled. - - Limit the use an x86-only attribute to 32-bit x86 builds. - - https://code.google.com/p/chromium/issues/detail?id=490016 - - Fix integer truncation warning/errors on Win64 build. - - Apply upstream thread safety (fix) patch from - - https://bugzilla.mozilla.org/show_bug.cgi?id=853169 - - Apply upstream fix for qcms_profile_from_memory from - - https://bugzilla.mozilla.org/show_bug.cgi?id=969226 - - Apply upstream simplification of qcmstypes.h - - https://hg.mozilla.org/mozilla-central/rev/b5be94737a83 - - Check for unused tag_len in read_nested_curveType() - - Apply qcms_transform_precacheLUT_float does not properly free dest buffer - - https://bugzilla.mozilla.org/show_bug.cgi?id=701348 - - Add qcms_profile_match api - - https://code.google.com/p/chromium/issues/detail?id=401971 - - Add qcms_profile_get_description api - - https://code.google.com/p/chromium/issues/detail?id=401971 - - Convert MLUC profile description embedded nulls to '.' - - https://code.google.com/p/chromium/issues/detail?id=401971 - - [APPLE port] Use en-localized profile description names - - https://code.google.com/p/chromium/issues/detail?id=401971 - - [APPLE port] Use mmod data for profile descriptions - - https://code.google.com/p/chromium/issues/detail?id=401971 - - Minor variable name change: description -> description_offset - - https://code.google.com/p/chromium/issues/detail?id=401971 - - Avoid divisions creating sample points in the float cube LUT builder - - https://code.google.com/p/chromium/issues/detail?id=443863 - - Add bgra (z,y,x) sampled transform lookup table api - - https://code.google.com/p/chromium/issues/detail?id=443863 - - Apply upstream fix reject invalid sizes from - - https://bugzilla.mozilla.org/show_bug.cgi?id=1132468 - - lut_inverse_interp16: remove odd whitespace formatting - - https://code.google.com/p/chromium/issues/detail?id=458024 - - lut_inverse_interp16: better handle degenerate TRC curves - - https://code.google.com/p/chromium/issues/detail?id=458024 - - Add vcgt tag reader and API to read its RGB gamma data - - https://code.google.com/p/chromium/issues/detail?id=471749 - - Consolidate loop over channels and elements in VCGT parser - - https://code.google.com/p/chromium/issues/detail?id=471749 - - Limit vcgt table to a maximum of 1024 entries - - https://code.google.com/p/chromium/issues/detail?id=471749 - - Add float to half float conversion routine - - https://code.google.com/p/chromium/issues/detail?id=491784 - - Use half float conversion tables (not functions) - - https://code.google.com/p/chromium/issues/detail?id=491784 - - Add matrix transform flag and matrix extraction api - - https://code.google.com/p/chromium/issues/detail?id=491826 - - Add tone reproduction curve (TRC) extraction api - - https://code.google.com/p/chromium/issues/detail?id=491826 - - lut_inverse_interp16: interpolate degenerate zeros in TRC curves - - https://code.google.com/p/chromium/issues/detail?id=458024 - - Make half float code self-contained: add halffloat.h - - https://code.google.com/p/chromium/issues/detail?id=491784 - - lut_inverse_interp16: fix black level inversion error - - https://code.google.com/p/chromium/issues/detail?id=504681 - - Apply upstream fix of uninitialized value - - https://github.com/jrmuizel/qcms/commit/0edb697 - - Apply Keep the output of the TRC between 0 and 1 - - https://bugzilla.mozilla.org/show_bug.cgi?id=764181 - - Drop SSE1 code as Chromium mandates SSE2 as a minimum requirement - - https://code.google.com/p/chromium/issues/detail?id=506856 - - Apply Fix potential leaks in qcms_transform_create - - https://bugzilla.mozilla.org/show_bug.cgi?id=1168480 - - Apply fix for crash in qcms_transform_data_rgb_out_lut_sse1 - - https://bugzilla.mozilla.org/show_bug.cgi?id=1163740 - - Add SSE2 code for qcms_transform_data_rgba_out_lut_sse2 - - https://code.google.com/p/chromium/issues/detail?id=506607 - - Turbo charge SSE2 qcms_transform_data_rgba_out_lut_sse2 - - https://code.google.com/p/chromium/issues/detail?id=506607 - - Check matrix transforms have the same PCS - - https://code.google.com/p/chromium/issues/detail?id=510682 - - Apply Don't reject valid profiles with no CLUT offset - - https://bugzilla.mozilla.org/show_bug.cgi?id=1176551 - - Runtime detect qcms_transform_data_tetra_clut_rgba_sse2 use - - https://code.google.com/p/chromium/issues/detail?id=506607 - - LUT8/16 profiles with an empty CLUT are invalid - - https://code.google.com/p/chromium/issues/detail?id=487284 - - Caching transform prelude to save computation in V4 profiles - - https://code.google.com/p/chromium/issues/detail?id=506607 - - Use the caching transform prelude for non-SSE code in transform.c - - https://code.google.com/p/chromium/issues/detail?id=506607 - - Expand QCMS tests. Add Munsell test for transform accuracy - - https://code.google.com/p/chromium/issues/detail?id=532910 - - Compute RMS error from color error dE in the Munsell test - - https://code.google.com/p/chromium/issues/detail?id=532910 - - Store color profile version and add a version read API - - https://code.google.com/p/chromium/issues/detail?id=532258 - - Add support for VCGT tag formula gamma - - https://code.google.com/p/chromium/issues/detail?id=551568 - - Minimize transform RMS in qcms_transform_data_rgb(a)_out_lut - - https://code.google.com/p/chromium/issues/detail?id=532910 - - Allow negative XYZ for display profiles on the APPLE port - - https://code.google.com/p/chromium/issues/detail?id=562951 - - Add a color profile white point transform api - - https://code.google.com/p/chromium/issues/detail?id=564355 - - Compute the pole and zero values needed by lut_inverse_interp16 once - - https://code.google.com/p/chromium/issues/detail?id=505793 - - Store the profile media white point during iccread.c - - https://code.google.com/p/chromium/issues/detail?id=565222 - - Add an API to check for profile media white point - - https://code.google.com/p/chromium/issues/detail?id=565222 - - Add a qcms_profile_get_white_point() api - - https://code.google.com/p/chromium/issues/detail?id=565222 - - Set the media white point of the sRGB profile - - https://code.google.com/p/chromium/issues/detail?id=565222 - - Don't build QCMS on Android and iOS - - https://code.google.com/p/chromium/issues/detail?id=577155 - - Fix para curve tag interval paramater use - - https://code.google.com/p/chromium/issues/detail?id=580920 - - Verify internal sRGB profile tristimulus match the standard sRGB profile - - https://code.google.com/p/chromium/issues/detail?id=580917 - - Expose unsigned short version of TRC curve - - https://code.google.com/p/chromium/issues/detail?id=495196 - - Add qcms_profile_ntsc_relative_gamut_size api - - https://code.google.com/p/chromium/issues/detail?id=582870 - - Fix build issue of qcms_tests for MIPS Linux - - https://code.google.com/p/chromium/issues/detail?id=590227 - - Update primaries used to build internal sRGB profile - - https://code.google.com/p/chromium/issues/detail?id=580917 - - Update internal sRGB profile test report output - - https://code.google.com/p/chromium/issues/detail?id=580917 - - Add more internal sRGB profile tests - - https://code.google.com/p/chromium/issues/detail?id=580917 - - Fix build_output_lut to return correct data for parametric curves - - https://bugs.chromium.org/p/chromium/issues/detail?id=600338 - - Make build_output_lut output 4096 points for parametric curves - - https://bugs.chromium.org/p/chromium/issues/detail?id=600338 - - Use a static table in build_output_lut to invert para curves - - https://bugs.chromium.org/p/chromium/issues/detail?id=600338 - - Make qcms_test_output_trc handle normal gamma curves - - https://bugs.chromium.org/p/chromium/issues/detail?id=600338 - -For the Chromium changes, since the import, in a patch format run: - git diff b8456f38 src diff --git a/third_party/qcms/qcms.gyp b/third_party/qcms/qcms.gyp deleted file mode 100644 index fd78e5e8d8..0000000000 --- a/third_party/qcms/qcms.gyp +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'variables': { - 'conditions': [ - # Do not build QCMS on Android or iOS. (See http://crbug.com/577155) - ['OS == "android" or OS == "ios"', { - 'disable_qcms%': 1, - }, { - 'disable_qcms%': 0, - }], - ], - }, - 'targets': [ - { - 'target_name': 'qcms', - 'product_name': 'qcms', - 'type': 'static_library', - - # Warning (sign-conversion) fixed upstream by large refactoring. Can be - # removed on next roll. - 'msvs_disabled_warnings': [ 4018 ], - - 'direct_dependent_settings': { - 'include_dirs': [ - './src', - ], - }, - - 'conditions': [ - ['disable_qcms == 1', { - 'sources': [ - 'src/empty.c', - ], - }, { # disable_qcms == 0 - 'sources': [ - 'src/chain.c', - 'src/chain.h', - 'src/iccread.c', - 'src/matrix.c', - 'src/matrix.h', - 'src/qcms.h', - 'src/qcmsint.h', - 'src/qcmstypes.h', - 'src/qcms_util.c', - 'src/transform.c', - 'src/transform_util.c', - 'src/transform_util.h', - ], - 'conditions': [ - ['target_arch=="ia32" or target_arch=="x64"', { - 'defines': [ - 'SSE2_ENABLE', - ], - 'sources': [ - 'src/transform-sse2.c', - ], - }], - ], - }], - ['OS == "win"', { - 'msvs_disabled_warnings': [ - 4056, # overflow in floating-point constant arithmetic (INFINITY) - 4756, # overflow in constant arithmetic (INFINITY) - ], - }], - ], - }, - ], - 'conditions': [ - ['disable_qcms == 0', { - 'targets': [ - { - 'target_name': 'qcms_tests', - 'product_name': 'qcms_tests', - 'type': 'executable', - 'dependencies': [ - 'qcms', - ], - 'conditions': [ - ['OS != "win"', { - 'libraries': [ - '-lm', - ], - }], - ['target_arch=="ia32" or target_arch=="x64"', { - 'defines': [ - 'SSE2_ENABLE', - ], - }], - ], - 'sources': [ - 'src/tests/qcms_test_main.c', - 'src/tests/qcms_test_internal_srgb.c', - 'src/tests/qcms_test_munsell.c', - 'src/tests/qcms_test_ntsc_gamut.c', - 'src/tests/qcms_test_output_trc.c', - 'src/tests/qcms_test_tetra_clut_rgba.c', - 'src/tests/qcms_test_util.c', - ], - }, - ], - }], - ], -} - -# Local Variables: -# tab-width:2 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/third_party/qcms/src/COPYING b/third_party/qcms/src/COPYING deleted file mode 100644 index 76b303b00a..0000000000 --- a/third_party/qcms/src/COPYING +++ /dev/null @@ -1,21 +0,0 @@ -qcms -Copyright (C) 2009 Mozilla Corporation -Copyright (C) 1998-2007 Marti Maria - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/third_party/qcms/src/README b/third_party/qcms/src/README deleted file mode 100644 index e3d95a37a3..0000000000 --- a/third_party/qcms/src/README +++ /dev/null @@ -1,9 +0,0 @@ -qcms -==== - -Quick color management. - -Current limitations ------------ -- Only supports RGB and Gray colorspaces. e.g. no support for CMYK yet. -- Only packed RGB and RGBA, K, and KA. diff --git a/third_party/qcms/src/chain.c b/third_party/qcms/src/chain.c deleted file mode 100644 index 525507084b..0000000000 --- a/third_party/qcms/src/chain.c +++ /dev/null @@ -1,1026 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Corporation -// Copyright (C) 1998-2007 Marti Maria -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include <stdlib.h> -#include <math.h> -#include <assert.h> -#include <string.h> //memcpy -#include "qcmsint.h" -#include "transform_util.h" -#include "matrix.h" - -static struct matrix build_lut_matrix(struct lutType *lut) -{ - struct matrix result; - if (lut) { - result.m[0][0] = s15Fixed16Number_to_float(lut->e00); - result.m[0][1] = s15Fixed16Number_to_float(lut->e01); - result.m[0][2] = s15Fixed16Number_to_float(lut->e02); - result.m[1][0] = s15Fixed16Number_to_float(lut->e10); - result.m[1][1] = s15Fixed16Number_to_float(lut->e11); - result.m[1][2] = s15Fixed16Number_to_float(lut->e12); - result.m[2][0] = s15Fixed16Number_to_float(lut->e20); - result.m[2][1] = s15Fixed16Number_to_float(lut->e21); - result.m[2][2] = s15Fixed16Number_to_float(lut->e22); - result.invalid = false; - } else { - memset(&result, 0, sizeof(struct matrix)); - result.invalid = true; - } - return result; -} - -static struct matrix build_mAB_matrix(struct lutmABType *lut) -{ - struct matrix result; - if (lut) { - result.m[0][0] = s15Fixed16Number_to_float(lut->e00); - result.m[0][1] = s15Fixed16Number_to_float(lut->e01); - result.m[0][2] = s15Fixed16Number_to_float(lut->e02); - result.m[1][0] = s15Fixed16Number_to_float(lut->e10); - result.m[1][1] = s15Fixed16Number_to_float(lut->e11); - result.m[1][2] = s15Fixed16Number_to_float(lut->e12); - result.m[2][0] = s15Fixed16Number_to_float(lut->e20); - result.m[2][1] = s15Fixed16Number_to_float(lut->e21); - result.m[2][2] = s15Fixed16Number_to_float(lut->e22); - result.invalid = false; - } else { - memset(&result, 0, sizeof(struct matrix)); - result.invalid = true; - } - return result; -} - -//Based on lcms cmsLab2XYZ -#define f(t) (t <= (24.0f/116.0f)*(24.0f/116.0f)*(24.0f/116.0f)) ? ((841.0/108.0) * t + (16.0/116.0)) : pow(t,1.0/3.0) -#define f_1(t) (t <= (24.0f/116.0f)) ? ((108.0/841.0) * (t - (16.0/116.0))) : (t * t * t) -static void qcms_transform_module_LAB_to_XYZ(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - // lcms: D50 XYZ values - float WhitePointX = 0.9642f; - float WhitePointY = 1.0f; - float WhitePointZ = 0.8249f; - for (i = 0; i < length; i++) { - float device_L = *src++ * 100.0f; - float device_a = *src++ * 255.0f - 128.0f; - float device_b = *src++ * 255.0f - 128.0f; - float y = (device_L + 16.0f) / 116.0f; - - float X = f_1((y + 0.002f * device_a)) * WhitePointX; - float Y = f_1(y) * WhitePointY; - float Z = f_1((y - 0.005f * device_b)) * WhitePointZ; - *dest++ = X / (1.0 + 32767.0/32768.0); - *dest++ = Y / (1.0 + 32767.0/32768.0); - *dest++ = Z / (1.0 + 32767.0/32768.0); - } -} - -//Based on lcms cmsXYZ2Lab -static void qcms_transform_module_XYZ_to_LAB(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - // lcms: D50 XYZ values - float WhitePointX = 0.9642f; - float WhitePointY = 1.0f; - float WhitePointZ = 0.8249f; - for (i = 0; i < length; i++) { - float device_x = *src++ * (1.0 + 32767.0/32768.0) / WhitePointX; - float device_y = *src++ * (1.0 + 32767.0/32768.0) / WhitePointY; - float device_z = *src++ * (1.0 + 32767.0/32768.0) / WhitePointZ; - - float fx = f(device_x); - float fy = f(device_y); - float fz = f(device_z); - - float L = 116.0f*fy - 16.0f; - float a = 500.0f*(fx - fy); - float b = 200.0f*(fy - fz); - *dest++ = L / 100.0f; - *dest++ = (a+128.0f) / 255.0f; - *dest++ = (b+128.0f) / 255.0f; - } - -} - -static void qcms_transform_module_clut_only(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - int xy_len = 1; - int x_len = transform->grid_size; - int len = x_len * x_len; - float* r_table = transform->r_clut; - float* g_table = transform->g_clut; - float* b_table = transform->b_clut; - - assert(transform->grid_size >= 1); - - for (i = 0; i < length; i++) { - float linear_r = *src++; - float linear_g = *src++; - float linear_b = *src++; - - int x = floor(linear_r * (transform->grid_size-1)); - int y = floor(linear_g * (transform->grid_size-1)); - int z = floor(linear_b * (transform->grid_size-1)); - int x_n = ceil(linear_r * (transform->grid_size-1)); - int y_n = ceil(linear_g * (transform->grid_size-1)); - int z_n = ceil(linear_b * (transform->grid_size-1)); - float x_d = linear_r * (transform->grid_size-1) - x; - float y_d = linear_g * (transform->grid_size-1) - y; - float z_d = linear_b * (transform->grid_size-1) - z; - - float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d); - float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d); - float r_y1 = lerp(r_x1, r_x2, y_d); - float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d); - float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d); - float r_y2 = lerp(r_x3, r_x4, y_d); - float clut_r = lerp(r_y1, r_y2, z_d); - - float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d); - float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d); - float g_y1 = lerp(g_x1, g_x2, y_d); - float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d); - float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d); - float g_y2 = lerp(g_x3, g_x4, y_d); - float clut_g = lerp(g_y1, g_y2, z_d); - - float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d); - float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d); - float b_y1 = lerp(b_x1, b_x2, y_d); - float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d); - float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d); - float b_y2 = lerp(b_x3, b_x4, y_d); - float clut_b = lerp(b_y1, b_y2, z_d); - - *dest++ = clamp_float(clut_r); - *dest++ = clamp_float(clut_g); - *dest++ = clamp_float(clut_b); - } -} - -static void qcms_transform_module_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - int xy_len = 1; - int x_len = transform->grid_size; - int len = x_len * x_len; - float* r_table = transform->r_clut; - float* g_table = transform->g_clut; - float* b_table = transform->b_clut; - - assert(transform->grid_size >= 1); - - for (i = 0; i < length; i++) { - float device_r = *src++; - float device_g = *src++; - float device_b = *src++; - float linear_r = lut_interp_linear_float(device_r, - transform->input_clut_table_r, transform->input_clut_table_length); - float linear_g = lut_interp_linear_float(device_g, - transform->input_clut_table_g, transform->input_clut_table_length); - float linear_b = lut_interp_linear_float(device_b, - transform->input_clut_table_b, transform->input_clut_table_length); - - int x = floor(linear_r * (transform->grid_size-1)); - int y = floor(linear_g * (transform->grid_size-1)); - int z = floor(linear_b * (transform->grid_size-1)); - int x_n = ceil(linear_r * (transform->grid_size-1)); - int y_n = ceil(linear_g * (transform->grid_size-1)); - int z_n = ceil(linear_b * (transform->grid_size-1)); - float x_d = linear_r * (transform->grid_size-1) - x; - float y_d = linear_g * (transform->grid_size-1) - y; - float z_d = linear_b * (transform->grid_size-1) - z; - - float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d); - float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d); - float r_y1 = lerp(r_x1, r_x2, y_d); - float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d); - float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d); - float r_y2 = lerp(r_x3, r_x4, y_d); - float clut_r = lerp(r_y1, r_y2, z_d); - - float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d); - float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d); - float g_y1 = lerp(g_x1, g_x2, y_d); - float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d); - float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d); - float g_y2 = lerp(g_x3, g_x4, y_d); - float clut_g = lerp(g_y1, g_y2, z_d); - - float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d); - float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d); - float b_y1 = lerp(b_x1, b_x2, y_d); - float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d); - float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d); - float b_y2 = lerp(b_x3, b_x4, y_d); - float clut_b = lerp(b_y1, b_y2, z_d); - - float pcs_r = lut_interp_linear_float(clut_r, - transform->output_clut_table_r, transform->output_clut_table_length); - float pcs_g = lut_interp_linear_float(clut_g, - transform->output_clut_table_g, transform->output_clut_table_length); - float pcs_b = lut_interp_linear_float(clut_b, - transform->output_clut_table_b, transform->output_clut_table_length); - - *dest++ = clamp_float(pcs_r); - *dest++ = clamp_float(pcs_g); - *dest++ = clamp_float(pcs_b); - } -} - -/* NOT USED -static void qcms_transform_module_tetra_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - int xy_len = 1; - int x_len = transform->grid_size; - int len = x_len * x_len; - float* r_table = transform->r_clut; - float* g_table = transform->g_clut; - float* b_table = transform->b_clut; - float c0_r, c1_r, c2_r, c3_r; - float c0_g, c1_g, c2_g, c3_g; - float c0_b, c1_b, c2_b, c3_b; - float clut_r, clut_g, clut_b; - float pcs_r, pcs_g, pcs_b; - for (i = 0; i < length; i++) { - float device_r = *src++; - float device_g = *src++; - float device_b = *src++; - float linear_r = lut_interp_linear_float(device_r, - transform->input_clut_table_r, transform->input_clut_table_length); - float linear_g = lut_interp_linear_float(device_g, - transform->input_clut_table_g, transform->input_clut_table_length); - float linear_b = lut_interp_linear_float(device_b, - transform->input_clut_table_b, transform->input_clut_table_length); - - int x = floor(linear_r * (transform->grid_size-1)); - int y = floor(linear_g * (transform->grid_size-1)); - int z = floor(linear_b * (transform->grid_size-1)); - int x_n = ceil(linear_r * (transform->grid_size-1)); - int y_n = ceil(linear_g * (transform->grid_size-1)); - int z_n = ceil(linear_b * (transform->grid_size-1)); - float rx = linear_r * (transform->grid_size-1) - x; - float ry = linear_g * (transform->grid_size-1) - y; - float rz = linear_b * (transform->grid_size-1) - z; - - c0_r = CLU(r_table, x, y, z); - c0_g = CLU(g_table, x, y, z); - c0_b = CLU(b_table, x, y, z); - if( rx >= ry ) { - if (ry >= rz) { //rx >= ry && ry >= rz - c1_r = CLU(r_table, x_n, y, z) - c0_r; - c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z); - c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); - c1_g = CLU(g_table, x_n, y, z) - c0_g; - c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z); - c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); - c1_b = CLU(b_table, x_n, y, z) - c0_b; - c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z); - c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); - } else { - if (rx >= rz) { //rx >= rz && rz >= ry - c1_r = CLU(r_table, x_n, y, z) - c0_r; - c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); - c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z); - c1_g = CLU(g_table, x_n, y, z) - c0_g; - c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); - c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z); - c1_b = CLU(b_table, x_n, y, z) - c0_b; - c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); - c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z); - } else { //rz > rx && rx >= ry - c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n); - c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); - c3_r = CLU(r_table, x, y, z_n) - c0_r; - c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n); - c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); - c3_g = CLU(g_table, x, y, z_n) - c0_g; - c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n); - c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); - c3_b = CLU(b_table, x, y, z_n) - c0_b; - } - } - } else { - if (rx >= rz) { //ry > rx && rx >= rz - c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z); - c2_r = CLU(r_table, x_n, y_n, z) - c0_r; - c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); - c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z); - c2_g = CLU(g_table, x_n, y_n, z) - c0_g; - c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); - c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z); - c2_b = CLU(b_table, x_n, y_n, z) - c0_b; - c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); - } else { - if (ry >= rz) { //ry >= rz && rz > rx - c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); - c2_r = CLU(r_table, x, y_n, z) - c0_r; - c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z); - c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); - c2_g = CLU(g_table, x, y_n, z) - c0_g; - c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z); - c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); - c2_b = CLU(b_table, x, y_n, z) - c0_b; - c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z); - } else { //rz > ry && ry > rx - c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); - c2_r = CLU(r_table, x, y_n, z) - c0_r; - c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); - c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); - c2_g = CLU(g_table, x, y_n, z) - c0_g; - c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); - c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); - c2_b = CLU(b_table, x, y_n, z) - c0_b; - c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); - } - } - } - - clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz; - clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz; - clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz; - - pcs_r = lut_interp_linear_float(clut_r, - transform->output_clut_table_r, transform->output_clut_table_length); - pcs_g = lut_interp_linear_float(clut_g, - transform->output_clut_table_g, transform->output_clut_table_length); - pcs_b = lut_interp_linear_float(clut_b, - transform->output_clut_table_b, transform->output_clut_table_length); - *dest++ = clamp_float(pcs_r); - *dest++ = clamp_float(pcs_g); - *dest++ = clamp_float(pcs_b); - } -} -*/ - -static void qcms_transform_module_gamma_table(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - float out_r, out_g, out_b; - for (i = 0; i < length; i++) { - float in_r = *src++; - float in_g = *src++; - float in_b = *src++; - - out_r = lut_interp_linear_float(in_r, transform->input_clut_table_r, 256); - out_g = lut_interp_linear_float(in_g, transform->input_clut_table_g, 256); - out_b = lut_interp_linear_float(in_b, transform->input_clut_table_b, 256); - - *dest++ = clamp_float(out_r); - *dest++ = clamp_float(out_g); - *dest++ = clamp_float(out_b); - } -} - -static void qcms_transform_module_gamma_lut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - float out_r, out_g, out_b; - for (i = 0; i < length; i++) { - float in_r = *src++; - float in_g = *src++; - float in_b = *src++; - - out_r = lut_interp_linear(in_r, - transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); - out_g = lut_interp_linear(in_g, - transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); - out_b = lut_interp_linear(in_b, - transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); - - *dest++ = clamp_float(out_r); - *dest++ = clamp_float(out_g); - *dest++ = clamp_float(out_b); - } -} - -static void qcms_transform_module_matrix_translate(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - struct matrix mat; - - /* store the results in column major mode - * this makes doing the multiplication with sse easier */ - mat.m[0][0] = transform->matrix.m[0][0]; - mat.m[1][0] = transform->matrix.m[0][1]; - mat.m[2][0] = transform->matrix.m[0][2]; - mat.m[0][1] = transform->matrix.m[1][0]; - mat.m[1][1] = transform->matrix.m[1][1]; - mat.m[2][1] = transform->matrix.m[1][2]; - mat.m[0][2] = transform->matrix.m[2][0]; - mat.m[1][2] = transform->matrix.m[2][1]; - mat.m[2][2] = transform->matrix.m[2][2]; - - for (i = 0; i < length; i++) { - float in_r = *src++; - float in_g = *src++; - float in_b = *src++; - - float out_r = mat.m[0][0]*in_r + mat.m[1][0]*in_g + mat.m[2][0]*in_b + transform->tx; - float out_g = mat.m[0][1]*in_r + mat.m[1][1]*in_g + mat.m[2][1]*in_b + transform->ty; - float out_b = mat.m[0][2]*in_r + mat.m[1][2]*in_g + mat.m[2][2]*in_b + transform->tz; - - *dest++ = clamp_float(out_r); - *dest++ = clamp_float(out_g); - *dest++ = clamp_float(out_b); - } -} - -static void qcms_transform_module_matrix(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) -{ - size_t i; - struct matrix mat; - - /* store the results in column major mode - * this makes doing the multiplication with sse easier */ - mat.m[0][0] = transform->matrix.m[0][0]; - mat.m[1][0] = transform->matrix.m[0][1]; - mat.m[2][0] = transform->matrix.m[0][2]; - mat.m[0][1] = transform->matrix.m[1][0]; - mat.m[1][1] = transform->matrix.m[1][1]; - mat.m[2][1] = transform->matrix.m[1][2]; - mat.m[0][2] = transform->matrix.m[2][0]; - mat.m[1][2] = transform->matrix.m[2][1]; - mat.m[2][2] = transform->matrix.m[2][2]; - - for (i = 0; i < length; i++) { - float in_r = *src++; - float in_g = *src++; - float in_b = *src++; - - float out_r = mat.m[0][0]*in_r + mat.m[1][0]*in_g + mat.m[2][0]*in_b; - float out_g = mat.m[0][1]*in_r + mat.m[1][1]*in_g + mat.m[2][1]*in_b; - float out_b = mat.m[0][2]*in_r + mat.m[1][2]*in_g + mat.m[2][2]*in_b; - - *dest++ = clamp_float(out_r); - *dest++ = clamp_float(out_g); - *dest++ = clamp_float(out_b); - } -} - -static struct qcms_modular_transform* qcms_modular_transform_alloc() { - return calloc(1, sizeof(struct qcms_modular_transform)); -} - -static void qcms_modular_transform_release(struct qcms_modular_transform *transform) -{ - struct qcms_modular_transform *next_transform; - while (transform != NULL) { - next_transform = transform->next_transform; - // clut may use a single block of memory. - // Perhaps we should remove this to simply the code. - if (transform->input_clut_table_r + transform->input_clut_table_length == transform->input_clut_table_g && transform->input_clut_table_g + transform->input_clut_table_length == transform->input_clut_table_b) { - if (transform->input_clut_table_r) free(transform->input_clut_table_r); - } else { - if (transform->input_clut_table_r) free(transform->input_clut_table_r); - if (transform->input_clut_table_g) free(transform->input_clut_table_g); - if (transform->input_clut_table_b) free(transform->input_clut_table_b); - } - if (transform->r_clut + 1 == transform->g_clut && transform->g_clut + 1 == transform->b_clut) { - if (transform->r_clut) free(transform->r_clut); - } else { - if (transform->r_clut) free(transform->r_clut); - if (transform->g_clut) free(transform->g_clut); - if (transform->b_clut) free(transform->b_clut); - } - if (transform->output_clut_table_r + transform->output_clut_table_length == transform->output_clut_table_g && transform->output_clut_table_g+ transform->output_clut_table_length == transform->output_clut_table_b) { - if (transform->output_clut_table_r) free(transform->output_clut_table_r); - } else { - if (transform->output_clut_table_r) free(transform->output_clut_table_r); - if (transform->output_clut_table_g) free(transform->output_clut_table_g); - if (transform->output_clut_table_b) free(transform->output_clut_table_b); - } - if (transform->output_gamma_lut_r) free(transform->output_gamma_lut_r); - if (transform->output_gamma_lut_g) free(transform->output_gamma_lut_g); - if (transform->output_gamma_lut_b) free(transform->output_gamma_lut_b); - free(transform); - transform = next_transform; - } -} - -/* Set transform to be the next element in the linked list. */ -static void append_transform(struct qcms_modular_transform *transform, struct qcms_modular_transform ***next_transform) -{ - **next_transform = transform; - while (transform) { - *next_transform = &(transform->next_transform); - transform = transform->next_transform; - } -} - -/* reverse the transformation list (used by mBA) */ -static struct qcms_modular_transform* reverse_transform(struct qcms_modular_transform *transform) -{ - struct qcms_modular_transform *prev_transform = NULL; - while (transform != NULL) { - struct qcms_modular_transform *next_transform = transform->next_transform; - transform->next_transform = prev_transform; - prev_transform = transform; - transform = next_transform; - } - - return prev_transform; -} - -#define EMPTY_TRANSFORM_LIST NULL -static struct qcms_modular_transform* qcms_modular_transform_create_mAB(struct lutmABType *lut) -{ - struct qcms_modular_transform *first_transform = NULL; - struct qcms_modular_transform **next_transform = &first_transform; - struct qcms_modular_transform *transform = NULL; - - if (lut->a_curves[0] != NULL) { - size_t clut_length; - float *clut; - - // If the A curve is present this also implies the - // presence of a CLUT. - if (!lut->clut_table) - goto fail; - - // Prepare A curve. - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->input_clut_table_r = build_input_gamma_table(lut->a_curves[0]); - transform->input_clut_table_g = build_input_gamma_table(lut->a_curves[1]); - transform->input_clut_table_b = build_input_gamma_table(lut->a_curves[2]); - transform->transform_module_fn = qcms_transform_module_gamma_table; - if (lut->num_grid_points[0] != lut->num_grid_points[1] || - lut->num_grid_points[1] != lut->num_grid_points[2] ) { - //XXX: We don't currently support clut that are not squared! - goto fail; - } - - // Prepare CLUT - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - clut_length = sizeof(float)*pow(lut->num_grid_points[0], 3)*3; - clut = malloc(clut_length); - if (!clut) - goto fail; - memcpy(clut, lut->clut_table, clut_length); - transform->r_clut = clut + 0; - transform->g_clut = clut + 1; - transform->b_clut = clut + 2; - transform->grid_size = lut->num_grid_points[0]; - transform->transform_module_fn = qcms_transform_module_clut_only; - } - if (lut->m_curves[0] != NULL) { - // M curve imples the presence of a Matrix - - // Prepare M curve - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->input_clut_table_r = build_input_gamma_table(lut->m_curves[0]); - transform->input_clut_table_g = build_input_gamma_table(lut->m_curves[1]); - transform->input_clut_table_b = build_input_gamma_table(lut->m_curves[2]); - transform->transform_module_fn = qcms_transform_module_gamma_table; - - // Prepare Matrix - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->matrix = build_mAB_matrix(lut); - if (transform->matrix.invalid) - goto fail; - transform->tx = s15Fixed16Number_to_float(lut->e03); - transform->ty = s15Fixed16Number_to_float(lut->e13); - transform->tz = s15Fixed16Number_to_float(lut->e23); - transform->transform_module_fn = qcms_transform_module_matrix_translate; - } - if (lut->b_curves[0] != NULL) { - // Prepare B curve - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->input_clut_table_r = build_input_gamma_table(lut->b_curves[0]); - transform->input_clut_table_g = build_input_gamma_table(lut->b_curves[1]); - transform->input_clut_table_b = build_input_gamma_table(lut->b_curves[2]); - transform->transform_module_fn = qcms_transform_module_gamma_table; - } else { - // B curve is mandatory - goto fail; - } - - if (lut->reversed) { - // mBA are identical to mAB except that the transformation order - // is reversed - first_transform = reverse_transform(first_transform); - } - - return first_transform; -fail: - qcms_modular_transform_release(first_transform); - return NULL; -} - -static struct qcms_modular_transform* qcms_modular_transform_create_lut(struct lutType *lut) -{ - struct qcms_modular_transform *first_transform = NULL; - struct qcms_modular_transform **next_transform = &first_transform; - struct qcms_modular_transform *transform = NULL; - - size_t in_curve_len, clut_length, out_curve_len; - float *in_curves, *clut, *out_curves; - - // Prepare Matrix - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->matrix = build_lut_matrix(lut); - if (transform->matrix.invalid) - goto fail; - transform->transform_module_fn = qcms_transform_module_matrix; - - // Prepare input curves - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - in_curve_len = sizeof(float)*lut->num_input_table_entries * 3; - in_curves = malloc(in_curve_len); - if (!in_curves) - goto fail; - memcpy(in_curves, lut->input_table, in_curve_len); - transform->input_clut_table_r = in_curves + lut->num_input_table_entries * 0; - transform->input_clut_table_g = in_curves + lut->num_input_table_entries * 1; - transform->input_clut_table_b = in_curves + lut->num_input_table_entries * 2; - transform->input_clut_table_length = lut->num_input_table_entries; - - // Prepare table - clut_length = sizeof(float)*pow(lut->num_clut_grid_points, 3)*3; - clut = malloc(clut_length); - if (!clut) - goto fail; - memcpy(clut, lut->clut_table, clut_length); - transform->r_clut = clut + 0; - transform->g_clut = clut + 1; - transform->b_clut = clut + 2; - transform->grid_size = lut->num_clut_grid_points; - - // Prepare output curves - out_curve_len = sizeof(float) * lut->num_output_table_entries * 3; - out_curves = malloc(out_curve_len); - if (!out_curves) - goto fail; - memcpy(out_curves, lut->output_table, out_curve_len); - transform->output_clut_table_r = out_curves + lut->num_output_table_entries * 0; - transform->output_clut_table_g = out_curves + lut->num_output_table_entries * 1; - transform->output_clut_table_b = out_curves + lut->num_output_table_entries * 2; - transform->output_clut_table_length = lut->num_output_table_entries; - transform->transform_module_fn = qcms_transform_module_clut; - - return first_transform; -fail: - qcms_modular_transform_release(first_transform); - return NULL; -} - -struct qcms_modular_transform* qcms_modular_transform_create_input(qcms_profile *in) -{ - struct qcms_modular_transform *first_transform = NULL; - struct qcms_modular_transform **next_transform = &first_transform; - - if (in->A2B0) { - struct qcms_modular_transform *lut_transform; - lut_transform = qcms_modular_transform_create_lut(in->A2B0); - if (!lut_transform) - goto fail; - append_transform(lut_transform, &next_transform); - } else if (in->mAB && in->mAB->num_in_channels == 3 && in->mAB->num_out_channels == 3) { - struct qcms_modular_transform *mAB_transform; - mAB_transform = qcms_modular_transform_create_mAB(in->mAB); - if (!mAB_transform) - goto fail; - append_transform(mAB_transform, &next_transform); - - } else { - struct qcms_modular_transform *transform; - - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->input_clut_table_r = build_input_gamma_table(in->redTRC); - transform->input_clut_table_g = build_input_gamma_table(in->greenTRC); - transform->input_clut_table_b = build_input_gamma_table(in->blueTRC); - transform->transform_module_fn = qcms_transform_module_gamma_table; - if (!transform->input_clut_table_r || !transform->input_clut_table_g || - !transform->input_clut_table_b) { - goto fail; - } - - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->matrix.m[0][0] = 1/1.999969482421875f; - transform->matrix.m[0][1] = 0.f; - transform->matrix.m[0][2] = 0.f; - transform->matrix.m[1][0] = 0.f; - transform->matrix.m[1][1] = 1/1.999969482421875f; - transform->matrix.m[1][2] = 0.f; - transform->matrix.m[2][0] = 0.f; - transform->matrix.m[2][1] = 0.f; - transform->matrix.m[2][2] = 1/1.999969482421875f; - transform->matrix.invalid = false; - transform->transform_module_fn = qcms_transform_module_matrix; - - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->matrix = build_colorant_matrix(in); - transform->transform_module_fn = qcms_transform_module_matrix; - } - - return first_transform; -fail: - qcms_modular_transform_release(first_transform); - return EMPTY_TRANSFORM_LIST; -} -static struct qcms_modular_transform* qcms_modular_transform_create_output(qcms_profile *out) -{ - struct qcms_modular_transform *first_transform = NULL; - struct qcms_modular_transform **next_transform = &first_transform; - - if (out->B2A0) { - struct qcms_modular_transform *lut_transform; - lut_transform = qcms_modular_transform_create_lut(out->B2A0); - if (!lut_transform) - goto fail; - append_transform(lut_transform, &next_transform); - } else if (out->mBA && out->mBA->num_in_channels == 3 && out->mBA->num_out_channels == 3) { - struct qcms_modular_transform *lut_transform; - lut_transform = qcms_modular_transform_create_mAB(out->mBA); - if (!lut_transform) - goto fail; - append_transform(lut_transform, &next_transform); - } else if (out->redTRC && out->greenTRC && out->blueTRC) { - struct qcms_modular_transform *transform; - - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->matrix = matrix_invert(build_colorant_matrix(out)); - transform->transform_module_fn = qcms_transform_module_matrix; - - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - transform->matrix.m[0][0] = 1.999969482421875f; - transform->matrix.m[0][1] = 0.f; - transform->matrix.m[0][2] = 0.f; - transform->matrix.m[1][0] = 0.f; - transform->matrix.m[1][1] = 1.999969482421875f; - transform->matrix.m[1][2] = 0.f; - transform->matrix.m[2][0] = 0.f; - transform->matrix.m[2][1] = 0.f; - transform->matrix.m[2][2] = 1.999969482421875f; - transform->matrix.invalid = false; - transform->transform_module_fn = qcms_transform_module_matrix; - - transform = qcms_modular_transform_alloc(); - if (!transform) - goto fail; - append_transform(transform, &next_transform); - build_output_lut(out->redTRC, &transform->output_gamma_lut_r, - &transform->output_gamma_lut_r_length); - build_output_lut(out->greenTRC, &transform->output_gamma_lut_g, - &transform->output_gamma_lut_g_length); - build_output_lut(out->blueTRC, &transform->output_gamma_lut_b, - &transform->output_gamma_lut_b_length); - transform->transform_module_fn = qcms_transform_module_gamma_lut; - - if (!transform->output_gamma_lut_r || !transform->output_gamma_lut_g || - !transform->output_gamma_lut_b) { - goto fail; - } - } else { - assert(0 && "Unsupported output profile workflow."); - return NULL; - } - - return first_transform; -fail: - qcms_modular_transform_release(first_transform); - return EMPTY_TRANSFORM_LIST; -} - -/* Not Completed -// Simplify the transformation chain to an equivalent transformation chain -static struct qcms_modular_transform* qcms_modular_transform_reduce(struct qcms_modular_transform *transform) -{ - struct qcms_modular_transform *first_transform = NULL; - struct qcms_modular_transform *curr_trans = transform; - struct qcms_modular_transform *prev_trans = NULL; - while (curr_trans) { - struct qcms_modular_transform *next_trans = curr_trans->next_transform; - if (curr_trans->transform_module_fn == qcms_transform_module_matrix) { - if (next_trans && next_trans->transform_module_fn == qcms_transform_module_matrix) { - curr_trans->matrix = matrix_multiply(curr_trans->matrix, next_trans->matrix); - goto remove_next; - } - } - if (curr_trans->transform_module_fn == qcms_transform_module_gamma_table) { - bool isLinear = true; - uint16_t i; - for (i = 0; isLinear && i < 256; i++) { - isLinear &= (int)(curr_trans->input_clut_table_r[i] * 255) == i; - isLinear &= (int)(curr_trans->input_clut_table_g[i] * 255) == i; - isLinear &= (int)(curr_trans->input_clut_table_b[i] * 255) == i; - } - goto remove_current; - } - -next_transform: - if (!next_trans) break; - prev_trans = curr_trans; - curr_trans = next_trans; - continue; -remove_current: - if (curr_trans == transform) { - //Update head - transform = next_trans; - } else { - prev_trans->next_transform = next_trans; - } - curr_trans->next_transform = NULL; - qcms_modular_transform_release(curr_trans); - //return transform; - return qcms_modular_transform_reduce(transform); -remove_next: - curr_trans->next_transform = next_trans->next_transform; - next_trans->next_transform = NULL; - qcms_modular_transform_release(next_trans); - continue; - } - return transform; -} -*/ - -static struct qcms_modular_transform* qcms_modular_transform_create(qcms_profile *in, qcms_profile *out) -{ - struct qcms_modular_transform *first_transform = NULL; - struct qcms_modular_transform **next_transform = &first_transform; - qcms_bool transform_to_pcs_xyz_only = (out == NULL); - - if (in->color_space == RGB_SIGNATURE) { - struct qcms_modular_transform* rgb_to_pcs; - rgb_to_pcs = qcms_modular_transform_create_input(in); - if (!rgb_to_pcs) - goto fail; - append_transform(rgb_to_pcs, &next_transform); - } else { - assert(0 && "input color space not supported"); - goto fail; - } - - if (in->pcs == LAB_SIGNATURE && (transform_to_pcs_xyz_only || out->pcs == XYZ_SIGNATURE)) { - struct qcms_modular_transform* lab_to_pcs; - lab_to_pcs = qcms_modular_transform_alloc(); - if (!lab_to_pcs) - goto fail; - append_transform(lab_to_pcs, &next_transform); - lab_to_pcs->transform_module_fn = qcms_transform_module_LAB_to_XYZ; - } - - if (transform_to_pcs_xyz_only) - return first_transform; - - // This does not improve accuracy in practice, something is wrong here. - //if (in->chromaticAdaption.invalid == false) { - // struct qcms_modular_transform* chromaticAdaption; - // chromaticAdaption = qcms_modular_transform_alloc(); - // if (!chromaticAdaption) - // goto fail; - // append_transform(chromaticAdaption, &next_transform); - // chromaticAdaption->matrix = matrix_invert(in->chromaticAdaption); - // chromaticAdaption->transform_module_fn = qcms_transform_module_matrix; - //} - - if (in->pcs == XYZ_SIGNATURE && out->pcs == LAB_SIGNATURE) { - struct qcms_modular_transform* pcs_to_lab; - pcs_to_lab = qcms_modular_transform_alloc(); - if (!pcs_to_lab) - goto fail; - append_transform(pcs_to_lab, &next_transform); - pcs_to_lab->transform_module_fn = qcms_transform_module_XYZ_to_LAB; - } - - if (out->color_space == RGB_SIGNATURE) { - struct qcms_modular_transform* pcs_to_rgb; - pcs_to_rgb = qcms_modular_transform_create_output(out); - if (!pcs_to_rgb) - goto fail; - append_transform(pcs_to_rgb, &next_transform); - } else { - assert(0 && "output color space not supported"); - goto fail; - } - // Not Completed - //return qcms_modular_transform_reduce(first_transform); - return first_transform; -fail: - qcms_modular_transform_release(first_transform); - return EMPTY_TRANSFORM_LIST; -} - -static float* qcms_modular_transform_data(struct qcms_modular_transform *transform, float *src, float *dest, size_t len) -{ - while (transform != NULL) { - // Keep swaping src/dest when performing a transform to use less memory. - float *new_src = dest; - const transform_module_fn_t transform_fn = transform->transform_module_fn; - if (transform_fn != qcms_transform_module_gamma_table && - transform_fn != qcms_transform_module_gamma_lut && - transform_fn != qcms_transform_module_clut && - transform_fn != qcms_transform_module_clut_only && - transform_fn != qcms_transform_module_matrix && - transform_fn != qcms_transform_module_matrix_translate && - transform_fn != qcms_transform_module_LAB_to_XYZ && - transform_fn != qcms_transform_module_XYZ_to_LAB) { - assert(0 && "Unsupported transform module"); - return NULL; - } - transform->transform_module_fn(transform,src,dest,len); - dest = src; - src = new_src; - transform = transform->next_transform; - } - // The results end up in the src buffer because of the switching - return src; -} - -float* qcms_chain_transform(qcms_profile *in, qcms_profile *out, float *src, float *dest, size_t lutSize) -{ - struct qcms_modular_transform *transform_list = qcms_modular_transform_create(in, out); - if (transform_list != NULL) { - float *lut = qcms_modular_transform_data(transform_list, src, dest, lutSize/3); - qcms_modular_transform_release(transform_list); - return lut; - } - return NULL; -} - -qcms_bool qcms_profile_white_transform(qcms_profile *profile, float XYZ[3]) -{ - const float inverse_internal_scale = 1.999969482421875f; - - // Set the output profile to NULL to request a color transform to PCS XYZ only. - struct qcms_modular_transform *transform_list = qcms_modular_transform_create(profile, NULL); - - // Now calculate how the profile transforms white input color to PCS XYZ space. - if (transform_list != NULL) { - XYZ[0] = XYZ[1] = XYZ[2] = 1.0f; // white input - qcms_modular_transform_data(transform_list, XYZ, XYZ, 1); - // qcms_modular_transform_create internally scales input by 1/1.999969482421875f - // but no qcms changelog describes why / how that number was choosen. junov@ "it - // might be related to the epsilon of the fixed-point type 2*(1-1/(2^16)), but - // there is no explanation, which is disconcerting." Meanwhile, undo the internal - // scaling so we return a normalized CIEXYZ value viz., where Y is scaled to 1.0. - // A properly created color profile should produce Y=~1.0 in PCS XYZ with white - // input (the D50 test). If it does not, then the profile is likely bogus. - XYZ[0] *= inverse_internal_scale; - XYZ[1] *= inverse_internal_scale; - XYZ[2] *= inverse_internal_scale; - qcms_modular_transform_release(transform_list); - return true; - } - - return false; -} diff --git a/third_party/qcms/src/chain.h b/third_party/qcms/src/chain.h deleted file mode 100644 index bdc6c8872a..0000000000 --- a/third_party/qcms/src/chain.h +++ /dev/null @@ -1,30 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// Copyright (C) 1998-2007 Marti Maria -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef _QCMS_CHAIN_H -#define _QCMS_CHAIN_H - -// Generates and returns a 3D LUT with lutSize^3 samples using the provided src/dest. -float* qcms_chain_transform(qcms_profile *in, qcms_profile *out, float *src, float *dest, size_t lutSize); - -#endif diff --git a/third_party/qcms/src/empty.c b/third_party/qcms/src/empty.c deleted file mode 100644 index 6fd68b8f64..0000000000 --- a/third_party/qcms/src/empty.c +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. -/* - * qcms is not built on this port: see http://crbug.com/577155 - */ diff --git a/third_party/qcms/src/halffloat.h b/third_party/qcms/src/halffloat.h deleted file mode 100644 index 35c725066b..0000000000 --- a/third_party/qcms/src/halffloat.h +++ /dev/null @@ -1,106 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// Copyright (C) 1998-2007 Marti Maria -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef _QCMS_HALFFLOAT_H -#define _QCMS_HALFFLOAT_H - -const unsigned short qcms_half_float_base_table[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, - 512, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360, - 16384, 17408, 18432, 19456, 20480, 21504, 22528, 23552, 24576, 25600, 26624, 27648, 28672, 29696, 30720, 31744, - 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, - 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, - 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, - 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, - 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, - 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, - 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, 31744, - 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, - 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, - 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, - 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, - 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, - 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, - 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32769, 32770, 32772, 32776, 32784, 32800, 32832, 32896, 33024, - 33280, 33792, 34816, 35840, 36864, 37888, 38912, 39936, 40960, 41984, 43008, 44032, 45056, 46080, 47104, 48128, - 49152, 50176, 51200, 52224, 53248, 54272, 55296, 56320, 57344, 58368, 59392, 60416, 61440, 62464, 63488, 64512, - 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, - 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, - 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, - 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, - 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, - 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, - 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512, 64512 -}; - -const unsigned char qcms_half_float_shift_table[512] = { - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, - 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 13, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, - 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 13 -}; - -static inline unsigned short float_to_half_float(float f) -{ - // See Blink::Source/platform/graphics/gpu/WebGLImageConversion.cpp::convertFloatToHalfFloat() and http://crbug.com/491784 - - unsigned temp = *((unsigned *)(&f)); - unsigned signexp = (temp >> 23) & 0x1ff; - return qcms_half_float_base_table[signexp] + ((temp & 0x007fffff) >> qcms_half_float_shift_table[signexp]); -} - -#endif diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c deleted file mode 100644 index b0a9a0296f..0000000000 --- a/third_party/qcms/src/iccread.c +++ /dev/null @@ -1,1645 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// Copyright (C) 1998-2007 Marti Maria -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include <math.h> -#include <assert.h> -#include <stdlib.h> -#include <string.h> //memset -#include "qcmsint.h" - -/* It might be worth having a unified limit on content controlled - * allocation per profile. This would remove the need for many - * of the arbitrary limits that we used */ - -typedef uint32_t be32; -typedef uint16_t be16; - -#if 0 -not used yet -/* __builtin_bswap isn't available in older gccs - * so open code it for now */ -static be32 cpu_to_be32(int32_t v) -{ -#ifdef IS_LITTLE_ENDIAN - return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24); - //return __builtin_bswap32(v); - return v; -#endif -} -#endif - -static uint32_t be32_to_cpu(be32 v) -{ -#ifdef IS_LITTLE_ENDIAN - return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24); - //return __builtin_bswap32(v); -#else - return v; -#endif -} - -static uint16_t be16_to_cpu(be16 v) -{ -#ifdef IS_LITTLE_ENDIAN - return ((v & 0xff) << 8) | ((v & 0xff00) >> 8); -#else - return v; -#endif -} - -/* a wrapper around the memory that we are going to parse - * into a qcms_profile */ -struct mem_source -{ - const unsigned char *buf; - size_t size; - qcms_bool valid; - const char *invalid_reason; -}; - -static void invalid_source(struct mem_source *mem, const char *reason) -{ - mem->valid = false; - mem->invalid_reason = reason; -} - -static uint32_t read_u32(struct mem_source *mem, size_t offset) -{ - /* Subtract from mem->size instead of the more intuitive adding to offset. - * This avoids overflowing offset. The subtraction is safe because - * mem->size is guaranteed to be > 4 */ - if (offset > mem->size - 4) { - invalid_source(mem, "Invalid offset"); - return 0; - } else { - be32 k; - memcpy(&k, mem->buf + offset, sizeof(k)); - return be32_to_cpu(k); - } -} - -static uint16_t read_u16(struct mem_source *mem, size_t offset) -{ - if (offset > mem->size - 2) { - invalid_source(mem, "Invalid offset"); - return 0; - } else { - be16 k; - memcpy(&k, mem->buf + offset, sizeof(k)); - return be16_to_cpu(k); - } -} - -static uint8_t read_u8(struct mem_source *mem, size_t offset) -{ - if (offset > mem->size - 1) { - invalid_source(mem, "Invalid offset"); - return 0; - } else { - return *(uint8_t*)(mem->buf + offset); - } -} - -static s15Fixed16Number read_s15Fixed16Number(struct mem_source *mem, size_t offset) -{ - return read_u32(mem, offset); -} - -static uInt8Number read_uInt8Number(struct mem_source *mem, size_t offset) -{ - return read_u8(mem, offset); -} - -static uInt16Number read_uInt16Number(struct mem_source *mem, size_t offset) -{ - return read_u16(mem, offset); -} - -#define BAD_VALUE_PROFILE NULL -#define INVALID_PROFILE NULL -#define NO_MEM_PROFILE NULL - -/* An arbitrary 4MB limit on profile size */ -#define MAX_PROFILE_SIZE 1024*1024*4 -#define MAX_TAG_COUNT 1024 - -static void check_CMM_type_signature(struct mem_source *src) -{ - //uint32_t CMM_type_signature = read_u32(src, 4); -} - -static void read_profile_version(qcms_profile *profile, struct mem_source *src) -{ - uint8_t major_revision = read_u8(src, 8 + 0); - uint8_t minor_revision = read_u8(src, 8 + 1); - uint8_t reserved_byte1 = read_u8(src, 8 + 2); - uint8_t reserved_byte2 = read_u8(src, 8 + 3); - - profile->icc_version = major_revision << 8 | minor_revision; - - if (reserved_byte1 || reserved_byte2) { - invalid_source(src, "Invalid reserved bytes"); - return; - } - - if (major_revision == 2) - return; // ICC V2.X color profile - if (major_revision == 4 && qcms_supports_iccv4) - return; // ICC V4.X color profile - - /* Checking the version doesn't buy us anything: permit any - version without failure for now */ - // invalid_source(src, "Unsupported ICC revision"); - return; -} - -#define INPUT_DEVICE_PROFILE 0x73636e72 // 'scnr' -#define DISPLAY_DEVICE_PROFILE 0x6d6e7472 // 'mntr' -#define OUTPUT_DEVICE_PROFILE 0x70727472 // 'prtr' -#define DEVICE_LINK_PROFILE 0x6c696e6b // 'link' -#define COLOR_SPACE_PROFILE 0x73706163 // 'spac' -#define ABSTRACT_PROFILE 0x61627374 // 'abst' -#define NAMED_COLOR_PROFILE 0x6e6d636c // 'nmcl' - -static void read_class_signature(qcms_profile *profile, struct mem_source *mem) -{ - profile->class = read_u32(mem, 12); - switch (profile->class) { - case DISPLAY_DEVICE_PROFILE: - case INPUT_DEVICE_PROFILE: - case OUTPUT_DEVICE_PROFILE: - case COLOR_SPACE_PROFILE: - break; - default: - invalid_source(mem, "Invalid Profile/Device Class signature"); - } -} - -static void read_color_space(qcms_profile *profile, struct mem_source *mem) -{ - profile->color_space = read_u32(mem, 16); - switch (profile->color_space) { - case RGB_SIGNATURE: - case GRAY_SIGNATURE: - break; - default: - invalid_source(mem, "Unsupported colorspace"); - } -} - -static void read_pcs(qcms_profile *profile, struct mem_source *mem) -{ - profile->pcs = read_u32(mem, 20); - switch (profile->pcs) { - case XYZ_SIGNATURE: - case LAB_SIGNATURE: - break; - default: - invalid_source(mem, "Unsupported pcs"); - } -} - -struct tag { - uint32_t signature; - uint32_t offset; - uint32_t size; -}; - -struct tag_index { - uint32_t count; - struct tag *tags; -}; - -static struct tag_index read_tag_table(qcms_profile *profile, struct mem_source *mem) -{ - struct tag_index index = {0, NULL}; - unsigned int i; - - index.count = read_u32(mem, 128); - if (index.count > MAX_TAG_COUNT) { - invalid_source(mem, "max number of tags exceeded"); - return index; - } - - index.tags = malloc(sizeof(struct tag)*index.count); - if (index.tags) { - for (i = 0; i < index.count; i++) { - index.tags[i].signature = read_u32(mem, 128 + 4 + 4*i*3); - index.tags[i].offset = read_u32(mem, 128 + 4 + 4*i*3 + 4); - index.tags[i].size = read_u32(mem, 128 + 4 + 4*i*3 + 8); - } - } - - return index; -} - -/* Checks a profile for obvious inconsistencies and return true if the - * profile looks bogus and should probably be ignored. - */ -qcms_bool qcms_profile_is_bogus(qcms_profile *profile) -{ - float rX, rY, rZ, gX, gY, gZ, bX, bY, bZ; - float target[3], tolerance[3], sum[3]; - unsigned i; - - // We currently only check the bogosity of RGB profiles. - if (profile->color_space != RGB_SIGNATURE) - return false; - - if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0)) - return false; - - rX = s15Fixed16Number_to_float(profile->redColorant.X); - rY = s15Fixed16Number_to_float(profile->redColorant.Y); - rZ = s15Fixed16Number_to_float(profile->redColorant.Z); - - gX = s15Fixed16Number_to_float(profile->greenColorant.X); - gY = s15Fixed16Number_to_float(profile->greenColorant.Y); - gZ = s15Fixed16Number_to_float(profile->greenColorant.Z); - - bX = s15Fixed16Number_to_float(profile->blueColorant.X); - bY = s15Fixed16Number_to_float(profile->blueColorant.Y); - bZ = s15Fixed16Number_to_float(profile->blueColorant.Z); - - // Build our target vector: CIE D50 white. See also mozilla bug 460629, - // and http://www.color.org/whyd50.xalter "Why is the media white point - // of a display profile always D50?" - - target[0] = (float) 0.96420; - target[1] = (float) 1.00000; - target[2] = (float) 0.82491; - - // Our tolerance vector - Recommended by Chris Murphy [1] based on - // conversion from the L*a*b space criterion of no more than 3 in any - // one channel. This is similar to, but slightly more tolerant than - // Adobe's criterion. [1] https://bugzil.la/460629#c10 - - tolerance[0] = (float) 0.02; - tolerance[1] = (float) 0.02; - tolerance[2] = (float) 0.04; - - // Sum the XYZ values: they should add to D50 white, within tolerance. - - // FIXME: this test assumes the TRC RGB curves equal 1.0 for the white - // input (255,255,255) RGB test color. For user display profiles, that - // is the normal case. Profiles with abnormal TRC exist. A better test - // would transform 255,255,255 white through the profile to either XYZ - // or L*a*b color and compare the result to D50 in XYZ or L*a*b color. - - sum[0] = rX + gX + bX; - sum[1] = rY + gY + bY; - sum[2] = rZ + gZ + bZ; - - for (i = 0; i < 3; ++i) { - if (!(((sum[i] - tolerance[i]) <= target[i]) && - ((sum[i] + tolerance[i]) >= target[i]))) { - return true; // out of tolerance: bogus - } - } - -#ifndef __APPLE__ - // Check if any of the XYZ values are negative (see mozilla bug 498245) - // CIEXYZ tristimulus values cannot be negative according to the spec. - - bool negative = - (rX < 0) || (rY < 0) || (rZ < 0) || - (gX < 0) || (gY < 0) || (gZ < 0) || - (bX < 0) || (bY < 0) || (bZ < 0); - - if (negative) - return true; // bogus -#else - // Chromatic adaption to D50 can result in negative XYZ, but the white - // point D50 tolerance test has passed. Accept negative values herein. - // See https://bugzilla.mozilla.org/show_bug.cgi?id=498245#c18 onwards - // for discussion about whether profile XYZ can or cannot be negative, - // per the spec. Also the https://bugzil.la/450923 user report. - - // FIXME: allow this relaxation on all ports? -#endif - // All good. - return false; -} - -qcms_bool qcms_profile_has_white_point(qcms_profile *profile) -{ - struct XYZNumber wp = profile->mediaWhitePoint; - - return (wp.X != 0) && (wp.Y != 0) && (wp.Z != 0); -} - -qcms_xyz_float qcms_profile_get_white_point(qcms_profile *profile) -{ - qcms_xyz_float wp = { 0.0f, 0.0f, 0.0f }; - - if (qcms_profile_has_white_point(profile)) { - wp.X = s15Fixed16Number_to_float(profile->mediaWhitePoint.X); - wp.Y = s15Fixed16Number_to_float(profile->mediaWhitePoint.Y); - wp.Z = s15Fixed16Number_to_float(profile->mediaWhitePoint.Z); - } - - return wp; -} - -#define TAG_bXYZ 0x6258595a -#define TAG_gXYZ 0x6758595a -#define TAG_rXYZ 0x7258595a -#define TAG_rTRC 0x72545243 -#define TAG_bTRC 0x62545243 -#define TAG_gTRC 0x67545243 -#define TAG_kTRC 0x6b545243 -#define TAG_A2B0 0x41324230 -#define TAG_B2A0 0x42324130 -#define TAG_CHAD 0x63686164 -#define TAG_desc 0x64657363 -#define TAG_vcgt 0x76636774 -#define TAG_wtpt 0x77747074 - -static struct tag *find_tag(struct tag_index index, uint32_t tag_id) -{ - unsigned int i; - - for (i = 0; i < index.count; i++) { - if (index.tags[i].signature == tag_id) - return &index.tags[i]; - } - - return NULL; -} - -#define DESC_TYPE 0x64657363 // 'desc' -#define MLUC_TYPE 0x6d6c7563 // 'mluc' -#define MMOD_TYPE 0x6D6D6F64 // 'mmod' -#define VCGT_TYPE 0x76636774 // 'vcgt' - -enum { - VCGT_TYPE_TABLE, - VCGT_TYPE_FORMULA, - VCGT_TYPE_LAST = VCGT_TYPE_FORMULA -}; - -static qcms_bool read_tag_vcgtType(qcms_profile *profile, struct mem_source *src, struct tag_index index) -{ - size_t tag_offset = find_tag(index, TAG_vcgt)->offset; - uint32_t tag_type = read_u32(src, tag_offset); - uint32_t vcgt_type = read_u32(src, tag_offset + 8); - - if (!src->valid || tag_type != VCGT_TYPE) - goto invalid_vcgt_tag; - - // Only support table and equation types. - if (vcgt_type > VCGT_TYPE_LAST) - return true; - - if (vcgt_type == VCGT_TYPE_TABLE) { - uint16_t channels = read_u16(src, tag_offset + 12); - uint16_t elements = read_u16(src, tag_offset + 14); - uint16_t byte_depth = read_u16(src, tag_offset + 16); - size_t table_offset = tag_offset + 18; - uint32_t i; - uint16_t *dest; - - if (!src->valid) - goto invalid_vcgt_tag; - - // Only support 3 channels. - if (channels != 3) - return true; - // Only support single or double byte values. - if (byte_depth != 1 && byte_depth != 2) - return true; - // Limit the table to a sensible size; 10-bit gamma is a reasonable - // maximum for hardware correction. - if (elements > 1024) - return true; - - // Empty table is invalid. - if (!elements) - goto invalid_vcgt_tag; - - profile->vcgt.length = elements; - profile->vcgt.data = malloc(3 * elements * sizeof(uint16_t)); - if (!profile->vcgt.data) - return false; - - dest = profile->vcgt.data; - - for (i = 0; i < 3 * elements; ++i) { - if (byte_depth == 1) { - *dest++ = read_u8(src, table_offset) * 256; - } else { - *dest++ = read_u16(src, table_offset); - } - - table_offset += byte_depth; - - if (!src->valid) - goto invalid_vcgt_tag; - } - } else { - size_t formula_offset = tag_offset + 12; - int i, j; - uint16_t *dest; - - // For formula always provide an 8-bit lut. - profile->vcgt.length = 256; - profile->vcgt.data = malloc(3 * profile->vcgt.length * sizeof(uint16_t)); - if (!profile->vcgt.data) - return false; - - dest = profile->vcgt.data; - for (i = 0; i < 3; ++i) { - float gamma = s15Fixed16Number_to_float( - read_s15Fixed16Number(src, formula_offset + 12 * i)); - float min = s15Fixed16Number_to_float( - read_s15Fixed16Number(src, formula_offset + 4 + 12 * i)); - float max = s15Fixed16Number_to_float( - read_s15Fixed16Number(src, formula_offset + 8 + 12 * i)); - float range = max - min; - - if (!src->valid) - goto invalid_vcgt_tag; - - for (j = 0; j < profile->vcgt.length; ++j) { - *dest++ = 65535.f * - (min + range * pow((float)j / (profile->vcgt.length - 1), gamma)); - } - } - } - - return true; - -invalid_vcgt_tag: - invalid_source(src, "invalid vcgt tag"); - return false; -} - -static bool read_tag_descType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id) -{ - struct tag *tag = find_tag(index, tag_id); - if (tag) { - const uint32_t limit = sizeof profile->description; - uint32_t offset = tag->offset; - uint32_t type = read_u32(src, offset); - uint32_t length = read_u32(src, offset+8); - uint32_t i, description_offset; - bool mluc = false; - if (length && type == MLUC_TYPE) { - length = read_u32(src, offset+20); - if (!length || (length & 1) || (read_u32(src, offset+12) != 12)) - goto invalid_desc_tag; - description_offset = offset + read_u32(src, offset+24); - if (!src->valid) - goto invalid_desc_tag; - mluc = true; - } else if (length && type == DESC_TYPE) { - description_offset = offset + 12; - } else { - goto invalid_desc_tag; - } - if (length >= limit) - length = limit - 1; - for (i = 0; i < length; ++i) { - uint8_t value = read_u8(src, description_offset + i); - if (!src->valid) - goto invalid_desc_tag; - if (mluc && !value) - value = '.'; - profile->description[i] = value; - } - profile->description[length] = 0; - } else { - goto invalid_desc_tag; - } - - if (src->valid) - return true; - -invalid_desc_tag: - invalid_source(src, "invalid description"); - return false; -} - -#if defined(__APPLE__) - -// Use the dscm tag to change profile description "Display" to its more specific en-localized monitor name, if any. - -#define TAG_dscm 0x6473636D // 'dscm' - -static bool read_tag_dscmType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id) -{ - if (strcmp(profile->description, "Display") != 0) - return true; - - struct tag *tag = find_tag(index, tag_id); - if (tag) { - uint32_t offset = tag->offset; - uint32_t type = read_u32(src, offset); - uint32_t records = read_u32(src, offset+8); - - if (!src->valid || !records || type != MLUC_TYPE) - goto invalid_dscm_tag; - if (read_u32(src, offset+12) != 12) // MLUC record size: bytes - goto invalid_dscm_tag; - - for (uint32_t i = 0; i < records; ++i) { - const uint32_t limit = sizeof profile->description; - const uint16_t isoen = 0x656E; // ISO-3166-1 language 'en' - - uint16_t language = read_u16(src, offset + 16 + (i * 12) + 0); - uint32_t length = read_u32(src, offset + 16 + (i * 12) + 4); - uint32_t description_offset = read_u32(src, offset + 16 + (i * 12) + 8); - - if (!src->valid || !length || (length & 1)) - goto invalid_dscm_tag; - if (language != isoen) - continue; - - // Use a prefix to identify the display description source - strcpy(profile->description, "dscm:"); - length += 5; - - if (length >= limit) - length = limit - 1; - for (uint32_t j = 5; j < length; ++j) { - uint8_t value = read_u8(src, offset + description_offset + j - 5); - if (!src->valid) - goto invalid_dscm_tag; - profile->description[j] = value ? value : '.'; - } - profile->description[length] = 0; - break; - } - } - - if (src->valid) - return true; - -invalid_dscm_tag: - invalid_source(src, "invalid dscm tag"); - return false; -} - -// Use the mmod tag to change profile description "Display" to its specific mmod maker model data, if any. - -#define TAG_mmod 0x6D6D6F64 // 'mmod' - -static bool read_tag_mmodType(qcms_profile *profile, struct mem_source *src, struct tag_index index, uint32_t tag_id) -{ - if (strcmp(profile->description, "Display") != 0) - return true; - - struct tag *tag = find_tag(index, tag_id); - if (tag) { - const uint8_t length = 4 * 4; // Four 4-byte fields: 'mmod', 0, maker, model. - - uint32_t offset = tag->offset; - if (tag->size < 40 || read_u32(src, offset) != MMOD_TYPE) - goto invalid_mmod_tag; - - for (uint8_t i = 0; i < length; ++i) { - uint8_t value = read_u8(src, offset + i); - if (!src->valid) - goto invalid_mmod_tag; - profile->description[i] = value ? value : '.'; - } - profile->description[length] = 0; - } - - if (src->valid) - return true; - -invalid_mmod_tag: - invalid_source(src, "invalid mmod tag"); - return false; -} - -#endif // __APPLE__ - -#define XYZ_TYPE 0x58595a20 // 'XYZ ' -#define CURVE_TYPE 0x63757276 // 'curv' -#define PARAMETRIC_CURVE_TYPE 0x70617261 // 'para' -#define LUT16_TYPE 0x6d667432 // 'mft2' -#define LUT8_TYPE 0x6d667431 // 'mft1' -#define LUT_MAB_TYPE 0x6d414220 // 'mAB ' -#define LUT_MBA_TYPE 0x6d424120 // 'mBA ' -#define CHROMATIC_TYPE 0x73663332 // 'sf32' - -static struct matrix read_tag_s15Fixed16ArrayType(struct mem_source *src, struct tag_index index, uint32_t tag_id) -{ - struct tag *tag = find_tag(index, tag_id); - struct matrix matrix; - if (tag) { - uint8_t i; - uint32_t offset = tag->offset; - uint32_t type = read_u32(src, offset); - - // Check mandatory type signature for s16Fixed16ArrayType - if (type != CHROMATIC_TYPE) { - invalid_source(src, "unexpected type, expected 'sf32'"); - } - - for (i = 0; i < 9; i++) { - matrix.m[i/3][i%3] = s15Fixed16Number_to_float(read_s15Fixed16Number(src, offset+8+i*4)); - } - matrix.invalid = false; - } else { - matrix.invalid = true; - invalid_source(src, "missing sf32tag"); - } - return matrix; -} - -static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_index index, uint32_t tag_id) -{ - struct XYZNumber num = {0, 0, 0}; - struct tag *tag = find_tag(index, tag_id); - if (tag) { - uint32_t offset = tag->offset; - - uint32_t type = read_u32(src, offset); - if (type != XYZ_TYPE) - invalid_source(src, "unexpected type, expected XYZ"); - num.X = read_s15Fixed16Number(src, offset+8); - num.Y = read_s15Fixed16Number(src, offset+12); - num.Z = read_s15Fixed16Number(src, offset+16); - } else { - invalid_source(src, "missing xyztag"); - } - return num; -} - -// Read the tag at a given offset rather then the tag_index. -// This method is used when reading mAB tags where nested curveType are -// present that are not part of the tag_index. -static struct curveType *read_curveType(struct mem_source *src, uint32_t offset, uint32_t *len) -{ - static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; - struct curveType *curve = NULL; - uint32_t type = read_u32(src, offset); - uint32_t count; - int i; - - if (type != CURVE_TYPE && type != PARAMETRIC_CURVE_TYPE) { - invalid_source(src, "unexpected type, expected CURV or PARA"); - return NULL; - } - - if (type == CURVE_TYPE) { - count = read_u32(src, offset+8); - -#define MAX_CURVE_ENTRIES 40000 //arbitrary - if (count > MAX_CURVE_ENTRIES) { - invalid_source(src, "curve size too large"); - return NULL; - } - curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*count); - if (!curve) - return NULL; - - curve->count = count; - curve->type = type; - - for (i=0; i<count; i++) { - curve->data[i] = read_u16(src, offset + 12 + i*2); - } - *len = 12 + count * 2; - } else { //PARAMETRIC_CURVE_TYPE - count = read_u16(src, offset+8); - - if (count > 4) { - invalid_source(src, "parametric function type not supported."); - return NULL; - } - - curve = malloc(sizeof(struct curveType)); - if (!curve) - return NULL; - - curve->count = count; - curve->type = type; - - for (i=0; i < COUNT_TO_LENGTH[count]; i++) { - curve->parameter[i] = s15Fixed16Number_to_float(read_s15Fixed16Number(src, offset + 12 + i*4)); - } - *len = 12 + COUNT_TO_LENGTH[count] * 4; - - if ((count == 1 || count == 2)) { - /* we have a type 1 or type 2 function that has a division by 'a' */ - float a = curve->parameter[1]; - if (a == 0.f) - invalid_source(src, "parametricCurve definition causes division by zero."); - } - } - - return curve; -} - -static struct curveType *read_tag_curveType(struct mem_source *src, struct tag_index index, uint32_t tag_id) -{ - struct tag *tag = find_tag(index, tag_id); - struct curveType *curve = NULL; - if (tag) { - uint32_t len; - return read_curveType(src, tag->offset, &len); - } else { - invalid_source(src, "missing curvetag"); - } - - return curve; -} - -#define MAX_CLUT_SIZE 500000 // arbitrary -#define MAX_CHANNELS 10 // arbitrary -static void read_nested_curveType(struct mem_source *src, struct curveType *(*curveArray)[MAX_CHANNELS], uint8_t num_channels, uint32_t curve_offset) -{ - uint32_t channel_offset = 0; - int i; - for (i = 0; i < num_channels; i++) { - uint32_t tag_len = ~0; - - (*curveArray)[i] = read_curveType(src, curve_offset + channel_offset, &tag_len); - if (!(*curveArray)[i]) { - invalid_source(src, "invalid nested curveType curve"); - } - - if (tag_len == ~0) { - invalid_source(src, "invalid nested curveType tag length"); - return; - } - - channel_offset += tag_len; - // 4 byte aligned - if ((tag_len % 4) != 0) - channel_offset += 4 - (tag_len % 4); - } -} - -static void mAB_release(struct lutmABType *lut) -{ - uint8_t i; - - for (i = 0; i < lut->num_in_channels; i++){ - free(lut->a_curves[i]); - } - for (i = 0; i < lut->num_out_channels; i++){ - free(lut->b_curves[i]); - free(lut->m_curves[i]); - } - free(lut); -} - -/* See section 10.10 for specs */ -static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag_index index, uint32_t tag_id) -{ - struct tag *tag = find_tag(index, tag_id); - uint32_t offset = tag->offset; - uint32_t a_curve_offset, b_curve_offset, m_curve_offset; - uint32_t matrix_offset; - uint32_t clut_offset; - uint32_t clut_size = 1; - uint8_t clut_precision; - uint32_t type = read_u32(src, offset); - uint8_t num_in_channels, num_out_channels; - struct lutmABType *lut; - int i; - - if (type != LUT_MAB_TYPE && type != LUT_MBA_TYPE) { - return NULL; - } - - num_in_channels = read_u8(src, offset + 8); - num_out_channels = read_u8(src, offset + 8); - if (num_in_channels > MAX_CHANNELS || num_out_channels > MAX_CHANNELS) - return NULL; - - // We require 3in/out channels since we only support RGB->XYZ (or RGB->LAB) - // XXX: If we remove this restriction make sure that the number of channels - // is less or equal to the maximum number of mAB curves in qcmsint.h - // also check for clut_size overflow. Also make sure it's != 0 - if (num_in_channels != 3 || num_out_channels != 3) - return NULL; - - // some of this data is optional and is denoted by a zero offset - // we also use this to track their existance - a_curve_offset = read_u32(src, offset + 28); - clut_offset = read_u32(src, offset + 24); - m_curve_offset = read_u32(src, offset + 20); - matrix_offset = read_u32(src, offset + 16); - b_curve_offset = read_u32(src, offset + 12); - - // Convert offsets relative to the tag to relative to the profile - // preserve zero for optional fields - if (a_curve_offset) - a_curve_offset += offset; - if (clut_offset) - clut_offset += offset; - if (m_curve_offset) - m_curve_offset += offset; - if (matrix_offset) - matrix_offset += offset; - if (b_curve_offset) - b_curve_offset += offset; - - if (clut_offset) { - assert (num_in_channels == 3); - // clut_size can not overflow since lg(256^num_in_channels) = 24 bits. - for (i = 0; i < num_in_channels; i++) { - clut_size *= read_u8(src, clut_offset + i); - if (clut_size == 0) { - invalid_source(src, "bad clut_size"); - } - } - } else { - clut_size = 0; - } - - // 24bits * 3 won't overflow either - clut_size = clut_size * num_out_channels; - - if (clut_size > MAX_CLUT_SIZE) - return NULL; - - lut = malloc(sizeof(struct lutmABType) + (clut_size) * sizeof(float)); - if (!lut) - return NULL; - // we'll fill in the rest below - memset(lut, 0, sizeof(struct lutmABType)); - lut->clut_table = &lut->clut_table_data[0]; - - if (clut_offset) { - for (i = 0; i < num_in_channels; i++) { - lut->num_grid_points[i] = read_u8(src, clut_offset + i); - if (lut->num_grid_points[i] == 0) { - invalid_source(src, "bad grid_points"); - } - } - } - - // Reverse the processing of transformation elements for mBA type. - lut->reversed = (type == LUT_MBA_TYPE); - - lut->num_in_channels = num_in_channels; - lut->num_out_channels = num_out_channels; - - if (matrix_offset) { - // read the matrix if we have it - lut->e00 = read_s15Fixed16Number(src, matrix_offset+4*0); - lut->e01 = read_s15Fixed16Number(src, matrix_offset+4*1); - lut->e02 = read_s15Fixed16Number(src, matrix_offset+4*2); - lut->e10 = read_s15Fixed16Number(src, matrix_offset+4*3); - lut->e11 = read_s15Fixed16Number(src, matrix_offset+4*4); - lut->e12 = read_s15Fixed16Number(src, matrix_offset+4*5); - lut->e20 = read_s15Fixed16Number(src, matrix_offset+4*6); - lut->e21 = read_s15Fixed16Number(src, matrix_offset+4*7); - lut->e22 = read_s15Fixed16Number(src, matrix_offset+4*8); - lut->e03 = read_s15Fixed16Number(src, matrix_offset+4*9); - lut->e13 = read_s15Fixed16Number(src, matrix_offset+4*10); - lut->e23 = read_s15Fixed16Number(src, matrix_offset+4*11); - } - - if (a_curve_offset) { - read_nested_curveType(src, &lut->a_curves, num_in_channels, a_curve_offset); - } - if (m_curve_offset) { - read_nested_curveType(src, &lut->m_curves, num_out_channels, m_curve_offset); - } - if (b_curve_offset) { - read_nested_curveType(src, &lut->b_curves, num_out_channels, b_curve_offset); - } else { - invalid_source(src, "B curves required"); - } - - if (clut_offset) { - clut_precision = read_u8(src, clut_offset + 16); - if (clut_precision == 1) { - for (i = 0; i < clut_size; i++) { - lut->clut_table[i] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + 20 + i*1)); - } - } else if (clut_precision == 2) { - for (i = 0; i < clut_size; i++) { - lut->clut_table[i] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + 20 + i*2)); - } - } else { - invalid_source(src, "Invalid clut precision"); - } - } - - if (!src->valid) { - mAB_release(lut); - return NULL; - } - - return lut; -} - -static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index index, uint32_t tag_id) -{ - struct tag *tag = find_tag(index, tag_id); - uint32_t offset = tag->offset; - uint32_t type = read_u32(src, offset); - uint16_t num_input_table_entries; - uint16_t num_output_table_entries; - uint8_t in_chan, grid_points, out_chan; - size_t clut_offset, output_offset; - uint32_t clut_size; - size_t entry_size; - struct lutType *lut; - int i; - - /* I'm not sure why the spec specifies a fixed number of entries for LUT8 tables even though - * they have room for the num_entries fields */ - if (type == LUT8_TYPE) { - num_input_table_entries = 256; - num_output_table_entries = 256; - entry_size = 1; - } else if (type == LUT16_TYPE) { - num_input_table_entries = read_u16(src, offset + 48); - num_output_table_entries = read_u16(src, offset + 50); - if (num_input_table_entries == 0 || num_output_table_entries == 0) { - invalid_source(src, "Bad channel count"); - return NULL; - } - entry_size = 2; - } else { - assert(0); // the caller checks that this doesn't happen - invalid_source(src, "Unexpected lut type"); - return NULL; - } - - in_chan = read_u8(src, offset + 8); - out_chan = read_u8(src, offset + 9); - grid_points = read_u8(src, offset + 10); - - clut_size = pow(grid_points, in_chan); - if (clut_size > MAX_CLUT_SIZE) { - invalid_source(src, "CLUT too large"); - return NULL; - } - - if (clut_size <= 0) { - invalid_source(src, "CLUT must not be empty."); - return NULL; - } - - if (in_chan != 3 || out_chan != 3) { - invalid_source(src, "CLUT only supports RGB"); - return NULL; - } - - lut = malloc(sizeof(struct lutType) + (num_input_table_entries * in_chan + clut_size*out_chan + num_output_table_entries * out_chan)*sizeof(float)); - if (!lut) { - invalid_source(src, "CLUT too large"); - return NULL; - } - - /* compute the offsets of tables */ - lut->input_table = &lut->table_data[0]; - lut->clut_table = &lut->table_data[in_chan*num_input_table_entries]; - lut->output_table = &lut->table_data[in_chan*num_input_table_entries + clut_size*out_chan]; - - lut->num_input_table_entries = num_input_table_entries; - lut->num_output_table_entries = num_output_table_entries; - lut->num_input_channels = in_chan; - lut->num_output_channels = out_chan; - lut->num_clut_grid_points = grid_points; - lut->e00 = read_s15Fixed16Number(src, offset+12); - lut->e01 = read_s15Fixed16Number(src, offset+16); - lut->e02 = read_s15Fixed16Number(src, offset+20); - lut->e10 = read_s15Fixed16Number(src, offset+24); - lut->e11 = read_s15Fixed16Number(src, offset+28); - lut->e12 = read_s15Fixed16Number(src, offset+32); - lut->e20 = read_s15Fixed16Number(src, offset+36); - lut->e21 = read_s15Fixed16Number(src, offset+40); - lut->e22 = read_s15Fixed16Number(src, offset+44); - - for (i = 0; i < lut->num_input_table_entries * in_chan; i++) { - if (type == LUT8_TYPE) { - lut->input_table[i] = uInt8Number_to_float(read_uInt8Number(src, offset + 52 + i * entry_size)); - } else { - lut->input_table[i] = uInt16Number_to_float(read_uInt16Number(src, offset + 52 + i * entry_size)); - } - } - - clut_offset = offset + 52 + lut->num_input_table_entries * in_chan * entry_size; - for (i = 0; i < clut_size * out_chan; i+=3) { - if (type == LUT8_TYPE) { - lut->clut_table[i+0] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 0)); - lut->clut_table[i+1] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 1)); - lut->clut_table[i+2] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 2)); - } else { - lut->clut_table[i+0] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 0)); - lut->clut_table[i+1] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 2)); - lut->clut_table[i+2] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 4)); - } - } - - output_offset = clut_offset + clut_size * out_chan * entry_size; - for (i = 0; i < lut->num_output_table_entries * out_chan; i++) { - if (type == LUT8_TYPE) { - lut->output_table[i] = uInt8Number_to_float(read_uInt8Number(src, output_offset + i*entry_size)); - } else { - lut->output_table[i] = uInt16Number_to_float(read_uInt16Number(src, output_offset + i*entry_size)); - } - } - - return lut; -} - -static void read_rendering_intent(qcms_profile *profile, struct mem_source *src) -{ - profile->rendering_intent = read_u32(src, 64); - switch (profile->rendering_intent) { - case QCMS_INTENT_PERCEPTUAL: - case QCMS_INTENT_SATURATION: - case QCMS_INTENT_RELATIVE_COLORIMETRIC: - case QCMS_INTENT_ABSOLUTE_COLORIMETRIC: - break; - default: - invalid_source(src, "unknown rendering intent"); - } -} - -qcms_profile *qcms_profile_create(void) -{ - return calloc(sizeof(qcms_profile), 1); -} - - - -/* build sRGB gamma table */ -/* based on cmsBuildParametricGamma() */ -static uint16_t *build_sRGB_gamma_table(int num_entries) -{ - int i; - /* taken from lcms: Build_sRGBGamma() */ - double gamma = 2.4; - double a = 1./1.055; - double b = 0.055/1.055; - double c = 1./12.92; - double d = 0.04045; - - uint16_t *table = malloc(sizeof(uint16_t) * num_entries); - if (!table) - return NULL; - - for (i=0; i<num_entries; i++) { - double x = (double)i / (num_entries-1); - double y, output; - // IEC 61966-2.1 (sRGB) - // Y = (aX + b)^Gamma | X >= d - // Y = cX | X < d - if (x >= d) { - double e = (a*x + b); - if (e > 0) - y = pow(e, gamma); - else - y = 0; - } else { - y = c*x; - } - - // Saturate -- this could likely move to a separate function - output = y * 65535. + .5; - if (output > 65535.) - output = 65535; - if (output < 0) - output = 0; - table[i] = (uint16_t)floor(output); - } - return table; -} - -static struct curveType *curve_from_table(uint16_t *table, int num_entries) -{ - struct curveType *curve; - int i; - curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entries); - if (!curve) - return NULL; - curve->type = CURVE_TYPE; - curve->count = num_entries; - for (i = 0; i < num_entries; i++) { - curve->data[i] = table[i]; - } - return curve; -} - -static uint16_t float_to_u8Fixed8Number(float a) -{ - if (a > (255.f + 255.f/256)) - return 0xffff; - else if (a < 0.f) - return 0; - else - return floor(a*256.f + .5f); -} - -static struct curveType *curve_from_gamma(float gamma) -{ - struct curveType *curve; - int num_entries = 1; - curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entries); - if (!curve) - return NULL; - curve->count = num_entries; - curve->data[0] = float_to_u8Fixed8Number(gamma); - return curve; -} - - -//XXX: it would be nice if we had a way of ensuring -// everything in a profile was initialized regardless of how it was created - -//XXX: should this also be taking a black_point? -/* similar to CGColorSpaceCreateCalibratedRGB */ -qcms_profile* qcms_profile_create_rgb_with_gamma( - qcms_CIE_xyY white_point, - qcms_CIE_xyYTRIPLE primaries, - float gamma) -{ - qcms_profile* profile = qcms_profile_create(); - if (!profile) - return NO_MEM_PROFILE; - - if (!set_rgb_colorants(profile, white_point, primaries)) { - qcms_profile_release(profile); - return INVALID_PROFILE; - } - - profile->redTRC = curve_from_gamma(gamma); - profile->blueTRC = curve_from_gamma(gamma); - profile->greenTRC = curve_from_gamma(gamma); - - if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) { - qcms_profile_release(profile); - return NO_MEM_PROFILE; - } - - profile->class = DISPLAY_DEVICE_PROFILE; - profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; - profile->color_space = RGB_SIGNATURE; - profile->pcs = XYZ_SIGNATURE; - return profile; -} - -qcms_profile* qcms_profile_create_rgb_with_table( - qcms_CIE_xyY white_point, - qcms_CIE_xyYTRIPLE primaries, - uint16_t *table, int num_entries) -{ - qcms_profile* profile = qcms_profile_create(); - if (!profile) - return NO_MEM_PROFILE; - - if (!set_rgb_colorants(profile, white_point, primaries)) { - qcms_profile_release(profile); - return INVALID_PROFILE; - } - - profile->redTRC = curve_from_table(table, num_entries); - profile->blueTRC = curve_from_table(table, num_entries); - profile->greenTRC = curve_from_table(table, num_entries); - - if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) { - qcms_profile_release(profile); - return NO_MEM_PROFILE; - } - - profile->class = DISPLAY_DEVICE_PROFILE; - profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; - profile->color_space = RGB_SIGNATURE; - profile->pcs = XYZ_SIGNATURE; - return profile; -} - -/* from lcms: cmsWhitePointFromTemp */ -/* tempK must be >= 4000. and <= 25000. - * Invalid values of tempK will return - * (x,y,Y) = (-1.0, -1.0, -1.0) - * similar to argyll: icx_DTEMP2XYZ() */ -qcms_CIE_xyY white_point_from_temp(int temp_K) -{ - qcms_CIE_xyY white_point; - double x, y; - double T, T2, T3; - // double M1, M2; - - // No optimization provided. - T = temp_K; - T2 = T*T; // Square - T3 = T2*T; // Cube - - // For correlated color temperature (T) between 4000K and 7000K: - if (T >= 4000. && T <= 7000.) { - x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; - } else { - // or for correlated color temperature (T) between 7000K and 25000K: - if (T > 7000.0 && T <= 25000.0) { - x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; - } else { - // Invalid tempK - white_point.x = -1.0; - white_point.y = -1.0; - white_point.Y = -1.0; - - assert(0 && "invalid temp"); - - return white_point; - } - } - - // Obtain y(x) - - y = -3.000*(x*x) + 2.870*x - 0.275; - - // wave factors (not used, but here for futures extensions) - - // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); - // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); - - // Fill white_point struct - white_point.x = x; - white_point.y = y; - white_point.Y = 1.0; - - return white_point; -} - -qcms_profile* qcms_profile_sRGB(void) -{ - qcms_profile *profile; - uint16_t *table; - - // Standard Illuminant D65 in XYZ coordinates, which is the standard - // sRGB IEC61966-2.1 / Rec.709 profile reference media white point. - struct XYZNumber D65 = { - 0xf351, 0x10000, 0x116cc // ( 0.950455, 1.000000, 1.089050 ) - }; - - // sRGB IEC61966-2.1 / Rec.709 color profile primaries, chromatically - // adapted (via Bradford procedures) to D50 white point. - // For details, refer to crbug/580917 -#if 0 - // lindbloom: ASTM E308-01 D50 White point. - s15Fixed16Number primaries[3][3] = { - { 0x06fa3, 0x06294, 0x024a1 }, // ( 0.436081, 0.385071, 0.143082 ) - { 0x038f6, 0x0b785, 0x00f85 }, // ( 0.222504, 0.716873, 0.060623 ) - { 0x00391, 0x018dc, 0x0b6d4 }, // ( 0.013931, 0.097107, 0.714172 ) - }; -#else - // ninedegreesbelow: ICC D50 White point. - s15Fixed16Number primaries[3][3] = { - { 0x06fa0, 0x06296, 0x024a0 }, // ( 0.436035, 0.385101, 0.143066 ) - { 0x038f2, 0x0b789, 0x00f85 }, // ( 0.222443, 0.716934, 0.060623 ) - { 0x0038f, 0x018da, 0x0b6c4 }, // ( 0.013901, 0.097076, 0.713928 ) - }; -#endif - - table = build_sRGB_gamma_table(1024); - - if (!table) - return NO_MEM_PROFILE; - - profile = qcms_profile_create(); - - if (!profile) { - free(table); - return NO_MEM_PROFILE; - } - - profile->redTRC = curve_from_table(table, 1024); - profile->blueTRC = curve_from_table(table, 1024); - profile->greenTRC = curve_from_table(table, 1024); - - if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) { - qcms_profile_release(profile); - free(table); - return NO_MEM_PROFILE; - } - - profile->redColorant.X = primaries[0][0]; - profile->redColorant.Y = primaries[1][0]; - profile->redColorant.Z = primaries[2][0]; - - profile->greenColorant.X = primaries[0][1]; - profile->greenColorant.Y = primaries[1][1]; - profile->greenColorant.Z = primaries[2][1]; - - profile->blueColorant.X = primaries[0][2]; - profile->blueColorant.Y = primaries[1][2]; - profile->blueColorant.Z = primaries[2][2]; - - profile->mediaWhitePoint.X = D65.X; - profile->mediaWhitePoint.Y = D65.Y; - profile->mediaWhitePoint.Z = D65.Z; - - profile->class = DISPLAY_DEVICE_PROFILE; - profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; - profile->color_space = RGB_SIGNATURE; - profile->pcs = XYZ_SIGNATURE; - - strcpy(profile->description, "sRGB IEC61966-2.1"); - - free(table); - - return profile; -} - -/* qcms_profile_from_memory does not hold a reference to the memory passed in */ -qcms_profile* qcms_profile_from_memory(const void *mem, size_t size) -{ - uint32_t length; - struct mem_source source; - struct mem_source *src = &source; - struct tag_index index; - qcms_profile *profile; - - source.buf = mem; - source.size = size; - source.valid = true; - - if (size < 4) - return INVALID_PROFILE; - - length = read_u32(src, 0); - if (length <= size) { - // shrink the area that we can read if appropriate - source.size = length; - } else { - return INVALID_PROFILE; - } - - /* ensure that the profile size is sane so it's easier to reason about */ - if (source.size <= 64 || source.size >= MAX_PROFILE_SIZE) - return INVALID_PROFILE; - - profile = qcms_profile_create(); - if (!profile) - return NO_MEM_PROFILE; - - check_CMM_type_signature(src); - read_profile_version(profile, src); - read_class_signature(profile, src); - read_rendering_intent(profile, src); - read_color_space(profile, src); - read_pcs(profile, src); - //TODO read rest of profile stuff - - if (!src->valid) - goto invalid_profile; - - index = read_tag_table(profile, src); - if (!src->valid || !index.tags) - goto invalid_tag_table; - - if (!read_tag_descType(profile, src, index, TAG_desc)) - goto invalid_tag_table; -#if defined(__APPLE__) - if (!read_tag_dscmType(profile, src, index, TAG_dscm)) - goto invalid_tag_table; - if (!read_tag_mmodType(profile, src, index, TAG_mmod)) - goto invalid_tag_table; -#endif // __APPLE__ - - if (find_tag(index, TAG_CHAD)) { - profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, index, TAG_CHAD); - } else { - profile->chromaticAdaption.invalid = true; //Signal the data is not present - } - - if (find_tag(index, TAG_vcgt)) { - if (!read_tag_vcgtType(profile, src, index)) - goto invalid_tag_table; - } - - if (profile->class == DISPLAY_DEVICE_PROFILE || profile->class == INPUT_DEVICE_PROFILE || - profile->class == OUTPUT_DEVICE_PROFILE || profile->class == COLOR_SPACE_PROFILE) { - if (profile->color_space == RGB_SIGNATURE) { - if (find_tag(index, TAG_A2B0)) { - if (read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT8_TYPE || - read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT16_TYPE) { - profile->A2B0 = read_tag_lutType(src, index, TAG_A2B0); - } else if (read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT_MAB_TYPE) { - profile->mAB = read_tag_lutmABType(src, index, TAG_A2B0); - } - } - if (find_tag(index, TAG_B2A0)) { - if (read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT8_TYPE || - read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT16_TYPE) { - profile->B2A0 = read_tag_lutType(src, index, TAG_B2A0); - } else if (read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT_MBA_TYPE) { - profile->mBA = read_tag_lutmABType(src, index, TAG_B2A0); - } - } - if (find_tag(index, TAG_rXYZ) || !qcms_supports_iccv4) { - profile->redColorant = read_tag_XYZType(src, index, TAG_rXYZ); - profile->greenColorant = read_tag_XYZType(src, index, TAG_gXYZ); - profile->blueColorant = read_tag_XYZType(src, index, TAG_bXYZ); - } - - if (!src->valid) - goto invalid_tag_table; - - if (find_tag(index, TAG_rTRC) || !qcms_supports_iccv4) { - profile->redTRC = read_tag_curveType(src, index, TAG_rTRC); - profile->greenTRC = read_tag_curveType(src, index, TAG_gTRC); - profile->blueTRC = read_tag_curveType(src, index, TAG_bTRC); - - if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) - goto invalid_tag_table; - } - } else if (profile->color_space == GRAY_SIGNATURE) { - - profile->grayTRC = read_tag_curveType(src, index, TAG_kTRC); - if (!profile->grayTRC) - goto invalid_tag_table; - - } else { - assert(0 && "read_color_space protects against entering here"); - goto invalid_tag_table; - } - } else { - goto invalid_tag_table; - } - - // Profiles other than DeviceLink should have a media white point. - // Here we read it if present. - if (find_tag(index, TAG_wtpt)) { - profile->mediaWhitePoint = read_tag_XYZType(src, index, TAG_wtpt); - } - - if (!src->valid) - goto invalid_tag_table; - - free(index.tags); - return profile; - -invalid_tag_table: - if (index.tags) - free(index.tags); -invalid_profile: - qcms_profile_release(profile); - return INVALID_PROFILE; -} - -qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2) -{ - return memcmp(p1->description, p2->description, sizeof p1->description) == 0; -} - -const char* qcms_profile_get_description(qcms_profile *profile) -{ - return profile->description; -} - -qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) -{ - return profile->rendering_intent; -} - -qcms_color_space qcms_profile_get_color_space(qcms_profile *profile) -{ - return profile->color_space; -} - -unsigned qcms_profile_get_version(qcms_profile *profile) -{ - return profile->icc_version & 0xffff; -} - -size_t qcms_profile_get_vcgt_channel_length(qcms_profile *profile) -{ - return profile->vcgt.length; -} - -// Check unsigned short is uint16_t. -typedef char assert_short_not_16b[(sizeof(unsigned short) == sizeof(uint16_t)) ? 1 : -1]; - -qcms_bool qcms_profile_get_vcgt_rgb_channels(qcms_profile *profile, unsigned short *data) -{ - size_t vcgt_channel_bytes = qcms_profile_get_vcgt_channel_length(profile) * sizeof(uint16_t); - - if (!vcgt_channel_bytes || !data) - return false; - - memcpy(data, profile->vcgt.data, 3 * vcgt_channel_bytes); - return true; -} - -static void lut_release(struct lutType *lut) -{ - free(lut); -} - -void qcms_profile_release(qcms_profile *profile) -{ - if (profile->output_table_r) - precache_release(profile->output_table_r); - if (profile->output_table_g) - precache_release(profile->output_table_g); - if (profile->output_table_b) - precache_release(profile->output_table_b); - - if (profile->A2B0) - lut_release(profile->A2B0); - if (profile->B2A0) - lut_release(profile->B2A0); - - if (profile->mAB) - mAB_release(profile->mAB); - if (profile->mBA) - mAB_release(profile->mBA); - - if (profile->vcgt.data) - free(profile->vcgt.data); - - free(profile->redTRC); - free(profile->blueTRC); - free(profile->greenTRC); - free(profile->grayTRC); - free(profile); -} - -#include <stdio.h> - -qcms_profile* qcms_profile_from_file(FILE *file) -{ - uint32_t length, remaining_length; - qcms_profile *profile; - size_t read_length; - be32 length_be; - void *data; - - if (fread(&length_be, 1, sizeof(length_be), file) != sizeof(length_be)) - return BAD_VALUE_PROFILE; - - length = be32_to_cpu(length_be); - if (length > MAX_PROFILE_SIZE || length < sizeof(length_be)) - return BAD_VALUE_PROFILE; - - /* allocate room for the entire profile */ - data = malloc(length); - if (!data) - return NO_MEM_PROFILE; - - /* copy in length to the front so that the buffer will contain the entire profile */ - *((be32*)data) = length_be; - remaining_length = length - sizeof(length_be); - - /* read the rest profile */ - read_length = fread((unsigned char*)data + sizeof(length_be), 1, remaining_length, file); - if (read_length != remaining_length) { - free(data); - return INVALID_PROFILE; - } - - profile = qcms_profile_from_memory(data, length); - free(data); - return profile; -} - -qcms_profile* qcms_profile_from_path(const char *path) -{ - qcms_profile *profile = NULL; - FILE *file = fopen(path, "rb"); - if (file) { - profile = qcms_profile_from_file(file); - fclose(file); - } - return profile; -} - -#ifdef _WIN32 -/* Unicode path version */ -qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path) -{ - qcms_profile *profile = NULL; - FILE *file = _wfopen(path, L"rb"); - if (file) { - profile = qcms_profile_from_file(file); - fclose(file); - } - return profile; -} -#endif diff --git a/third_party/qcms/src/matrix.c b/third_party/qcms/src/matrix.c deleted file mode 100644 index 0ce5bd66d1..0000000000 --- a/third_party/qcms/src/matrix.c +++ /dev/null @@ -1,136 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// Copyright (C) 1998-2007 Marti Maria -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include <stdlib.h> -#include "qcmsint.h" -#include "matrix.h" - -struct vector matrix_eval(struct matrix mat, struct vector v) -{ - struct vector result; - result.v[0] = mat.m[0][0]*v.v[0] + mat.m[0][1]*v.v[1] + mat.m[0][2]*v.v[2]; - result.v[1] = mat.m[1][0]*v.v[0] + mat.m[1][1]*v.v[1] + mat.m[1][2]*v.v[2]; - result.v[2] = mat.m[2][0]*v.v[0] + mat.m[2][1]*v.v[1] + mat.m[2][2]*v.v[2]; - return result; -} - -//XXX: should probably pass by reference and we could -//probably reuse this computation in matrix_invert -float matrix_det(struct matrix mat) -{ - float det; - det = mat.m[0][0]*mat.m[1][1]*mat.m[2][2] + - mat.m[0][1]*mat.m[1][2]*mat.m[2][0] + - mat.m[0][2]*mat.m[1][0]*mat.m[2][1] - - mat.m[0][0]*mat.m[1][2]*mat.m[2][1] - - mat.m[0][1]*mat.m[1][0]*mat.m[2][2] - - mat.m[0][2]*mat.m[1][1]*mat.m[2][0]; - return det; -} - -/* from pixman and cairo and Mathematics for Game Programmers */ -/* lcms uses gauss-jordan elimination with partial pivoting which is - * less efficient and not as numerically stable. See Mathematics for - * Game Programmers. */ -struct matrix matrix_invert(struct matrix mat) -{ - struct matrix dest_mat; - int i,j; - static int a[3] = { 2, 2, 1 }; - static int b[3] = { 1, 0, 0 }; - - /* inv (A) = 1/det (A) * adj (A) */ - float det = matrix_det(mat); - - if (det == 0) { - dest_mat.invalid = true; - } else { - dest_mat.invalid = false; - } - - det = 1/det; - - for (j = 0; j < 3; j++) { - for (i = 0; i < 3; i++) { - double p; - int ai = a[i]; - int aj = a[j]; - int bi = b[i]; - int bj = b[j]; - - p = mat.m[ai][aj] * mat.m[bi][bj] - - mat.m[ai][bj] * mat.m[bi][aj]; - if (((i + j) & 1) != 0) - p = -p; - - dest_mat.m[j][i] = det * p; - } - } - return dest_mat; -} - -struct matrix matrix_identity(void) -{ - struct matrix i; - i.m[0][0] = 1; - i.m[0][1] = 0; - i.m[0][2] = 0; - i.m[1][0] = 0; - i.m[1][1] = 1; - i.m[1][2] = 0; - i.m[2][0] = 0; - i.m[2][1] = 0; - i.m[2][2] = 1; - i.invalid = false; - return i; -} - -struct matrix matrix_invalid(void) -{ - struct matrix inv = matrix_identity(); - inv.invalid = true; - return inv; -} - - -/* from pixman */ -/* MAT3per... */ -struct matrix matrix_multiply(struct matrix a, struct matrix b) -{ - struct matrix result; - int dx, dy; - int o; - for (dy = 0; dy < 3; dy++) { - for (dx = 0; dx < 3; dx++) { - double v = 0; - for (o = 0; o < 3; o++) { - v += a.m[dy][o] * b.m[o][dx]; - } - result.m[dy][dx] = v; - } - } - result.invalid = a.invalid || b.invalid; - return result; -} - - diff --git a/third_party/qcms/src/matrix.h b/third_party/qcms/src/matrix.h deleted file mode 100644 index 5011988a16..0000000000 --- a/third_party/qcms/src/matrix.h +++ /dev/null @@ -1,39 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// Copyright (C) 1998-2007 Marti Maria -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef _QCMS_MATRIX_H -#define _QCMS_MATRIX_H - -struct vector { - float v[3]; -}; - -struct vector matrix_eval(struct matrix mat, struct vector v); -float matrix_det(struct matrix mat); -struct matrix matrix_identity(void); -struct matrix matrix_multiply(struct matrix a, struct matrix b); -struct matrix matrix_invert(struct matrix mat); - -struct matrix matrix_invalid(void); - -#endif diff --git a/third_party/qcms/src/qcms.h b/third_party/qcms/src/qcms.h deleted file mode 100644 index 9efe21fa7c..0000000000 --- a/third_party/qcms/src/qcms.h +++ /dev/null @@ -1,171 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef QCMS_H -#define QCMS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdio.h> - -struct _qcms_profile; -typedef struct _qcms_profile qcms_profile; - -struct _qcms_transform; -typedef struct _qcms_transform qcms_transform; - -typedef int qcms_bool; - -/* ICC Section 6.1.5 Color Space Signatures (abridged) */ -typedef enum { - XYZData /* ‘XYZ ’ */ = 0x58595A20, - labData /* ‘Lab ’ */ = 0x4C616220, - luvData /* ‘Luv ’ */ = 0x4C757620, - YCbCrData /* ‘YCbr' */ = 0x59436272, - YxyData /* ‘Yxy ’ */ = 0x59787920, - rgbData /* ‘RGB ’ */ = 0x52474220, - grayData /* ‘GRAY’ */ = 0x47524159, - hsvData /* ‘HSV ’ */ = 0x48535620, - hlsData /* ‘HLS ’ */ = 0x484C5320, - cmykData /* ‘CMYK’ */ = 0x434D594B, - cmyData /* ‘CMY ’ */ = 0x434D5920, -} qcms_color_space; - -/* ICC Section 6.1.11 Rendering Intents */ -typedef enum { - QCMS_INTENT_DEFAULT = 0, - QCMS_INTENT_PERCEPTUAL = 0, - QCMS_INTENT_RELATIVE_COLORIMETRIC = 1, - QCMS_INTENT_SATURATION = 2, - QCMS_INTENT_ABSOLUTE_COLORIMETRIC = 3 -} qcms_intent; - -/* Input data formats */ -typedef enum { - QCMS_DATA_RGB_8, - QCMS_DATA_RGBA_8, - QCMS_DATA_GRAY_8, - QCMS_DATA_GRAYA_8 -} qcms_data_type; - -/* Output data format for qcms_transform_data_type() */ -typedef enum { - QCMS_OUTPUT_RGBX, - QCMS_OUTPUT_BGRX -} qcms_output_type; - -/* Output data format for qcms_transform_get_input|output_trc_rgba() */ -typedef enum { - QCMS_TRC_PARAMETRIC, // Not implemented. - QCMS_TRC_FLOAT, // Not implemented. - QCMS_TRC_HALF_FLOAT, // IEE754: binary16. - QCMS_TRC_USHORT, // 0.16 fixed point. -} qcms_trc_type; - -typedef struct { - double x; - double y; - double Y; -} qcms_CIE_xyY; - -typedef struct { - qcms_CIE_xyY red; - qcms_CIE_xyY green; - qcms_CIE_xyY blue; -} qcms_CIE_xyYTRIPLE; - -typedef struct { - float X; - float Y; - float Z; -} qcms_xyz_float; - -qcms_profile* qcms_profile_create_rgb_with_gamma( - qcms_CIE_xyY white_point, - qcms_CIE_xyYTRIPLE primaries, - float gamma); - -qcms_profile* qcms_profile_from_memory(const void *mem, size_t size); - -qcms_profile* qcms_profile_from_file(FILE *file); -qcms_profile* qcms_profile_from_path(const char *path); -#ifdef _WIN32 -qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path); -#endif -qcms_profile* qcms_profile_sRGB(void); -void qcms_profile_release(qcms_profile *profile); - -qcms_bool qcms_profile_is_bogus(qcms_profile *profile); -qcms_bool qcms_profile_has_white_point(qcms_profile *profile); -qcms_xyz_float qcms_profile_get_white_point(qcms_profile *profile); -qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile); -qcms_color_space qcms_profile_get_color_space(qcms_profile *profile); -unsigned qcms_profile_get_version(qcms_profile *profile); -qcms_bool qcms_profile_white_transform(qcms_profile *profile, float XYZ[3]); - -qcms_bool qcms_profile_match(qcms_profile *p1, qcms_profile *p2); -const char* qcms_profile_get_description(qcms_profile *profile); - -void qcms_profile_precache_output_transform(qcms_profile *profile); - -size_t qcms_profile_get_vcgt_channel_length(qcms_profile *profile); -qcms_bool qcms_profile_get_vcgt_rgb_channels(qcms_profile *profile, unsigned short *data); - -float qcms_profile_ntsc_relative_gamut_size(qcms_profile *profile); - -qcms_transform* qcms_transform_create( - qcms_profile *in, qcms_data_type in_type, - qcms_profile *out, qcms_data_type out_type, - qcms_intent intent); - -size_t qcms_transform_get_input_trc_rgba( - qcms_transform *transform, qcms_profile *in, qcms_trc_type type, unsigned short *data); -size_t qcms_transform_get_output_trc_rgba( - qcms_transform *transform, qcms_profile *out, qcms_trc_type type, unsigned short *data); - -qcms_bool qcms_transform_is_matrix(qcms_transform *transform); -float qcms_transform_get_matrix(qcms_transform *transform, unsigned i, unsigned j); - -qcms_bool qcms_transform_create_LUT_zyx_bgra( - qcms_profile *in, qcms_profile *out, qcms_intent intent, - int samples, unsigned char* lut); - -void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length); -void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type); - -void qcms_transform_release(qcms_transform *); - -void qcms_enable_iccv4(); - -#ifdef __cplusplus -} -#endif - -/* - * In general, QCMS is not threadsafe. However, it should be safe to create - * profile and transformation objects on different threads, so long as you - * don't use the same objects on different threads at the same time. - */ - -#endif diff --git a/third_party/qcms/src/qcms_util.c b/third_party/qcms/src/qcms_util.c deleted file mode 100644 index 9b2d9fa744..0000000000 --- a/third_party/qcms/src/qcms_util.c +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcmsint.h" - -#include <math.h> - -typedef struct _qcms_coords { - float x; - float y; -} qcms_coords; - -typedef struct _qcms_triangle { - qcms_coords verticies[3]; -} qcms_triangle; - -#define NTSC_1953_GAMUT_SIZE 0.1582 - -static qcms_triangle get_profile_triangle(qcms_profile *profile) -{ - float sumRed = s15Fixed16Number_to_float(profile->redColorant.X) + - s15Fixed16Number_to_float(profile->redColorant.Y) + - s15Fixed16Number_to_float(profile->redColorant.Z); - float xRed = s15Fixed16Number_to_float(profile->redColorant.X) / sumRed; - float yRed = s15Fixed16Number_to_float(profile->redColorant.Y) / sumRed; - - float sumGreen = s15Fixed16Number_to_float(profile->greenColorant.X) + - s15Fixed16Number_to_float(profile->greenColorant.Y) + - s15Fixed16Number_to_float(profile->greenColorant.Z); - float xGreen = s15Fixed16Number_to_float(profile->greenColorant.X) / sumGreen; - float yGreen = s15Fixed16Number_to_float(profile->greenColorant.Y) / sumGreen; - - float sumBlue = s15Fixed16Number_to_float(profile->blueColorant.X) + - s15Fixed16Number_to_float(profile->blueColorant.Y) + - s15Fixed16Number_to_float(profile->blueColorant.Z); - float xBlue = s15Fixed16Number_to_float(profile->blueColorant.X) / sumBlue; - float yBlue = s15Fixed16Number_to_float(profile->blueColorant.Y) / sumBlue; - - qcms_triangle triangle = {{{xRed, yRed}, {xGreen, yGreen}, {xBlue, yBlue}}}; - return triangle; -} - -static float get_triangle_area(const qcms_triangle candidate) -{ - float xRed = candidate.verticies[0].x; - float yRed = candidate.verticies[0].y; - float xGreen = candidate.verticies[1].x; - float yGreen = candidate.verticies[1].y; - float xBlue = candidate.verticies[2].x; - float yBlue = candidate.verticies[2].y; - - float area = fabs((xRed - xBlue) * (yGreen - yBlue) - (xGreen - xBlue) * (yRed - yBlue)) / 2; - return area; -} - -static float get_ntsc_gamut_metric_area(const qcms_triangle candidate) -{ - float area = get_triangle_area(candidate); - return area * 100 / NTSC_1953_GAMUT_SIZE; -} - -float qcms_profile_ntsc_relative_gamut_size(qcms_profile *profile) -{ - qcms_triangle triangle = get_profile_triangle(profile); - return get_ntsc_gamut_metric_area(triangle); -} - - diff --git a/third_party/qcms/src/qcmsint.h b/third_party/qcms/src/qcmsint.h deleted file mode 100644 index 005b089758..0000000000 --- a/third_party/qcms/src/qcmsint.h +++ /dev/null @@ -1,342 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include "qcms.h" -#include "qcmstypes.h" - -/* used as a lookup table for the output transformation. - * we refcount them so we only need to have one around per output - * profile, instead of duplicating them per transform */ -struct precache_output -{ - int ref_count; - /* We previously used a count of 65536 here but that seems like more - * precision than we actually need. By reducing the size we can - * improve startup performance and reduce memory usage. ColorSync on - * 10.5 uses 4097 which is perhaps because they use a fixed point - * representation where 1. is represented by 0x1000. */ -#define PRECACHE_OUTPUT_SIZE 8192 -#define PRECACHE_OUTPUT_MAX (PRECACHE_OUTPUT_SIZE-1) - uint8_t data[PRECACHE_OUTPUT_SIZE]; -}; - -#ifdef _MSC_VER -#define ALIGN __declspec(align(16)) -#else -#define ALIGN __attribute__(( aligned (16) )) -#endif - -typedef struct _qcms_format_type { - int r; - int b; -} qcms_format_type; - -struct _qcms_transform { - float ALIGN matrix[3][4]; - float *input_gamma_table_r; - float *input_gamma_table_g; - float *input_gamma_table_b; - - float *input_clut_table_r; - float *input_clut_table_g; - float *input_clut_table_b; - uint16_t input_clut_table_length; - float *r_clut; - float *g_clut; - float *b_clut; - uint16_t grid_size; - float *output_clut_table_r; - float *output_clut_table_g; - float *output_clut_table_b; - uint16_t output_clut_table_length; - - float *input_gamma_table_gray; - - float out_gamma_r; - float out_gamma_g; - float out_gamma_b; - - float out_gamma_gray; - - uint16_t *output_gamma_lut_r; - uint16_t *output_gamma_lut_g; - uint16_t *output_gamma_lut_b; - - uint16_t *output_gamma_lut_gray; - - size_t output_gamma_lut_r_length; - size_t output_gamma_lut_g_length; - size_t output_gamma_lut_b_length; - - size_t output_gamma_lut_gray_length; - - struct precache_output *output_table_r; - struct precache_output *output_table_g; - struct precache_output *output_table_b; - - void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, struct _qcms_format_type output_format); - - unsigned char floor_cache[256]; - unsigned char ceil_cache[256]; - float r_cache[256]; - -#define TRANSFORM_FLAG_MATRIX 0x0001 -#define TRANSFORM_FLAG_CLUT_CACHE 0x0002 - - uint16_t transform_flags; -}; - -struct matrix { - float m[3][3]; - bool invalid; -}; - -struct qcms_modular_transform; - -typedef void (*transform_module_fn_t)(struct qcms_modular_transform *transform, float *src, float *dest, size_t length); - -struct qcms_modular_transform { - struct matrix matrix; - float tx, ty, tz; - - float *input_clut_table_r; - float *input_clut_table_g; - float *input_clut_table_b; - uint16_t input_clut_table_length; - float *r_clut; - float *g_clut; - float *b_clut; - uint16_t grid_size; - float *output_clut_table_r; - float *output_clut_table_g; - float *output_clut_table_b; - uint16_t output_clut_table_length; - - uint16_t *output_gamma_lut_r; - uint16_t *output_gamma_lut_g; - uint16_t *output_gamma_lut_b; - - size_t output_gamma_lut_r_length; - size_t output_gamma_lut_g_length; - size_t output_gamma_lut_b_length; - - transform_module_fn_t transform_module_fn; - struct qcms_modular_transform *next_transform; -}; - -typedef int32_t s15Fixed16Number; -typedef uint16_t uInt16Number; -typedef uint8_t uInt8Number; - -struct XYZNumber { - s15Fixed16Number X; - s15Fixed16Number Y; - s15Fixed16Number Z; -}; - -struct curveType { - uint32_t type; - uint32_t count; - float parameter[7]; - uInt16Number data[]; -}; - -struct lutmABType { - uint8_t num_in_channels; - uint8_t num_out_channels; - // 16 is the upperbound, actual is 0..num_in_channels. - uint8_t num_grid_points[16]; - - s15Fixed16Number e00; - s15Fixed16Number e01; - s15Fixed16Number e02; - s15Fixed16Number e03; - s15Fixed16Number e10; - s15Fixed16Number e11; - s15Fixed16Number e12; - s15Fixed16Number e13; - s15Fixed16Number e20; - s15Fixed16Number e21; - s15Fixed16Number e22; - s15Fixed16Number e23; - - // reversed elements (for mBA) - bool reversed; - - float *clut_table; - struct curveType *a_curves[10]; - struct curveType *b_curves[10]; - struct curveType *m_curves[10]; - float clut_table_data[]; -}; - -/* should lut8Type and lut16Type be different types? */ -struct lutType { // used by lut8Type/lut16Type (mft2) only - uint8_t num_input_channels; - uint8_t num_output_channels; - uint8_t num_clut_grid_points; - - s15Fixed16Number e00; - s15Fixed16Number e01; - s15Fixed16Number e02; - s15Fixed16Number e10; - s15Fixed16Number e11; - s15Fixed16Number e12; - s15Fixed16Number e20; - s15Fixed16Number e21; - s15Fixed16Number e22; - - uint16_t num_input_table_entries; - uint16_t num_output_table_entries; - - float *input_table; - float *clut_table; - float *output_table; - - float table_data[]; -}; - -struct vcgtType { - /* data contains three gamma channels: R[length], then G[length], then - * B[length]. */ - uint16_t *data; - size_t length; -}; - -#if 0 -/* this is from an intial idea of having the struct correspond to the data in - * the file. I decided that it wasn't a good idea. - */ -struct tag_value { - uint32_t type; - union { - struct { - uint32_t reserved; - struct { - s15Fixed16Number X; - s15Fixed16Number Y; - s15Fixed16Number Z; - } XYZNumber; - } XYZType; - }; -}; // I guess we need to pack this? -#endif - -#define RGB_SIGNATURE 0x52474220 -#define GRAY_SIGNATURE 0x47524159 -#define XYZ_SIGNATURE 0x58595A20 -#define LAB_SIGNATURE 0x4C616220 - -struct _qcms_profile { - uint32_t icc_version; - char description[64]; - uint32_t class; - uint32_t color_space; - uint32_t pcs; - qcms_intent rendering_intent; - struct XYZNumber mediaWhitePoint; - struct XYZNumber redColorant; - struct XYZNumber blueColorant; - struct XYZNumber greenColorant; - struct curveType *redTRC; - struct curveType *blueTRC; - struct curveType *greenTRC; - struct curveType *grayTRC; - struct lutType *A2B0; - struct lutType *B2A0; - struct lutmABType *mAB; - struct lutmABType *mBA; - struct matrix chromaticAdaption; - struct vcgtType vcgt; - - struct precache_output *output_table_r; - struct precache_output *output_table_g; - struct precache_output *output_table_b; -}; - -#ifdef _MSC_VER -#define inline _inline -#endif - -/* produces the nearest float to 'a' with a maximum error - * of 1/1024 which happens for large values like 0x40000040 */ -static inline float s15Fixed16Number_to_float(s15Fixed16Number a) -{ - return ((int32_t)a)/65536.f; -} - -static inline s15Fixed16Number double_to_s15Fixed16Number(double v) -{ - return (int32_t)(v*65536); -} - -static inline float uInt8Number_to_float(uInt8Number a) -{ - return ((int32_t)a)/255.f; -} - -static inline float uInt16Number_to_float(uInt16Number a) -{ - return ((int32_t)a)/65535.f; -} - - -void precache_release(struct precache_output *p); -qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries); - -void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format); -void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format); -void qcms_transform_data_tetra_clut_rgba_sse2(qcms_transform* transform, - unsigned char* src, - unsigned char* dest, - size_t length, - qcms_format_type output_format); - -void qcms_transform_build_clut_cache(qcms_transform* transform); - -extern qcms_bool qcms_supports_iccv4; - - -#ifdef _MSC_VER - -long __cdecl _InterlockedIncrement(long volatile *); -long __cdecl _InterlockedDecrement(long volatile *); -#pragma intrinsic(_InterlockedIncrement) -#pragma intrinsic(_InterlockedDecrement) - -#define qcms_atomic_increment(x) _InterlockedIncrement((long volatile *)&x) -#define qcms_atomic_decrement(x) _InterlockedDecrement((long volatile*)&x) - -#else - -#define qcms_atomic_increment(x) __sync_add_and_fetch(&x, 1) -#define qcms_atomic_decrement(x) __sync_sub_and_fetch(&x, 1) - -#endif diff --git a/third_party/qcms/src/qcmstypes.h b/third_party/qcms/src/qcmstypes.h deleted file mode 100644 index d58f691535..0000000000 --- a/third_party/qcms/src/qcmstypes.h +++ /dev/null @@ -1,77 +0,0 @@ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef QCMS_TYPES_H -#define QCMS_TYPES_H - -#if BYTE_ORDER == LITTLE_ENDIAN -#define IS_LITTLE_ENDIAN -#elif BYTE_ORDER == BIG_ENDIAN -#define IS_BIG_ENDIAN -#endif - -/* all of the platforms that we use _MSC_VER on are little endian - * so this is sufficient for now */ -#ifdef _MSC_VER -#define IS_LITTLE_ENDIAN -#endif - -#ifdef __OS2__ -#define IS_LITTLE_ENDIAN -#endif - -#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN) -#error Unknown endianess -#endif - -#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__) -# include <inttypes.h> -#elif defined (_MSC_VER) && _MSC_VER < 1600 -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#ifdef _WIN64 -typedef unsigned __int64 uintptr_t; -#else -#pragma warning(push) -/* Disable benign redefinition of type warning 4142 */ -#pragma warning(disable:4142) -typedef unsigned long uintptr_t; -/* Restore warnings */ -#pragma warning(pop) -#endif - -#elif defined (_AIX) -# include <sys/inttypes.h> -#else -# include <stdint.h> -#endif - -typedef qcms_bool bool; -#define true 1 -#define false 0 - -#endif diff --git a/third_party/qcms/src/tests/Makefile b/third_party/qcms/src/tests/Makefile deleted file mode 100644 index 4adb7e217f..0000000000 --- a/third_party/qcms/src/tests/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -CC=gcc -INCLUDE=-I../ -WALL=-Wall -CFLAGS=-O2 -msse2 $(WALL) -DSSE2_ENABLE -LDFLAGS=-lm - -QCMS=../transform.c ../transform-sse2.c ../transform_util.c ../matrix.c ../iccread.c ../chain.c ../qcms_util.c -OBJS=$(QCMS:.c=.o) - -all: qcms_tests - -qcms_tests: qcms_test_*.c $(OBJS) - $(CC) $(CFLAGS) $(INCLUDE) $^ -o $@ $(LDFLAGS) - -clean: - rm -rf qcms_tests *.o $(OBJS) diff --git a/third_party/qcms/src/tests/qcms_test_internal_srgb.c b/third_party/qcms/src/tests/qcms_test_internal_srgb.c deleted file mode 100644 index dac55f339f..0000000000 --- a/third_party/qcms/src/tests/qcms_test_internal_srgb.c +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcms.h" -#include "qcms_test_util.h" - -#include <assert.h> -#include <math.h> // sqrt -#include <stdio.h> -#include <stdint.h> -#include <stdlib.h> - -#ifndef DISPLAY_DEVICE_PROFILE -#define DISPLAY_DEVICE_PROFILE 0x6d6e7472 // 'mntr' -#endif - -// D50 adapted color primaries of the internal sRGB color profile. -static s15Fixed16Number sRGB_reference[3][3] = { - { 0x06fa0, 0x06296, 0x024a0 }, // ( 0.436035, 0.385101, 0.143066 ) - { 0x038f2, 0x0b789, 0x00f85 }, // ( 0.222443, 0.716934, 0.060623 ) - { 0x0038f, 0x018da, 0x0b6c4 }, // ( 0.013901, 0.097076, 0.713928 ) -}; - -// Reference media white point of the sRGB IEC61966-2.1 color profile. -static struct XYZNumber D65 = { - 0xf351, 0x10000, 0x116cc // ( 0.950455, 1.000000, 1.089050 ) -}; - -static void check_profile_description(qcms_profile *profile) -{ - printf("Test profile description:\n"); - - const char* description = qcms_profile_get_description(profile); - printf("description=[%s]\n\n", description); -} - -static void check_profile_pcs_white_point(const qcms_profile *profile) -{ - float rX = s15Fixed16Number_to_float(profile->redColorant.X); - float gX = s15Fixed16Number_to_float(profile->greenColorant.X); - float bX = s15Fixed16Number_to_float(profile->blueColorant.X); - float rY = s15Fixed16Number_to_float(profile->redColorant.Y); - float gY = s15Fixed16Number_to_float(profile->greenColorant.Y); - float bY = s15Fixed16Number_to_float(profile->blueColorant.Y); - float rZ = s15Fixed16Number_to_float(profile->redColorant.Z); - float gZ = s15Fixed16Number_to_float(profile->greenColorant.Z); - float bZ = s15Fixed16Number_to_float(profile->blueColorant.Z); - - printf("Test PCS white point against expected D50 XYZ values\n"); - - float X = rX + gX + bX; - float Y = rY + gY + bY; - float Z = rZ + gZ + bZ; - - float x = X / (X + Y + Z); - float y = Y / (X + Y + Z); - - printf("Computed profile D50 White point xyY = [%.6f %.6f %.6f]\n", x, y, Y); - - float xerr = x - 0.345702915; // Compute error to ICC spec D50 xyY. - float yerr = y - 0.358538597; - float Yerr = Y - 1.000000000; - - printf("D50 white point error = %.6f\n\n", (float) - sqrt((xerr * xerr) + (yerr * yerr) + (Yerr * Yerr))); -} - -static void check_profile_media_white_point(const qcms_profile *profile) -{ - int errX = profile->mediaWhitePoint.X - D65.X; - int errY = profile->mediaWhitePoint.Y - D65.Y; - int errZ = profile->mediaWhitePoint.Z - D65.Z; - - printf("Test media white point against expected D65 XYZ values\n"); - printf("Internal profile D65 values = [0x%X, 0x%X, 0x%X]\n", - profile->mediaWhitePoint.X, profile->mediaWhitePoint.Y, profile->mediaWhitePoint.Z); - printf("D65 media white point error = [%d, %d, %d]\n\n", errX, errY, errZ); -} - -static s15Fixed16Number check_profile_primaries(const qcms_profile *profile) -{ - s15Fixed16Number sRGB_internal[3][3]; - s15Fixed16Number primary_error; - int i, j; - - printf("Test qcms internal sRGB color 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; - - primary_error = 0; - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - s15Fixed16Number tmp = sRGB_internal[i][j] - sRGB_reference[i][j]; - printf(" %d", tmp); - primary_error += abs(tmp); - } - printf("\n"); - } - - return primary_error; -} - -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) -{ - s15Fixed16Number primary_error; - - qcms_profile *profile = qcms_profile_sRGB(); - - assert(profile->class == DISPLAY_DEVICE_PROFILE); - assert(profile->rendering_intent == QCMS_INTENT_PERCEPTUAL); - assert(profile->color_space == RGB_SIGNATURE); - assert(profile->pcs == XYZ_SIGNATURE); - - if (qcms_profile_is_bogus(profile)) { - fprintf(stderr, "Failure: the internal sRGB profile failed the bogus profile check\n"); - qcms_profile_release(profile); - return -1; - } - - // Compute tristimulus matrix error. - primary_error = check_profile_primaries(profile); - printf("Total primary error = 0x%x [%.6f]\n\n", primary_error, primary_error / 65536.0); - - // Verify media white point correctness. - check_profile_media_white_point(profile); - - // Verify PCS white point correctness. - check_profile_pcs_white_point(profile); - - // Output profile description. - check_profile_description(profile); - - qcms_profile_release(profile); - return primary_error; -} - -struct qcms_test_case qcms_test_internal_srgb_info = { - "qcms_test_internal_srgb", - qcms_test_internal_srgb, - QCMS_TEST_DISABLED -}; diff --git a/third_party/qcms/src/tests/qcms_test_main.c b/third_party/qcms/src/tests/qcms_test_main.c deleted file mode 100644 index 455d17b4ab..0000000000 --- a/third_party/qcms/src/tests/qcms_test_main.c +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcms.h" -#include "qcms_test_util.h" -#include "timing.h" - -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -// Manually update the items below to add more tests. -extern struct qcms_test_case qcms_test_tetra_clut_rgba_info; -extern struct qcms_test_case qcms_test_munsell_info; -extern struct qcms_test_case qcms_test_internal_srgb_info; -extern struct qcms_test_case qcms_test_ntsc_gamut_info; -extern struct qcms_test_case qcms_test_output_trc_info; - -struct qcms_test_case qcms_test[5]; -#define TEST_CASES (sizeof(qcms_test) / sizeof(qcms_test[0])) - -static void initialize_tests() -{ - qcms_test[0] = qcms_test_tetra_clut_rgba_info; - qcms_test[1] = qcms_test_munsell_info; - qcms_test[2] = qcms_test_internal_srgb_info; - qcms_test[3] = qcms_test_ntsc_gamut_info; - qcms_test[4] = qcms_test_output_trc_info; -} - -static void list_tests() -{ - int i; - printf("Available qcms tests:\n"); - - for (i = 0; i < TEST_CASES; ++i) { - printf("\t%s\n", qcms_test[i].test_name); - } - - exit(EXIT_FAILURE); -} - -static void print_usage() -{ - printf("Usage:\n\tqcms_test -w WIDTH -h HEIGHT -n ITERATIONS -t TEST\n"); - printf("\t-w INT\t\ttest image width\n"); - printf("\t-h INT\t\ttest image height\n"); - printf("\t-n INT\t\tnumber of iterations for each test\n"); - printf("\t-a\t\trun all tests\n"); - printf("\t-l\t\tlist available tests\n"); - printf("\t-s \t\tforce software(non-sse) transform function, where available\n"); - printf("\t-i STRING\tspecify input icc color profile\n"); - printf("\t-o STRING\tspecify output icc color profile\n"); - printf("\t-t STRING\trun specific test - use \"-l\" to list possible values\n"); - printf("\n"); - exit(1); -} - -int enable_test(const char *args) -{ - int i; - - if (!args) - return 0; - - for (i = 0; i < TEST_CASES; ++i) { - if (strcmp(qcms_test[i].test_name, args) == 0) { - qcms_test[i].status = QCMS_TEST_ENABLED; - return 1; - } - } - - return 0; -} - -int main(int argc, const char **argv) -{ - int iterations = 1; - size_t height = 2000; - size_t width = 2000; - int run_all = 0; - const char *in = NULL, *out = NULL; - int force_software = 0; - int exit_status; - int enabled_tests = 0; - int i; - - initialize_tests(); - seconds(); - - if (argc == 1) { - print_usage(); - } - - while (argc > 1) { - if (strcmp(argv[1], "-n") == 0) - iterations = abs(atoi(argv[2])); - else if (strcmp(argv[1], "-w") == 0) - width = (size_t) abs(atoi(argv[2])); - else if (strcmp(argv[1], "-h") == 0) - height = (size_t) abs(atoi(argv[2])); - else if (strcmp(argv[1], "-l") == 0) - list_tests(); - else if (strcmp(argv[1], "-t") == 0) - enabled_tests += enable_test(argv[2]); - else if (strcmp(argv[1], "-a") == 0) - run_all = 1; - else if (strcmp(argv[1], "-i") == 0) - in = argv[2]; - else if (strcmp(argv[1], "-o") == 0) - out = argv[2]; - else if (strcmp(argv[1], "-s") == 0) - force_software = 1; - (--argc, ++argv); - } - - if (!run_all && !enabled_tests) { - print_usage(); - } - - exit_status = 0; - - for (i = 0; i < TEST_CASES; ++i) { - if (run_all || QCMS_TEST_ENABLED == qcms_test[i].status) - exit_status += qcms_test[i].test_fn(width, height, iterations, in, out, force_software); - } - - return exit_status; -} diff --git a/third_party/qcms/src/tests/qcms_test_munsell.c b/third_party/qcms/src/tests/qcms_test_munsell.c deleted file mode 100644 index 8df3570eb0..0000000000 --- a/third_party/qcms/src/tests/qcms_test_munsell.c +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcms.h" -#include "qcms_test_util.h" - -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -struct color_checker_chart { - char* name; - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; -}; - -struct color_checker_chart adobe_munsell[24] = { - { "Dark Skin", 106, 81, 67, 255 }, - { "Light Skin", 182, 149, 130, 255 }, - { "Blue Sky", 103, 122, 154, 255 }, - { "Foliage", 95, 108, 69, 255 }, - { "Blue Flower", 129, 128, 174, 255 }, - { "Bluish Green", 133, 189, 170, 255 }, - { "Orange", 194, 121, 48, 255 }, - { "Purplish Blue", 79, 91, 162, 255 }, - { "Moderate Red", 170, 85, 97, 255 }, - { "Purple", 84, 62, 105, 255 }, - { "Yellow Green", 167, 186, 73, 255 }, - { "Orange Yellow", 213, 162, 57, 255 }, - { "Blue", 54, 62, 149, 255 }, - { "Green", 101, 148, 76, 255 }, - { "Red", 152, 48, 58, 255 }, - { "Yellow", 228, 199, 55, 255 }, - { "Magenta", 164, 83, 144, 255 }, - { "Cyan", 63, 134, 163, 255 }, - { "White", 242, 241, 236, 255 }, - { "Neutral 8", 200, 200, 199, 255 }, - { "Neutral 6.5", 159, 160, 159, 255 }, - { "Neutral 5", 122, 121, 120, 255 }, - { "Neutral 3.5", 84, 84, 84, 255 }, - { "Black", 53, 53, 53, 255 }, -}; - -struct color_checker_chart srgb_munsell[24] = { - { "Dark Skin", 115, 80, 64, 255 }, - { "Light Skin", 195, 151, 130, 255 }, - { "Blue Sky", 94, 123, 156, 255 }, - { "Foliage", 88, 108, 65, 255 }, - { "Blue Flower", 130, 129, 177, 255 }, - { "Bluish Green", 100, 190, 171, 255 }, - { "Orange", 217, 122, 37, 255 }, - { "Purplish Blue", 72, 91, 165, 255 }, - { "Moderate Red", 194, 84, 98, 255 }, - { "Purple", 91, 59, 107, 255 }, - { "Yellow Green", 160, 188, 60, 255 }, - { "Orange Yellow", 230, 163, 42, 255 }, - { "Blue", 46, 60, 153, 255 }, - { "Green", 71, 150, 69, 255 }, - { "Red", 177, 44, 56, 255 }, - { "Yellow", 238, 200, 27, 255 }, - { "Magenta", 187, 82, 148, 255 }, - { "Cyan", /* -49 */ 0, 135, 166, 255 }, - { "White", 243, 242, 237, 255 }, - { "Neutral 8",201, 201, 201, 255 }, - { "Neutral 6.5", 161, 161, 161, 255 }, - { "Neutral 5",122, 122, 121, 255 }, - { "Neutral 3.5", 83, 83, 83, 255 }, - { "Black", 50, 49, 50, 255 }, -}; - -extern void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format); - -static qcms_bool invalid_rgb_color_profile(qcms_profile *profile) -{ - return rgbData != qcms_profile_get_color_space(profile) || qcms_profile_is_bogus(profile); -} - -static int color_error(struct color_checker_chart cx, struct color_checker_chart cy) -{ - int dr = cx.r - cy.r; - int dg = cx.g - cy.g; - int db = cx.b - cy.b; - - return round(sqrt((dr * dr) + (dg * dg) + (db * db))); -} - -static qcms_profile* open_profile_from_path(const char *path) -{ - if (strcmp(path, "internal-srgb") != 0) - return qcms_profile_from_path(path); - return qcms_profile_sRGB(); -} - -static int qcms_test_munsell(size_t width, - size_t height, - int iterations, - const char *in_path, - const char *out_path, - const int force_software) -{ - qcms_profile *in_profile = NULL; - qcms_profile *out_profile = NULL; - qcms_format_type format = {0, 2}; // RGBA - qcms_transform *transform; - - struct color_checker_chart *source_munsell = NULL; - struct color_checker_chart *reference_munsell = NULL; - struct color_checker_chart destination_munsell[24]; - - char file_name[256]; - FILE *output; - int dE[24]; - float rmse; - - int i; - - printf("Test qcms data transform accuracy using Munsell colors\n"); - fflush(stdout); - - if (in_path == NULL || out_path == NULL) { - fprintf(stderr, "%s: please provide valid ICC profiles via -i/o options\n", __FUNCTION__); - return EXIT_FAILURE; - } - - in_profile = open_profile_from_path(in_path); - if (!in_profile || invalid_rgb_color_profile(in_profile)) { - fprintf(stderr, "Invalid input profile\n"); - return EXIT_FAILURE; - } - - source_munsell = srgb_munsell; - if (strstr(in_profile->description, "Adobe") != NULL) { - source_munsell = adobe_munsell; - } - - printf("Input profile %s\n", in_profile->description); - - out_profile = open_profile_from_path(out_path); - if (!out_profile || invalid_rgb_color_profile(out_profile)) { - fprintf(stderr, "Invalid output profile\n"); - return EXIT_FAILURE; - } - - reference_munsell = srgb_munsell; - if (strstr(out_profile->description, "Adobe") != NULL) { - reference_munsell = adobe_munsell; - } - - printf("Output profile %s (using qcms precache)\n", out_profile->description); - qcms_profile_precache_output_transform(out_profile); - - transform = qcms_transform_create(in_profile, QCMS_DATA_RGBA_8, out_profile, QCMS_DATA_RGBA_8, QCMS_INTENT_DEFAULT); - if (!transform) { - fprintf(stderr, "Failed to create color transform\n"); - return EXIT_FAILURE; - } else if (force_software) { - transform->transform_fn = qcms_transform_data_rgba_out_lut_precache; - } - - if (qcms_profile_match(in_profile, out_profile)) { - printf("Note: input / output profiles match\n"); - } - - rmse = 0.0f; - - for (i = 0; i < 24; i++) { - transform->transform_fn(transform, &source_munsell[i].r, &destination_munsell[i].r, 1, format); - dE[i] = color_error(reference_munsell[i], destination_munsell[i]); - rmse += dE[i] * dE[i]; - } - - rmse = sqrt(rmse / 24); - printf("RMS color error %.2f\n", rmse); - - // Name and open test result file. - sprintf(file_name, "qcms-test-%ld-munsell-%s-to-%s-rms-%.3f.csv", (long int)time(NULL), in_profile->description, out_profile->description, rmse); - // FIXME: remove spaces from the file name? - output = fopen(file_name, "w"); - - // Print headers. - if (force_software) - fprintf(output, "Report for: qcms_transform_data_rgba_out_lut_precache\n\n"); - else - fprintf(output, "Report for: qcms_transform_data_rgba_out_lut_sse2\n\n"); - - fprintf(output, "%14s,\t%s,\t%s,\t%s\n\n", "Color,", "Actual,,", "Expected,", "dE"); - - // Print results. - for (i = 0; i < 24; i++) { - fprintf(output, "%14s,\t%d,%d,%d,\t%d,%d,%d,\t%d\n", - source_munsell[i].name, - destination_munsell[i].r, destination_munsell[i].g, destination_munsell[i].b, - reference_munsell[i].r, reference_munsell[i].g, reference_munsell[i].b, - dE[i]); - } - - fprintf(output, "\nRMS color error = %.2f\n", rmse); - fclose(output); - - printf("Output written to %s\n", file_name); - return rmse > 0.000001f; -} - -struct qcms_test_case qcms_test_munsell_info = { - "qcms_test_munsell", - qcms_test_munsell, - QCMS_TEST_DISABLED -}; diff --git a/third_party/qcms/src/tests/qcms_test_ntsc_gamut.c b/third_party/qcms/src/tests/qcms_test_ntsc_gamut.c deleted file mode 100644 index 22a702b04b..0000000000 --- a/third_party/qcms/src/tests/qcms_test_ntsc_gamut.c +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcms_test_util.h" - -#include <stdio.h> -#include <stdlib.h> -#include <time.h> - -static qcms_bool invalid_rgb_color_profile(qcms_profile *profile) -{ - return rgbData != qcms_profile_get_color_space(profile) || qcms_profile_is_bogus(profile); -} - -static int qcms_test_ntsc_gamut(size_t width, - size_t height, - int iterations, - const char *input_path, - const char *referece_path, - const int force_software) -{ - qcms_profile *input_profile; - qcms_profile *reference_profile = qcms_profile_sRGB(); - qcms_transform *transform; - float input_gamut_metric, reference_gamut_metric; - - if (!input_path) { - fprintf(stderr, "%s: please provide valid ICC profiles via -i/o options\n", __FUNCTION__); - return EXIT_FAILURE; - } - - input_profile = qcms_profile_from_path(input_path); - if (!input_profile || invalid_rgb_color_profile(input_profile)) { - fprintf(stderr, "Invalid input profile\n"); - return EXIT_FAILURE; - } - - transform = qcms_transform_create(input_profile, QCMS_DATA_RGBA_8, reference_profile, QCMS_DATA_RGBA_8, QCMS_INTENT_DEFAULT); - if (!transform) { - fprintf(stderr, "Could not create transform\n"); - return EXIT_FAILURE; - } - - if (!(transform->transform_flags & TRANSFORM_FLAG_MATRIX)) { - fprintf(stderr, "Transform is not matrix\n"); - qcms_transform_release(transform); - qcms_profile_release(input_profile); - qcms_profile_release(reference_profile); - return EXIT_FAILURE; - } - - printf("NTSC 1953 relative gamut area test\n"); - - input_gamut_metric = qcms_profile_ntsc_relative_gamut_size(input_profile); - printf("Input profile\n\tDescription: %s\n\tNTSC relative gamut area: %.3f %%\n", - input_profile->description, input_gamut_metric); - - reference_gamut_metric = qcms_profile_ntsc_relative_gamut_size(reference_profile); - printf("Internal reference profile\n\tDescription: %s\n\tNTSC relative gamut area: %.3f %%\n", - reference_profile->description, reference_gamut_metric); - - qcms_transform_release(transform); - qcms_profile_release(input_profile); - qcms_profile_release(reference_profile); - - return 0; -} - -struct qcms_test_case qcms_test_ntsc_gamut_info = { - "qcms_test_ntsc_gamut", - qcms_test_ntsc_gamut, - QCMS_TEST_DISABLED -}; diff --git a/third_party/qcms/src/tests/qcms_test_output_trc.c b/third_party/qcms/src/tests/qcms_test_output_trc.c deleted file mode 100644 index 049141b634..0000000000 --- a/third_party/qcms/src/tests/qcms_test_output_trc.c +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcms.h" -#include "qcms_test_util.h" - -#include <assert.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> - -#define PARAMETRIC_CURVE_TYPE 0x70617261 // 'para' - -static const float inverse65535 = (float) (1.0 / 65535.0); - -extern float clamp_float(float a); - -static int get_output_gamma_table(const char *profile_path, uint16_t **table, size_t *size) -{ - qcms_transform *transform; - qcms_profile *sRGB; - qcms_profile *target; - - target = qcms_profile_from_path(profile_path); - if (!target) { - fprintf(stderr, "Invalid input profile\n"); - return EXIT_FAILURE; - } - - sRGB = qcms_profile_sRGB(); - - transform = qcms_transform_create(sRGB, QCMS_DATA_RGBA_8, target, QCMS_DATA_RGBA_8, QCMS_INTENT_DEFAULT); - if (!transform) { - fprintf(stderr, "Failed to create colour transform\n"); - qcms_profile_release(sRGB); - qcms_profile_release(target); - return EXIT_FAILURE; - } - - *size = qcms_transform_get_output_trc_rgba(transform, target, QCMS_TRC_USHORT, NULL); - assert(*size >= 256); - - *table = malloc(*size * sizeof(uint16_t) * 4); - qcms_transform_get_output_trc_rgba(transform, target, QCMS_TRC_USHORT, *table); - - qcms_transform_release(transform); - qcms_profile_release(sRGB); - qcms_profile_release(target); - - return 0; -} - -static int get_input_gamma_table(const char *profile_path, uint16_t **table, size_t *size) -{ - qcms_transform *transform; - qcms_profile *source; - qcms_profile *sRGB; - - source = qcms_profile_from_path(profile_path); - if (!source) { - fprintf(stderr, "Invalid input profile\n"); - return EXIT_FAILURE; - } - - sRGB = qcms_profile_sRGB(); - - transform = qcms_transform_create(source, QCMS_DATA_RGBA_8, sRGB, QCMS_DATA_RGBA_8, QCMS_INTENT_DEFAULT); - if (!transform) { - fprintf(stderr, "Failed to create colour transform\n"); - qcms_profile_release(sRGB); - qcms_profile_release(source); - return EXIT_FAILURE; - } - - *size = qcms_transform_get_input_trc_rgba(transform, source, QCMS_TRC_USHORT, NULL); - assert(*size >= 256); - - *table = calloc(*size, sizeof(uint16_t) * 4); - qcms_transform_get_input_trc_rgba(transform, source, QCMS_TRC_USHORT, *table); - - qcms_transform_release(transform); - qcms_profile_release(sRGB); - qcms_profile_release(source); - - return 0; -} - -static int qcms_test_output_trc(size_t width, - size_t height, - int iterations, - const char *in_path, - const char *out_path, - const int force_software) -{ - uint16_t *gamma_table_out = NULL; - size_t output_size = 0; - qcms_profile *profile; - long time_stamp = (long)time(NULL); - char output_file_name[1024]; - float scale_factor; - size_t i; - - if (!in_path) { - fprintf(stderr, "%s: please provide valid ICC profiles via -i option\n", __FUNCTION__); - return EXIT_FAILURE; - } - - printf("Test color profile gamma curves\n"); - fflush(stdout); - - if (get_output_gamma_table(in_path, &gamma_table_out, &output_size) != 0) { - fprintf(stderr, "Unable to extract output gamma table\n"); - return EXIT_FAILURE; - } - - printf("Output gamma table size = %zu\n", output_size); - - profile = qcms_profile_from_path(in_path); - if (!profile) { - fprintf(stderr, "Invalid input profile\n"); - free(gamma_table_out); - return EXIT_FAILURE; - } - - if (profile->redTRC->type == PARAMETRIC_CURVE_TYPE) { - // Check the red TRC curve only for now. - int type = - (int)(profile->redTRC->count + 1); - uint16_t *gamma_table_in = NULL; - size_t input_size = 0; - FILE *output_file; - - printf("Detected parametric curve type = %d\n", profile->redTRC->count); - - if (get_input_gamma_table(in_path, &gamma_table_in, &input_size) != 0) { - fprintf(stderr, "Failed to compute input gamma table\n"); - qcms_profile_release(profile); - free(gamma_table_out); - return EXIT_FAILURE; - } - - // Write output to stdout and tables into a csv file. - sprintf(output_file_name, "qcms-test-%ld-parametric-gamma-output-%s.csv", - time_stamp, profile->description); - printf("Writing output gamma tables to %s\n", output_file_name); - output_file = fopen(output_file_name, "w"); - - printf("Parametric gamma values for profile %s description [%s]\n", - in_path, profile->description); - fprintf(output_file, "Parametric gamma values for profile %s description [%s]\n", - in_path, profile->description); - - printf("gamma = %.6f, a = %.6f, b = %.6f, c = %.6f, d = %.6f, e = %.6f, f = %.6f\n", - profile->redTRC->parameter[0], profile->redTRC->parameter[1], profile->redTRC->parameter[2], - profile->redTRC->parameter[3], profile->redTRC->parameter[4], profile->redTRC->parameter[5], - profile->redTRC->parameter[6]); - - fprintf(output_file, "gamma, a, b, c, d, e, f\n"); - fprintf(output_file, "%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f\n", - profile->redTRC->parameter[0], profile->redTRC->parameter[1], profile->redTRC->parameter[2], - profile->redTRC->parameter[3], profile->redTRC->parameter[4], profile->redTRC->parameter[5], - profile->redTRC->parameter[6]); - - fprintf(output_file, "\nInput curve size: %zu", input_size); - fprintf(output_file, "\nOutput curve size: %zu", output_size); - - fprintf(output_file, "\n\nInput gamma, Output gamma, LCMS Output gamma, Output gamma error\n"); - // Output gamma curve down-sample factor. - scale_factor = (float)(output_size - 1) / (input_size - 1); - - for (i = 0; i < input_size; ++i) { - float input = gamma_table_in[i * 4] * inverse65535; - size_t out_index = (size_t)floor(i * scale_factor + 0.5); - float output = gamma_table_out[out_index * 4] * inverse65535; - float x = out_index / (float)(output_size - 1); - float reference = clamp_float(evaluate_parametric_curve(type, profile->redTRC->parameter, x)); - float difference = fabs(output - reference); - - fprintf(output_file, "%.6f, %.6f, %6f, %6f\n", input, output, reference, difference); - } - - fprintf(output_file, "\nNote: the output gamma curves are down-sampled by a factor of %zu / %zu\n", - output_size, input_size); - - fclose(output_file); - free(gamma_table_in); - } else { - uint16_t *gamma_table_in = NULL; - size_t input_size = 0; - FILE *output_file; - - if (get_input_gamma_table(in_path, &gamma_table_in, &input_size) != 0) { - fprintf(stderr, "Failed to compute input gamma table\n"); - qcms_profile_release(profile); - free(gamma_table_out); - return EXIT_FAILURE; - } - - // Write output to stdout and tables into a csv file. - sprintf(output_file_name, "qcms-test-%ld-gamma-output-%s.csv", - time_stamp, profile->description); - printf("Writing gamma tables to %s\n", output_file_name); - output_file = fopen(output_file_name, "w"); - - printf("Gamma values for profile %s description [%s]\n", - in_path, profile->description); - fprintf(output_file, "Gamma values for profile %s description [%s]\n", - in_path, profile->description); - - if (profile->redTRC->count == 0) { - printf("Gamma LUT type 0: linear gamma\n"); - fprintf(output_file, "Gamma LUT type 0: linear gamma\n"); - } else if (profile->redTRC->count == 1) { - float gamma = profile->redTRC->data[0] / 256.0f; - printf("Gamma LUT type 1: gamma = %.6f\n", gamma); - fprintf(output_file, "Gamma LUT type 1: gamma = %.6f\n", gamma); - } else { - printf("Gamma LUT table size = %u\n", profile->redTRC->count); - fprintf(output_file, "Gamma LUT table size = %u\n", profile->redTRC->count); - } - - fprintf(output_file, "\nInput curve size: %zu", input_size); - fprintf(output_file, "\nOutput curve size: %zu", output_size); - - fprintf(output_file, "\n\nInput gamma, Output gamma\n"); - // Output gamma curve down-sample factor. - scale_factor = (float)(output_size - 1) / (input_size - 1); - - for (i = 0; i < input_size; ++i) { - float input = gamma_table_in[i * 4] * inverse65535; - size_t out_index = (size_t)floor(i * scale_factor + 0.5); - float output = gamma_table_out[out_index * 4] * inverse65535; - - fprintf(output_file, "%.6f, %.6f\n", input, output); - } - - fprintf(output_file, "\nNote: the output gamma curves are down-sampled by a factor of %zu / %zu\n", - output_size, input_size); - - fclose(output_file); - free(gamma_table_in); - } - - qcms_profile_release(profile); - free(gamma_table_out); - - return 0; -} - -struct qcms_test_case qcms_test_output_trc_info = { - "qcms_test_output_trc", - qcms_test_output_trc, - QCMS_TEST_DISABLED -}; diff --git a/third_party/qcms/src/tests/qcms_test_tetra_clut_rgba.c b/third_party/qcms/src/tests/qcms_test_tetra_clut_rgba.c deleted file mode 100644 index 81b6ee3287..0000000000 --- a/third_party/qcms/src/tests/qcms_test_tetra_clut_rgba.c +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcms.h" -#include "qcms_test_util.h" -#include "timing.h" - -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -// External qcms tetra clut interpolators. - -extern void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format); - -#ifdef SSE2_ENABLE -extern void qcms_transform_data_tetra_clut_rgba_sse2(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format); -#else -void qcms_transform_data_tetra_clut_rgba_dummy(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format) -{ - (void)(transform); - (void)(src); - (void)(dest); - (void)(length); - (void)(output_format); -} -#endif - -static float *create_lut(size_t lutSize) -{ - float *lut = malloc(lutSize * sizeof(float)); - size_t i; - - for (i = 0; i < lutSize; ++i) { - lut[i] = (rand() & 255) * (1.0f / 255.0f); - } - - return lut; -} - -static int diffs; - -static int validate(unsigned char *dst0, unsigned char *dst1, size_t length, int limit, const size_t pixel_size) -{ - size_t bytes = length * pixel_size; - size_t i; - - // Compare dst0/dst0 byte-by-byte, allowing for minor differences due - // to SSE rounding modes (controlled by the limit argument). - - if (limit < 0) - limit = 255; // Ignore all differences. - - for (diffs = 0, i = 0; i < bytes; ++i) { - if (abs((int)dst0[i] - (int)dst1[i]) > limit) { - ++diffs; - } - } - - return !diffs; -} - -static int qcms_test_tetra_clut_rgba(size_t width, - size_t height, - int iterations, - const char *in_profile, - const char *out_profile, - const int force_software) -{ - qcms_transform transform0, transform1; - qcms_format_type format = {2, 0}; - uint16_t samples = 33; - size_t lutSize; - float *lut0, *lut1; - - const size_t length = width * height; - const size_t pixel_size = 4; - - double time0, time1; - int i; - - printf("Test qcms clut transforms for %d iterations\n", iterations); - printf("Test image size %u x %u pixels\n", (unsigned) width, (unsigned) height); - fflush(stdout); - - srand(0); - seconds(); - - memset(&transform0, 0, sizeof(transform0)); - memset(&transform1, 0, sizeof(transform1)); - - transform0.grid_size = samples; - transform1.grid_size = samples; - - transform0.transform_flags = 0; - transform1.transform_flags = 0; - - lutSize = 3 * samples * samples * samples; - lut0 = create_lut(lutSize); - lut1 = (float *)malloc(lutSize * sizeof(float)); - memcpy(lut1, lut0, lutSize * sizeof(float)); - - transform0.r_clut = &lut0[0]; - transform0.g_clut = &lut0[1]; - transform0.b_clut = &lut0[2]; - - transform1.r_clut = &lut1[0]; - transform1.g_clut = &lut1[1]; - transform1.b_clut = &lut1[2]; - - // Re-generate and use different data sources during the iteration loop - // to avoid compiler / cache optimizations that may affect performance. - - time0 = 0.0; - time1 = 0.0; - - for (i = 0; i < iterations; ++i) { - unsigned char *src0 = (unsigned char *)calloc(length, pixel_size); - unsigned char *src1 = (unsigned char *)calloc(length, pixel_size); - unsigned char *dst0 = (unsigned char *)calloc(length, pixel_size); - unsigned char *dst1 = (unsigned char *)calloc(length, pixel_size); - - generate_source_uint8_t(src0, length, pixel_size); - memcpy(src1, src0, length * pixel_size); - -#define TRANSFORM_TEST0 qcms_transform_data_tetra_clut_rgba -#ifdef SSE2_ENABLE -#define TRANSFORM_TEST1 qcms_transform_data_tetra_clut_rgba_sse2 -#else -#define TRANSFORM_TEST1 qcms_transform_data_tetra_clut_rgba_dummy -#endif - - TIME(TRANSFORM_TEST0(&transform0, src0, dst0, length, format), &time0); - TIME(TRANSFORM_TEST1(&transform1, src1, dst1, length, format), &time1); - - if (!validate(dst0, dst1, length, 0, pixel_size)) { - fprintf(stderr, "Invalid transform output: %d diffs\n", diffs); - } - - free(src0); - free(src1); - free(dst0); - free(dst1); - } - -#define STRINGIZE(s) #s -#define STRING(s) STRINGIZE(s) - - printf("%.6lf (avg %.6lf) seconds " STRING(TRANSFORM_TEST0) "\n", - time0, time0 / iterations); - printf("%.6lf (avg %.6lf) seconds " STRING(TRANSFORM_TEST1) "\n", - time1, time1 / iterations); - printf("%.6lf speedup after %d iterations\n\n", - time0 / time1, iterations); - - free(lut0); - free(lut1); - - return diffs; -} - -struct qcms_test_case qcms_test_tetra_clut_rgba_info = { - "qcms_test_tetra_clut_rgba", - qcms_test_tetra_clut_rgba, - QCMS_TEST_DISABLED -}; diff --git a/third_party/qcms/src/tests/qcms_test_util.c b/third_party/qcms/src/tests/qcms_test_util.c deleted file mode 100644 index e0ecff3af4..0000000000 --- a/third_party/qcms/src/tests/qcms_test_util.c +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcms_test_util.h" - -#include <math.h> -#include <stdlib.h> - -#define MAX_FLOAT_ERROR 0.000001f - -// Store random pixel data in the source. -void generate_source_uint8_t(unsigned char *src, const size_t length, const size_t pixel_size) -{ - size_t bytes = length * pixel_size; - size_t i; - - for (i = 0; i < bytes; ++i) { - *src++ = rand() & 255; - } -} - -// Parametric Fn using floating point <from lcms/src/cmsgamma.c>: DefaultEvalParametricFn -float evaluate_parametric_curve(int type, const float params[], float r) -{ - float e, val, disc; - - switch (type) { - - // X = Y ^ Gamma - case 1: - if (r < 0) { - - if (fabs(params[0] - 1.0) < MAX_FLOAT_ERROR) - val = r; - else - val = 0; - } - else - val = pow(r, params[0]); - break; - - // Type 1 Reversed: X = Y ^1/gamma - case -1: - if (r < 0) { - - if (fabs(params[0] - 1.0) < MAX_FLOAT_ERROR) - val = r; - else - val = 0; - } - else - val = pow(r, 1/params[0]); - break; - - // CIE 122-1966 - // Y = (aX + b)^Gamma | X >= -b/a - // Y = 0 | else - case 2: - disc = -params[2] / params[1]; - - if (r >= disc ) { - - e = params[1]*r + params[2]; - - if (e > 0) - val = pow(e, params[0]); - else - val = 0; - } - else - val = 0; - break; - - // Type 2 Reversed - // X = (Y ^1/g - b) / a - case -2: - if (r < 0) - val = 0; - else - val = (pow(r, 1.0/params[0]) - params[2]) / params[1]; - - if (val < 0) - val = 0; - break; - - - // IEC 61966-3 - // Y = (aX + b)^Gamma | X <= -b/a - // Y = c | else - case 3: - disc = -params[2] / params[1]; - if (disc < 0) - disc = 0; - - if (r >= disc) { - - e = params[1]*r + params[2]; - - if (e > 0) - val = pow(e, params[0]) + params[3]; - else - val = 0; - } - else - val = params[3]; - break; - - - // Type 3 reversed - // X=((Y-c)^1/g - b)/a | (Y>=c) - // X=-b/a | (Y<c) - case -3: - if (r >= params[3]) { - - e = r - params[3]; - - if (e > 0) - val = (pow(e, 1/params[0]) - params[2]) / params[1]; - else - val = 0; - } - else { - val = -params[2] / params[1]; - } - break; - - - // IEC 61966-2.1 (sRGB) - // Y = (aX + b)^Gamma | X >= d - // Y = cX | X < d - case 4: - if (r >= params[4]) { - - e = params[1]*r + params[2]; - - if (e > 0) - val = pow(e, params[0]); - else - val = 0; - } - else - val = r * params[3]; - break; - - // Type 4 reversed - // X=((Y^1/g-b)/a) | Y >= (ad+b)^g - // X=Y/c | Y< (ad+b)^g - case -4: - e = params[1] * params[4] + params[2]; - if (e < 0) - disc = 0; - else - disc = pow(e, params[0]); - - if (r >= disc) { - - val = (pow(r, 1.0/params[0]) - params[2]) / params[1]; - } - else { - val = r / params[3]; - } - break; - - - // Y = (aX + b)^Gamma + e | X >= d - // Y = cX + f | X < d - case 5: - if (r >= params[4]) { - - e = params[1]*r + params[2]; - - if (e > 0) - val = pow(e, params[0]) + params[5]; - else - val = params[5]; - } - else - val = r*params[3] + params[6]; - break; - - - // Reversed type 5 - // X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e), cd+f - // X=(Y-f)/c | else - case -5: - - disc = params[3] * params[4] + params[6]; - if (r >= disc) { - - e = r - params[5]; - if (e < 0) - val = 0; - else - val = (pow(e, 1.0/params[0]) - params[2]) / params[1]; - } - else { - val = (r - params[6]) / params[3]; - } - break; - - - // Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf - // Type 6 is basically identical to type 5 without d - - // Y = (a * X + b) ^ Gamma + c - case 6: - e = params[1]*r + params[2]; - - if (e < 0) - val = params[3]; - else - val = pow(e, params[0]) + params[3]; - break; - - // ((Y - c) ^1/Gamma - b) / a - case -6: - e = r - params[3]; - if (e < 0) - val = 0; - else - val = (pow(e, 1.0/params[0]) - params[2]) / params[1]; - break; - - - // Y = a * log (b * X^Gamma + c) + d - case 7: - - e = params[2] * pow(r, params[0]) + params[3]; - if (e <= 0) - val = params[4]; - else - val = params[1]*log10(e) + params[4]; - break; - - // (Y - d) / a = log(b * X ^Gamma + c) - // pow(10, (Y-d) / a) = b * X ^Gamma + c - // pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X - case -7: - val = pow((pow(10.0, (r-params[4]) / params[1]) - params[3]) / params[2], 1.0 / params[0]); - break; - - - //Y = a * b^(c*X+d) + e - case 8: - val = (params[0] * pow(params[1], params[2] * r + params[3]) + params[4]); - break; - - - // Y = (log((y-e) / a) / log(b) - d ) / c - // a=0, b=1, c=2, d=3, e=4, - case -8: - - disc = r - params[4]; - if (disc < 0) val = 0; - else - val = (log(disc / params[0]) / log(params[1]) - params[3]) / params[2]; - break; - - // S-Shaped: (1 - (1-x)^1/g)^1/g - case 108: - val = pow(1.0 - pow(1 - r, 1/params[0]), 1/params[0]); - break; - - // y = (1 - (1-x)^1/g)^1/g - // y^g = (1 - (1-x)^1/g) - // 1 - y^g = (1-x)^1/g - // (1 - y^g)^g = 1 - x - // 1 - (1 - y^g)^g - case -108: - val = 1 - pow(1 - pow(r, params[0]), params[0]); - break; - - default: - // Unsupported parametric curve. Should never reach here - return 0; - } - - return val; -} diff --git a/third_party/qcms/src/tests/qcms_test_util.h b/third_party/qcms/src/tests/qcms_test_util.h deleted file mode 100644 index d8286e6028..0000000000 --- a/third_party/qcms/src/tests/qcms_test_util.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#include "qcmsint.h" -#include "qcmstypes.h" - -typedef int (*qcms_test_function)(size_t width, - size_t height, - int iterations, - const char *in_profile, - const char *out_profile, - const int force_software); - -enum QCMS_TEST_STATUS { - QCMS_TEST_DISABLED = 0, - QCMS_TEST_ENABLED = 1, -}; - -struct qcms_test_case { - char test_name[256]; - qcms_test_function test_fn; - enum QCMS_TEST_STATUS status; -}; - -void generate_source_uint8_t(unsigned char *src, const size_t length, const size_t pixel_size); -float evaluate_parametric_curve(int type, const float params[], float r); diff --git a/third_party/qcms/src/tests/timing.h b/third_party/qcms/src/tests/timing.h deleted file mode 100644 index 83f1bbdf0c..0000000000 --- a/third_party/qcms/src/tests/timing.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the Chromium LICENSE file. - -#ifndef TESTS_TIMING_H -#define TESTS_TIMING_H - -#include <assert.h> -#if defined(_WIN32) -#include <windows.h> -#else -#include <sys/time.h> -#endif -#include <time.h> - -#if defined(_WIN32) - -static double seconds() -{ - static double clock_frequency; - static bool have_frequency; - - LARGE_INTEGER qpc; - QueryPerformanceCounter(&qpc); - if (have_frequency) - return qpc.QuadPart * clock_frequency; - - have_frequency = true; - QueryPerformanceFrequency(&qpc); - clock_frequency = 1.0 / (double) qpc.QuadPart; - return seconds(); -} - -#else - -static double seconds() -{ - struct timeval now; - gettimeofday(&now, 0); - return now.tv_sec + now.tv_usec * (1.0 / 1000000.0); -} - -#endif - -#define TIME(function, time) do { \ - double start = seconds(); \ - (function); \ - *time += seconds() - start; \ -} while (0) - -#endif // TESTS_TIMING_H diff --git a/third_party/qcms/src/transform-sse2.c b/third_party/qcms/src/transform-sse2.c deleted file mode 100644 index c06db69cd3..0000000000 --- a/third_party/qcms/src/transform-sse2.c +++ /dev/null @@ -1,458 +0,0 @@ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// Copyright (C) 2015 Intel Corporation -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include <emmintrin.h> - -#include "qcmsint.h" - -/* pre-shuffled: just load these into XMM reg instead of load-scalar/shufps sequence */ -#define FLOATSCALE (float)(PRECACHE_OUTPUT_SIZE - 1) -#define CLAMPMAXVAL 1.0f - -static const ALIGN float floatScaleX4[4] = - { FLOATSCALE, FLOATSCALE, FLOATSCALE, FLOATSCALE}; -static const ALIGN float clampMaxValueX4[4] = - { CLAMPMAXVAL, CLAMPMAXVAL, CLAMPMAXVAL, CLAMPMAXVAL}; - -void qcms_transform_data_rgb_out_lut_sse2(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format) -{ - unsigned int i; - float (*mat)[4] = transform->matrix; - char input_back[32]; - /* Ensure we have a buffer that's 16 byte aligned regardless of the original - * stack alignment. We can't use __attribute__((aligned(16))) or __declspec(align(32)) - * because they don't work on stack variables. gcc 4.4 does do the right thing - * on x86 but that's too new for us right now. For more info: gcc bug #16660 */ - float const * input = (float*)(((uintptr_t)&input_back[16]) & ~0xf); - /* share input and output locations to save having to keep the - * locations in separate registers */ - uint32_t const * output = (uint32_t*)input; - - /* deref *transform now to avoid it in loop */ - const float *igtbl_r = transform->input_gamma_table_r; - const float *igtbl_g = transform->input_gamma_table_g; - const float *igtbl_b = transform->input_gamma_table_b; - - /* deref *transform now to avoid it in loop */ - const uint8_t *otdata_r = &transform->output_table_r->data[0]; - const uint8_t *otdata_g = &transform->output_table_g->data[0]; - const uint8_t *otdata_b = &transform->output_table_b->data[0]; - - /* input matrix values never change */ - const __m128 mat0 = _mm_load_ps(mat[0]); - const __m128 mat1 = _mm_load_ps(mat[1]); - const __m128 mat2 = _mm_load_ps(mat[2]); - - /* these values don't change, either */ - const __m128 max = _mm_load_ps(clampMaxValueX4); - const __m128 min = _mm_setzero_ps(); - const __m128 scale = _mm_load_ps(floatScaleX4); - - /* working variables */ - __m128 vec_r, vec_g, vec_b, result; - const int r_out = output_format.r; - const int b_out = output_format.b; - - /* CYA */ - if (!length) - return; - - /* one pixel is handled outside of the loop */ - length--; - - /* setup for transforming 1st pixel */ - vec_r = _mm_load_ss(&igtbl_r[src[0]]); - vec_g = _mm_load_ss(&igtbl_g[src[1]]); - vec_b = _mm_load_ss(&igtbl_b[src[2]]); - src += 3; - - /* transform all but final pixel */ - - for (i=0; i<length; i++) - { - /* position values from gamma tables */ - vec_r = _mm_shuffle_ps(vec_r, vec_r, 0); - vec_g = _mm_shuffle_ps(vec_g, vec_g, 0); - vec_b = _mm_shuffle_ps(vec_b, vec_b, 0); - - /* gamma * matrix */ - vec_r = _mm_mul_ps(vec_r, mat0); - vec_g = _mm_mul_ps(vec_g, mat1); - vec_b = _mm_mul_ps(vec_b, mat2); - - /* crunch, crunch, crunch */ - vec_r = _mm_add_ps(vec_g, _mm_add_ps(vec_r, vec_b)); - vec_r = _mm_max_ps(min, vec_r); - vec_r = _mm_min_ps(max, vec_r); - result = _mm_mul_ps(vec_r, scale); - - /* store calc'd output tables indices */ - _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result)); - - /* load for next loop while store completes */ - vec_r = _mm_load_ss(&igtbl_r[src[0]]); - vec_g = _mm_load_ss(&igtbl_g[src[1]]); - vec_b = _mm_load_ss(&igtbl_b[src[2]]); - src += 3; - - /* use calc'd indices to output RGB values */ - dest[r_out] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[b_out] = otdata_b[output[2]]; - dest += 3; - } - - /* handle final (maybe only) pixel */ - - vec_r = _mm_shuffle_ps(vec_r, vec_r, 0); - vec_g = _mm_shuffle_ps(vec_g, vec_g, 0); - vec_b = _mm_shuffle_ps(vec_b, vec_b, 0); - - vec_r = _mm_mul_ps(vec_r, mat0); - vec_g = _mm_mul_ps(vec_g, mat1); - vec_b = _mm_mul_ps(vec_b, mat2); - - vec_r = _mm_add_ps(vec_g, _mm_add_ps(vec_r, vec_b)); - vec_r = _mm_max_ps(min, vec_r); - vec_r = _mm_min_ps(max, vec_r); - result = _mm_mul_ps(vec_r, scale); - - _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result)); - - dest[r_out] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[b_out] = otdata_b[output[2]]; -} - -void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format) -{ - unsigned int i; - float (*mat)[4] = transform->matrix; - char input_back[32]; - /* Ensure we have a buffer that's 16 byte aligned regardless of the original - * stack alignment. We can't use __attribute__((aligned(16))) or __declspec(align(32)) - * because they don't work on stack variables. gcc 4.4 does do the right thing - * on x86 but that's too new for us right now. For more info: gcc bug #16660 */ - float const * input = (float*)(((uintptr_t)&input_back[16]) & ~0xf); - /* share input and output locations to save having to keep the - * locations in separate registers */ - uint32_t const * output = (uint32_t*)input; - - /* deref *transform now to avoid it in loop */ - const float *igtbl_r = transform->input_gamma_table_r; - const float *igtbl_g = transform->input_gamma_table_g; - const float *igtbl_b = transform->input_gamma_table_b; - - /* deref *transform now to avoid it in loop */ - const uint8_t *otdata_r = &transform->output_table_r->data[0]; - const uint8_t *otdata_g = &transform->output_table_g->data[0]; - const uint8_t *otdata_b = &transform->output_table_b->data[0]; - - /* input matrix values never change */ - const __m128 mat0 = _mm_load_ps(mat[0]); - const __m128 mat1 = _mm_load_ps(mat[1]); - const __m128 mat2 = _mm_load_ps(mat[2]); - - /* these values don't change, either */ - const __m128 max = _mm_load_ps(clampMaxValueX4); - const __m128 min = _mm_setzero_ps(); - const __m128 scale = _mm_load_ps(floatScaleX4); - - /* working variables */ - __m128 vec_r, vec_g, vec_b, result; - const int r_out = output_format.r; - const int b_out = output_format.b; - unsigned char alpha; - - /* CYA */ - if (!length) - return; - - /* one pixel is handled outside of the loop */ - length--; - - /* setup for transforming 1st pixel */ - vec_r = _mm_load_ss(&igtbl_r[src[0]]); - vec_g = _mm_load_ss(&igtbl_g[src[1]]); - vec_b = _mm_load_ss(&igtbl_b[src[2]]); - alpha = src[3]; - src += 4; - - /* transform all but final pixel */ - - for (i=0; i<length; i++) - { - /* position values from gamma tables */ - vec_r = _mm_shuffle_ps(vec_r, vec_r, 0); - vec_g = _mm_shuffle_ps(vec_g, vec_g, 0); - vec_b = _mm_shuffle_ps(vec_b, vec_b, 0); - - /* gamma * matrix */ - vec_r = _mm_mul_ps(vec_r, mat0); - vec_g = _mm_mul_ps(vec_g, mat1); - vec_b = _mm_mul_ps(vec_b, mat2); - - /* store alpha for this pixel; load alpha for next */ - dest[3] = alpha; - alpha = src[3]; - - /* crunch, crunch, crunch */ - vec_r = _mm_add_ps(vec_g, _mm_add_ps(vec_r, vec_b)); - vec_r = _mm_max_ps(min, vec_r); - vec_r = _mm_min_ps(max, vec_r); - result = _mm_mul_ps(vec_r, scale); - - /* store calc'd output tables indices */ - _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result)); - - /* load gamma values for next loop while store completes */ - vec_r = _mm_load_ss(&igtbl_r[src[0]]); - vec_g = _mm_load_ss(&igtbl_g[src[1]]); - vec_b = _mm_load_ss(&igtbl_b[src[2]]); - src += 4; - - /* use calc'd indices to output RGB values */ - dest[r_out] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[b_out] = otdata_b[output[2]]; - dest += 4; - } - - /* handle final (maybe only) pixel */ - - vec_r = _mm_shuffle_ps(vec_r, vec_r, 0); - vec_g = _mm_shuffle_ps(vec_g, vec_g, 0); - vec_b = _mm_shuffle_ps(vec_b, vec_b, 0); - - vec_r = _mm_mul_ps(vec_r, mat0); - vec_g = _mm_mul_ps(vec_g, mat1); - vec_b = _mm_mul_ps(vec_b, mat2); - - dest[3] = alpha; - - vec_r = _mm_add_ps(vec_g, _mm_add_ps(vec_r, vec_b)); - vec_r = _mm_max_ps(min, vec_r); - vec_r = _mm_min_ps(max, vec_r); - result = _mm_mul_ps(vec_r, scale); - - _mm_store_si128((__m128i*)output, _mm_cvtps_epi32(result)); - - dest[r_out] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[b_out] = otdata_b[output[2]]; -} - -static inline __m128i __mm_swizzle_epi32(__m128i value, int bgra) -{ - return bgra ? _mm_shuffle_epi32(value, _MM_SHUFFLE(0, 1, 2, 3)) : - _mm_shuffle_epi32(value, _MM_SHUFFLE(0, 3, 2, 1)) ; -} - -void qcms_transform_data_tetra_clut_rgba_sse2(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length, - qcms_format_type output_format) -{ - const int bgra = output_format.r; - - size_t i; - - const int xy_len_3 = 3 * 1; - const int x_len_3 = 3 * transform->grid_size; - const int len_3 = x_len_3 * transform->grid_size; - - const __m128 __255 = _mm_set1_ps(255.0f); - const __m128 __one = _mm_set1_ps(1.0f); - const __m128 __000 = _mm_setzero_ps(); - - const float* r_table = transform->r_clut; - const float* g_table = transform->g_clut; - const float* b_table = transform->b_clut; - - int i3, i2, i1, i0; - - __m128 c3; - __m128 c2; - __m128 c1; - __m128 c0; - - if (!(transform->transform_flags & TRANSFORM_FLAG_CLUT_CACHE)) - qcms_transform_build_clut_cache(transform); - - for (i = 0; i < length; ++i) { - unsigned char in_r = *src++; - unsigned char in_g = *src++; - unsigned char in_b = *src++; - - // initialize the output result with the alpha channel only - - __m128i result = _mm_setr_epi32(*src++, 0, 0, 0); - - // get the input point r.xyz relative to the subcube origin - - float rx = transform->r_cache[in_r]; - float ry = transform->r_cache[in_g]; - float rz = transform->r_cache[in_b]; - - // load and LUT scale the subcube maximum vertex - - int xn = transform->ceil_cache[in_r] * len_3; - int yn = transform->ceil_cache[in_g] * x_len_3; - int zn = transform->ceil_cache[in_b] * xy_len_3; - - // load and LUT scale the subcube origin vertex - - int x0 = transform->floor_cache[in_r] * len_3; - int y0 = transform->floor_cache[in_g] * x_len_3; - int z0 = transform->floor_cache[in_b] * xy_len_3; - - // tetrahedral interpolate the input color r.xyz - -#define TETRA_LOOKUP_CLUT(i3, i2, i1, i0) \ - c0 = _mm_set_ps(b_table[i0], g_table[i0], r_table[i0], 0.f), \ - c1 = _mm_set_ps(b_table[i1], g_table[i1], r_table[i1], 0.f), \ - c2 = _mm_set_ps(b_table[i2], g_table[i2], r_table[i2], 0.f), \ - c3 = _mm_set_ps(b_table[i3], g_table[i3], r_table[i3], 0.f) - - i0 = x0 + y0 + z0; - - if (rx >= ry) { - - if (ry >= rz) { // rx >= ry && ry >= rz - - i3 = yn + (i1 = xn); - i1 += i0 - x0; - i2 = i3 + z0; - i3 += zn; - - TETRA_LOOKUP_CLUT(i3, i2, i1, i0); - - c3 = _mm_sub_ps(c3, c2); - c2 = _mm_sub_ps(c2, c1); - c1 = _mm_sub_ps(c1, c0); - - } else if (rx >= rz) { // rx >= rz && rz >= ry - - i3 = zn + (i1 = xn); - i1 += i0 - x0; - i2 = i3 + yn; - i3 += y0; - - TETRA_LOOKUP_CLUT(i3, i2, i1, i0); - - c2 = _mm_sub_ps(c2, c3); - c3 = _mm_sub_ps(c3, c1); - c1 = _mm_sub_ps(c1, c0); - - } else { // rz > rx && rx >= ry - - i2 = xn + (i3 = zn); - i3 += i0 - z0; - i1 = i2 + y0; - i2 += yn; - - TETRA_LOOKUP_CLUT(i3, i2, i1, i0); - - c2 = _mm_sub_ps(c2, c1); - c1 = _mm_sub_ps(c1, c3); - c3 = _mm_sub_ps(c3, c0); - } - } else { - - if (rx >= rz) { // ry > rx && rx >= rz - - i3 = xn + (i2 = yn); - i2 += i0 - y0; - i1 = i3 + z0; - i3 += zn; - - TETRA_LOOKUP_CLUT(i3, i2, i1, i0); - - c3 = _mm_sub_ps(c3, c1); - c1 = _mm_sub_ps(c1, c2); - c2 = _mm_sub_ps(c2, c0); - - } else if (ry >= rz) { // ry >= rz && rz > rx - - i3 = zn + (i2 = yn); - i2 += i0 - y0; - i1 = i3 + xn; - i3 += x0; - - TETRA_LOOKUP_CLUT(i3, i2, i1, i0); - - c1 = _mm_sub_ps(c1, c3); - c3 = _mm_sub_ps(c3, c2); - c2 = _mm_sub_ps(c2, c0); - - } else { // rz > ry && ry > rx - - i2 = yn + (i3 = zn); - i3 += i0 - z0; - i1 = i2 + xn; - i2 += x0; - - TETRA_LOOKUP_CLUT(i3, i2, i1, i0); - - c1 = _mm_sub_ps(c1, c2); - c2 = _mm_sub_ps(c2, c3); - c3 = _mm_sub_ps(c3, c0); - } - } - - // output.xyz = column_matrix(c1, c2, c3) x r.xyz + c0.xyz - - c0 = _mm_add_ps(c0, _mm_mul_ps(c1, _mm_set1_ps(rx))); - c0 = _mm_add_ps(c0, _mm_mul_ps(c2, _mm_set1_ps(ry))); - c0 = _mm_add_ps(c0, _mm_mul_ps(c3, _mm_set1_ps(rz))); - - // clamp to [0.0..1.0], then scale by 255 - - c0 = _mm_max_ps(c0, __000); - c0 = _mm_min_ps(c0, __one); - c0 = _mm_mul_ps(c0, __255); - - // int(c0) with float rounding, add alpha - - result = _mm_add_epi32(result, _mm_cvtps_epi32(c0)); - - // swizzle and repack in result low bytes - - result = __mm_swizzle_epi32(result, bgra); - result = _mm_packus_epi16(result, result); - result = _mm_packus_epi16(result, result); - - // store into uint32_t* pixel destination - - *(uint32_t *)dest = _mm_cvtsi128_si32(result); - dest += 4; - } -} diff --git a/third_party/qcms/src/transform.c b/third_party/qcms/src/transform.c deleted file mode 100644 index dd4eee46ec..0000000000 --- a/third_party/qcms/src/transform.c +++ /dev/null @@ -1,1641 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Corporation -// Copyright (C) 1998-2007 Marti Maria -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include <stdlib.h> -#include <math.h> -#include <assert.h> -#include <string.h> //memcpy -#include "qcmsint.h" -#include "chain.h" -#include "halffloat.h" -#include "matrix.h" -#include "transform_util.h" - -/* for MSVC, GCC, Intel, and Sun compilers */ -#if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_M_AMD64) || defined(__x86_64__) || defined(__x86_64) -#define X86 -#endif /* _M_IX86 || __i386__ || __i386 || _M_AMD64 || __x86_64__ || __x86_64 */ - -// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ -// This is just an approximation, I am not handling all the non-linear -// aspects of the RGB to XYZ process, and assumming that the gamma correction -// has transitive property in the tranformation chain. -// -// the alghoritm: -// -// - First I build the absolute conversion matrix using -// primaries in XYZ. This matrix is next inverted -// - Then I eval the source white point across this matrix -// obtaining the coeficients of the transformation -// - Then, I apply these coeficients to the original matrix -static struct matrix build_RGB_to_XYZ_transfer_matrix(qcms_CIE_xyY white, qcms_CIE_xyYTRIPLE primrs) -{ - struct matrix primaries; - struct matrix primaries_invert; - struct matrix result; - struct vector white_point; - struct vector coefs; - - double xn, yn; - double xr, yr; - double xg, yg; - double xb, yb; - - xn = white.x; - yn = white.y; - - if (yn == 0.0) - return matrix_invalid(); - - xr = primrs.red.x; - yr = primrs.red.y; - xg = primrs.green.x; - yg = primrs.green.y; - xb = primrs.blue.x; - yb = primrs.blue.y; - - primaries.m[0][0] = xr; - primaries.m[0][1] = xg; - primaries.m[0][2] = xb; - - primaries.m[1][0] = yr; - primaries.m[1][1] = yg; - primaries.m[1][2] = yb; - - primaries.m[2][0] = 1 - xr - yr; - primaries.m[2][1] = 1 - xg - yg; - primaries.m[2][2] = 1 - xb - yb; - primaries.invalid = false; - - white_point.v[0] = xn/yn; - white_point.v[1] = 1.; - white_point.v[2] = (1.0-xn-yn)/yn; - - primaries_invert = matrix_invert(primaries); - - coefs = matrix_eval(primaries_invert, white_point); - - result.m[0][0] = coefs.v[0]*xr; - result.m[0][1] = coefs.v[1]*xg; - result.m[0][2] = coefs.v[2]*xb; - - result.m[1][0] = coefs.v[0]*yr; - result.m[1][1] = coefs.v[1]*yg; - result.m[1][2] = coefs.v[2]*yb; - - result.m[2][0] = coefs.v[0]*(1.-xr-yr); - result.m[2][1] = coefs.v[1]*(1.-xg-yg); - result.m[2][2] = coefs.v[2]*(1.-xb-yb); - result.invalid = primaries_invert.invalid; - - return result; -} - -struct CIE_XYZ { - double X; - double Y; - double Z; -}; - -/* CIE Illuminant D50 */ -static const struct CIE_XYZ D50_XYZ = { - 0.9642, - 1.0000, - 0.8249 -}; - -/* from lcms: xyY2XYZ() - * corresponds to argyll: icmYxy2XYZ() */ -static struct CIE_XYZ xyY2XYZ(qcms_CIE_xyY source) -{ - struct CIE_XYZ dest; - dest.X = (source.x / source.y) * source.Y; - dest.Y = source.Y; - dest.Z = ((1 - source.x - source.y) / source.y) * source.Y; - return dest; -} - -/* from lcms: ComputeChromaticAdaption */ -// Compute chromatic adaption matrix using chad as cone matrix -static struct matrix -compute_chromatic_adaption(struct CIE_XYZ source_white_point, - struct CIE_XYZ dest_white_point, - struct matrix chad) -{ - struct matrix chad_inv; - struct vector cone_source_XYZ, cone_source_rgb; - struct vector cone_dest_XYZ, cone_dest_rgb; - struct matrix cone, tmp; - - tmp = chad; - chad_inv = matrix_invert(tmp); - - cone_source_XYZ.v[0] = source_white_point.X; - cone_source_XYZ.v[1] = source_white_point.Y; - cone_source_XYZ.v[2] = source_white_point.Z; - - cone_dest_XYZ.v[0] = dest_white_point.X; - cone_dest_XYZ.v[1] = dest_white_point.Y; - cone_dest_XYZ.v[2] = dest_white_point.Z; - - cone_source_rgb = matrix_eval(chad, cone_source_XYZ); - cone_dest_rgb = matrix_eval(chad, cone_dest_XYZ); - - cone.m[0][0] = cone_dest_rgb.v[0]/cone_source_rgb.v[0]; - cone.m[0][1] = 0; - cone.m[0][2] = 0; - cone.m[1][0] = 0; - cone.m[1][1] = cone_dest_rgb.v[1]/cone_source_rgb.v[1]; - cone.m[1][2] = 0; - cone.m[2][0] = 0; - cone.m[2][1] = 0; - cone.m[2][2] = cone_dest_rgb.v[2]/cone_source_rgb.v[2]; - cone.invalid = false; - - // Normalize - return matrix_multiply(chad_inv, matrix_multiply(cone, chad)); -} - -/* from lcms: cmsAdaptionMatrix */ -// Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll -// Bradford is assumed -static struct matrix -adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumination) -{ -#if defined (_MSC_VER) -#pragma warning(push) -/* Disable double to float truncation warning 4305 */ -#pragma warning(disable:4305) -#endif - struct matrix lam_rigg = {{ // Bradford matrix - { 0.8951, 0.2664, -0.1614 }, - { -0.7502, 1.7135, 0.0367 }, - { 0.0389, -0.0685, 1.0296 } - }}; -#if defined (_MSC_VER) -/* Restore warnings */ -#pragma warning(pop) -#endif - return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg); -} - -/* from lcms: cmsAdaptMatrixToD50 */ -static struct matrix adapt_matrix_to_D50(struct matrix r, qcms_CIE_xyY source_white_point) -{ - struct CIE_XYZ DNN_XYZ; - struct matrix Bradford; - - if (source_white_point.y == 0.0) - return matrix_invalid(); - - DNN_XYZ = xyY2XYZ(source_white_point); - - Bradford = adaption_matrix(DNN_XYZ, D50_XYZ); - - return matrix_multiply(Bradford, r); -} - -qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries) -{ - struct CIE_XYZ source_white; - struct matrix colorants; - - colorants = build_RGB_to_XYZ_transfer_matrix(white_point, primaries); - colorants = adapt_matrix_to_D50(colorants, white_point); - - if (colorants.invalid) - return false; - - /* note: there's a transpose type of operation going on here */ - profile->redColorant.X = double_to_s15Fixed16Number(colorants.m[0][0]); - profile->redColorant.Y = double_to_s15Fixed16Number(colorants.m[1][0]); - profile->redColorant.Z = double_to_s15Fixed16Number(colorants.m[2][0]); - - profile->greenColorant.X = double_to_s15Fixed16Number(colorants.m[0][1]); - profile->greenColorant.Y = double_to_s15Fixed16Number(colorants.m[1][1]); - profile->greenColorant.Z = double_to_s15Fixed16Number(colorants.m[2][1]); - - profile->blueColorant.X = double_to_s15Fixed16Number(colorants.m[0][2]); - profile->blueColorant.Y = double_to_s15Fixed16Number(colorants.m[1][2]); - profile->blueColorant.Z = double_to_s15Fixed16Number(colorants.m[2][2]); - - /* Store the media white point */ - source_white = xyY2XYZ(white_point); - profile->mediaWhitePoint.X = double_to_s15Fixed16Number(source_white.X); - profile->mediaWhitePoint.Y = double_to_s15Fixed16Number(source_white.Y); - profile->mediaWhitePoint.Z = double_to_s15Fixed16Number(source_white.Z); - - return true; -} - -#if 0 -static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - int i; - float (*mat)[4] = transform->matrix; - for (i=0; i<length; i++) { - unsigned char device_r = *src++; - unsigned char device_g = *src++; - unsigned char device_b = *src++; - - float linear_r = transform->input_gamma_table_r[device_r]; - float linear_g = transform->input_gamma_table_g[device_g]; - float linear_b = transform->input_gamma_table_b[device_b]; - - float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; - float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; - float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; - - float out_device_r = pow(out_linear_r, transform->out_gamma_r); - float out_device_g = pow(out_linear_g, transform->out_gamma_g); - float out_device_b = pow(out_linear_b, transform->out_gamma_b); - - dest[r_out] = clamp_u8(out_device_r*255); - dest[1] = clamp_u8(out_device_g*255); - dest[b_out] = clamp_u8(out_device_b*255); - dest += 3; - } -} -#endif - -static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - for (i = 0; i < length; i++) { - float out_device_r, out_device_g, out_device_b; - unsigned char device = *src++; - - float linear = transform->input_gamma_table_gray[device]; - - out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); - out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); - out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); - - dest[r_out] = clamp_u8(out_device_r*255); - dest[1] = clamp_u8(out_device_g*255); - dest[b_out] = clamp_u8(out_device_b*255); - dest += 3; - } -} - -/* Alpha is not corrected. - A rationale for this is found in Alvy Ray's "Should Alpha Be Nonlinear If - RGB Is?" Tech Memo 17 (December 14, 1998). - See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf -*/ - -static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - for (i = 0; i < length; i++) { - float out_device_r, out_device_g, out_device_b; - unsigned char device = *src++; - unsigned char alpha = *src++; - - float linear = transform->input_gamma_table_gray[device]; - - out_device_r = lut_interp_linear(linear, transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); - out_device_g = lut_interp_linear(linear, transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); - out_device_b = lut_interp_linear(linear, transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); - - dest[r_out] = clamp_u8(out_device_r*255); - dest[1] = clamp_u8(out_device_g*255); - dest[b_out] = clamp_u8(out_device_b*255); - dest[3] = alpha; - dest += 4; - } -} - - -static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - for (i = 0; i < length; i++) { - unsigned char device = *src++; - uint16_t gray; - - float linear = transform->input_gamma_table_gray[device]; - - /* we could round here... */ - gray = linear * PRECACHE_OUTPUT_MAX; - - dest[r_out] = transform->output_table_r->data[gray]; - dest[1] = transform->output_table_g->data[gray]; - dest[b_out] = transform->output_table_b->data[gray]; - dest += 3; - } -} - - -static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - for (i = 0; i < length; i++) { - unsigned char device = *src++; - unsigned char alpha = *src++; - uint16_t gray; - - float linear = transform->input_gamma_table_gray[device]; - - /* we could round here... */ - gray = linear * PRECACHE_OUTPUT_MAX; - - dest[r_out] = transform->output_table_r->data[gray]; - dest[1] = transform->output_table_g->data[gray]; - dest[b_out] = transform->output_table_b->data[gray]; - dest[3] = alpha; - dest += 4; - } -} - -static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - float (*mat)[4] = transform->matrix; - for (i = 0; i < length; i++) { - unsigned char device_r = *src++; - unsigned char device_g = *src++; - unsigned char device_b = *src++; - uint16_t r, g, b; - - float linear_r = transform->input_gamma_table_r[device_r]; - float linear_g = transform->input_gamma_table_g[device_g]; - float linear_b = transform->input_gamma_table_b[device_b]; - - float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; - float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; - float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; - - out_linear_r = clamp_float(out_linear_r); - out_linear_g = clamp_float(out_linear_g); - out_linear_b = clamp_float(out_linear_b); - - /* we could round here... */ - r = out_linear_r * PRECACHE_OUTPUT_MAX; - g = out_linear_g * PRECACHE_OUTPUT_MAX; - b = out_linear_b * PRECACHE_OUTPUT_MAX; - - dest[r_out] = transform->output_table_r->data[r]; - dest[1] = transform->output_table_g->data[g]; - dest[b_out] = transform->output_table_b->data[b]; - dest += 3; - } -} - -void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - float (*mat)[4] = transform->matrix; - for (i = 0; i < length; i++) { - unsigned char device_r = *src++; - unsigned char device_g = *src++; - unsigned char device_b = *src++; - unsigned char alpha = *src++; - uint16_t r, g, b; - - float linear_r = transform->input_gamma_table_r[device_r]; - float linear_g = transform->input_gamma_table_g[device_g]; - float linear_b = transform->input_gamma_table_b[device_b]; - - float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; - float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; - float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; - - out_linear_r = clamp_float(out_linear_r); - out_linear_g = clamp_float(out_linear_g); - out_linear_b = clamp_float(out_linear_b); - - /* we could round here... */ - r = out_linear_r * PRECACHE_OUTPUT_MAX; - g = out_linear_g * PRECACHE_OUTPUT_MAX; - b = out_linear_b * PRECACHE_OUTPUT_MAX; - - dest[r_out] = transform->output_table_r->data[r]; - dest[1] = transform->output_table_g->data[g]; - dest[b_out] = transform->output_table_b->data[b]; - dest[3] = alpha; - dest += 4; - } -} - -// Not used -/* -static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - int xy_len = 1; - int x_len = transform->grid_size; - int len = x_len * x_len; - float* r_table = transform->r_clut; - float* g_table = transform->g_clut; - float* b_table = transform->b_clut; - - for (i = 0; i < length; i++) { - unsigned char in_r = *src++; - unsigned char in_g = *src++; - unsigned char in_b = *src++; - float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = in_b/255.0f; - - int x = floor(linear_r * (transform->grid_size-1)); - int y = floor(linear_g * (transform->grid_size-1)); - int z = floor(linear_b * (transform->grid_size-1)); - int x_n = ceil(linear_r * (transform->grid_size-1)); - int y_n = ceil(linear_g * (transform->grid_size-1)); - int z_n = ceil(linear_b * (transform->grid_size-1)); - float x_d = linear_r * (transform->grid_size-1) - x; - float y_d = linear_g * (transform->grid_size-1) - y; - float z_d = linear_b * (transform->grid_size-1) - z; - - float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d); - float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d); - float r_y1 = lerp(r_x1, r_x2, y_d); - float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d); - float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_n), x_d); - float r_y2 = lerp(r_x3, r_x4, y_d); - float clut_r = lerp(r_y1, r_y2, z_d); - - float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d); - float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d); - float g_y1 = lerp(g_x1, g_x2, y_d); - float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d); - float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_n), x_d); - float g_y2 = lerp(g_x3, g_x4, y_d); - float clut_g = lerp(g_y1, g_y2, z_d); - - float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d); - float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d); - float b_y1 = lerp(b_x1, b_x2, y_d); - float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d); - float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_n), x_d); - float b_y2 = lerp(b_x3, b_x4, y_d); - float clut_b = lerp(b_y1, b_y2, z_d); - - dest[r_out] = clamp_u8(clut_r*255.0f); - dest[1] = clamp_u8(clut_g*255.0f); - dest[b_out] = clamp_u8(clut_b*255.0f); - dest += 3; - } -} -*/ - -// Using lcms' tetra interpolation algorithm. -void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - int xy_len = 1; - int x_len = transform->grid_size; - int len = x_len * x_len; - float* r_table = transform->r_clut; - float* g_table = transform->g_clut; - float* b_table = transform->b_clut; - float c0_r, c1_r, c2_r, c3_r; - float c0_g, c1_g, c2_g, c3_g; - float c0_b, c1_b, c2_b, c3_b; - float clut_r, clut_g, clut_b; - - if (!(transform->transform_flags & TRANSFORM_FLAG_CLUT_CACHE)) - qcms_transform_build_clut_cache(transform); - - for (i = 0; i < length; i++) { - unsigned char in_r = *src++; - unsigned char in_g = *src++; - unsigned char in_b = *src++; - unsigned char in_a = *src++; - - int x = transform->floor_cache[in_r]; - int y = transform->floor_cache[in_g]; - int z = transform->floor_cache[in_b]; - - int x_n = transform->ceil_cache[in_r]; - int y_n = transform->ceil_cache[in_g]; - int z_n = transform->ceil_cache[in_b]; - - float rx = transform->r_cache[in_r]; - float ry = transform->r_cache[in_g]; - float rz = transform->r_cache[in_b]; - - c0_r = CLU(r_table, x, y, z); - c0_g = CLU(g_table, x, y, z); - c0_b = CLU(b_table, x, y, z); - - if( rx >= ry ) { - if (ry >= rz) { //rx >= ry && ry >= rz - c1_r = CLU(r_table, x_n, y, z) - c0_r; - c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z); - c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); - c1_g = CLU(g_table, x_n, y, z) - c0_g; - c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z); - c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); - c1_b = CLU(b_table, x_n, y, z) - c0_b; - c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z); - c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); - } else { - if (rx >= rz) { //rx >= rz && rz >= ry - c1_r = CLU(r_table, x_n, y, z) - c0_r; - c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); - c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z); - c1_g = CLU(g_table, x_n, y, z) - c0_g; - c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); - c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z); - c1_b = CLU(b_table, x_n, y, z) - c0_b; - c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); - c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z); - } else { //rz > rx && rx >= ry - c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n); - c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); - c3_r = CLU(r_table, x, y, z_n) - c0_r; - c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n); - c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); - c3_g = CLU(g_table, x, y, z_n) - c0_g; - c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n); - c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); - c3_b = CLU(b_table, x, y, z_n) - c0_b; - } - } - } else { - if (rx >= rz) { //ry > rx && rx >= rz - c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z); - c2_r = CLU(r_table, x, y_n, z) - c0_r; - c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); - c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z); - c2_g = CLU(g_table, x, y_n, z) - c0_g; - c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); - c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z); - c2_b = CLU(b_table, x, y_n, z) - c0_b; - c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); - } else { - if (ry >= rz) { //ry >= rz && rz > rx - c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); - c2_r = CLU(r_table, x, y_n, z) - c0_r; - c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z); - c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); - c2_g = CLU(g_table, x, y_n, z) - c0_g; - c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z); - c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); - c2_b = CLU(b_table, x, y_n, z) - c0_b; - c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z); - } else { //rz > ry && ry > rx - c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); - c2_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y, z_n); - c3_r = CLU(r_table, x, y, z_n) - c0_r; - c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); - c2_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y, z_n); - c3_g = CLU(g_table, x, y, z_n) - c0_g; - c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); - c2_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y, z_n); - c3_b = CLU(b_table, x, y, z_n) - c0_b; - } - } - } - - clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz; - clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz; - clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz; - - dest[r_out] = clamp_u8(clut_r*255.0f); - dest[1] = clamp_u8(clut_g*255.0f); - dest[b_out] = clamp_u8(clut_b*255.0f); - dest[3] = in_a; - dest += 4; - } -} - -// Using lcms' tetra interpolation code. -static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - int xy_len = 1; - int x_len = transform->grid_size; - int len = x_len * x_len; - float* r_table = transform->r_clut; - float* g_table = transform->g_clut; - float* b_table = transform->b_clut; - float c0_r, c1_r, c2_r, c3_r; - float c0_g, c1_g, c2_g, c3_g; - float c0_b, c1_b, c2_b, c3_b; - float clut_r, clut_g, clut_b; - - if (!(transform->transform_flags & TRANSFORM_FLAG_CLUT_CACHE)) - qcms_transform_build_clut_cache(transform); - - for (i = 0; i < length; i++) { - unsigned char in_r = *src++; - unsigned char in_g = *src++; - unsigned char in_b = *src++; - - int x = transform->floor_cache[in_r]; - int y = transform->floor_cache[in_g]; - int z = transform->floor_cache[in_b]; - - int x_n = transform->ceil_cache[in_r]; - int y_n = transform->ceil_cache[in_g]; - int z_n = transform->ceil_cache[in_b]; - - float rx = transform->r_cache[in_r]; - float ry = transform->r_cache[in_g]; - float rz = transform->r_cache[in_b]; - - c0_r = CLU(r_table, x, y, z); - c0_g = CLU(g_table, x, y, z); - c0_b = CLU(b_table, x, y, z); - - if( rx >= ry ) { - if (ry >= rz) { //rx >= ry && ry >= rz - c1_r = CLU(r_table, x_n, y, z) - c0_r; - c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z); - c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); - c1_g = CLU(g_table, x_n, y, z) - c0_g; - c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z); - c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); - c1_b = CLU(b_table, x_n, y, z) - c0_b; - c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z); - c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); - } else { - if (rx >= rz) { //rx >= rz && rz >= ry - c1_r = CLU(r_table, x_n, y, z) - c0_r; - c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); - c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z); - c1_g = CLU(g_table, x_n, y, z) - c0_g; - c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); - c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z); - c1_b = CLU(b_table, x_n, y, z) - c0_b; - c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); - c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z); - } else { //rz > rx && rx >= ry - c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n); - c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); - c3_r = CLU(r_table, x, y, z_n) - c0_r; - c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n); - c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); - c3_g = CLU(g_table, x, y, z_n) - c0_g; - c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n); - c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); - c3_b = CLU(b_table, x, y, z_n) - c0_b; - } - } - } else { - if (rx >= rz) { //ry > rx && rx >= rz - c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z); - c2_r = CLU(r_table, x, y_n, z) - c0_r; - c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); - c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z); - c2_g = CLU(g_table, x, y_n, z) - c0_g; - c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); - c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z); - c2_b = CLU(b_table, x, y_n, z) - c0_b; - c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); - } else { - if (ry >= rz) { //ry >= rz && rz > rx - c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); - c2_r = CLU(r_table, x, y_n, z) - c0_r; - c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z); - c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); - c2_g = CLU(g_table, x, y_n, z) - c0_g; - c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z); - c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); - c2_b = CLU(b_table, x, y_n, z) - c0_b; - c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z); - } else { //rz > ry && ry > rx - c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); - c2_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y, z_n); - c3_r = CLU(r_table, x, y, z_n) - c0_r; - c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); - c2_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y, z_n); - c3_g = CLU(g_table, x, y, z_n) - c0_g; - c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); - c2_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y, z_n); - c3_b = CLU(b_table, x, y, z_n) - c0_b; - } - } - } - - clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz; - clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz; - clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz; - - dest[r_out] = clamp_u8(clut_r*255.0f); - dest[1] = clamp_u8(clut_g*255.0f); - dest[b_out] = clamp_u8(clut_b*255.0f); - dest += 3; - } -} - -static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - float (*mat)[4] = transform->matrix; - for (i = 0; i < length; i++) { - unsigned char device_r = *src++; - unsigned char device_g = *src++; - unsigned char device_b = *src++; - float out_device_r, out_device_g, out_device_b; - - float linear_r = transform->input_gamma_table_r[device_r]; - float linear_g = transform->input_gamma_table_g[device_g]; - float linear_b = transform->input_gamma_table_b[device_b]; - - float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; - float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; - float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; - - out_linear_r = clamp_float(out_linear_r); - out_linear_g = clamp_float(out_linear_g); - out_linear_b = clamp_float(out_linear_b); - - out_device_r = lut_interp_linear(out_linear_r, - transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); - out_device_g = lut_interp_linear(out_linear_g, - transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); - out_device_b = lut_interp_linear(out_linear_b, - transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); - - dest[r_out] = clamp_u8(out_device_r*255); - dest[1] = clamp_u8(out_device_g*255); - dest[b_out] = clamp_u8(out_device_b*255); - dest += 3; - } -} - -static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - unsigned int i; - float (*mat)[4] = transform->matrix; - for (i = 0; i < length; i++) { - unsigned char device_r = *src++; - unsigned char device_g = *src++; - unsigned char device_b = *src++; - unsigned char alpha = *src++; - float out_device_r, out_device_g, out_device_b; - - float linear_r = transform->input_gamma_table_r[device_r]; - float linear_g = transform->input_gamma_table_g[device_g]; - float linear_b = transform->input_gamma_table_b[device_b]; - - float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; - float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; - float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; - - out_linear_r = clamp_float(out_linear_r); - out_linear_g = clamp_float(out_linear_g); - out_linear_b = clamp_float(out_linear_b); - - out_device_r = lut_interp_linear(out_linear_r, - transform->output_gamma_lut_r, transform->output_gamma_lut_r_length); - out_device_g = lut_interp_linear(out_linear_g, - transform->output_gamma_lut_g, transform->output_gamma_lut_g_length); - out_device_b = lut_interp_linear(out_linear_b, - transform->output_gamma_lut_b, transform->output_gamma_lut_b_length); - - dest[r_out] = clamp_u8(out_device_r*255); - dest[1] = clamp_u8(out_device_g*255); - dest[b_out] = clamp_u8(out_device_b*255); - dest[3] = alpha; - dest += 4; - } -} - -#if 0 -static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format) -{ - const int r_out = output_format.r; - const int b_out = output_format.b; - - int i; - float (*mat)[4] = transform->matrix; - for (i = 0; i < length; i++) { - unsigned char device_r = *src++; - unsigned char device_g = *src++; - unsigned char device_b = *src++; - - float linear_r = transform->input_gamma_table_r[device_r]; - float linear_g = transform->input_gamma_table_g[device_g]; - float linear_b = transform->input_gamma_table_b[device_b]; - - float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + mat[2][0]*linear_b; - float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + mat[2][1]*linear_b; - float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + mat[2][2]*linear_b; - - dest[r_out] = clamp_u8(out_linear_r*255); - dest[1] = clamp_u8(out_linear_g*255); - dest[b_out] = clamp_u8(out_linear_b*255); - dest += 3; - } -} -#endif - -/* - * If users create and destroy objects on different threads, even if the same - * objects aren't used on different threads at the same time, we can still run - * in to trouble with refcounts if they aren't atomic. - * - * This can lead to us prematurely deleting the precache if threads get unlucky - * and write the wrong value to the ref count. - */ -static struct precache_output *precache_reference(struct precache_output *p) -{ - qcms_atomic_increment(p->ref_count); - return p; -} - -static struct precache_output *precache_create() -{ - struct precache_output *p = malloc(sizeof(struct precache_output)); - if (p) - p->ref_count = 1; - return p; -} - -void precache_release(struct precache_output *p) -{ - if (qcms_atomic_decrement(p->ref_count) == 0) { - free(p); - } -} - -#ifdef HAVE_POSIX_MEMALIGN -static qcms_transform *transform_alloc(void) -{ - qcms_transform *t; - if (!posix_memalign(&t, 16, sizeof(*t))) { - return t; - } else { - return NULL; - } -} -static void transform_free(qcms_transform *t) -{ - free(t); -} -#else -static qcms_transform *transform_alloc(void) -{ - /* transform needs to be aligned on a 16byte boundrary */ - char *original_block = calloc(sizeof(qcms_transform) + sizeof(void*) + 16, 1); - /* make room for a pointer to the block returned by calloc */ - void *transform_start = original_block + sizeof(void*); - /* align transform_start */ - qcms_transform *transform_aligned = (qcms_transform*)(((uintptr_t)transform_start + 15) & ~0xf); - - /* store a pointer to the block returned by calloc so that we can free it later */ - void **(original_block_ptr) = (void**)transform_aligned; - if (!original_block) - return NULL; - original_block_ptr--; - *original_block_ptr = original_block; - - return transform_aligned; -} -static void transform_free(qcms_transform *t) -{ - /* get at the pointer to the unaligned block returned by calloc */ - void **p = (void**)t; - p--; - free(*p); -} -#endif - -void qcms_transform_release(qcms_transform *t) -{ - /* ensure we only free the gamma tables once even if there are - * multiple references to the same data */ - - if (t->output_table_r) - precache_release(t->output_table_r); - if (t->output_table_g) - precache_release(t->output_table_g); - if (t->output_table_b) - precache_release(t->output_table_b); - - free(t->input_gamma_table_r); - if (t->input_gamma_table_g != t->input_gamma_table_r) - free(t->input_gamma_table_g); - if (t->input_gamma_table_g != t->input_gamma_table_r && - t->input_gamma_table_g != t->input_gamma_table_b) - free(t->input_gamma_table_b); - - free(t->input_gamma_table_gray); - - free(t->output_gamma_lut_r); - free(t->output_gamma_lut_g); - free(t->output_gamma_lut_b); - - transform_free(t); -} - -#ifdef X86 -// Determine if we can build with SSE2 (this was partly copied from jmorecfg.h in -// mozilla/jpeg) - // ------------------------------------------------------------------------- -#if defined(_M_IX86) && defined(_MSC_VER) -#define HAS_CPUID -/* Get us a CPUID function. Avoid clobbering EBX because sometimes it's the PIC - register - I'm not sure if that ever happens on windows, but cpuid isn't - on the critical path so we just preserve the register to be safe and to be - consistent with the non-windows version. */ -static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { - uint32_t a_, b_, c_, d_; - __asm { - xchg ebx, esi - mov eax, fxn - cpuid - mov a_, eax - mov b_, ebx - mov c_, ecx - mov d_, edx - xchg ebx, esi - } - *a = a_; - *b = b_; - *c = c_; - *d = d_; -} -#elif (defined(__GNUC__) || defined(__SUNPRO_C)) && (defined(__i386__) || defined(__i386)) -#define HAS_CPUID -/* Get us a CPUID function. We can't use ebx because it's the PIC register on - some platforms, so we use ESI instead and save ebx to avoid clobbering it. */ -static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) { - - uint32_t a_, b_, c_, d_; - __asm__ __volatile__ ("xchgl %%ebx, %%esi; cpuid; xchgl %%ebx, %%esi;" - : "=a" (a_), "=S" (b_), "=c" (c_), "=d" (d_) : "a" (fxn)); - *a = a_; - *b = b_; - *c = c_; - *d = d_; -} -#endif - -// -------------------------Runtime SSEx Detection----------------------------- - -/* MMX is always supported per - * Gecko v1.9.1 minimum CPU requirements */ -#define SSE1_EDX_MASK (1UL << 25) -#define SSE2_EDX_MASK (1UL << 26) -#define SSE3_ECX_MASK (1UL << 0) - -static int sse_version_available(void) -{ -#if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) - /* we know at build time that 64-bit CPUs always have SSE2 - * this tells the compiler that non-SSE2 branches will never be - * taken (i.e. OK to optimze away the SSE1 and non-SIMD code */ - return 2; -#elif defined(HAS_CPUID) - static int sse_version = -1; - uint32_t a, b, c, d; - uint32_t function = 0x00000001; - - if (sse_version == -1) { - sse_version = 0; - cpuid(function, &a, &b, &c, &d); - if (c & SSE3_ECX_MASK) - sse_version = 3; - else if (d & SSE2_EDX_MASK) - sse_version = 2; - else if (d & SSE1_EDX_MASK) - sse_version = 1; - } - - return sse_version; -#else - return 0; -#endif -} -#endif - -static const struct matrix bradford_matrix = {{ { 0.8951f, 0.2664f,-0.1614f}, - {-0.7502f, 1.7135f, 0.0367f}, - { 0.0389f,-0.0685f, 1.0296f}}, - false}; - -static const struct matrix bradford_matrix_inv = {{ { 0.9869929f,-0.1470543f, 0.1599627f}, - { 0.4323053f, 0.5183603f, 0.0492912f}, - {-0.0085287f, 0.0400428f, 0.9684867f}}, - false}; - -// See ICCv4 E.3 -struct matrix compute_whitepoint_adaption(float X, float Y, float Z) { - float p = (0.96422f*bradford_matrix.m[0][0] + 1.000f*bradford_matrix.m[1][0] + 0.82521f*bradford_matrix.m[2][0]) / - (X*bradford_matrix.m[0][0] + Y*bradford_matrix.m[1][0] + Z*bradford_matrix.m[2][0] ); - float y = (0.96422f*bradford_matrix.m[0][1] + 1.000f*bradford_matrix.m[1][1] + 0.82521f*bradford_matrix.m[2][1]) / - (X*bradford_matrix.m[0][1] + Y*bradford_matrix.m[1][1] + Z*bradford_matrix.m[2][1] ); - float b = (0.96422f*bradford_matrix.m[0][2] + 1.000f*bradford_matrix.m[1][2] + 0.82521f*bradford_matrix.m[2][2]) / - (X*bradford_matrix.m[0][2] + Y*bradford_matrix.m[1][2] + Z*bradford_matrix.m[2][2] ); - struct matrix white_adaption = {{ {p,0,0}, {0,y,0}, {0,0,b}}, false}; - return matrix_multiply( bradford_matrix_inv, matrix_multiply(white_adaption, bradford_matrix) ); -} - -void qcms_profile_precache_output_transform(qcms_profile *profile) -{ - /* we only support precaching on rgb profiles */ - if (profile->color_space != RGB_SIGNATURE) - return; - - if (qcms_supports_iccv4) { - /* don't precache since we will use the B2A LUT */ - if (profile->B2A0) - return; - - /* don't precache since we will use the mBA LUT */ - if (profile->mBA) - return; - } - - /* don't precache if we do not have the TRC curves */ - if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC) - return; - - if (!profile->output_table_r) { - profile->output_table_r = precache_create(); - if (profile->output_table_r && - !compute_precache(profile->redTRC, profile->output_table_r->data)) { - precache_release(profile->output_table_r); - profile->output_table_r = NULL; - } - } - if (!profile->output_table_g) { - profile->output_table_g = precache_create(); - if (profile->output_table_g && - !compute_precache(profile->greenTRC, profile->output_table_g->data)) { - precache_release(profile->output_table_g); - profile->output_table_g = NULL; - } - } - if (!profile->output_table_b) { - profile->output_table_b = precache_create(); - if (profile->output_table_b && - !compute_precache(profile->blueTRC, profile->output_table_b->data)) { - precache_release(profile->output_table_b); - profile->output_table_b = NULL; - } - } -} - -/* Replace the current transformation with a LUT transformation using a given number of sample points */ -qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms_profile *in, qcms_profile *out, - int samples, qcms_data_type in_type) -{ - /* The range between which 2 consecutive sample points can be used to interpolate */ - uint16_t x,y,z; - uint32_t l; - uint32_t lutSize = 3 * samples * samples * samples; - float* src = NULL; - float* dest = NULL; - float* lut = NULL; - float inverse; - - src = malloc(lutSize*sizeof(float)); - dest = malloc(lutSize*sizeof(float)); - - if (src && dest) { - /* Prepare a list of points we want to sample: x, y, z order */ - l = 0; - inverse = 1 / (float)(samples-1); - for (x = 0; x < samples; x++) { - for (y = 0; y < samples; y++) { - for (z = 0; z < samples; z++) { - src[l++] = x * inverse; // r - src[l++] = y * inverse; // g - src[l++] = z * inverse; // b - } - } - } - - lut = qcms_chain_transform(in, out, src, dest, lutSize); - - if (lut) { - transform->r_clut = &lut[0]; // r - transform->g_clut = &lut[1]; // g - transform->b_clut = &lut[2]; // b - transform->grid_size = samples; - - if (in_type == QCMS_DATA_RGBA_8) { -#if defined(SSE2_ENABLE) - if (sse_version_available() >= 2) { - transform->transform_fn = qcms_transform_data_tetra_clut_rgba_sse2; - } else { - transform->transform_fn = qcms_transform_data_tetra_clut_rgba; - } -#else - transform->transform_fn = qcms_transform_data_tetra_clut_rgba; -#endif - } else { - transform->transform_fn = qcms_transform_data_tetra_clut; - } - } - } - - // XXX: qcms_modular_transform_data may return the lut in either the src or the - // dest buffer. If so, it must not be free-ed. - if (src && lut != src) { - free(src); - } - if (dest && lut != dest) { - free(dest); - } - - if (lut == NULL) { - return NULL; - } - return transform; -} - -/* Create a transform LUT using the given number of sample points. The transform LUT data is stored - in the output (cube) in bgra format in zyx sample order. */ -qcms_bool qcms_transform_create_LUT_zyx_bgra(qcms_profile *in, qcms_profile *out, qcms_intent intent, - int samples, unsigned char* cube) -{ - uint16_t z,y,x; - uint32_t l,index; - uint32_t lutSize = 3 * samples * samples * samples; - - float* src = NULL; - float* dest = NULL; - float* lut = NULL; - float inverse; - - src = malloc(lutSize*sizeof(float)); - dest = malloc(lutSize*sizeof(float)); - - if (src && dest) { - /* Prepare a list of points we want to sample: z, y, x order */ - l = 0; - inverse = 1 / (float)(samples-1); - for (z = 0; z < samples; z++) { - for (y = 0; y < samples; y++) { - for (x = 0; x < samples; x++) { - src[l++] = x * inverse; // r - src[l++] = y * inverse; // g - src[l++] = z * inverse; // b - } - } - } - - lut = qcms_chain_transform(in, out, src, dest, lutSize); - - if (lut) { - index = l = 0; - for (z = 0; z < samples; z++) { - for (y = 0; y < samples; y++) { - for (x = 0; x < samples; x++) { - cube[index++] = (int)floorf(lut[l + 2] * 255.0f + 0.5f); // b - cube[index++] = (int)floorf(lut[l + 1] * 255.0f + 0.5f); // g - cube[index++] = (int)floorf(lut[l + 0] * 255.0f + 0.5f); // r - cube[index++] = 255; // a - l += 3; - } - } - } - } - } - - // XXX: qcms_modular_transform_data may return the lut data in either the src or - // dest buffer so free src, dest, and lut with care. - - if (src && lut != src) - free(src); - if (dest && lut != dest) - free(dest); - - if (lut) { - free(lut); - return true; - } - - return false; -} - -void qcms_transform_build_clut_cache(qcms_transform* transform) { - const int grid_factor = transform->grid_size - 1; - const float grid_scaled = (1.0f / 255.0f) * grid_factor; - int i; - -#define div_255_ceiling(value) (((value) + 254) / 255) - - for (i = 0; i < 256; i++) { - transform->ceil_cache[i] = div_255_ceiling(i * grid_factor); - transform->floor_cache[i] = i * grid_factor / 255; - transform->r_cache[i] = (i * grid_scaled) - transform->floor_cache[i]; - } - -#undef div_255_ceil - - transform->transform_flags |= TRANSFORM_FLAG_CLUT_CACHE; -} - -#define NO_MEM_TRANSFORM NULL - -qcms_transform* qcms_transform_create( - qcms_profile *in, qcms_data_type in_type, - qcms_profile *out, qcms_data_type out_type, - qcms_intent intent) -{ - qcms_transform *transform = NULL; - bool precache = false; - int i, j; - - transform = transform_alloc(); - if (!transform) { - return NULL; - } - - if (out_type != QCMS_DATA_RGB_8 && out_type != QCMS_DATA_RGBA_8) { - assert(0 && "output type"); - qcms_transform_release(transform); - return NULL; - } - - transform->transform_flags = 0; - - if (out->output_table_r && out->output_table_g && out->output_table_b) { - precache = true; - } - - if (qcms_supports_iccv4 && (in->A2B0 || out->B2A0 || in->mAB || out->mAB)) { - // Precache the transformation to a CLUT 33x33x33 in size. - // 33 is used by many profiles and works well in practice. - // This evenly divides 256 into blocks of 8x8x8. - // TODO For transforming small data sets of about 200x200 or less - // precaching should be avoided. - qcms_transform *result = qcms_transform_precacheLUT_float(transform, in, out, 33, in_type); - if (!result) { - assert(0 && "precacheLUT failed"); - qcms_transform_release(transform); - return NULL; - } - return result; - } - - /* A matrix-based transform will be selected: check that the PCS - of the input/output profiles are the same, crbug.com/5120682 */ - if (in->pcs != out->pcs) { - qcms_transform_release(transform); - return NULL; - } - - if (precache) { - transform->output_table_r = precache_reference(out->output_table_r); - transform->output_table_g = precache_reference(out->output_table_g); - transform->output_table_b = precache_reference(out->output_table_b); - } else { - if (!out->redTRC || !out->greenTRC || !out->blueTRC) { - qcms_transform_release(transform); - return NO_MEM_TRANSFORM; - } - - build_output_lut(out->redTRC, &transform->output_gamma_lut_r, &transform->output_gamma_lut_r_length); - build_output_lut(out->greenTRC, &transform->output_gamma_lut_g, &transform->output_gamma_lut_g_length); - build_output_lut(out->blueTRC, &transform->output_gamma_lut_b, &transform->output_gamma_lut_b_length); - - if (!transform->output_gamma_lut_r || !transform->output_gamma_lut_g || !transform->output_gamma_lut_b) { - qcms_transform_release(transform); - return NO_MEM_TRANSFORM; - } - } - - if (in->color_space == RGB_SIGNATURE) { - struct matrix in_matrix, out_matrix, result; - - if (in_type != QCMS_DATA_RGB_8 && in_type != QCMS_DATA_RGBA_8) { - assert(0 && "input type"); - qcms_transform_release(transform); - return NULL; - } - - if (precache) { -#if defined(SSE2_ENABLE) - if (sse_version_available() >= 2) { - if (in_type == QCMS_DATA_RGB_8) - transform->transform_fn = qcms_transform_data_rgb_out_lut_sse2; - else - transform->transform_fn = qcms_transform_data_rgba_out_lut_sse2; - } else -#endif - { - if (in_type == QCMS_DATA_RGB_8) - transform->transform_fn = qcms_transform_data_rgb_out_lut_precache; - else - transform->transform_fn = qcms_transform_data_rgba_out_lut_precache; - } - } else { - if (in_type == QCMS_DATA_RGB_8) - transform->transform_fn = qcms_transform_data_rgb_out_lut; - else - transform->transform_fn = qcms_transform_data_rgba_out_lut; - } - - //XXX: avoid duplicating tables if we can - transform->input_gamma_table_r = build_input_gamma_table(in->redTRC); - transform->input_gamma_table_g = build_input_gamma_table(in->greenTRC); - transform->input_gamma_table_b = build_input_gamma_table(in->blueTRC); - - if (!transform->input_gamma_table_r || !transform->input_gamma_table_g || !transform->input_gamma_table_b) { - qcms_transform_release(transform); - return NO_MEM_TRANSFORM; - } - - /* build combined colorant matrix */ - in_matrix = build_colorant_matrix(in); - out_matrix = build_colorant_matrix(out); - out_matrix = matrix_invert(out_matrix); - if (out_matrix.invalid) { - qcms_transform_release(transform); - return NULL; - } - result = matrix_multiply(out_matrix, in_matrix); - - /* check for NaN values in the matrix and bail if we find any - see also https://bugzilla.mozilla.org/show_bug.cgi?id=1170316 */ - for (i = 0 ; i < 3 ; ++i) { - for (j = 0 ; j < 3 ; ++j) { - if (result.m[i][j] != result.m[i][j]) { - qcms_transform_release(transform); - return NULL; - } - } - } - - /* store the results in column major mode - * this makes doing the multiplication with sse easier */ - transform->matrix[0][0] = result.m[0][0]; - transform->matrix[1][0] = result.m[0][1]; - transform->matrix[2][0] = result.m[0][2]; - transform->matrix[0][1] = result.m[1][0]; - transform->matrix[1][1] = result.m[1][1]; - transform->matrix[2][1] = result.m[1][2]; - transform->matrix[0][2] = result.m[2][0]; - transform->matrix[1][2] = result.m[2][1]; - transform->matrix[2][2] = result.m[2][2]; - - /* Flag transform as matrix. */ - transform->transform_flags |= TRANSFORM_FLAG_MATRIX; - - } else if (in->color_space == GRAY_SIGNATURE) { - if (in_type != QCMS_DATA_GRAY_8 && in_type != QCMS_DATA_GRAYA_8) { - assert(0 && "input type"); - qcms_transform_release(transform); - return NULL; - } - - transform->input_gamma_table_gray = build_input_gamma_table(in->grayTRC); - - if (!transform->input_gamma_table_gray) { - qcms_transform_release(transform); - return NO_MEM_TRANSFORM; - } - - if (precache) { - if (in_type == QCMS_DATA_GRAY_8) { - transform->transform_fn = qcms_transform_data_gray_out_precache; - } else { - transform->transform_fn = qcms_transform_data_graya_out_precache; - } - } else { - if (in_type == QCMS_DATA_GRAY_8) { - transform->transform_fn = qcms_transform_data_gray_out_lut; - } else { - transform->transform_fn = qcms_transform_data_graya_out_lut; - } - } - } else { - assert(0 && "unexpected colorspace"); - qcms_transform_release(transform); - return NULL; - } - - return transform; -} - -/* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on unused - * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the presence - * of the attribute but is currently only supported by clang */ -#if defined(__has_attribute) -#define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__) -#elif defined(__GNUC__) && defined(__i386__) -#define HAS_FORCE_ALIGN_ARG_POINTER 1 -#else -#define HAS_FORCE_ALIGN_ARG_POINTER 0 -#endif - -#if HAS_FORCE_ALIGN_ARG_POINTER -/* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */ -__attribute__((__force_align_arg_pointer__)) -#endif -void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length) -{ - static const struct _qcms_format_type output_rgbx = { 0, 2 }; - - transform->transform_fn(transform, src, dest, length, output_rgbx); -} - -void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type) -{ - static const struct _qcms_format_type output_rgbx = { 0, 2 }; - static const struct _qcms_format_type output_bgrx = { 2, 0 }; - - transform->transform_fn(transform, src, dest, length, type == QCMS_OUTPUT_BGRX ? output_bgrx : output_rgbx); -} - -#define ENABLE_ICC_V4_PROFILE_SUPPORT false - -qcms_bool qcms_supports_iccv4 = ENABLE_ICC_V4_PROFILE_SUPPORT; - -void qcms_enable_iccv4() -{ - qcms_supports_iccv4 = true; -} - -static inline qcms_bool transform_is_matrix(qcms_transform *t) -{ - return (t->transform_flags & TRANSFORM_FLAG_MATRIX) ? true : false; -} - -qcms_bool qcms_transform_is_matrix(qcms_transform *t) -{ - return transform_is_matrix(t); -} - -float qcms_transform_get_matrix(qcms_transform *t, unsigned i, unsigned j) -{ - assert(transform_is_matrix(t) && i < 3 && j < 3); - - // Return transform matrix element in row major order (permute i and j) - - return t->matrix[j][i]; -} - -static inline qcms_bool supported_trc_type(qcms_trc_type type) -{ - return (type == QCMS_TRC_HALF_FLOAT || type == QCMS_TRC_USHORT); -} - -const uint16_t half_float_one = 0x3c00; - -size_t qcms_transform_get_input_trc_rgba(qcms_transform *t, qcms_profile *in, qcms_trc_type type, unsigned short *data) -{ - const size_t size = 256; // The input gamma tables always have 256 entries. - - size_t i; - - if (in->color_space != RGB_SIGNATURE || !supported_trc_type(type)) - return 0; - - // qcms_profile *in is assumed to be the profile on the input-side of the color transform t. - // When a transform is created, the input gamma curve data is stored in the transform ... - - if (!t->input_gamma_table_r || !t->input_gamma_table_g || !t->input_gamma_table_b) - return 0; - - // Report the size if no output data is requested. This allows callers to first work out the - // the curve size, then provide allocated memory sufficient to store the curve rgba data. - - if (!data) - return size; - - switch(type) { - case QCMS_TRC_HALF_FLOAT: - for (i = 0; i < size; ++i) { - *data++ = float_to_half_float(t->input_gamma_table_r[i]); // r - *data++ = float_to_half_float(t->input_gamma_table_g[i]); // g - *data++ = float_to_half_float(t->input_gamma_table_b[i]); // b - *data++ = half_float_one; // a - } - break; - case QCMS_TRC_USHORT: - for (i = 0; i < size; ++i) { - *data++ = roundf(t->input_gamma_table_r[i] * 65535.0); // r - *data++ = roundf(t->input_gamma_table_g[i] * 65535.0); // g - *data++ = roundf(t->input_gamma_table_b[i] * 65535.0); // b - *data++ = 65535; // a - } - break; - default: - /* should not be reached */ - assert(0); - } - - return size; -} - -const float inverse65535 = (float) (1.0 / 65535.0); - -size_t qcms_transform_get_output_trc_rgba(qcms_transform *t, qcms_profile *out, qcms_trc_type type, unsigned short *data) -{ - size_t size, i; - - if (out->color_space != RGB_SIGNATURE || !supported_trc_type(type)) - return 0; - - // qcms_profile *out is assumed to be the profile on the output-side of the transform t. - // If the transform output gamma curves need building, do that. They're usually built when - // the transform was created, but sometimes not due to the output gamma precache ... - - if (!out->redTRC || !out->greenTRC || !out->blueTRC) - return 0; - if (!t->output_gamma_lut_r) - build_output_lut(out->redTRC, &t->output_gamma_lut_r, &t->output_gamma_lut_r_length); - if (!t->output_gamma_lut_g) - build_output_lut(out->greenTRC, &t->output_gamma_lut_g, &t->output_gamma_lut_g_length); - if (!t->output_gamma_lut_b) - build_output_lut(out->blueTRC, &t->output_gamma_lut_b, &t->output_gamma_lut_b_length); - - if (!t->output_gamma_lut_r || !t->output_gamma_lut_g || !t->output_gamma_lut_b) - return 0; - - // Output gamma tables should have the same size and should have 4096 entries at most (the - // minimum is 256). Larger tables are rare and ignored here: fail by returning 0. - - size = t->output_gamma_lut_r_length; - if (size != t->output_gamma_lut_g_length) - return 0; - if (size != t->output_gamma_lut_b_length) - return 0; - if (size < 256 || size > 4096) - return 0; - - // Report the size if no output data is requested. This allows callers to first work out the - // the curve size, then provide allocated memory sufficient to store the curve rgba data. - - if (!data) - return size; - - switch (type) { - case QCMS_TRC_HALF_FLOAT: - for (i = 0; i < size; ++i) { - *data++ = float_to_half_float(t->output_gamma_lut_r[i] * inverse65535); // r - *data++ = float_to_half_float(t->output_gamma_lut_g[i] * inverse65535); // g - *data++ = float_to_half_float(t->output_gamma_lut_b[i] * inverse65535); // b - *data++ = half_float_one; // a - } - break; - case QCMS_TRC_USHORT: - for (i = 0; i < size; ++i) { - *data++ = t->output_gamma_lut_r[i]; // r - *data++ = t->output_gamma_lut_g[i]; // g - *data++ = t->output_gamma_lut_b[i]; // b - *data++ = 65535; // a - } - break; - default: - /* should not be reached */ - assert(0); - } - - return size; -} diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transform_util.c deleted file mode 100644 index e60744742c..0000000000 --- a/third_party/qcms/src/transform_util.c +++ /dev/null @@ -1,639 +0,0 @@ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#define _ISOC99_SOURCE /* for INFINITY */ - -#include <math.h> -#include <assert.h> -#include <string.h> //memcpy -#include "qcmsint.h" -#include "transform_util.h" -#include "matrix.h" - -#if !defined(INFINITY) -#define INFINITY HUGE_VAL -#endif - -#define PARAMETRIC_CURVE_TYPE 0x70617261 //'para' - -/* value must be a value between 0 and 1 */ -//XXX: is the above a good restriction to have? -// the output range of this function is 0..1 -float lut_interp_linear(double input_value, uint16_t *table, size_t length) -{ - int upper, lower; - float value; - input_value = input_value * (length - 1); // scale to length of the array - upper = ceil(input_value); - lower = floor(input_value); - //XXX: can we be more performant here? - value = table[upper]*(1. - (upper - input_value)) + table[lower]*(upper - input_value); - /* scale the value */ - return value * (1.f/65535.f); -} - -/* same as above but takes and returns a uint16_t value representing a range from 0..1 */ -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length) -{ - /* Start scaling input_value to the length of the array: 65535*(length-1). - * We'll divide out the 65535 next */ - uintptr_t value = (input_value * (length - 1)); - uint32_t upper = (value + 65534) / 65535; /* equivalent to ceil(value/65535) */ - uint32_t lower = value / 65535; /* equivalent to floor(value/65535) */ - /* interp is the distance from upper to value scaled to 0..65535 */ - uint32_t interp = value % 65535; - - value = (table[upper]*(interp) + table[lower]*(65535 - interp))/65535; // 0..65535*65535 - - return value; -} - -/* same as above but takes an input_value from 0..PRECACHE_OUTPUT_MAX - * and returns a uint8_t value representing a range from 0..1 */ -static -uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, size_t length) -{ - /* Start scaling input_value to the length of the array: PRECACHE_OUTPUT_MAX*(length-1). - * We'll divide out the PRECACHE_OUTPUT_MAX next */ - uintptr_t value = (input_value * (length - 1)); - - /* equivalent to ceil(value/PRECACHE_OUTPUT_MAX) */ - uint32_t upper = (value + PRECACHE_OUTPUT_MAX-1) / PRECACHE_OUTPUT_MAX; - /* equivalent to floor(value/PRECACHE_OUTPUT_MAX) */ - uint32_t lower = value / PRECACHE_OUTPUT_MAX; - /* interp is the distance from upper to value scaled to 0..PRECACHE_OUTPUT_MAX */ - uint32_t interp = value % PRECACHE_OUTPUT_MAX; - - /* the table values range from 0..65535 */ - value = (table[upper]*(interp) + table[lower]*(PRECACHE_OUTPUT_MAX - interp)); // 0..(65535*PRECACHE_OUTPUT_MAX) - - /* round and scale */ - value += (PRECACHE_OUTPUT_MAX*65535/255)/2; - value /= (PRECACHE_OUTPUT_MAX*65535/255); // scale to 0..255 - return value; -} - -/* value must be a value between 0 and 1 */ -//XXX: is the above a good restriction to have? -float lut_interp_linear_float(float value, float *table, size_t length) -{ - int upper, lower; - value = value * (length - 1); - upper = ceil(value); - lower = floor(value); - //XXX: can we be more performant here? - value = table[upper]*(1. - (upper - value)) + table[lower]*(upper - value); - /* scale the value */ - return value; -} - -#if 0 -/* if we use a different representation i.e. one that goes from 0 to 0x1000 we can be more efficient - * because we can avoid the divisions and use a shifting instead */ -/* same as above but takes and returns a uint16_t value representing a range from 0..1 */ -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length) -{ - uint32_t value = (input_value * (length - 1)); - uint32_t upper = (value + 4095) / 4096; /* equivalent to ceil(value/4096) */ - uint32_t lower = value / 4096; /* equivalent to floor(value/4096) */ - uint32_t interp = value % 4096; - - value = (table[upper]*(interp) + table[lower]*(4096 - interp))/4096; // 0..4096*4096 - - return value; -} -#endif - -void compute_curve_gamma_table_type1(float gamma_table[256], uint16_t gamma) -{ - unsigned int i; - float gamma_float = u8Fixed8Number_to_float(gamma); - for (i = 0; i < 256; i++) { - // 0..1^(0..255 + 255/256) will always be between 0 and 1 - gamma_table[i] = pow(i/255., gamma_float); - } -} - -void compute_curve_gamma_table_type2(float gamma_table[256], uint16_t *table, size_t length) -{ - unsigned int i; - for (i = 0; i < 256; i++) { - gamma_table[i] = lut_interp_linear(i/255., table, length); - } -} - -void compute_curve_gamma_table_type_parametric(float gamma_table[256], float parameter[7], int count) -{ - size_t X; - float interval; - float a, b, c, e, f; - float y = parameter[0]; - if (count == 0) { - a = 1; - b = 0; - c = 0; - e = 0; - f = 0; - interval = -INFINITY; - } else if(count == 1) { - a = parameter[1]; - b = parameter[2]; - c = 0; - e = 0; - f = 0; - interval = -1 * parameter[2] / parameter[1]; - } else if(count == 2) { - a = parameter[1]; - b = parameter[2]; - c = 0; - e = parameter[3]; - f = parameter[3]; - interval = -1 * parameter[2] / parameter[1]; - } else if(count == 3) { - a = parameter[1]; - b = parameter[2]; - c = parameter[3]; - e = -c; - f = 0; - interval = parameter[4]; - } else if(count == 4) { - a = parameter[1]; - b = parameter[2]; - c = parameter[3]; - e = parameter[5] - c; - f = parameter[6]; - interval = parameter[4]; - } else { - assert(0 && "invalid parametric function type."); - a = 1; - b = 0; - c = 0; - e = 0; - f = 0; - interval = -INFINITY; - } - for (X = 0; X < 256; X++) { - float x = X / 255.0; - if (x >= interval) { - // XXX The equations are not exactly as definied in the spec but are - // algebraic equivilent. - // TODO Should division by 255 be for the whole expression. - gamma_table[X] = clamp_float(pow(a * x + b, y) + c + e); - } else { - gamma_table[X] = clamp_float(c * x + f); - } - } -} - -void compute_curve_gamma_table_type0(float gamma_table[256]) -{ - unsigned int i; - for (i = 0; i < 256; i++) { - gamma_table[i] = i/255.; - } -} - -float clamp_float(float a) -{ - /* One would naturally write this function as the following: - if (a > 1.) - return 1.; - else if (a < 0) - return 0; - else - return a; - - However, that version will let NaNs pass through which is undesirable - for most consumers. - */ - - if (a > 1.) - return 1.; - else if (a >= 0) - return a; - else // a < 0 or a is NaN - return 0; -} - -unsigned char clamp_u8(float v) -{ - if (v > 255.) - return 255; - else if (v < 0) - return 0; - else - return floor(v+.5); -} - -float u8Fixed8Number_to_float(uint16_t x) -{ - // 0x0000 = 0. - // 0x0100 = 1. - // 0xffff = 255 + 255/256 - return x/256.; -} - -/* The SSE2 code uses min & max which let NaNs pass through. - We want to try to prevent that here by ensuring that - gamma table is within expected values. */ -void validate_gamma_table(float gamma_table[256]) -{ - int i; - for (i = 0; i < 256; i++) { - // Note: we check that the gamma is not in range - // instead of out of range so that we catch NaNs - if (!(gamma_table[i] >= 0.f && gamma_table[i] <= 1.f)) { - gamma_table[i] = 0.f; - } - } -} - -float *build_input_gamma_table(struct curveType *TRC) -{ - float *gamma_table; - - if (!TRC) return NULL; - gamma_table = malloc(sizeof(float)*256); - if (gamma_table) { - if (TRC->type == PARAMETRIC_CURVE_TYPE) { - compute_curve_gamma_table_type_parametric(gamma_table, TRC->parameter, TRC->count); - } else { - if (TRC->count == 0) { - compute_curve_gamma_table_type0(gamma_table); - } else if (TRC->count == 1) { - compute_curve_gamma_table_type1(gamma_table, TRC->data[0]); - } else { - compute_curve_gamma_table_type2(gamma_table, TRC->data, TRC->count); - } - } - } - - validate_gamma_table(gamma_table); - - return gamma_table; -} - -struct matrix build_colorant_matrix(qcms_profile *p) -{ - struct matrix result; - result.m[0][0] = s15Fixed16Number_to_float(p->redColorant.X); - result.m[0][1] = s15Fixed16Number_to_float(p->greenColorant.X); - result.m[0][2] = s15Fixed16Number_to_float(p->blueColorant.X); - result.m[1][0] = s15Fixed16Number_to_float(p->redColorant.Y); - result.m[1][1] = s15Fixed16Number_to_float(p->greenColorant.Y); - result.m[1][2] = s15Fixed16Number_to_float(p->blueColorant.Y); - result.m[2][0] = s15Fixed16Number_to_float(p->redColorant.Z); - result.m[2][1] = s15Fixed16Number_to_float(p->greenColorant.Z); - result.m[2][2] = s15Fixed16Number_to_float(p->blueColorant.Z); - result.invalid = false; - return result; -} - -/* The following code is copied nearly directly from lcms. - * I think it could be much better. For example, Argyll seems to have better code in - * icmTable_lookup_bwd and icmTable_setup_bwd. However, for now this is a quick way - * to a working solution and allows for easy comparing with lcms. */ -uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int length, int NumZeroes, int NumPoles) -{ - int l = 1; - int r = 0x10000; - int x = 0, res; // 'int' Give spacing for negative values - int cell0, cell1; - double val2; - double y0, y1, x0, x1; - double a, b, f; - - // July/27 2001 - Expanded to handle degenerated curves with an arbitrary - // number of elements containing 0 at the beginning of the table (Zeroes) - // and another arbitrary number of poles (FFFFh) at the end. - - // There are no zeros at the beginning and we are trying to find a zero, so - // return anything. It seems zero would be the less destructive choice - /* I'm not sure that this makes sense, but oh well... */ - if (NumZeroes == 0 && Value == 0) - return 0; - - // Does the curve belong to this case? - if (NumZeroes > 1 || NumPoles > 1) - { - int a, b, sample; - - // Identify if value fall downto 0 or FFFF zone - if (Value == 0) return 0; - // if (Value == 0xFFFF) return 0xFFFF; - sample = (length-1) * ((double) Value * (1./65535.)); - if (LutTable[sample] == 0xffff) - return 0xffff; - - // else restrict to valid zone - - a = ((NumZeroes-1) * 0xFFFF) / (length-1); - b = ((length-1 - NumPoles) * 0xFFFF) / (length-1); - - l = a - 1; - r = b + 1; - - // Ensure a valid binary search range - - if (l < 1) - l = 1; - if (r > 0x10000) - r = 0x10000; - - // If the search range is inverted due to degeneracy, - // deem LutTable non-invertible in this search range. - // Refer to https://bugzil.la/1132467 - - if (r <= l) - return 0; - } - - // For input 0, return that to maintain black level. Note the binary search - // does not. For example, it inverts the standard sRGB gamma curve to 7 at - // the origin, causing a black level error. - - if (Value == 0 && NumZeroes) { - return 0; - } - - // Seems not a degenerated case... apply binary search - - while (r > l) { - - x = (l + r) / 2; - - res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable, length); - - if (res == Value) { - - // Found exact match. - - return (uint16_fract_t) (x - 1); - } - - if (res > Value) r = x - 1; - else l = x + 1; - } - - // Not found, should we interpolate? - - // Get surrounding nodes - - assert(x >= 1); - - val2 = (length-1) * ((double) (x - 1) / 65535.0); - - cell0 = (int) floor(val2); - cell1 = (int) ceil(val2); - - assert(cell0 >= 0); - assert(cell1 >= 0); - assert(cell0 < length); - assert(cell1 < length); - - if (cell0 == cell1) return (uint16_fract_t) x; - - y0 = LutTable[cell0] ; - x0 = (65535.0 * cell0) / (length-1); - - y1 = LutTable[cell1] ; - x1 = (65535.0 * cell1) / (length-1); - - a = (y1 - y0) / (x1 - x0); - b = y0 - a * x0; - - if (fabs(a) < 0.01) return (uint16_fract_t) x; - - f = ((Value - b) / a); - - if (f < 0.0) return (uint16_fract_t) 0; - if (f >= 65535.0) return (uint16_fract_t) 0xFFFF; - - return (uint16_fract_t) floor(f + 0.5); -} - -// December/16 2015 - Moved this code out of lut_inverse_interp16 -// in order to save computation in invert_lut loop. -static void count_zeroes_and_poles(uint16_t *LutTable, int length, int *NumZeroes, int *NumPoles) -{ - int z = 0, p = 0; - - while (LutTable[z] == 0 && z < length - 1) - z++; - *NumZeroes = z; - - while (LutTable[length - 1 - p] == 0xFFFF && p < length - 1) - p++; - *NumPoles = p; -} - -/* - The number of entries needed to invert a lookup table should not - necessarily be the same as the original number of entries. This is - especially true of lookup tables that have a small number of entries. - - For example: - Using a table like: - {0, 3104, 14263, 34802, 65535} - invert_lut will produce an inverse of: - {3, 34459, 47529, 56801, 65535} - which has an maximum error of about 9855 (pixel difference of ~38.346) - - For now, we punt the decision of output size to the caller. */ -static uint16_t *invert_lut(uint16_t *table, int length, size_t out_length) -{ - int NumZeroes; - int NumPoles; - int i; - /* for now we invert the lut by creating a lut of size out_length - * and attempting to lookup a value for each entry using lut_inverse_interp16 */ - uint16_t *output = malloc(sizeof(uint16_t)*out_length); - if (!output) - return NULL; - - // December/16 2015 - Compute the input curve zero and pole extents outside - // the loop and pass them to lut_inverse_interp16. - count_zeroes_and_poles(table, length, &NumZeroes, &NumPoles); - - for (i = 0; i < out_length; i++) { - double x = ((double) i * 65535.) / (double) (out_length - 1); - uint16_fract_t input = floor(x + .5); - output[i] = lut_inverse_interp16(input, table, length, NumZeroes, NumPoles); - } - - return output; -} - -static void compute_precache_pow(uint8_t *output, float gamma) -{ - uint32_t v = 0; - for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) { - //XXX: don't do integer/float conversion... and round? - output[v] = 255. * pow(v/(double)PRECACHE_OUTPUT_MAX, gamma); - } -} - -void compute_precache_lut(uint8_t *output, uint16_t *table, int length) -{ - uint32_t v = 0; - for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) { - output[v] = lut_interp_linear_precache_output(v, table, length); - } -} - -void compute_precache_linear(uint8_t *output) -{ - uint32_t v = 0; - for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) { - //XXX: round? - output[v] = v / (PRECACHE_OUTPUT_SIZE/256); - } -} - -qcms_bool compute_precache(struct curveType *trc, uint8_t *output) -{ - - if (trc->type == PARAMETRIC_CURVE_TYPE) { - float gamma_table[256]; - uint16_t gamma_table_uint[256]; - uint16_t i; - uint16_t *inverted; - int inverted_size = 256; - - compute_curve_gamma_table_type_parametric(gamma_table, trc->parameter, trc->count); - for(i = 0; i < 256; i++) { - gamma_table_uint[i] = (uint16_t)(gamma_table[i] * 65535); - } - - //XXX: the choice of a minimum of 256 here is not backed by any theory, - // measurement or data, howeve r it is what lcms uses. - // the maximum number we would need is 65535 because that's the - // accuracy used for computing the pre cache table - if (inverted_size < 256) - inverted_size = 256; - - inverted = invert_lut(gamma_table_uint, 256, inverted_size); - if (!inverted) - return false; - compute_precache_lut(output, inverted, inverted_size); - free(inverted); - } else { - if (trc->count == 0) { - compute_precache_linear(output); - } else if (trc->count == 1) { - compute_precache_pow(output, 1./u8Fixed8Number_to_float(trc->data[0])); - } else { - uint16_t *inverted; - int inverted_size = trc->count; - //XXX: the choice of a minimum of 256 here is not backed by any theory, - // measurement or data, howeve r it is what lcms uses. - // the maximum number we would need is 65535 because that's the - // accuracy used for computing the pre cache table - if (inverted_size < 256) - inverted_size = 256; - - inverted = invert_lut(trc->data, trc->count, inverted_size); - if (!inverted) - return false; - compute_precache_lut(output, inverted, inverted_size); - free(inverted); - } - } - return true; -} - - -static uint16_t *build_linear_table(int length) -{ - int i; - uint16_t *output = malloc(sizeof(uint16_t)*length); - if (!output) - return NULL; - - for (i = 0; i < length; i++) { - double x = ((double) i * 65535.) / (double) (length - 1); - uint16_fract_t input = floor(x + .5); - output[i] = input; - } - return output; -} - -static uint16_t *build_pow_table(float gamma, int length) -{ - int i; - uint16_t *output = malloc(sizeof(uint16_t)*length); - if (!output) - return NULL; - - for (i = 0; i < length; i++) { - uint16_fract_t result; - double x = ((double) i) / (double) (length - 1); - x = pow(x, gamma); //XXX turn this conversion into a function - result = floor(x*65535. + .5); - output[i] = result; - } - return output; -} - -void build_output_lut(struct curveType *trc, - uint16_t **output_gamma_lut, size_t *output_gamma_lut_length) -{ - if (trc->type == PARAMETRIC_CURVE_TYPE) { - float gamma_table[256]; - uint16_t gamma_table_uint[256]; - uint16_t i; - uint16_t *inverted; - int inverted_size = 4096; - - compute_curve_gamma_table_type_parametric(gamma_table, trc->parameter, trc->count); - for(i = 0; i < 256; i++) { - gamma_table_uint[i] = (uint16_t)(gamma_table[i] * 65535); - } - - //XXX: the choice of a minimum of 256 here is not backed by any theory, - // measurement or data, however it is what lcms uses. - // the maximum number we would need is 65535 because that's the - // accuracy used for computing the pre cache table - inverted = invert_lut(gamma_table_uint, 256, inverted_size); - if (!inverted) - return; - *output_gamma_lut = inverted; - *output_gamma_lut_length = inverted_size; - } else { - if (trc->count == 0) { - *output_gamma_lut = build_linear_table(4096); - *output_gamma_lut_length = 4096; - } else if (trc->count == 1) { - float gamma = 1./u8Fixed8Number_to_float(trc->data[0]); - *output_gamma_lut = build_pow_table(gamma, 4096); - *output_gamma_lut_length = 4096; - } else { - //XXX: the choice of a minimum of 256 here is not backed by any theory, - // measurement or data, however it is what lcms uses. - *output_gamma_lut_length = trc->count; - if (*output_gamma_lut_length < 256) - *output_gamma_lut_length = 256; - - *output_gamma_lut = invert_lut(trc->data, trc->count, *output_gamma_lut_length); - } - } - -} diff --git a/third_party/qcms/src/transform_util.h b/third_party/qcms/src/transform_util.h deleted file mode 100644 index f83477aed6..0000000000 --- a/third_party/qcms/src/transform_util.h +++ /dev/null @@ -1,58 +0,0 @@ -/* vim: set ts=8 sw=8 noexpandtab: */ -// qcms -// Copyright (C) 2009 Mozilla Foundation -// Copyright (C) 1998-2007 Marti Maria -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef _QCMS_TRANSFORM_UTIL_H -#define _QCMS_TRANSFORM_UTIL_H - -#include <stdlib.h> - -#define CLU(table,x,y,z) table[(x*len + y*x_len + z*xy_len)*3] - -//XXX: could use a bettername -typedef uint16_t uint16_fract_t; - -float lut_interp_linear(double input_value, uint16_t *table, size_t length); -float lut_interp_linear_float(float input_value, float *table, size_t length); -uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, size_t length); - - -static inline float lerp(float a, float b, float t) -{ - return a*(1.f-t) + b*t; -} - -unsigned char clamp_u8(float v); -float clamp_float(float a); - -float u8Fixed8Number_to_float(uint16_t x); - - -float *build_input_gamma_table(struct curveType *TRC); -struct matrix build_colorant_matrix(qcms_profile *p); -void build_output_lut(struct curveType *trc, - uint16_t **output_gamma_lut, size_t *output_gamma_lut_length); - -struct matrix matrix_invert(struct matrix mat); -qcms_bool compute_precache(struct curveType *trc, uint8_t *output); - -#endif |