diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-29 18:28:52 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-29 18:28:52 +0000 |
commit | 7396ca286f6332422bcdc080c2a78e9b71840db5 (patch) | |
tree | 73dc46aa666598a2ac14376d7fe3d3ba641194e8 /third_party/qcms | |
parent | f202429bdd316c214b193e1807d9c1161b9fd575 (diff) | |
download | chromium_src-7396ca286f6332422bcdc080c2a78e9b71840db5.zip chromium_src-7396ca286f6332422bcdc080c2a78e9b71840db5.tar.gz chromium_src-7396ca286f6332422bcdc080c2a78e9b71840db5.tar.bz2 |
Remove unused qcms library.
BUG=98460
Review URL: http://codereview.chromium.org/8079005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@103316 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/qcms')
-rw-r--r-- | third_party/qcms/LICENSE | 55 | ||||
-rw-r--r-- | third_party/qcms/Makefile.in | 70 | ||||
-rw-r--r-- | third_party/qcms/README.chromium | 7 | ||||
-rw-r--r-- | third_party/qcms/iccread.c | 822 | ||||
-rw-r--r-- | third_party/qcms/qcms.gyp | 34 | ||||
-rw-r--r-- | third_party/qcms/qcms.h | 153 | ||||
-rw-r--r-- | third_party/qcms/qcmsint.h | 172 | ||||
-rw-r--r-- | third_party/qcms/qcmstypes.h | 84 | ||||
-rw-r--r-- | third_party/qcms/transform-sse1.c | 253 | ||||
-rw-r--r-- | third_party/qcms/transform-sse2.c | 243 | ||||
-rw-r--r-- | third_party/qcms/transform.c | 1372 |
11 files changed, 0 insertions, 3265 deletions
diff --git a/third_party/qcms/LICENSE b/third_party/qcms/LICENSE deleted file mode 100644 index 51de07c..0000000 --- a/third_party/qcms/LICENSE +++ /dev/null @@ -1,55 +0,0 @@ -This license applies to certain files in the directory third_party/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.
-
-
-
-This license applies to the ICC_H block in third_party/qcms/qcms.h.
-
-Copyright (c) 1994-1996 SunSoft, Inc.
-
- Rights Reserved
-
-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 restrict-
-ion, 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 NON-
-INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT
-COMPANY 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.
-
-Except as contained in this notice, the name of SunSoft, Inc.
-shall not be used in advertising or otherwise to promote the
-sale, use or other dealings in this Software without written
-authorization from SunSoft Inc.
diff --git a/third_party/qcms/Makefile.in b/third_party/qcms/Makefile.in deleted file mode 100644 index 4dfd839..0000000 --- a/third_party/qcms/Makefile.in +++ /dev/null @@ -1,70 +0,0 @@ -DEPTH = ../.. -topsrcdir = @top_srcdir@ -srcdir = @srcdir@ -VPATH = @srcdir@ - -include $(DEPTH)/config/autoconf.mk - -MODULE = qcms -LIBRARY_NAME = mozqcms -LIBXUL_LIBRARY = 1 -GRE_MODULE = 1 -DIST_INSTALL = 1 - -EXPORTS = qcms.h qcmstypes.h - -CSRCS = iccread.c transform.c - -ifeq (86,$(findstring 86,$(OS_TEST))) -CSRCS += transform-sse2.c -ifdef _MSC_VER -ifneq ($(OS_ARCH)_$(OS_TEST),WINNT_x86_64) - CSRCS += transform-sse1.c -endif -else - CSRCS += transform-sse1.c -ifdef GNU_CC - SSE1_FLAGS=-msse - SSE2_FLAGS=-msse2 -else -ifeq ($(SOLARIS_SUNPRO_CC),1) -ifneq (64,$(findstring 64,$(OS_TEST))) - SSE1_FLAGS=-xarch=sse - SSE2_FLAGS=-xarch=sse2 -else -# Sun Studio doesn't work correctly for x86 intristics -# with -m64 and without optimization. - SSE1_FLAGS= -xO4 - SSE2_FLAGS= -xO4 -endif -else - SSE1_FLAGS= - SSE2_FLAGS= -endif -endif -endif -endif - -FORCE_STATIC_LIB = 1 -# This library is used by other shared libs -FORCE_USE_PIC = 1 - -include $(topsrcdir)/config/rules.mk - -CFLAGS += -DMOZ_QCMS - -# Disable spammy "missing initializer" GCC warning -ifdef GNU_CC -CFLAGS += -Wno-missing-field-initializers -endif # GNU_CC - -# special rules for transform-sse*.c to get the right cflags. (taken from pixman/src/Makefile.in) -transform-sse1.$(OBJ_SUFFIX): transform-sse1.c $(GLOBAL_DEPS) - $(REPORT_BUILD) - @$(MAKE_DEPS_AUTO_CC) - $(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(SSE1_FLAGS) $(_VPATH_SRCS) - -transform-sse2.$(OBJ_SUFFIX): transform-sse2.c $(GLOBAL_DEPS) - $(REPORT_BUILD) - @$(MAKE_DEPS_AUTO_CC) - $(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(SSE2_FLAGS) $(_VPATH_SRCS) diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium deleted file mode 100644 index a1b19a9..0000000 --- a/third_party/qcms/README.chromium +++ /dev/null @@ -1,7 +0,0 @@ -Name: qcms -URL: http://mxr.mozilla.org/mozilla-central/source/gfx/qcms/ -Version: unknown - -Contain support for apply an ICC color profile to an image. The code is -originally based on tinycms, by re-written by Mozilla for better security and -performance. This copy is a source-drop from Mozilla on November 11, 2010. diff --git a/third_party/qcms/iccread.c b/third_party/qcms/iccread.c deleted file mode 100644 index dc8b365..0000000 --- a/third_party/qcms/iccread.c +++ /dev/null @@ -1,822 +0,0 @@ -// 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> -#include "qcmsint.h" - -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); -} - -#if 0 -static uInt16Number read_uInt16Number(struct mem_source *mem, size_t offset) -{ - return read_u16(mem, offset); -} -#endif - -#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); - //TODO: do the check? - -} - -static void check_profile_version(struct mem_source *src) -{ - uint8_t major_revision = read_u8(src, 8 + 0); - uint8_t minor_revision = read_u8(src, 8 + 1); - uint8_t reserved1 = read_u8(src, 8 + 2); - uint8_t reserved2 = read_u8(src, 8 + 3); - if (major_revision != 0x4) { - if (major_revision > 0x2) - invalid_source(src, "Unsupported major revision"); - if (minor_revision > 0x40) - invalid_source(src, "Unsupported minor revision"); - } - if (reserved1 != 0 || reserved2 != 0) - invalid_source(src, "Invalid reserved bytes"); -} - -#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: - break; - case OUTPUT_DEVICE_PROFILE: - 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"); - } -} - -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 returns -// true if the profile looks bogus and should probably be -// ignored. -qcms_bool qcms_profile_is_bogus(qcms_profile *profile) -{ - float sum[3], target[3], tolerance[3]; - float rX, rY, rZ, gX, gY, gZ, bX, bY, bZ; - bool negative; - unsigned i; - - // We currently only check the bogosity of RGB profiles - if (profile->color_space != RGB_SIGNATURE) - 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); - - // Check if any of the XYZ values are negative (see mozilla bug 498245) - // CIEXYZ tristimulus values cannot be negative according to the spec. - negative = - (rX < 0) || (rY < 0) || (rZ < 0) || - (gX < 0) || (gY < 0) || (gZ < 0) || - (bX < 0) || (bY < 0) || (bZ < 0); - - if (negative) - return true; - - - // Sum the values; they should add up to something close to white - sum[0] = rX + gX + bX; - sum[1] = rY + gY + bY; - sum[2] = rZ + gZ + bZ; - - // Build our target vector (see mozilla bug 460629) - target[0] = 0.96420; - target[1] = 1.00000; - target[2] = 0.82491; - - // Our tolerance vector - Recommended by Chris Murphy based on - // conversion from the LAB space criterion of no more than 3 in any one - // channel. This is similar to, but slightly more tolerant than Adobe's - // criterion. - tolerance[0] = 0.02; - tolerance[1] = 0.02; - tolerance[2] = 0.04; - - // Compare with our tolerance - for (i = 0; i < 3; ++i) { - if (!(((sum[i] - tolerance[i]) <= target[i]) && - ((sum[i] + tolerance[i]) >= target[i]))) - return true; - } - - // All Good - return false; -} - -#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 - -static struct tag *find_tag(struct tag_index index, uint32_t tag_id) -{ - unsigned int i; - struct tag *tag = NULL; - for (i = 0; i < index.count; i++) { - if (index.tags[i].signature == tag_id) { - return &index.tags[i]; - } - } - return tag; -} - -#define XYZ_TYPE 0x58595a20 // 'XYZ ' -#define CURVE_TYPE 0x63757276 // 'curv' -#define LUT16_TYPE 0x6d667432 // 'mft2' -#define LUT8_TYPE 0x6d667431 // 'mft1' - -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; -} - -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 offset = tag->offset; - uint32_t type = read_u32(src, offset); - uint32_t count = read_u32(src, offset+8); - unsigned int i; - - if (type != CURVE_TYPE) { - invalid_source(src, "unexpected type, expected CURV"); - return NULL; - } - -#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; - for (i=0; i<count; i++) { - curve->data[i] = read_u16(src, offset + 12 + i *2); - } - } else { - invalid_source(src, "missing curvetag"); - } - - return curve; -} - -/* This function's not done yet */ -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; - uint32_t clut_size; - struct lutType *lut; - int i; - - num_input_table_entries = read_u16(src, offset + 48); - num_output_table_entries = read_u16(src, offset + 50); - - in_chan = read_u8(src, offset + 8); - out_chan = read_u8(src, offset + 9); - grid_points = read_u8(src, offset + 10); - - if (!src->valid) - return NULL; - - clut_size = in_chan * grid_points * out_chan; -#define MAX_CLUT_SIZE 10000 // arbitrary - if (clut_size > MAX_CLUT_SIZE) { - return NULL; - } - - if (type != LUT16_TYPE && type != LUT8_TYPE) - return NULL; - - lut = malloc(sizeof(struct lutType) + (clut_size + num_input_table_entries + num_output_table_entries)*sizeof(uint8_t)); - if (!lut) - return NULL; - lut->num_input_channels = read_u8(src, offset + 8); - lut->num_output_channels = read_u8(src, offset + 9); - lut->num_clut_grid_points = read_u8(src, offset + 10); - 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); - - //TODO: finish up - 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->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. + 255./256)) - return 0xffff; - else if (a < 0.) - return 0; - else - return floor(a*256. + .5); -} - -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; -} - -static void qcms_profile_fini(qcms_profile *profile) -{ - free(profile->redTRC); - free(profile->blueTRC); - free(profile->greenTRC); - free(profile->grayTRC); - free(profile); -} - -//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; - - //XXX: should store the whitepoint - if (!set_rgb_colorants(profile, white_point, primaries)) { - qcms_profile_fini(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_fini(profile); - return NO_MEM_PROFILE; - } - profile->class = DISPLAY_DEVICE_PROFILE; - profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; - profile->color_space = RGB_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; - - //XXX: should store the whitepoint - if (!set_rgb_colorants(profile, white_point, primaries)) { - qcms_profile_fini(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_fini(profile); - return NO_MEM_PROFILE; - } - profile->class = DISPLAY_DEVICE_PROFILE; - profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; - profile->color_space = RGB_SIGNATURE; - return profile; -} - -/* from lcms: cmsWhitePointFromTemp */ -/* tempK must be >= 4000. and <= 25000. - * similar to argyll: icx_DTEMP2XYZ() */ -static 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 { - assert(0 && "invalid temp"); - } - } - - // 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; - - qcms_CIE_xyYTRIPLE Rec709Primaries = { - {0.6400, 0.3300, 1.0}, - {0.3000, 0.6000, 1.0}, - {0.1500, 0.0600, 1.0} - }; - qcms_CIE_xyY D65; - - D65 = white_point_from_temp(6504); - - table = build_sRGB_gamma_table(1024); - - if (!table) - return NO_MEM_PROFILE; - - profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table, 1024); - 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; - - 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); - check_profile_version(src); - read_class_signature(profile, src); - read_rendering_intent(profile, src); - read_color_space(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 (profile->class == DISPLAY_DEVICE_PROFILE || profile->class == INPUT_DEVICE_PROFILE) { - if (profile->color_space == RGB_SIGNATURE) { - - profile->redColorant = read_tag_XYZType(src, index, TAG_rXYZ); - profile->blueColorant = read_tag_XYZType(src, index, TAG_bXYZ); - profile->greenColorant = read_tag_XYZType(src, index, TAG_gXYZ); - - if (!src->valid) - goto invalid_tag_table; - - profile->redTRC = read_tag_curveType(src, index, TAG_rTRC); - profile->blueTRC = read_tag_curveType(src, index, TAG_bTRC); - profile->greenTRC = read_tag_curveType(src, index, TAG_gTRC); - - 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 { - goto invalid_tag_table; - } - } else if (0 && profile->class == OUTPUT_DEVICE_PROFILE) { - profile->A2B0 = read_tag_lutType(src, index, TAG_A2B0); - } else { - goto invalid_tag_table; - } - - if (!src->valid) - goto invalid_tag_table; - - free(index.tags); - - return profile; - -invalid_tag_table: - free(index.tags); -invalid_profile: - qcms_profile_fini(profile); - return INVALID_PROFILE; -} - -qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) -{ - return profile->rendering_intent; -} - -icColorSpaceSignature -qcms_profile_get_color_space(qcms_profile *profile) -{ - return profile->color_space; -} - -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); - - qcms_profile_fini(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; - - fread(&length_be, sizeof(length), 1, file); - length = be32_to_cpu(length_be); - if (length > MAX_PROFILE_SIZE) - 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; -} diff --git a/third_party/qcms/qcms.gyp b/third_party/qcms/qcms.gyp deleted file mode 100644 index 93fc3ad..0000000 --- a/third_party/qcms/qcms.gyp +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2010 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. - -{ - 'targets': [ - { - 'target_name': 'qcms', - 'type': 'static_library', - 'sources': [ - 'qcms.h', - 'qcmsint.h', - 'qcmstypes.h', - 'iccread.c', - 'transform-sse1.c', - 'transform-sse2.c', - 'transform.c', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - '.', - ], - }, - 'conditions': [ - ['os_posix == 1 and OS != "mac" and (branding == "Chrome" or disable_sse2 == 1)', { - 'sources/': [ - ['exclude', 'transform-sse1.c'], - ['exclude', 'transform-sse2.c'], - ], - },], - ], - }, - ], -} diff --git a/third_party/qcms/qcms.h b/third_party/qcms/qcms.h deleted file mode 100644 index d45e89c..0000000 --- a/third_party/qcms/qcms.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef QCMS_H -#define QCMS_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* if we've already got an ICC_H header we can ignore the following */ -#ifndef ICC_H -/* icc34 defines */ - -/***************************************************************** - Copyright (c) 1994-1996 SunSoft, Inc. - - Rights Reserved - -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 restrict- -ion, 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 NON- -INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT -COMPANY 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. - -Except as contained in this notice, the name of SunSoft, Inc. -shall not be used in advertising or otherwise to promote the -sale, use or other dealings in this Software without written -authorization from SunSoft Inc. -******************************************************************/ - -/* - * Color Space Signatures - * Note that only icSigXYZData and icSigLabData are valid - * Profile Connection Spaces (PCSs) - */ -typedef enum { - icSigXYZData = 0x58595A20L, /* 'XYZ ' */ - icSigLabData = 0x4C616220L, /* 'Lab ' */ - icSigLuvData = 0x4C757620L, /* 'Luv ' */ - icSigYCbCrData = 0x59436272L, /* 'YCbr' */ - icSigYxyData = 0x59787920L, /* 'Yxy ' */ - icSigRgbData = 0x52474220L, /* 'RGB ' */ - icSigGrayData = 0x47524159L, /* 'GRAY' */ - icSigHsvData = 0x48535620L, /* 'HSV ' */ - icSigHlsData = 0x484C5320L, /* 'HLS ' */ - icSigCmykData = 0x434D594BL, /* 'CMYK' */ - icSigCmyData = 0x434D5920L, /* 'CMY ' */ - icSig2colorData = 0x32434C52L, /* '2CLR' */ - icSig3colorData = 0x33434C52L, /* '3CLR' */ - icSig4colorData = 0x34434C52L, /* '4CLR' */ - icSig5colorData = 0x35434C52L, /* '5CLR' */ - icSig6colorData = 0x36434C52L, /* '6CLR' */ - icSig7colorData = 0x37434C52L, /* '7CLR' */ - icSig8colorData = 0x38434C52L, /* '8CLR' */ - icSig9colorData = 0x39434C52L, /* '9CLR' */ - icSig10colorData = 0x41434C52L, /* 'ACLR' */ - icSig11colorData = 0x42434C52L, /* 'BCLR' */ - icSig12colorData = 0x43434C52L, /* 'CCLR' */ - icSig13colorData = 0x44434C52L, /* 'DCLR' */ - icSig14colorData = 0x45434C52L, /* 'ECLR' */ - icSig15colorData = 0x46434C52L, /* 'FCLR' */ - icMaxEnumData = 0xFFFFFFFFL -} icColorSpaceSignature; -#endif - -#include <stdio.h> - -typedef int qcms_bool; - -struct _qcms_transform; -typedef struct _qcms_transform qcms_transform; - -struct _qcms_profile; -typedef struct _qcms_profile qcms_profile; - -/* these values match the Rendering Intent values from the ICC spec */ -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; - -//XXX: I don't really like the _DATA_ prefix -typedef enum { - QCMS_DATA_RGB_8, - QCMS_DATA_RGBA_8, - QCMS_DATA_GRAY_8, - QCMS_DATA_GRAYA_8 -} qcms_data_type; - -/* the names for the following two types are sort of ugly */ -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; - -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); -qcms_profile* qcms_profile_sRGB(void); -void qcms_profile_release(qcms_profile *profile); - -qcms_bool qcms_profile_is_bogus(qcms_profile *profile); -qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile); -icColorSpaceSignature qcms_profile_get_color_space(qcms_profile *profile); - -void qcms_profile_precache_output_transform(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); - -void qcms_transform_release(qcms_transform *); - -void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_t length); - - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/third_party/qcms/qcmsint.h b/third_party/qcms/qcmsint.h deleted file mode 100644 index 217b651..0000000 --- a/third_party/qcms/qcmsint.h +++ /dev/null @@ -1,172 +0,0 @@ -#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 - -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_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); -}; - -typedef int32_t s15Fixed16Number; -typedef uint16_t uInt16Number; - -struct XYZNumber { - s15Fixed16Number X; - s15Fixed16Number Y; - s15Fixed16Number Z; -}; - -struct curveType { - uint32_t count; -/* Using the C99 flexible array member syntax with IBM compiler */ -#if defined (__IBMC__) || defined (__IBMCPP__) - uInt16Number data[]; -#else - uInt16Number data[0]; -#endif -}; - -struct lutType { - 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; - - uint16_t *input_table; - uint16_t *clut_table; - uint16_t *output_table; -}; -#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 - -struct _qcms_profile { - uint32_t class; - uint32_t color_space; - qcms_intent rendering_intent; - 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 precache_output *output_table_r; - struct precache_output *output_table_g; - struct precache_output *output_table_b; -}; - -#ifdef _MSC_VER -#define inline _inline -#endif - -static inline float s15Fixed16Number_to_float(s15Fixed16Number a) -{ - return ((int32_t)a)/65536.; -} - -static inline s15Fixed16Number double_to_s15Fixed16Number(double v) -{ - return (int32_t)(v*65536); -} - -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); -void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length); -void qcms_transform_data_rgb_out_lut_sse1(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length); -void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length); diff --git a/third_party/qcms/qcmstypes.h b/third_party/qcms/qcmstypes.h deleted file mode 100644 index 2d98c0c..0000000 --- a/third_party/qcms/qcmstypes.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef QCMS_TYPES_H -#define QCMS_TYPES_H - -#ifdef MOZ_QCMS - -#include "prtypes.h" - -/* prtypes.h defines IS_LITTLE_ENDIAN and IS_BIG ENDIAN */ - -#if defined (__SVR4) && defined (__sun) -/* int_types.h gets included somehow, so avoid redefining the types differently */ -#include <sys/int_types.h> -#elif defined (_AIX) -#include <sys/types.h> -#elif !defined(ANDROID) -typedef PRInt8 int8_t; -typedef PRUint8 uint8_t; -typedef PRInt16 int16_t; -typedef PRUint16 uint16_t; -typedef PRInt32 int32_t; -typedef PRUint32 uint32_t; -typedef PRInt64 int64_t; -typedef PRUint64 uint64_t; - -#ifdef __OS2__ -/* OS/2's stdlib typdefs uintptr_t. So we'll just include that so we don't collide */ -#include <stdlib.h> -#elif !defined(__intptr_t_defined) && !defined(_UINTPTR_T_DEFINED) -typedef PRUptrdiff uintptr_t; -#endif -#endif - -#else // MOZ_QCMS - -#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) -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 -typedef unsigned long uintptr_t; -#endif - -#elif defined (_AIX) -# include <sys/inttypes.h> -#else -# include <stdint.h> -#endif - -#endif - -typedef qcms_bool bool; -#define true 1 -#define false 0 - -#endif diff --git a/third_party/qcms/transform-sse1.c b/third_party/qcms/transform-sse1.c deleted file mode 100644 index 00707ca..0000000 --- a/third_party/qcms/transform-sse1.c +++ /dev/null @@ -1,253 +0,0 @@ -#include <xmmintrin.h> - -#include "qcmsint.h" - -/* pre-shuffled: just load these into XMM reg instead of load-scalar/shufps sequence */ -#define FLOATSCALE (float)(PRECACHE_OUTPUT_SIZE) -#define CLAMPMAXVAL ( ((float) (PRECACHE_OUTPUT_SIZE - 1)) / PRECACHE_OUTPUT_SIZE ) -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_sse1(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length) -{ - 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; - - /* 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_r, _mm_add_ps(vec_g, 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 */ - *((__m64 *)&output[0]) = _mm_cvtps_pi32(result); - result = _mm_movehl_ps(result, result); - *((__m64 *)&output[2]) = _mm_cvtps_pi32(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[0] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[2] = 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_r, _mm_add_ps(vec_g, 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); - - *((__m64 *)&output[0]) = _mm_cvtps_pi32(result); - result = _mm_movehl_ps(result, result); - *((__m64 *)&output[2]) = _mm_cvtps_pi32(result); - - dest[0] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[2] = otdata_b[output[2]]; - - _mm_empty(); -} - -void qcms_transform_data_rgba_out_lut_sse1(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length) -{ - 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; - 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_r, _mm_add_ps(vec_g, 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 */ - *((__m64 *)&output[0]) = _mm_cvtps_pi32(result); - result = _mm_movehl_ps(result, result); - *((__m64 *)&output[2]) = _mm_cvtps_pi32(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[0] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[2] = 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_r, _mm_add_ps(vec_g, 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); - - *((__m64 *)&output[0]) = _mm_cvtps_pi32(result); - result = _mm_movehl_ps(result, result); - *((__m64 *)&output[2]) = _mm_cvtps_pi32(result); - - dest[0] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[2] = otdata_b[output[2]]; - - _mm_empty(); -} diff --git a/third_party/qcms/transform-sse2.c b/third_party/qcms/transform-sse2.c deleted file mode 100644 index f6e1674..0000000 --- a/third_party/qcms/transform-sse2.c +++ /dev/null @@ -1,243 +0,0 @@ -#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) -#define CLAMPMAXVAL ( ((float) (PRECACHE_OUTPUT_SIZE - 1)) / PRECACHE_OUTPUT_SIZE ) -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) -{ - 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; - - /* 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_r, _mm_add_ps(vec_g, 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[0] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[2] = 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_r, _mm_add_ps(vec_g, 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[0] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[2] = otdata_b[output[2]]; -} - -void qcms_transform_data_rgba_out_lut_sse2(qcms_transform *transform, - unsigned char *src, - unsigned char *dest, - size_t length) -{ - 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; - 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_r, _mm_add_ps(vec_g, 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[0] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[2] = 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_r, _mm_add_ps(vec_g, 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[0] = otdata_r[output[0]]; - dest[1] = otdata_g[output[1]]; - dest[2] = otdata_b[output[2]]; -} - - diff --git a/third_party/qcms/transform.c b/third_party/qcms/transform.c deleted file mode 100644 index 0e7da10..0000000 --- a/third_party/qcms/transform.c +++ /dev/null @@ -1,1372 +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. - -#include <stdlib.h> -#include <math.h> -#include <assert.h> -#include "qcmsint.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 */ - -//XXX: could use a bettername -typedef uint16_t uint16_fract_t; - -/* value must be a value between 0 and 1 */ -//XXX: is the above a good restriction to have? -float lut_interp_linear(double value, uint16_t *table, int length) -{ - int upper, lower; - value = value * (length - 1); // scale to length of the array - 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 * (1./65535.); -} - -/* 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) -{ - /* Start scaling input_value to the length of the array: 65535*(length-1). - * We'll divide out the 65535 next */ - uint32_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, int 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 */ - uint32_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; -} - -#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], double gamma) -{ - unsigned int i; - for (i = 0; i < 256; i++) { - gamma_table[i] = pow(i/255., gamma); - } -} - -void compute_curve_gamma_table_type2(float gamma_table[256], uint16_t *table, int 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_type0(float gamma_table[256]) -{ - unsigned int i; - for (i = 0; i < 256; i++) { - gamma_table[i] = i/255.; - } -} - -unsigned char clamp_u8(float v) -{ - if (v > 255.) - return 255; - else if (v < 0) - return 0; - else - return floor(v+.5); -} - -struct vector { - float v[3]; -}; - -struct matrix { - float m[3][3]; - bool invalid; -}; - -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; -} - -static 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; -} - -float u8Fixed8Number_to_float(uint16_t x) -{ - // 0x0000 = 0. - // 0x0100 = 1. - // 0xffff = 255 + 255/256 - return x/256.; -} - -float *build_input_gamma_table(struct curveType *TRC) -{ - float *gamma_table = malloc(sizeof(float)*256); - if (gamma_table) { - if (TRC->count == 0) { - compute_curve_gamma_table_type0(gamma_table); - } else if (TRC->count == 1) { - compute_curve_gamma_table_type1(gamma_table, u8Fixed8Number_to_float(TRC->data[0])); - } else { - compute_curve_gamma_table_type2(gamma_table, TRC->data, TRC->count); - } - } - 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 l = 1; - int r = 0x10000; - int x = 0, res; // 'int' Give spacing for negative values - int NumZeroes, NumPoles; - 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 begining of the table (Zeroes) - // and another arbitrary number of poles (FFFFh) at the end. - // First the zero and pole extents are computed, then value is compared. - - NumZeroes = 0; - while (LutTable[NumZeroes] == 0 && NumZeroes < length-1) - NumZeroes++; - - // 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; - - NumPoles = 0; - while (LutTable[length-1- NumPoles] == 0xFFFF && NumPoles < length-1) - NumPoles++; - - // Does the curve belong to this case? - if (NumZeroes > 1 || NumPoles > 1) - { - int a, b; - - // Identify if value fall downto 0 or FFFF zone - if (Value == 0) return 0; - // if (Value == 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; - } - - - // 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 - - val2 = (length-1) * ((double) (x - 1) / 65535.0); - - cell0 = (int) floor(val2); - cell1 = (int) ceil(val2); - - 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); - -} - -// 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) -{ - struct matrix lam_rigg = {{ // Bradford matrix - { 0.8951, 0.2664, -0.1614 }, - { -0.7502, 1.7135, 0.0367 }, - { 0.0389, -0.0685, 1.0296 } - }}; - 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_pt) -{ - struct CIE_XYZ Dn; - struct matrix Bradford; - - if (source_white_pt.y == 0.0) - return matrix_invalid(); - - Dn = xyY2XYZ(source_white_pt); - - Bradford = adaption_matrix(Dn, 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 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]); - - return true; -} - -/* - 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, int out_length) -{ - 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; - - 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); - } - return output; -} - -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; -} - -static float clamp_float(float a) -{ - if (a > 1.) - return 1.; - else if (a < 0) - return 0; - else - return a; -} - -#if 0 -static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = clamp_u8(255*out_device_r); - *dest++ = clamp_u8(255*out_device_g); - *dest++ = clamp_u8(255*out_device_b); - } -} -#endif - -static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = clamp_u8(out_device_r*255); - *dest++ = clamp_u8(out_device_g*255); - *dest++ = clamp_u8(out_device_b*255); - } -} - -/* 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) -{ - 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++ = clamp_u8(out_device_r*255); - *dest++ = clamp_u8(out_device_g*255); - *dest++ = clamp_u8(out_device_b*255); - *dest++ = alpha; - } -} - - -static void qcms_transform_data_gray_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = transform->output_table_r->data[gray]; - *dest++ = transform->output_table_g->data[gray]; - *dest++ = transform->output_table_b->data[gray]; - } -} - -static void qcms_transform_data_graya_out_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = transform->output_table_r->data[gray]; - *dest++ = transform->output_table_g->data[gray]; - *dest++ = transform->output_table_b->data[gray]; - *dest++ = alpha; - } -} - -static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = transform->output_table_r->data[r]; - *dest++ = transform->output_table_g->data[g]; - *dest++ = transform->output_table_b->data[b]; - } -} - -static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = transform->output_table_r->data[r]; - *dest++ = transform->output_table_g->data[g]; - *dest++ = transform->output_table_b->data[b]; - *dest++ = alpha; - } -} - -static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = clamp_u8(out_device_r*255); - *dest++ = clamp_u8(out_device_g*255); - *dest++ = clamp_u8(out_device_b*255); - } -} - -static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = clamp_u8(out_device_r*255); - *dest++ = clamp_u8(out_device_g*255); - *dest++ = clamp_u8(out_device_b*255); - *dest++ = alpha; - } -} - -#if 0 -static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length) -{ - 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++ = clamp_u8(out_linear_r*255); - *dest++ = clamp_u8(out_linear_g*255); - *dest++ = clamp_u8(out_linear_b*255); - } -} -#endif - -static struct precache_output *precache_reference(struct precache_output *p) -{ - 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 (--p->ref_count == 0) { - free(p); - } -} - -#ifdef HAS_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); -} - -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->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, however it is what lcms uses. - // the maximum number we would need is 65535 because that's the accuracy used for computing the precache 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; -} - -#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 - -void build_output_lut(struct curveType *trc, - uint16_t **output_gamma_lut, size_t *output_gamma_lut_length) -{ - 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); - } - -} - -void qcms_profile_precache_output_transform(qcms_profile *profile) -{ - /* we only support precaching on rgb profiles */ - if (profile->color_space != RGB_SIGNATURE) - 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; - } - } -} - -#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) -{ - bool precache = false; - - qcms_transform *transform = transform_alloc(); - if (!transform) { - return NULL; - } - if (out_type != QCMS_DATA_RGB_8 && - out_type != QCMS_DATA_RGBA_8) { - assert(0 && "output type"); - transform_free(transform); - return NULL; - } - - if (out->output_table_r && - out->output_table_g && - out->output_table_b) { - precache = true; - } - - 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 { - 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"); - transform_free(transform); - return NULL; - } - if (precache) { -#ifdef X86 - 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; - -#if !(defined(_MSC_VER) && defined(_M_AMD64)) - /* Microsoft Compiler for x64 doesn't support MMX. - * SSE code uses MMX so that we disable on x64 */ - } else - if (sse_version_available() >= 1) { - if (in_type == QCMS_DATA_RGB_8) - transform->transform_fn = qcms_transform_data_rgb_out_lut_sse1; - else - transform->transform_fn = qcms_transform_data_rgba_out_lut_sse1; -#endif - } 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); - - /* 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]; - - } else if (in->color_space == GRAY_SIGNATURE) { - if (in_type != QCMS_DATA_GRAY_8 && - in_type != QCMS_DATA_GRAYA_8){ - assert(0 && "input type"); - transform_free(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 NO_MEM_TRANSFORM; - } - return transform; -} - -#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__) -/* 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) -{ - transform->transform_fn(transform, src, dest, length); -} |