diff options
Diffstat (limited to 'utils/tificc')
-rw-r--r-- | utils/tificc/Makefile.am | 25 | ||||
-rw-r--r-- | utils/tificc/Makefile.in | 581 | ||||
-rw-r--r-- | utils/tificc/tifdiff.c | 708 | ||||
-rw-r--r-- | utils/tificc/tificc.1 | 100 | ||||
-rw-r--r-- | utils/tificc/tificc.c | 1110 |
5 files changed, 2524 insertions, 0 deletions
diff --git a/utils/tificc/Makefile.am b/utils/tificc/Makefile.am new file mode 100644 index 0000000..9ca83f8 --- /dev/null +++ b/utils/tificc/Makefile.am @@ -0,0 +1,25 @@ +# +# Makefile for building tificc +# Originally written by Bob Friesenhahn, June 2003 +# bugs introduced by Marti Maria + +# Don't require all the GNU mandated files +AUTOMAKE_OPTIONS = 1.7 foreign + +AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/utils/common -I$(top_builddir)/utils/common + + +if HasTIFF +bin_PROGRAMS = tificc +else +bin_PROGRAMS = +endif + +tificc_LDADD = $(top_builddir)/src/liblcms2.la @TIFFICC_DEPLIBS@ +tificc_LDFLAGS = @LDFLAGS@ +tificc_SOURCES = tificc.c ../common/xgetopt.c ../common/vprf.c ../common/utils.h +man_MANS = tificc.1 + + +EXTRA_DIST = $(man_MANS) diff --git a/utils/tificc/Makefile.in b/utils/tificc/Makefile.in new file mode 100644 index 0000000..93f55c1 --- /dev/null +++ b/utils/tificc/Makefile.in @@ -0,0 +1,581 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 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 tificc +# Originally written by Bob Friesenhahn, June 2003 +# bugs introduced by Marti Maria + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +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@ +target_triplet = @target@ +LIBOBJDIR = +@HasTIFF_TRUE@bin_PROGRAMS = tificc$(EXEEXT) +subdir = utils/tificc +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 = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_tificc_OBJECTS = tificc.$(OBJEXT) xgetopt.$(OBJEXT) vprf.$(OBJEXT) +tificc_OBJECTS = $(am_tificc_OBJECTS) +tificc_DEPENDENCIES = $(top_builddir)/src/liblcms2.la +DEFAULT_INCLUDES = -I. -I$(srcdir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(tificc_SOURCES) +DIST_SOURCES = $(tificc_SOURCES) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(man_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +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@ +HasJPEG_FALSE = @HasJPEG_FALSE@ +HasJPEG_TRUE = @HasJPEG_TRUE@ +HasTIFF_FALSE = @HasTIFF_FALSE@ +HasTIFF_TRUE = @HasTIFF_TRUE@ +HasZLIB_FALSE = @HasZLIB_FALSE@ +HasZLIB_TRUE = @HasZLIB_TRUE@ +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@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +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@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +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@ +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@ +includedir = @includedir@ +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@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +to_host_path_cmd = @to_host_path_cmd@ + +# Don't require all the GNU mandated files +AUTOMAKE_OPTIONS = 1.7 foreign +AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/utils/common -I$(top_builddir)/utils/common + +tificc_LDADD = $(top_builddir)/src/liblcms2.la @TIFFICC_DEPLIBS@ +tificc_LDFLAGS = @LDFLAGS@ +tificc_SOURCES = tificc.c ../common/xgetopt.c ../common/vprf.c ../common/utils.h +man_MANS = tificc.1 +EXTRA_DIST = $(man_MANS) +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 \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign utils/tificc/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign utils/tificc/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 +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +tificc$(EXEEXT): $(tificc_OBJECTS) $(tificc_DEPENDENCIES) + @rm -f tificc$(EXEEXT) + $(LINK) $(tificc_LDFLAGS) $(tificc_OBJECTS) $(tificc_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tificc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vprf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xgetopt.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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 $@ $< + +xgetopt.o: ../common/xgetopt.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xgetopt.o -MD -MP -MF "$(DEPDIR)/xgetopt.Tpo" -c -o xgetopt.o `test -f '../common/xgetopt.c' || echo '$(srcdir)/'`../common/xgetopt.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/xgetopt.Tpo" "$(DEPDIR)/xgetopt.Po"; else rm -f "$(DEPDIR)/xgetopt.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../common/xgetopt.c' object='xgetopt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgetopt.o `test -f '../common/xgetopt.c' || echo '$(srcdir)/'`../common/xgetopt.c + +xgetopt.obj: ../common/xgetopt.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xgetopt.obj -MD -MP -MF "$(DEPDIR)/xgetopt.Tpo" -c -o xgetopt.obj `if test -f '../common/xgetopt.c'; then $(CYGPATH_W) '../common/xgetopt.c'; else $(CYGPATH_W) '$(srcdir)/../common/xgetopt.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/xgetopt.Tpo" "$(DEPDIR)/xgetopt.Po"; else rm -f "$(DEPDIR)/xgetopt.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../common/xgetopt.c' object='xgetopt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xgetopt.obj `if test -f '../common/xgetopt.c'; then $(CYGPATH_W) '../common/xgetopt.c'; else $(CYGPATH_W) '$(srcdir)/../common/xgetopt.c'; fi` + +vprf.o: ../common/vprf.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT vprf.o -MD -MP -MF "$(DEPDIR)/vprf.Tpo" -c -o vprf.o `test -f '../common/vprf.c' || echo '$(srcdir)/'`../common/vprf.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/vprf.Tpo" "$(DEPDIR)/vprf.Po"; else rm -f "$(DEPDIR)/vprf.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../common/vprf.c' object='vprf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o vprf.o `test -f '../common/vprf.c' || echo '$(srcdir)/'`../common/vprf.c + +vprf.obj: ../common/vprf.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT vprf.obj -MD -MP -MF "$(DEPDIR)/vprf.Tpo" -c -o vprf.obj `if test -f '../common/vprf.c'; then $(CYGPATH_W) '../common/vprf.c'; else $(CYGPATH_W) '$(srcdir)/../common/vprf.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/vprf.Tpo" "$(DEPDIR)/vprf.Po"; else rm -f "$(DEPDIR)/vprf.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../common/vprf.c' object='vprf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o vprf.obj `if test -f '../common/vprf.c'; then $(CYGPATH_W) '../common/vprf.c'; else $(CYGPATH_W) '$(srcdir)/../common/vprf.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +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; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + 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; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && 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)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$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 $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; 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) + +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-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: install-man1 + +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-binPROGRAMS uninstall-info-am uninstall-man + +uninstall-man: uninstall-man1 + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic 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-binPROGRAMS install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-man1 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-binPROGRAMS uninstall-info-am \ + uninstall-man uninstall-man1 + +# 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: diff --git a/utils/tificc/tifdiff.c b/utils/tificc/tifdiff.c new file mode 100644 index 0000000..8d4eaf2 --- /dev/null +++ b/utils/tificc/tifdiff.c @@ -0,0 +1,708 @@ +//--------------------------------------------------------------------------------- +// +// 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 "utils.h" +#include "tiffio.h" + + +// ------------------------------------------------------------------------ + +static TIFF *Tiff1, *Tiff2, *TiffDiff; +static const char* TiffDiffFilename; +static const char* CGATSout; + +typedef struct { + double n, x, x2; + double Min, Peak; + + } STAT, *LPSTAT; + + +static STAT ColorantStat[4]; +static STAT EuclideanStat; +static STAT ColorimetricStat; + +static uint16 Channels; + +static cmsHPROFILE hLab; + + +static +void ConsoleWarningHandler(const char* module, const char* fmt, va_list ap) +{ + char e[512] = { '\0' }; + if (module != NULL) + strcat(strcpy(e, module), ": "); + + vsprintf(e+strlen(e), fmt, ap); + strcat(e, "."); + if (Verbose) { + + fprintf(stderr, "\nWarning"); + fprintf(stderr, " %s\n", e); + fflush(stderr); + } +} + +static +void ConsoleErrorHandler(const char* module, const char* fmt, va_list ap) +{ + char e[512] = { '\0' }; + + if (module != NULL) + strcat(strcpy(e, module), ": "); + + vsprintf(e+strlen(e), fmt, ap); + strcat(e, "."); + fprintf(stderr, "\nError"); + fprintf(stderr, " %s\n", e); + fflush(stderr); +} + + + +static +void Help() +{ + fprintf(stderr, "Little cms TIFF compare utility. v1.0\n\n"); + + fprintf(stderr, "usage: tiffdiff [flags] input.tif output.tif\n"); + + fprintf(stderr, "\nflags:\n\n"); + + + fprintf(stderr, "%co<tiff> - Output TIFF file\n", SW); + fprintf(stderr, "%cg<CGATS> - Output results in CGATS file\n", SW); + + fprintf(stderr, "\n"); + + fprintf(stderr, "%cv - Verbose (show warnings)\n", SW); + fprintf(stderr, "%ch - This help\n", SW); + + + fflush(stderr); + exit(0); +} + + + +// The toggles stuff + +static +void HandleSwitches(int argc, char *argv[]) +{ + int s; + + while ((s=xgetopt(argc,argv,"o:O:hHvVg:G:")) != EOF) { + + switch (s) { + + + case 'v': + case 'V': + Verbose = TRUE; + break; + + case 'o': + case 'O': + TiffDiffFilename = xoptarg; + break; + + + case 'H': + case 'h': + Help(); + break; + + case 'g': + case 'G': + CGATSout = xoptarg; + break; + + default: + + FatalError("Unknown option - run without args to see valid ones"); + } + } +} + + +static +void ClearStatistics(LPSTAT st) +{ + + st ->n = st ->x = st->x2 = st->Peak = 0; + st ->Min = 1E10; + +} + + +static +void AddOnePixel(LPSTAT st, double dE) +{ + + st-> x += dE; st ->x2 += (dE * dE); st->n += 1.0; + if (dE > st ->Peak) st ->Peak = dE; + if (dE < st ->Min) st ->Min= dE; +} + +static +double Std(LPSTAT st) +{ + return sqrt((st->n * st->x2 - st->x * st->x) / (st->n*(st->n-1))); +} + +static +double Mean(LPSTAT st) +{ + return st ->x/st ->n; +} + + +// Build up the pixeltype descriptor + +static +cmsUInt32Number GetInputPixelType(TIFF *Bank) +{ + uint16 Photometric, bps, spp, extra, PlanarConfig, *info; + uint16 Compression, reverse = 0; + int ColorChannels, IsPlanar = 0, pt = 0; + + TIFFGetField(Bank, TIFFTAG_PHOTOMETRIC, &Photometric); + TIFFGetFieldDefaulted(Bank, TIFFTAG_BITSPERSAMPLE, &bps); + + if (bps == 1) + FatalError("Sorry, bilevel TIFFs has nothig to do with ICC profiles"); + + if (bps != 8 && bps != 16) + FatalError("Sorry, 8 or 16 bits per sample only"); + + TIFFGetFieldDefaulted(Bank, TIFFTAG_SAMPLESPERPIXEL, &spp); + TIFFGetFieldDefaulted(Bank, TIFFTAG_PLANARCONFIG, &PlanarConfig); + + switch (PlanarConfig) + { + case PLANARCONFIG_CONTIG: IsPlanar = 0; break; + case PLANARCONFIG_SEPARATE: FatalError("Planar TIFF are not supported"); + default: + + FatalError("Unsupported planar configuration (=%d) ", (int) PlanarConfig); + } + + // If Samples per pixel == 1, PlanarConfiguration is irrelevant and need + // not to be included. + + if (spp == 1) IsPlanar = 0; + + + // Any alpha? + + TIFFGetFieldDefaulted(Bank, TIFFTAG_EXTRASAMPLES, &extra, &info); + + + ColorChannels = spp - extra; + + switch (Photometric) { + + case PHOTOMETRIC_MINISWHITE: + + reverse = 1; + + case PHOTOMETRIC_MINISBLACK: + + pt = PT_GRAY; + break; + + case PHOTOMETRIC_RGB: + + pt = PT_RGB; + break; + + + case PHOTOMETRIC_PALETTE: + + FatalError("Sorry, palette images not supported (at least on this version)"); + + case PHOTOMETRIC_SEPARATED: + pt = PixelTypeFromChanCount(ColorChannels); + break; + + case PHOTOMETRIC_YCBCR: + TIFFGetField(Bank, TIFFTAG_COMPRESSION, &Compression); + { + uint16 subx, suby; + + pt = PT_YCbCr; + TIFFGetFieldDefaulted(Bank, TIFFTAG_YCBCRSUBSAMPLING, &subx, &suby); + if (subx != 1 || suby != 1) + FatalError("Sorry, subsampled images not supported"); + + } + break; + + case 9: + case PHOTOMETRIC_CIELAB: + pt = PT_Lab; + break; + + + case PHOTOMETRIC_LOGLUV: /* CIE Log2(L) (u',v') */ + + TIFFSetField(Bank, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_16BIT); + pt = PT_YUV; // *ICCSpace = icSigLuvData; + bps = 16; // 16 bits forced by LibTiff + break; + + default: + FatalError("Unsupported TIFF color space (Photometric %d)", Photometric); + } + + // Convert bits per sample to bytes per sample + + bps >>= 3; + + return (COLORSPACE_SH(pt)|PLANAR_SH(IsPlanar)|EXTRA_SH(extra)|CHANNELS_SH(ColorChannels)|BYTES_SH(bps)|FLAVOR_SH(reverse)); +} + + + +static +cmsUInt32Number OpenEmbedded(TIFF* tiff, cmsHPROFILE* PtrProfile, cmsHTRANSFORM* PtrXform) +{ + + cmsUInt32Number EmbedLen, dwFormat = 0; + cmsUInt8Number* EmbedBuffer; + + *PtrProfile = NULL; + *PtrXform = NULL; + + if (TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &EmbedLen, &EmbedBuffer)) { + + *PtrProfile = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen); + + if (Verbose) { + + fprintf(stdout, "Embedded profile found:\n"); + PrintProfileInformation(*PtrProfile); + + } + + dwFormat = GetInputPixelType(tiff); + *PtrXform = cmsCreateTransform(*PtrProfile, dwFormat, + hLab, TYPE_Lab_DBL, INTENT_RELATIVE_COLORIMETRIC, 0); + + } + + return dwFormat; +} + + +static +size_t PixelSize(cmsUInt32Number dwFormat) +{ + return T_BYTES(dwFormat) * (T_CHANNELS(dwFormat) + T_EXTRA(dwFormat)); +} + + +static +int CmpImages(TIFF* tiff1, TIFF* tiff2, TIFF* diff) +{ + cmsUInt8Number* buf1, *buf2, *buf3=NULL; + int row, cols, imagewidth = 0, imagelength = 0; + uint16 Photometric; + double dE = 0; + double dR, dG, dB, dC, dM, dY, dK; + int rc = 0; + cmsHPROFILE hProfile1 = 0, hProfile2 = 0; + cmsHTRANSFORM xform1 = 0, xform2 = 0; + cmsUInt32Number dwFormat1, dwFormat2; + + + + TIFFGetField(tiff1, TIFFTAG_PHOTOMETRIC, &Photometric); + TIFFGetField(tiff1, TIFFTAG_IMAGEWIDTH, &imagewidth); + TIFFGetField(tiff1, TIFFTAG_IMAGELENGTH, &imagelength); + TIFFGetField(tiff1, TIFFTAG_SAMPLESPERPIXEL, &Channels); + + dwFormat1 = OpenEmbedded(tiff1, &hProfile1, &xform1); + dwFormat2 = OpenEmbedded(tiff2, &hProfile2, &xform2); + + + + buf1 = (cmsUInt8Number*)_TIFFmalloc(TIFFScanlineSize(tiff1)); + buf2 = (cmsUInt8Number*)_TIFFmalloc(TIFFScanlineSize(tiff2)); + + if (diff) { + + TIFFSetField(diff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(diff, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(diff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + + TIFFSetField(diff, TIFFTAG_IMAGEWIDTH, imagewidth); + TIFFSetField(diff, TIFFTAG_IMAGELENGTH, imagelength); + + TIFFSetField(diff, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(diff, TIFFTAG_BITSPERSAMPLE, 8); + + buf3 = (cmsUInt8Number*)_TIFFmalloc(TIFFScanlineSize(diff)); + } + + + + for (row = 0; row < imagelength; row++) { + + if (TIFFReadScanline(tiff1, buf1, row, 0) < 0) goto Error; + if (TIFFReadScanline(tiff2, buf2, row, 0) < 0) goto Error; + + + for (cols = 0; cols < imagewidth; cols++) { + + + switch (Photometric) { + + case PHOTOMETRIC_MINISWHITE: + case PHOTOMETRIC_MINISBLACK: + + dE = fabs(buf2[cols] - buf1[cols]); + + AddOnePixel(&ColorantStat[0], dE); + AddOnePixel(&EuclideanStat, dE); + break; + + case PHOTOMETRIC_RGB: + + { + int index = 3 * cols; + + dR = fabs(buf2[index+0] - buf1[index+0]); + dG = fabs(buf2[index+1] - buf1[index+1]); + dB = fabs(buf2[index+2] - buf1[index+2]); + + dE = sqrt(dR * dR + dG * dG + dB * dB) / sqrt(3.); + } + + AddOnePixel(&ColorantStat[0], dR); + AddOnePixel(&ColorantStat[1], dG); + AddOnePixel(&ColorantStat[2], dB); + AddOnePixel(&EuclideanStat, dE); + break; + + case PHOTOMETRIC_SEPARATED: + + { + int index = 4 * cols; + + dC = fabs(buf2[index+0] - buf1[index+0]); + dM = fabs(buf2[index+1] - buf1[index+1]); + dY = fabs(buf2[index+2] - buf1[index+2]); + dK = fabs(buf2[index+3] - buf1[index+3]); + + dE = sqrt(dC * dC + dM * dM + dY * dY + dK * dK) / 2.; + } + AddOnePixel(&ColorantStat[0], dC); + AddOnePixel(&ColorantStat[1], dM); + AddOnePixel(&ColorantStat[2], dY); + AddOnePixel(&ColorantStat[3], dK); + AddOnePixel(&EuclideanStat, dE); + break; + + default: + FatalError("Unsupported channels: %d", Channels); + } + + + if (xform1 && xform2) { + + + cmsCIELab Lab1, Lab2; + size_t index1 = cols * PixelSize(dwFormat1); + size_t index2 = cols * PixelSize(dwFormat2); + + cmsDoTransform(xform1, &buf1[index1], &Lab1, 1); + cmsDoTransform(xform2, &buf2[index2], &Lab2, 1); + + dE = cmsDeltaE(&Lab1, &Lab2); + AddOnePixel(&ColorimetricStat, dE); + } + + + if (diff) { + buf3[cols] = (cmsUInt8Number) floor(dE + 0.5); + } + + } + + if (diff) { + + if (TIFFWriteScanline(diff, buf3, row, 0) < 0) goto Error; + } + + + } + + rc = 1; + +Error: + + if (hProfile1) cmsCloseProfile(hProfile1); + if (hProfile2) cmsCloseProfile(hProfile2); + if (xform1) cmsDeleteTransform(xform1); + if (xform2) cmsDeleteTransform(xform2); + _TIFFfree(buf1); _TIFFfree(buf2); + if (diff) { + TIFFWriteDirectory(diff); + if (buf3 != NULL) _TIFFfree(buf3); + } + return rc; +} + + +static +void AssureShortTagIs(TIFF* tif1, TIFF* tiff2, int tag, int Val, const char* Error) +{ + uint16 v1; + + + if (!TIFFGetField(tif1, tag, &v1)) goto Err; + if (v1 != Val) goto Err; + + if (!TIFFGetField(tiff2, tag, &v1)) goto Err; + if (v1 != Val) goto Err; + + return; +Err: + FatalError("%s is not proper", Error); +} + + +static +int CmpShortTag(TIFF* tif1, TIFF* tif2, int tag) +{ + uint16 v1, v2; + + if (!TIFFGetField(tif1, tag, &v1)) return 0; + if (!TIFFGetField(tif2, tag, &v2)) return 0; + + return v1 == v2; +} + +static +int CmpLongTag(TIFF* tif1, TIFF* tif2, int tag) +{ + uint32 v1, v2; + + if (!TIFFGetField(tif1, tag, &v1)) return 0; + if (!TIFFGetField(tif2, tag, &v2)) return 0; + + return v1 == v2; +} + + +static +void EqualShortTag(TIFF* tif1, TIFF* tif2, int tag, const char* Error) +{ + if (!CmpShortTag(tif1, tif2, tag)) + FatalError("%s is different", Error); +} + + + +static +void EqualLongTag(TIFF* tif1, TIFF* tif2, int tag, const char* Error) +{ + if (!CmpLongTag(tif1, tif2, tag)) + FatalError("%s is different", Error); +} + + + +static +void AddOneCGATSRow(cmsHANDLE hIT8, char *Name, LPSTAT st) +{ + + double Per100 = 100.0 * ((255.0 - Mean(st)) / 255.0); + + cmsIT8SetData(hIT8, Name, "SAMPLE_ID", Name); + cmsIT8SetDataDbl(hIT8, Name, "PER100_EQUAL", Per100); + cmsIT8SetDataDbl(hIT8, Name, "MEAN_DE", Mean(st)); + cmsIT8SetDataDbl(hIT8, Name, "STDEV_DE", Std(st)); + cmsIT8SetDataDbl(hIT8, Name, "MIN_DE", st ->Min); + cmsIT8SetDataDbl(hIT8, Name, "MAX_DE", st ->Peak); + +} + + +static +void CreateCGATS(const char* TiffName1, const char* TiffName2) +{ + cmsHANDLE hIT8 = cmsIT8Alloc(0); + time_t ltime; + char Buffer[256]; + + cmsIT8SetSheetType(hIT8, "TIFFDIFF"); + + + sprintf(Buffer, "Differences between %s and %s", TiffName1, TiffName2); + + cmsIT8SetComment(hIT8, Buffer); + + cmsIT8SetPropertyStr(hIT8, "ORIGINATOR", "TIFFDIFF"); + time( <ime ); + strcpy(Buffer, ctime(<ime)); + Buffer[strlen(Buffer)-1] = 0; // Remove the nasty "\n" + + cmsIT8SetPropertyStr(hIT8, "CREATED", Buffer); + + cmsIT8SetComment(hIT8, " "); + + cmsIT8SetPropertyDbl(hIT8, "NUMBER_OF_FIELDS", 6); + + + cmsIT8SetDataFormat(hIT8, 0, "SAMPLE_ID"); + cmsIT8SetDataFormat(hIT8, 1, "PER100_EQUAL"); + cmsIT8SetDataFormat(hIT8, 2, "MEAN_DE"); + cmsIT8SetDataFormat(hIT8, 3, "STDEV_DE"); + cmsIT8SetDataFormat(hIT8, 4, "MIN_DE"); + cmsIT8SetDataFormat(hIT8, 5, "MAX_DE"); + + + switch (Channels) { + + case 1: + cmsIT8SetPropertyDbl(hIT8, "NUMBER_OF_SETS", 3); + AddOneCGATSRow(hIT8, "GRAY_PLANE", &ColorantStat[0]); + break; + + case 3: + cmsIT8SetPropertyDbl(hIT8, "NUMBER_OF_SETS", 5); + AddOneCGATSRow(hIT8, "R_PLANE", &ColorantStat[0]); + AddOneCGATSRow(hIT8, "G_PLANE", &ColorantStat[1]); + AddOneCGATSRow(hIT8, "B_PLANE", &ColorantStat[2]); + break; + + + case 4: + cmsIT8SetPropertyDbl(hIT8, "NUMBER_OF_SETS", 6); + AddOneCGATSRow(hIT8, "C_PLANE", &ColorantStat[0]); + AddOneCGATSRow(hIT8, "M_PLANE", &ColorantStat[1]); + AddOneCGATSRow(hIT8, "Y_PLANE", &ColorantStat[2]); + AddOneCGATSRow(hIT8, "K_PLANE", &ColorantStat[3]); + break; + + default: FatalError("Internal error: Bad ColorSpace"); + + } + + AddOneCGATSRow(hIT8, "EUCLIDEAN", &EuclideanStat); + AddOneCGATSRow(hIT8, "COLORIMETRIC", &ColorimetricStat); + + cmsIT8SaveToFile(hIT8, CGATSout); + cmsIT8Free(hIT8); +} + +int main(int argc, char* argv[]) +{ + int i; + + Tiff1 = Tiff2 = TiffDiff = NULL; + + InitUtils("tiffdiff"); + + HandleSwitches(argc, argv); + + if ((argc - xoptind) != 2) { + + Help(); + } + + TIFFSetErrorHandler(ConsoleErrorHandler); + TIFFSetWarningHandler(ConsoleWarningHandler); + + Tiff1 = TIFFOpen(argv[xoptind], "r"); + if (Tiff1 == NULL) FatalError("Unable to open '%s'", argv[xoptind]); + + Tiff2 = TIFFOpen(argv[xoptind+1], "r"); + if (Tiff2 == NULL) FatalError("Unable to open '%s'", argv[xoptind+1]); + + if (TiffDiffFilename) { + + TiffDiff = TIFFOpen(TiffDiffFilename, "w"); + if (TiffDiff == NULL) FatalError("Unable to create '%s'", TiffDiffFilename); + + } + + + AssureShortTagIs(Tiff1, Tiff2, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG, "Planar Config"); + AssureShortTagIs(Tiff1, Tiff2, TIFFTAG_BITSPERSAMPLE, 8, "8 bit per sample"); + + EqualLongTag(Tiff1, Tiff2, TIFFTAG_IMAGEWIDTH, "Image width"); + EqualLongTag(Tiff1, Tiff2, TIFFTAG_IMAGELENGTH, "Image length"); + + EqualShortTag(Tiff1, Tiff2, TIFFTAG_SAMPLESPERPIXEL, "Samples per pixel"); + + + hLab = cmsCreateLab4Profile(NULL); + + ClearStatistics(&EuclideanStat); + for (i=0; i < 4; i++) + ClearStatistics(&ColorantStat[i]); + + if (!CmpImages(Tiff1, Tiff2, TiffDiff)) + FatalError("Error comparing images"); + + if (CGATSout) { + CreateCGATS(argv[xoptind], argv[xoptind+1]); + } + else { + + double Per100 = 100.0 * ((255.0 - Mean(&EuclideanStat)) / 255.0); + + printf("Digital counts %g%% equal. mean %g, min %g, max %g, Std %g\n", Per100, Mean(&EuclideanStat), + EuclideanStat.Min, + EuclideanStat.Peak, + Std(&EuclideanStat)); + + if (ColorimetricStat.n > 0) { + + Per100 = 100.0 * ((255.0 - Mean(&ColorimetricStat)) / 255.0); + + printf("dE Colorimetric %g%% equal. mean %g, min %g, max %g, Std %g\n", Per100, Mean(&ColorimetricStat), + ColorimetricStat.Min, + ColorimetricStat.Peak, + Std(&ColorimetricStat)); + } + + } + + if (hLab) cmsCloseProfile(hLab); + if (Tiff1) TIFFClose(Tiff1); + if (Tiff2) TIFFClose(Tiff2); + if (TiffDiff) TIFFClose(TiffDiff); + + return 0; +} + + diff --git a/utils/tificc/tificc.1 b/utils/tificc/tificc.1 new file mode 100644 index 0000000..d03c1df --- /dev/null +++ b/utils/tificc/tificc.1 @@ -0,0 +1,100 @@ +.\"Shiju P. Nair September 30, 2004 +.TH TIFFICC 1 "October 23, 2004" +.SH NAME +tifficc - little cms ICC profile applier for TIFF. +.SH SYNOPSIS +.B tifficc +.RI [ options ] " input.tif output.tif" +.SH DESCRIPTION +lcms is a standalone CMM engine, which deals with the color management. +It implements a fast transformation between ICC profiles. +.B tifficc +is little cms ICC profile applier for TIFF. +.SH OPTIONS +.TP +.B \-a +Handle channels > 4 as alpha. +.TP +.B \-b +Black point compensation. +.TP +.B \-c <0,1,2,3> +Precalculates transform. (0=Off, 1=Normal, 2=Hi-res, 3=LoRes) [defaults to 1] +.TP +.B \-e +Embed destination profile. +.TP +.B \-g +Marks out-of-gamut colors on softproof. +.TP +.B \-h <0,1,2> +Show summary of options and examples. +.TP +.BI \-i\ profile +Input profile (defaults to sRGB). +.TP +.B -k <0..400> +Ink-limiting in % (CMYK only). +.TP +.BI \-l\ profile +Transform by device-link profile. +.TP +.B \-m <0,1,2,3> +SoftProof intent. +.TP +.B \-n +Ignore embedded profile on input. +.TP +.BI \-p\ profile +Soft proof profile. +.TP +.BI \-o\ profile +.p +Output profile (defaults to sRGB). +.TP +.BI \-s\ profile +Save embedded profile as <new profile> +.TP +.B \-t <0,1,2,3> +Intent (0=Perceptual, 1=Colorimetric, 2=Saturation, 3=Absolute). +.TP +.B \-v +Verbose. +.TP +.B \-w +Wide output (generates 16 bps tiff). +.TP +You can also use following builtins +*Lab - CIE Lab D50 based +*XYZ - XYZ +*adobe1998RBB - AdobeRGB +*colormatchrgb - ColorMatch RGB +*applergb - Apple RGB +.SH EXAMPLES +.nf +To color correct from scanner to sRGB: + tifficc -iscanner.icm in.tif out.tif + +To convert from monitor1 to monitor2: + tifficc -imon1.icm -omon2.icm in.tif out.tif + +To make a CMYK separation: + tifficc -oprinter.icm inrgb.tif outcmyk.tif + +To recover sRGB from a CMYK separation: + tifficc -iprinter.icm incmyk.tif outrgb.tif + +To convert from CIELab TIFF to sRGB + tifficc -iTiffLab8Spac.icm in.tif out.tif +.fi +.SH NOTES +For suggestions, comments, bug reports etc. send mail to info@littlecms.com. +.SH SEE ALSO +.BR jpegicc (1), +.BR icc2ps (1), +.BR icclink (1), +.BR icctrans (1), +.BR wtpt (1) +.SH AUTHOR +This manual page was originally written by Shiju p. Nair <shiju.p@gmail.com>, +for the Debian project. Modified by Marti Maria to reflect further changes. diff --git a/utils/tificc/tificc.c b/utils/tificc/tificc.c new file mode 100644 index 0000000..f71f6b6 --- /dev/null +++ b/utils/tificc/tificc.c @@ -0,0 +1,1110 @@ +//--------------------------------------------------------------------------------- +// +// 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. +// +//--------------------------------------------------------------------------------- + +// This program does apply profiles to (some) TIFF files + +#include "lcms2_plugin.h" +#include "tiffio.h" +#include "utils.h" + + +// Flags + +static cmsBool BlackWhiteCompensation = FALSE; +static cmsBool IgnoreEmbedded = FALSE; +static cmsBool EmbedProfile = FALSE; +static int Width = 8; +static cmsBool GamutCheck = FALSE; +static cmsBool lIsDeviceLink = FALSE; +static cmsBool StoreAsAlpha = FALSE; +static cmsBool InputLabUsingICC = FALSE; + +static int Intent = INTENT_PERCEPTUAL; +static int ProofingIntent = INTENT_PERCEPTUAL; +static int PrecalcMode = 1; +static cmsFloat64Number InkLimit = 400; + +static cmsFloat64Number ObserverAdaptationState = 0; + +static const char *cInpProf = NULL; +static const char *cOutProf = NULL; +static const char *cProofing = NULL; + +static const char* SaveEmbedded = NULL; + +// Console error & warning +static +void ConsoleWarningHandler(const char* module, const char* fmt, va_list ap) +{ + char e[512] = { '\0' }; + if (module != NULL) + strcat(strcpy(e, module), ": "); + + vsprintf(e+strlen(e), fmt, ap); + strcat(e, "."); + if (Verbose) { + + fprintf(stderr, "\nWarning"); + fprintf(stderr, " %s\n", e); + fflush(stderr); + } +} + +static +void ConsoleErrorHandler(const char* module, const char* fmt, va_list ap) +{ + char e[512] = { '\0' }; + + if (module != NULL) + strcat(strcpy(e, module), ": "); + + vsprintf(e+strlen(e), fmt, ap); + strcat(e, "."); + fprintf(stderr, "\nError"); + fprintf(stderr, " %s\n", e); + fflush(stderr); +} + + +// Issue a warning +static +void Warning(const char *frm, ...) +{ + va_list args; + + va_start(args, frm); + ConsoleWarningHandler("[tifficc]", frm, args); + va_end(args); +} + + + +// Out of mememory is a fatal error +static +void OutOfMem(cmsUInt32Number size) +{ + FatalError("Out of memory on allocating %d bytes.", size); +} + + +// ----------------------------------------------------------------------------------------------- + +// In TIFF, Lab is encoded in a different way, so let's use the plug-in +// capabilities of lcms2 to change the meaning of TYPE_Lab_8. + +// * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256 +static int FromLabV2ToLabV4(int x) +{ + int a; + + a = (x << 8 | x) >> 8; // * 257 / 256 + if ( a > 0xffff) return 0xffff; + return a; +} + +// * 0xf00 / 0xffff = * 256 / 257 +static int FromLabV4ToLabV2(int x) +{ + return ((x << 8) + 0x80) / 257; +} + + +// Formatter for 8bit Lab TIFF (photometric 8) +static +unsigned char* UnrollTIFFLab8(register void* nfo, register cmsUInt16Number wIn[], register cmsUInt8Number* accum) +{ + wIn[0] = (cmsUInt16Number) FromLabV2ToLabV4((accum[0]) << 8); + wIn[1] = (cmsUInt16Number) FromLabV2ToLabV4(((accum[1] > 127) ? (accum[1] - 128) : (accum[1] + 128)) << 8); + wIn[2] = (cmsUInt16Number) FromLabV2ToLabV4(((accum[2] > 127) ? (accum[2] - 128) : (accum[2] + 128)) << 8); + + return accum + 3; +} + +static +unsigned char* PackTIFFLab8(register void* nfo, register cmsUInt16Number wOut[], register cmsUInt8Number* output) +{ + int a, b; + + *output++ = (cmsUInt8Number) (FromLabV4ToLabV2(wOut[0] + 0x0080) >> 8); + + a = (FromLabV4ToLabV2(wOut[1]) + 0x0080) >> 8; + b = (FromLabV4ToLabV2(wOut[2]) + 0x0080) >> 8; + + *output++ = (cmsUInt8Number) ((a < 128) ? (a + 128) : (a - 128)); + *output++ = (cmsUInt8Number) ((b < 128) ? (b + 128) : (b - 128)); + + return output; +} + + +static +cmsFormatter TiffFormatterFactory(cmsUInt32Number Type, + cmsFormatterDirection Dir, + cmsUInt32Number dwFlags) +{ + cmsFormatter Result = { NULL }; + + if (Type == TYPE_Lab_8 && !(dwFlags & CMS_PACK_FLAGS_FLOAT)) { + + if (Dir == cmsFormatterInput) + Result.Fmt16 = UnrollTIFFLab8; + else + Result.Fmt16 = PackTIFFLab8; + } + + return Result; +} + +static cmsPluginFormatters TiffLabPlugin = { {cmsPluginMagicNumber, 2000, cmsPluginFormattersSig, NULL}, TiffFormatterFactory }; + + +// Build up the pixeltype descriptor +static +cmsUInt32Number GetInputPixelType(TIFF *Bank) +{ + uint16 Photometric, bps, spp, extra, PlanarConfig, *info; + uint16 Compression, reverse = 0; + int ColorChannels, IsPlanar = 0, pt = 0; + + TIFFGetField(Bank, TIFFTAG_PHOTOMETRIC, &Photometric); + TIFFGetFieldDefaulted(Bank, TIFFTAG_BITSPERSAMPLE, &bps); + + if (bps == 1) + FatalError("Sorry, bilevel TIFFs has nothig to do with ICC profiles"); + + if (bps != 8 && bps != 16 && bps != 32) + FatalError("Sorry, 8, 16 or 32 bits per sample only"); + + TIFFGetFieldDefaulted(Bank, TIFFTAG_SAMPLESPERPIXEL, &spp); + TIFFGetFieldDefaulted(Bank, TIFFTAG_PLANARCONFIG, &PlanarConfig); + + switch (PlanarConfig) { + + case PLANARCONFIG_CONTIG: IsPlanar = 0; break; + case PLANARCONFIG_SEPARATE: IsPlanar = 1; break; + default: + + FatalError("Unsupported planar configuration (=%d) ", (int) PlanarConfig); + } + + // If Samples per pixel == 1, PlanarConfiguration is irrelevant and need + // not to be included. + + if (spp == 1) IsPlanar = 0; + + // Any alpha? + + TIFFGetFieldDefaulted(Bank, TIFFTAG_EXTRASAMPLES, &extra, &info); + + // Read alpha channels as colorant + + if (StoreAsAlpha) { + + ColorChannels = spp; + extra = 0; + } + else + ColorChannels = spp - extra; + + switch (Photometric) { + + case PHOTOMETRIC_MINISWHITE: + + reverse = 1; + + // ... fall through ... + + case PHOTOMETRIC_MINISBLACK: + pt = PT_GRAY; + break; + + case PHOTOMETRIC_RGB: + pt = PT_RGB; + break; + + + case PHOTOMETRIC_PALETTE: + FatalError("Sorry, palette images not supported"); + break; + + case PHOTOMETRIC_SEPARATED: + + pt = PixelTypeFromChanCount(ColorChannels); + break; + + case PHOTOMETRIC_YCBCR: + TIFFGetField(Bank, TIFFTAG_COMPRESSION, &Compression); + { + uint16 subx, suby; + + pt = PT_YCbCr; + TIFFGetFieldDefaulted(Bank, TIFFTAG_YCBCRSUBSAMPLING, &subx, &suby); + if (subx != 1 || suby != 1) + FatalError("Sorry, subsampled images not supported"); + + } + break; + + case PHOTOMETRIC_ICCLAB: + pt = PT_Lab; + InputLabUsingICC = TRUE; + break; + + case PHOTOMETRIC_CIELAB: + pt = PT_Lab; + InputLabUsingICC = FALSE; + break; + + + case PHOTOMETRIC_LOGLUV: // CIE Log2(L) (u',v') + + TIFFSetField(Bank, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_16BIT); + pt = PT_YUV; // *ICCSpace = icSigLuvData; + bps = 16; // 16 bits forced by LibTiff + break; + + default: + FatalError("Unsupported TIFF color space (Photometric %d)", Photometric); + } + + // Convert bits per sample to bytes per sample + + bps >>= 3; + + return (COLORSPACE_SH(pt)|PLANAR_SH(IsPlanar)|EXTRA_SH(extra)|CHANNELS_SH(ColorChannels)|BYTES_SH(bps)|FLAVOR_SH(reverse)); +} + + + +// Rearrange pixel type to build output descriptor +static +cmsUInt32Number ComputeOutputFormatDescriptor(cmsUInt32Number dwInput, int OutColorSpace, int bps) +{ + int IsPlanar = T_PLANAR(dwInput); + int Channels = ChanCountFromPixelType(OutColorSpace); + + return (COLORSPACE_SH(OutColorSpace)|PLANAR_SH(IsPlanar)|CHANNELS_SH(Channels)|BYTES_SH(bps)); +} + + + +// Tile based transforms +static +int TileBasedXform(cmsHTRANSFORM hXForm, TIFF* in, TIFF* out, int nPlanes) +{ + tsize_t BufSizeIn = TIFFTileSize(in); + tsize_t BufSizeOut = TIFFTileSize(out); + unsigned char *BufferIn, *BufferOut; + ttile_t i, TileCount = TIFFNumberOfTiles(in) / nPlanes; + uint32 tw, tl; + int PixelCount, j; + + + TIFFGetFieldDefaulted(in, TIFFTAG_TILEWIDTH, &tw); + TIFFGetFieldDefaulted(in, TIFFTAG_TILELENGTH, &tl); + + PixelCount = (int) tw * tl; + + BufferIn = (unsigned char *) _TIFFmalloc(BufSizeIn * nPlanes); + if (!BufferIn) OutOfMem(BufSizeIn * nPlanes); + + BufferOut = (unsigned char *) _TIFFmalloc(BufSizeOut * nPlanes); + if (!BufferOut) OutOfMem(BufSizeOut * nPlanes); + + + for (i = 0; i < TileCount; i++) { + + for (j=0; j < nPlanes; j++) { + + if (TIFFReadEncodedTile(in, i + (j* TileCount), + BufferIn + (j*BufSizeIn), BufSizeIn) < 0) goto cleanup; + } + + cmsDoTransform(hXForm, BufferIn, BufferOut, PixelCount); + + for (j=0; j < nPlanes; j++) { + + if (TIFFWriteEncodedTile(out, i + (j*TileCount), + BufferOut + (j*BufSizeOut), BufSizeOut) < 0) goto cleanup; + } + + } + + _TIFFfree(BufferIn); + _TIFFfree(BufferOut); + return 1; + + +cleanup: + + _TIFFfree(BufferIn); + _TIFFfree(BufferOut); + return 0; +} + + +// Strip based transforms + +static +int StripBasedXform(cmsHTRANSFORM hXForm, TIFF* in, TIFF* out, int nPlanes) +{ + tsize_t BufSizeIn = TIFFStripSize(in); + tsize_t BufSizeOut = TIFFStripSize(out); + unsigned char *BufferIn, *BufferOut; + ttile_t i, StripCount = TIFFNumberOfStrips(in) / nPlanes; + uint32 sw; + uint32 sl; + uint32 iml; + int j; + int PixelCount; + + TIFFGetFieldDefaulted(in, TIFFTAG_IMAGEWIDTH, &sw); + TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &sl); + TIFFGetFieldDefaulted(in, TIFFTAG_IMAGELENGTH, &iml); + + // It is possible to get infinite rows per strip + if (sl == 0 || sl > iml) + sl = iml; // One strip for whole image + + BufferIn = (unsigned char *) _TIFFmalloc(BufSizeIn * nPlanes); + if (!BufferIn) OutOfMem(BufSizeIn * nPlanes); + + BufferOut = (unsigned char *) _TIFFmalloc(BufSizeOut * nPlanes); + if (!BufferOut) OutOfMem(BufSizeOut * nPlanes); + + + for (i = 0; i < StripCount; i++) { + + for (j=0; j < nPlanes; j++) { + + if (TIFFReadEncodedStrip(in, i + (j * StripCount), + BufferIn + (j * BufSizeIn), BufSizeIn) < 0) goto cleanup; + } + + PixelCount = (int) sw * (iml < sl ? iml : sl); + iml -= sl; + + cmsDoTransform(hXForm, BufferIn, BufferOut, PixelCount); + + for (j=0; j < nPlanes; j++) { + if (TIFFWriteEncodedStrip(out, i + (j * StripCount), + BufferOut + j * BufSizeOut, BufSizeOut) < 0) goto cleanup; + } + + } + + _TIFFfree(BufferIn); + _TIFFfree(BufferOut); + return 1; + +cleanup: + + _TIFFfree(BufferIn); + _TIFFfree(BufferOut); + return 0; +} + + +// Creates minimum required tags +static +void WriteOutputTags(TIFF *out, int Colorspace, int BytesPerSample) +{ + int BitsPerSample = (8 * BytesPerSample); + int nChannels = ChanCountFromPixelType(Colorspace); + + uint16 Extra[] = { EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA, + EXTRASAMPLE_UNASSALPHA + }; + + + switch (Colorspace) { + + case PT_GRAY: + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, BitsPerSample); + break; + + case PT_RGB: + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, BitsPerSample); + break; + + case PT_CMY: + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED); + TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(out, TIFFTAG_INKSET, 2); + TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, BitsPerSample); + break; + + case PT_CMYK: + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED); + TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 4); + TIFFSetField(out, TIFFTAG_INKSET, INKSET_CMYK); + TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, BitsPerSample); + break; + + case PT_Lab: + if (BitsPerSample == 16) + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, 9); + else + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB); + TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, BitsPerSample); // Needed by TIFF Spec + break; + + + // Multi-ink separations + case PT_MCH5: + case PT_MCH6: + case PT_MCH7: + case PT_MCH8: + case PT_MCH9: + case PT_MCH10: + case PT_MCH11: + case PT_MCH12: + case PT_MCH13: + case PT_MCH14: + case PT_MCH15: + + TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED); + TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, nChannels); + + if (StoreAsAlpha) { + // CMYK plus extra alpha + TIFFSetField(out, TIFFTAG_EXTRASAMPLES, nChannels - 4, Extra); + } + else { + TIFFSetField(out, TIFFTAG_INKSET, 2); + } + + TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, BitsPerSample); + break; + + + default: + FatalError("Unsupported output colorspace"); + } + + if (Width == 32) + TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); +} + + +// Copies a bunch of tages + +static +void CopyOtherTags(TIFF* in, TIFF* out) +{ +#define CopyField(tag, v) \ + if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v) + + + short shortv; + uint32 ow, ol; + cmsFloat32Number floatv; + char *stringv; + uint32 longv; + + CopyField(TIFFTAG_SUBFILETYPE, longv); + + TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &ow); + TIFFGetField(in, TIFFTAG_IMAGELENGTH, &ol); + + TIFFSetField(out, TIFFTAG_IMAGEWIDTH, ow); + TIFFSetField(out, TIFFTAG_IMAGELENGTH, ol); + + CopyField(TIFFTAG_PLANARCONFIG, shortv); + CopyField(TIFFTAG_COMPRESSION, shortv); + + if (Width != 32) + CopyField(TIFFTAG_PREDICTOR, shortv); + + CopyField(TIFFTAG_THRESHHOLDING, shortv); + CopyField(TIFFTAG_FILLORDER, shortv); + CopyField(TIFFTAG_ORIENTATION, shortv); + CopyField(TIFFTAG_MINSAMPLEVALUE, shortv); + CopyField(TIFFTAG_MAXSAMPLEVALUE, shortv); + CopyField(TIFFTAG_XRESOLUTION, floatv); + CopyField(TIFFTAG_YRESOLUTION, floatv); + CopyField(TIFFTAG_RESOLUTIONUNIT, shortv); + CopyField(TIFFTAG_ROWSPERSTRIP, longv); + CopyField(TIFFTAG_XPOSITION, floatv); + CopyField(TIFFTAG_YPOSITION, floatv); + CopyField(TIFFTAG_IMAGEDEPTH, longv); + CopyField(TIFFTAG_TILEDEPTH, longv); + + CopyField(TIFFTAG_TILEWIDTH, longv); + CopyField(TIFFTAG_TILELENGTH, longv); + + CopyField(TIFFTAG_ARTIST, stringv); + CopyField(TIFFTAG_IMAGEDESCRIPTION, stringv); + CopyField(TIFFTAG_MAKE, stringv); + CopyField(TIFFTAG_MODEL, stringv); + + CopyField(TIFFTAG_DATETIME, stringv); + CopyField(TIFFTAG_HOSTCOMPUTER, stringv); + CopyField(TIFFTAG_PAGENAME, stringv); + CopyField(TIFFTAG_DOCUMENTNAME, stringv); + +} + +// A replacement for (the nonstandard) filelenght + + +static +void DoEmbedProfile(TIFF* Out, const char* ProfileFile) +{ + FILE* f; + cmsUInt32Number size, EmbedLen; + cmsUInt8Number* EmbedBuffer; + + f = fopen(ProfileFile, "rb"); + if (f == NULL) return; + + size = cmsfilelength(f); + EmbedBuffer = (cmsUInt8Number*) malloc(size + 1); + if (EmbedBuffer == NULL) { + OutOfMem(size+1); + return; + } + + EmbedLen = fread(EmbedBuffer, 1, size, f); + + if (EmbedLen != size) + FatalError("Cannot read %ld bytes to %s", size, ProfileFile); + + fclose(f); + EmbedBuffer[EmbedLen] = 0; + + TIFFSetField(Out, TIFFTAG_ICCPROFILE, EmbedLen, EmbedBuffer); + free(EmbedBuffer); +} + + + +static +cmsHPROFILE GetTIFFProfile(TIFF* in) +{ + cmsCIExyYTRIPLE Primaries; + cmsFloat32Number* chr; + cmsCIExyY WhitePoint; + cmsFloat32Number* wp; + int i; + cmsToneCurve* Curve[3]; + cmsUInt16Number *gmr, *gmg, *gmb; + cmsHPROFILE hProfile; + cmsUInt32Number EmbedLen; + cmsUInt8Number* EmbedBuffer; + + if (IgnoreEmbedded) return NULL; + + if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &EmbedLen, &EmbedBuffer)) { + + hProfile = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen); + + // Print description found in the profile + if (Verbose) { + + fprintf(stdout, "\n[Embedded profile]\n"); + PrintProfileInformation(hProfile); + fflush(stdout); + } + + if (hProfile != NULL && SaveEmbedded != NULL) + SaveMemoryBlock(EmbedBuffer, EmbedLen, SaveEmbedded); + + if (hProfile) return hProfile; + } + + // Try to see if "colorimetric" tiff + + if (TIFFGetField(in, TIFFTAG_PRIMARYCHROMATICITIES, &chr)) { + + Primaries.Red.x = chr[0]; + Primaries.Red.y = chr[1]; + Primaries.Green.x = chr[2]; + Primaries.Green.y = chr[3]; + Primaries.Blue.x = chr[4]; + Primaries.Blue.y = chr[5]; + + Primaries.Red.Y = Primaries.Green.Y = Primaries.Blue.Y = 1.0; + + if (TIFFGetField(in, TIFFTAG_WHITEPOINT, &wp)) { + + WhitePoint.x = wp[0]; + WhitePoint.y = wp[1]; + WhitePoint.Y = 1.0; + + // Transferfunction is a bit harder.... + + TIFFGetFieldDefaulted(in, TIFFTAG_TRANSFERFUNCTION, + &gmr, + &gmg, + &gmb); + + Curve[0] = cmsBuildTabulatedToneCurve16(NULL, 256, gmr); + Curve[1] = cmsBuildTabulatedToneCurve16(NULL, 256, gmg); + Curve[2] = cmsBuildTabulatedToneCurve16(NULL, 256, gmb); + + hProfile = cmsCreateRGBProfileTHR(NULL, &WhitePoint, &Primaries, Curve); + + for (i=0; i < 3; i++) + cmsFreeToneCurve(Curve[i]); + + if (Verbose) { + fprintf(stdout, "\n[Colorimetric TIFF]\n"); + } + + + return hProfile; + } + } + + return NULL; +} + + +// Transform one image +static +int TransformImage(TIFF* in, TIFF* out, const char *cDefInpProf) +{ + cmsHPROFILE hIn, hOut, hProof, hInkLimit = NULL; + cmsHTRANSFORM xform; + cmsUInt32Number wInput, wOutput; + int OutputColorSpace; + int bps = Width / 8; + cmsUInt32Number dwFlags = 0; + int nPlanes; + + // Observer adaptation state (only meaningful on absolute colorimetric intent) + + cmsSetAdaptationState(ObserverAdaptationState); + + if (EmbedProfile && cOutProf) + DoEmbedProfile(out, cOutProf); + + if (BlackWhiteCompensation) + dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION; + + + switch (PrecalcMode) { + + case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break; + case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break; + case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break; + case 1: break; + + default: FatalError("Unknown precalculation mode '%d'", PrecalcMode); + } + + + if (GamutCheck) + dwFlags |= cmsFLAGS_GAMUTCHECK; + + hProof = NULL; + hOut = NULL; + + if (lIsDeviceLink) { + + hIn = cmsOpenProfileFromFile(cDefInpProf, "r"); + } + else { + + hIn = GetTIFFProfile(in); + + if (hIn == NULL) + hIn = OpenStockProfile(NULL, cDefInpProf); + + hOut = OpenStockProfile(NULL, cOutProf); + + if (cProofing != NULL) { + + hProof = OpenStockProfile(NULL, cProofing); + dwFlags |= cmsFLAGS_SOFTPROOFING; + } + } + + // Take input color space + + wInput = GetInputPixelType(in); + + // Assure both, input profile and input TIFF are on same colorspace + + if (_cmsLCMScolorSpace(cmsGetColorSpace(hIn)) != (int) T_COLORSPACE(wInput)) + FatalError("Input profile is not operating in proper color space"); + + + if (!lIsDeviceLink) + OutputColorSpace = _cmsLCMScolorSpace(cmsGetColorSpace(hOut)); + else + OutputColorSpace = _cmsLCMScolorSpace(cmsGetPCS(hIn)); + + wOutput = ComputeOutputFormatDescriptor(wInput, OutputColorSpace, bps); + + WriteOutputTags(out, OutputColorSpace, bps); + CopyOtherTags(in, out); + + // Ink limit + if (InkLimit != 400.0 && + (OutputColorSpace == PT_CMYK || OutputColorSpace == PT_CMY)) { + + cmsHPROFILE hProfiles[10]; + int nProfiles = 0; + + + hInkLimit = cmsCreateInkLimitingDeviceLink(cmsGetColorSpace(hOut), InkLimit); + + hProfiles[nProfiles++] = hIn; + if (hProof) { + hProfiles[nProfiles++] = hProof; + hProfiles[nProfiles++] = hProof; + } + + hProfiles[nProfiles++] = hOut; + hProfiles[nProfiles++] = hInkLimit; + + xform = cmsCreateMultiprofileTransform(hProfiles, nProfiles, + wInput, wOutput, Intent, dwFlags); + + } + else { + + xform = cmsCreateProofingTransform(hIn, wInput, + hOut, wOutput, + hProof, Intent, + ProofingIntent, + dwFlags); + } + + cmsCloseProfile(hIn); + cmsCloseProfile(hOut); + + if (hInkLimit) + cmsCloseProfile(hInkLimit); + if (hProof) + cmsCloseProfile(hProof); + + // Planar stuff + if (T_PLANAR(wInput)) + nPlanes = T_CHANNELS(wInput) + T_EXTRA(wInput); + else + nPlanes = 1; + + + // Handle tile by tile or strip by strip + if (TIFFIsTiled(in)) { + + TileBasedXform(xform, in, out, nPlanes); + } + else { + StripBasedXform(xform, in, out, nPlanes); + } + + + cmsDeleteTransform(xform); + + TIFFWriteDirectory(out); + + return 1; +} + + +// Print help +static +void Help(int level) +{ + fprintf(stderr, "little cms ICC profile applier for TIFF - v6.0 [LittleCMS %2.2f]\n\n", LCMS_VERSION / 1000.0); + fflush(stderr); + + switch(level) { + + default: + case 0: + + fprintf(stderr, "usage: tifficc [flags] input.tif output.tif\n"); + + fprintf(stderr, "\nflags:\n\n"); + fprintf(stderr, "%cv - Verbose\n", SW); + fprintf(stderr, "%ci<profile> - Input profile (defaults to sRGB)\n", SW); + fprintf(stderr, "%co<profile> - Output profile (defaults to sRGB)\n", SW); + fprintf(stderr, "%cl<profile> - Transform by device-link profile\n", SW); + + PrintRenderingIntents(); + + fprintf(stderr, "%cb - Black point compensation\n", SW); + fprintf(stderr, "%cd<0..1> - Observer adaptation state (abs.col. only)\n", SW); + + fprintf(stderr, "%cc<0,1,2,3> - Precalculates transform (0=Off, 1=Normal, 2=Hi-res, 3=LoRes)\n", SW); + fprintf(stderr, "\n"); + + fprintf(stderr, "%cw<8,16,32> - Output depth. Use 32 for floating-point\n\n", SW); + fprintf(stderr, "%ca - Handle channels > 4 as alpha\n", SW); + + fprintf(stderr, "%cn - Ignore embedded profile on input\n", SW); + fprintf(stderr, "%ce - Embed destination profile\n", SW); + fprintf(stderr, "%cs<new profile> - Save embedded profile as <new profile>\n", SW); + fprintf(stderr, "\n"); + + + fprintf(stderr, "%cp<profile> - Soft proof profile\n", SW); + fprintf(stderr, "%cm<n> - Soft proof intent\n", SW); + fprintf(stderr, "%cg - Marks out-of-gamut colors on softproof\n", SW); + + fprintf(stderr, "\n"); + + fprintf(stderr, "%ck<0..400> - Ink-limiting in %% (CMYK only)\n", SW); + fprintf(stderr, "\n"); + fprintf(stderr, "%ch<0,1,2> - More help\n", SW); + fprintf(stderr, "\n"); + fprintf(stderr, "You can also use '*Lab' and '*XYZ' as predefined, built-in\n"); + fprintf(stderr, "profiles for CIE L*a*b* and XYZ color spaces.\n"); + + break; + + case 1: + + + fprintf(stderr, "Examples:\n\n" + "To color correct from scanner to sRGB:\n" + "\ttifficc %ciscanner.icm in.tif out.tif\n" + "To convert from monitor1 to monitor2:\n" + "\ttifficc %cimon1.icm %comon2.icm in.tif out.tif\n" + "To make a CMYK separation:\n" + "\ttifficc %coprinter.icm inrgb.tif outcmyk.tif\n" + "To recover sRGB from a CMYK separation:\n" + "\ttifficc %ciprinter.icm incmyk.tif outrgb.tif\n" + "To convert from CIELab TIFF to sRGB\n" + "\ttifficc %ci*Lab in.tif out.tif\n\n", + SW, SW, SW, SW, SW, SW); + break; + + case 2: + + + fprintf(stderr, "This program is intended to be a demo of the little cms\n" + "engine. Both lcms and this program are freeware. You can\n" + "obtain both in source code at http://www.littlecms.com\n" + "For suggestions, comments, bug reports etc. send mail to\n" + "info@littlecms.com\n\n"); + + break; + } + + fflush(stderr); + exit(0); +} + + +// The toggles stuff + +static +void HandleSwitches(int argc, char *argv[]) +{ + int s; + + while ((s=xgetopt(argc,argv,"aAeEbBw:W:nNvVGgh:H:i:I:o:O:P:p:t:T:c:C:l:L:M:m:K:k:S:s:D:d:")) != EOF) { + + switch (s) + { + + case 'a': + case 'A': + StoreAsAlpha = TRUE; + break; + case 'b': + case 'B': + BlackWhiteCompensation = TRUE; + break; + + case 'c': + case 'C': + PrecalcMode = atoi(xoptarg); + if (PrecalcMode < 0 || PrecalcMode > 3) + FatalError("Unknown precalc mode '%d'", PrecalcMode); + break; + + case 'd': + case 'D': ObserverAdaptationState = atof(xoptarg); + if (ObserverAdaptationState != 0 && + ObserverAdaptationState != 1.0) + Warning("Adaptation states other that 0 or 1 are not yet implemented"); + break; + + case 'e': + case 'E': + EmbedProfile = TRUE; + break; + + case 'g': + case 'G': + GamutCheck = TRUE; + break; + + case 'v': + case 'V': + Verbose = TRUE; + break; + + case 'i': + case 'I': + if (lIsDeviceLink) + FatalError("Device-link already specified"); + + cInpProf = xoptarg; + break; + + case 'o': + case 'O': + if (lIsDeviceLink) + FatalError("Device-link already specified"); + + cOutProf = xoptarg; + break; + + case 'l': + case 'L': + if (cInpProf != NULL || cOutProf != NULL) + FatalError("input/output profiles already specified"); + + cInpProf = xoptarg; + lIsDeviceLink = TRUE; + break; + + case 'p': + case 'P': + cProofing = xoptarg; + break; + + case 't': + case 'T': + Intent = atoi(xoptarg); + break; + + case 'm': + case 'M': + ProofingIntent = atoi(xoptarg); + break; + + case 'N': + case 'n': + IgnoreEmbedded = TRUE; + break; + + case 'W': + case 'w': + Width = atoi(xoptarg); + if (Width != 8 && Width != 16 && Width != 32) + FatalError("Only 8, 16 and 32 bps are supported"); + break; + + + case 'k': + case 'K': + InkLimit = atof(xoptarg); + if (InkLimit < 0.0 || InkLimit > 400.0) + FatalError("Ink limit must be 0%%..400%%"); + break; + + + case 's': + case 'S': SaveEmbedded = xoptarg; + break; + + case 'H': + case 'h': { + + int a = atoi(xoptarg); + Help(a); + } + break; + + default: + + FatalError("Unknown option - run without args to see valid ones"); + } + + } +} + + +// The main sink + +int main(int argc, char* argv[]) +{ + TIFF *in, *out; + + cmsPlugin(&TiffLabPlugin); + + InitUtils("tifficc"); + + HandleSwitches(argc, argv); + + if ((argc - xoptind) != 2) { + + Help(0); + } + + + TIFFSetErrorHandler(ConsoleErrorHandler); + TIFFSetWarningHandler(ConsoleWarningHandler); + + in = TIFFOpen(argv[xoptind], "r"); + if (in == NULL) FatalError("Unable to open '%s'", argv[xoptind]); + + out = TIFFOpen(argv[xoptind+1], "w"); + + if (out == NULL) { + + TIFFClose(in); + FatalError("Unable to write '%s'", argv[xoptind+1]); + } + + do { + + TransformImage(in, out, cInpProf); + + + } while (TIFFReadDirectory(in)); + + + if (Verbose) { fprintf(stdout, "\n"); fflush(stdout); } + + TIFFClose(in); + TIFFClose(out); + + return 0; +} + |