mirror of
https://github.com/love2d/love-android.git
synced 2026-08-20 04:31:26 +02:00
added dependencies and build files (loosely inspired by Sebastian Dorda's love-native-android)
This commit is contained in:
@@ -0,0 +1,583 @@
|
||||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# src/Makefile. Generated from Makefile.in by configure.
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||
# Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Makefile for building lcms 2 library
|
||||
#
|
||||
|
||||
|
||||
pkgdatadir = $(datadir)/lcms2
|
||||
pkgincludedir = $(includedir)/lcms2
|
||||
pkglibdir = $(libdir)/lcms2
|
||||
pkglibexecdir = $(libexecdir)/lcms2
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = i686-pc-linux-gnu
|
||||
host_triplet = i686-pc-linux-gnu
|
||||
subdir = src
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__installdirs = "$(DESTDIR)$(libdir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
am__DEPENDENCIES_1 =
|
||||
liblcms2_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
|
||||
am_liblcms2_la_OBJECTS = cmscnvrt.lo cmserr.lo cmsgamma.lo cmsgmt.lo \
|
||||
cmsintrp.lo cmsio0.lo cmsio1.lo cmslut.lo cmsplugin.lo \
|
||||
cmssm.lo cmsmd5.lo cmsmtrx.lo cmspack.lo cmspcs.lo cmswtpnt.lo \
|
||||
cmsxform.lo cmssamp.lo cmsnamed.lo cmscam02.lo cmsvirt.lo \
|
||||
cmstypes.lo cmscgats.lo cmsps2.lo cmsopt.lo
|
||||
liblcms2_la_OBJECTS = $(am_liblcms2_la_OBJECTS)
|
||||
liblcms2_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(liblcms2_la_LDFLAGS) $(LDFLAGS) -o $@
|
||||
DEFAULT_INCLUDES = -I.
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(liblcms2_la_SOURCES)
|
||||
DIST_SOURCES = $(liblcms2_la_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = ${SHELL} /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/missing --run aclocal-1.11
|
||||
AMTAR = ${SHELL} /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/missing --run tar
|
||||
AR = ar
|
||||
AS = as
|
||||
AUTOCONF = ${SHELL} /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/missing --run autoconf
|
||||
AUTOHEADER = ${SHELL} /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/missing --run autoheader
|
||||
AUTOMAKE = ${SHELL} /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/missing --run automake-1.11
|
||||
AWK = gawk
|
||||
CC = gcc -std=gnu99
|
||||
CCDEPMODE = depmode=gcc3
|
||||
CFLAGS = -g -O2
|
||||
CPP = gcc -std=gnu99 -E
|
||||
CPPFLAGS =
|
||||
CXX = g++
|
||||
CXXCPP = g++ -E
|
||||
CXXDEPMODE = depmode=gcc3
|
||||
CXXFLAGS = -g -O2
|
||||
CYGPATH_W = echo
|
||||
DEFS = -DPACKAGE_NAME=\"lcms2\" -DPACKAGE_TARNAME=\"lcms2\" -DPACKAGE_VERSION=\"2.2\" -DPACKAGE_STRING=\"lcms2\ 2.2\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -DHasJPEG=1 -DHasZLIB=1 -DHasTIFF=1 -DHAVE_TIFFCONF_H=1
|
||||
DEPDIR = .deps
|
||||
DLLTOOL = dlltool
|
||||
DSYMUTIL =
|
||||
DUMPBIN =
|
||||
ECHO_C =
|
||||
ECHO_N = -n
|
||||
ECHO_T =
|
||||
EGREP = /bin/grep -E
|
||||
EXEEXT =
|
||||
FGREP = /bin/grep -F
|
||||
GREP = /bin/grep
|
||||
INSTALL = /usr/bin/install -c
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
INSTALL_PROGRAM = ${INSTALL}
|
||||
INSTALL_SCRIPT = ${INSTALL}
|
||||
INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
|
||||
JPEGICC_DEPLIBS = -ljpeg -lm
|
||||
LCMS_LIB_DEPLIBS = -lm
|
||||
LD = /usr/bin/ld
|
||||
LDFLAGS =
|
||||
LIBOBJS =
|
||||
LIBRARY_AGE = 0
|
||||
LIBRARY_CURRENT = 2
|
||||
LIBRARY_REVISION = 2
|
||||
LIBS =
|
||||
LIBTOOL = $(SHELL) $(top_builddir)/libtool
|
||||
LIBTOOL_DEPS = ./ltmain.sh
|
||||
LIB_JPEG = -ljpeg
|
||||
LIB_MATH = -lm
|
||||
LIB_TIFF = -ltiff
|
||||
LIB_ZLIB = -lz
|
||||
LIPO =
|
||||
LN_S = ln -s
|
||||
LTLIBOBJS =
|
||||
MAINT = #
|
||||
MAKEINFO = ${SHELL} /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/missing --run makeinfo
|
||||
MANIFEST_TOOL = :
|
||||
MKDIR_P = /bin/mkdir -p
|
||||
NM = /usr/bin/nm -B
|
||||
NMEDIT =
|
||||
OBJDUMP = objdump
|
||||
OBJEXT = o
|
||||
OTOOL =
|
||||
OTOOL64 =
|
||||
PACKAGE = lcms2
|
||||
PACKAGE_BUGREPORT =
|
||||
PACKAGE_NAME = lcms2
|
||||
PACKAGE_STRING = lcms2 2.2
|
||||
PACKAGE_TARNAME = lcms2
|
||||
PACKAGE_URL =
|
||||
PACKAGE_VERSION = 2.2
|
||||
PATH_SEPARATOR = :
|
||||
RANLIB = ranlib
|
||||
SED = /bin/sed
|
||||
SET_MAKE =
|
||||
SHELL = /bin/bash
|
||||
STRIP = strip
|
||||
TIFFICC_DEPLIBS = -ltiff -ljpeg -lz -lm
|
||||
VERSION = 2.2
|
||||
abs_builddir = /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/src
|
||||
abs_srcdir = /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/src
|
||||
abs_top_builddir = /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2
|
||||
abs_top_srcdir = /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2
|
||||
ac_ct_AR = ar
|
||||
ac_ct_CC = gcc
|
||||
ac_ct_CXX = g++
|
||||
ac_ct_DUMPBIN =
|
||||
am__include = include
|
||||
am__leading_dot = .
|
||||
am__quote =
|
||||
am__tar = ${AMTAR} chof - "$$tardir"
|
||||
am__untar = ${AMTAR} xf -
|
||||
bindir = ${exec_prefix}/bin
|
||||
build = i686-pc-linux-gnu
|
||||
build_alias =
|
||||
build_cpu = i686
|
||||
build_os = linux-gnu
|
||||
build_vendor = pc
|
||||
builddir = .
|
||||
datadir = ${datarootdir}
|
||||
datarootdir = ${prefix}/share
|
||||
docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
|
||||
dvidir = ${docdir}
|
||||
exec_prefix = ${prefix}
|
||||
host = i686-pc-linux-gnu
|
||||
host_alias =
|
||||
host_cpu = i686
|
||||
host_os = linux-gnu
|
||||
host_vendor = pc
|
||||
htmldir = ${docdir}
|
||||
|
||||
# CFLAGS = -pedantic -Wall -std=c99 -O3
|
||||
includedir = ${prefix}/include
|
||||
infodir = ${datarootdir}/info
|
||||
inline =
|
||||
install_sh = ${SHELL} /home/hagish/workspace/adt/love-native-android/jni/lcms2-2.2/install-sh
|
||||
libdir = ${exec_prefix}/lib
|
||||
libexecdir = ${exec_prefix}/libexec
|
||||
localedir = ${datarootdir}/locale
|
||||
localstatedir = ${prefix}/var
|
||||
mandir = ${datarootdir}/man
|
||||
mkdir_p = /bin/mkdir -p
|
||||
oldincludedir = /usr/include
|
||||
pdfdir = ${docdir}
|
||||
prefix = /usr/local
|
||||
program_transform_name = s,x,x,
|
||||
psdir = ${docdir}
|
||||
sbindir = ${exec_prefix}/sbin
|
||||
sharedstatedir = ${prefix}/com
|
||||
srcdir = .
|
||||
sysconfdir = ${prefix}/etc
|
||||
target_alias =
|
||||
top_build_prefix = ../
|
||||
top_builddir = ..
|
||||
top_srcdir = ..
|
||||
|
||||
# Don't require all the GNU mandated files
|
||||
AUTOMAKE_OPTIONS = 1.7 foreign
|
||||
|
||||
# Shared libraries built in this directory
|
||||
lib_LTLIBRARIES = liblcms2.la
|
||||
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
liblcms2_la_LDFLAGS = -no-undefined \
|
||||
-version-info $(LIBRARY_CURRENT):$(LIBRARY_REVISION):$(LIBRARY_AGE)
|
||||
|
||||
liblcms2_la_LIBADD = $(LCMS_LIB_DEPLIBS)
|
||||
liblcms2_la_SOURCES = \
|
||||
cmscnvrt.c cmserr.c cmsgamma.c cmsgmt.c cmsintrp.c cmsio0.c cmsio1.c cmslut.c \
|
||||
cmsplugin.c cmssm.c cmsmd5.c cmsmtrx.c cmspack.c cmspcs.c cmswtpnt.c cmsxform.c \
|
||||
cmssamp.c cmsnamed.c cmscam02.c cmsvirt.c cmstypes.c cmscgats.c cmsps2.c cmsopt.c \
|
||||
lcms2_internal.h
|
||||
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: # $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign src/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: # $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): # $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
list2=; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
list2="$$list2 $$p"; \
|
||||
else :; fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
|
||||
}
|
||||
|
||||
uninstall-libLTLIBRARIES:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
|
||||
done
|
||||
|
||||
clean-libLTLIBRARIES:
|
||||
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
|
||||
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
liblcms2.la: $(liblcms2_la_OBJECTS) $(liblcms2_la_DEPENDENCIES)
|
||||
$(liblcms2_la_LINK) -rpath $(libdir) $(liblcms2_la_OBJECTS) $(liblcms2_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
include ./$(DEPDIR)/cmscam02.Plo
|
||||
include ./$(DEPDIR)/cmscgats.Plo
|
||||
include ./$(DEPDIR)/cmscnvrt.Plo
|
||||
include ./$(DEPDIR)/cmserr.Plo
|
||||
include ./$(DEPDIR)/cmsgamma.Plo
|
||||
include ./$(DEPDIR)/cmsgmt.Plo
|
||||
include ./$(DEPDIR)/cmsintrp.Plo
|
||||
include ./$(DEPDIR)/cmsio0.Plo
|
||||
include ./$(DEPDIR)/cmsio1.Plo
|
||||
include ./$(DEPDIR)/cmslut.Plo
|
||||
include ./$(DEPDIR)/cmsmd5.Plo
|
||||
include ./$(DEPDIR)/cmsmtrx.Plo
|
||||
include ./$(DEPDIR)/cmsnamed.Plo
|
||||
include ./$(DEPDIR)/cmsopt.Plo
|
||||
include ./$(DEPDIR)/cmspack.Plo
|
||||
include ./$(DEPDIR)/cmspcs.Plo
|
||||
include ./$(DEPDIR)/cmsplugin.Plo
|
||||
include ./$(DEPDIR)/cmsps2.Plo
|
||||
include ./$(DEPDIR)/cmssamp.Plo
|
||||
include ./$(DEPDIR)/cmssm.Plo
|
||||
include ./$(DEPDIR)/cmstypes.Plo
|
||||
include ./$(DEPDIR)/cmsvirt.Plo
|
||||
include ./$(DEPDIR)/cmswtpnt.Plo
|
||||
include ./$(DEPDIR)/cmsxform.Plo
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
# source='$<' object='$@' libtool=no \
|
||||
# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
|
||||
# $(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
# source='$<' object='$@' libtool=no \
|
||||
# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
|
||||
# $(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
# source='$<' object='$@' libtool=yes \
|
||||
# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
|
||||
# $(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-libLTLIBRARIES
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-libLTLIBRARIES
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libLTLIBRARIES clean-libtool ctags distclean \
|
||||
distclean-compile distclean-generic distclean-libtool \
|
||||
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am \
|
||||
install-libLTLIBRARIES install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags uninstall uninstall-am uninstall-libLTLIBRARIES
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Makefile for building lcms 2 library
|
||||
#
|
||||
|
||||
# Don't require all the GNU mandated files
|
||||
AUTOMAKE_OPTIONS = 1.7 foreign
|
||||
|
||||
# CFLAGS = -pedantic -Wall -std=c99 -O3
|
||||
|
||||
includedir = ${prefix}/include
|
||||
|
||||
# Shared libraries built in this directory
|
||||
lib_LTLIBRARIES = liblcms2.la
|
||||
|
||||
LIBRARY_CURRENT = @LIBRARY_CURRENT@
|
||||
LIBRARY_REVISION = @LIBRARY_REVISION@
|
||||
LIBRARY_AGE = @LIBRARY_AGE@
|
||||
|
||||
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
|
||||
liblcms2_la_LDFLAGS = -no-undefined \
|
||||
-version-info $(LIBRARY_CURRENT):$(LIBRARY_REVISION):$(LIBRARY_AGE)
|
||||
|
||||
liblcms2_la_LIBADD = $(LCMS_LIB_DEPLIBS)
|
||||
|
||||
liblcms2_la_SOURCES = \
|
||||
cmscnvrt.c cmserr.c cmsgamma.c cmsgmt.c cmsintrp.c cmsio0.c cmsio1.c cmslut.c \
|
||||
cmsplugin.c cmssm.c cmsmd5.c cmsmtrx.c cmspack.c cmspcs.c cmswtpnt.c cmsxform.c \
|
||||
cmssamp.c cmsnamed.c cmscam02.c cmsvirt.c cmstypes.c cmscgats.c cmsps2.c cmsopt.c \
|
||||
lcms2_internal.h
|
||||
|
||||
@@ -0,0 +1,583 @@
|
||||
# Makefile.in generated by automake 1.11.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
|
||||
# Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
#
|
||||
# Makefile for building lcms 2 library
|
||||
#
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = src
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__installdirs = "$(DESTDIR)$(libdir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
am__DEPENDENCIES_1 =
|
||||
liblcms2_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
|
||||
am_liblcms2_la_OBJECTS = cmscnvrt.lo cmserr.lo cmsgamma.lo cmsgmt.lo \
|
||||
cmsintrp.lo cmsio0.lo cmsio1.lo cmslut.lo cmsplugin.lo \
|
||||
cmssm.lo cmsmd5.lo cmsmtrx.lo cmspack.lo cmspcs.lo cmswtpnt.lo \
|
||||
cmsxform.lo cmssamp.lo cmsnamed.lo cmscam02.lo cmsvirt.lo \
|
||||
cmstypes.lo cmscgats.lo cmsps2.lo cmsopt.lo
|
||||
liblcms2_la_OBJECTS = $(am_liblcms2_la_OBJECTS)
|
||||
liblcms2_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(liblcms2_la_LDFLAGS) $(LDFLAGS) -o $@
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(liblcms2_la_SOURCES)
|
||||
DIST_SOURCES = $(liblcms2_la_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AS = @AS@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
JPEGICC_DEPLIBS = @JPEGICC_DEPLIBS@
|
||||
LCMS_LIB_DEPLIBS = @LCMS_LIB_DEPLIBS@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBRARY_AGE = @LIBRARY_AGE@
|
||||
LIBRARY_CURRENT = @LIBRARY_CURRENT@
|
||||
LIBRARY_REVISION = @LIBRARY_REVISION@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIBTOOL_DEPS = @LIBTOOL_DEPS@
|
||||
LIB_JPEG = @LIB_JPEG@
|
||||
LIB_MATH = @LIB_MATH@
|
||||
LIB_TIFF = @LIB_TIFF@
|
||||
LIB_ZLIB = @LIB_ZLIB@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
TIFFICC_DEPLIBS = @TIFFICC_DEPLIBS@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
|
||||
# CFLAGS = -pedantic -Wall -std=c99 -O3
|
||||
includedir = ${prefix}/include
|
||||
infodir = @infodir@
|
||||
inline = @inline@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
# Don't require all the GNU mandated files
|
||||
AUTOMAKE_OPTIONS = 1.7 foreign
|
||||
|
||||
# Shared libraries built in this directory
|
||||
lib_LTLIBRARIES = liblcms2.la
|
||||
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
liblcms2_la_LDFLAGS = -no-undefined \
|
||||
-version-info $(LIBRARY_CURRENT):$(LIBRARY_REVISION):$(LIBRARY_AGE)
|
||||
|
||||
liblcms2_la_LIBADD = $(LCMS_LIB_DEPLIBS)
|
||||
liblcms2_la_SOURCES = \
|
||||
cmscnvrt.c cmserr.c cmsgamma.c cmsgmt.c cmsintrp.c cmsio0.c cmsio1.c cmslut.c \
|
||||
cmsplugin.c cmssm.c cmsmd5.c cmsmtrx.c cmspack.c cmspcs.c cmswtpnt.c cmsxform.c \
|
||||
cmssamp.c cmsnamed.c cmscam02.c cmsvirt.c cmstypes.c cmscgats.c cmsps2.c cmsopt.c \
|
||||
lcms2_internal.h
|
||||
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign src/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
list2=; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
list2="$$list2 $$p"; \
|
||||
else :; fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
|
||||
}
|
||||
|
||||
uninstall-libLTLIBRARIES:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
|
||||
done
|
||||
|
||||
clean-libLTLIBRARIES:
|
||||
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
|
||||
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
liblcms2.la: $(liblcms2_la_OBJECTS) $(liblcms2_la_DEPENDENCIES)
|
||||
$(liblcms2_la_LINK) -rpath $(libdir) $(liblcms2_la_OBJECTS) $(liblcms2_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmscam02.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmscgats.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmscnvrt.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmserr.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsgamma.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsgmt.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsintrp.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsio0.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsio1.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmslut.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsmd5.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsmtrx.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsnamed.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsopt.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmspack.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmspcs.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsplugin.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsps2.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmssamp.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmssm.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmstypes.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsvirt.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmswtpnt.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmsxform.Plo@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-libLTLIBRARIES
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-libLTLIBRARIES
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libLTLIBRARIES clean-libtool ctags distclean \
|
||||
distclean-compile distclean-generic distclean-libtool \
|
||||
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am \
|
||||
install-libLTLIBRARIES install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags uninstall uninstall-am uninstall-libLTLIBRARIES
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
@@ -0,0 +1,483 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
// CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging.
|
||||
|
||||
// ---------- Implementation --------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
|
||||
cmsFloat64Number XYZ[3];
|
||||
cmsFloat64Number RGB[3];
|
||||
cmsFloat64Number RGBc[3];
|
||||
cmsFloat64Number RGBp[3];
|
||||
cmsFloat64Number RGBpa[3];
|
||||
cmsFloat64Number a, b, h, e, H, A, J, Q, s, t, C, M;
|
||||
cmsFloat64Number abC[2];
|
||||
cmsFloat64Number abs[2];
|
||||
cmsFloat64Number abM[2];
|
||||
|
||||
} CAM02COLOR;
|
||||
|
||||
typedef struct {
|
||||
|
||||
CAM02COLOR adoptedWhite;
|
||||
cmsFloat64Number LA, Yb;
|
||||
cmsFloat64Number F, c, Nc;
|
||||
cmsUInt32Number surround;
|
||||
cmsFloat64Number n, Nbb, Ncb, z, FL, D;
|
||||
|
||||
cmsContext ContextID;
|
||||
|
||||
} cmsCIECAM02;
|
||||
|
||||
|
||||
static
|
||||
cmsFloat64Number compute_n(cmsCIECAM02* pMod)
|
||||
{
|
||||
return (pMod -> Yb / pMod -> adoptedWhite.XYZ[1]);
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number compute_z(cmsCIECAM02* pMod)
|
||||
{
|
||||
return (1.48 + pow(pMod -> n, 0.5));
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number computeNbb(cmsCIECAM02* pMod)
|
||||
{
|
||||
return (0.725 * pow((1.0 / pMod -> n), 0.2));
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number computeFL(cmsCIECAM02* pMod)
|
||||
{
|
||||
cmsFloat64Number k, FL;
|
||||
|
||||
k = 1.0 / ((5.0 * pMod->LA) + 1.0);
|
||||
FL = 0.2 * pow(k, 4.0) * (5.0 * pMod->LA) + 0.1 *
|
||||
(pow((1.0 - pow(k, 4.0)), 2.0)) *
|
||||
(pow((5.0 * pMod->LA), (1.0 / 3.0)));
|
||||
|
||||
return FL;
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number computeD(cmsCIECAM02* pMod)
|
||||
{
|
||||
cmsFloat64Number D;
|
||||
|
||||
D = pMod->F - (1.0/3.6)*(exp(((-pMod ->LA-42) / 92.0)));
|
||||
|
||||
return D;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
CAM02COLOR XYZtoCAT02(CAM02COLOR clr)
|
||||
{
|
||||
clr.RGB[0] = (clr.XYZ[0] * 0.7328) + (clr.XYZ[1] * 0.4296) + (clr.XYZ[2] * -0.1624);
|
||||
clr.RGB[1] = (clr.XYZ[0] * -0.7036) + (clr.XYZ[1] * 1.6975) + (clr.XYZ[2] * 0.0061);
|
||||
clr.RGB[2] = (clr.XYZ[0] * 0.0030) + (clr.XYZ[1] * 0.0136) + (clr.XYZ[2] * 0.9834);
|
||||
|
||||
return clr;
|
||||
}
|
||||
|
||||
static
|
||||
CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod)
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
clr.RGBc[i] = ((pMod -> adoptedWhite.XYZ[1] *
|
||||
(pMod->D / pMod -> adoptedWhite.RGB[i])) +
|
||||
(1.0 - pMod->D)) * clr.RGB[i];
|
||||
}
|
||||
|
||||
return clr;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
CAM02COLOR CAT02toHPE(CAM02COLOR clr)
|
||||
{
|
||||
cmsFloat64Number M[9];
|
||||
|
||||
M[0] =(( 0.38971 * 1.096124) + (0.68898 * 0.454369) + (-0.07868 * -0.009628));
|
||||
M[1] =(( 0.38971 * -0.278869) + (0.68898 * 0.473533) + (-0.07868 * -0.005698));
|
||||
M[2] =(( 0.38971 * 0.182745) + (0.68898 * 0.072098) + (-0.07868 * 1.015326));
|
||||
M[3] =((-0.22981 * 1.096124) + (1.18340 * 0.454369) + ( 0.04641 * -0.009628));
|
||||
M[4] =((-0.22981 * -0.278869) + (1.18340 * 0.473533) + ( 0.04641 * -0.005698));
|
||||
M[5] =((-0.22981 * 0.182745) + (1.18340 * 0.072098) + ( 0.04641 * 1.015326));
|
||||
M[6] =(-0.009628);
|
||||
M[7] =(-0.005698);
|
||||
M[8] =( 1.015326);
|
||||
|
||||
clr.RGBp[0] = (clr.RGBc[0] * M[0]) + (clr.RGBc[1] * M[1]) + (clr.RGBc[2] * M[2]);
|
||||
clr.RGBp[1] = (clr.RGBc[0] * M[3]) + (clr.RGBc[1] * M[4]) + (clr.RGBc[2] * M[5]);
|
||||
clr.RGBp[2] = (clr.RGBc[0] * M[6]) + (clr.RGBc[1] * M[7]) + (clr.RGBc[2] * M[8]);
|
||||
|
||||
return clr;
|
||||
}
|
||||
|
||||
static
|
||||
CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod)
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
cmsFloat64Number temp;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (clr.RGBp[i] < 0) {
|
||||
|
||||
temp = pow((-1.0 * pMod->FL * clr.RGBp[i] / 100.0), 0.42);
|
||||
clr.RGBpa[i] = (-1.0 * 400.0 * temp) / (temp + 27.13) + 0.1;
|
||||
}
|
||||
else {
|
||||
temp = pow((pMod->FL * clr.RGBp[i] / 100.0), 0.42);
|
||||
clr.RGBpa[i] = (400.0 * temp) / (temp + 27.13) + 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] +
|
||||
(clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb;
|
||||
|
||||
return clr;
|
||||
}
|
||||
|
||||
static
|
||||
CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod)
|
||||
{
|
||||
cmsFloat64Number a, b, temp, e, t, r2d, d2r;
|
||||
|
||||
a = clr.RGBpa[0] - (12.0 * clr.RGBpa[1] / 11.0) + (clr.RGBpa[2] / 11.0);
|
||||
b = (clr.RGBpa[0] + clr.RGBpa[1] - (2.0 * clr.RGBpa[2])) / 9.0;
|
||||
|
||||
r2d = (180.0 / 3.141592654);
|
||||
if (a == 0) {
|
||||
if (b == 0) clr.h = 0;
|
||||
else if (b > 0) clr.h = 90;
|
||||
else clr.h = 270;
|
||||
}
|
||||
else if (a > 0) {
|
||||
temp = b / a;
|
||||
if (b > 0) clr.h = (r2d * atan(temp));
|
||||
else if (b == 0) clr.h = 0;
|
||||
else clr.h = (r2d * atan(temp)) + 360;
|
||||
}
|
||||
else {
|
||||
temp = b / a;
|
||||
clr.h = (r2d * atan(temp)) + 180;
|
||||
}
|
||||
|
||||
d2r = (3.141592654 / 180.0);
|
||||
e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) *
|
||||
(cos((clr.h * d2r + 2.0)) + 3.8);
|
||||
|
||||
if (clr.h < 20.14) {
|
||||
temp = ((clr.h + 122.47)/1.2) + ((20.14 - clr.h)/0.8);
|
||||
clr.H = 300 + (100*((clr.h + 122.47)/1.2)) / temp;
|
||||
}
|
||||
else if (clr.h < 90.0) {
|
||||
temp = ((clr.h - 20.14)/0.8) + ((90.00 - clr.h)/0.7);
|
||||
clr.H = (100*((clr.h - 20.14)/0.8)) / temp;
|
||||
}
|
||||
else if (clr.h < 164.25) {
|
||||
temp = ((clr.h - 90.00)/0.7) + ((164.25 - clr.h)/1.0);
|
||||
clr.H = 100 + ((100*((clr.h - 90.00)/0.7)) / temp);
|
||||
}
|
||||
else if (clr.h < 237.53) {
|
||||
temp = ((clr.h - 164.25)/1.0) + ((237.53 - clr.h)/1.2);
|
||||
clr.H = 200 + ((100*((clr.h - 164.25)/1.0)) / temp);
|
||||
}
|
||||
else {
|
||||
temp = ((clr.h - 237.53)/1.2) + ((360 - clr.h + 20.14)/0.8);
|
||||
clr.H = 300 + ((100*((clr.h - 237.53)/1.2)) / temp);
|
||||
}
|
||||
|
||||
clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A),
|
||||
(pMod->c * pMod->z));
|
||||
|
||||
clr.Q = (4.0 / pMod->c) * pow((clr.J / 100.0), 0.5) *
|
||||
(pMod->adoptedWhite.A + 4.0) * pow(pMod->FL, 0.25);
|
||||
|
||||
t = (e * pow(((a * a) + (b * b)), 0.5)) /
|
||||
(clr.RGBpa[0] + clr.RGBpa[1] +
|
||||
((21.0 / 20.0) * clr.RGBpa[2]));
|
||||
|
||||
clr.C = pow(t, 0.9) * pow((clr.J / 100.0), 0.5) *
|
||||
pow((1.64 - pow(0.29, pMod->n)), 0.73);
|
||||
|
||||
clr.M = clr.C * pow(pMod->FL, 0.25);
|
||||
clr.s = 100.0 * pow((clr.M / clr.Q), 0.5);
|
||||
|
||||
return clr;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod)
|
||||
{
|
||||
|
||||
cmsFloat64Number t, e, p1, p2, p3, p4, p5, hr, d2r;
|
||||
d2r = 3.141592654 / 180.0;
|
||||
|
||||
t = pow( (clr.C / (pow((clr.J / 100.0), 0.5) *
|
||||
(pow((1.64 - pow(0.29, pMod->n)), 0.73)))),
|
||||
(1.0 / 0.9) );
|
||||
e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) *
|
||||
(cos((clr.h * d2r + 2.0)) + 3.8);
|
||||
|
||||
clr.A = pMod->adoptedWhite.A * pow(
|
||||
(clr.J / 100.0),
|
||||
(1.0 / (pMod->c * pMod->z)));
|
||||
|
||||
p1 = e / t;
|
||||
p2 = (clr.A / pMod->Nbb) + 0.305;
|
||||
p3 = 21.0 / 20.0;
|
||||
|
||||
hr = clr.h * d2r;
|
||||
|
||||
if (fabs(sin(hr)) >= fabs(cos(hr))) {
|
||||
p4 = p1 / sin(hr);
|
||||
clr.b = (p2 * (2.0 + p3) * (460.0 / 1403.0)) /
|
||||
(p4 + (2.0 + p3) * (220.0 / 1403.0) *
|
||||
(cos(hr) / sin(hr)) - (27.0 / 1403.0) +
|
||||
p3 * (6300.0 / 1403.0));
|
||||
clr.a = clr.b * (cos(hr) / sin(hr));
|
||||
}
|
||||
else {
|
||||
p5 = p1 / cos(hr);
|
||||
clr.a = (p2 * (2.0 + p3) * (460.0 / 1403.0)) /
|
||||
(p5 + (2.0 + p3) * (220.0 / 1403.0) -
|
||||
((27.0 / 1403.0) - p3 * (6300.0 / 1403.0)) *
|
||||
(sin(hr) / cos(hr)));
|
||||
clr.b = clr.a * (sin(hr) / cos(hr));
|
||||
}
|
||||
|
||||
clr.RGBpa[0] = ((460.0 / 1403.0) * p2) +
|
||||
((451.0 / 1403.0) * clr.a) +
|
||||
((288.0 / 1403.0) * clr.b);
|
||||
clr.RGBpa[1] = ((460.0 / 1403.0) * p2) -
|
||||
((891.0 / 1403.0) * clr.a) -
|
||||
((261.0 / 1403.0) * clr.b);
|
||||
clr.RGBpa[2] = ((460.0 / 1403.0) * p2) -
|
||||
((220.0 / 1403.0) * clr.a) -
|
||||
((6300.0 / 1403.0) * clr.b);
|
||||
|
||||
return clr;
|
||||
}
|
||||
|
||||
static
|
||||
CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod)
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
cmsFloat64Number c1;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if ((clr.RGBpa[i] - 0.1) < 0) c1 = -1;
|
||||
else c1 = 1;
|
||||
clr.RGBp[i] = c1 * (100.0 / pMod->FL) *
|
||||
pow(((27.13 * fabs(clr.RGBpa[i] - 0.1)) /
|
||||
(400.0 - fabs(clr.RGBpa[i] - 0.1))),
|
||||
(1.0 / 0.42));
|
||||
}
|
||||
|
||||
return clr;
|
||||
}
|
||||
|
||||
static
|
||||
CAM02COLOR HPEtoCAT02(CAM02COLOR clr)
|
||||
{
|
||||
cmsFloat64Number M[9];
|
||||
|
||||
M[0] = (( 0.7328 * 1.910197) + (0.4296 * 0.370950));
|
||||
M[1] = (( 0.7328 * -1.112124) + (0.4296 * 0.629054));
|
||||
M[2] = (( 0.7328 * 0.201908) + (0.4296 * 0.000008) - 0.1624);
|
||||
M[3] = ((-0.7036 * 1.910197) + (1.6975 * 0.370950));
|
||||
M[4] = ((-0.7036 * -1.112124) + (1.6975 * 0.629054));
|
||||
M[5] = ((-0.7036 * 0.201908) + (1.6975 * 0.000008) + 0.0061);
|
||||
M[6] = (( 0.0030 * 1.910197) + (0.0136 * 0.370950));
|
||||
M[7] = (( 0.0030 * -1.112124) + (0.0136 * 0.629054));
|
||||
M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834);;
|
||||
|
||||
clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]);
|
||||
clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]);
|
||||
clr.RGBc[2] = (clr.RGBp[0] * M[6]) + (clr.RGBp[1] * M[7]) + (clr.RGBp[2] * M[8]);
|
||||
return clr;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod)
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
clr.RGB[i] = clr.RGBc[i] /
|
||||
((pMod->adoptedWhite.XYZ[1] * pMod->D / pMod->adoptedWhite.RGB[i]) + 1.0 - pMod->D);
|
||||
}
|
||||
return clr;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
CAM02COLOR CAT02toXYZ(CAM02COLOR clr)
|
||||
{
|
||||
clr.XYZ[0] = (clr.RGB[0] * 1.096124) + (clr.RGB[1] * -0.278869) + (clr.RGB[2] * 0.182745);
|
||||
clr.XYZ[1] = (clr.RGB[0] * 0.454369) + (clr.RGB[1] * 0.473533) + (clr.RGB[2] * 0.072098);
|
||||
clr.XYZ[2] = (clr.RGB[0] * -0.009628) + (clr.RGB[1] * -0.005698) + (clr.RGB[2] * 1.015326);
|
||||
|
||||
return clr;
|
||||
}
|
||||
|
||||
|
||||
cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC)
|
||||
{
|
||||
cmsCIECAM02* lpMod;
|
||||
|
||||
_cmsAssert(pVC != NULL);
|
||||
|
||||
if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lpMod ->ContextID = ContextID;
|
||||
|
||||
lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X;
|
||||
lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y;
|
||||
lpMod ->adoptedWhite.XYZ[2] = pVC ->whitePoint.Z;
|
||||
|
||||
lpMod -> LA = pVC ->La;
|
||||
lpMod -> Yb = pVC ->Yb;
|
||||
lpMod -> D = pVC ->D_value;
|
||||
lpMod -> surround = pVC ->surround;
|
||||
|
||||
switch (lpMod -> surround) {
|
||||
|
||||
|
||||
case CUTSHEET_SURROUND:
|
||||
lpMod->F = 0.8;
|
||||
lpMod->c = 0.41;
|
||||
lpMod->Nc = 0.8;
|
||||
break;
|
||||
|
||||
case DARK_SURROUND:
|
||||
lpMod -> F = 0.8;
|
||||
lpMod -> c = 0.525;
|
||||
lpMod -> Nc = 0.8;
|
||||
break;
|
||||
|
||||
case DIM_SURROUND:
|
||||
lpMod -> F = 0.9;
|
||||
lpMod -> c = 0.59;
|
||||
lpMod -> Nc = 0.95;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Average surround
|
||||
lpMod -> F = 1.0;
|
||||
lpMod -> c = 0.69;
|
||||
lpMod -> Nc = 1.0;
|
||||
}
|
||||
|
||||
lpMod -> n = compute_n(lpMod);
|
||||
lpMod -> z = compute_z(lpMod);
|
||||
lpMod -> Nbb = computeNbb(lpMod);
|
||||
lpMod -> FL = computeFL(lpMod);
|
||||
|
||||
if (lpMod -> D == D_CALCULATE) {
|
||||
lpMod -> D = computeD(lpMod);
|
||||
}
|
||||
|
||||
lpMod -> Ncb = lpMod -> Nbb;
|
||||
|
||||
lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite);
|
||||
lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod);
|
||||
lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite);
|
||||
lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod);
|
||||
|
||||
return (cmsHANDLE) lpMod;
|
||||
|
||||
}
|
||||
|
||||
void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel)
|
||||
{
|
||||
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
|
||||
|
||||
if (lpMod) _cmsFree(lpMod ->ContextID, lpMod);
|
||||
}
|
||||
|
||||
|
||||
void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut)
|
||||
{
|
||||
CAM02COLOR clr;
|
||||
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
|
||||
|
||||
_cmsAssert(lpMod != NULL);
|
||||
_cmsAssert(pIn != NULL);
|
||||
_cmsAssert(pOut != NULL);
|
||||
|
||||
clr.XYZ[0] = pIn ->X;
|
||||
clr.XYZ[1] = pIn ->Y;
|
||||
clr.XYZ[2] = pIn ->Z;
|
||||
|
||||
clr = XYZtoCAT02(clr);
|
||||
clr = ChromaticAdaptation(clr, lpMod);
|
||||
clr = CAT02toHPE(clr);
|
||||
clr = NonlinearCompression(clr, lpMod);
|
||||
clr = ComputeCorrelates(clr, lpMod);
|
||||
|
||||
pOut ->J = clr.J;
|
||||
pOut ->C = clr.C;
|
||||
pOut ->h = clr.h;
|
||||
}
|
||||
|
||||
void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut)
|
||||
{
|
||||
CAM02COLOR clr;
|
||||
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
|
||||
|
||||
_cmsAssert(lpMod != NULL);
|
||||
_cmsAssert(pIn != NULL);
|
||||
_cmsAssert(pOut != NULL);
|
||||
|
||||
clr.J = pIn -> J;
|
||||
clr.C = pIn -> C;
|
||||
clr.h = pIn -> h;
|
||||
|
||||
clr = InverseCorrelates(clr, lpMod);
|
||||
clr = InverseNonlinearity(clr, lpMod);
|
||||
clr = HPEtoCAT02(clr);
|
||||
clr = InverseChromaticAdaptation(clr, lpMod);
|
||||
clr = CAT02toXYZ(clr);
|
||||
|
||||
pOut ->X = clr.XYZ[0];
|
||||
pOut ->Y = clr.XYZ[1];
|
||||
pOut ->Z = clr.XYZ[2];
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,428 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
// I am so tired about incompatibilities on those functions that here are some replacements
|
||||
// that hopefully would be fully portable.
|
||||
|
||||
// compare two strings ignoring case
|
||||
int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2)
|
||||
{
|
||||
register const unsigned char *us1 = (const unsigned char *)s1,
|
||||
*us2 = (const unsigned char *)s2;
|
||||
|
||||
while (toupper(*us1) == toupper(*us2++))
|
||||
if (*us1++ == '\0')
|
||||
return (0);
|
||||
return (toupper(*us1) - toupper(*--us2));
|
||||
}
|
||||
|
||||
// long int because C99 specifies ftell in such way (7.19.9.2)
|
||||
long int CMSEXPORT cmsfilelength(FILE* f)
|
||||
{
|
||||
long int p , n;
|
||||
|
||||
p = ftell(f); // register current file position
|
||||
|
||||
if (fseek(f, 0, SEEK_END) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = ftell(f);
|
||||
fseek(f, p, SEEK_SET); // file position restored
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
// Memory handling ------------------------------------------------------------------
|
||||
//
|
||||
// This is the interface to low-level memory management routines. By default a simple
|
||||
// wrapping to malloc/free/realloc is provided, although there is a limit on the max
|
||||
// amount of memoy that can be reclaimed. This is mostly as a safety feature to
|
||||
// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms
|
||||
// would never need.
|
||||
|
||||
#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))
|
||||
|
||||
// User may override this behaviour by using a memory plug-in, which basically replaces
|
||||
// the default memory management functions. In this case, no check is performed and it
|
||||
// is up to the plug-in writter to keep in the safe side. There are only three functions
|
||||
// required to be implemented: malloc, realloc and free, although the user may want to
|
||||
// replace the optional mallocZero, calloc and dup as well.
|
||||
|
||||
cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// *********************************************************************************
|
||||
|
||||
// This is the default memory allocation function. It does a very coarse
|
||||
// check of amout of memory, just to prevent exploits
|
||||
static
|
||||
void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)
|
||||
{
|
||||
if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum
|
||||
|
||||
return (void*) malloc(size);
|
||||
|
||||
cmsUNUSED_PARAMETER(ContextID);
|
||||
}
|
||||
|
||||
// Generic allocate & zero
|
||||
static
|
||||
void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size)
|
||||
{
|
||||
void *pt = _cmsMalloc(ContextID, size);
|
||||
if (pt == NULL) return NULL;
|
||||
|
||||
memset(pt, 0, size);
|
||||
return pt;
|
||||
}
|
||||
|
||||
|
||||
// The default free function. The only check proformed is against NULL pointers
|
||||
static
|
||||
void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr)
|
||||
{
|
||||
// free(NULL) is defined a no-op by C99, therefore it is safe to
|
||||
// avoid the check, but it is here just in case...
|
||||
|
||||
if (Ptr) free(Ptr);
|
||||
|
||||
cmsUNUSED_PARAMETER(ContextID);
|
||||
}
|
||||
|
||||
// The default realloc function. Again it check for exploits. If Ptr is NULL,
|
||||
// realloc behaves the same way as malloc and allocates a new block of size bytes.
|
||||
static
|
||||
void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
|
||||
{
|
||||
|
||||
if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb
|
||||
|
||||
return realloc(Ptr, size);
|
||||
|
||||
cmsUNUSED_PARAMETER(ContextID);
|
||||
}
|
||||
|
||||
|
||||
// The default calloc function. Allocates an array of num elements, each one of size bytes
|
||||
// all memory is initialized to zero.
|
||||
static
|
||||
void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
|
||||
{
|
||||
cmsUInt32Number Total = num * size;
|
||||
|
||||
// Preserve calloc behaviour
|
||||
if (Total == 0) return NULL;
|
||||
|
||||
// Safe check for overflow.
|
||||
if (num >= UINT_MAX / size) return NULL;
|
||||
|
||||
// Check for overflow
|
||||
if (Total < num || Total < size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb
|
||||
|
||||
return _cmsMallocZero(ContextID, Total);
|
||||
}
|
||||
|
||||
// Generic block duplication
|
||||
static
|
||||
void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size)
|
||||
{
|
||||
void* mem;
|
||||
|
||||
if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb
|
||||
|
||||
mem = _cmsMalloc(ContextID, size);
|
||||
|
||||
if (mem != NULL && Org != NULL)
|
||||
memmove(mem, Org, size);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
// Pointers to malloc and _cmsFree functions in current environment
|
||||
static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn;
|
||||
static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn;
|
||||
static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn;
|
||||
static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn;
|
||||
static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn;
|
||||
static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn;
|
||||
|
||||
// Plug-in replacement entry
|
||||
cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data)
|
||||
{
|
||||
cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data;
|
||||
|
||||
// NULL forces to reset to defaults
|
||||
if (Data == NULL) {
|
||||
|
||||
MallocPtr = _cmsMallocDefaultFn;
|
||||
MallocZeroPtr= _cmsMallocZeroDefaultFn;
|
||||
FreePtr = _cmsFreeDefaultFn;
|
||||
ReallocPtr = _cmsReallocDefaultFn;
|
||||
CallocPtr = _cmsCallocDefaultFn;
|
||||
DupPtr = _cmsDupDefaultFn;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check for required callbacks
|
||||
if (Plugin -> MallocPtr == NULL ||
|
||||
Plugin -> FreePtr == NULL ||
|
||||
Plugin -> ReallocPtr == NULL) return FALSE;
|
||||
|
||||
// Set replacement functions
|
||||
MallocPtr = Plugin -> MallocPtr;
|
||||
FreePtr = Plugin -> FreePtr;
|
||||
ReallocPtr = Plugin -> ReallocPtr;
|
||||
|
||||
if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr;
|
||||
if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr;
|
||||
if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Generic allocate
|
||||
void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size)
|
||||
{
|
||||
return MallocPtr(ContextID, size);
|
||||
}
|
||||
|
||||
// Generic allocate & zero
|
||||
void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size)
|
||||
{
|
||||
return MallocZeroPtr(ContextID, size);
|
||||
}
|
||||
|
||||
// Generic calloc
|
||||
void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
|
||||
{
|
||||
return CallocPtr(ContextID, num, size);
|
||||
}
|
||||
|
||||
// Generic reallocate
|
||||
void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
|
||||
{
|
||||
return ReallocPtr(ContextID, Ptr, size);
|
||||
}
|
||||
|
||||
// Generic free memory
|
||||
void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr)
|
||||
{
|
||||
if (Ptr != NULL) FreePtr(ContextID, Ptr);
|
||||
}
|
||||
|
||||
// Generic block duplication
|
||||
void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size)
|
||||
{
|
||||
return DupPtr(ContextID, Org, size);
|
||||
}
|
||||
|
||||
// ********************************************************************************************
|
||||
|
||||
// Sub allocation takes care of many pointers of small size. The memory allocated in
|
||||
// this way have be freed at once. Next function allocates a single chunk for linked list
|
||||
// I prefer this method over realloc due to the big inpact on xput realloc may have if
|
||||
// memory is being swapped to disk. This approach is safer (although that may not be true on all platforms)
|
||||
static
|
||||
_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial)
|
||||
{
|
||||
_cmsSubAllocator_chunk* chunk;
|
||||
|
||||
// Create the container
|
||||
chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk));
|
||||
if (chunk == NULL) return NULL;
|
||||
|
||||
// Initialize values
|
||||
chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial);
|
||||
if (chunk ->Block == NULL) {
|
||||
|
||||
// Something went wrong
|
||||
_cmsFree(ContextID, chunk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 20K by default
|
||||
if (Initial == 0)
|
||||
Initial = 20*1024;
|
||||
|
||||
chunk ->BlockSize = Initial;
|
||||
chunk ->Used = 0;
|
||||
chunk ->next = NULL;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
// The suballocated is nothing but a pointer to the first element in the list. We also keep
|
||||
// the thread ID in this structure.
|
||||
_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial)
|
||||
{
|
||||
_cmsSubAllocator* sub;
|
||||
|
||||
// Create the container
|
||||
sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator));
|
||||
if (sub == NULL) return NULL;
|
||||
|
||||
sub ->ContextID = ContextID;
|
||||
|
||||
sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial);
|
||||
if (sub ->h == NULL) {
|
||||
_cmsFree(ContextID, sub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
|
||||
// Get rid of whole linked list
|
||||
void _cmsSubAllocDestroy(_cmsSubAllocator* sub)
|
||||
{
|
||||
_cmsSubAllocator_chunk *chunk, *n;
|
||||
|
||||
for (chunk = sub ->h; chunk != NULL; chunk = n) {
|
||||
|
||||
n = chunk->next;
|
||||
if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block);
|
||||
_cmsFree(sub ->ContextID, chunk);
|
||||
}
|
||||
|
||||
// Free the header
|
||||
_cmsFree(sub ->ContextID, sub);
|
||||
}
|
||||
|
||||
|
||||
// Get a pointer to small memory block.
|
||||
void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size)
|
||||
{
|
||||
cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used;
|
||||
cmsUInt8Number* ptr;
|
||||
|
||||
size = _cmsALIGNLONG(size);
|
||||
|
||||
// Check for memory. If there is no room, allocate a new chunk of double memory size.
|
||||
if (size > Free) {
|
||||
|
||||
_cmsSubAllocator_chunk* chunk;
|
||||
cmsUInt32Number newSize;
|
||||
|
||||
newSize = sub -> h ->BlockSize * 2;
|
||||
if (newSize < size) newSize = size;
|
||||
|
||||
chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize);
|
||||
if (chunk == NULL) return NULL;
|
||||
|
||||
// Link list
|
||||
chunk ->next = sub ->h;
|
||||
sub ->h = chunk;
|
||||
|
||||
}
|
||||
|
||||
ptr = sub -> h ->Block + sub -> h ->Used;
|
||||
sub -> h -> Used += size;
|
||||
|
||||
return (void*) ptr;
|
||||
}
|
||||
|
||||
// Error logging ******************************************************************
|
||||
|
||||
// There is no error handling at all. When a funtion fails, it returns proper value.
|
||||
// For example, all create functions does return NULL on failure. Other return FALSE
|
||||
// It may be interesting, for the developer, to know why the function is failing.
|
||||
// for that reason, lcms2 does offer a logging function. This function does recive
|
||||
// a ENGLISH string with some clues on what is going wrong. You can show this
|
||||
// info to the end user, or just create some sort of log.
|
||||
// The logging function should NOT terminate the program, as this obviously can leave
|
||||
// resources. It is the programmer's responsability to check each function return code
|
||||
// to make sure it didn't fail.
|
||||
|
||||
// Error messages are limited to MAX_ERROR_MESSAGE_LEN
|
||||
|
||||
#define MAX_ERROR_MESSAGE_LEN 1024
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------
|
||||
|
||||
// This is our default log error
|
||||
static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text);
|
||||
|
||||
// The current handler in actual environment
|
||||
static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction;
|
||||
|
||||
// The default error logger does nothing.
|
||||
static
|
||||
void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
|
||||
{
|
||||
// fprintf(stderr, "[lcms]: %s\n", Text);
|
||||
// fflush(stderr);
|
||||
|
||||
cmsUNUSED_PARAMETER(ContextID);
|
||||
cmsUNUSED_PARAMETER(ErrorCode);
|
||||
cmsUNUSED_PARAMETER(Text);
|
||||
}
|
||||
|
||||
// Change log error
|
||||
void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn)
|
||||
{
|
||||
if (Fn == NULL)
|
||||
LogErrorHandler = DefaultLogErrorHandlerFunction;
|
||||
else
|
||||
LogErrorHandler = Fn;
|
||||
}
|
||||
|
||||
// Log an error
|
||||
// ErrorText is a text holding an english description of error.
|
||||
void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...)
|
||||
{
|
||||
va_list args;
|
||||
char Buffer[MAX_ERROR_MESSAGE_LEN];
|
||||
|
||||
va_start(args, ErrorText);
|
||||
vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args);
|
||||
va_end(args);
|
||||
|
||||
// Call handler
|
||||
LogErrorHandler(ContextID, ErrorCode, Buffer);
|
||||
}
|
||||
|
||||
// Utility function to print signatures
|
||||
void _cmsTagSignature2String(char String[5], cmsTagSignature sig)
|
||||
{
|
||||
cmsUInt32Number be;
|
||||
|
||||
// Convert to big endian
|
||||
be = _cmsAdjustEndianess32((cmsUInt32Number) sig);
|
||||
|
||||
// Move chars
|
||||
memmove(String, &be, 4);
|
||||
|
||||
// Make sure of terminator
|
||||
String[4] = 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,590 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
|
||||
// Auxiliar: append a Lab identity after the given sequence of profiles
|
||||
// and return the transform. Lab profile is closed, rest of profiles are kept open.
|
||||
cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID,
|
||||
cmsUInt32Number nProfiles,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsUInt32Number OutputFormat,
|
||||
const cmsUInt32Number Intents[],
|
||||
const cmsHPROFILE hProfiles[],
|
||||
const cmsBool BPC[],
|
||||
const cmsFloat64Number AdaptationStates[],
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
cmsHTRANSFORM xform;
|
||||
cmsHPROFILE hLab;
|
||||
cmsHPROFILE ProfileList[256];
|
||||
cmsBool BPCList[256];
|
||||
cmsFloat64Number AdaptationList[256];
|
||||
cmsUInt32Number IntentList[256];
|
||||
cmsUInt32Number i;
|
||||
|
||||
// This is a rather big number and there is no need of dynamic memory
|
||||
// since we are adding a profile, 254 + 1 = 255 and this is the limit
|
||||
if (nProfiles > 254) return NULL;
|
||||
|
||||
// The output space
|
||||
hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
|
||||
if (hLab == NULL) return NULL;
|
||||
|
||||
// Create a copy of parameters
|
||||
for (i=0; i < nProfiles; i++) {
|
||||
|
||||
ProfileList[i] = hProfiles[i];
|
||||
BPCList[i] = BPC[i];
|
||||
AdaptationList[i] = AdaptationStates[i];
|
||||
IntentList[i] = Intents[i];
|
||||
}
|
||||
|
||||
// Place Lab identity at chain's end.
|
||||
ProfileList[nProfiles] = hLab;
|
||||
BPCList[nProfiles] = 0;
|
||||
AdaptationList[nProfiles] = 1.0;
|
||||
IntentList[nProfiles] = INTENT_RELATIVE_COLORIMETRIC;
|
||||
|
||||
// Create the transform
|
||||
xform = cmsCreateExtendedTransform(ContextID, nProfiles + 1, ProfileList,
|
||||
BPCList,
|
||||
IntentList,
|
||||
AdaptationList,
|
||||
NULL, 0,
|
||||
InputFormat,
|
||||
OutputFormat,
|
||||
dwFlags);
|
||||
|
||||
cmsCloseProfile(hLab);
|
||||
|
||||
return xform;
|
||||
}
|
||||
|
||||
|
||||
// Compute K -> L* relationship. Flags may include black point compensation. In this case,
|
||||
// the relationship is assumed from the profile with BPC to a black point zero.
|
||||
static
|
||||
cmsToneCurve* ComputeKToLstar(cmsContext ContextID,
|
||||
cmsUInt32Number nPoints,
|
||||
cmsUInt32Number nProfiles,
|
||||
const cmsUInt32Number Intents[],
|
||||
const cmsHPROFILE hProfiles[],
|
||||
const cmsBool BPC[],
|
||||
const cmsFloat64Number AdaptationStates[],
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
cmsToneCurve* out = NULL;
|
||||
cmsUInt32Number i;
|
||||
cmsHTRANSFORM xform;
|
||||
cmsCIELab Lab;
|
||||
cmsFloat32Number cmyk[4];
|
||||
cmsFloat32Number* SampledPoints;
|
||||
|
||||
xform = _cmsChain2Lab(ContextID, nProfiles, TYPE_CMYK_FLT, TYPE_Lab_DBL, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
|
||||
if (xform == NULL) return NULL;
|
||||
|
||||
SampledPoints = (cmsFloat32Number*) _cmsCalloc(ContextID, nPoints, sizeof(cmsFloat32Number));
|
||||
if (SampledPoints == NULL) goto Error;
|
||||
|
||||
for (i=0; i < nPoints; i++) {
|
||||
|
||||
cmyk[0] = 0;
|
||||
cmyk[1] = 0;
|
||||
cmyk[2] = 0;
|
||||
cmyk[3] = (cmsFloat32Number) ((i * 100.0) / (nPoints-1));
|
||||
|
||||
cmsDoTransform(xform, cmyk, &Lab, 1);
|
||||
SampledPoints[i]= (cmsFloat32Number) (1.0 - Lab.L / 100.0); // Negate K for easier operation
|
||||
}
|
||||
|
||||
out = cmsBuildTabulatedToneCurveFloat(ContextID, nPoints, SampledPoints);
|
||||
|
||||
Error:
|
||||
|
||||
cmsDeleteTransform(xform);
|
||||
if (SampledPoints) _cmsFree(ContextID, SampledPoints);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// Compute Black tone curve on a CMYK -> CMYK transform. This is done by
|
||||
// using the proof direction on both profiles to find K->L* relationship
|
||||
// then joining both curves. dwFlags may include black point compensation.
|
||||
cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
|
||||
cmsUInt32Number nPoints,
|
||||
cmsUInt32Number nProfiles,
|
||||
const cmsUInt32Number Intents[],
|
||||
const cmsHPROFILE hProfiles[],
|
||||
const cmsBool BPC[],
|
||||
const cmsFloat64Number AdaptationStates[],
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
cmsToneCurve *in, *out, *KTone;
|
||||
|
||||
// Make sure CMYK -> CMYK
|
||||
if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
|
||||
cmsGetColorSpace(hProfiles[nProfiles-1])!= cmsSigCmykData) return NULL;
|
||||
|
||||
|
||||
// Make sure last is an output profile
|
||||
if (cmsGetDeviceClass(hProfiles[nProfiles - 1]) != cmsSigOutputClass) return NULL;
|
||||
|
||||
// Create individual curves. BPC works also as each K to L* is
|
||||
// computed as a BPC to zero black point in case of L*
|
||||
in = ComputeKToLstar(ContextID, nPoints, nProfiles - 1, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
|
||||
if (in == NULL) return NULL;
|
||||
|
||||
out = ComputeKToLstar(ContextID, nPoints, 1,
|
||||
Intents + (nProfiles - 1),
|
||||
hProfiles + (nProfiles - 1),
|
||||
BPC + (nProfiles - 1),
|
||||
AdaptationStates + (nProfiles - 1),
|
||||
dwFlags);
|
||||
if (out == NULL) {
|
||||
cmsFreeToneCurve(in);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Build the relationship. This effectively limits the maximum accuracy to 16 bits, but
|
||||
// since this is used on black-preserving LUTs, we are not loosing accuracy in any case
|
||||
KTone = cmsJoinToneCurve(ContextID, in, out, nPoints);
|
||||
|
||||
// Get rid of components
|
||||
cmsFreeToneCurve(in); cmsFreeToneCurve(out);
|
||||
|
||||
// Something went wrong...
|
||||
if (KTone == NULL) return NULL;
|
||||
|
||||
// Make sure it is monotonic
|
||||
if (!cmsIsToneCurveMonotonic(KTone)) {
|
||||
cmsFreeToneCurve(KTone);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return KTone;
|
||||
}
|
||||
|
||||
|
||||
// Gamut LUT Creation -----------------------------------------------------------------------------------------
|
||||
|
||||
// Used by gamut & softproofing
|
||||
|
||||
typedef struct {
|
||||
|
||||
cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL
|
||||
cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back
|
||||
cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut
|
||||
|
||||
} GAMUTCHAIN;
|
||||
|
||||
// This sampler does compute gamut boundaries by comparing original
|
||||
// values with a transform going back and forth. Values above ERR_THERESHOLD
|
||||
// of maximum are considered out of gamut.
|
||||
|
||||
#define ERR_THERESHOLD 5
|
||||
|
||||
|
||||
static
|
||||
int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
|
||||
{
|
||||
GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo;
|
||||
cmsCIELab LabIn1, LabOut1;
|
||||
cmsCIELab LabIn2, LabOut2;
|
||||
cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
|
||||
cmsFloat64Number dE1, dE2, ErrorRatio;
|
||||
|
||||
// Assume in-gamut by default.
|
||||
dE1 = 0.;
|
||||
dE2 = 0;
|
||||
ErrorRatio = 1.0;
|
||||
|
||||
// Convert input to Lab
|
||||
if (t -> hInput != NULL)
|
||||
cmsDoTransform(t -> hInput, In, &LabIn1, 1);
|
||||
|
||||
// converts from PCS to colorant. This always
|
||||
// does return in-gamut values,
|
||||
cmsDoTransform(t -> hForward, &LabIn1, Proof, 1);
|
||||
|
||||
// Now, do the inverse, from colorant to PCS.
|
||||
cmsDoTransform(t -> hReverse, Proof, &LabOut1, 1);
|
||||
|
||||
memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab));
|
||||
|
||||
// Try again, but this time taking Check as input
|
||||
cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1);
|
||||
cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1);
|
||||
|
||||
// Take difference of direct value
|
||||
dE1 = cmsDeltaE(&LabIn1, &LabOut1);
|
||||
|
||||
// Take difference of converted value
|
||||
dE2 = cmsDeltaE(&LabIn2, &LabOut2);
|
||||
|
||||
|
||||
// if dE1 is small and dE2 is small, value is likely to be in gamut
|
||||
if (dE1 < t->Thereshold && dE2 < t->Thereshold)
|
||||
Out[0] = 0;
|
||||
else {
|
||||
|
||||
// if dE1 is small and dE2 is big, undefined. Assume in gamut
|
||||
if (dE1 < t->Thereshold && dE2 > t->Thereshold)
|
||||
Out[0] = 0;
|
||||
else
|
||||
// dE1 is big and dE2 is small, clearly out of gamut
|
||||
if (dE1 > t->Thereshold && dE2 < t->Thereshold)
|
||||
Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5);
|
||||
else {
|
||||
|
||||
// dE1 is big and dE2 is also big, could be due to perceptual mapping
|
||||
// so take error ratio
|
||||
if (dE2 == 0.0)
|
||||
ErrorRatio = dE1;
|
||||
else
|
||||
ErrorRatio = dE1 / dE2;
|
||||
|
||||
if (ErrorRatio > t->Thereshold)
|
||||
Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5);
|
||||
else
|
||||
Out[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Does compute a gamut LUT going back and forth across pcs -> relativ. colorimetric intent -> pcs
|
||||
// the dE obtained is then annotated on the LUT. Values truely out of gamut are clipped to dE = 0xFFFE
|
||||
// and values changed are supposed to be handled by any gamut remapping, so, are out of gamut as well.
|
||||
//
|
||||
// **WARNING: This algorithm does assume that gamut remapping algorithms does NOT move in-gamut colors,
|
||||
// of course, many perceptual and saturation intents does not work in such way, but relativ. ones should.
|
||||
|
||||
cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
|
||||
cmsHPROFILE hProfiles[],
|
||||
cmsBool BPC[],
|
||||
cmsUInt32Number Intents[],
|
||||
cmsFloat64Number AdaptationStates[],
|
||||
cmsUInt32Number nGamutPCSposition,
|
||||
cmsHPROFILE hGamut)
|
||||
{
|
||||
cmsHPROFILE hLab;
|
||||
cmsPipeline* Gamut;
|
||||
cmsStage* CLUT;
|
||||
cmsUInt32Number dwFormat;
|
||||
GAMUTCHAIN Chain;
|
||||
int nChannels, nGridpoints;
|
||||
cmsColorSpaceSignature ColorSpace;
|
||||
cmsUInt32Number i;
|
||||
cmsHPROFILE ProfileList[256];
|
||||
cmsBool BPCList[256];
|
||||
cmsFloat64Number AdaptationList[256];
|
||||
cmsUInt32Number IntentList[256];
|
||||
|
||||
memset(&Chain, 0, sizeof(GAMUTCHAIN));
|
||||
|
||||
|
||||
if (nGamutPCSposition <= 0 || nGamutPCSposition > 255) {
|
||||
cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong position of PCS. 1..255 expected, %d found.", nGamutPCSposition);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
|
||||
if (hLab == NULL) return NULL;
|
||||
|
||||
|
||||
// The figure of merit. On matrix-shaper profiles, should be almost zero as
|
||||
// the conversion is pretty exact. On LUT based profiles, different resolutions
|
||||
// of input and output CLUT may result in differences.
|
||||
|
||||
if (cmsIsMatrixShaper(hGamut)) {
|
||||
|
||||
Chain.Thereshold = 1.0;
|
||||
}
|
||||
else {
|
||||
Chain.Thereshold = ERR_THERESHOLD;
|
||||
}
|
||||
|
||||
|
||||
// Create a copy of parameters
|
||||
for (i=0; i < nGamutPCSposition; i++) {
|
||||
ProfileList[i] = hProfiles[i];
|
||||
BPCList[i] = BPC[i];
|
||||
AdaptationList[i] = AdaptationStates[i];
|
||||
IntentList[i] = Intents[i];
|
||||
}
|
||||
|
||||
// Fill Lab identity
|
||||
ProfileList[nGamutPCSposition] = hLab;
|
||||
BPCList[nGamutPCSposition] = 0;
|
||||
AdaptationList[nGamutPCSposition] = 1.0;
|
||||
Intents[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC;
|
||||
|
||||
|
||||
ColorSpace = cmsGetColorSpace(hGamut);
|
||||
|
||||
nChannels = cmsChannelsOf(ColorSpace);
|
||||
nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
|
||||
dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
|
||||
|
||||
// 16 bits to Lab double
|
||||
Chain.hInput = cmsCreateExtendedTransform(ContextID,
|
||||
nGamutPCSposition + 1,
|
||||
ProfileList,
|
||||
BPCList,
|
||||
Intents,
|
||||
AdaptationList,
|
||||
NULL, 0,
|
||||
dwFormat, TYPE_Lab_DBL,
|
||||
cmsFLAGS_NOCACHE);
|
||||
|
||||
|
||||
// Does create the forward step. Lab double to device
|
||||
dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
|
||||
Chain.hForward = cmsCreateTransformTHR(ContextID,
|
||||
hLab, TYPE_Lab_DBL,
|
||||
hGamut, dwFormat,
|
||||
INTENT_RELATIVE_COLORIMETRIC,
|
||||
cmsFLAGS_NOCACHE);
|
||||
|
||||
// Does create the backwards step
|
||||
Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat,
|
||||
hLab, TYPE_Lab_DBL,
|
||||
INTENT_RELATIVE_COLORIMETRIC,
|
||||
cmsFLAGS_NOCACHE);
|
||||
|
||||
|
||||
// All ok?
|
||||
if (Chain.hForward && Chain.hReverse) {
|
||||
|
||||
// Go on, try to compute gamut LUT from PCS. This consist on a single channel containing
|
||||
// dE when doing a transform back and forth on the colorimetric intent.
|
||||
|
||||
Gamut = cmsPipelineAlloc(ContextID, 3, 1);
|
||||
|
||||
if (Gamut != NULL) {
|
||||
|
||||
CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL);
|
||||
cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT);
|
||||
|
||||
cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
Gamut = NULL; // Didn't work...
|
||||
|
||||
// Free all needed stuff.
|
||||
if (Chain.hInput) cmsDeleteTransform(Chain.hInput);
|
||||
if (Chain.hForward) cmsDeleteTransform(Chain.hForward);
|
||||
if (Chain.hReverse) cmsDeleteTransform(Chain.hReverse);
|
||||
if (hLab) cmsCloseProfile(hLab);
|
||||
|
||||
// And return computed hull
|
||||
return Gamut;
|
||||
}
|
||||
|
||||
// Total Area Coverage estimation ----------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
cmsUInt32Number nOutputChans;
|
||||
cmsHTRANSFORM hRoundTrip;
|
||||
cmsFloat32Number MaxTAC;
|
||||
cmsFloat32Number MaxInput[cmsMAXCHANNELS];
|
||||
|
||||
} cmsTACestimator;
|
||||
|
||||
|
||||
// This callback just accounts the maximum ink dropped in the given node. It does not populate any
|
||||
// memory, as the destination table is NULL. Its only purpose it to know the global maximum.
|
||||
static
|
||||
int EstimateTAC(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void * Cargo)
|
||||
{
|
||||
cmsTACestimator* bp = (cmsTACestimator*) Cargo;
|
||||
cmsFloat32Number RoundTrip[cmsMAXCHANNELS];
|
||||
cmsUInt32Number i;
|
||||
cmsFloat32Number Sum;
|
||||
|
||||
|
||||
// Evaluate the xform
|
||||
cmsDoTransform(bp->hRoundTrip, In, RoundTrip, 1);
|
||||
|
||||
// All all amounts of ink
|
||||
for (Sum=0, i=0; i < bp ->nOutputChans; i++)
|
||||
Sum += RoundTrip[i];
|
||||
|
||||
// If above maximum, keep track of input values
|
||||
if (Sum > bp ->MaxTAC) {
|
||||
|
||||
bp ->MaxTAC = Sum;
|
||||
|
||||
for (i=0; i < bp ->nOutputChans; i++) {
|
||||
bp ->MaxInput[i] = In[i];
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
cmsUNUSED_PARAMETER(Out);
|
||||
}
|
||||
|
||||
|
||||
// Detect Total area coverage of the profile
|
||||
cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsTACestimator bp;
|
||||
cmsUInt32Number dwFormatter;
|
||||
cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS];
|
||||
cmsHPROFILE hLab;
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
// TAC only works on output profiles
|
||||
if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a fake formatter for result
|
||||
dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE);
|
||||
|
||||
bp.nOutputChans = T_CHANNELS(dwFormatter);
|
||||
bp.MaxTAC = 0; // Initial TAC is 0
|
||||
|
||||
// for safety
|
||||
if (bp.nOutputChans >= cmsMAXCHANNELS) return 0;
|
||||
|
||||
hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
|
||||
if (hLab == NULL) return 0;
|
||||
// Setup a roundtrip on perceptual intent in output profile for TAC estimation
|
||||
bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16,
|
||||
hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
|
||||
|
||||
cmsCloseProfile(hLab);
|
||||
if (bp.hRoundTrip == NULL) return 0;
|
||||
|
||||
// For L* we only need black and white. For C* we need many points
|
||||
GridPoints[0] = 6;
|
||||
GridPoints[1] = 74;
|
||||
GridPoints[2] = 74;
|
||||
|
||||
|
||||
if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) {
|
||||
bp.MaxTAC = 0;
|
||||
}
|
||||
|
||||
cmsDeleteTransform(bp.hRoundTrip);
|
||||
|
||||
// Results in %
|
||||
return bp.MaxTAC;
|
||||
}
|
||||
|
||||
|
||||
// Carefully, clamp on CIELab space.
|
||||
|
||||
cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
|
||||
double amax, double amin,
|
||||
double bmax, double bmin)
|
||||
{
|
||||
|
||||
// Whole Luma surface to zero
|
||||
|
||||
if (Lab -> L < 0) {
|
||||
|
||||
Lab-> L = Lab->a = Lab-> b = 0.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Clamp white, DISCARD HIGHLIGHTS. This is done
|
||||
// in such way because icc spec doesn't allow the
|
||||
// use of L>100 as a highlight means.
|
||||
|
||||
if (Lab->L > 100)
|
||||
Lab -> L = 100;
|
||||
|
||||
// Check out gamut prism, on a, b faces
|
||||
|
||||
if (Lab -> a < amin || Lab->a > amax||
|
||||
Lab -> b < bmin || Lab->b > bmax) {
|
||||
|
||||
cmsCIELCh LCh;
|
||||
double h, slope;
|
||||
|
||||
// Falls outside a, b limits. Transports to LCh space,
|
||||
// and then do the clipping
|
||||
|
||||
|
||||
if (Lab -> a == 0.0) { // Is hue exactly 90?
|
||||
|
||||
// atan will not work, so clamp here
|
||||
Lab -> b = Lab->b < 0 ? bmin : bmax;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsLab2LCh(&LCh, Lab);
|
||||
|
||||
slope = Lab -> b / Lab -> a;
|
||||
h = LCh.h;
|
||||
|
||||
// There are 4 zones
|
||||
|
||||
if ((h >= 0. && h < 45.) ||
|
||||
(h >= 315 && h <= 360.)) {
|
||||
|
||||
// clip by amax
|
||||
Lab -> a = amax;
|
||||
Lab -> b = amax * slope;
|
||||
}
|
||||
else
|
||||
if (h >= 45. && h < 135.)
|
||||
{
|
||||
// clip by bmax
|
||||
Lab -> b = bmax;
|
||||
Lab -> a = bmax / slope;
|
||||
}
|
||||
else
|
||||
if (h >= 135. && h < 225.) {
|
||||
// clip by amin
|
||||
Lab -> a = amin;
|
||||
Lab -> b = amin * slope;
|
||||
|
||||
}
|
||||
else
|
||||
if (h >= 225. && h < 315.) {
|
||||
// clip by bmin
|
||||
Lab -> b = bmin;
|
||||
Lab -> a = bmin / slope;
|
||||
}
|
||||
else {
|
||||
cmsSignalError(0, cmsERROR_RANGE, "Invalid angle");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,808 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2011 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
// Read tags using low-level functions, provides necessary glue code to adapt versions, etc.
|
||||
|
||||
// LUT tags
|
||||
static const cmsTagSignature Device2PCS16[] = {cmsSigAToB0Tag, // Perceptual
|
||||
cmsSigAToB1Tag, // Relative colorimetric
|
||||
cmsSigAToB2Tag, // Saturation
|
||||
cmsSigAToB1Tag }; // Absolute colorimetric
|
||||
|
||||
static const cmsTagSignature Device2PCSFloat[] = {cmsSigDToB0Tag, // Perceptual
|
||||
cmsSigDToB1Tag, // Relative colorimetric
|
||||
cmsSigDToB2Tag, // Saturation
|
||||
cmsSigDToB3Tag }; // Absolute colorimetric
|
||||
|
||||
static const cmsTagSignature PCS2Device16[] = {cmsSigBToA0Tag, // Perceptual
|
||||
cmsSigBToA1Tag, // Relative colorimetric
|
||||
cmsSigBToA2Tag, // Saturation
|
||||
cmsSigBToA1Tag }; // Absolute colorimetric
|
||||
|
||||
static const cmsTagSignature PCS2DeviceFloat[] = {cmsSigBToD0Tag, // Perceptual
|
||||
cmsSigBToD1Tag, // Relative colorimetric
|
||||
cmsSigBToD2Tag, // Saturation
|
||||
cmsSigBToD3Tag }; // Absolute colorimetric
|
||||
|
||||
|
||||
// Factors to convert from 1.15 fixed point to 0..1.0 range and vice-versa
|
||||
#define InpAdj (1.0/MAX_ENCODEABLE_XYZ) // (65536.0/(65535.0*2.0))
|
||||
#define OutpAdj (MAX_ENCODEABLE_XYZ) // ((2.0*65535.0)/65536.0)
|
||||
|
||||
// Several resources for gray conversions.
|
||||
static const cmsFloat64Number GrayInputMatrix[] = { (InpAdj*cmsD50X), (InpAdj*cmsD50Y), (InpAdj*cmsD50Z) };
|
||||
static const cmsFloat64Number OneToThreeInputMatrix[] = { 1, 1, 1 };
|
||||
static const cmsFloat64Number PickYMatrix[] = { 0, (OutpAdj*cmsD50Y), 0 };
|
||||
static const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 };
|
||||
|
||||
// Get a media white point fixing some issues found in certain old profiles
|
||||
cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsCIEXYZ* Tag;
|
||||
|
||||
_cmsAssert(Dest != NULL);
|
||||
|
||||
Tag = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag);
|
||||
|
||||
// If no wp, take D50
|
||||
if (Tag == NULL) {
|
||||
*Dest = *cmsD50_XYZ();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// V2 display profiles should give D50
|
||||
if (cmsGetEncodedICCversion(hProfile) < 0x4000000) {
|
||||
|
||||
if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) {
|
||||
*Dest = *cmsD50_XYZ();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// All seems ok
|
||||
*Dest = *Tag;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Chromatic adaptation matrix. Fix some issues as well
|
||||
cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsMAT3* Tag;
|
||||
|
||||
_cmsAssert(Dest != NULL);
|
||||
|
||||
Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag);
|
||||
|
||||
if (Tag != NULL) {
|
||||
|
||||
*Dest = *Tag;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// No CHAD available, default it to identity
|
||||
_cmsMAT3identity(Dest);
|
||||
|
||||
// V2 display profiles should give D50
|
||||
if (cmsGetEncodedICCversion(hProfile) < 0x4000000) {
|
||||
|
||||
if (cmsGetDeviceClass(hProfile) == cmsSigDisplayClass) {
|
||||
|
||||
cmsCIEXYZ* White = (cmsCIEXYZ*) cmsReadTag(hProfile, cmsSigMediaWhitePointTag);
|
||||
|
||||
if (White == NULL) {
|
||||
|
||||
_cmsMAT3identity(Dest);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return _cmsAdaptationMatrix(Dest, NULL, cmsD50_XYZ(), White);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Auxiliar, read colorants as a MAT3 structure. Used by any function that needs a matrix-shaper
|
||||
static
|
||||
cmsBool ReadICCMatrixRGB2XYZ(cmsMAT3* r, cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsCIEXYZ *PtrRed, *PtrGreen, *PtrBlue;
|
||||
|
||||
_cmsAssert(r != NULL);
|
||||
|
||||
PtrRed = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigRedColorantTag);
|
||||
PtrGreen = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigGreenColorantTag);
|
||||
PtrBlue = (cmsCIEXYZ *) cmsReadTag(hProfile, cmsSigBlueColorantTag);
|
||||
|
||||
if (PtrRed == NULL || PtrGreen == NULL || PtrBlue == NULL)
|
||||
return FALSE;
|
||||
|
||||
_cmsVEC3init(&r -> v[0], PtrRed -> X, PtrGreen -> X, PtrBlue -> X);
|
||||
_cmsVEC3init(&r -> v[1], PtrRed -> Y, PtrGreen -> Y, PtrBlue -> Y);
|
||||
_cmsVEC3init(&r -> v[2], PtrRed -> Z, PtrGreen -> Z, PtrBlue -> Z);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Gray input pipeline
|
||||
static
|
||||
cmsPipeline* BuildGrayInputMatrixPipeline(cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsToneCurve *GrayTRC;
|
||||
cmsPipeline* Lut;
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag);
|
||||
if (GrayTRC == NULL) return NULL;
|
||||
|
||||
Lut = cmsPipelineAlloc(ContextID, 1, 3);
|
||||
if (Lut == NULL) return NULL;
|
||||
|
||||
if (cmsGetPCS(hProfile) == cmsSigLabData) {
|
||||
|
||||
// In this case we implement the profile as an identity matrix plus 3 tone curves
|
||||
cmsUInt16Number Zero[2] = { 0x8080, 0x8080 };
|
||||
cmsToneCurve* EmptyTab;
|
||||
cmsToneCurve* LabCurves[3];
|
||||
|
||||
EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
|
||||
|
||||
if (EmptyTab == NULL) {
|
||||
|
||||
cmsPipelineFree(Lut);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LabCurves[0] = GrayTRC;
|
||||
LabCurves[1] = EmptyTab;
|
||||
LabCurves[2] = EmptyTab;
|
||||
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL));
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves));
|
||||
|
||||
cmsFreeToneCurve(EmptyTab);
|
||||
|
||||
}
|
||||
else {
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC));
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL));
|
||||
}
|
||||
|
||||
return Lut;
|
||||
}
|
||||
|
||||
// RGB Matrix shaper
|
||||
static
|
||||
cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsPipeline* Lut;
|
||||
cmsMAT3 Mat;
|
||||
cmsToneCurve *Shapes[3];
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
int i, j;
|
||||
|
||||
if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile)) return NULL;
|
||||
|
||||
// XYZ PCS in encoded in 1.15 format, and the matrix output comes in 0..0xffff range, so
|
||||
// we need to adjust the output by a factor of (0x10000/0xffff) to put data in
|
||||
// a 1.16 range, and then a >> 1 to obtain 1.15. The total factor is (65536.0)/(65535.0*2)
|
||||
|
||||
for (i=0; i < 3; i++)
|
||||
for (j=0; j < 3; j++)
|
||||
Mat.v[i].n[j] *= InpAdj;
|
||||
|
||||
|
||||
Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag);
|
||||
Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag);
|
||||
Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag);
|
||||
|
||||
if (!Shapes[0] || !Shapes[1] || !Shapes[2])
|
||||
return NULL;
|
||||
|
||||
Lut = cmsPipelineAlloc(ContextID, 3, 3);
|
||||
if (Lut != NULL) {
|
||||
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes));
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL));
|
||||
}
|
||||
|
||||
return Lut;
|
||||
}
|
||||
|
||||
// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc
|
||||
// is adjusted here in order to create a LUT that takes care of all those details
|
||||
cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
|
||||
{
|
||||
cmsTagTypeSignature OriginalType;
|
||||
cmsTagSignature tag16 = Device2PCS16[Intent];
|
||||
cmsTagSignature tagFloat = Device2PCSFloat[Intent];
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
// On named color, take the appropiate tag
|
||||
if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
|
||||
|
||||
cmsPipeline* Lut;
|
||||
cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag);
|
||||
|
||||
if (nc == NULL) return NULL;
|
||||
|
||||
Lut = cmsPipelineAlloc(ContextID, 0, 0);
|
||||
if (Lut == NULL) {
|
||||
cmsFreeNamedColorList(nc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE));
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
|
||||
return Lut;
|
||||
}
|
||||
|
||||
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
|
||||
|
||||
// Floating point LUT are always V4, so no adjustment is required
|
||||
return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
|
||||
}
|
||||
|
||||
// Revert to perceptual if no tag is found
|
||||
if (!cmsIsTag(hProfile, tag16)) {
|
||||
tag16 = Device2PCS16[0];
|
||||
}
|
||||
|
||||
if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
|
||||
|
||||
// Check profile version and LUT type. Do the necessary adjustments if needed
|
||||
|
||||
// First read the tag
|
||||
cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
|
||||
if (Lut == NULL) return NULL;
|
||||
|
||||
// After reading it, we have now info about the original type
|
||||
OriginalType = _cmsGetTagTrueType(hProfile, tag16);
|
||||
|
||||
// The profile owns the Lut, so we need to copy it
|
||||
Lut = cmsPipelineDup(Lut);
|
||||
|
||||
// We need to adjust data only for Lab16 on output
|
||||
if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
|
||||
return Lut;
|
||||
|
||||
// If the input is Lab, add also a conversion at the begin
|
||||
if (cmsGetColorSpace(hProfile) == cmsSigLabData)
|
||||
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
|
||||
|
||||
// Add a matrix for conversion V2 to V4 Lab PCS
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
|
||||
return Lut;
|
||||
}
|
||||
|
||||
// Lut was not found, try to create a matrix-shaper
|
||||
|
||||
// Check if this is a grayscale profile.
|
||||
if (cmsGetColorSpace(hProfile) == cmsSigGrayData) {
|
||||
|
||||
// if so, build appropiate conversion tables.
|
||||
// The tables are the PCS iluminant, scaled across GrayTRC
|
||||
return BuildGrayInputMatrixPipeline(hProfile);
|
||||
}
|
||||
|
||||
// Not gray, create a normal matrix-shaper
|
||||
return BuildRGBInputMatrixShaper(hProfile);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Gray output pipeline.
|
||||
// XYZ -> Gray or Lab -> Gray. Since we only know the GrayTRC, we need to do some assumptions. Gray component will be
|
||||
// given by Y on XYZ PCS and by L* on Lab PCS, Both across inverse TRC curve.
|
||||
// The complete pipeline on XYZ is Matrix[3:1] -> Tone curve and in Lab Matrix[3:1] -> Tone Curve as well.
|
||||
|
||||
static
|
||||
cmsPipeline* BuildGrayOutputPipeline(cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsToneCurve *GrayTRC, *RevGrayTRC;
|
||||
cmsPipeline* Lut;
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
GrayTRC = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGrayTRCTag);
|
||||
if (GrayTRC == NULL) return NULL;
|
||||
|
||||
RevGrayTRC = cmsReverseToneCurve(GrayTRC);
|
||||
if (RevGrayTRC == NULL) return NULL;
|
||||
|
||||
Lut = cmsPipelineAlloc(ContextID, 3, 1);
|
||||
if (Lut == NULL) {
|
||||
cmsFreeToneCurve(RevGrayTRC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cmsGetPCS(hProfile) == cmsSigLabData) {
|
||||
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL));
|
||||
}
|
||||
else {
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL));
|
||||
}
|
||||
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC));
|
||||
cmsFreeToneCurve(RevGrayTRC);
|
||||
|
||||
return Lut;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static
|
||||
cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsPipeline* Lut;
|
||||
cmsToneCurve *Shapes[3], *InvShapes[3];
|
||||
cmsMAT3 Mat, Inv;
|
||||
int i, j;
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
if (!ReadICCMatrixRGB2XYZ(&Mat, hProfile))
|
||||
return NULL;
|
||||
|
||||
if (!_cmsMAT3inverse(&Mat, &Inv))
|
||||
return NULL;
|
||||
|
||||
// XYZ PCS in encoded in 1.15 format, and the matrix input should come in 0..0xffff range, so
|
||||
// we need to adjust the input by a << 1 to obtain a 1.16 fixed and then by a factor of
|
||||
// (0xffff/0x10000) to put data in 0..0xffff range. Total factor is (2.0*65535.0)/65536.0;
|
||||
|
||||
for (i=0; i < 3; i++)
|
||||
for (j=0; j < 3; j++)
|
||||
Inv.v[i].n[j] *= OutpAdj;
|
||||
|
||||
Shapes[0] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigRedTRCTag);
|
||||
Shapes[1] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigGreenTRCTag);
|
||||
Shapes[2] = (cmsToneCurve *) cmsReadTag(hProfile, cmsSigBlueTRCTag);
|
||||
|
||||
if (!Shapes[0] || !Shapes[1] || !Shapes[2])
|
||||
return NULL;
|
||||
|
||||
InvShapes[0] = cmsReverseToneCurve(Shapes[0]);
|
||||
InvShapes[1] = cmsReverseToneCurve(Shapes[1]);
|
||||
InvShapes[2] = cmsReverseToneCurve(Shapes[2]);
|
||||
|
||||
if (!InvShapes[0] || !InvShapes[1] || !InvShapes[2]) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Lut = cmsPipelineAlloc(ContextID, 3, 3);
|
||||
if (Lut != NULL) {
|
||||
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL));
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes));
|
||||
}
|
||||
|
||||
cmsFreeToneCurveTriple(InvShapes);
|
||||
return Lut;
|
||||
}
|
||||
|
||||
|
||||
// Change CLUT interpolation to trilinear
|
||||
static
|
||||
void ChangeInterpolationToTrilinear(cmsPipeline* Lut)
|
||||
{
|
||||
cmsStage* Stage;
|
||||
|
||||
for (Stage = cmsPipelineGetPtrToFirstStage(Lut);
|
||||
Stage != NULL;
|
||||
Stage = cmsStageNext(Stage)) {
|
||||
|
||||
if (cmsStageType(Stage) == cmsSigCLutElemType) {
|
||||
|
||||
_cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data;
|
||||
|
||||
CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR;
|
||||
_cmsSetInterpolationRoutine(CLUT ->Params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create an output MPE LUT from agiven profile. Version mismatches are handled here
|
||||
cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
|
||||
{
|
||||
cmsTagTypeSignature OriginalType;
|
||||
cmsTagSignature tag16 = PCS2Device16[Intent];
|
||||
cmsTagSignature tagFloat = PCS2DeviceFloat[Intent];
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
|
||||
|
||||
// Floating point LUT are always V4, so no adjustment is required
|
||||
return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
|
||||
}
|
||||
|
||||
// Revert to perceptual if no tag is found
|
||||
if (!cmsIsTag(hProfile, tag16)) {
|
||||
tag16 = PCS2Device16[0];
|
||||
}
|
||||
|
||||
if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
|
||||
|
||||
// Check profile version and LUT type. Do the necessary adjustments if needed
|
||||
|
||||
// First read the tag
|
||||
cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
|
||||
if (Lut == NULL) return NULL;
|
||||
|
||||
// After reading it, we have info about the original type
|
||||
OriginalType = _cmsGetTagTrueType(hProfile, tag16);
|
||||
|
||||
// The profile owns the Lut, so we need to copy it
|
||||
Lut = cmsPipelineDup(Lut);
|
||||
if (Lut == NULL) return NULL;
|
||||
|
||||
// Now it is time for a controversial stuff. I found that for 3D LUTS using
|
||||
// Lab used as indexer space, trilinear interpolation should be used
|
||||
if (cmsGetPCS(hProfile) == cmsSigLabData)
|
||||
ChangeInterpolationToTrilinear(Lut);
|
||||
|
||||
// We need to adjust data only for Lab and Lut16 type
|
||||
if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
|
||||
return Lut;
|
||||
|
||||
// Add a matrix for conversion V4 to V2 Lab PCS
|
||||
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
|
||||
|
||||
// If the output is Lab, add also a conversion at the end
|
||||
if (cmsGetColorSpace(hProfile) == cmsSigLabData)
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
|
||||
|
||||
return Lut;
|
||||
}
|
||||
|
||||
// Lut not found, try to create a matrix-shaper
|
||||
|
||||
// Check if this is a grayscale profile.
|
||||
if (cmsGetColorSpace(hProfile) == cmsSigGrayData) {
|
||||
|
||||
// if so, build appropiate conversion tables.
|
||||
// The tables are the PCS iluminant, scaled across GrayTRC
|
||||
return BuildGrayOutputPipeline(hProfile);
|
||||
}
|
||||
|
||||
// Not gray, create a normal matrix-shaper
|
||||
return BuildRGBOutputMatrixShaper(hProfile);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The
|
||||
// tag name here may default to AToB0
|
||||
cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
|
||||
{
|
||||
cmsPipeline* Lut;
|
||||
cmsTagTypeSignature OriginalType;
|
||||
cmsTagSignature tag16 = Device2PCS16[Intent];
|
||||
cmsTagSignature tagFloat = Device2PCSFloat[Intent];
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
|
||||
// On named color, take the appropiate tag
|
||||
if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {
|
||||
|
||||
cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag);
|
||||
|
||||
if (nc == NULL) return NULL;
|
||||
|
||||
Lut = cmsPipelineAlloc(ContextID, 0, 0);
|
||||
if (Lut == NULL) {
|
||||
cmsFreeNamedColorList(nc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE));
|
||||
if (cmsGetColorSpace(hProfile) == cmsSigLabData)
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
|
||||
return Lut;
|
||||
}
|
||||
|
||||
if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
|
||||
|
||||
// Floating point LUT are always V4, no adjustment is required
|
||||
return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
|
||||
}
|
||||
|
||||
tagFloat = Device2PCSFloat[0];
|
||||
if (cmsIsTag(hProfile, tagFloat)) {
|
||||
|
||||
return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
|
||||
}
|
||||
|
||||
if (!cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
|
||||
|
||||
tag16 = Device2PCS16[0];
|
||||
if (!cmsIsTag(hProfile, tag16)) return NULL;
|
||||
}
|
||||
|
||||
// Check profile version and LUT type. Do the necessary adjustments if needed
|
||||
|
||||
// Read the tag
|
||||
Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
|
||||
if (Lut == NULL) return NULL;
|
||||
|
||||
// The profile owns the Lut, so we need to copy it
|
||||
Lut = cmsPipelineDup(Lut);
|
||||
if (Lut == NULL) return NULL;
|
||||
|
||||
// Now it is time for a controversial stuff. I found that for 3D LUTS using
|
||||
// Lab used as indexer space, trilinear interpolation should be used
|
||||
if (cmsGetColorSpace(hProfile) == cmsSigLabData)
|
||||
ChangeInterpolationToTrilinear(Lut);
|
||||
|
||||
// After reading it, we have info about the original type
|
||||
OriginalType = _cmsGetTagTrueType(hProfile, tag16);
|
||||
|
||||
// We need to adjust data for Lab16 on output
|
||||
if (OriginalType != cmsSigLut16Type) return Lut;
|
||||
|
||||
// Here it is possible to get Lab on both sides
|
||||
|
||||
if (cmsGetPCS(hProfile) == cmsSigLabData) {
|
||||
cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
|
||||
}
|
||||
|
||||
if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
|
||||
cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
|
||||
}
|
||||
|
||||
return Lut;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Returns TRUE if the profile is implemented as matrix-shaper
|
||||
cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile)
|
||||
{
|
||||
switch (cmsGetColorSpace(hProfile)) {
|
||||
|
||||
case cmsSigGrayData:
|
||||
|
||||
return cmsIsTag(hProfile, cmsSigGrayTRCTag);
|
||||
|
||||
case cmsSigRgbData:
|
||||
|
||||
return (cmsIsTag(hProfile, cmsSigRedColorantTag) &&
|
||||
cmsIsTag(hProfile, cmsSigGreenColorantTag) &&
|
||||
cmsIsTag(hProfile, cmsSigBlueColorantTag) &&
|
||||
cmsIsTag(hProfile, cmsSigRedTRCTag) &&
|
||||
cmsIsTag(hProfile, cmsSigGreenTRCTag) &&
|
||||
cmsIsTag(hProfile, cmsSigBlueTRCTag));
|
||||
|
||||
default:
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns TRUE if the intent is implemented as CLUT
|
||||
cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection)
|
||||
{
|
||||
const cmsTagSignature* TagTable;
|
||||
|
||||
// For devicelinks, the supported intent is that one stated in the header
|
||||
if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) {
|
||||
return (cmsGetHeaderRenderingIntent(hProfile) == Intent);
|
||||
}
|
||||
|
||||
switch (UsedDirection) {
|
||||
|
||||
case LCMS_USED_AS_INPUT: TagTable = Device2PCS16; break;
|
||||
case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device16; break;
|
||||
|
||||
// For proofing, we need rel. colorimetric in output. Let's do some recursion
|
||||
case LCMS_USED_AS_PROOF:
|
||||
return cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) &&
|
||||
cmsIsIntentSupported(hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_OUTPUT);
|
||||
|
||||
default:
|
||||
cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_RANGE, "Unexpected direction (%d)", UsedDirection);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return cmsIsTag(hProfile, TagTable[Intent]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Return info about supported intents
|
||||
cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile,
|
||||
cmsUInt32Number Intent, cmsUInt32Number UsedDirection)
|
||||
{
|
||||
|
||||
if (cmsIsCLUT(hProfile, Intent, UsedDirection)) return TRUE;
|
||||
|
||||
// Is there any matrix-shaper? If so, the intent is supported. This is a bit odd, since V2 matrix shaper
|
||||
// does not fully support relative colorimetric because they cannot deal with non-zero black points, but
|
||||
// many profiles claims that, and this is certainly not true for V4 profiles. Lets answer "yes" no matter
|
||||
// the accuracy would be less than optimal in rel.col and v2 case.
|
||||
|
||||
return cmsIsMatrixShaper(hProfile);
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Read both, profile sequence description and profile sequence id if present. Then combine both to
|
||||
// create qa unique structure holding both. Shame on ICC to store things in such complicated way.
|
||||
cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsSEQ* ProfileSeq;
|
||||
cmsSEQ* ProfileId;
|
||||
cmsSEQ* NewSeq;
|
||||
cmsUInt32Number i;
|
||||
|
||||
// Take profile sequence description first
|
||||
ProfileSeq = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceDescTag);
|
||||
|
||||
// Take profile sequence ID
|
||||
ProfileId = (cmsSEQ*) cmsReadTag(hProfile, cmsSigProfileSequenceIdTag);
|
||||
|
||||
if (ProfileSeq == NULL && ProfileId == NULL) return NULL;
|
||||
|
||||
if (ProfileSeq == NULL) return cmsDupProfileSequenceDescription(ProfileId);
|
||||
if (ProfileId == NULL) return cmsDupProfileSequenceDescription(ProfileSeq);
|
||||
|
||||
// We have to mix both together. For that they must agree
|
||||
if (ProfileSeq ->n != ProfileId ->n) return cmsDupProfileSequenceDescription(ProfileSeq);
|
||||
|
||||
NewSeq = cmsDupProfileSequenceDescription(ProfileSeq);
|
||||
|
||||
// Ok, proceed to the mixing
|
||||
if (NewSeq != NULL) {
|
||||
for (i=0; i < ProfileSeq ->n; i++) {
|
||||
|
||||
memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID));
|
||||
NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description);
|
||||
}
|
||||
}
|
||||
return NewSeq;
|
||||
}
|
||||
|
||||
// Dump the contents of profile sequence in both tags (if v4 available)
|
||||
cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq)
|
||||
{
|
||||
if (!cmsWriteTag(hProfile, cmsSigProfileSequenceDescTag, seq)) return FALSE;
|
||||
|
||||
if (cmsGetProfileVersion(hProfile) >= 4.0) {
|
||||
|
||||
if (!cmsWriteTag(hProfile, cmsSigProfileSequenceIdTag, seq)) return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Auxiliar, read and duplicate a MLU if found.
|
||||
static
|
||||
cmsMLU* GetMLUFromProfile(cmsHPROFILE h, cmsTagSignature sig)
|
||||
{
|
||||
cmsMLU* mlu = (cmsMLU*) cmsReadTag(h, sig);
|
||||
if (mlu == NULL) return NULL;
|
||||
|
||||
return cmsMLUdup(mlu);
|
||||
}
|
||||
|
||||
// Create a sequence description out of an array of profiles
|
||||
cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[])
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
cmsSEQ* seq = cmsAllocProfileSequenceDescription(ContextID, nProfiles);
|
||||
|
||||
if (seq == NULL) return NULL;
|
||||
|
||||
for (i=0; i < nProfiles; i++) {
|
||||
|
||||
cmsPSEQDESC* ps = &seq ->seq[i];
|
||||
cmsHPROFILE h = hProfiles[i];
|
||||
cmsTechnologySignature* techpt;
|
||||
|
||||
cmsGetHeaderAttributes(h, &ps ->attributes);
|
||||
cmsGetHeaderProfileID(h, ps ->ProfileID.ID8);
|
||||
ps ->deviceMfg = cmsGetHeaderManufacturer(h);
|
||||
ps ->deviceModel = cmsGetHeaderModel(h);
|
||||
|
||||
techpt = (cmsTechnologySignature*) cmsReadTag(h, cmsSigTechnologyTag);
|
||||
if (techpt == NULL)
|
||||
ps ->technology = (cmsTechnologySignature) 0;
|
||||
else
|
||||
ps ->technology = *techpt;
|
||||
|
||||
ps ->Manufacturer = GetMLUFromProfile(h, cmsSigDeviceMfgDescTag);
|
||||
ps ->Model = GetMLUFromProfile(h, cmsSigDeviceModelDescTag);
|
||||
ps ->Description = GetMLUFromProfile(h, cmsSigProfileDescriptionTag);
|
||||
|
||||
}
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
static
|
||||
const cmsMLU* GetInfo(cmsHPROFILE hProfile, cmsInfoType Info)
|
||||
{
|
||||
cmsTagSignature sig;
|
||||
|
||||
switch (Info) {
|
||||
|
||||
case cmsInfoDescription:
|
||||
sig = cmsSigProfileDescriptionTag;
|
||||
break;
|
||||
|
||||
case cmsInfoManufacturer:
|
||||
sig = cmsSigDeviceMfgDescTag;
|
||||
break;
|
||||
|
||||
case cmsInfoModel:
|
||||
sig = cmsSigDeviceModelDescTag;
|
||||
break;
|
||||
|
||||
case cmsInfoCopyright:
|
||||
sig = cmsSigCopyrightTag;
|
||||
break;
|
||||
|
||||
default: return NULL;
|
||||
}
|
||||
|
||||
|
||||
return (cmsMLU*) cmsReadTag(hProfile, sig);
|
||||
}
|
||||
|
||||
|
||||
|
||||
cmsUInt32Number CMSEXPORT cmsGetProfileInfo(cmsHPROFILE hProfile, cmsInfoType Info,
|
||||
const char LanguageCode[3], const char CountryCode[3],
|
||||
wchar_t* Buffer, cmsUInt32Number BufferSize)
|
||||
{
|
||||
const cmsMLU* mlu = GetInfo(hProfile, Info);
|
||||
if (mlu == NULL) return 0;
|
||||
|
||||
return cmsMLUgetWide(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
|
||||
}
|
||||
|
||||
|
||||
cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoType Info,
|
||||
const char LanguageCode[3], const char CountryCode[3],
|
||||
char* Buffer, cmsUInt32Number BufferSize)
|
||||
{
|
||||
const cmsMLU* mlu = GetInfo(hProfile, Info);
|
||||
if (mlu == NULL) return 0;
|
||||
|
||||
return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,317 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
#ifdef CMS_USE_BIG_ENDIAN
|
||||
|
||||
static
|
||||
void byteReverse(cmsUInt8Number * buf, cmsUInt32Number longs)
|
||||
{
|
||||
do {
|
||||
|
||||
cmsUInt32Number t = _cmsAdjustEndianess32(*(cmsUInt32Number *) buf);
|
||||
*(cmsUInt32Number *) buf = t;
|
||||
buf += sizeof(cmsUInt32Number);
|
||||
|
||||
} while (--longs);
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
#define byteReverse(buf, len)
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
cmsUInt32Number buf[4];
|
||||
cmsUInt32Number bits[2];
|
||||
cmsUInt8Number in[64];
|
||||
cmsContext ContextID;
|
||||
|
||||
} _cmsMD5;
|
||||
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
#define STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
|
||||
static
|
||||
void MD5_Transform(cmsUInt32Number buf[4], cmsUInt32Number in[16])
|
||||
|
||||
{
|
||||
register cmsUInt32Number a, b, c, d;
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
|
||||
STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
|
||||
// Create a MD5 object
|
||||
static
|
||||
cmsHANDLE MD5alloc(cmsContext ContextID)
|
||||
{
|
||||
_cmsMD5* ctx = (_cmsMD5*) _cmsMallocZero(ContextID, sizeof(_cmsMD5));
|
||||
if (ctx == NULL) return NULL;
|
||||
|
||||
ctx ->ContextID = ContextID;
|
||||
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
|
||||
return (cmsHANDLE) ctx;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void MD5add(cmsHANDLE Handle, cmsUInt8Number* buf, cmsUInt32Number len)
|
||||
{
|
||||
_cmsMD5* ctx = (_cmsMD5*) Handle;
|
||||
cmsUInt32Number t;
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = t + (len << 3)) < t)
|
||||
ctx->bits[1]++;
|
||||
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f;
|
||||
|
||||
if (t) {
|
||||
|
||||
cmsUInt8Number *p = (cmsUInt8Number *) ctx->in + t;
|
||||
|
||||
t = 64 - t;
|
||||
if (len < t) {
|
||||
memmove(p, buf, len);
|
||||
return;
|
||||
}
|
||||
|
||||
memmove(p, buf, t);
|
||||
byteReverse(ctx->in, 16);
|
||||
|
||||
MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
|
||||
while (len >= 64) {
|
||||
memmove(ctx->in, buf, 64);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
memmove(ctx->in, buf, len);
|
||||
}
|
||||
|
||||
// Destroy the object and return the checksum
|
||||
static
|
||||
void MD5finish(cmsProfileID* ProfileID, cmsHANDLE Handle)
|
||||
{
|
||||
_cmsMD5* ctx = (_cmsMD5*) Handle;
|
||||
cmsUInt32Number count;
|
||||
cmsUInt8Number *p;
|
||||
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
p = ctx->in + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
count = 64 - 1 - count;
|
||||
|
||||
if (count < 8) {
|
||||
|
||||
memset(p, 0, count);
|
||||
byteReverse(ctx->in, 16);
|
||||
MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
|
||||
|
||||
memset(ctx->in, 0, 56);
|
||||
} else {
|
||||
memset(p, 0, count - 8);
|
||||
}
|
||||
byteReverse(ctx->in, 14);
|
||||
|
||||
((cmsUInt32Number *) ctx->in)[14] = ctx->bits[0];
|
||||
((cmsUInt32Number *) ctx->in)[15] = ctx->bits[1];
|
||||
|
||||
MD5_Transform(ctx->buf, (cmsUInt32Number *) ctx->in);
|
||||
|
||||
byteReverse((cmsUInt8Number *) ctx->buf, 4);
|
||||
memmove(ProfileID ->ID8, ctx->buf, 16);
|
||||
|
||||
_cmsFree(ctx ->ContextID, ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Assuming io points to an ICC profile, compute and store MD5 checksum
|
||||
// In the header, rendering intentent, attributes and ID should be set to zero
|
||||
// before computing MD5 checksum (per 6.1.13 in ICC spec)
|
||||
|
||||
cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile)
|
||||
{
|
||||
cmsContext ContextID;
|
||||
cmsUInt32Number BytesNeeded;
|
||||
cmsUInt8Number* Mem = NULL;
|
||||
cmsHANDLE MD5 = NULL;
|
||||
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
|
||||
_cmsICCPROFILE Keep;
|
||||
|
||||
_cmsAssert(hProfile != NULL);
|
||||
|
||||
ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
// Save a copy of the profile header
|
||||
memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
|
||||
|
||||
// Set RI, attributes and ID
|
||||
memset(&Icc ->attributes, 0, sizeof(Icc ->attributes));
|
||||
Icc ->RenderingIntent = 0;
|
||||
memset(&Icc ->ProfileID, 0, sizeof(Icc ->ProfileID));
|
||||
|
||||
// Compute needed storage
|
||||
if (!cmsSaveProfileToMem(hProfile, NULL, &BytesNeeded)) goto Error;
|
||||
|
||||
// Allocate memory
|
||||
Mem = (cmsUInt8Number*) _cmsMalloc(ContextID, BytesNeeded);
|
||||
if (Mem == NULL) goto Error;
|
||||
|
||||
// Save to temporary storage
|
||||
if (!cmsSaveProfileToMem(hProfile, Mem, &BytesNeeded)) goto Error;
|
||||
|
||||
// Create MD5 object
|
||||
MD5 = MD5alloc(ContextID);
|
||||
if (MD5 == NULL) goto Error;
|
||||
|
||||
// Add all bytes
|
||||
MD5add(MD5, Mem, BytesNeeded);
|
||||
|
||||
// Temp storage is no longer needed
|
||||
_cmsFree(ContextID, Mem);
|
||||
|
||||
// Restore header
|
||||
memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
|
||||
|
||||
// And store the ID
|
||||
MD5finish(&Icc ->ProfileID, MD5);
|
||||
return TRUE;
|
||||
|
||||
Error:
|
||||
|
||||
// Free resources as something went wrong
|
||||
if (MD5 != NULL) _cmsFree(ContextID, MD5);
|
||||
if (Mem != NULL) _cmsFree(ContextID, Mem);
|
||||
memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
|
||||
#define DSWAP(x, y) {cmsFloat64Number tmp = (x); (x)=(y); (y)=tmp;}
|
||||
|
||||
|
||||
// Initiate a vector
|
||||
void CMSEXPORT _cmsVEC3init(cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z)
|
||||
{
|
||||
r -> n[VX] = x;
|
||||
r -> n[VY] = y;
|
||||
r -> n[VZ] = z;
|
||||
}
|
||||
|
||||
// Vector substraction
|
||||
void CMSEXPORT _cmsVEC3minus(cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b)
|
||||
{
|
||||
r -> n[VX] = a -> n[VX] - b -> n[VX];
|
||||
r -> n[VY] = a -> n[VY] - b -> n[VY];
|
||||
r -> n[VZ] = a -> n[VZ] - b -> n[VZ];
|
||||
}
|
||||
|
||||
// Vector cross product
|
||||
void CMSEXPORT _cmsVEC3cross(cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v)
|
||||
{
|
||||
r ->n[VX] = u->n[VY] * v->n[VZ] - v->n[VY] * u->n[VZ];
|
||||
r ->n[VY] = u->n[VZ] * v->n[VX] - v->n[VZ] * u->n[VX];
|
||||
r ->n[VZ] = u->n[VX] * v->n[VY] - v->n[VX] * u->n[VY];
|
||||
}
|
||||
|
||||
// Vector dot product
|
||||
cmsFloat64Number CMSEXPORT _cmsVEC3dot(const cmsVEC3* u, const cmsVEC3* v)
|
||||
{
|
||||
return u->n[VX] * v->n[VX] + u->n[VY] * v->n[VY] + u->n[VZ] * v->n[VZ];
|
||||
}
|
||||
|
||||
// Euclidean length
|
||||
cmsFloat64Number CMSEXPORT _cmsVEC3length(const cmsVEC3* a)
|
||||
{
|
||||
return sqrt(a ->n[VX] * a ->n[VX] +
|
||||
a ->n[VY] * a ->n[VY] +
|
||||
a ->n[VZ] * a ->n[VZ]);
|
||||
}
|
||||
|
||||
// Euclidean distance
|
||||
cmsFloat64Number CMSEXPORT _cmsVEC3distance(const cmsVEC3* a, const cmsVEC3* b)
|
||||
{
|
||||
cmsFloat64Number d1 = a ->n[VX] - b ->n[VX];
|
||||
cmsFloat64Number d2 = a ->n[VY] - b ->n[VY];
|
||||
cmsFloat64Number d3 = a ->n[VZ] - b ->n[VZ];
|
||||
|
||||
return sqrt(d1*d1 + d2*d2 + d3*d3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 3x3 Identity
|
||||
void CMSEXPORT _cmsMAT3identity(cmsMAT3* a)
|
||||
{
|
||||
_cmsVEC3init(&a-> v[0], 1.0, 0.0, 0.0);
|
||||
_cmsVEC3init(&a-> v[1], 0.0, 1.0, 0.0);
|
||||
_cmsVEC3init(&a-> v[2], 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
static
|
||||
cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b)
|
||||
{
|
||||
return fabs(b - a) < (1.0 / 65535.0);
|
||||
}
|
||||
|
||||
|
||||
cmsBool CMSEXPORT _cmsMAT3isIdentity(const cmsMAT3* a)
|
||||
{
|
||||
cmsMAT3 Identity;
|
||||
int i, j;
|
||||
|
||||
_cmsMAT3identity(&Identity);
|
||||
|
||||
for (i=0; i < 3; i++)
|
||||
for (j=0; j < 3; j++)
|
||||
if (!CloseEnough(a ->v[i].n[j], Identity.v[i].n[j])) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Multiply two matrices
|
||||
void CMSEXPORT _cmsMAT3per(cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b)
|
||||
{
|
||||
#define ROWCOL(i, j) \
|
||||
a->v[i].n[0]*b->v[0].n[j] + a->v[i].n[1]*b->v[1].n[j] + a->v[i].n[2]*b->v[2].n[j]
|
||||
|
||||
_cmsVEC3init(&r-> v[0], ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2));
|
||||
_cmsVEC3init(&r-> v[1], ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2));
|
||||
_cmsVEC3init(&r-> v[2], ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2));
|
||||
|
||||
#undef ROWCOL //(i, j)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Inverse of a matrix b = a^(-1)
|
||||
cmsBool CMSEXPORT _cmsMAT3inverse(const cmsMAT3* a, cmsMAT3* b)
|
||||
{
|
||||
cmsFloat64Number det, c0, c1, c2;
|
||||
|
||||
c0 = a -> v[1].n[1]*a -> v[2].n[2] - a -> v[1].n[2]*a -> v[2].n[1];
|
||||
c1 = -a -> v[1].n[0]*a -> v[2].n[2] + a -> v[1].n[2]*a -> v[2].n[0];
|
||||
c2 = a -> v[1].n[0]*a -> v[2].n[1] - a -> v[1].n[1]*a -> v[2].n[0];
|
||||
|
||||
det = a -> v[0].n[0]*c0 + a -> v[0].n[1]*c1 + a -> v[0].n[2]*c2;
|
||||
|
||||
if (fabs(det) < MATRIX_DET_TOLERANCE) return FALSE; // singular matrix; can't invert
|
||||
|
||||
b -> v[0].n[0] = c0/det;
|
||||
b -> v[0].n[1] = (a -> v[0].n[2]*a -> v[2].n[1] - a -> v[0].n[1]*a -> v[2].n[2])/det;
|
||||
b -> v[0].n[2] = (a -> v[0].n[1]*a -> v[1].n[2] - a -> v[0].n[2]*a -> v[1].n[1])/det;
|
||||
b -> v[1].n[0] = c1/det;
|
||||
b -> v[1].n[1] = (a -> v[0].n[0]*a -> v[2].n[2] - a -> v[0].n[2]*a -> v[2].n[0])/det;
|
||||
b -> v[1].n[2] = (a -> v[0].n[2]*a -> v[1].n[0] - a -> v[0].n[0]*a -> v[1].n[2])/det;
|
||||
b -> v[2].n[0] = c2/det;
|
||||
b -> v[2].n[1] = (a -> v[0].n[1]*a -> v[2].n[0] - a -> v[0].n[0]*a -> v[2].n[1])/det;
|
||||
b -> v[2].n[2] = (a -> v[0].n[0]*a -> v[1].n[1] - a -> v[0].n[1]*a -> v[1].n[0])/det;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Solve a system in the form Ax = b
|
||||
cmsBool CMSEXPORT _cmsMAT3solve(cmsVEC3* x, cmsMAT3* a, cmsVEC3* b)
|
||||
{
|
||||
cmsMAT3 m, a_1;
|
||||
|
||||
memmove(&m, a, sizeof(cmsMAT3));
|
||||
|
||||
if (!_cmsMAT3inverse(&m, &a_1)) return FALSE; // Singular matrix
|
||||
|
||||
_cmsMAT3eval(x, &a_1, b);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Evaluate a vector across a matrix
|
||||
void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v)
|
||||
{
|
||||
r->n[VX] = a->v[0].n[VX]*v->n[VX] + a->v[0].n[VY]*v->n[VY] + a->v[0].n[VZ]*v->n[VZ];
|
||||
r->n[VY] = a->v[1].n[VX]*v->n[VX] + a->v[1].n[VY]*v->n[VY] + a->v[1].n[VZ]*v->n[VZ];
|
||||
r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,893 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
// Multilocalized unicode objects. That is an attempt to encapsulate i18n.
|
||||
|
||||
|
||||
// Allocates an empty multi localizad unicode object
|
||||
cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems)
|
||||
{
|
||||
cmsMLU* mlu;
|
||||
|
||||
// nItems should be positive if given
|
||||
if (nItems <= 0) nItems = 2;
|
||||
|
||||
// Create the container
|
||||
mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU));
|
||||
if (mlu == NULL) return NULL;
|
||||
|
||||
mlu ->ContextID = ContextID;
|
||||
|
||||
// Create entry array
|
||||
mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry));
|
||||
if (mlu ->Entries == NULL) {
|
||||
_cmsFree(ContextID, mlu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ok, keep indexes up to date
|
||||
mlu ->AllocatedEntries = nItems;
|
||||
mlu ->UsedEntries = 0;
|
||||
|
||||
return mlu;
|
||||
}
|
||||
|
||||
|
||||
// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two.
|
||||
static
|
||||
cmsBool GrowMLUpool(cmsMLU* mlu)
|
||||
{
|
||||
cmsUInt32Number size;
|
||||
void *NewPtr;
|
||||
|
||||
// Sanity check
|
||||
if (mlu == NULL) return FALSE;
|
||||
|
||||
if (mlu ->PoolSize == 0)
|
||||
size = 256;
|
||||
else
|
||||
size = mlu ->PoolSize * 2;
|
||||
|
||||
// Check for overflow
|
||||
if (size < mlu ->PoolSize) return FALSE;
|
||||
|
||||
// Reallocate the pool
|
||||
NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size);
|
||||
if (NewPtr == NULL) return FALSE;
|
||||
|
||||
|
||||
mlu ->MemPool = NewPtr;
|
||||
mlu ->PoolSize = size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Grows a ntry table for a MLU. Each time this function is called, table size is multiplied times two.
|
||||
static
|
||||
cmsBool GrowMLUtable(cmsMLU* mlu)
|
||||
{
|
||||
int AllocatedEntries;
|
||||
_cmsMLUentry *NewPtr;
|
||||
|
||||
// Sanity check
|
||||
if (mlu == NULL) return FALSE;
|
||||
|
||||
AllocatedEntries = mlu ->AllocatedEntries * 2;
|
||||
|
||||
// Check for overflow
|
||||
if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE;
|
||||
|
||||
// Reallocate the memory
|
||||
NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry));
|
||||
if (NewPtr == NULL) return FALSE;
|
||||
|
||||
mlu ->Entries = NewPtr;
|
||||
mlu ->AllocatedEntries = AllocatedEntries;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Search for a specific entry in the structure. Language and Country are used.
|
||||
static
|
||||
int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Sanity check
|
||||
if (mlu == NULL) return -1;
|
||||
|
||||
// Iterate whole table
|
||||
for (i=0; i < mlu ->UsedEntries; i++) {
|
||||
|
||||
if (mlu ->Entries[i].Country == CountryCode &&
|
||||
mlu ->Entries[i].Language == LanguageCode) return i;
|
||||
}
|
||||
|
||||
// Not found
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add a block of characters to the intended MLU. Language and country are specified.
|
||||
// Only one entry for Language/country pair is allowed.
|
||||
static
|
||||
cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block,
|
||||
cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
|
||||
{
|
||||
cmsUInt32Number Offset;
|
||||
cmsUInt8Number* Ptr;
|
||||
|
||||
// Sanity check
|
||||
if (mlu == NULL) return FALSE;
|
||||
|
||||
// Is there any room available?
|
||||
if (mlu ->UsedEntries >= mlu ->AllocatedEntries) {
|
||||
if (!GrowMLUtable(mlu)) return FALSE;
|
||||
}
|
||||
|
||||
// Only one ASCII string
|
||||
if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed!
|
||||
|
||||
// Check for size
|
||||
while ((mlu ->PoolSize - mlu ->PoolUsed) < size) {
|
||||
|
||||
if (!GrowMLUpool(mlu)) return FALSE;
|
||||
}
|
||||
|
||||
Offset = mlu ->PoolUsed;
|
||||
|
||||
Ptr = (cmsUInt8Number*) mlu ->MemPool;
|
||||
if (Ptr == NULL) return FALSE;
|
||||
|
||||
// Set the entry
|
||||
memmove(Ptr + Offset, Block, size);
|
||||
mlu ->PoolUsed += size;
|
||||
|
||||
mlu ->Entries[mlu ->UsedEntries].StrW = Offset;
|
||||
mlu ->Entries[mlu ->UsedEntries].Len = size;
|
||||
mlu ->Entries[mlu ->UsedEntries].Country = CountryCode;
|
||||
mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode;
|
||||
mlu ->UsedEntries++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Add an ASCII entry.
|
||||
cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
|
||||
{
|
||||
cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1;
|
||||
wchar_t* WStr;
|
||||
cmsBool rc;
|
||||
cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
|
||||
cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
|
||||
|
||||
if (mlu == NULL) return FALSE;
|
||||
|
||||
WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t));
|
||||
if (WStr == NULL) return FALSE;
|
||||
|
||||
for (i=0; i < len; i++)
|
||||
WStr[i] = (wchar_t) ASCIIString[i];
|
||||
|
||||
rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);
|
||||
|
||||
_cmsFree(mlu ->ContextID, WStr);
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
// We don't need any wcs support library
|
||||
static
|
||||
cmsUInt32Number mywcslen(const wchar_t *s)
|
||||
{
|
||||
const wchar_t *p;
|
||||
|
||||
p = s;
|
||||
while (*p)
|
||||
p++;
|
||||
|
||||
return (cmsUInt32Number)(p - s);
|
||||
}
|
||||
|
||||
|
||||
// Add a wide entry
|
||||
cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString)
|
||||
{
|
||||
cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language);
|
||||
cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country);
|
||||
cmsUInt32Number len;
|
||||
|
||||
if (mlu == NULL) return FALSE;
|
||||
if (WideString == NULL) return FALSE;
|
||||
|
||||
len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t);
|
||||
return AddMLUBlock(mlu, len, WideString, Lang, Cntry);
|
||||
}
|
||||
|
||||
// Duplicating a MLU is as easy as copying all members
|
||||
cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu)
|
||||
{
|
||||
cmsMLU* NewMlu = NULL;
|
||||
|
||||
// Duplicating a NULL obtains a NULL
|
||||
if (mlu == NULL) return NULL;
|
||||
|
||||
NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries);
|
||||
if (NewMlu == NULL) return NULL;
|
||||
|
||||
// Should never happen
|
||||
if (NewMlu ->AllocatedEntries < mlu ->UsedEntries)
|
||||
goto Error;
|
||||
|
||||
// Sanitize...
|
||||
if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error;
|
||||
|
||||
memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry));
|
||||
NewMlu ->UsedEntries = mlu ->UsedEntries;
|
||||
|
||||
// The MLU may be empty
|
||||
if (mlu ->PoolUsed == 0) {
|
||||
NewMlu ->MemPool = NULL;
|
||||
}
|
||||
else {
|
||||
// It is not empty
|
||||
NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed);
|
||||
if (NewMlu ->MemPool == NULL) goto Error;
|
||||
}
|
||||
|
||||
NewMlu ->PoolSize = mlu ->PoolUsed;
|
||||
|
||||
if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error;
|
||||
|
||||
memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed);
|
||||
NewMlu ->PoolUsed = mlu ->PoolUsed;
|
||||
|
||||
return NewMlu;
|
||||
|
||||
Error:
|
||||
|
||||
if (NewMlu != NULL) cmsMLUfree(NewMlu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Free any used memory
|
||||
void CMSEXPORT cmsMLUfree(cmsMLU* mlu)
|
||||
{
|
||||
if (mlu) {
|
||||
|
||||
if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries);
|
||||
if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool);
|
||||
|
||||
_cmsFree(mlu ->ContextID, mlu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The algorithm first searches for an exact match of country and language, if not found it uses
|
||||
// the Language. If none is found, first entry is used instead.
|
||||
static
|
||||
const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
|
||||
cmsUInt32Number *len,
|
||||
cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode,
|
||||
cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode)
|
||||
{
|
||||
int i;
|
||||
int Best = -1;
|
||||
_cmsMLUentry* v;
|
||||
|
||||
if (mlu == NULL) return NULL;
|
||||
|
||||
if (mlu -> AllocatedEntries <= 0) return NULL;
|
||||
|
||||
for (i=0; i < mlu ->UsedEntries; i++) {
|
||||
|
||||
v = mlu ->Entries + i;
|
||||
|
||||
if (v -> Language == LanguageCode) {
|
||||
|
||||
if (Best == -1) Best = i;
|
||||
|
||||
if (v -> Country == CountryCode) {
|
||||
|
||||
if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
|
||||
if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
|
||||
|
||||
if (len != NULL) *len = v ->Len;
|
||||
|
||||
return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No string found. Return First one
|
||||
if (Best == -1)
|
||||
Best = 0;
|
||||
|
||||
v = mlu ->Entries + Best;
|
||||
|
||||
if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
|
||||
if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
|
||||
|
||||
if (len != NULL) *len = v ->Len;
|
||||
|
||||
return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
|
||||
}
|
||||
|
||||
|
||||
// Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len
|
||||
cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
|
||||
const char LanguageCode[3], const char CountryCode[3],
|
||||
char* Buffer, cmsUInt32Number BufferSize)
|
||||
{
|
||||
const wchar_t *Wide;
|
||||
cmsUInt32Number StrLen = 0;
|
||||
cmsUInt32Number ASCIIlen, i;
|
||||
|
||||
cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
|
||||
cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
|
||||
|
||||
// Sanitize
|
||||
if (mlu == NULL) return 0;
|
||||
|
||||
// Get WideChar
|
||||
Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
|
||||
if (Wide == NULL) return 0;
|
||||
|
||||
ASCIIlen = StrLen / sizeof(wchar_t);
|
||||
|
||||
// Maybe we want only to know the len?
|
||||
if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end
|
||||
|
||||
// No buffer size means no data
|
||||
if (BufferSize <= 0) return 0;
|
||||
|
||||
// Some clipping may be required
|
||||
if (BufferSize < ASCIIlen + 1)
|
||||
ASCIIlen = BufferSize - 1;
|
||||
|
||||
// Precess each character
|
||||
for (i=0; i < ASCIIlen; i++) {
|
||||
|
||||
if (Wide[i] == 0)
|
||||
Buffer[i] = 0;
|
||||
else
|
||||
Buffer[i] = (char) Wide[i];
|
||||
}
|
||||
|
||||
// We put a termination "\0"
|
||||
Buffer[ASCIIlen] = 0;
|
||||
return ASCIIlen + 1;
|
||||
}
|
||||
|
||||
// Obtain a wide representation of the MLU, on depending on current locale settings
|
||||
cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
|
||||
const char LanguageCode[3], const char CountryCode[3],
|
||||
wchar_t* Buffer, cmsUInt32Number BufferSize)
|
||||
{
|
||||
const wchar_t *Wide;
|
||||
cmsUInt32Number StrLen = 0;
|
||||
|
||||
cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
|
||||
cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
|
||||
|
||||
// Sanitize
|
||||
if (mlu == NULL) return 0;
|
||||
|
||||
Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
|
||||
if (Wide == NULL) return 0;
|
||||
|
||||
// Maybe we want only to know the len?
|
||||
if (Buffer == NULL) return StrLen + sizeof(wchar_t);
|
||||
|
||||
// No buffer size means no data
|
||||
if (BufferSize <= 0) return 0;
|
||||
|
||||
// Some clipping may be required
|
||||
if (BufferSize < StrLen + sizeof(wchar_t))
|
||||
StrLen = BufferSize - + sizeof(wchar_t);
|
||||
|
||||
memmove(Buffer, Wide, StrLen);
|
||||
Buffer[StrLen / sizeof(wchar_t)] = 0;
|
||||
|
||||
return StrLen + sizeof(wchar_t);
|
||||
}
|
||||
|
||||
|
||||
// Get also the language and country
|
||||
CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
|
||||
const char LanguageCode[3], const char CountryCode[3],
|
||||
char ObtainedLanguage[3], char ObtainedCountry[3])
|
||||
{
|
||||
const wchar_t *Wide;
|
||||
|
||||
cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
|
||||
cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
|
||||
cmsUInt16Number ObtLang, ObtCode;
|
||||
|
||||
// Sanitize
|
||||
if (mlu == NULL) return FALSE;
|
||||
|
||||
Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode);
|
||||
if (Wide == NULL) return FALSE;
|
||||
|
||||
// Get used language and code
|
||||
*(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang);
|
||||
*(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode);
|
||||
|
||||
ObtainedLanguage[2] = ObtainedCountry[2] = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Named color lists --------------------------------------------------------------------------------------------
|
||||
|
||||
// Grow the list to keep at least NumElements
|
||||
static
|
||||
cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v)
|
||||
{
|
||||
cmsUInt32Number size;
|
||||
_cmsNAMEDCOLOR * NewPtr;
|
||||
|
||||
if (v == NULL) return FALSE;
|
||||
|
||||
if (v ->Allocated == 0)
|
||||
size = 64; // Initial guess
|
||||
else
|
||||
size = v ->Allocated * 2;
|
||||
|
||||
// Keep a maximum color lists can grow, 100K entries seems reasonable
|
||||
if (size > 1024*100) return FALSE;
|
||||
|
||||
NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR));
|
||||
if (NewPtr == NULL)
|
||||
return FALSE;
|
||||
|
||||
v ->List = NewPtr;
|
||||
v ->Allocated = size;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Allocate a list for n elements
|
||||
cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix)
|
||||
{
|
||||
cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST));
|
||||
|
||||
if (v == NULL) return NULL;
|
||||
|
||||
v ->List = NULL;
|
||||
v ->nColors = 0;
|
||||
v ->ContextID = ContextID;
|
||||
|
||||
while (v -> Allocated < n)
|
||||
GrowNamedColorList(v);
|
||||
|
||||
strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix));
|
||||
strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix));
|
||||
v -> ColorantCount = ColorantCount;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
// Free a list
|
||||
void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v)
|
||||
{
|
||||
if (v ->List) _cmsFree(v ->ContextID, v ->List);
|
||||
if (v) _cmsFree(v ->ContextID, v);
|
||||
}
|
||||
|
||||
cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)
|
||||
{
|
||||
cmsNAMEDCOLORLIST* NewNC;
|
||||
|
||||
if (v == NULL) return NULL;
|
||||
|
||||
NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix);
|
||||
if (NewNC == NULL) return NULL;
|
||||
|
||||
// For really large tables we need this
|
||||
while (NewNC ->Allocated < v ->Allocated)
|
||||
GrowNamedColorList(NewNC);
|
||||
|
||||
memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix));
|
||||
memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix));
|
||||
NewNC ->ColorantCount = v ->ColorantCount;
|
||||
memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR));
|
||||
NewNC ->nColors = v ->nColors;
|
||||
return NewNC;
|
||||
}
|
||||
|
||||
|
||||
// Append a color to a list. List pointer may change if reallocated
|
||||
cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList,
|
||||
const char* Name,
|
||||
cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS])
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
|
||||
if (NamedColorList == NULL) return FALSE;
|
||||
|
||||
if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) {
|
||||
if (!GrowNamedColorList(NamedColorList)) return FALSE;
|
||||
}
|
||||
|
||||
for (i=0; i < NamedColorList ->ColorantCount; i++)
|
||||
NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL? 0 : Colorant[i];
|
||||
|
||||
for (i=0; i < 3; i++)
|
||||
NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i];
|
||||
|
||||
if (Name != NULL)
|
||||
strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name,
|
||||
sizeof(NamedColorList ->List[NamedColorList ->nColors].Name));
|
||||
else
|
||||
NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0;
|
||||
|
||||
|
||||
NamedColorList ->nColors++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Returns number of elements
|
||||
cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList)
|
||||
{
|
||||
if (NamedColorList == NULL) return 0;
|
||||
return NamedColorList ->nColors;
|
||||
}
|
||||
|
||||
// Info aboout a given color
|
||||
cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
|
||||
char* Name,
|
||||
char* Prefix,
|
||||
char* Suffix,
|
||||
cmsUInt16Number* PCS,
|
||||
cmsUInt16Number* Colorant)
|
||||
{
|
||||
if (NamedColorList == NULL) return FALSE;
|
||||
|
||||
if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE;
|
||||
|
||||
if (Name) strcpy(Name, NamedColorList->List[nColor].Name);
|
||||
if (Prefix) strcpy(Prefix, NamedColorList->Prefix);
|
||||
if (Suffix) strcpy(Suffix, NamedColorList->Suffix);
|
||||
if (PCS)
|
||||
memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number));
|
||||
|
||||
if (Colorant)
|
||||
memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant,
|
||||
sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount);
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Search for a given color name (no prefix or suffix)
|
||||
cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
if (NamedColorList == NULL) return -1;
|
||||
n = cmsNamedColorCount(NamedColorList);
|
||||
for (i=0; i < n; i++) {
|
||||
if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// MPE support -----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
static
|
||||
void FreeNamedColorList(cmsStage* mpe)
|
||||
{
|
||||
cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
|
||||
cmsFreeNamedColorList(List);
|
||||
}
|
||||
|
||||
static
|
||||
void* DupNamedColorList(cmsStage* mpe)
|
||||
{
|
||||
cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
|
||||
return cmsDupNamedColorList(List);
|
||||
}
|
||||
|
||||
static
|
||||
void EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
|
||||
{
|
||||
cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
|
||||
cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
|
||||
|
||||
if (index >= NamedColorList-> nColors) {
|
||||
cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
|
||||
}
|
||||
else {
|
||||
|
||||
// Named color always uses Lab
|
||||
Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0);
|
||||
Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0);
|
||||
Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
|
||||
{
|
||||
cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
|
||||
cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
|
||||
cmsUInt32Number j;
|
||||
|
||||
if (index >= NamedColorList-> nColors) {
|
||||
cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
|
||||
}
|
||||
else {
|
||||
for (j=0; j < NamedColorList ->ColorantCount; j++)
|
||||
Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Named color lookup element
|
||||
cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS)
|
||||
{
|
||||
return _cmsStageAllocPlaceholder(NamedColorList ->ContextID,
|
||||
cmsSigNamedColorElemType,
|
||||
1, UsePCS ? 3 : NamedColorList ->ColorantCount,
|
||||
UsePCS ? EvalNamedColorPCS : EvalNamedColor,
|
||||
DupNamedColorList,
|
||||
FreeNamedColorList,
|
||||
cmsDupNamedColorList(NamedColorList));
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Retrieve the named color list from a transform. Should be first element in the LUT
|
||||
cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform)
|
||||
{
|
||||
_cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
|
||||
cmsStage* mpe = v ->Lut->Elements;
|
||||
|
||||
if (mpe ->Type != cmsSigNamedColorElemType) return NULL;
|
||||
return (cmsNAMEDCOLORLIST*) mpe ->Data;
|
||||
}
|
||||
|
||||
|
||||
// Profile sequence description routines -------------------------------------------------------------------------------------
|
||||
|
||||
cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n)
|
||||
{
|
||||
cmsSEQ* Seq;
|
||||
cmsUInt32Number i;
|
||||
|
||||
if (n == 0) return NULL;
|
||||
|
||||
// In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked
|
||||
// in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door!
|
||||
if (n > 255) return NULL;
|
||||
|
||||
Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ));
|
||||
if (Seq == NULL) return NULL;
|
||||
|
||||
Seq -> ContextID = ContextID;
|
||||
Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC));
|
||||
Seq -> n = n;
|
||||
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
Seq -> seq[i].Manufacturer = NULL;
|
||||
Seq -> seq[i].Model = NULL;
|
||||
Seq -> seq[i].Description = NULL;
|
||||
}
|
||||
|
||||
return Seq;
|
||||
}
|
||||
|
||||
void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
|
||||
for (i=0; i < pseq ->n; i++) {
|
||||
if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
|
||||
if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
|
||||
if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
|
||||
}
|
||||
|
||||
if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq);
|
||||
_cmsFree(pseq -> ContextID, pseq);
|
||||
}
|
||||
|
||||
cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq)
|
||||
{
|
||||
cmsSEQ *NewSeq;
|
||||
cmsUInt32Number i;
|
||||
|
||||
if (pseq == NULL)
|
||||
return NULL;
|
||||
|
||||
NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ));
|
||||
if (NewSeq == NULL) return NULL;
|
||||
|
||||
|
||||
NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC));
|
||||
if (NewSeq ->seq == NULL) goto Error;
|
||||
|
||||
NewSeq -> ContextID = pseq ->ContextID;
|
||||
NewSeq -> n = pseq ->n;
|
||||
|
||||
for (i=0; i < pseq->n; i++) {
|
||||
|
||||
memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number));
|
||||
|
||||
NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg;
|
||||
NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel;
|
||||
memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID));
|
||||
NewSeq ->seq[i].technology = pseq ->seq[i].technology;
|
||||
|
||||
NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer);
|
||||
NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model);
|
||||
NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description);
|
||||
|
||||
}
|
||||
|
||||
return NewSeq;
|
||||
|
||||
Error:
|
||||
|
||||
cmsFreeProfileSequenceDescription(NewSeq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Dictionaries --------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Dictionaries are just very simple linked lists
|
||||
|
||||
|
||||
typedef struct _cmsDICT_struct {
|
||||
cmsDICTentry* head;
|
||||
cmsContext ContextID;
|
||||
} _cmsDICT;
|
||||
|
||||
|
||||
// Allocate an empty dictionary
|
||||
cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID)
|
||||
{
|
||||
_cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT));
|
||||
if (dict == NULL) return NULL;
|
||||
|
||||
dict ->ContextID = ContextID;
|
||||
return (cmsHANDLE) dict;
|
||||
|
||||
}
|
||||
|
||||
// Dispose resources
|
||||
void CMSEXPORT cmsDictFree(cmsHANDLE hDict)
|
||||
{
|
||||
_cmsDICT* dict = (_cmsDICT*) hDict;
|
||||
cmsDICTentry *entry, *next;
|
||||
|
||||
_cmsAssert(dict != NULL);
|
||||
|
||||
// Walk the list freeing all nodes
|
||||
entry = dict ->head;
|
||||
while (entry != NULL) {
|
||||
|
||||
if (entry ->DisplayName != NULL) cmsMLUfree(entry ->DisplayName);
|
||||
if (entry ->DisplayValue != NULL) cmsMLUfree(entry ->DisplayValue);
|
||||
if (entry ->Name != NULL) _cmsFree(dict ->ContextID, entry -> Name);
|
||||
if (entry ->Value != NULL) _cmsFree(dict ->ContextID, entry -> Value);
|
||||
|
||||
// Don't fall in the habitual trap...
|
||||
next = entry ->Next;
|
||||
_cmsFree(dict ->ContextID, entry);
|
||||
|
||||
entry = next;
|
||||
}
|
||||
|
||||
_cmsFree(dict ->ContextID, dict);
|
||||
}
|
||||
|
||||
|
||||
// Duplicate a wide char string
|
||||
static
|
||||
wchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr)
|
||||
{
|
||||
if (ptr == NULL) return NULL;
|
||||
return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t));
|
||||
}
|
||||
|
||||
// Add a new entry to the linked list
|
||||
cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue)
|
||||
{
|
||||
_cmsDICT* dict = (_cmsDICT*) hDict;
|
||||
cmsDICTentry *entry;
|
||||
|
||||
_cmsAssert(dict != NULL);
|
||||
_cmsAssert(Name != NULL);
|
||||
|
||||
entry = (cmsDICTentry*) _cmsMallocZero(dict ->ContextID, sizeof(cmsDICTentry));
|
||||
if (entry == NULL) return FALSE;
|
||||
|
||||
entry ->DisplayName = cmsMLUdup(DisplayName);
|
||||
entry ->DisplayValue = cmsMLUdup(DisplayValue);
|
||||
entry ->Name = DupWcs(dict ->ContextID, Name);
|
||||
entry ->Value = DupWcs(dict ->ContextID, Value);
|
||||
|
||||
entry ->Next = dict ->head;
|
||||
dict ->head = entry;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Duplicates an existing dictionary
|
||||
cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict)
|
||||
{
|
||||
_cmsDICT* old_dict = (_cmsDICT*) hDict;
|
||||
cmsHANDLE hNew;
|
||||
_cmsDICT* new_dict;
|
||||
cmsDICTentry *entry;
|
||||
|
||||
_cmsAssert(old_dict != NULL);
|
||||
|
||||
hNew = cmsDictAlloc(old_dict ->ContextID);
|
||||
if (hNew == NULL) return NULL;
|
||||
|
||||
new_dict = (_cmsDICT*) hNew;
|
||||
|
||||
// Walk the list freeing all nodes
|
||||
entry = old_dict ->head;
|
||||
while (entry != NULL) {
|
||||
|
||||
if (!cmsDictAddEntry(hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) {
|
||||
|
||||
cmsDictFree(hNew);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry = entry -> Next;
|
||||
}
|
||||
|
||||
return hNew;
|
||||
}
|
||||
|
||||
// Get a pointer to the linked list
|
||||
const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict)
|
||||
{
|
||||
_cmsDICT* dict = (_cmsDICT*) hDict;
|
||||
|
||||
if (dict == NULL) return NULL;
|
||||
return dict ->head;
|
||||
}
|
||||
|
||||
// Helper For external languages
|
||||
const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e)
|
||||
{
|
||||
if (e == NULL) return NULL;
|
||||
return e ->Next;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,926 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
// inter PCS conversions XYZ <-> CIE L* a* b*
|
||||
/*
|
||||
|
||||
|
||||
CIE 15:2004 CIELab is defined as:
|
||||
|
||||
L* = 116*f(Y/Yn) - 16 0 <= L* <= 100
|
||||
a* = 500*[f(X/Xn) - f(Y/Yn)]
|
||||
b* = 200*[f(Y/Yn) - f(Z/Zn)]
|
||||
|
||||
and
|
||||
|
||||
f(t) = t^(1/3) 1 >= t > (24/116)^3
|
||||
(841/108)*t + (16/116) 0 <= t <= (24/116)^3
|
||||
|
||||
|
||||
Reverse transform is:
|
||||
|
||||
X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > (24/116)
|
||||
= Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= (24/116)
|
||||
|
||||
|
||||
|
||||
PCS in Lab2 is encoded as:
|
||||
|
||||
8 bit Lab PCS:
|
||||
|
||||
L* 0..100 into a 0..ff byte.
|
||||
a* t + 128 range is -128.0 +127.0
|
||||
b*
|
||||
|
||||
16 bit Lab PCS:
|
||||
|
||||
L* 0..100 into a 0..ff00 word.
|
||||
a* t + 128 range is -128.0 +127.9961
|
||||
b*
|
||||
|
||||
|
||||
|
||||
Interchange Space Component Actual Range Encoded Range
|
||||
CIE XYZ X 0 -> 1.99997 0x0000 -> 0xffff
|
||||
CIE XYZ Y 0 -> 1.99997 0x0000 -> 0xffff
|
||||
CIE XYZ Z 0 -> 1.99997 0x0000 -> 0xffff
|
||||
|
||||
Version 2,3
|
||||
-----------
|
||||
|
||||
CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xff00
|
||||
CIELAB (16 bit) a* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff
|
||||
CIELAB (16 bit) b* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff
|
||||
|
||||
|
||||
Version 4
|
||||
---------
|
||||
|
||||
CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff
|
||||
CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff
|
||||
CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff
|
||||
|
||||
*/
|
||||
|
||||
// Conversions
|
||||
void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source)
|
||||
{
|
||||
cmsFloat64Number ISum;
|
||||
|
||||
ISum = 1./(Source -> X + Source -> Y + Source -> Z);
|
||||
|
||||
Dest -> x = (Source -> X) * ISum;
|
||||
Dest -> y = (Source -> Y) * ISum;
|
||||
Dest -> Y = Source -> Y;
|
||||
}
|
||||
|
||||
void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source)
|
||||
{
|
||||
Dest -> X = (Source -> x / Source -> y) * Source -> Y;
|
||||
Dest -> Y = Source -> Y;
|
||||
Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y;
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number f(cmsFloat64Number t)
|
||||
{
|
||||
const cmsFloat64Number Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0);
|
||||
|
||||
if (t <= Limit)
|
||||
return (841.0/108.0) * t + (16.0/116.0);
|
||||
else
|
||||
return pow(t, 1.0/3.0);
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number f_1(cmsFloat64Number t)
|
||||
{
|
||||
const cmsFloat64Number Limit = (24.0/116.0);
|
||||
|
||||
if (t <= Limit) {
|
||||
return (108.0/841.0) * (t - (16.0/116.0));
|
||||
}
|
||||
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
|
||||
// Standard XYZ to Lab. it can handle negative XZY numbers in some cases
|
||||
void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz)
|
||||
{
|
||||
cmsFloat64Number fx, fy, fz;
|
||||
|
||||
if (WhitePoint == NULL)
|
||||
WhitePoint = cmsD50_XYZ();
|
||||
|
||||
fx = f(xyz->X / WhitePoint->X);
|
||||
fy = f(xyz->Y / WhitePoint->Y);
|
||||
fz = f(xyz->Z / WhitePoint->Z);
|
||||
|
||||
Lab->L = 116.0*fy - 16.0;
|
||||
Lab->a = 500.0*(fx - fy);
|
||||
Lab->b = 200.0*(fy - fz);
|
||||
}
|
||||
|
||||
|
||||
// Standard XYZ to Lab. It can return negative XYZ in some cases
|
||||
void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab)
|
||||
{
|
||||
cmsFloat64Number x, y, z;
|
||||
|
||||
if (WhitePoint == NULL)
|
||||
WhitePoint = cmsD50_XYZ();
|
||||
|
||||
y = (Lab-> L + 16.0) / 116.0;
|
||||
x = y + 0.002 * Lab -> a;
|
||||
z = y - 0.005 * Lab -> b;
|
||||
|
||||
xyz -> X = f_1(x) * WhitePoint -> X;
|
||||
xyz -> Y = f_1(y) * WhitePoint -> Y;
|
||||
xyz -> Z = f_1(z) * WhitePoint -> Z;
|
||||
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number L2float2(cmsUInt16Number v)
|
||||
{
|
||||
return (cmsFloat64Number) v / 652.800;
|
||||
}
|
||||
|
||||
// the a/b part
|
||||
static
|
||||
cmsFloat64Number ab2float2(cmsUInt16Number v)
|
||||
{
|
||||
return ((cmsFloat64Number) v / 256.0) - 128.0;
|
||||
}
|
||||
|
||||
static
|
||||
cmsUInt16Number L2Fix2(cmsFloat64Number L)
|
||||
{
|
||||
return _cmsQuickSaturateWord(L * 652.8);
|
||||
}
|
||||
|
||||
static
|
||||
cmsUInt16Number ab2Fix2(cmsFloat64Number ab)
|
||||
{
|
||||
return _cmsQuickSaturateWord((ab + 128.0) * 256.0);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
cmsFloat64Number L2float4(cmsUInt16Number v)
|
||||
{
|
||||
return (cmsFloat64Number) v / 655.35;
|
||||
}
|
||||
|
||||
// the a/b part
|
||||
static
|
||||
cmsFloat64Number ab2float4(cmsUInt16Number v)
|
||||
{
|
||||
return ((cmsFloat64Number) v / 257.0) - 128.0;
|
||||
}
|
||||
|
||||
|
||||
void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3])
|
||||
{
|
||||
Lab->L = L2float2(wLab[0]);
|
||||
Lab->a = ab2float2(wLab[1]);
|
||||
Lab->b = ab2float2(wLab[2]);
|
||||
}
|
||||
|
||||
|
||||
void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3])
|
||||
{
|
||||
Lab->L = L2float4(wLab[0]);
|
||||
Lab->a = ab2float4(wLab[1]);
|
||||
Lab->b = ab2float4(wLab[2]);
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number Clamp_L_doubleV2(cmsFloat64Number L)
|
||||
{
|
||||
const cmsFloat64Number L_max = (cmsFloat64Number) (0xFFFF * 100.0) / 0xFF00;
|
||||
|
||||
if (L < 0) L = 0;
|
||||
if (L > L_max) L = L_max;
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
cmsFloat64Number Clamp_ab_doubleV2(cmsFloat64Number ab)
|
||||
{
|
||||
if (ab < MIN_ENCODEABLE_ab2) ab = MIN_ENCODEABLE_ab2;
|
||||
if (ab > MAX_ENCODEABLE_ab2) ab = MAX_ENCODEABLE_ab2;
|
||||
|
||||
return ab;
|
||||
}
|
||||
|
||||
void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* fLab)
|
||||
{
|
||||
cmsCIELab Lab;
|
||||
|
||||
Lab.L = Clamp_L_doubleV2(fLab ->L);
|
||||
Lab.a = Clamp_ab_doubleV2(fLab ->a);
|
||||
Lab.b = Clamp_ab_doubleV2(fLab ->b);
|
||||
|
||||
wLab[0] = L2Fix2(Lab.L);
|
||||
wLab[1] = ab2Fix2(Lab.a);
|
||||
wLab[2] = ab2Fix2(Lab.b);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
cmsFloat64Number Clamp_L_doubleV4(cmsFloat64Number L)
|
||||
{
|
||||
if (L < 0) L = 0;
|
||||
if (L > 100.0) L = 100.0;
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
static
|
||||
cmsFloat64Number Clamp_ab_doubleV4(cmsFloat64Number ab)
|
||||
{
|
||||
if (ab < MIN_ENCODEABLE_ab4) ab = MIN_ENCODEABLE_ab4;
|
||||
if (ab > MAX_ENCODEABLE_ab4) ab = MAX_ENCODEABLE_ab4;
|
||||
|
||||
return ab;
|
||||
}
|
||||
|
||||
static
|
||||
cmsUInt16Number L2Fix4(cmsFloat64Number L)
|
||||
{
|
||||
return _cmsQuickSaturateWord(L * 655.35);
|
||||
}
|
||||
|
||||
static
|
||||
cmsUInt16Number ab2Fix4(cmsFloat64Number ab)
|
||||
{
|
||||
return _cmsQuickSaturateWord((ab + 128.0) * 257.0);
|
||||
}
|
||||
|
||||
void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLab)
|
||||
{
|
||||
cmsCIELab Lab;
|
||||
|
||||
Lab.L = Clamp_L_doubleV4(fLab ->L);
|
||||
Lab.a = Clamp_ab_doubleV4(fLab ->a);
|
||||
Lab.b = Clamp_ab_doubleV4(fLab ->b);
|
||||
|
||||
wLab[0] = L2Fix4(Lab.L);
|
||||
wLab[1] = ab2Fix4(Lab.a);
|
||||
wLab[2] = ab2Fix4(Lab.b);
|
||||
}
|
||||
|
||||
// Auxiliar: convert to Radians
|
||||
static
|
||||
cmsFloat64Number RADIANS(cmsFloat64Number deg)
|
||||
{
|
||||
return (deg * M_PI) / 180.;
|
||||
}
|
||||
|
||||
|
||||
// Auxiliar: atan2 but operating in degrees and returning 0 if a==b==0
|
||||
static
|
||||
cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b)
|
||||
{
|
||||
cmsFloat64Number h;
|
||||
|
||||
if (a == 0 && b == 0)
|
||||
h = 0;
|
||||
else
|
||||
h = atan2(a, b);
|
||||
|
||||
h *= (180. / M_PI);
|
||||
|
||||
while (h > 360.)
|
||||
h -= 360.;
|
||||
|
||||
while ( h < 0)
|
||||
h += 360.;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
// Auxiliar: Square
|
||||
static
|
||||
cmsFloat64Number Sqr(cmsFloat64Number v)
|
||||
{
|
||||
return v * v;
|
||||
}
|
||||
// From cylindrical coordinates. No check is performed, then negative values are allowed
|
||||
void CMSEXPORT cmsLab2LCh(cmsCIELCh* LCh, const cmsCIELab* Lab)
|
||||
{
|
||||
LCh -> L = Lab -> L;
|
||||
LCh -> C = pow(Sqr(Lab ->a) + Sqr(Lab ->b), 0.5);
|
||||
LCh -> h = atan2deg(Lab ->b, Lab ->a);
|
||||
}
|
||||
|
||||
|
||||
// To cylindrical coordinates. No check is performed, then negative values are allowed
|
||||
void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh)
|
||||
{
|
||||
cmsFloat64Number h = (LCh -> h * M_PI) / 180.0;
|
||||
|
||||
Lab -> L = LCh -> L;
|
||||
Lab -> a = LCh -> C * cos(h);
|
||||
Lab -> b = LCh -> C * sin(h);
|
||||
}
|
||||
|
||||
// In XYZ All 3 components are encoded using 1.15 fixed point
|
||||
static
|
||||
cmsUInt16Number XYZ2Fix(cmsFloat64Number d)
|
||||
{
|
||||
return _cmsQuickSaturateWord(d * 32768.0);
|
||||
}
|
||||
|
||||
void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ)
|
||||
{
|
||||
cmsCIEXYZ xyz;
|
||||
|
||||
xyz.X = fXYZ -> X;
|
||||
xyz.Y = fXYZ -> Y;
|
||||
xyz.Z = fXYZ -> Z;
|
||||
|
||||
// Clamp to encodeable values.
|
||||
if (xyz.Y <= 0) {
|
||||
|
||||
xyz.X = 0;
|
||||
xyz.Y = 0;
|
||||
xyz.Z = 0;
|
||||
}
|
||||
|
||||
if (xyz.X > MAX_ENCODEABLE_XYZ)
|
||||
xyz.X = MAX_ENCODEABLE_XYZ;
|
||||
|
||||
if (xyz.X < 0)
|
||||
xyz.X = 0;
|
||||
|
||||
if (xyz.Y > MAX_ENCODEABLE_XYZ)
|
||||
xyz.Y = MAX_ENCODEABLE_XYZ;
|
||||
|
||||
if (xyz.Y < 0)
|
||||
xyz.Y = 0;
|
||||
|
||||
if (xyz.Z > MAX_ENCODEABLE_XYZ)
|
||||
xyz.Z = MAX_ENCODEABLE_XYZ;
|
||||
|
||||
if (xyz.Z < 0)
|
||||
xyz.Z = 0;
|
||||
|
||||
|
||||
XYZ[0] = XYZ2Fix(xyz.X);
|
||||
XYZ[1] = XYZ2Fix(xyz.Y);
|
||||
XYZ[2] = XYZ2Fix(xyz.Z);
|
||||
}
|
||||
|
||||
|
||||
// To convert from Fixed 1.15 point to cmsFloat64Number
|
||||
static
|
||||
cmsFloat64Number XYZ2float(cmsUInt16Number v)
|
||||
{
|
||||
cmsS15Fixed16Number fix32;
|
||||
|
||||
// From 1.15 to 15.16
|
||||
fix32 = v << 1;
|
||||
|
||||
// From fixed 15.16 to cmsFloat64Number
|
||||
return _cms15Fixed16toDouble(fix32);
|
||||
}
|
||||
|
||||
|
||||
void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fXYZ, const cmsUInt16Number XYZ[3])
|
||||
{
|
||||
fXYZ -> X = XYZ2float(XYZ[0]);
|
||||
fXYZ -> Y = XYZ2float(XYZ[1]);
|
||||
fXYZ -> Z = XYZ2float(XYZ[2]);
|
||||
}
|
||||
|
||||
|
||||
// Returns dE on two Lab values
|
||||
cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
|
||||
{
|
||||
cmsFloat64Number dL, da, db;
|
||||
|
||||
dL = fabs(Lab1 -> L - Lab2 -> L);
|
||||
da = fabs(Lab1 -> a - Lab2 -> a);
|
||||
db = fabs(Lab1 -> b - Lab2 -> b);
|
||||
|
||||
return pow(Sqr(dL) + Sqr(da) + Sqr(db), 0.5);
|
||||
}
|
||||
|
||||
|
||||
// Return the CIE94 Delta E
|
||||
cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
|
||||
{
|
||||
cmsCIELCh LCh1, LCh2;
|
||||
cmsFloat64Number dE, dL, dC, dh, dhsq;
|
||||
cmsFloat64Number c12, sc, sh;
|
||||
|
||||
dL = fabs(Lab1 ->L - Lab2 ->L);
|
||||
|
||||
cmsLab2LCh(&LCh1, Lab1);
|
||||
cmsLab2LCh(&LCh2, Lab2);
|
||||
|
||||
dC = fabs(LCh1.C - LCh2.C);
|
||||
dE = cmsDeltaE(Lab1, Lab2);
|
||||
|
||||
dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC);
|
||||
if (dhsq < 0)
|
||||
dh = 0;
|
||||
else
|
||||
dh = pow(dhsq, 0.5);
|
||||
|
||||
c12 = sqrt(LCh1.C * LCh2.C);
|
||||
|
||||
sc = 1.0 + (0.048 * c12);
|
||||
sh = 1.0 + (0.014 * c12);
|
||||
|
||||
return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh));
|
||||
}
|
||||
|
||||
|
||||
// Auxiliary
|
||||
static
|
||||
cmsFloat64Number ComputeLBFD(const cmsCIELab* Lab)
|
||||
{
|
||||
cmsFloat64Number yt;
|
||||
|
||||
if (Lab->L > 7.996969)
|
||||
yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100;
|
||||
else
|
||||
yt = 100 * (Lab->L / 903.3);
|
||||
|
||||
return (54.6 * (M_LOG10E * (log(yt + 1.5))) - 9.6);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// bfd - gets BFD(1:1) difference between Lab1, Lab2
|
||||
cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2)
|
||||
{
|
||||
cmsFloat64Number lbfd1,lbfd2,AveC,Aveh,dE,deltaL,
|
||||
deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd;
|
||||
cmsCIELCh LCh1, LCh2;
|
||||
|
||||
|
||||
lbfd1 = ComputeLBFD(Lab1);
|
||||
lbfd2 = ComputeLBFD(Lab2);
|
||||
deltaL = lbfd2 - lbfd1;
|
||||
|
||||
cmsLab2LCh(&LCh1, Lab1);
|
||||
cmsLab2LCh(&LCh2, Lab2);
|
||||
|
||||
deltaC = LCh2.C - LCh1.C;
|
||||
AveC = (LCh1.C+LCh2.C)/2;
|
||||
Aveh = (LCh1.h+LCh2.h)/2;
|
||||
|
||||
dE = cmsDeltaE(Lab1, Lab2);
|
||||
|
||||
if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC)))
|
||||
deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC));
|
||||
else
|
||||
deltah =0;
|
||||
|
||||
|
||||
dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521;
|
||||
g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000));
|
||||
t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))-
|
||||
0.040*cos((2*Aveh-136)/(180/M_PI))+
|
||||
0.070*cos((3*Aveh-31)/(180/M_PI))+
|
||||
0.049*cos((4*Aveh+114)/(180/M_PI))-
|
||||
0.015*cos((5*Aveh-103)/(180/M_PI)));
|
||||
|
||||
dh = dc*(g*t+1-g);
|
||||
rh = -0.260*cos((Aveh-308)/(180/M_PI))-
|
||||
0.379*cos((2*Aveh-160)/(180/M_PI))-
|
||||
0.636*cos((3*Aveh+254)/(180/M_PI))+
|
||||
0.226*cos((4*Aveh+140)/(180/M_PI))-
|
||||
0.194*cos((5*Aveh+280)/(180/M_PI));
|
||||
|
||||
rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000));
|
||||
rt = rh*rc;
|
||||
|
||||
bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh)));
|
||||
|
||||
return bfd;
|
||||
}
|
||||
|
||||
|
||||
// cmc - CMC(l:c) difference between Lab1, Lab2
|
||||
cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c)
|
||||
{
|
||||
cmsFloat64Number dE,dL,dC,dh,sl,sc,sh,t,f,cmc;
|
||||
cmsCIELCh LCh1, LCh2;
|
||||
|
||||
if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0;
|
||||
|
||||
cmsLab2LCh(&LCh1, Lab1);
|
||||
cmsLab2LCh(&LCh2, Lab2);
|
||||
|
||||
|
||||
dL = Lab2->L-Lab1->L;
|
||||
dC = LCh2.C-LCh1.C;
|
||||
|
||||
dE = cmsDeltaE(Lab1, Lab2);
|
||||
|
||||
if (Sqr(dE)>(Sqr(dL)+Sqr(dC)))
|
||||
dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC));
|
||||
else
|
||||
dh =0;
|
||||
|
||||
if ((LCh1.h > 164) && (LCh1.h < 345))
|
||||
t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI))));
|
||||
else
|
||||
t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI))));
|
||||
|
||||
sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638;
|
||||
sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L);
|
||||
|
||||
if (Lab1->L<16)
|
||||
sl = 0.511;
|
||||
|
||||
f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900));
|
||||
sh = sc*(t*f+1-f);
|
||||
cmc = sqrt(Sqr(dL/(l*sl))+Sqr(dC/(c*sc))+Sqr(dh/sh));
|
||||
|
||||
return cmc;
|
||||
}
|
||||
|
||||
// dE2000 The weightings KL, KC and KH can be modified to reflect the relative
|
||||
// importance of lightness, chroma and hue in different industrial applications
|
||||
cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2,
|
||||
cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh)
|
||||
{
|
||||
cmsFloat64Number L1 = Lab1->L;
|
||||
cmsFloat64Number a1 = Lab1->a;
|
||||
cmsFloat64Number b1 = Lab1->b;
|
||||
cmsFloat64Number C = sqrt( Sqr(a1) + Sqr(b1) );
|
||||
|
||||
cmsFloat64Number Ls = Lab2 ->L;
|
||||
cmsFloat64Number as = Lab2 ->a;
|
||||
cmsFloat64Number bs = Lab2 ->b;
|
||||
cmsFloat64Number Cs = sqrt( Sqr(as) + Sqr(bs) );
|
||||
|
||||
cmsFloat64Number G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) ));
|
||||
|
||||
cmsFloat64Number a_p = (1 + G ) * a1;
|
||||
cmsFloat64Number b_p = b1;
|
||||
cmsFloat64Number C_p = sqrt( Sqr(a_p) + Sqr(b_p));
|
||||
cmsFloat64Number h_p = atan2deg(b_p, a_p);
|
||||
|
||||
|
||||
cmsFloat64Number a_ps = (1 + G) * as;
|
||||
cmsFloat64Number b_ps = bs;
|
||||
cmsFloat64Number C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps));
|
||||
cmsFloat64Number h_ps = atan2deg(b_ps, a_ps);
|
||||
|
||||
cmsFloat64Number meanC_p =(C_p + C_ps) / 2;
|
||||
|
||||
cmsFloat64Number hps_plus_hp = h_ps + h_p;
|
||||
cmsFloat64Number hps_minus_hp = h_ps - h_p;
|
||||
|
||||
cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 :
|
||||
(hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 :
|
||||
(hps_plus_hp - 360)/2;
|
||||
|
||||
cmsFloat64Number delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) :
|
||||
(hps_minus_hp) > 180 ? (hps_minus_hp - 360) :
|
||||
(hps_minus_hp);
|
||||
cmsFloat64Number delta_L = (Ls - L1);
|
||||
cmsFloat64Number delta_C = (C_ps - C_p );
|
||||
|
||||
|
||||
cmsFloat64Number delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANS(delta_h) / 2);
|
||||
|
||||
cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30))
|
||||
+ 0.24 * cos(RADIANS(2*meanh_p))
|
||||
+ 0.32 * cos(RADIANS(3*meanh_p + 6))
|
||||
- 0.2 * cos(RADIANS(4*meanh_p - 63));
|
||||
|
||||
cmsFloat64Number Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) );
|
||||
|
||||
cmsFloat64Number Sc = 1 + 0.045 * (C_p + C_ps)/2;
|
||||
cmsFloat64Number Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T;
|
||||
|
||||
cmsFloat64Number delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25)));
|
||||
|
||||
cmsFloat64Number Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0)));
|
||||
|
||||
cmsFloat64Number Rt = -sin(2 * RADIANS(delta_ro)) * Rc;
|
||||
|
||||
cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) +
|
||||
Sqr(delta_C/(Sc * Kc)) +
|
||||
Sqr(delta_H/(Sh * Kh)) +
|
||||
Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh)));
|
||||
|
||||
return deltaE00;
|
||||
}
|
||||
|
||||
// This function returns a number of gridpoints to be used as LUT table. It assumes same number
|
||||
// of gripdpoints in all dimensions. Flags may override the choice.
|
||||
int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags)
|
||||
{
|
||||
int nChannels;
|
||||
|
||||
// Already specified?
|
||||
if (dwFlags & 0x00FF0000) {
|
||||
// Yes, grab'em
|
||||
return (dwFlags >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
nChannels = cmsChannelsOf(Colorspace);
|
||||
|
||||
// HighResPrecalc is maximum resolution
|
||||
if (dwFlags & cmsFLAGS_HIGHRESPRECALC) {
|
||||
|
||||
if (nChannels > 4)
|
||||
return 7; // 7 for Hifi
|
||||
|
||||
if (nChannels == 4) // 23 for CMYK
|
||||
return 23;
|
||||
|
||||
return 49; // 49 for RGB and others
|
||||
}
|
||||
|
||||
|
||||
// LowResPrecal is lower resolution
|
||||
if (dwFlags & cmsFLAGS_LOWRESPRECALC) {
|
||||
|
||||
if (nChannels > 4)
|
||||
return 6; // 6 for more than 4 channels
|
||||
|
||||
if (nChannels == 1)
|
||||
return 33; // For monochrome
|
||||
|
||||
return 17; // 17 for remaining
|
||||
}
|
||||
|
||||
// Default values
|
||||
if (nChannels > 4)
|
||||
return 7; // 7 for Hifi
|
||||
|
||||
if (nChannels == 4)
|
||||
return 17; // 17 for CMYK
|
||||
|
||||
return 33; // 33 for RGB
|
||||
}
|
||||
|
||||
|
||||
cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
|
||||
cmsUInt16Number **White,
|
||||
cmsUInt16Number **Black,
|
||||
cmsUInt32Number *nOutputs)
|
||||
{
|
||||
// Only most common spaces
|
||||
|
||||
static cmsUInt16Number RGBblack[4] = { 0, 0, 0 };
|
||||
static cmsUInt16Number RGBwhite[4] = { 0xffff, 0xffff, 0xffff };
|
||||
static cmsUInt16Number CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff }; // 400% of ink
|
||||
static cmsUInt16Number CMYKwhite[4] = { 0, 0, 0, 0 };
|
||||
static cmsUInt16Number LABblack[4] = { 0, 0x8080, 0x8080 }; // V4 Lab encoding
|
||||
static cmsUInt16Number LABwhite[4] = { 0xFFFF, 0x8080, 0x8080 };
|
||||
static cmsUInt16Number CMYblack[4] = { 0xffff, 0xffff, 0xffff };
|
||||
static cmsUInt16Number CMYwhite[4] = { 0, 0, 0 };
|
||||
static cmsUInt16Number Grayblack[4] = { 0 };
|
||||
static cmsUInt16Number GrayWhite[4] = { 0xffff };
|
||||
|
||||
switch (Space) {
|
||||
|
||||
case cmsSigGrayData: if (White) *White = GrayWhite;
|
||||
if (Black) *Black = Grayblack;
|
||||
if (nOutputs) *nOutputs = 1;
|
||||
return TRUE;
|
||||
|
||||
case cmsSigRgbData: if (White) *White = RGBwhite;
|
||||
if (Black) *Black = RGBblack;
|
||||
if (nOutputs) *nOutputs = 3;
|
||||
return TRUE;
|
||||
|
||||
case cmsSigLabData: if (White) *White = LABwhite;
|
||||
if (Black) *Black = LABblack;
|
||||
if (nOutputs) *nOutputs = 3;
|
||||
return TRUE;
|
||||
|
||||
case cmsSigCmykData: if (White) *White = CMYKwhite;
|
||||
if (Black) *Black = CMYKblack;
|
||||
if (nOutputs) *nOutputs = 4;
|
||||
return TRUE;
|
||||
|
||||
case cmsSigCmyData: if (White) *White = CMYwhite;
|
||||
if (Black) *Black = CMYblack;
|
||||
if (nOutputs) *nOutputs = 3;
|
||||
return TRUE;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Several utilities -------------------------------------------------------
|
||||
|
||||
// Translate from our colorspace to ICC representation
|
||||
|
||||
cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation)
|
||||
{
|
||||
switch (OurNotation) {
|
||||
|
||||
case 1:
|
||||
case PT_GRAY: return cmsSigGrayData;
|
||||
|
||||
case 2:
|
||||
case PT_RGB: return cmsSigRgbData;
|
||||
|
||||
case PT_CMY: return cmsSigCmyData;
|
||||
case PT_CMYK: return cmsSigCmykData;
|
||||
case PT_YCbCr:return cmsSigYCbCrData;
|
||||
case PT_YUV: return cmsSigLuvData;
|
||||
case PT_XYZ: return cmsSigXYZData;
|
||||
|
||||
case PT_LabV2:
|
||||
case PT_Lab: return cmsSigLabData;
|
||||
|
||||
case PT_YUVK: return cmsSigLuvKData;
|
||||
case PT_HSV: return cmsSigHsvData;
|
||||
case PT_HLS: return cmsSigHlsData;
|
||||
case PT_Yxy: return cmsSigYxyData;
|
||||
|
||||
case PT_MCH1: return cmsSigMCH1Data;
|
||||
case PT_MCH2: return cmsSigMCH2Data;
|
||||
case PT_MCH3: return cmsSigMCH3Data;
|
||||
case PT_MCH4: return cmsSigMCH4Data;
|
||||
case PT_MCH5: return cmsSigMCH5Data;
|
||||
case PT_MCH6: return cmsSigMCH6Data;
|
||||
case PT_MCH7: return cmsSigMCH7Data;
|
||||
case PT_MCH8: return cmsSigMCH8Data;
|
||||
|
||||
case PT_MCH9: return cmsSigMCH9Data;
|
||||
case PT_MCH10: return cmsSigMCHAData;
|
||||
case PT_MCH11: return cmsSigMCHBData;
|
||||
case PT_MCH12: return cmsSigMCHCData;
|
||||
case PT_MCH13: return cmsSigMCHDData;
|
||||
case PT_MCH14: return cmsSigMCHEData;
|
||||
case PT_MCH15: return cmsSigMCHFData;
|
||||
|
||||
default: return (cmsColorSpaceSignature) (-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace)
|
||||
{
|
||||
switch (ProfileSpace) {
|
||||
|
||||
case cmsSigGrayData: return PT_GRAY;
|
||||
case cmsSigRgbData: return PT_RGB;
|
||||
case cmsSigCmyData: return PT_CMY;
|
||||
case cmsSigCmykData: return PT_CMYK;
|
||||
case cmsSigYCbCrData:return PT_YCbCr;
|
||||
case cmsSigLuvData: return PT_YUV;
|
||||
case cmsSigXYZData: return PT_XYZ;
|
||||
case cmsSigLabData: return PT_Lab;
|
||||
case cmsSigLuvKData: return PT_YUVK;
|
||||
case cmsSigHsvData: return PT_HSV;
|
||||
case cmsSigHlsData: return PT_HLS;
|
||||
case cmsSigYxyData: return PT_Yxy;
|
||||
|
||||
case cmsSig1colorData:
|
||||
case cmsSigMCH1Data: return PT_MCH1;
|
||||
|
||||
case cmsSig2colorData:
|
||||
case cmsSigMCH2Data: return PT_MCH2;
|
||||
|
||||
case cmsSig3colorData:
|
||||
case cmsSigMCH3Data: return PT_MCH3;
|
||||
|
||||
case cmsSig4colorData:
|
||||
case cmsSigMCH4Data: return PT_MCH4;
|
||||
|
||||
case cmsSig5colorData:
|
||||
case cmsSigMCH5Data: return PT_MCH5;
|
||||
|
||||
case cmsSig6colorData:
|
||||
case cmsSigMCH6Data: return PT_MCH6;
|
||||
|
||||
case cmsSigMCH7Data:
|
||||
case cmsSig7colorData:return PT_MCH7;
|
||||
|
||||
case cmsSigMCH8Data:
|
||||
case cmsSig8colorData:return PT_MCH8;
|
||||
|
||||
case cmsSigMCH9Data:
|
||||
case cmsSig9colorData:return PT_MCH9;
|
||||
|
||||
case cmsSigMCHAData:
|
||||
case cmsSig10colorData:return PT_MCH10;
|
||||
|
||||
case cmsSigMCHBData:
|
||||
case cmsSig11colorData:return PT_MCH11;
|
||||
|
||||
case cmsSigMCHCData:
|
||||
case cmsSig12colorData:return PT_MCH12;
|
||||
|
||||
case cmsSigMCHDData:
|
||||
case cmsSig13colorData:return PT_MCH13;
|
||||
|
||||
case cmsSigMCHEData:
|
||||
case cmsSig14colorData:return PT_MCH14;
|
||||
|
||||
case cmsSigMCHFData:
|
||||
case cmsSig15colorData:return PT_MCH15;
|
||||
|
||||
default: return (cmsColorSpaceSignature) (-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
|
||||
{
|
||||
switch (ColorSpace) {
|
||||
|
||||
case cmsSigGrayData: return 1;
|
||||
|
||||
case cmsSig2colorData: return 2;
|
||||
|
||||
case cmsSigXYZData:
|
||||
case cmsSigLabData:
|
||||
case cmsSigLuvData:
|
||||
case cmsSigYCbCrData:
|
||||
case cmsSigYxyData:
|
||||
case cmsSigRgbData:
|
||||
case cmsSigHsvData:
|
||||
case cmsSigHlsData:
|
||||
case cmsSigCmyData:
|
||||
case cmsSig3colorData: return 3;
|
||||
|
||||
case cmsSigLuvKData:
|
||||
case cmsSigCmykData:
|
||||
case cmsSig4colorData: return 4;
|
||||
|
||||
case cmsSigMCH5Data:
|
||||
case cmsSig5colorData: return 5;
|
||||
|
||||
case cmsSigMCH6Data:
|
||||
case cmsSig6colorData: return 6;
|
||||
|
||||
case cmsSigMCH7Data:
|
||||
case cmsSig7colorData: return 7;
|
||||
|
||||
case cmsSigMCH8Data:
|
||||
case cmsSig8colorData: return 8;
|
||||
|
||||
case cmsSigMCH9Data:
|
||||
case cmsSig9colorData: return 9;
|
||||
|
||||
case cmsSigMCHAData:
|
||||
case cmsSig10colorData: return 10;
|
||||
|
||||
case cmsSigMCHBData:
|
||||
case cmsSig11colorData: return 11;
|
||||
|
||||
case cmsSigMCHCData:
|
||||
case cmsSig12colorData: return 12;
|
||||
|
||||
case cmsSigMCHDData:
|
||||
case cmsSig13colorData: return 13;
|
||||
|
||||
case cmsSigMCHEData:
|
||||
case cmsSig14colorData: return 14;
|
||||
|
||||
case cmsSigMCHFData:
|
||||
case cmsSig15colorData: return 15;
|
||||
|
||||
default: return 3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// Encoding & Decoding support functions
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
// Little-Endian to Big-Endian
|
||||
|
||||
// Adjust a word value after being readed/ before being written from/to an ICC profile
|
||||
cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word)
|
||||
{
|
||||
#ifndef CMS_USE_BIG_ENDIAN
|
||||
|
||||
cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;
|
||||
cmsUInt8Number tmp;
|
||||
|
||||
tmp = pByte[0];
|
||||
pByte[0] = pByte[1];
|
||||
pByte[1] = tmp;
|
||||
#endif
|
||||
|
||||
return Word;
|
||||
}
|
||||
|
||||
|
||||
// Transports to properly encoded values - note that icc profiles does use big endian notation.
|
||||
|
||||
// 1 2 3 4
|
||||
// 4 3 2 1
|
||||
|
||||
cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord)
|
||||
{
|
||||
#ifndef CMS_USE_BIG_ENDIAN
|
||||
|
||||
cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
|
||||
cmsUInt8Number temp1;
|
||||
cmsUInt8Number temp2;
|
||||
|
||||
temp1 = *pByte++;
|
||||
temp2 = *pByte++;
|
||||
*(pByte-1) = *pByte;
|
||||
*pByte++ = temp2;
|
||||
*(pByte-3) = *pByte;
|
||||
*pByte = temp1;
|
||||
#endif
|
||||
return DWord;
|
||||
}
|
||||
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 8 7 6 5 4 3 2 1
|
||||
|
||||
void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord)
|
||||
{
|
||||
|
||||
#ifndef CMS_USE_BIG_ENDIAN
|
||||
|
||||
cmsUInt8Number* pIn = (cmsUInt8Number*) &QWord;
|
||||
cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
|
||||
|
||||
_cmsAssert(Result != NULL);
|
||||
|
||||
pOut[7] = pIn[0];
|
||||
pOut[6] = pIn[1];
|
||||
pOut[5] = pIn[2];
|
||||
pOut[4] = pIn[3];
|
||||
pOut[3] = pIn[4];
|
||||
pOut[2] = pIn[5];
|
||||
pOut[1] = pIn[6];
|
||||
pOut[0] = pIn[7];
|
||||
|
||||
#else
|
||||
|
||||
_cmsAssert(Result != NULL);
|
||||
|
||||
*Result = QWord;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Auxiliar -- read 8, 16 and 32-bit numbers
|
||||
cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
|
||||
{
|
||||
cmsUInt8Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
|
||||
return FALSE;
|
||||
|
||||
if (n != NULL) *n = tmp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
|
||||
{
|
||||
cmsUInt16Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
|
||||
return FALSE;
|
||||
|
||||
if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
|
||||
if (Array != NULL) {
|
||||
if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;
|
||||
}
|
||||
else {
|
||||
if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
|
||||
{
|
||||
cmsUInt32Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
|
||||
return FALSE;
|
||||
|
||||
if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
|
||||
{
|
||||
cmsUInt32Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1)
|
||||
return FALSE;
|
||||
|
||||
if (n != NULL) {
|
||||
|
||||
tmp = _cmsAdjustEndianess32(tmp);
|
||||
*n = *(cmsFloat32Number*) &tmp;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
|
||||
{
|
||||
cmsUInt64Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
|
||||
return FALSE;
|
||||
|
||||
if (n != NULL) _cmsAdjustEndianess64(n, tmp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
|
||||
{
|
||||
cmsUInt32Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
|
||||
return FALSE;
|
||||
|
||||
if (n != NULL) {
|
||||
*n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Jun-21-2000: Some profiles (those that comes with W2K) comes
|
||||
// with the media white (media black?) x 100. Add a sanity check
|
||||
|
||||
static
|
||||
void NormalizeXYZ(cmsCIEXYZ* Dest)
|
||||
{
|
||||
while (Dest -> X > 2. &&
|
||||
Dest -> Y > 2. &&
|
||||
Dest -> Z > 2.) {
|
||||
|
||||
Dest -> X /= 10.;
|
||||
Dest -> Y /= 10.;
|
||||
Dest -> Z /= 10.;
|
||||
}
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
|
||||
{
|
||||
cmsEncodedXYZNumber xyz;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
|
||||
|
||||
if (XYZ != NULL) {
|
||||
|
||||
XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
|
||||
XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
|
||||
XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
|
||||
|
||||
NormalizeXYZ(XYZ);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
|
||||
{
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
|
||||
{
|
||||
cmsUInt16Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
tmp = _cmsAdjustEndianess16(n);
|
||||
if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
_cmsAssert(Array != NULL);
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
|
||||
{
|
||||
cmsUInt32Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
tmp = _cmsAdjustEndianess32(n);
|
||||
if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
|
||||
{
|
||||
cmsUInt32Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
tmp = *(cmsUInt32Number*) &n;
|
||||
tmp = _cmsAdjustEndianess32(tmp);
|
||||
if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n)
|
||||
{
|
||||
cmsUInt64Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
_cmsAdjustEndianess64(&tmp, n);
|
||||
if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
|
||||
{
|
||||
cmsUInt32Number tmp;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
|
||||
if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
|
||||
{
|
||||
cmsEncodedXYZNumber xyz;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
_cmsAssert(XYZ != NULL);
|
||||
|
||||
xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
|
||||
xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
|
||||
xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
|
||||
|
||||
return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz);
|
||||
}
|
||||
|
||||
// from Fixed point 8.8 to double
|
||||
cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
|
||||
{
|
||||
cmsUInt8Number msb, lsb;
|
||||
|
||||
lsb = (cmsUInt8Number) (fixed8 & 0xff);
|
||||
msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
|
||||
|
||||
return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
|
||||
}
|
||||
|
||||
cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
|
||||
{
|
||||
cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
|
||||
return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
|
||||
}
|
||||
|
||||
// from Fixed point 15.16 to double
|
||||
cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
|
||||
{
|
||||
cmsFloat64Number floater, sign, mid;
|
||||
int Whole, FracPart;
|
||||
|
||||
sign = (fix32 < 0 ? -1 : 1);
|
||||
fix32 = abs(fix32);
|
||||
|
||||
Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
|
||||
FracPart = (cmsUInt16Number)(fix32 & 0xffff);
|
||||
|
||||
mid = (cmsFloat64Number) FracPart / 65536.0;
|
||||
floater = (cmsFloat64Number) Whole + mid;
|
||||
|
||||
return sign * floater;
|
||||
}
|
||||
|
||||
// from double to Fixed point 15.16
|
||||
cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
|
||||
{
|
||||
return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
|
||||
}
|
||||
|
||||
// Date/Time functions
|
||||
|
||||
void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
|
||||
{
|
||||
|
||||
_cmsAssert(Dest != NULL);
|
||||
_cmsAssert(Source != NULL);
|
||||
|
||||
Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds);
|
||||
Dest->tm_min = _cmsAdjustEndianess16(Source->minutes);
|
||||
Dest->tm_hour = _cmsAdjustEndianess16(Source->hours);
|
||||
Dest->tm_mday = _cmsAdjustEndianess16(Source->day);
|
||||
Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1;
|
||||
Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900;
|
||||
Dest->tm_wday = -1;
|
||||
Dest->tm_yday = -1;
|
||||
Dest->tm_isdst = 0;
|
||||
}
|
||||
|
||||
void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
|
||||
{
|
||||
_cmsAssert(Dest != NULL);
|
||||
_cmsAssert(Source != NULL);
|
||||
|
||||
Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);
|
||||
Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);
|
||||
Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);
|
||||
Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);
|
||||
Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));
|
||||
Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));
|
||||
}
|
||||
|
||||
// Read base and return type base
|
||||
cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
|
||||
{
|
||||
_cmsTagBase Base;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
|
||||
return (cmsTagTypeSignature) 0;
|
||||
|
||||
return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
|
||||
}
|
||||
|
||||
// Setup base marker
|
||||
cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
|
||||
{
|
||||
_cmsTagBase Base;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
|
||||
memset(&Base.reserved, 0, sizeof(Base.reserved));
|
||||
return io -> Write(io, sizeof(_cmsTagBase), &Base);
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
|
||||
{
|
||||
cmsUInt8Number Buffer[4];
|
||||
cmsUInt32Number NextAligned, At;
|
||||
cmsUInt32Number BytesToNextAlignedPos;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
At = io -> Tell(io);
|
||||
NextAligned = _cmsALIGNLONG(At);
|
||||
BytesToNextAlignedPos = NextAligned - At;
|
||||
if (BytesToNextAlignedPos == 0) return TRUE;
|
||||
if (BytesToNextAlignedPos > 4) return FALSE;
|
||||
|
||||
return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
|
||||
}
|
||||
|
||||
cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
|
||||
{
|
||||
cmsUInt8Number Buffer[4];
|
||||
cmsUInt32Number NextAligned, At;
|
||||
cmsUInt32Number BytesToNextAlignedPos;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
|
||||
At = io -> Tell(io);
|
||||
NextAligned = _cmsALIGNLONG(At);
|
||||
BytesToNextAlignedPos = NextAligned - At;
|
||||
if (BytesToNextAlignedPos == 0) return TRUE;
|
||||
if (BytesToNextAlignedPos > 4) return FALSE;
|
||||
|
||||
memset(Buffer, 0, BytesToNextAlignedPos);
|
||||
return io -> Write(io, BytesToNextAlignedPos, Buffer);
|
||||
}
|
||||
|
||||
|
||||
// To deal with text streams. 2K at most
|
||||
cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
|
||||
{
|
||||
va_list args;
|
||||
int len;
|
||||
cmsUInt8Number Buffer[2048];
|
||||
cmsBool rc;
|
||||
|
||||
_cmsAssert(io != NULL);
|
||||
_cmsAssert(frm != NULL);
|
||||
|
||||
va_start(args, frm);
|
||||
|
||||
len = vsnprintf((char*) Buffer, 2047, frm, args);
|
||||
if (len < 0) return FALSE; // Truncated, which is a fatal error for us
|
||||
|
||||
rc = io ->Write(io, len, Buffer);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
// Plugin memory management -------------------------------------------------------------------------------------------------
|
||||
|
||||
static _cmsSubAllocator* PluginPool = NULL;
|
||||
|
||||
// Specialized malloc for plug-ins, that is freed upon exit.
|
||||
void* _cmsPluginMalloc(cmsUInt32Number size)
|
||||
{
|
||||
if (PluginPool == NULL)
|
||||
PluginPool = _cmsCreateSubAlloc(0, 4*1024);
|
||||
|
||||
return _cmsSubAlloc(PluginPool, size);
|
||||
}
|
||||
|
||||
|
||||
// Main plug-in dispatcher
|
||||
cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
|
||||
{
|
||||
cmsPluginBase* Plugin;
|
||||
|
||||
for (Plugin = (cmsPluginBase*) Plug_in;
|
||||
Plugin != NULL;
|
||||
Plugin = Plugin -> Next) {
|
||||
|
||||
if (Plugin -> Magic != cmsPluginMagicNumber) {
|
||||
cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Plugin ->ExpectedVersion > LCMS_VERSION) {
|
||||
cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
|
||||
Plugin ->ExpectedVersion, LCMS_VERSION);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (Plugin -> Type) {
|
||||
|
||||
case cmsPluginMemHandlerSig:
|
||||
if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
case cmsPluginInterpolationSig:
|
||||
if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
case cmsPluginTagTypeSig:
|
||||
if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
case cmsPluginTagSig:
|
||||
if (!_cmsRegisterTagPlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
case cmsPluginFormattersSig:
|
||||
if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
case cmsPluginRenderingIntentSig:
|
||||
if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
case cmsPluginParametricCurveSig:
|
||||
if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
case cmsPluginMultiProcessElementSig:
|
||||
if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
case cmsPluginOptimizationSig:
|
||||
if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a reference to the plug-in
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Revert all plug-ins to default
|
||||
void CMSEXPORT cmsUnregisterPlugins(void)
|
||||
{
|
||||
_cmsRegisterMemHandlerPlugin(NULL);
|
||||
_cmsRegisterInterpPlugin(NULL);
|
||||
_cmsRegisterTagTypePlugin(NULL);
|
||||
_cmsRegisterTagPlugin(NULL);
|
||||
_cmsRegisterFormattersPlugin(NULL);
|
||||
_cmsRegisterRenderingIntentPlugin(NULL);
|
||||
_cmsRegisterParametricCurvesPlugin(NULL);
|
||||
_cmsRegisterMultiProcessElementPlugin(NULL);
|
||||
_cmsRegisterOptimizationPlugin(NULL);
|
||||
|
||||
if (PluginPool != NULL)
|
||||
_cmsSubAllocDestroy(PluginPool);
|
||||
|
||||
PluginPool = NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,266 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
|
||||
|
||||
// This file contains routines for resampling and LUT optimization, black point detection
|
||||
// and black preservation.
|
||||
|
||||
// Black point detection -------------------------------------------------------------------------
|
||||
|
||||
|
||||
// PCS -> PCS round trip transform, always uses relative intent on the device -> pcs
|
||||
static
|
||||
cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent)
|
||||
{
|
||||
cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);
|
||||
cmsHTRANSFORM xform;
|
||||
cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE };
|
||||
cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 };
|
||||
cmsHPROFILE hProfiles[4];
|
||||
cmsUInt32Number Intents[4];
|
||||
cmsContext ContextID = cmsGetProfileContextID(hProfile);
|
||||
|
||||
hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab;
|
||||
Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC;
|
||||
|
||||
xform = cmsCreateExtendedTransform(ContextID, 4, hProfiles, BPC, Intents,
|
||||
States, NULL, 0, TYPE_Lab_DBL, TYPE_Lab_DBL, cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
|
||||
|
||||
cmsCloseProfile(hLab);
|
||||
return xform;
|
||||
}
|
||||
|
||||
// Use darker colorants to obtain black point. This works in the relative colorimetric intent and
|
||||
// assumes more ink results in darker colors. No ink limit is assumed.
|
||||
static
|
||||
cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput,
|
||||
cmsUInt32Number Intent,
|
||||
cmsCIEXYZ* BlackPoint,
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
cmsUInt16Number *Black;
|
||||
cmsHTRANSFORM xform;
|
||||
cmsColorSpaceSignature Space;
|
||||
cmsUInt32Number nChannels;
|
||||
cmsUInt32Number dwFormat;
|
||||
cmsHPROFILE hLab;
|
||||
cmsCIELab Lab;
|
||||
cmsCIEXYZ BlackXYZ;
|
||||
cmsContext ContextID = cmsGetProfileContextID(hInput);
|
||||
|
||||
// If the profile does not support input direction, assume Black point 0
|
||||
if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) {
|
||||
|
||||
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Create a formatter which has n channels and floating point
|
||||
dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2, FALSE);
|
||||
|
||||
// Try to get black by using black colorant
|
||||
Space = cmsGetColorSpace(hInput);
|
||||
|
||||
// This function returns darker colorant in 16 bits for several spaces
|
||||
if (!_cmsEndPointsBySpace(Space, NULL, &Black, &nChannels)) {
|
||||
|
||||
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nChannels != T_CHANNELS(dwFormat)) {
|
||||
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Lab will be used as the output space, but lab2 will avoid recursion
|
||||
hLab = cmsCreateLab2ProfileTHR(ContextID, NULL);
|
||||
if (hLab == NULL) {
|
||||
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Create the transform
|
||||
xform = cmsCreateTransformTHR(ContextID, hInput, dwFormat,
|
||||
hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
|
||||
cmsCloseProfile(hLab);
|
||||
|
||||
if (xform == NULL) {
|
||||
// Something went wrong. Get rid of open resources and return zero as black
|
||||
|
||||
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Convert black to Lab
|
||||
cmsDoTransform(xform, Black, &Lab, 1);
|
||||
|
||||
// Force it to be neutral, clip to max. L* of 50
|
||||
Lab.a = Lab.b = 0;
|
||||
if (Lab.L > 50) Lab.L = 50;
|
||||
|
||||
// Free the resources
|
||||
cmsDeleteTransform(xform);
|
||||
|
||||
// Convert from Lab (which is now clipped) to XYZ.
|
||||
cmsLab2XYZ(NULL, &BlackXYZ, &Lab);
|
||||
|
||||
if (BlackPoint != NULL)
|
||||
*BlackPoint = BlackXYZ;
|
||||
|
||||
return TRUE;
|
||||
|
||||
cmsUNUSED_PARAMETER(dwFlags);
|
||||
}
|
||||
|
||||
// Get a black point of output CMYK profile, discounting any ink-limiting embedded
|
||||
// in the profile. For doing that, we use perceptual intent in input direction:
|
||||
// Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab
|
||||
static
|
||||
cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile)
|
||||
|
||||
{
|
||||
cmsHTRANSFORM hRoundTrip;
|
||||
cmsCIELab LabIn, LabOut;
|
||||
cmsCIEXYZ BlackXYZ;
|
||||
|
||||
// Is the intent supported by the profile?
|
||||
if (!cmsIsIntentSupported(hProfile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT)) {
|
||||
|
||||
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
hRoundTrip = CreateRoundtripXForm(hProfile, INTENT_PERCEPTUAL);
|
||||
if (hRoundTrip == NULL) {
|
||||
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LabIn.L = LabIn.a = LabIn.b = 0;
|
||||
cmsDoTransform(hRoundTrip, &LabIn, &LabOut, 1);
|
||||
|
||||
// Clip Lab to reasonable limits
|
||||
if (LabOut.L > 50) LabOut.L = 50;
|
||||
LabOut.a = LabOut.b = 0;
|
||||
|
||||
cmsDeleteTransform(hRoundTrip);
|
||||
|
||||
// Convert it to XYZ
|
||||
cmsLab2XYZ(NULL, &BlackXYZ, &LabOut);
|
||||
|
||||
if (BlackPoint != NULL)
|
||||
*BlackPoint = BlackXYZ;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// This function shouldn't exist at all -- there is such quantity of broken
|
||||
// profiles on black point tag, that we must somehow fix chromaticity to
|
||||
// avoid huge tint when doing Black point compensation. This function does
|
||||
// just that. There is a special flag for using black point tag, but turned
|
||||
// off by default because it is bogus on most profiles. The detection algorithm
|
||||
// involves to turn BP to neutral and to use only L component.
|
||||
|
||||
cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
|
||||
{
|
||||
|
||||
// Zero for black point
|
||||
if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) {
|
||||
|
||||
BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// v4 + perceptual & saturation intents does have its own black point, and it is
|
||||
// well specified enough to use it. Black point tag is deprecated in V4.
|
||||
|
||||
if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) &&
|
||||
(Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) {
|
||||
|
||||
// Matrix shaper share MRC & perceptual intents
|
||||
if (cmsIsMatrixShaper(hProfile))
|
||||
return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0);
|
||||
|
||||
// Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents
|
||||
BlackPoint -> X = cmsPERCEPTUAL_BLACK_X;
|
||||
BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y;
|
||||
BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CMS_USE_PROFILE_BLACK_POINT_TAG
|
||||
|
||||
// v2, v4 rel/abs colorimetric
|
||||
if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) &&
|
||||
Intent == INTENT_RELATIVE_COLORIMETRIC) {
|
||||
|
||||
cmsCIEXYZ *BlackPtr, BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite;
|
||||
cmsCIELab Lab;
|
||||
|
||||
// If black point is specified, then use it,
|
||||
|
||||
BlackPtr = cmsReadTag(hProfile, cmsSigMediaBlackPointTag);
|
||||
if (BlackPtr != NULL) {
|
||||
|
||||
BlackXYZ = *BlackPtr;
|
||||
_cmsReadMediaWhitePoint(&MediaWhite, hProfile);
|
||||
|
||||
// Black point is absolute XYZ, so adapt to D50 to get PCS value
|
||||
cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ);
|
||||
|
||||
// Force a=b=0 to get rid of any chroma
|
||||
cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint);
|
||||
Lab.a = Lab.b = 0;
|
||||
if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50
|
||||
cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab);
|
||||
|
||||
if (BlackPoint != NULL)
|
||||
*BlackPoint = TrustedBlackPoint;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// That is about v2 profiles.
|
||||
|
||||
// If output profile, discount ink-limiting and that's all
|
||||
if (Intent == INTENT_RELATIVE_COLORIMETRIC &&
|
||||
(cmsGetDeviceClass(hProfile) == cmsSigOutputClass) &&
|
||||
(cmsGetColorSpace(hProfile) == cmsSigCmykData))
|
||||
return BlackPointUsingPerceptualBlack(BlackPoint, hProfile);
|
||||
|
||||
// Nope, compute BP using current intent.
|
||||
return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,734 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2011 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Gamut boundary description by using Jan Morovic's Segment maxima method
|
||||
// Many thanks to Jan for allowing me to use his algorithm.
|
||||
|
||||
// r = C*
|
||||
// alpha = Hab
|
||||
// theta = L*
|
||||
|
||||
#define SECTORS 16 // number of divisions in alpha and theta
|
||||
|
||||
// Spherical coordinates
|
||||
typedef struct {
|
||||
|
||||
cmsFloat64Number r;
|
||||
cmsFloat64Number alpha;
|
||||
cmsFloat64Number theta;
|
||||
|
||||
} cmsSpherical;
|
||||
|
||||
typedef enum {
|
||||
GP_EMPTY,
|
||||
GP_SPECIFIED,
|
||||
GP_MODELED
|
||||
|
||||
} GDBPointType;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
GDBPointType Type;
|
||||
cmsSpherical p; // Keep also alpha & theta of maximum
|
||||
|
||||
} cmsGDBPoint;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
cmsContext ContextID;
|
||||
cmsGDBPoint Gamut[SECTORS][SECTORS];
|
||||
|
||||
} cmsGDB;
|
||||
|
||||
|
||||
// A line using the parametric form
|
||||
// P = a + t*u
|
||||
typedef struct {
|
||||
|
||||
cmsVEC3 a;
|
||||
cmsVEC3 u;
|
||||
|
||||
} cmsLine;
|
||||
|
||||
|
||||
// A plane using the parametric form
|
||||
// Q = b + r*v + s*w
|
||||
typedef struct {
|
||||
|
||||
cmsVEC3 b;
|
||||
cmsVEC3 v;
|
||||
cmsVEC3 w;
|
||||
|
||||
} cmsPlane;
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
// ATAN2() which always returns degree positive numbers
|
||||
|
||||
static
|
||||
cmsFloat64Number _cmsAtan2(cmsFloat64Number y, cmsFloat64Number x)
|
||||
{
|
||||
cmsFloat64Number a;
|
||||
|
||||
// Deal with undefined case
|
||||
if (x == 0.0 && y == 0.0) return 0;
|
||||
|
||||
a = (atan2(y, x) * 180.0) / M_PI;
|
||||
|
||||
while (a < 0) {
|
||||
a += 360;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
// Convert to spherical coordinates
|
||||
static
|
||||
void ToSpherical(cmsSpherical* sp, const cmsVEC3* v)
|
||||
{
|
||||
|
||||
cmsFloat64Number L, a, b;
|
||||
|
||||
L = v ->n[VX];
|
||||
a = v ->n[VY];
|
||||
b = v ->n[VZ];
|
||||
|
||||
sp ->r = sqrt( L*L + a*a + b*b );
|
||||
|
||||
if (sp ->r == 0) {
|
||||
sp ->alpha = sp ->theta = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
sp ->alpha = _cmsAtan2(a, b);
|
||||
sp ->theta = _cmsAtan2(sqrt(a*a + b*b), L);
|
||||
}
|
||||
|
||||
|
||||
// Convert to cartesian from spherical
|
||||
static
|
||||
void ToCartesian(cmsVEC3* v, const cmsSpherical* sp)
|
||||
{
|
||||
cmsFloat64Number sin_alpha;
|
||||
cmsFloat64Number cos_alpha;
|
||||
cmsFloat64Number sin_theta;
|
||||
cmsFloat64Number cos_theta;
|
||||
cmsFloat64Number L, a, b;
|
||||
|
||||
sin_alpha = sin((M_PI * sp ->alpha) / 180.0);
|
||||
cos_alpha = cos((M_PI * sp ->alpha) / 180.0);
|
||||
sin_theta = sin((M_PI * sp ->theta) / 180.0);
|
||||
cos_theta = cos((M_PI * sp ->theta) / 180.0);
|
||||
|
||||
a = sp ->r * sin_theta * sin_alpha;
|
||||
b = sp ->r * sin_theta * cos_alpha;
|
||||
L = sp ->r * cos_theta;
|
||||
|
||||
v ->n[VX] = L;
|
||||
v ->n[VY] = a;
|
||||
v ->n[VZ] = b;
|
||||
}
|
||||
|
||||
|
||||
// Quantize sector of a spherical coordinate. Saturate 360, 180 to last sector
|
||||
// The limits are the centers of each sector, so
|
||||
static
|
||||
void QuantizeToSector(const cmsSpherical* sp, int* alpha, int* theta)
|
||||
{
|
||||
*alpha = (int) floor(((sp->alpha * (SECTORS)) / 360.0) );
|
||||
*theta = (int) floor(((sp->theta * (SECTORS)) / 180.0) );
|
||||
|
||||
if (*alpha >= SECTORS)
|
||||
*alpha = SECTORS-1;
|
||||
if (*theta >= SECTORS)
|
||||
*theta = SECTORS-1;
|
||||
}
|
||||
|
||||
|
||||
// Line determined by 2 points
|
||||
static
|
||||
void LineOf2Points(cmsLine* line, cmsVEC3* a, cmsVEC3* b)
|
||||
{
|
||||
|
||||
_cmsVEC3init(&line ->a, a ->n[VX], a ->n[VY], a ->n[VZ]);
|
||||
_cmsVEC3init(&line ->u, b ->n[VX] - a ->n[VX],
|
||||
b ->n[VY] - a ->n[VY],
|
||||
b ->n[VZ] - a ->n[VZ]);
|
||||
}
|
||||
|
||||
|
||||
// Evaluate parametric line
|
||||
static
|
||||
void GetPointOfLine(cmsVEC3* p, const cmsLine* line, cmsFloat64Number t)
|
||||
{
|
||||
p ->n[VX] = line ->a.n[VX] + t * line->u.n[VX];
|
||||
p ->n[VY] = line ->a.n[VY] + t * line->u.n[VY];
|
||||
p ->n[VZ] = line ->a.n[VZ] + t * line->u.n[VZ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Closest point in sector line1 to sector line2 (both are defined as 0 <=t <= 1)
|
||||
http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
|
||||
|
||||
Copyright 2001, softSurfer (www.softsurfer.com)
|
||||
This code may be freely used and modified for any purpose
|
||||
providing that this copyright notice is included with it.
|
||||
SoftSurfer makes no warranty for this code, and cannot be held
|
||||
liable for any real or imagined damage resulting from its use.
|
||||
Users of this code must verify correctness for their application.
|
||||
|
||||
*/
|
||||
|
||||
static
|
||||
cmsBool ClosestLineToLine(cmsVEC3* r, const cmsLine* line1, const cmsLine* line2)
|
||||
{
|
||||
cmsFloat64Number a, b, c, d, e, D;
|
||||
cmsFloat64Number sc, sN, sD;
|
||||
cmsFloat64Number tc, tN, tD;
|
||||
cmsVEC3 w0;
|
||||
|
||||
_cmsVEC3minus(&w0, &line1 ->a, &line2 ->a);
|
||||
|
||||
a = _cmsVEC3dot(&line1 ->u, &line1 ->u);
|
||||
b = _cmsVEC3dot(&line1 ->u, &line2 ->u);
|
||||
c = _cmsVEC3dot(&line2 ->u, &line2 ->u);
|
||||
d = _cmsVEC3dot(&line1 ->u, &w0);
|
||||
e = _cmsVEC3dot(&line2 ->u, &w0);
|
||||
|
||||
D = a*c - b * b; // Denominator
|
||||
sD = tD = D; // default sD = D >= 0
|
||||
|
||||
if (D < MATRIX_DET_TOLERANCE) { // the lines are almost parallel
|
||||
|
||||
sN = 0.0; // force using point P0 on segment S1
|
||||
sD = 1.0; // to prevent possible division by 0.0 later
|
||||
tN = e;
|
||||
tD = c;
|
||||
}
|
||||
else { // get the closest points on the infinite lines
|
||||
|
||||
sN = (b*e - c*d);
|
||||
tN = (a*e - b*d);
|
||||
|
||||
if (sN < 0.0) { // sc < 0 => the s=0 edge is visible
|
||||
|
||||
sN = 0.0;
|
||||
tN = e;
|
||||
tD = c;
|
||||
}
|
||||
else if (sN > sD) { // sc > 1 => the s=1 edge is visible
|
||||
sN = sD;
|
||||
tN = e + b;
|
||||
tD = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (tN < 0.0) { // tc < 0 => the t=0 edge is visible
|
||||
|
||||
tN = 0.0;
|
||||
// recompute sc for this edge
|
||||
if (-d < 0.0)
|
||||
sN = 0.0;
|
||||
else if (-d > a)
|
||||
sN = sD;
|
||||
else {
|
||||
sN = -d;
|
||||
sD = a;
|
||||
}
|
||||
}
|
||||
else if (tN > tD) { // tc > 1 => the t=1 edge is visible
|
||||
|
||||
tN = tD;
|
||||
|
||||
// recompute sc for this edge
|
||||
if ((-d + b) < 0.0)
|
||||
sN = 0;
|
||||
else if ((-d + b) > a)
|
||||
sN = sD;
|
||||
else {
|
||||
sN = (-d + b);
|
||||
sD = a;
|
||||
}
|
||||
}
|
||||
// finally do the division to get sc and tc
|
||||
sc = (fabs(sN) < MATRIX_DET_TOLERANCE ? 0.0 : sN / sD);
|
||||
tc = (fabs(tN) < MATRIX_DET_TOLERANCE ? 0.0 : tN / tD);
|
||||
|
||||
GetPointOfLine(r, line1, sc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------ Wrapper
|
||||
|
||||
|
||||
// Allocate & free structure
|
||||
cmsHANDLE CMSEXPORT cmsGBDAlloc(cmsContext ContextID)
|
||||
{
|
||||
cmsGDB* gbd = (cmsGDB*) _cmsMallocZero(ContextID, sizeof(cmsGDB));
|
||||
if (gbd == NULL) return NULL;
|
||||
|
||||
gbd -> ContextID = ContextID;
|
||||
|
||||
return (cmsHANDLE) gbd;
|
||||
}
|
||||
|
||||
|
||||
void CMSEXPORT cmsGBDFree(cmsHANDLE hGBD)
|
||||
{
|
||||
cmsGDB* gbd = (cmsGDB*) hGBD;
|
||||
if (hGBD != NULL)
|
||||
_cmsFree(gbd->ContextID, (void*) gbd);
|
||||
}
|
||||
|
||||
|
||||
// Auxiliar to retrieve a pointer to the segmentr containing the Lab value
|
||||
static
|
||||
cmsGDBPoint* GetPoint(cmsGDB* gbd, const cmsCIELab* Lab, cmsSpherical* sp)
|
||||
{
|
||||
cmsVEC3 v;
|
||||
int alpha, theta;
|
||||
|
||||
// Housekeeping
|
||||
_cmsAssert(gbd != NULL);
|
||||
_cmsAssert(Lab != NULL);
|
||||
_cmsAssert(sp != NULL);
|
||||
|
||||
// Center L* by substracting half of its domain, that's 50
|
||||
_cmsVEC3init(&v, Lab ->L - 50.0, Lab ->a, Lab ->b);
|
||||
|
||||
// Convert to spherical coordinates
|
||||
ToSpherical(sp, &v);
|
||||
|
||||
if (sp ->r < 0 || sp ->alpha < 0 || sp->theta < 0) {
|
||||
cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, "spherical value out of range");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// On which sector it falls?
|
||||
QuantizeToSector(sp, &alpha, &theta);
|
||||
|
||||
if (alpha < 0 || theta < 0 || alpha >= SECTORS || theta >= SECTORS) {
|
||||
cmsSignalError(gbd ->ContextID, cmsERROR_RANGE, " quadrant out of range");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get pointer to the sector
|
||||
return &gbd ->Gamut[theta][alpha];
|
||||
}
|
||||
|
||||
// Add a point to gamut descriptor. Point to add is in Lab color space.
|
||||
// GBD is centered on a=b=0 and L*=50
|
||||
cmsBool CMSEXPORT cmsGDBAddPoint(cmsHANDLE hGBD, const cmsCIELab* Lab)
|
||||
{
|
||||
cmsGDB* gbd = (cmsGDB*) hGBD;
|
||||
cmsGDBPoint* ptr;
|
||||
cmsSpherical sp;
|
||||
|
||||
|
||||
// Get pointer to the sector
|
||||
ptr = GetPoint(gbd, Lab, &sp);
|
||||
if (ptr == NULL) return FALSE;
|
||||
|
||||
// If no samples at this sector, add it
|
||||
if (ptr ->Type == GP_EMPTY) {
|
||||
|
||||
ptr -> Type = GP_SPECIFIED;
|
||||
ptr -> p = sp;
|
||||
}
|
||||
else {
|
||||
|
||||
|
||||
// Substitute only if radius is greater
|
||||
if (sp.r > ptr -> p.r) {
|
||||
|
||||
ptr -> Type = GP_SPECIFIED;
|
||||
ptr -> p = sp;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check if a given point falls inside gamut
|
||||
cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIELab* Lab)
|
||||
{
|
||||
cmsGDB* gbd = (cmsGDB*) hGBD;
|
||||
cmsGDBPoint* ptr;
|
||||
cmsSpherical sp;
|
||||
|
||||
// Get pointer to the sector
|
||||
ptr = GetPoint(gbd, Lab, &sp);
|
||||
if (ptr == NULL) return FALSE;
|
||||
|
||||
// If no samples at this sector, return no data
|
||||
if (ptr ->Type == GP_EMPTY) return FALSE;
|
||||
|
||||
// In gamut only if radius is greater
|
||||
|
||||
return (sp.r <= ptr -> p.r);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Find near sectors. The list of sectors found is returned on Close[].
|
||||
// The function returns the number of sectors as well.
|
||||
|
||||
// 24 9 10 11 12
|
||||
// 23 8 1 2 13
|
||||
// 22 7 * 3 14
|
||||
// 21 6 5 4 15
|
||||
// 20 19 18 17 16
|
||||
//
|
||||
// Those are the relative movements
|
||||
// {-2,-2}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2},
|
||||
// {-2,-1}, {-1, -1}, {0, -1}, {+1, -1}, {+2, -1},
|
||||
// {-2, 0}, {-1, 0}, {0, 0}, {+1, 0}, {+2, 0},
|
||||
// {-2,+1}, {-1, +1}, {0, +1}, {+1, +1}, {+2, +1},
|
||||
// {-2,+2}, {-1, +2}, {0, +2}, {+1, +2}, {+2, +2}};
|
||||
|
||||
|
||||
static
|
||||
const struct _spiral {
|
||||
|
||||
int AdvX, AdvY;
|
||||
|
||||
} Spiral[] = { {0, -1}, {+1, -1}, {+1, 0}, {+1, +1}, {0, +1}, {-1, +1},
|
||||
{-1, 0}, {-1, -1}, {-1, -2}, {0, -2}, {+1, -2}, {+2, -2},
|
||||
{+2, -1}, {+2, 0}, {+2, +1}, {+2, +2}, {+1, +2}, {0, +2},
|
||||
{-1, +2}, {-2, +2}, {-2, +1}, {-2, 0}, {-2, -1}, {-2, -2} };
|
||||
|
||||
#define NSTEPS (sizeof(Spiral) / sizeof(struct _spiral))
|
||||
|
||||
static
|
||||
int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[])
|
||||
{
|
||||
int nSectors = 0;
|
||||
int i, a, t;
|
||||
cmsGDBPoint* pt;
|
||||
|
||||
for (i=0; i < NSTEPS; i++) {
|
||||
|
||||
a = alpha + Spiral[i].AdvX;
|
||||
t = theta + Spiral[i].AdvY;
|
||||
|
||||
// Cycle at the end
|
||||
a %= SECTORS;
|
||||
t %= SECTORS;
|
||||
|
||||
// Cycle at the begin
|
||||
if (a < 0) a = SECTORS + a;
|
||||
if (t < 0) t = SECTORS + t;
|
||||
|
||||
pt = &gbd ->Gamut[t][a];
|
||||
|
||||
if (pt -> Type != GP_EMPTY) {
|
||||
|
||||
Close[nSectors++] = pt;
|
||||
}
|
||||
}
|
||||
|
||||
return nSectors;
|
||||
}
|
||||
|
||||
|
||||
// Interpolate a missing sector. Method identifies whatever this is top, bottom or mid
|
||||
static
|
||||
cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta)
|
||||
{
|
||||
cmsSpherical sp;
|
||||
cmsVEC3 Lab;
|
||||
cmsVEC3 Centre;
|
||||
cmsLine ray;
|
||||
int nCloseSectors;
|
||||
cmsGDBPoint* Close[NSTEPS + 1];
|
||||
cmsSpherical closel, templ;
|
||||
cmsLine edge;
|
||||
int k, m;
|
||||
|
||||
// Is that point already specified?
|
||||
if (gbd ->Gamut[theta][alpha].Type != GP_EMPTY) return TRUE;
|
||||
|
||||
// Fill close points
|
||||
nCloseSectors = FindNearSectors(gbd, alpha, theta, Close);
|
||||
|
||||
|
||||
// Find a central point on the sector
|
||||
sp.alpha = (cmsFloat64Number) ((alpha + 0.5) * 360.0) / (SECTORS);
|
||||
sp.theta = (cmsFloat64Number) ((theta + 0.5) * 180.0) / (SECTORS);
|
||||
sp.r = 50.0;
|
||||
|
||||
// Convert to Cartesian
|
||||
ToCartesian(&Lab, &sp);
|
||||
|
||||
// Create a ray line from centre to this point
|
||||
_cmsVEC3init(&Centre, 50.0, 0, 0);
|
||||
LineOf2Points(&ray, &Lab, &Centre);
|
||||
|
||||
// For all close sectors
|
||||
closel.r = 0.0;
|
||||
closel.alpha = 0;
|
||||
closel.theta = 0;
|
||||
|
||||
for (k=0; k < nCloseSectors; k++) {
|
||||
|
||||
for(m = k+1; m < nCloseSectors; m++) {
|
||||
|
||||
cmsVEC3 temp, a1, a2;
|
||||
|
||||
// A line from sector to sector
|
||||
ToCartesian(&a1, &Close[k]->p);
|
||||
ToCartesian(&a2, &Close[m]->p);
|
||||
|
||||
LineOf2Points(&edge, &a1, &a2);
|
||||
|
||||
// Find a line
|
||||
ClosestLineToLine(&temp, &ray, &edge);
|
||||
|
||||
// Convert to spherical
|
||||
ToSpherical(&templ, &temp);
|
||||
|
||||
|
||||
if ( templ.r > closel.r &&
|
||||
templ.theta >= (theta*180.0/SECTORS) &&
|
||||
templ.theta <= ((theta+1)*180.0/SECTORS) &&
|
||||
templ.alpha >= (alpha*360.0/SECTORS) &&
|
||||
templ.alpha <= ((alpha+1)*360.0/SECTORS)) {
|
||||
|
||||
closel = templ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gbd ->Gamut[theta][alpha].p = closel;
|
||||
gbd ->Gamut[theta][alpha].Type = GP_MODELED;
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Interpolate missing parts. The algorithm fist computes slices at
|
||||
// theta=0 and theta=Max.
|
||||
cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags)
|
||||
{
|
||||
int alpha, theta;
|
||||
cmsGDB* gbd = (cmsGDB*) hGBD;
|
||||
|
||||
_cmsAssert(hGBD != NULL);
|
||||
|
||||
// Interpolate black
|
||||
for (alpha = 0; alpha <= SECTORS; alpha++) {
|
||||
|
||||
if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE;
|
||||
}
|
||||
|
||||
// Interpolate white
|
||||
for (alpha = 0; alpha <= SECTORS; alpha++) {
|
||||
|
||||
if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Interpolate Mid
|
||||
for (theta = 1; theta < SECTORS; theta++) {
|
||||
for (alpha = 0; alpha <= SECTORS; alpha++) {
|
||||
|
||||
if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Done
|
||||
return TRUE;
|
||||
|
||||
cmsUNUSED_PARAMETER(dwFlags);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Great for debug, but not suitable for real use
|
||||
|
||||
#if 0
|
||||
cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname)
|
||||
{
|
||||
FILE* fp;
|
||||
int i, j;
|
||||
cmsGDB* gbd = (cmsGDB*) hGBD;
|
||||
cmsGDBPoint* pt;
|
||||
|
||||
fp = fopen (fname, "wt");
|
||||
if (fp == NULL)
|
||||
return FALSE;
|
||||
|
||||
fprintf (fp, "#VRML V2.0 utf8\n");
|
||||
|
||||
// set the viewing orientation and distance
|
||||
fprintf (fp, "DEF CamTest Group {\n");
|
||||
fprintf (fp, "\tchildren [\n");
|
||||
fprintf (fp, "\t\tDEF Cameras Group {\n");
|
||||
fprintf (fp, "\t\t\tchildren [\n");
|
||||
fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n");
|
||||
fprintf (fp, "\t\t\t\t\tposition 0 0 340\n");
|
||||
fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n");
|
||||
fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n");
|
||||
fprintf (fp, "\t\t\t\t}\n");
|
||||
fprintf (fp, "\t\t\t]\n");
|
||||
fprintf (fp, "\t\t},\n");
|
||||
fprintf (fp, "\t]\n");
|
||||
fprintf (fp, "}\n");
|
||||
|
||||
// Output the background stuff
|
||||
fprintf (fp, "Background {\n");
|
||||
fprintf (fp, "\tskyColor [\n");
|
||||
fprintf (fp, "\t\t.5 .5 .5\n");
|
||||
fprintf (fp, "\t]\n");
|
||||
fprintf (fp, "}\n");
|
||||
|
||||
// Output the shape stuff
|
||||
fprintf (fp, "Transform {\n");
|
||||
fprintf (fp, "\tscale .3 .3 .3\n");
|
||||
fprintf (fp, "\tchildren [\n");
|
||||
|
||||
// Draw the axes as a shape:
|
||||
fprintf (fp, "\t\tShape {\n");
|
||||
fprintf (fp, "\t\t\tappearance Appearance {\n");
|
||||
fprintf (fp, "\t\t\t\tmaterial Material {\n");
|
||||
fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
|
||||
fprintf (fp, "\t\t\t\t\temissiveColor 1.0 1.0 1.0\n");
|
||||
fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
|
||||
fprintf (fp, "\t\t\t\t}\n");
|
||||
fprintf (fp, "\t\t\t}\n");
|
||||
fprintf (fp, "\t\t\tgeometry IndexedLineSet {\n");
|
||||
fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
|
||||
fprintf (fp, "\t\t\t\t\tpoint [\n");
|
||||
fprintf (fp, "\t\t\t\t\t0.0 0.0 0.0,\n");
|
||||
fprintf (fp, "\t\t\t\t\t%f 0.0 0.0,\n", 255.0);
|
||||
fprintf (fp, "\t\t\t\t\t0.0 %f 0.0,\n", 255.0);
|
||||
fprintf (fp, "\t\t\t\t\t0.0 0.0 %f]\n", 255.0);
|
||||
fprintf (fp, "\t\t\t\t}\n");
|
||||
fprintf (fp, "\t\t\t\tcoordIndex [\n");
|
||||
fprintf (fp, "\t\t\t\t\t0, 1, -1\n");
|
||||
fprintf (fp, "\t\t\t\t\t0, 2, -1\n");
|
||||
fprintf (fp, "\t\t\t\t\t0, 3, -1]\n");
|
||||
fprintf (fp, "\t\t\t}\n");
|
||||
fprintf (fp, "\t\t}\n");
|
||||
|
||||
|
||||
fprintf (fp, "\t\tShape {\n");
|
||||
fprintf (fp, "\t\t\tappearance Appearance {\n");
|
||||
fprintf (fp, "\t\t\t\tmaterial Material {\n");
|
||||
fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
|
||||
fprintf (fp, "\t\t\t\t\temissiveColor 1 1 1\n");
|
||||
fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
|
||||
fprintf (fp, "\t\t\t\t}\n");
|
||||
fprintf (fp, "\t\t\t}\n");
|
||||
fprintf (fp, "\t\t\tgeometry PointSet {\n");
|
||||
|
||||
// fill in the points here
|
||||
fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
|
||||
fprintf (fp, "\t\t\t\t\tpoint [\n");
|
||||
|
||||
// We need to transverse all gamut hull.
|
||||
for (i=0; i < SECTORS; i++)
|
||||
for (j=0; j < SECTORS; j++) {
|
||||
|
||||
cmsVEC3 v;
|
||||
|
||||
pt = &gbd ->Gamut[i][j];
|
||||
ToCartesian(&v, &pt ->p);
|
||||
|
||||
fprintf (fp, "\t\t\t\t\t%g %g %g", v.n[0]+50, v.n[1], v.n[2]);
|
||||
|
||||
if ((j == SECTORS - 1) && (i == SECTORS - 1))
|
||||
fprintf (fp, "]\n");
|
||||
else
|
||||
fprintf (fp, ",\n");
|
||||
|
||||
}
|
||||
|
||||
fprintf (fp, "\t\t\t\t}\n");
|
||||
|
||||
|
||||
|
||||
// fill in the face colors
|
||||
fprintf (fp, "\t\t\t\tcolor Color {\n");
|
||||
fprintf (fp, "\t\t\t\t\tcolor [\n");
|
||||
|
||||
for (i=0; i < SECTORS; i++)
|
||||
for (j=0; j < SECTORS; j++) {
|
||||
|
||||
cmsVEC3 v;
|
||||
|
||||
pt = &gbd ->Gamut[i][j];
|
||||
|
||||
|
||||
ToCartesian(&v, &pt ->p);
|
||||
|
||||
|
||||
if (pt ->Type == GP_EMPTY)
|
||||
fprintf (fp, "\t\t\t\t\t%g %g %g", 0.0, 0.0, 0.0);
|
||||
else
|
||||
if (pt ->Type == GP_MODELED)
|
||||
fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, .5, .5);
|
||||
else {
|
||||
fprintf (fp, "\t\t\t\t\t%g %g %g", 1.0, 1.0, 1.0);
|
||||
|
||||
}
|
||||
|
||||
if ((j == SECTORS - 1) && (i == SECTORS - 1))
|
||||
fprintf (fp, "]\n");
|
||||
else
|
||||
fprintf (fp, ",\n");
|
||||
}
|
||||
fprintf (fp, "\t\t\t}\n");
|
||||
|
||||
|
||||
fprintf (fp, "\t\t\t}\n");
|
||||
fprintf (fp, "\t\t}\n");
|
||||
fprintf (fp, "\t]\n");
|
||||
fprintf (fp, "}\n");
|
||||
|
||||
fclose (fp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,351 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2010 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
|
||||
// D50 - Widely used
|
||||
const cmsCIEXYZ* CMSEXPORT cmsD50_XYZ(void)
|
||||
{
|
||||
static cmsCIEXYZ D50XYZ = {cmsD50X, cmsD50Y, cmsD50Z};
|
||||
|
||||
return &D50XYZ;
|
||||
}
|
||||
|
||||
const cmsCIExyY* CMSEXPORT cmsD50_xyY(void)
|
||||
{
|
||||
static cmsCIExyY D50xyY;
|
||||
|
||||
cmsXYZ2xyY(&D50xyY, cmsD50_XYZ());
|
||||
|
||||
return &D50xyY;
|
||||
}
|
||||
|
||||
// Obtains WhitePoint from Temperature
|
||||
cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK)
|
||||
{
|
||||
cmsFloat64Number x, y;
|
||||
cmsFloat64Number T, T2, T3;
|
||||
// cmsFloat64Number M1, M2;
|
||||
|
||||
_cmsAssert(WhitePoint != NULL);
|
||||
|
||||
T = TempK;
|
||||
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 {
|
||||
cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
WhitePoint -> x = x;
|
||||
WhitePoint -> y = y;
|
||||
WhitePoint -> Y = 1.0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
cmsFloat64Number mirek; // temp (in microreciprocal kelvin)
|
||||
cmsFloat64Number ut; // u coord of intersection w/ blackbody locus
|
||||
cmsFloat64Number vt; // v coord of intersection w/ blackbody locus
|
||||
cmsFloat64Number tt; // slope of ISOTEMPERATURE. line
|
||||
|
||||
} ISOTEMPERATURE;
|
||||
|
||||
static ISOTEMPERATURE isotempdata[] = {
|
||||
// {Mirek, Ut, Vt, Tt }
|
||||
{0, 0.18006, 0.26352, -0.24341},
|
||||
{10, 0.18066, 0.26589, -0.25479},
|
||||
{20, 0.18133, 0.26846, -0.26876},
|
||||
{30, 0.18208, 0.27119, -0.28539},
|
||||
{40, 0.18293, 0.27407, -0.30470},
|
||||
{50, 0.18388, 0.27709, -0.32675},
|
||||
{60, 0.18494, 0.28021, -0.35156},
|
||||
{70, 0.18611, 0.28342, -0.37915},
|
||||
{80, 0.18740, 0.28668, -0.40955},
|
||||
{90, 0.18880, 0.28997, -0.44278},
|
||||
{100, 0.19032, 0.29326, -0.47888},
|
||||
{125, 0.19462, 0.30141, -0.58204},
|
||||
{150, 0.19962, 0.30921, -0.70471},
|
||||
{175, 0.20525, 0.31647, -0.84901},
|
||||
{200, 0.21142, 0.32312, -1.0182 },
|
||||
{225, 0.21807, 0.32909, -1.2168 },
|
||||
{250, 0.22511, 0.33439, -1.4512 },
|
||||
{275, 0.23247, 0.33904, -1.7298 },
|
||||
{300, 0.24010, 0.34308, -2.0637 },
|
||||
{325, 0.24702, 0.34655, -2.4681 },
|
||||
{350, 0.25591, 0.34951, -2.9641 },
|
||||
{375, 0.26400, 0.35200, -3.5814 },
|
||||
{400, 0.27218, 0.35407, -4.3633 },
|
||||
{425, 0.28039, 0.35577, -5.3762 },
|
||||
{450, 0.28863, 0.35714, -6.7262 },
|
||||
{475, 0.29685, 0.35823, -8.5955 },
|
||||
{500, 0.30505, 0.35907, -11.324 },
|
||||
{525, 0.31320, 0.35968, -15.628 },
|
||||
{550, 0.32129, 0.36011, -23.325 },
|
||||
{575, 0.32931, 0.36038, -40.770 },
|
||||
{600, 0.33724, 0.36051, -116.45 }
|
||||
};
|
||||
|
||||
#define NISO sizeof(isotempdata)/sizeof(ISOTEMPERATURE)
|
||||
|
||||
|
||||
// Robertson's method
|
||||
cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint)
|
||||
{
|
||||
int j;
|
||||
cmsFloat64Number us,vs;
|
||||
cmsFloat64Number uj,vj,tj,di,dj,mi,mj;
|
||||
cmsFloat64Number xs, ys;
|
||||
|
||||
_cmsAssert(WhitePoint != NULL);
|
||||
_cmsAssert(TempK != NULL);
|
||||
|
||||
di = mi = 0;
|
||||
xs = WhitePoint -> x;
|
||||
ys = WhitePoint -> y;
|
||||
|
||||
// convert (x,y) to CIE 1960 (u,WhitePoint)
|
||||
|
||||
us = (2*xs) / (-xs + 6*ys + 1.5);
|
||||
vs = (3*ys) / (-xs + 6*ys + 1.5);
|
||||
|
||||
|
||||
for (j=0; j < NISO; j++) {
|
||||
|
||||
uj = isotempdata[j].ut;
|
||||
vj = isotempdata[j].vt;
|
||||
tj = isotempdata[j].tt;
|
||||
mj = isotempdata[j].mirek;
|
||||
|
||||
dj = ((vs - vj) - tj * (us - uj)) / sqrt(1.0 + tj * tj);
|
||||
|
||||
if ((j != 0) && (di/dj < 0.0)) {
|
||||
|
||||
// Found a match
|
||||
*TempK = 1000000.0 / (mi + (di / (di - dj)) * (mj - mi));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
di = dj;
|
||||
mi = mj;
|
||||
}
|
||||
|
||||
// Not found
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Compute chromatic adaptation matrix using Chad as cone matrix
|
||||
|
||||
static
|
||||
cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion,
|
||||
const cmsCIEXYZ* SourceWhitePoint,
|
||||
const cmsCIEXYZ* DestWhitePoint,
|
||||
const cmsMAT3* Chad)
|
||||
|
||||
{
|
||||
|
||||
cmsMAT3 Chad_Inv;
|
||||
cmsVEC3 ConeSourceXYZ, ConeSourceRGB;
|
||||
cmsVEC3 ConeDestXYZ, ConeDestRGB;
|
||||
cmsMAT3 Cone, Tmp;
|
||||
|
||||
|
||||
Tmp = *Chad;
|
||||
if (!_cmsMAT3inverse(&Tmp, &Chad_Inv)) return FALSE;
|
||||
|
||||
_cmsVEC3init(&ConeSourceXYZ, SourceWhitePoint -> X,
|
||||
SourceWhitePoint -> Y,
|
||||
SourceWhitePoint -> Z);
|
||||
|
||||
_cmsVEC3init(&ConeDestXYZ, DestWhitePoint -> X,
|
||||
DestWhitePoint -> Y,
|
||||
DestWhitePoint -> Z);
|
||||
|
||||
_cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ);
|
||||
_cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ);
|
||||
|
||||
// Build matrix
|
||||
_cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0);
|
||||
_cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0);
|
||||
_cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]);
|
||||
|
||||
|
||||
// Normalize
|
||||
_cmsMAT3per(&Tmp, &Cone, Chad);
|
||||
_cmsMAT3per(Conversion, &Chad_Inv, &Tmp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Returns the final chrmatic adaptation from illuminant FromIll to Illuminant ToIll
|
||||
// The cone matrix can be specified in ConeMatrix. If NULL, Bradford is assumed
|
||||
cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll)
|
||||
{
|
||||
cmsMAT3 LamRigg = {{ // Bradford matrix
|
||||
{{ 0.8951, 0.2664, -0.1614 }},
|
||||
{{ -0.7502, 1.7135, 0.0367 }},
|
||||
{{ 0.0389, -0.0685, 1.0296 }}
|
||||
}};
|
||||
|
||||
if (ConeMatrix == NULL)
|
||||
ConeMatrix = &LamRigg;
|
||||
|
||||
return ComputeChromaticAdaptation(r, FromIll, ToIll, ConeMatrix);
|
||||
}
|
||||
|
||||
// Same as anterior, but assuming D50 destination. White point is given in xyY
|
||||
static
|
||||
cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt)
|
||||
{
|
||||
cmsCIEXYZ Dn;
|
||||
cmsMAT3 Bradford;
|
||||
cmsMAT3 Tmp;
|
||||
|
||||
cmsxyY2XYZ(&Dn, SourceWhitePt);
|
||||
|
||||
if (!_cmsAdaptationMatrix(&Bradford, NULL, &Dn, cmsD50_XYZ())) return FALSE;
|
||||
|
||||
Tmp = *r;
|
||||
_cmsMAT3per(r, &Bradford, &Tmp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// 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
|
||||
//
|
||||
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs)
|
||||
{
|
||||
cmsVEC3 WhitePoint, Coef;
|
||||
cmsMAT3 Result, Primaries;
|
||||
cmsFloat64Number xn, yn;
|
||||
cmsFloat64Number xr, yr;
|
||||
cmsFloat64Number xg, yg;
|
||||
cmsFloat64Number xb, yb;
|
||||
|
||||
xn = WhitePt -> x;
|
||||
yn = WhitePt -> y;
|
||||
xr = Primrs -> Red.x;
|
||||
yr = Primrs -> Red.y;
|
||||
xg = Primrs -> Green.x;
|
||||
yg = Primrs -> Green.y;
|
||||
xb = Primrs -> Blue.x;
|
||||
yb = Primrs -> Blue.y;
|
||||
|
||||
// Build Primaries matrix
|
||||
_cmsVEC3init(&Primaries.v[0], xr, xg, xb);
|
||||
_cmsVEC3init(&Primaries.v[1], yr, yg, yb);
|
||||
_cmsVEC3init(&Primaries.v[2], (1-xr-yr), (1-xg-yg), (1-xb-yb));
|
||||
|
||||
|
||||
// Result = Primaries ^ (-1) inverse matrix
|
||||
if (!_cmsMAT3inverse(&Primaries, &Result))
|
||||
return FALSE;
|
||||
|
||||
|
||||
_cmsVEC3init(&WhitePoint, xn/yn, 1.0, (1.0-xn-yn)/yn);
|
||||
|
||||
// Across inverse primaries ...
|
||||
_cmsMAT3eval(&Coef, &Result, &WhitePoint);
|
||||
|
||||
// Give us the Coefs, then I build transformation matrix
|
||||
_cmsVEC3init(&r -> v[0], Coef.n[VX]*xr, Coef.n[VY]*xg, Coef.n[VZ]*xb);
|
||||
_cmsVEC3init(&r -> v[1], Coef.n[VX]*yr, Coef.n[VY]*yg, Coef.n[VZ]*yb);
|
||||
_cmsVEC3init(&r -> v[2], Coef.n[VX]*(1.0-xr-yr), Coef.n[VY]*(1.0-xg-yg), Coef.n[VZ]*(1.0-xb-yb));
|
||||
|
||||
|
||||
return _cmsAdaptMatrixToD50(r, WhitePt);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Adapts a color to a given illuminant. Original color is expected to have
|
||||
// a SourceWhitePt white point.
|
||||
cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result,
|
||||
const cmsCIEXYZ* SourceWhitePt,
|
||||
const cmsCIEXYZ* Illuminant,
|
||||
const cmsCIEXYZ* Value)
|
||||
{
|
||||
cmsMAT3 Bradford;
|
||||
cmsVEC3 In, Out;
|
||||
|
||||
_cmsAssert(Result != NULL);
|
||||
_cmsAssert(SourceWhitePt != NULL);
|
||||
_cmsAssert(Illuminant != NULL);
|
||||
_cmsAssert(Value != NULL);
|
||||
|
||||
if (!_cmsAdaptationMatrix(&Bradford, NULL, SourceWhitePt, Illuminant)) return FALSE;
|
||||
|
||||
_cmsVEC3init(&In, Value -> X, Value -> Y, Value -> Z);
|
||||
_cmsMAT3eval(&Out, &Bradford, &In);
|
||||
|
||||
Result -> X = Out.n[0];
|
||||
Result -> Y = Out.n[1];
|
||||
Result -> Z = Out.n[2];
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,815 @@
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2011 Marti Maria Saguer
|
||||
//
|
||||
// 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 "lcms2_internal.h"
|
||||
|
||||
// Transformations stuff
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Alarm codes for 16-bit transformations, because the fixed range of containers there are
|
||||
// no values left to mark out of gamut. volatile is C99 per 6.2.5
|
||||
static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS];
|
||||
static volatile cmsFloat64Number GlobalAdaptationState = 0;
|
||||
|
||||
// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
|
||||
cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
|
||||
{
|
||||
cmsFloat64Number OldVal = GlobalAdaptationState;
|
||||
|
||||
if (d >= 0)
|
||||
GlobalAdaptationState = d;
|
||||
|
||||
return OldVal;
|
||||
}
|
||||
|
||||
// Alarm codes are always global
|
||||
void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
|
||||
{
|
||||
int i;
|
||||
|
||||
_cmsAssert(NewAlarm != NULL);
|
||||
|
||||
for (i=0; i < cmsMAXCHANNELS; i++)
|
||||
Alarm[i] = NewAlarm[i];
|
||||
}
|
||||
|
||||
// You can get the codes cas well
|
||||
void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
|
||||
{
|
||||
int i;
|
||||
|
||||
_cmsAssert(OldAlarm != NULL);
|
||||
|
||||
for (i=0; i < cmsMAXCHANNELS; i++)
|
||||
OldAlarm[i] = Alarm[i];
|
||||
}
|
||||
|
||||
// Get rid of transform resources
|
||||
void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
|
||||
{
|
||||
_cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform;
|
||||
|
||||
_cmsAssert(p != NULL);
|
||||
|
||||
if (p -> GamutCheck)
|
||||
cmsPipelineFree(p -> GamutCheck);
|
||||
|
||||
if (p -> Lut)
|
||||
cmsPipelineFree(p -> Lut);
|
||||
|
||||
if (p ->InputColorant)
|
||||
cmsFreeNamedColorList(p ->InputColorant);
|
||||
|
||||
if (p -> OutputColorant)
|
||||
cmsFreeNamedColorList(p ->OutputColorant);
|
||||
|
||||
if (p ->Sequence)
|
||||
cmsFreeProfileSequenceDescription(p ->Sequence);
|
||||
|
||||
_cmsFree(p ->ContextID, (void *) p);
|
||||
}
|
||||
|
||||
// Apply transform.
|
||||
void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
|
||||
const void* InputBuffer,
|
||||
void* OutputBuffer,
|
||||
cmsUInt32Number Size)
|
||||
|
||||
{
|
||||
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
|
||||
|
||||
p -> xform(p, InputBuffer, OutputBuffer, Size);
|
||||
}
|
||||
|
||||
|
||||
// Transform routines ----------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
|
||||
// Note that because extended range, we can use a -1.0 value for out of gamut in this case.
|
||||
static
|
||||
void FloatXFORM(_cmsTRANSFORM* p,
|
||||
const void* in,
|
||||
void* out, cmsUInt32Number Size)
|
||||
{
|
||||
cmsUInt8Number* accum;
|
||||
cmsUInt8Number* output;
|
||||
cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
|
||||
cmsFloat32Number OutOfGamut;
|
||||
cmsUInt32Number i, j;
|
||||
|
||||
accum = (cmsUInt8Number*) in;
|
||||
output = (cmsUInt8Number*) out;
|
||||
|
||||
for (i=0; i < Size; i++) {
|
||||
|
||||
accum = p -> FromInputFloat(p, fIn, accum, Size);
|
||||
|
||||
// Any gamut chack to do?
|
||||
if (p ->GamutCheck != NULL) {
|
||||
|
||||
// Evaluate gamut marker.
|
||||
cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck);
|
||||
|
||||
// Is current color out of gamut?
|
||||
if (OutOfGamut > 0.0) {
|
||||
|
||||
// Certainly, out of gamut
|
||||
for (j=0; j < cmsMAXCHANNELS; j++)
|
||||
fOut[j] = -1.0;
|
||||
|
||||
}
|
||||
else {
|
||||
// No, proceed normally
|
||||
cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// No gamut check at all
|
||||
cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
|
||||
}
|
||||
|
||||
// Back to asked representation
|
||||
output = p -> ToOutputFloat(p, fOut, output, Size);
|
||||
}
|
||||
}
|
||||
|
||||
// 16 bit precision -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Null transformation, only applies formatters. No caché
|
||||
static
|
||||
void NullXFORM(_cmsTRANSFORM* p,
|
||||
const void* in,
|
||||
void* out, cmsUInt32Number Size)
|
||||
{
|
||||
cmsUInt8Number* accum;
|
||||
cmsUInt8Number* output;
|
||||
cmsUInt16Number wIn[cmsMAXCHANNELS];
|
||||
cmsUInt32Number i, n;
|
||||
|
||||
accum = (cmsUInt8Number*) in;
|
||||
output = (cmsUInt8Number*) out;
|
||||
n = Size; // Buffer len
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
|
||||
accum = p -> FromInput(p, wIn, accum, Size);
|
||||
output = p -> ToOutput(p, wIn, output, Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// No gamut check, no cache, 16 bits
|
||||
static
|
||||
void PrecalculatedXFORM(_cmsTRANSFORM* p,
|
||||
const void* in,
|
||||
void* out, cmsUInt32Number Size)
|
||||
{
|
||||
register cmsUInt8Number* accum;
|
||||
register cmsUInt8Number* output;
|
||||
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
|
||||
cmsUInt32Number i, n;
|
||||
|
||||
accum = (cmsUInt8Number*) in;
|
||||
output = (cmsUInt8Number*) out;
|
||||
n = Size;
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
|
||||
accum = p -> FromInput(p, wIn, accum, Size);
|
||||
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
|
||||
output = p -> ToOutput(p, wOut, output, Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Auxiliar: Handle precalculated gamut check
|
||||
static
|
||||
void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
|
||||
const cmsUInt16Number wIn[],
|
||||
cmsUInt16Number wOut[])
|
||||
{
|
||||
cmsUInt16Number wOutOfGamut;
|
||||
|
||||
p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
|
||||
if (wOutOfGamut >= 1) {
|
||||
|
||||
cmsUInt16Number i;
|
||||
|
||||
for (i=0; i < p ->Lut->OutputChannels; i++)
|
||||
wOut[i] = Alarm[i];
|
||||
}
|
||||
else
|
||||
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
|
||||
}
|
||||
|
||||
// Gamut check, No caché, 16 bits.
|
||||
static
|
||||
void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
|
||||
const void* in,
|
||||
void* out, cmsUInt32Number Size)
|
||||
{
|
||||
cmsUInt8Number* accum;
|
||||
cmsUInt8Number* output;
|
||||
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
|
||||
cmsUInt32Number i, n;
|
||||
|
||||
accum = (cmsUInt8Number*) in;
|
||||
output = (cmsUInt8Number*) out;
|
||||
n = Size; // Buffer len
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
|
||||
accum = p -> FromInput(p, wIn, accum, Size);
|
||||
TransformOnePixelWithGamutCheck(p, wIn, wOut);
|
||||
output = p -> ToOutput(p, wOut, output, Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// No gamut check, Caché, 16 bits,
|
||||
static
|
||||
void CachedXFORM(_cmsTRANSFORM* p,
|
||||
const void* in,
|
||||
void* out, cmsUInt32Number Size)
|
||||
{
|
||||
cmsUInt8Number* accum;
|
||||
cmsUInt8Number* output;
|
||||
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
|
||||
cmsUInt32Number i, n;
|
||||
_cmsCACHE Cache;
|
||||
|
||||
accum = (cmsUInt8Number*) in;
|
||||
output = (cmsUInt8Number*) out;
|
||||
n = Size; // Buffer len
|
||||
|
||||
// Empty buffers for quick memcmp
|
||||
memset(wIn, 0, sizeof(wIn));
|
||||
memset(wOut, 0, sizeof(wOut));
|
||||
|
||||
// Get copy of zero cache
|
||||
memcpy(&Cache, &p ->Cache, sizeof(Cache));
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
|
||||
accum = p -> FromInput(p, wIn, accum, Size);
|
||||
|
||||
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
|
||||
|
||||
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
|
||||
}
|
||||
else {
|
||||
|
||||
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
|
||||
|
||||
memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
|
||||
memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
|
||||
}
|
||||
|
||||
output = p -> ToOutput(p, wOut, output, Size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// All those nice features together
|
||||
static
|
||||
void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
|
||||
const void* in,
|
||||
void* out, cmsUInt32Number Size)
|
||||
{
|
||||
cmsUInt8Number* accum;
|
||||
cmsUInt8Number* output;
|
||||
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
|
||||
cmsUInt32Number i, n;
|
||||
_cmsCACHE Cache;
|
||||
|
||||
accum = (cmsUInt8Number*) in;
|
||||
output = (cmsUInt8Number*) out;
|
||||
n = Size; // Buffer len
|
||||
|
||||
// Empty buffers for quick memcmp
|
||||
memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
|
||||
memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
|
||||
|
||||
// Get copy of zero cache
|
||||
memcpy(&Cache, &p ->Cache, sizeof(Cache));
|
||||
|
||||
for (i=0; i < n; i++) {
|
||||
|
||||
accum = p -> FromInput(p, wIn, accum, Size);
|
||||
|
||||
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
|
||||
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
|
||||
}
|
||||
else {
|
||||
TransformOnePixelWithGamutCheck(p, wIn, wOut);
|
||||
memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
|
||||
memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
|
||||
}
|
||||
|
||||
output = p -> ToOutput(p, wOut, output, Size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Allocate transform struct and set it to defaults
|
||||
static
|
||||
_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags)
|
||||
{
|
||||
// Allocate needed memory
|
||||
_cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
|
||||
if (!p) return NULL;
|
||||
|
||||
// Check whatever this is a true floating point transform
|
||||
if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) {
|
||||
|
||||
// Get formatter function always return a valid union, but the contents of this union may be NULL.
|
||||
p ->FromInputFloat = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
|
||||
p ->ToOutputFloat = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
|
||||
dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
|
||||
|
||||
if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
|
||||
|
||||
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
|
||||
_cmsFree(ContextID, p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Float transforms don't use caché, always are non-NULL
|
||||
p ->xform = FloatXFORM;
|
||||
}
|
||||
else {
|
||||
|
||||
if (InputFormat == 0 && OutputFormat == 0) {
|
||||
p ->FromInput = p ->ToOutput = NULL;
|
||||
}
|
||||
else {
|
||||
|
||||
int BytesPerPixelInput;
|
||||
|
||||
p ->FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
|
||||
p ->ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
|
||||
|
||||
|
||||
if (p ->FromInput == NULL || p ->ToOutput == NULL) {
|
||||
|
||||
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
|
||||
_cmsFree(ContextID, p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BytesPerPixelInput = T_BYTES(p ->InputFormat);
|
||||
if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
|
||||
dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
|
||||
|
||||
}
|
||||
|
||||
if (dwFlags & cmsFLAGS_NULLTRANSFORM) {
|
||||
|
||||
p ->xform = NullXFORM;
|
||||
}
|
||||
else {
|
||||
if (dwFlags & cmsFLAGS_NOCACHE) {
|
||||
|
||||
if (dwFlags & cmsFLAGS_GAMUTCHECK)
|
||||
p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no caché
|
||||
else
|
||||
p ->xform = PrecalculatedXFORM; // No caché, no gamut check
|
||||
}
|
||||
else {
|
||||
|
||||
if (dwFlags & cmsFLAGS_GAMUTCHECK)
|
||||
p ->xform = CachedXFORMGamutCheck; // Gamut check, caché
|
||||
else
|
||||
p ->xform = CachedXFORM; // No gamut check, caché
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
p ->InputFormat = InputFormat;
|
||||
p ->OutputFormat = OutputFormat;
|
||||
p ->dwOriginalFlags = dwFlags;
|
||||
p ->ContextID = ContextID;
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
|
||||
{
|
||||
cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
|
||||
cmsColorSpaceSignature PostColorSpace;
|
||||
int i;
|
||||
|
||||
if (hProfiles[0] == NULL) return FALSE;
|
||||
|
||||
*Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
|
||||
|
||||
// Special handling for named color profiles as devicelinks
|
||||
if (nProfiles == 1 && cmsGetDeviceClass(hProfiles[0]) == cmsSigNamedColorClass) {
|
||||
*Input = cmsSig1colorData;
|
||||
*Output = PostColorSpace;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (i=0; i < nProfiles; i++) {
|
||||
|
||||
cmsHPROFILE hProfile = hProfiles[i];
|
||||
|
||||
int lIsInput = (PostColorSpace != cmsSigXYZData) &&
|
||||
(PostColorSpace != cmsSigLabData);
|
||||
|
||||
int lIsDeviceLink;
|
||||
|
||||
if (hProfile == NULL) return FALSE;
|
||||
|
||||
lIsDeviceLink = (cmsGetDeviceClass(hProfile) == cmsSigLinkClass);
|
||||
|
||||
if (lIsInput || lIsDeviceLink) {
|
||||
|
||||
ColorSpaceIn = cmsGetColorSpace(hProfile);
|
||||
ColorSpaceOut = cmsGetPCS(hProfile);
|
||||
}
|
||||
else {
|
||||
|
||||
ColorSpaceIn = cmsGetPCS(hProfile);
|
||||
ColorSpaceOut = cmsGetColorSpace(hProfile);
|
||||
}
|
||||
|
||||
PostColorSpace = ColorSpaceOut;
|
||||
}
|
||||
|
||||
*Output = PostColorSpace;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check colorspace
|
||||
static
|
||||
cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
|
||||
{
|
||||
int Space1 = T_COLORSPACE(dwFormat);
|
||||
int Space2 = _cmsLCMScolorSpace(Check);
|
||||
|
||||
if (Space1 == PT_ANY) return TRUE;
|
||||
if (Space1 == Space2) return TRUE;
|
||||
|
||||
if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
|
||||
if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// New to lcms 2.0 -- have all parameters available.
|
||||
cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
|
||||
cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
|
||||
cmsBool BPC[],
|
||||
cmsUInt32Number Intents[],
|
||||
cmsFloat64Number AdaptationStates[],
|
||||
cmsHPROFILE hGamutProfile,
|
||||
cmsUInt32Number nGamutPCSposition,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsUInt32Number OutputFormat,
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
_cmsTRANSFORM* xform;
|
||||
cmsBool FloatTransform;
|
||||
cmsColorSpaceSignature EntryColorSpace;
|
||||
cmsColorSpaceSignature ExitColorSpace;
|
||||
cmsPipeline* Lut;
|
||||
cmsUInt32Number LastIntent = Intents[nProfiles-1];
|
||||
|
||||
// If gamut check is requested, make sure we have a gamut profile
|
||||
if (dwFlags & cmsFLAGS_GAMUTCHECK) {
|
||||
if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
|
||||
}
|
||||
|
||||
// On floating point transforms, inhibit optimizations
|
||||
FloatTransform = (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat));
|
||||
|
||||
if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
|
||||
dwFlags |= cmsFLAGS_NOCACHE;
|
||||
|
||||
// Mark entry/exit spaces
|
||||
if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
|
||||
cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if proper colorspaces
|
||||
if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
|
||||
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
|
||||
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create a pipeline with all transformations
|
||||
Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
|
||||
if (Lut == NULL) {
|
||||
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Optimize the LUT if possible
|
||||
_cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
|
||||
|
||||
|
||||
// All seems ok
|
||||
xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags);
|
||||
if (xform == NULL) {
|
||||
cmsPipelineFree(Lut);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Keep values
|
||||
xform ->EntryColorSpace = EntryColorSpace;
|
||||
xform ->ExitColorSpace = ExitColorSpace;
|
||||
xform ->RenderingIntent = Intents[nProfiles-1];
|
||||
xform ->Lut = Lut;
|
||||
|
||||
// Create a gamut check LUT if requested
|
||||
if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
|
||||
xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
|
||||
BPC, Intents,
|
||||
AdaptationStates,
|
||||
nGamutPCSposition,
|
||||
hGamutProfile);
|
||||
|
||||
|
||||
// Try to read input and output colorant table
|
||||
if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
|
||||
|
||||
// Input table can only come in this way.
|
||||
xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
|
||||
}
|
||||
|
||||
// Output is a little bit more complex.
|
||||
if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
|
||||
|
||||
// This tag may exist only on devicelink profiles.
|
||||
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
|
||||
|
||||
// It may be NULL if error
|
||||
xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
|
||||
|
||||
xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
|
||||
}
|
||||
}
|
||||
|
||||
// Store the sequence of profiles
|
||||
if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
|
||||
xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
|
||||
}
|
||||
else
|
||||
xform ->Sequence = NULL;
|
||||
|
||||
// If this is a cached transform, init first value, which is zero (16 bits only)
|
||||
if (!(dwFlags & cmsFLAGS_NOCACHE)) {
|
||||
|
||||
memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));
|
||||
|
||||
if (xform ->GamutCheck != NULL) {
|
||||
TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
|
||||
}
|
||||
else {
|
||||
|
||||
xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (cmsHTRANSFORM) xform;
|
||||
}
|
||||
|
||||
// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
|
||||
cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
|
||||
cmsHPROFILE hProfiles[],
|
||||
cmsUInt32Number nProfiles,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsUInt32Number OutputFormat,
|
||||
cmsUInt32Number Intent,
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
cmsUInt32Number i;
|
||||
cmsBool BPC[256];
|
||||
cmsUInt32Number Intents[256];
|
||||
cmsFloat64Number AdaptationStates[256];
|
||||
|
||||
if (nProfiles <= 0 || nProfiles > 255) {
|
||||
cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i=0; i < nProfiles; i++) {
|
||||
BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
|
||||
Intents[i] = Intent;
|
||||
AdaptationStates[i] = GlobalAdaptationState;
|
||||
}
|
||||
|
||||
|
||||
return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);
|
||||
}
|
||||
|
||||
|
||||
|
||||
cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
|
||||
cmsUInt32Number nProfiles,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsUInt32Number OutputFormat,
|
||||
cmsUInt32Number Intent,
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
|
||||
if (nProfiles <= 0 || nProfiles > 255) {
|
||||
cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),
|
||||
hProfiles,
|
||||
nProfiles,
|
||||
InputFormat,
|
||||
OutputFormat,
|
||||
Intent,
|
||||
dwFlags);
|
||||
}
|
||||
|
||||
cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
|
||||
cmsHPROFILE Input,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsHPROFILE Output,
|
||||
cmsUInt32Number OutputFormat,
|
||||
cmsUInt32Number Intent,
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
|
||||
cmsHPROFILE hArray[2];
|
||||
|
||||
hArray[0] = Input;
|
||||
hArray[1] = Output;
|
||||
|
||||
return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags);
|
||||
}
|
||||
|
||||
CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsHPROFILE Output,
|
||||
cmsUInt32Number OutputFormat,
|
||||
cmsUInt32Number Intent,
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);
|
||||
}
|
||||
|
||||
|
||||
cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
|
||||
cmsHPROFILE InputProfile,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsHPROFILE OutputProfile,
|
||||
cmsUInt32Number OutputFormat,
|
||||
cmsHPROFILE ProofingProfile,
|
||||
cmsUInt32Number nIntent,
|
||||
cmsUInt32Number ProofingIntent,
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
cmsHPROFILE hArray[4];
|
||||
cmsUInt32Number Intents[4];
|
||||
cmsBool BPC[4];
|
||||
cmsFloat64Number Adaptation[4];
|
||||
cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;
|
||||
|
||||
|
||||
hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile;
|
||||
Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;
|
||||
BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;
|
||||
|
||||
Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState;
|
||||
|
||||
if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
|
||||
return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
|
||||
|
||||
return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
|
||||
ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
|
||||
|
||||
}
|
||||
|
||||
|
||||
cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsHPROFILE OutputProfile,
|
||||
cmsUInt32Number OutputFormat,
|
||||
cmsHPROFILE ProofingProfile,
|
||||
cmsUInt32Number nIntent,
|
||||
cmsUInt32Number ProofingIntent,
|
||||
cmsUInt32Number dwFlags)
|
||||
{
|
||||
return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
|
||||
InputProfile,
|
||||
InputFormat,
|
||||
OutputProfile,
|
||||
OutputFormat,
|
||||
ProofingProfile,
|
||||
nIntent,
|
||||
ProofingIntent,
|
||||
dwFlags);
|
||||
}
|
||||
|
||||
|
||||
// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
|
||||
cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
|
||||
{
|
||||
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
|
||||
|
||||
if (xform == NULL) return NULL;
|
||||
return xform -> ContextID;
|
||||
}
|
||||
|
||||
// Grab the input/output formats
|
||||
cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)
|
||||
{
|
||||
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
|
||||
|
||||
if (xform == NULL) return 0;
|
||||
return xform->InputFormat;
|
||||
}
|
||||
|
||||
cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
|
||||
{
|
||||
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
|
||||
|
||||
if (xform == NULL) return 0;
|
||||
return xform->OutputFormat;
|
||||
}
|
||||
|
||||
// For backwards compatibility
|
||||
cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsUInt32Number OutputFormat)
|
||||
{
|
||||
|
||||
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
|
||||
cmsFormatter16 FromInput, ToOutput;
|
||||
cmsUInt32Number BytesPerPixelInput;
|
||||
|
||||
// We only can afford to change formatters if previous transform is at least 16 bits
|
||||
BytesPerPixelInput = T_BYTES(xform ->InputFormat);
|
||||
if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
|
||||
|
||||
cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
|
||||
ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
|
||||
|
||||
if (FromInput == NULL || ToOutput == NULL) {
|
||||
|
||||
cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xform ->InputFormat = InputFormat;
|
||||
xform ->OutputFormat = OutputFormat;
|
||||
xform ->FromInput = FromInput;
|
||||
xform ->ToOutput = ToOutput;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
LIBRARY LCMS2.DLL
|
||||
|
||||
EXPORTS
|
||||
|
||||
_cms15Fixed16toDouble = _cms15Fixed16toDouble
|
||||
_cms8Fixed8toDouble = _cms8Fixed8toDouble
|
||||
cmsAdaptToIlluminant = cmsAdaptToIlluminant
|
||||
_cmsAdjustEndianess16 = _cmsAdjustEndianess16
|
||||
_cmsAdjustEndianess32 = _cmsAdjustEndianess32
|
||||
_cmsAdjustEndianess64 = _cmsAdjustEndianess64
|
||||
cmsAllocNamedColorList = cmsAllocNamedColorList
|
||||
cmsAllocProfileSequenceDescription = cmsAllocProfileSequenceDescription
|
||||
cmsAppendNamedColor = cmsAppendNamedColor
|
||||
cmsBFDdeltaE = cmsBFDdeltaE
|
||||
cmsBuildGamma = cmsBuildGamma
|
||||
cmsBuildParametricToneCurve = cmsBuildParametricToneCurve
|
||||
cmsBuildSegmentedToneCurve = cmsBuildSegmentedToneCurve
|
||||
cmsBuildTabulatedToneCurve16 = cmsBuildTabulatedToneCurve16
|
||||
cmsBuildTabulatedToneCurveFloat = cmsBuildTabulatedToneCurveFloat
|
||||
_cmsCalloc = _cmsCalloc
|
||||
cmsChannelsOf = cmsChannelsOf
|
||||
cmsCIE2000DeltaE = cmsCIE2000DeltaE
|
||||
cmsCIE94DeltaE = cmsCIE94DeltaE
|
||||
cmsCIECAM02Done = cmsCIECAM02Done
|
||||
cmsCIECAM02Forward = cmsCIECAM02Forward
|
||||
cmsCIECAM02Init = cmsCIECAM02Init
|
||||
cmsCIECAM02Reverse = cmsCIECAM02Reverse
|
||||
cmsCloseIOhandler = cmsCloseIOhandler
|
||||
cmsCloseProfile = cmsCloseProfile
|
||||
cmsCMCdeltaE = cmsCMCdeltaE
|
||||
cmsCreate_sRGBProfile = cmsCreate_sRGBProfile
|
||||
cmsCreate_sRGBProfileTHR = cmsCreate_sRGBProfileTHR
|
||||
cmsCreateBCHSWabstractProfile = cmsCreateBCHSWabstractProfile
|
||||
cmsCreateBCHSWabstractProfileTHR = cmsCreateBCHSWabstractProfileTHR
|
||||
cmsCreateExtendedTransform = cmsCreateExtendedTransform
|
||||
cmsCreateGrayProfile = cmsCreateGrayProfile
|
||||
cmsCreateGrayProfileTHR = cmsCreateGrayProfileTHR
|
||||
cmsCreateInkLimitingDeviceLink = cmsCreateInkLimitingDeviceLink
|
||||
cmsCreateInkLimitingDeviceLinkTHR = cmsCreateInkLimitingDeviceLinkTHR
|
||||
cmsCreateLab2Profile = cmsCreateLab2Profile
|
||||
cmsCreateLab2ProfileTHR = cmsCreateLab2ProfileTHR
|
||||
cmsCreateLab4Profile = cmsCreateLab4Profile
|
||||
cmsCreateLab4ProfileTHR = cmsCreateLab4ProfileTHR
|
||||
cmsCreateLinearizationDeviceLink = cmsCreateLinearizationDeviceLink
|
||||
cmsCreateLinearizationDeviceLinkTHR = cmsCreateLinearizationDeviceLinkTHR
|
||||
cmsCreateMultiprofileTransform = cmsCreateMultiprofileTransform
|
||||
cmsCreateMultiprofileTransformTHR = cmsCreateMultiprofileTransformTHR
|
||||
cmsCreateNULLProfile = cmsCreateNULLProfile
|
||||
cmsCreateNULLProfileTHR = cmsCreateNULLProfileTHR
|
||||
cmsCreateProfilePlaceholder = cmsCreateProfilePlaceholder
|
||||
cmsCreateProofingTransform = cmsCreateProofingTransform
|
||||
cmsCreateProofingTransformTHR = cmsCreateProofingTransformTHR
|
||||
cmsCreateRGBProfile = cmsCreateRGBProfile
|
||||
cmsCreateRGBProfileTHR = cmsCreateRGBProfileTHR
|
||||
cmsCreateTransform = cmsCreateTransform
|
||||
cmsCreateTransformTHR = cmsCreateTransformTHR
|
||||
cmsCreateXYZProfile = cmsCreateXYZProfile
|
||||
cmsCreateXYZProfileTHR = cmsCreateXYZProfileTHR
|
||||
cmsD50_xyY = cmsD50_xyY
|
||||
cmsD50_XYZ = cmsD50_XYZ
|
||||
_cmsDecodeDateTimeNumber = _cmsDecodeDateTimeNumber
|
||||
_cmsDefaultICCintents = _cmsDefaultICCintents
|
||||
cmsDeleteTransform = cmsDeleteTransform
|
||||
cmsDeltaE = cmsDeltaE
|
||||
cmsDetectBlackPoint = cmsDetectBlackPoint
|
||||
cmsDetectTAC = cmsDetectTAC
|
||||
cmsDesaturateLab = cmsDesaturateLab
|
||||
cmsDoTransform = cmsDoTransform
|
||||
_cmsDoubleTo15Fixed16 = _cmsDoubleTo15Fixed16
|
||||
_cmsDoubleTo8Fixed8 = _cmsDoubleTo8Fixed8
|
||||
_cmsDupMem = _cmsDupMem
|
||||
cmsDupNamedColorList = cmsDupNamedColorList
|
||||
cmsDupProfileSequenceDescription = cmsDupProfileSequenceDescription
|
||||
cmsDupToneCurve = cmsDupToneCurve
|
||||
_cmsEncodeDateTimeNumber = _cmsEncodeDateTimeNumber
|
||||
cmsEstimateGamma = cmsEstimateGamma
|
||||
cmsEvalToneCurve16 = cmsEvalToneCurve16
|
||||
cmsEvalToneCurveFloat = cmsEvalToneCurveFloat
|
||||
cmsfilelength = cmsfilelength
|
||||
cmsFloat2LabEncoded = cmsFloat2LabEncoded
|
||||
cmsFloat2LabEncodedV2 = cmsFloat2LabEncodedV2
|
||||
cmsFloat2XYZEncoded = cmsFloat2XYZEncoded
|
||||
cmsFormatterForColorspaceOfProfile = cmsFormatterForColorspaceOfProfile
|
||||
cmsFormatterForPCSOfProfile = cmsFormatterForPCSOfProfile
|
||||
_cmsFree = _cmsFree
|
||||
cmsFreeNamedColorList = cmsFreeNamedColorList
|
||||
cmsFreeProfileSequenceDescription = cmsFreeProfileSequenceDescription
|
||||
cmsFreeToneCurve = cmsFreeToneCurve
|
||||
cmsFreeToneCurveTriple = cmsFreeToneCurveTriple
|
||||
cmsGBDAlloc = cmsGBDAlloc
|
||||
cmsGBDFree = cmsGBDFree
|
||||
cmsGDBAddPoint = cmsGDBAddPoint
|
||||
cmsGDBCheckPoint = cmsGDBCheckPoint
|
||||
cmsGDBCompute = cmsGDBCompute
|
||||
cmsGetAlarmCodes = cmsGetAlarmCodes
|
||||
cmsGetColorSpace = cmsGetColorSpace
|
||||
cmsGetDeviceClass = cmsGetDeviceClass
|
||||
cmsGetEncodedICCversion = cmsGetEncodedICCversion
|
||||
cmsGetHeaderAttributes = cmsGetHeaderAttributes
|
||||
cmsGetHeaderCreationDateTime = cmsGetHeaderCreationDateTime
|
||||
cmsGetHeaderFlags = cmsGetHeaderFlags
|
||||
cmsGetHeaderManufacturer = cmsGetHeaderManufacturer
|
||||
cmsGetHeaderModel = cmsGetHeaderModel
|
||||
cmsGetHeaderProfileID = cmsGetHeaderProfileID
|
||||
cmsGetHeaderRenderingIntent = cmsGetHeaderRenderingIntent
|
||||
cmsGetNamedColorList = cmsGetNamedColorList
|
||||
cmsGetPCS = cmsGetPCS
|
||||
cmsGetPostScriptColorResource = cmsGetPostScriptColorResource
|
||||
cmsGetPostScriptCRD = cmsGetPostScriptCRD
|
||||
cmsGetPostScriptCSA = cmsGetPostScriptCSA
|
||||
cmsGetProfileInfo = cmsGetProfileInfo
|
||||
cmsGetProfileInfoASCII = cmsGetProfileInfoASCII
|
||||
cmsGetProfileContextID = cmsGetProfileContextID
|
||||
cmsGetProfileVersion = cmsGetProfileVersion
|
||||
cmsGetSupportedIntents = cmsGetSupportedIntents
|
||||
cmsGetTagCount = cmsGetTagCount
|
||||
cmsGetTagSignature = cmsGetTagSignature
|
||||
cmsGetTransformContextID = cmsGetTransformContextID
|
||||
_cmsICCcolorSpace = _cmsICCcolorSpace
|
||||
_cmsIOPrintf = _cmsIOPrintf
|
||||
cmsIsCLUT = cmsIsCLUT
|
||||
cmsIsIntentSupported = cmsIsIntentSupported
|
||||
cmsIsMatrixShaper = cmsIsMatrixShaper
|
||||
cmsIsTag = cmsIsTag
|
||||
cmsIsToneCurveDescending = cmsIsToneCurveDescending
|
||||
cmsIsToneCurveLinear = cmsIsToneCurveLinear
|
||||
cmsIsToneCurveMonotonic = cmsIsToneCurveMonotonic
|
||||
cmsIsToneCurveMultisegment = cmsIsToneCurveMultisegment
|
||||
cmsGetToneCurveParametricType = cmsGetToneCurveParametricType
|
||||
cmsIT8Alloc = cmsIT8Alloc
|
||||
cmsIT8DefineDblFormat = cmsIT8DefineDblFormat
|
||||
cmsIT8EnumDataFormat = cmsIT8EnumDataFormat
|
||||
cmsIT8EnumProperties = cmsIT8EnumProperties
|
||||
cmsIT8Free = cmsIT8Free
|
||||
cmsIT8GetData = cmsIT8GetData
|
||||
cmsIT8GetDataDbl = cmsIT8GetDataDbl
|
||||
cmsIT8FindDataFormat = cmsIT8FindDataFormat
|
||||
cmsIT8GetDataRowCol = cmsIT8GetDataRowCol
|
||||
cmsIT8GetDataRowColDbl = cmsIT8GetDataRowColDbl
|
||||
cmsIT8GetPatchName = cmsIT8GetPatchName
|
||||
cmsIT8GetProperty = cmsIT8GetProperty
|
||||
cmsIT8GetPropertyDbl = cmsIT8GetPropertyDbl
|
||||
cmsIT8GetSheetType = cmsIT8GetSheetType
|
||||
cmsIT8LoadFromFile = cmsIT8LoadFromFile
|
||||
cmsIT8LoadFromMem = cmsIT8LoadFromMem
|
||||
cmsIT8SaveToFile = cmsIT8SaveToFile
|
||||
cmsIT8SaveToMem = cmsIT8SaveToMem
|
||||
cmsIT8SetComment = cmsIT8SetComment
|
||||
cmsIT8SetData = cmsIT8SetData
|
||||
cmsIT8SetDataDbl = cmsIT8SetDataDbl
|
||||
cmsIT8SetDataFormat = cmsIT8SetDataFormat
|
||||
cmsIT8SetDataRowCol = cmsIT8SetDataRowCol
|
||||
cmsIT8SetDataRowColDbl = cmsIT8SetDataRowColDbl
|
||||
cmsIT8SetPropertyDbl = cmsIT8SetPropertyDbl
|
||||
cmsIT8SetPropertyHex = cmsIT8SetPropertyHex
|
||||
cmsIT8SetPropertyStr = cmsIT8SetPropertyStr
|
||||
cmsIT8SetPropertyUncooked = cmsIT8SetPropertyUncooked
|
||||
cmsIT8SetSheetType = cmsIT8SetSheetType
|
||||
cmsIT8SetTable = cmsIT8SetTable
|
||||
cmsIT8SetTableByLabel = cmsIT8SetTableByLabel
|
||||
cmsIT8TableCount = cmsIT8TableCount
|
||||
cmsJoinToneCurve = cmsJoinToneCurve
|
||||
cmsLab2LCh = cmsLab2LCh
|
||||
cmsLab2XYZ = cmsLab2XYZ
|
||||
cmsLabEncoded2Float = cmsLabEncoded2Float
|
||||
cmsLabEncoded2FloatV2 = cmsLabEncoded2FloatV2
|
||||
cmsLCh2Lab = cmsLCh2Lab
|
||||
_cmsLCMScolorSpace = _cmsLCMScolorSpace
|
||||
cmsLinkTag = cmsLinkTag
|
||||
cmsPipelineAlloc = cmsPipelineAlloc
|
||||
cmsPipelineCat = cmsPipelineCat
|
||||
cmsPipelineCheckAndRetreiveStages = cmsPipelineCheckAndRetreiveStages
|
||||
cmsPipelineDup = cmsPipelineDup
|
||||
cmsPipelineStageCount = cmsPipelineStageCount
|
||||
cmsPipelineEval16 = cmsPipelineEval16
|
||||
cmsPipelineEvalFloat = cmsPipelineEvalFloat
|
||||
cmsPipelineEvalReverseFloat = cmsPipelineEvalReverseFloat
|
||||
cmsPipelineFree = cmsPipelineFree
|
||||
cmsPipelineGetPtrToFirstStage = cmsPipelineGetPtrToFirstStage
|
||||
cmsPipelineGetPtrToLastStage = cmsPipelineGetPtrToLastStage
|
||||
cmsPipelineInputChannels = cmsPipelineInputChannels
|
||||
cmsPipelineInsertStage = cmsPipelineInsertStage
|
||||
cmsPipelineOutputChannels = cmsPipelineOutputChannels
|
||||
cmsPipelineSetSaveAs8bitsFlag = cmsPipelineSetSaveAs8bitsFlag
|
||||
_cmsPipelineSetOptimizationParameters = _cmsPipelineSetOptimizationParameters
|
||||
cmsPipelineUnlinkStage = cmsPipelineUnlinkStage
|
||||
_cmsMalloc = _cmsMalloc
|
||||
_cmsMallocZero = _cmsMallocZero
|
||||
_cmsMAT3eval = _cmsMAT3eval
|
||||
_cmsMAT3identity = _cmsMAT3identity
|
||||
_cmsMAT3inverse = _cmsMAT3inverse
|
||||
_cmsMAT3isIdentity = _cmsMAT3isIdentity
|
||||
_cmsMAT3per = _cmsMAT3per
|
||||
_cmsMAT3solve = _cmsMAT3solve
|
||||
cmsMD5computeID = cmsMD5computeID
|
||||
cmsMLUalloc = cmsMLUalloc
|
||||
cmsMLUdup = cmsMLUdup
|
||||
cmsMLUfree = cmsMLUfree
|
||||
cmsMLUgetASCII = cmsMLUgetASCII
|
||||
cmsMLUgetTranslation = cmsMLUgetTranslation
|
||||
cmsMLUgetWide = cmsMLUgetWide
|
||||
cmsMLUsetASCII = cmsMLUsetASCII
|
||||
cmsMLUsetWide = cmsMLUsetWide
|
||||
cmsStageAllocCLut16bit = cmsStageAllocCLut16bit
|
||||
cmsStageAllocCLut16bitGranular = cmsStageAllocCLut16bitGranular
|
||||
cmsStageAllocCLutFloat = cmsStageAllocCLutFloat
|
||||
cmsStageAllocCLutFloatGranular = cmsStageAllocCLutFloatGranular
|
||||
cmsStageAllocToneCurves = cmsStageAllocToneCurves
|
||||
cmsStageAllocIdentity = cmsStageAllocIdentity
|
||||
cmsStageAllocMatrix = cmsStageAllocMatrix
|
||||
_cmsStageAllocPlaceholder = _cmsStageAllocPlaceholder
|
||||
cmsStageDup = cmsStageDup
|
||||
cmsStageFree = cmsStageFree
|
||||
cmsStageNext = cmsStageNext
|
||||
cmsStageInputChannels = cmsStageInputChannels
|
||||
cmsStageOutputChannels = cmsStageOutputChannels
|
||||
cmsStageSampleCLut16bit = cmsStageSampleCLut16bit
|
||||
cmsStageSampleCLutFloat = cmsStageSampleCLutFloat
|
||||
cmsStageType = cmsStageType
|
||||
cmsStageData = cmsStageData
|
||||
cmsNamedColorCount = cmsNamedColorCount
|
||||
cmsNamedColorIndex = cmsNamedColorIndex
|
||||
cmsNamedColorInfo = cmsNamedColorInfo
|
||||
cmsOpenIOhandlerFromFile = cmsOpenIOhandlerFromFile
|
||||
cmsOpenIOhandlerFromMem = cmsOpenIOhandlerFromMem
|
||||
cmsOpenIOhandlerFromNULL = cmsOpenIOhandlerFromNULL
|
||||
cmsOpenIOhandlerFromStream = cmsOpenIOhandlerFromStream
|
||||
cmsOpenProfileFromFile = cmsOpenProfileFromFile
|
||||
cmsOpenProfileFromFileTHR = cmsOpenProfileFromFileTHR
|
||||
cmsOpenProfileFromIOhandlerTHR = cmsOpenProfileFromIOhandlerTHR
|
||||
cmsOpenProfileFromMem = cmsOpenProfileFromMem
|
||||
cmsOpenProfileFromMemTHR = cmsOpenProfileFromMemTHR
|
||||
cmsOpenProfileFromStream = cmsOpenProfileFromStream
|
||||
cmsOpenProfileFromStreamTHR = cmsOpenProfileFromStreamTHR
|
||||
cmsPlugin = cmsPlugin
|
||||
_cmsRead15Fixed16Number = _cmsRead15Fixed16Number
|
||||
_cmsReadAlignment = _cmsReadAlignment
|
||||
_cmsReadFloat32Number = _cmsReadFloat32Number
|
||||
cmsReadRawTag = cmsReadRawTag
|
||||
cmsReadTag = cmsReadTag
|
||||
_cmsReadTypeBase = _cmsReadTypeBase
|
||||
_cmsReadUInt16Array = _cmsReadUInt16Array
|
||||
_cmsReadUInt16Number = _cmsReadUInt16Number
|
||||
_cmsReadUInt32Number = _cmsReadUInt32Number
|
||||
_cmsReadUInt64Number = _cmsReadUInt64Number
|
||||
_cmsReadUInt8Number = _cmsReadUInt8Number
|
||||
_cmsReadXYZNumber = _cmsReadXYZNumber
|
||||
_cmsRealloc = _cmsRealloc
|
||||
cmsReverseToneCurve = cmsReverseToneCurve
|
||||
cmsReverseToneCurveEx = cmsReverseToneCurveEx
|
||||
cmsSaveProfileToFile = cmsSaveProfileToFile
|
||||
cmsSaveProfileToIOhandler = cmsSaveProfileToIOhandler
|
||||
cmsSaveProfileToMem = cmsSaveProfileToMem
|
||||
cmsSaveProfileToStream = cmsSaveProfileToStream
|
||||
cmsSetAdaptationState = cmsSetAdaptationState
|
||||
cmsSetAlarmCodes = cmsSetAlarmCodes
|
||||
cmsSetColorSpace = cmsSetColorSpace
|
||||
cmsSetDeviceClass = cmsSetDeviceClass
|
||||
cmsSetEncodedICCversion = cmsSetEncodedICCversion
|
||||
cmsSetHeaderAttributes = cmsSetHeaderAttributes
|
||||
cmsSetHeaderFlags = cmsSetHeaderFlags
|
||||
cmsSetHeaderManufacturer = cmsSetHeaderManufacturer
|
||||
cmsSetHeaderModel = cmsSetHeaderModel
|
||||
cmsSetHeaderProfileID = cmsSetHeaderProfileID
|
||||
cmsSetHeaderRenderingIntent = cmsSetHeaderRenderingIntent
|
||||
cmsSetLogErrorHandler = cmsSetLogErrorHandler
|
||||
cmsSetPCS = cmsSetPCS
|
||||
cmsSetProfileVersion = cmsSetProfileVersion
|
||||
cmsSignalError = cmsSignalError
|
||||
cmsSmoothToneCurve = cmsSmoothToneCurve
|
||||
cmsstrcasecmp = cmsstrcasecmp
|
||||
cmsTempFromWhitePoint = cmsTempFromWhitePoint
|
||||
cmsTransform2DeviceLink = cmsTransform2DeviceLink
|
||||
cmsUnregisterPlugins = cmsUnregisterPlugins
|
||||
_cmsVEC3cross = _cmsVEC3cross
|
||||
_cmsVEC3distance = _cmsVEC3distance
|
||||
_cmsVEC3dot = _cmsVEC3dot
|
||||
_cmsVEC3init = _cmsVEC3init
|
||||
_cmsVEC3length = _cmsVEC3length
|
||||
_cmsVEC3minus = _cmsVEC3minus
|
||||
cmsWhitePointFromTemp = cmsWhitePointFromTemp
|
||||
_cmsWrite15Fixed16Number = _cmsWrite15Fixed16Number
|
||||
_cmsWriteAlignment = _cmsWriteAlignment
|
||||
_cmsWriteFloat32Number = _cmsWriteFloat32Number
|
||||
cmsWriteRawTag = cmsWriteRawTag
|
||||
cmsWriteTag = cmsWriteTag
|
||||
_cmsWriteTypeBase = _cmsWriteTypeBase
|
||||
_cmsWriteUInt16Array = _cmsWriteUInt16Array
|
||||
_cmsWriteUInt16Number = _cmsWriteUInt16Number
|
||||
_cmsWriteUInt32Number = _cmsWriteUInt32Number
|
||||
_cmsWriteUInt64Number = _cmsWriteUInt64Number
|
||||
_cmsWriteUInt8Number = _cmsWriteUInt8Number
|
||||
_cmsWriteXYZNumber = _cmsWriteXYZNumber
|
||||
cmsxyY2XYZ = cmsxyY2XYZ
|
||||
cmsXYZ2Lab = cmsXYZ2Lab
|
||||
cmsXYZ2xyY = cmsXYZ2xyY
|
||||
cmsXYZEncoded2Float = cmsXYZEncoded2Float
|
||||
cmsSliceSpace16 = cmsSliceSpace16
|
||||
cmsSliceSpaceFloat = cmsSliceSpaceFloat
|
||||
cmsChangeBuffersFormat = cmsChangeBuffersFormat
|
||||
@@ -0,0 +1,628 @@
|
||||
|
||||
//
|
||||
// Little Color Management System
|
||||
// Copyright (c) 1998-2011 Marti Maria Saguer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#ifndef _lcms_internal_H
|
||||
|
||||
// Include plug-in foundation
|
||||
#ifndef _lcms_plugin_H
|
||||
# include "lcms2_plugin.h"
|
||||
#endif
|
||||
|
||||
// ctype is part of C99 as per 7.1.2
|
||||
#include <ctype.h>
|
||||
|
||||
// assert macro is part of C99 as per 7.2
|
||||
#include <assert.h>
|
||||
|
||||
// Some needed constants
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#ifndef M_LOG10E
|
||||
# define M_LOG10E 0.434294481903251827651
|
||||
#endif
|
||||
|
||||
// BorlandC 5.5, VC2003 are broken on that
|
||||
#if defined(__BORLANDC__) || (_MSC_VER <= 1400) // 1400 == VC++ 8.0
|
||||
#define sinf(x) (float)sin((float)x)
|
||||
#define sqrtf(x) (float)sqrt((float)x)
|
||||
#endif
|
||||
|
||||
|
||||
// Alignment of ICC file format uses 4 bytes (cmsUInt32Number)
|
||||
#define _cmsSIZEOFLONGMINUS1 (sizeof(cmsUInt32Number)-1)
|
||||
#define _cmsALIGNLONG(x) (((x)+_cmsSIZEOFLONGMINUS1) & ~(_cmsSIZEOFLONGMINUS1))
|
||||
|
||||
// Maximum encodeable values in floating point
|
||||
#define MAX_ENCODEABLE_XYZ (1.0 + 32767.0/32768.0)
|
||||
#define MIN_ENCODEABLE_ab2 (-128.0)
|
||||
#define MAX_ENCODEABLE_ab2 ((65535.0/256.0) - 128.0)
|
||||
#define MIN_ENCODEABLE_ab4 (-128.0)
|
||||
#define MAX_ENCODEABLE_ab4 (127.0)
|
||||
|
||||
// Maximum of channels for internal pipeline evaluation
|
||||
#define MAX_STAGE_CHANNELS 128
|
||||
|
||||
// Unused parameter warning supression
|
||||
#define cmsUNUSED_PARAMETER(x) ((void)x)
|
||||
|
||||
// The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999).
|
||||
// unfortunately VisualC++ does not conform that
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
# define cmsINLINE __inline
|
||||
#else
|
||||
# define cmsINLINE static inline
|
||||
#endif
|
||||
|
||||
// Other replacement functions
|
||||
#ifdef _MSC_VER
|
||||
# ifndef snprintf
|
||||
# define snprintf _snprintf
|
||||
# endif
|
||||
# ifndef vsnprintf
|
||||
# define vsnprintf _vsnprintf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// A fast way to convert from/to 16 <-> 8 bits
|
||||
#define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb))
|
||||
#define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((rgb) * 65281 + 8388608) >> 24) & 0xFF)
|
||||
|
||||
// Code analysis is broken on asserts
|
||||
#ifdef _MSC_VER
|
||||
# if (_MSC_VER >= 1500)
|
||||
# define _cmsAssert(a) { assert((a)); __analysis_assume((a)); }
|
||||
# else
|
||||
# define _cmsAssert(a) assert((a))
|
||||
# endif
|
||||
#else
|
||||
# define _cmsAssert(a) assert((a))
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
// Determinant lower than that are assumed zero (used on matrix invert)
|
||||
#define MATRIX_DET_TOLERANCE 0.0001
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
// Fixed point
|
||||
#define FIXED_TO_INT(x) ((x)>>16)
|
||||
#define FIXED_REST_TO_INT(x) ((x)&0xFFFFU)
|
||||
#define ROUND_FIXED_TO_INT(x) (((x)+0x8000)>>16)
|
||||
|
||||
cmsINLINE cmsS15Fixed16Number _cmsToFixedDomain(int a) { return a + ((a + 0x7fff) / 0xffff); }
|
||||
cmsINLINE int _cmsFromFixedDomain(cmsS15Fixed16Number a) { return a - ((a + 0x7fff) >> 16); }
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon
|
||||
// note than this only works in the range ..-32767...+32767 because
|
||||
// mantissa is interpreted as 15.16 fixed point.
|
||||
// The union is to avoid pointer aliasing overoptimization.
|
||||
cmsINLINE int _cmsQuickFloor(cmsFloat64Number val)
|
||||
{
|
||||
#ifdef CMS_DONT_USE_FAST_FLOOR
|
||||
return (int) floor(val);
|
||||
#else
|
||||
const cmsFloat64Number _lcms_double2fixmagic = 68719476736.0 * 1.5; // 2^36 * 1.5, (52-16=36) uses limited precision to floor
|
||||
union {
|
||||
cmsFloat64Number val;
|
||||
int halves[2];
|
||||
} temp;
|
||||
|
||||
temp.val = val + _lcms_double2fixmagic;
|
||||
|
||||
#ifdef CMS_USE_BIG_ENDIAN
|
||||
return temp.halves[1] >> 16;
|
||||
#else
|
||||
return temp.halves[0] >> 16;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// Fast floor restricted to 0..65535.0
|
||||
cmsINLINE cmsUInt16Number _cmsQuickFloorWord(cmsFloat64Number d)
|
||||
{
|
||||
return (cmsUInt16Number) _cmsQuickFloor(d - 32767.0) + 32767U;
|
||||
}
|
||||
|
||||
// Floor to word, taking care of saturation
|
||||
cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d)
|
||||
{
|
||||
d += 0.5;
|
||||
if (d <= 0) return 0;
|
||||
if (d >= 65535.0) return 0xffff;
|
||||
|
||||
return _cmsQuickFloorWord(d);
|
||||
}
|
||||
|
||||
// Plug-In registering ---------------------------------------------------------------
|
||||
|
||||
// Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once.
|
||||
void* _cmsPluginMalloc(cmsUInt32Number size);
|
||||
|
||||
// Memory management
|
||||
cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// Interpolation
|
||||
cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// Parametric curves
|
||||
cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// Formatters management
|
||||
cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// Tag type management
|
||||
cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// Tag management
|
||||
cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// Intent management
|
||||
cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// Multi Process elements
|
||||
cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
// Optimization
|
||||
cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin);
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Suballocators. Those are blocks of memory that is freed at the end on whole block.
|
||||
typedef struct _cmsSubAllocator_chunk_st {
|
||||
|
||||
cmsUInt8Number* Block;
|
||||
cmsUInt32Number BlockSize;
|
||||
cmsUInt32Number Used;
|
||||
|
||||
struct _cmsSubAllocator_chunk_st* next;
|
||||
|
||||
} _cmsSubAllocator_chunk;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
cmsContext ContextID;
|
||||
_cmsSubAllocator_chunk* h;
|
||||
|
||||
} _cmsSubAllocator;
|
||||
|
||||
|
||||
_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial);
|
||||
void _cmsSubAllocDestroy(_cmsSubAllocator* s);
|
||||
void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size);
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
// MLU internal representation
|
||||
typedef struct {
|
||||
|
||||
cmsUInt16Number Language;
|
||||
cmsUInt16Number Country;
|
||||
|
||||
cmsUInt32Number StrW; // Offset to current unicode string
|
||||
cmsUInt32Number Len; // Lenght in bytes
|
||||
|
||||
} _cmsMLUentry;
|
||||
|
||||
struct _cms_MLU_struct {
|
||||
|
||||
cmsContext ContextID;
|
||||
|
||||
// The directory
|
||||
int AllocatedEntries;
|
||||
int UsedEntries;
|
||||
_cmsMLUentry* Entries; // Array of pointers to strings allocated in MemPool
|
||||
|
||||
// The Pool
|
||||
cmsUInt32Number PoolSize; // The maximum allocated size
|
||||
cmsUInt32Number PoolUsed; // The used size
|
||||
void* MemPool; // Pointer to begin of memory pool
|
||||
};
|
||||
|
||||
// Named color list internal representation
|
||||
typedef struct {
|
||||
|
||||
char Name[cmsMAX_PATH];
|
||||
cmsUInt16Number PCS[3];
|
||||
cmsUInt16Number DeviceColorant[cmsMAXCHANNELS];
|
||||
|
||||
} _cmsNAMEDCOLOR;
|
||||
|
||||
struct _cms_NAMEDCOLORLIST_struct {
|
||||
|
||||
cmsUInt32Number nColors;
|
||||
cmsUInt32Number Allocated;
|
||||
cmsUInt32Number ColorantCount;
|
||||
|
||||
char Prefix[33]; // Prefix and suffix are defined to be 32 characters at most
|
||||
char Suffix[33];
|
||||
|
||||
_cmsNAMEDCOLOR* List;
|
||||
|
||||
cmsContext ContextID;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
// This is the internal struct holding profile details.
|
||||
|
||||
// Maximum supported tags in a profile
|
||||
#define MAX_TABLE_TAG 100
|
||||
|
||||
typedef struct _cms_iccprofile_struct {
|
||||
|
||||
// I/O handler
|
||||
cmsIOHANDLER* IOhandler;
|
||||
|
||||
// The thread ID
|
||||
cmsContext ContextID;
|
||||
|
||||
// Creation time
|
||||
struct tm Created;
|
||||
|
||||
// Only most important items found in ICC profiles
|
||||
cmsUInt32Number Version;
|
||||
cmsProfileClassSignature DeviceClass;
|
||||
cmsColorSpaceSignature ColorSpace;
|
||||
cmsColorSpaceSignature PCS;
|
||||
cmsUInt32Number RenderingIntent;
|
||||
cmsUInt32Number flags;
|
||||
cmsUInt32Number manufacturer, model;
|
||||
cmsUInt64Number attributes;
|
||||
|
||||
cmsProfileID ProfileID;
|
||||
|
||||
// Dictionary
|
||||
cmsUInt32Number TagCount;
|
||||
cmsTagSignature TagNames[MAX_TABLE_TAG];
|
||||
cmsTagSignature TagLinked[MAX_TABLE_TAG]; // The tag to wich is linked (0=none)
|
||||
cmsUInt32Number TagSizes[MAX_TABLE_TAG]; // Size on disk
|
||||
cmsUInt32Number TagOffsets[MAX_TABLE_TAG];
|
||||
cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked
|
||||
void * TagPtrs[MAX_TABLE_TAG];
|
||||
cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types
|
||||
// depending on profile version, so we keep track of the // type handler for each tag in the list.
|
||||
// Special
|
||||
cmsBool IsWrite;
|
||||
|
||||
} _cmsICCPROFILE;
|
||||
|
||||
// IO helpers for profiles
|
||||
cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc);
|
||||
cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace);
|
||||
int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks);
|
||||
|
||||
// Tag types
|
||||
cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig);
|
||||
cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig);
|
||||
cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig);
|
||||
|
||||
// Error logging ---------------------------------------------------------------------------------------------------------
|
||||
|
||||
void _cmsTagSignature2String(char String[5], cmsTagSignature sig);
|
||||
|
||||
// Interpolation ---------------------------------------------------------------------------------------------------------
|
||||
|
||||
cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
|
||||
cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
|
||||
void _cmsFreeInterpParams(cmsInterpParams* p);
|
||||
cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p);
|
||||
|
||||
// Curves ----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// This struct holds information about a segment, plus a pointer to the function that implements the evaluation.
|
||||
// In the case of table-based, Eval pointer is set to NULL
|
||||
|
||||
// The gamma function main structure
|
||||
struct _cms_curve_struct {
|
||||
|
||||
cmsInterpParams* InterpParams; // Private optimizations for interpolation
|
||||
|
||||
cmsUInt32Number nSegments; // Number of segments in the curve. Zero for a 16-bit based tables
|
||||
cmsCurveSegment* Segments; // The segments
|
||||
cmsInterpParams** SegInterp; // Array of private optimizations for interpolation in table-based segments
|
||||
|
||||
cmsParametricCurveEvaluator* Evals; // Evaluators (one per segment)
|
||||
|
||||
// 16 bit Table-based representation follows
|
||||
cmsUInt32Number nEntries; // Number of table elements
|
||||
cmsUInt16Number* Table16; // The table itself.
|
||||
};
|
||||
|
||||
|
||||
// Pipelines & Stages ---------------------------------------------------------------------------------------------
|
||||
|
||||
// A single stage
|
||||
struct _cmsStage_struct {
|
||||
|
||||
cmsContext ContextID;
|
||||
|
||||
cmsStageSignature Type; // Identifies the stage
|
||||
cmsStageSignature Implements; // Identifies the *function* of the stage (for optimizations)
|
||||
|
||||
cmsUInt32Number InputChannels; // Input channels -- for optimization purposes
|
||||
cmsUInt32Number OutputChannels; // Output channels -- for optimization purposes
|
||||
|
||||
_cmsStageEvalFn EvalPtr; // Points to fn that evaluates the stage (always in floating point)
|
||||
_cmsStageDupElemFn DupElemPtr; // Points to a fn that duplicates the *data* of the stage
|
||||
_cmsStageFreeElemFn FreePtr; // Points to a fn that sets the *data* of the stage free
|
||||
|
||||
// A generic pointer to whatever memory needed by the stage
|
||||
void* Data;
|
||||
|
||||
// Maintains linked list (used internally)
|
||||
struct _cmsStage_struct* Next;
|
||||
};
|
||||
|
||||
// Data kept in "Element" member of cmsStage
|
||||
|
||||
// Curves
|
||||
typedef struct {
|
||||
cmsUInt32Number nCurves;
|
||||
cmsToneCurve** TheCurves;
|
||||
|
||||
} _cmsStageToneCurvesData;
|
||||
|
||||
// Matrix
|
||||
typedef struct {
|
||||
cmsFloat64Number* Double; // floating point for the matrix
|
||||
cmsFloat64Number* Offset; // The offset
|
||||
|
||||
} _cmsStageMatrixData;
|
||||
|
||||
// CLUT
|
||||
typedef struct {
|
||||
|
||||
union { // Can have only one of both representations at same time
|
||||
cmsUInt16Number* T; // Points to the table 16 bits table
|
||||
cmsFloat32Number* TFloat; // Points to the cmsFloat32Number table
|
||||
|
||||
} Tab;
|
||||
|
||||
cmsInterpParams* Params;
|
||||
cmsUInt32Number nEntries;
|
||||
cmsBool HasFloatValues;
|
||||
|
||||
} _cmsStageCLutData;
|
||||
|
||||
|
||||
// Special Stages (cannot be saved)
|
||||
cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID);
|
||||
cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID);
|
||||
cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID);
|
||||
cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID);
|
||||
cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID);
|
||||
cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID);
|
||||
cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS);
|
||||
cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels);
|
||||
cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan);
|
||||
|
||||
// For curve set only
|
||||
cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe);
|
||||
|
||||
|
||||
// Pipeline Evaluator (in floating point)
|
||||
typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[],
|
||||
cmsFloat32Number Out[],
|
||||
const void* Data);
|
||||
|
||||
struct _cmsPipeline_struct {
|
||||
|
||||
cmsStage* Elements; // Points to elements chain
|
||||
cmsUInt32Number InputChannels, OutputChannels;
|
||||
|
||||
// Data & evaluators
|
||||
void *Data;
|
||||
|
||||
_cmsOPTeval16Fn Eval16Fn;
|
||||
_cmsPipelineEvalFloatFn EvalFloatFn;
|
||||
_cmsOPTfreeDataFn FreeDataFn;
|
||||
_cmsOPTdupDataFn DupDataFn;
|
||||
|
||||
cmsContext ContextID; // Environment
|
||||
|
||||
cmsBool SaveAs8Bits; // Implementation-specific: save as 8 bits if possible
|
||||
};
|
||||
|
||||
// LUT reading & creation -------------------------------------------------------------------------------------------
|
||||
|
||||
// Read tags using low-level function, provide necessary glue code to adapt versions, etc. All those return a brand new copy
|
||||
// of the LUTS, since ownership of original is up to the profile. The user should free allocated resources.
|
||||
|
||||
cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent);
|
||||
cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent);
|
||||
cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent);
|
||||
|
||||
// Special values
|
||||
cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile);
|
||||
cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile);
|
||||
|
||||
// Profile linker --------------------------------------------------------------------------------------------------
|
||||
|
||||
cmsPipeline* _cmsLinkProfiles(cmsContext ContextID,
|
||||
cmsUInt32Number nProfiles,
|
||||
cmsUInt32Number TheIntents[],
|
||||
cmsHPROFILE hProfiles[],
|
||||
cmsBool BPC[],
|
||||
cmsFloat64Number AdaptationStates[],
|
||||
cmsUInt32Number dwFlags);
|
||||
|
||||
// Sequence --------------------------------------------------------------------------------------------------------
|
||||
|
||||
cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile);
|
||||
cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq);
|
||||
cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]);
|
||||
|
||||
|
||||
// LUT optimization ------------------------------------------------------------------------------------------------
|
||||
|
||||
cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples);
|
||||
int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags);
|
||||
|
||||
cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
|
||||
cmsUInt16Number **White,
|
||||
cmsUInt16Number **Black,
|
||||
cmsUInt32Number *nOutputs);
|
||||
|
||||
cmsBool _cmsOptimizePipeline(cmsPipeline** Lut,
|
||||
int Intent,
|
||||
cmsUInt32Number* InputFormat,
|
||||
cmsUInt32Number* OutputFormat,
|
||||
cmsUInt32Number* dwFlags );
|
||||
|
||||
|
||||
// Hi level LUT building ----------------------------------------------------------------------------------------------
|
||||
|
||||
cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
|
||||
cmsHPROFILE hProfiles[],
|
||||
cmsBool BPC[],
|
||||
cmsUInt32Number Intents[],
|
||||
cmsFloat64Number AdaptationStates[],
|
||||
cmsUInt32Number nGamutPCSposition,
|
||||
cmsHPROFILE hGamut);
|
||||
|
||||
|
||||
// Formatters ------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#define cmsFLAGS_CAN_CHANGE_FORMATTER 0x02000000 // Allow change buffer format
|
||||
|
||||
cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type);
|
||||
cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type);
|
||||
|
||||
cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
|
||||
cmsFormatterDirection Dir,
|
||||
cmsUInt32Number dwFlags);
|
||||
|
||||
|
||||
// Transform logic ------------------------------------------------------------------------------------------------------
|
||||
|
||||
struct _cmstransform_struct;
|
||||
|
||||
typedef struct {
|
||||
|
||||
// 1-pixel cache (16 bits only)
|
||||
cmsUInt16Number CacheIn[cmsMAXCHANNELS];
|
||||
cmsUInt16Number CacheOut[cmsMAXCHANNELS];
|
||||
|
||||
} _cmsCACHE;
|
||||
|
||||
|
||||
// Full xform
|
||||
typedef void (* _cmsTransformFn)(struct _cmstransform_struct *Transform,
|
||||
const void* InputBuffer,
|
||||
void* OutputBuffer,
|
||||
cmsUInt32Number Size);
|
||||
|
||||
typedef struct {
|
||||
|
||||
cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference
|
||||
cmsUInt32Number StrideIn, StrideOut; // Planar support
|
||||
|
||||
} cmsFormatterInfo;
|
||||
|
||||
// Transformation
|
||||
typedef struct _cmstransform_struct {
|
||||
|
||||
cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference
|
||||
|
||||
// Points to transform code
|
||||
_cmsTransformFn xform;
|
||||
|
||||
// Formatters, cannot be embedded into LUT because cache
|
||||
cmsFormatter16 FromInput;
|
||||
cmsFormatter16 ToOutput;
|
||||
|
||||
cmsFormatterFloat FromInputFloat;
|
||||
cmsFormatterFloat ToOutputFloat;
|
||||
|
||||
// 1-pixel cache seed for zero as input (16 bits, read only)
|
||||
_cmsCACHE Cache;
|
||||
|
||||
// A MPE LUT holding the full (optimized) transform
|
||||
cmsPipeline* Lut;
|
||||
|
||||
// A MPE LUT holding the gamut check. It goes from the input space to bilevel
|
||||
cmsPipeline* GamutCheck;
|
||||
|
||||
// Colorant tables
|
||||
cmsNAMEDCOLORLIST* InputColorant; // Input Colorant table
|
||||
cmsNAMEDCOLORLIST* OutputColorant; // Colorant table (for n chans > CMYK)
|
||||
|
||||
// Informational only
|
||||
cmsColorSpaceSignature EntryColorSpace;
|
||||
cmsColorSpaceSignature ExitColorSpace;
|
||||
|
||||
// Profiles used to create the transform
|
||||
cmsSEQ* Sequence;
|
||||
|
||||
cmsUInt32Number dwOriginalFlags;
|
||||
cmsFloat64Number AdaptationState;
|
||||
|
||||
// The intent of this transform. That is usually the last intent in the profilechain, but may differ
|
||||
cmsUInt32Number RenderingIntent;
|
||||
|
||||
// An id that uniquely identifies the running context. May be null.
|
||||
cmsContext ContextID;
|
||||
|
||||
} _cmsTRANSFORM;
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
cmsHTRANSFORM _cmsChain2Lab(cmsContext ContextID,
|
||||
cmsUInt32Number nProfiles,
|
||||
cmsUInt32Number InputFormat,
|
||||
cmsUInt32Number OutputFormat,
|
||||
const cmsUInt32Number Intents[],
|
||||
const cmsHPROFILE hProfiles[],
|
||||
const cmsBool BPC[],
|
||||
const cmsFloat64Number AdaptationStates[],
|
||||
cmsUInt32Number dwFlags);
|
||||
|
||||
|
||||
cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID,
|
||||
cmsUInt32Number nPoints,
|
||||
cmsUInt32Number nProfiles,
|
||||
const cmsUInt32Number Intents[],
|
||||
const cmsHPROFILE hProfiles[],
|
||||
const cmsBool BPC[],
|
||||
const cmsFloat64Number AdaptationStates[],
|
||||
cmsUInt32Number dwFlags);
|
||||
|
||||
cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll);
|
||||
|
||||
cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries);
|
||||
|
||||
|
||||
#define _lcms_internal_H
|
||||
#endif
|
||||
Reference in New Issue
Block a user