summaryrefslogtreecommitdiff
path: root/tiff/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tiff/tools')
-rw-r--r--tiff/tools/Jamfile20
-rw-r--r--tiff/tools/Makefile.am145
-rw-r--r--tiff/tools/Makefile.in876
-rw-r--r--tiff/tools/Makefile.vc51
-rw-r--r--tiff/tools/bmp2tiff.c850
-rw-r--r--tiff/tools/fax2ps.c446
-rw-r--r--tiff/tools/fax2tiff.c465
-rw-r--r--tiff/tools/gif2tiff.c522
-rw-r--r--tiff/tools/pal2rgb.c431
-rw-r--r--tiff/tools/ppm2tiff.c362
-rw-r--r--tiff/tools/ras2tiff.c306
-rw-r--r--tiff/tools/rasterfile.h49
-rw-r--r--tiff/tools/raw2tiff.c647
-rw-r--r--tiff/tools/rgb2ycbcr.c382
-rw-r--r--tiff/tools/sgi2tiff.c335
-rw-r--r--tiff/tools/sgisv.c316
-rw-r--r--tiff/tools/thumbnail.c639
-rw-r--r--tiff/tools/tiff2bw.c467
-rw-r--r--tiff/tools/tiff2pdf.c5405
-rw-r--r--tiff/tools/tiff2ps.c2370
-rw-r--r--tiff/tools/tiff2rgba.c548
-rw-r--r--tiff/tools/tiffcmp.c640
-rw-r--r--tiff/tools/tiffcp.c1770
-rw-r--r--tiff/tools/tiffcrop.c9012
-rw-r--r--tiff/tools/tiffdither.c332
-rw-r--r--tiff/tools/tiffdump.c785
-rw-r--r--tiff/tools/tiffgt.c462
-rw-r--r--tiff/tools/tiffinfo.c456
-rw-r--r--tiff/tools/tiffmedian.c902
-rw-r--r--tiff/tools/tiffset.c325
-rw-r--r--tiff/tools/tiffsplit.c297
-rw-r--r--tiff/tools/ycbcr.c168
32 files changed, 30781 insertions, 0 deletions
diff --git a/tiff/tools/Jamfile b/tiff/tools/Jamfile
new file mode 100644
index 0000000..99f1307
--- /dev/null
+++ b/tiff/tools/Jamfile
@@ -0,0 +1,20 @@
+
+PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+#PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ;
+
+HDRS = .. ../libtiff ;
+
+LINKLIBS = ../libtiff ../libport ../$(JPEGLIB) ;
+
+Main tiffcp : tiffcp.c ;
+
+Main tiff2bw : tiff2bw.c ;
+
+Main tiffset : tiffset.c ;
+
+Main tiffdump : tiffdump.c ;
+
+Main tiffinfo : tiffinfo.c ;
+
+Main tiffsplit : tiffsplit.c ;
diff --git a/tiff/tools/Makefile.am b/tiff/tools/Makefile.am
new file mode 100644
index 0000000..0f3be93
--- /dev/null
+++ b/tiff/tools/Makefile.am
@@ -0,0 +1,145 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+LIBPORT = $(top_builddir)/port/libport.la
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+
+EXTRA_DIST = Makefile.vc
+
+bin_PROGRAMS = \
+ bmp2tiff \
+ fax2ps \
+ fax2tiff \
+ gif2tiff \
+ pal2rgb \
+ ppm2tiff \
+ ras2tiff \
+ raw2tiff \
+ rgb2ycbcr \
+ thumbnail \
+ tiff2bw \
+ tiff2pdf \
+ tiff2ps \
+ tiff2rgba \
+ tiffcmp \
+ tiffcp \
+ tiffcrop \
+ tiffdither \
+ tiffdump \
+ tiffinfo \
+ tiffmedian \
+ tiffset \
+ tiffsplit
+if HAVE_OPENGL
+bin_PROGRAMS += tiffgt
+endif
+
+EXTRA_PROGRAMS = sgi2tiff sgisv ycbcr
+
+if HAVE_RPATH
+AM_LDFLAGS = $(LIBDIR)
+endif
+
+bmp2tiff_SOURCES = bmp2tiff.c
+bmp2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+fax2ps_SOURCES = fax2ps.c
+fax2ps_LDADD = $(LIBTIFF) $(LIBPORT)
+
+fax2tiff_SOURCES = fax2tiff.c
+fax2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+gif2tiff_SOURCES = gif2tiff.c
+gif2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+pal2rgb_SOURCES = pal2rgb.c
+pal2rgb_LDADD = $(LIBTIFF) $(LIBPORT)
+
+ppm2tiff_SOURCES = ppm2tiff.c
+ppm2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+ras2tiff_SOURCES = ras2tiff.c rasterfile.h
+ras2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+raw2tiff_SOURCES = raw2tiff.c
+raw2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+rgb2ycbcr_SOURCES = rgb2ycbcr.c
+rgb2ycbcr_LDADD = $(LIBTIFF) $(LIBPORT)
+
+thumbnail_SOURCES = thumbnail.c
+thumbnail_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiff2bw_SOURCES = tiff2bw.c
+tiff2bw_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiff2pdf_SOURCES = tiff2pdf.c
+tiff2pdf_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiff2ps_SOURCES = tiff2ps.c
+tiff2ps_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiff2rgba_SOURCES = tiff2rgba.c
+tiff2rgba_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffcmp_SOURCES = tiffcmp.c
+tiffcmp_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffcp_SOURCES = tiffcp.c
+tiffcp_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffcrop_SOURCES = tiffcrop.c
+tiffcrop_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffdither_SOURCES = tiffdither.c
+tiffdither_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffdump_SOURCES = tiffdump.c
+tiffdump_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffinfo_SOURCES = tiffinfo.c
+tiffinfo_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffmedian_SOURCES = tiffmedian.c
+tiffmedian_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffset_SOURCES = tiffset.c
+tiffset_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffsplit_SOURCES = tiffsplit.c
+tiffsplit_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffgt_SOURCES = tiffgt.c
+tiffgt_CFLAGS = $(CFLAGS) $(GLUT_CFLAGS) $(AM_CFLAGS)
+tiffgt_LDADD = $(LIBTIFF) $(LIBPORT) $(X_LIBS) $(GLUT_LIBS)
+
+INCLUDES = -I../libtiff -I$(top_srcdir)/libtiff
+
+echo:
+ (echo $(CFLAGS))
+ (echo $(tiffgt_CFLAGS))
+ (echo $(GL_CFLAGS))
+ (echo $(GLU_CFLAGS))
+ (echo $(GLUT_CFLAGS))
diff --git a/tiff/tools/Makefile.in b/tiff/tools/Makefile.in
new file mode 100644
index 0000000..7682ca4
--- /dev/null
+++ b/tiff/tools/Makefile.in
@@ -0,0 +1,876 @@
+# Makefile.in generated by automake 1.11 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@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+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@
+target_triplet = @target@
+bin_PROGRAMS = bmp2tiff$(EXEEXT) fax2ps$(EXEEXT) fax2tiff$(EXEEXT) \
+ gif2tiff$(EXEEXT) pal2rgb$(EXEEXT) ppm2tiff$(EXEEXT) \
+ ras2tiff$(EXEEXT) raw2tiff$(EXEEXT) rgb2ycbcr$(EXEEXT) \
+ thumbnail$(EXEEXT) tiff2bw$(EXEEXT) tiff2pdf$(EXEEXT) \
+ tiff2ps$(EXEEXT) tiff2rgba$(EXEEXT) tiffcmp$(EXEEXT) \
+ tiffcp$(EXEEXT) tiffcrop$(EXEEXT) tiffdither$(EXEEXT) \
+ tiffdump$(EXEEXT) tiffinfo$(EXEEXT) tiffmedian$(EXEEXT) \
+ tiffset$(EXEEXT) tiffsplit$(EXEEXT) $(am__EXEEXT_1)
+@HAVE_OPENGL_TRUE@am__append_1 = tiffgt
+EXTRA_PROGRAMS = sgi2tiff$(EXEEXT) sgisv$(EXEEXT) ycbcr$(EXEEXT)
+subdir = tools
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_OPENGL_TRUE@am__EXEEXT_1 = tiffgt$(EXEEXT)
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_bmp2tiff_OBJECTS = bmp2tiff.$(OBJEXT)
+bmp2tiff_OBJECTS = $(am_bmp2tiff_OBJECTS)
+bmp2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+am_fax2ps_OBJECTS = fax2ps.$(OBJEXT)
+fax2ps_OBJECTS = $(am_fax2ps_OBJECTS)
+fax2ps_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_fax2tiff_OBJECTS = fax2tiff.$(OBJEXT)
+fax2tiff_OBJECTS = $(am_fax2tiff_OBJECTS)
+fax2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_gif2tiff_OBJECTS = gif2tiff.$(OBJEXT)
+gif2tiff_OBJECTS = $(am_gif2tiff_OBJECTS)
+gif2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_pal2rgb_OBJECTS = pal2rgb.$(OBJEXT)
+pal2rgb_OBJECTS = $(am_pal2rgb_OBJECTS)
+pal2rgb_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_ppm2tiff_OBJECTS = ppm2tiff.$(OBJEXT)
+ppm2tiff_OBJECTS = $(am_ppm2tiff_OBJECTS)
+ppm2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_ras2tiff_OBJECTS = ras2tiff.$(OBJEXT)
+ras2tiff_OBJECTS = $(am_ras2tiff_OBJECTS)
+ras2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_raw2tiff_OBJECTS = raw2tiff.$(OBJEXT)
+raw2tiff_OBJECTS = $(am_raw2tiff_OBJECTS)
+raw2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_rgb2ycbcr_OBJECTS = rgb2ycbcr.$(OBJEXT)
+rgb2ycbcr_OBJECTS = $(am_rgb2ycbcr_OBJECTS)
+rgb2ycbcr_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+sgi2tiff_SOURCES = sgi2tiff.c
+sgi2tiff_OBJECTS = sgi2tiff.$(OBJEXT)
+sgi2tiff_LDADD = $(LDADD)
+sgisv_SOURCES = sgisv.c
+sgisv_OBJECTS = sgisv.$(OBJEXT)
+sgisv_LDADD = $(LDADD)
+am_thumbnail_OBJECTS = thumbnail.$(OBJEXT)
+thumbnail_OBJECTS = $(am_thumbnail_OBJECTS)
+thumbnail_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiff2bw_OBJECTS = tiff2bw.$(OBJEXT)
+tiff2bw_OBJECTS = $(am_tiff2bw_OBJECTS)
+tiff2bw_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiff2pdf_OBJECTS = tiff2pdf.$(OBJEXT)
+tiff2pdf_OBJECTS = $(am_tiff2pdf_OBJECTS)
+tiff2pdf_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiff2ps_OBJECTS = tiff2ps.$(OBJEXT)
+tiff2ps_OBJECTS = $(am_tiff2ps_OBJECTS)
+tiff2ps_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiff2rgba_OBJECTS = tiff2rgba.$(OBJEXT)
+tiff2rgba_OBJECTS = $(am_tiff2rgba_OBJECTS)
+tiff2rgba_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffcmp_OBJECTS = tiffcmp.$(OBJEXT)
+tiffcmp_OBJECTS = $(am_tiffcmp_OBJECTS)
+tiffcmp_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffcp_OBJECTS = tiffcp.$(OBJEXT)
+tiffcp_OBJECTS = $(am_tiffcp_OBJECTS)
+tiffcp_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffcrop_OBJECTS = tiffcrop.$(OBJEXT)
+tiffcrop_OBJECTS = $(am_tiffcrop_OBJECTS)
+tiffcrop_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffdither_OBJECTS = tiffdither.$(OBJEXT)
+tiffdither_OBJECTS = $(am_tiffdither_OBJECTS)
+tiffdither_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffdump_OBJECTS = tiffdump.$(OBJEXT)
+tiffdump_OBJECTS = $(am_tiffdump_OBJECTS)
+tiffdump_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffgt_OBJECTS = tiffgt-tiffgt.$(OBJEXT)
+tiffgt_OBJECTS = $(am_tiffgt_OBJECTS)
+am__DEPENDENCIES_1 =
+tiffgt_DEPENDENCIES = $(LIBTIFF) $(LIBPORT) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+tiffgt_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(tiffgt_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+am_tiffinfo_OBJECTS = tiffinfo.$(OBJEXT)
+tiffinfo_OBJECTS = $(am_tiffinfo_OBJECTS)
+tiffinfo_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffmedian_OBJECTS = tiffmedian.$(OBJEXT)
+tiffmedian_OBJECTS = $(am_tiffmedian_OBJECTS)
+tiffmedian_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffset_OBJECTS = tiffset.$(OBJEXT)
+tiffset_OBJECTS = $(am_tiffset_OBJECTS)
+tiffset_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffsplit_OBJECTS = tiffsplit.$(OBJEXT)
+tiffsplit_OBJECTS = $(am_tiffsplit_OBJECTS)
+tiffsplit_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+ycbcr_SOURCES = ycbcr.c
+ycbcr_OBJECTS = ycbcr.$(OBJEXT)
+ycbcr_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libtiff
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(bmp2tiff_SOURCES) $(fax2ps_SOURCES) $(fax2tiff_SOURCES) \
+ $(gif2tiff_SOURCES) $(pal2rgb_SOURCES) $(ppm2tiff_SOURCES) \
+ $(ras2tiff_SOURCES) $(raw2tiff_SOURCES) $(rgb2ycbcr_SOURCES) \
+ sgi2tiff.c sgisv.c $(thumbnail_SOURCES) $(tiff2bw_SOURCES) \
+ $(tiff2pdf_SOURCES) $(tiff2ps_SOURCES) $(tiff2rgba_SOURCES) \
+ $(tiffcmp_SOURCES) $(tiffcp_SOURCES) $(tiffcrop_SOURCES) \
+ $(tiffdither_SOURCES) $(tiffdump_SOURCES) $(tiffgt_SOURCES) \
+ $(tiffinfo_SOURCES) $(tiffmedian_SOURCES) $(tiffset_SOURCES) \
+ $(tiffsplit_SOURCES) ycbcr.c
+DIST_SOURCES = $(bmp2tiff_SOURCES) $(fax2ps_SOURCES) \
+ $(fax2tiff_SOURCES) $(gif2tiff_SOURCES) $(pal2rgb_SOURCES) \
+ $(ppm2tiff_SOURCES) $(ras2tiff_SOURCES) $(raw2tiff_SOURCES) \
+ $(rgb2ycbcr_SOURCES) sgi2tiff.c sgisv.c $(thumbnail_SOURCES) \
+ $(tiff2bw_SOURCES) $(tiff2pdf_SOURCES) $(tiff2ps_SOURCES) \
+ $(tiff2rgba_SOURCES) $(tiffcmp_SOURCES) $(tiffcp_SOURCES) \
+ $(tiffcrop_SOURCES) $(tiffdither_SOURCES) $(tiffdump_SOURCES) \
+ $(tiffgt_SOURCES) $(tiffinfo_SOURCES) $(tiffmedian_SOURCES) \
+ $(tiffset_SOURCES) $(tiffsplit_SOURCES) ycbcr.c
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+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@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+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@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+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@
+includedir = @includedir@
+infodir = @infodir@
+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 = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+LIBPORT = $(top_builddir)/port/libport.la
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+EXTRA_DIST = Makefile.vc
+@HAVE_RPATH_TRUE@AM_LDFLAGS = $(LIBDIR)
+bmp2tiff_SOURCES = bmp2tiff.c
+bmp2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+fax2ps_SOURCES = fax2ps.c
+fax2ps_LDADD = $(LIBTIFF) $(LIBPORT)
+fax2tiff_SOURCES = fax2tiff.c
+fax2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+gif2tiff_SOURCES = gif2tiff.c
+gif2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+pal2rgb_SOURCES = pal2rgb.c
+pal2rgb_LDADD = $(LIBTIFF) $(LIBPORT)
+ppm2tiff_SOURCES = ppm2tiff.c
+ppm2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+ras2tiff_SOURCES = ras2tiff.c rasterfile.h
+ras2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+raw2tiff_SOURCES = raw2tiff.c
+raw2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+rgb2ycbcr_SOURCES = rgb2ycbcr.c
+rgb2ycbcr_LDADD = $(LIBTIFF) $(LIBPORT)
+thumbnail_SOURCES = thumbnail.c
+thumbnail_LDADD = $(LIBTIFF) $(LIBPORT)
+tiff2bw_SOURCES = tiff2bw.c
+tiff2bw_LDADD = $(LIBTIFF) $(LIBPORT)
+tiff2pdf_SOURCES = tiff2pdf.c
+tiff2pdf_LDADD = $(LIBTIFF) $(LIBPORT)
+tiff2ps_SOURCES = tiff2ps.c
+tiff2ps_LDADD = $(LIBTIFF) $(LIBPORT)
+tiff2rgba_SOURCES = tiff2rgba.c
+tiff2rgba_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffcmp_SOURCES = tiffcmp.c
+tiffcmp_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffcp_SOURCES = tiffcp.c
+tiffcp_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffcrop_SOURCES = tiffcrop.c
+tiffcrop_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffdither_SOURCES = tiffdither.c
+tiffdither_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffdump_SOURCES = tiffdump.c
+tiffdump_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffinfo_SOURCES = tiffinfo.c
+tiffinfo_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffmedian_SOURCES = tiffmedian.c
+tiffmedian_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffset_SOURCES = tiffset.c
+tiffset_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffsplit_SOURCES = tiffsplit.c
+tiffsplit_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffgt_SOURCES = tiffgt.c
+tiffgt_CFLAGS = $(CFLAGS) $(GLUT_CFLAGS) $(AM_CFLAGS)
+tiffgt_LDADD = $(LIBTIFF) $(LIBPORT) $(X_LIBS) $(GLUT_LIBS)
+INCLUDES = -I../libtiff -I$(top_srcdir)/libtiff
+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 tools/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tools/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-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+bmp2tiff$(EXEEXT): $(bmp2tiff_OBJECTS) $(bmp2tiff_DEPENDENCIES)
+ @rm -f bmp2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bmp2tiff_OBJECTS) $(bmp2tiff_LDADD) $(LIBS)
+fax2ps$(EXEEXT): $(fax2ps_OBJECTS) $(fax2ps_DEPENDENCIES)
+ @rm -f fax2ps$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(fax2ps_OBJECTS) $(fax2ps_LDADD) $(LIBS)
+fax2tiff$(EXEEXT): $(fax2tiff_OBJECTS) $(fax2tiff_DEPENDENCIES)
+ @rm -f fax2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(fax2tiff_OBJECTS) $(fax2tiff_LDADD) $(LIBS)
+gif2tiff$(EXEEXT): $(gif2tiff_OBJECTS) $(gif2tiff_DEPENDENCIES)
+ @rm -f gif2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gif2tiff_OBJECTS) $(gif2tiff_LDADD) $(LIBS)
+pal2rgb$(EXEEXT): $(pal2rgb_OBJECTS) $(pal2rgb_DEPENDENCIES)
+ @rm -f pal2rgb$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(pal2rgb_OBJECTS) $(pal2rgb_LDADD) $(LIBS)
+ppm2tiff$(EXEEXT): $(ppm2tiff_OBJECTS) $(ppm2tiff_DEPENDENCIES)
+ @rm -f ppm2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ppm2tiff_OBJECTS) $(ppm2tiff_LDADD) $(LIBS)
+ras2tiff$(EXEEXT): $(ras2tiff_OBJECTS) $(ras2tiff_DEPENDENCIES)
+ @rm -f ras2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ras2tiff_OBJECTS) $(ras2tiff_LDADD) $(LIBS)
+raw2tiff$(EXEEXT): $(raw2tiff_OBJECTS) $(raw2tiff_DEPENDENCIES)
+ @rm -f raw2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(raw2tiff_OBJECTS) $(raw2tiff_LDADD) $(LIBS)
+rgb2ycbcr$(EXEEXT): $(rgb2ycbcr_OBJECTS) $(rgb2ycbcr_DEPENDENCIES)
+ @rm -f rgb2ycbcr$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rgb2ycbcr_OBJECTS) $(rgb2ycbcr_LDADD) $(LIBS)
+sgi2tiff$(EXEEXT): $(sgi2tiff_OBJECTS) $(sgi2tiff_DEPENDENCIES)
+ @rm -f sgi2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sgi2tiff_OBJECTS) $(sgi2tiff_LDADD) $(LIBS)
+sgisv$(EXEEXT): $(sgisv_OBJECTS) $(sgisv_DEPENDENCIES)
+ @rm -f sgisv$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sgisv_OBJECTS) $(sgisv_LDADD) $(LIBS)
+thumbnail$(EXEEXT): $(thumbnail_OBJECTS) $(thumbnail_DEPENDENCIES)
+ @rm -f thumbnail$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(thumbnail_OBJECTS) $(thumbnail_LDADD) $(LIBS)
+tiff2bw$(EXEEXT): $(tiff2bw_OBJECTS) $(tiff2bw_DEPENDENCIES)
+ @rm -f tiff2bw$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff2bw_OBJECTS) $(tiff2bw_LDADD) $(LIBS)
+tiff2pdf$(EXEEXT): $(tiff2pdf_OBJECTS) $(tiff2pdf_DEPENDENCIES)
+ @rm -f tiff2pdf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff2pdf_OBJECTS) $(tiff2pdf_LDADD) $(LIBS)
+tiff2ps$(EXEEXT): $(tiff2ps_OBJECTS) $(tiff2ps_DEPENDENCIES)
+ @rm -f tiff2ps$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff2ps_OBJECTS) $(tiff2ps_LDADD) $(LIBS)
+tiff2rgba$(EXEEXT): $(tiff2rgba_OBJECTS) $(tiff2rgba_DEPENDENCIES)
+ @rm -f tiff2rgba$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff2rgba_OBJECTS) $(tiff2rgba_LDADD) $(LIBS)
+tiffcmp$(EXEEXT): $(tiffcmp_OBJECTS) $(tiffcmp_DEPENDENCIES)
+ @rm -f tiffcmp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffcmp_OBJECTS) $(tiffcmp_LDADD) $(LIBS)
+tiffcp$(EXEEXT): $(tiffcp_OBJECTS) $(tiffcp_DEPENDENCIES)
+ @rm -f tiffcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffcp_OBJECTS) $(tiffcp_LDADD) $(LIBS)
+tiffcrop$(EXEEXT): $(tiffcrop_OBJECTS) $(tiffcrop_DEPENDENCIES)
+ @rm -f tiffcrop$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffcrop_OBJECTS) $(tiffcrop_LDADD) $(LIBS)
+tiffdither$(EXEEXT): $(tiffdither_OBJECTS) $(tiffdither_DEPENDENCIES)
+ @rm -f tiffdither$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffdither_OBJECTS) $(tiffdither_LDADD) $(LIBS)
+tiffdump$(EXEEXT): $(tiffdump_OBJECTS) $(tiffdump_DEPENDENCIES)
+ @rm -f tiffdump$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffdump_OBJECTS) $(tiffdump_LDADD) $(LIBS)
+tiffgt$(EXEEXT): $(tiffgt_OBJECTS) $(tiffgt_DEPENDENCIES)
+ @rm -f tiffgt$(EXEEXT)
+ $(AM_V_CCLD)$(tiffgt_LINK) $(tiffgt_OBJECTS) $(tiffgt_LDADD) $(LIBS)
+tiffinfo$(EXEEXT): $(tiffinfo_OBJECTS) $(tiffinfo_DEPENDENCIES)
+ @rm -f tiffinfo$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffinfo_OBJECTS) $(tiffinfo_LDADD) $(LIBS)
+tiffmedian$(EXEEXT): $(tiffmedian_OBJECTS) $(tiffmedian_DEPENDENCIES)
+ @rm -f tiffmedian$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffmedian_OBJECTS) $(tiffmedian_LDADD) $(LIBS)
+tiffset$(EXEEXT): $(tiffset_OBJECTS) $(tiffset_DEPENDENCIES)
+ @rm -f tiffset$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffset_OBJECTS) $(tiffset_LDADD) $(LIBS)
+tiffsplit$(EXEEXT): $(tiffsplit_OBJECTS) $(tiffsplit_DEPENDENCIES)
+ @rm -f tiffsplit$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffsplit_OBJECTS) $(tiffsplit_LDADD) $(LIBS)
+ycbcr$(EXEEXT): $(ycbcr_OBJECTS) $(ycbcr_DEPENDENCIES)
+ @rm -f ycbcr$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ycbcr_OBJECTS) $(ycbcr_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bmp2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fax2ps.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fax2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gif2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pal2rgb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppm2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ras2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rgb2ycbcr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgi2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgisv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thumbnail.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff2bw.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff2pdf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff2ps.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff2rgba.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffcmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffcp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffcrop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffdither.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffdump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffgt-tiffgt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffmedian.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffset.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffsplit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ycbcr.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@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@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@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@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@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 $@ $<
+
+tiffgt-tiffgt.o: tiffgt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tiffgt_CFLAGS) $(CFLAGS) -MT tiffgt-tiffgt.o -MD -MP -MF $(DEPDIR)/tiffgt-tiffgt.Tpo -c -o tiffgt-tiffgt.o `test -f 'tiffgt.c' || echo '$(srcdir)/'`tiffgt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tiffgt-tiffgt.Tpo $(DEPDIR)/tiffgt-tiffgt.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tiffgt.c' object='tiffgt-tiffgt.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) $(tiffgt_CFLAGS) $(CFLAGS) -c -o tiffgt-tiffgt.o `test -f 'tiffgt.c' || echo '$(srcdir)/'`tiffgt.c
+
+tiffgt-tiffgt.obj: tiffgt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tiffgt_CFLAGS) $(CFLAGS) -MT tiffgt-tiffgt.obj -MD -MP -MF $(DEPDIR)/tiffgt-tiffgt.Tpo -c -o tiffgt-tiffgt.obj `if test -f 'tiffgt.c'; then $(CYGPATH_W) 'tiffgt.c'; else $(CYGPATH_W) '$(srcdir)/tiffgt.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tiffgt-tiffgt.Tpo $(DEPDIR)/tiffgt-tiffgt.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tiffgt.c' object='tiffgt-tiffgt.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) $(tiffgt_CFLAGS) $(CFLAGS) -c -o tiffgt-tiffgt.obj `if test -f 'tiffgt.c'; then $(CYGPATH_W) 'tiffgt.c'; else $(CYGPATH_W) '$(srcdir)/tiffgt.c'; fi`
+
+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 $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; 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-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-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-binPROGRAMS
+
+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-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.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-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am 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-binPROGRAMS
+
+
+echo:
+ (echo $(CFLAGS))
+ (echo $(tiffgt_CFLAGS))
+ (echo $(GL_CFLAGS))
+ (echo $(GLU_CFLAGS))
+ (echo $(GLUT_CFLAGS))
+
+# 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/tiff/tools/Makefile.vc b/tiff/tools/Makefile.vc
new file mode 100644
index 0000000..ea9e859
--- /dev/null
+++ b/tiff/tools/Makefile.vc
@@ -0,0 +1,51 @@
+# $Id: Makefile.vc,v 1.13 2007/02/24 15:26:09 dron Exp $
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+# Makefile for MS Visual C and Watcom C compilers.
+#
+# To build:
+# C:\libtiff\tools> nmake /f makefile.vc
+
+!INCLUDE ..\nmake.opt
+
+TARGETS = bmp2tiff.exe tiffinfo.exe tiffdump.exe fax2tiff.exe \
+ fax2ps.exe gif2tiff.exe pal2rgb.exe ppm2tiff.exe \
+ rgb2ycbcr.exe thumbnail.exe ras2tiff.exe raw2tiff.exe \
+ tiff2bw.exe tiff2rgba.exe tiff2pdf.exe tiff2ps.exe \
+ tiffcmp.exe tiffcp.exe tiffcrop.exe tiffdither.exe \
+ tiffmedian.exe tiffset.exe tiffsplit.exe
+
+INCL = -I..\libtiff
+LIBS = $(LIBS) ..\port\libport.lib ..\libtiff\libtiff.lib
+
+default: $(TARGETS)
+
+.c.exe:
+ $(CC) $(CFLAGS) $*.c $(EXTRA_OBJ) $(LIBS)
+
+tiffgt.exe:
+ $(CC) $(CFLAGS) tiffgt.c $(EXTRA_OBJ) $(LIBS)
+
+clean:
+ -del *.exe
+ -del *.obj
diff --git a/tiff/tools/bmp2tiff.c b/tiff/tools/bmp2tiff.c
new file mode 100644
index 0000000..02b83b3
--- /dev/null
+++ b/tiff/tools/bmp2tiff.c
@@ -0,0 +1,850 @@
+/* $Id: bmp2tiff.c,v 1.20.2.1 2010-06-08 18:50:43 bfriesen Exp $
+ *
+ * Project: libtiff tools
+ * Purpose: Convert Windows BMP files in TIFF.
+ * Author: Andrey Kiselev, dron@ak4719.spb.edu
+ *
+ ******************************************************************************
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+enum BMPType
+{
+ BMPT_WIN4, /* BMP used in Windows 3.0/NT 3.51/95 */
+ BMPT_WIN5, /* BMP used in Windows NT 4.0/98/Me/2000/XP */
+ BMPT_OS21, /* BMP used in OS/2 PM 1.x */
+ BMPT_OS22 /* BMP used in OS/2 PM 2.x */
+};
+
+/*
+ * Bitmap file consists of a BMPFileHeader structure followed by a
+ * BMPInfoHeader structure. An array of BMPColorEntry structures (also called
+ * a colour table) follows the bitmap information header structure. The colour
+ * table is followed by a second array of indexes into the colour table (the
+ * actual bitmap data). Data may be comressed, for 4-bpp and 8-bpp used RLE
+ * compression.
+ *
+ * +---------------------+
+ * | BMPFileHeader |
+ * +---------------------+
+ * | BMPInfoHeader |
+ * +---------------------+
+ * | BMPColorEntry array |
+ * +---------------------+
+ * | Colour-index array |
+ * +---------------------+
+ *
+ * All numbers stored in Intel order with least significant byte first.
+ */
+
+enum BMPComprMethod
+{
+ BMPC_RGB = 0L, /* Uncompressed */
+ BMPC_RLE8 = 1L, /* RLE for 8 bpp images */
+ BMPC_RLE4 = 2L, /* RLE for 4 bpp images */
+ BMPC_BITFIELDS = 3L, /* Bitmap is not compressed and the colour table
+ * consists of three DWORD color masks that specify
+ * the red, green, and blue components of each
+ * pixel. This is valid when used with
+ * 16- and 32-bpp bitmaps. */
+ BMPC_JPEG = 4L, /* Indicates that the image is a JPEG image. */
+ BMPC_PNG = 5L /* Indicates that the image is a PNG image. */
+};
+
+enum BMPLCSType /* Type of logical color space. */
+{
+ BMPLT_CALIBRATED_RGB = 0, /* This value indicates that endpoints and
+ * gamma values are given in the appropriate
+ * fields. */
+ BMPLT_DEVICE_RGB = 1,
+ BMPLT_DEVICE_CMYK = 2
+};
+
+typedef struct
+{
+ int32 iCIEX;
+ int32 iCIEY;
+ int32 iCIEZ;
+} BMPCIEXYZ;
+
+typedef struct /* This structure contains the x, y, and z */
+{ /* coordinates of the three colors that */
+ /* correspond */
+ BMPCIEXYZ iCIERed; /* to the red, green, and blue endpoints for */
+ BMPCIEXYZ iCIEGreen; /* a specified logical color space. */
+ BMPCIEXYZ iCIEBlue;
+} BMPCIEXYZTriple;
+
+typedef struct
+{
+ char bType[2]; /* Signature "BM" */
+ uint32 iSize; /* Size in bytes of the bitmap file. Should
+ * always be ignored while reading because
+ * of error in Windows 3.0 SDK's description
+ * of this field */
+ uint16 iReserved1; /* Reserved, set as 0 */
+ uint16 iReserved2; /* Reserved, set as 0 */
+ uint32 iOffBits; /* Offset of the image from file start in bytes */
+} BMPFileHeader;
+
+/* File header size in bytes: */
+const int BFH_SIZE = 14;
+
+typedef struct
+{
+ uint32 iSize; /* Size of BMPInfoHeader structure in bytes.
+ * Should be used to determine start of the
+ * colour table */
+ int32 iWidth; /* Image width */
+ int32 iHeight; /* Image height. If positive, image has bottom
+ * left origin, if negative --- top left. */
+ int16 iPlanes; /* Number of image planes (must be set to 1) */
+ int16 iBitCount; /* Number of bits per pixel (1, 4, 8, 16, 24
+ * or 32). If 0 then the number of bits per
+ * pixel is specified or is implied by the
+ * JPEG or PNG format. */
+ uint32 iCompression; /* Compression method */
+ uint32 iSizeImage; /* Size of uncomressed image in bytes. May
+ * be 0 for BMPC_RGB bitmaps. If iCompression
+ * is BI_JPEG or BI_PNG, iSizeImage indicates
+ * the size of the JPEG or PNG image buffer. */
+ int32 iXPelsPerMeter; /* X resolution, pixels per meter (0 if not used) */
+ int32 iYPelsPerMeter; /* Y resolution, pixels per meter (0 if not used) */
+ uint32 iClrUsed; /* Size of colour table. If 0, iBitCount should
+ * be used to calculate this value
+ * (1<<iBitCount). This value should be
+ * unsigned for proper shifting. */
+ int32 iClrImportant; /* Number of important colours. If 0, all
+ * colours are required */
+
+ /*
+ * Fields above should be used for bitmaps, compatible with Windows NT 3.51
+ * and earlier. Windows 98/Me, Windows 2000/XP introduces additional fields:
+ */
+
+ int32 iRedMask; /* Colour mask that specifies the red component
+ * of each pixel, valid only if iCompression
+ * is set to BI_BITFIELDS. */
+ int32 iGreenMask; /* The same for green component */
+ int32 iBlueMask; /* The same for blue component */
+ int32 iAlphaMask; /* Colour mask that specifies the alpha
+ * component of each pixel. */
+ uint32 iCSType; /* Colour space of the DIB. */
+ BMPCIEXYZTriple sEndpoints; /* This member is ignored unless the iCSType
+ * member specifies BMPLT_CALIBRATED_RGB. */
+ int32 iGammaRed; /* Toned response curve for red. This member
+ * is ignored unless color values are
+ * calibrated RGB values and iCSType is set to
+ * BMPLT_CALIBRATED_RGB. Specified
+ * in 16^16 format. */
+ int32 iGammaGreen; /* Toned response curve for green. */
+ int32 iGammaBlue; /* Toned response curve for blue. */
+} BMPInfoHeader;
+
+/*
+ * Info header size in bytes:
+ */
+const unsigned int BIH_WIN4SIZE = 40; /* for BMPT_WIN4 */
+const unsigned int BIH_WIN5SIZE = 57; /* for BMPT_WIN5 */
+const unsigned int BIH_OS21SIZE = 12; /* for BMPT_OS21 */
+const unsigned int BIH_OS22SIZE = 64; /* for BMPT_OS22 */
+
+/*
+ * We will use plain byte array instead of this structure, but declaration
+ * provided for reference
+ */
+typedef struct
+{
+ char bBlue;
+ char bGreen;
+ char bRed;
+ char bReserved; /* Must be 0 */
+} BMPColorEntry;
+
+static uint16 compression = (uint16) -1;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+static uint16 predictor = 0;
+
+static void usage(void);
+static int processCompressOptions(char*);
+static void rearrangePixels(char *, uint32, uint32);
+
+int
+main(int argc, char* argv[])
+{
+ uint32 width, length;
+ uint16 nbands = 1; /* number of bands in input image */
+ uint16 depth = 8; /* bits per pixel in input image */
+ uint32 rowsperstrip = (uint32) -1;
+ uint16 photometric = PHOTOMETRIC_MINISBLACK;
+ int fd = 0;
+ struct stat instat;
+ char *outfilename = NULL, *infilename = NULL;
+ TIFF *out = NULL;
+
+ BMPFileHeader file_hdr;
+ BMPInfoHeader info_hdr;
+ int bmp_type;
+ uint32 clr_tbl_size, n_clr_elems = 3;
+ unsigned char *clr_tbl;
+ unsigned short *red_tbl = NULL, *green_tbl = NULL, *blue_tbl = NULL;
+ uint32 row, clr;
+
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:r:o:h")) != -1) {
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'o':
+ outfilename = optarg;
+ break;
+ case 'h':
+ usage();
+ default:
+ break;
+ }
+ }
+
+ if (argc - optind < 2)
+ usage();
+
+ if (outfilename == NULL)
+ outfilename = argv[argc-1];
+ out = TIFFOpen(outfilename, "w");
+ if (out == NULL) {
+ TIFFError(infilename, "Cannot open file %s for output",
+ outfilename);
+ goto bad3;
+ }
+
+
+ while (optind < argc-1) {
+ infilename = argv[optind];
+ optind++;
+
+ fd = open(infilename, O_RDONLY|O_BINARY, 0);
+ if (fd < 0) {
+ TIFFError(infilename, "Cannot open input file");
+ return -1;
+ }
+
+ read(fd, file_hdr.bType, 2);
+ if(file_hdr.bType[0] != 'B' || file_hdr.bType[1] != 'M') {
+ TIFFError(infilename, "File is not BMP");
+ goto bad;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Read the BMPFileHeader. We need iOffBits value only */
+/* -------------------------------------------------------------------- */
+ lseek(fd, 10, SEEK_SET);
+ read(fd, &file_hdr.iOffBits, 4);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabLong(&file_hdr.iOffBits);
+#endif
+ fstat(fd, &instat);
+ file_hdr.iSize = instat.st_size;
+
+/* -------------------------------------------------------------------- */
+/* Read the BMPInfoHeader. */
+/* -------------------------------------------------------------------- */
+
+ lseek(fd, BFH_SIZE, SEEK_SET);
+ read(fd, &info_hdr.iSize, 4);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabLong(&info_hdr.iSize);
+#endif
+
+ if (info_hdr.iSize == BIH_WIN4SIZE)
+ bmp_type = BMPT_WIN4;
+ else if (info_hdr.iSize == BIH_OS21SIZE)
+ bmp_type = BMPT_OS21;
+ else if (info_hdr.iSize == BIH_OS22SIZE
+ || info_hdr.iSize == 16)
+ bmp_type = BMPT_OS22;
+ else
+ bmp_type = BMPT_WIN5;
+
+ if (bmp_type == BMPT_WIN4
+ || bmp_type == BMPT_WIN5
+ || bmp_type == BMPT_OS22) {
+ read(fd, &info_hdr.iWidth, 4);
+ read(fd, &info_hdr.iHeight, 4);
+ read(fd, &info_hdr.iPlanes, 2);
+ read(fd, &info_hdr.iBitCount, 2);
+ read(fd, &info_hdr.iCompression, 4);
+ read(fd, &info_hdr.iSizeImage, 4);
+ read(fd, &info_hdr.iXPelsPerMeter, 4);
+ read(fd, &info_hdr.iYPelsPerMeter, 4);
+ read(fd, &info_hdr.iClrUsed, 4);
+ read(fd, &info_hdr.iClrImportant, 4);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabLong((uint32*) &info_hdr.iWidth);
+ TIFFSwabLong((uint32*) &info_hdr.iHeight);
+ TIFFSwabShort((uint16*) &info_hdr.iPlanes);
+ TIFFSwabShort((uint16*) &info_hdr.iBitCount);
+ TIFFSwabLong((uint32*) &info_hdr.iCompression);
+ TIFFSwabLong((uint32*) &info_hdr.iSizeImage);
+ TIFFSwabLong((uint32*) &info_hdr.iXPelsPerMeter);
+ TIFFSwabLong((uint32*) &info_hdr.iYPelsPerMeter);
+ TIFFSwabLong((uint32*) &info_hdr.iClrUsed);
+ TIFFSwabLong((uint32*) &info_hdr.iClrImportant);
+#endif
+ n_clr_elems = 4;
+ }
+
+ if (bmp_type == BMPT_OS22) {
+ /*
+ * FIXME: different info in different documents
+ * regarding this!
+ */
+ n_clr_elems = 3;
+ }
+
+ if (bmp_type == BMPT_OS21) {
+ int16 iShort;
+
+ read(fd, &iShort, 2);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabShort((uint16*) &iShort);
+#endif
+ info_hdr.iWidth = iShort;
+ read(fd, &iShort, 2);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabShort((uint16*) &iShort);
+#endif
+ info_hdr.iHeight = iShort;
+ read(fd, &iShort, 2);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabShort((uint16*) &iShort);
+#endif
+ info_hdr.iPlanes = iShort;
+ read(fd, &iShort, 2);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabShort((uint16*) &iShort);
+#endif
+ info_hdr.iBitCount = iShort;
+ info_hdr.iCompression = BMPC_RGB;
+ n_clr_elems = 3;
+ }
+
+ if (info_hdr.iBitCount != 1 && info_hdr.iBitCount != 4 &&
+ info_hdr.iBitCount != 8 && info_hdr.iBitCount != 16 &&
+ info_hdr.iBitCount != 24 && info_hdr.iBitCount != 32) {
+ TIFFError(infilename,
+ "Cannot process BMP file with bit count %d",
+ info_hdr.iBitCount);
+ close(fd);
+ return 0;
+ }
+
+ width = info_hdr.iWidth;
+ length = (info_hdr.iHeight > 0) ? info_hdr.iHeight : -info_hdr.iHeight;
+
+ switch (info_hdr.iBitCount)
+ {
+ case 1:
+ case 4:
+ case 8:
+ nbands = 1;
+ depth = info_hdr.iBitCount;
+ photometric = PHOTOMETRIC_PALETTE;
+ /* Allocate memory for colour table and read it. */
+ if (info_hdr.iClrUsed)
+ clr_tbl_size =
+ ((uint32)(1<<depth)<info_hdr.iClrUsed)
+ ? (uint32) (1 << depth)
+ : info_hdr.iClrUsed;
+ else
+ clr_tbl_size = 1 << depth;
+ clr_tbl = (unsigned char *)
+ _TIFFmalloc(n_clr_elems * clr_tbl_size);
+ if (!clr_tbl) {
+ TIFFError(infilename,
+ "Can't allocate space for color table");
+ goto bad;
+ }
+
+ lseek(fd, BFH_SIZE + info_hdr.iSize, SEEK_SET);
+ read(fd, clr_tbl, n_clr_elems * clr_tbl_size);
+
+ red_tbl = (unsigned short*)
+ _TIFFmalloc(1<<depth * sizeof(unsigned short));
+ if (!red_tbl) {
+ TIFFError(infilename,
+ "Can't allocate space for red component table");
+ _TIFFfree(clr_tbl);
+ goto bad1;
+ }
+ green_tbl = (unsigned short*)
+ _TIFFmalloc(1<<depth * sizeof(unsigned short));
+ if (!green_tbl) {
+ TIFFError(infilename,
+ "Can't allocate space for green component table");
+ _TIFFfree(clr_tbl);
+ goto bad2;
+ }
+ blue_tbl = (unsigned short*)
+ _TIFFmalloc(1<<depth * sizeof(unsigned short));
+ if (!blue_tbl) {
+ TIFFError(infilename,
+ "Can't allocate space for blue component table");
+ _TIFFfree(clr_tbl);
+ goto bad3;
+ }
+
+ for(clr = 0; clr < clr_tbl_size; clr++) {
+ red_tbl[clr] = 257*clr_tbl[clr*n_clr_elems+2];
+ green_tbl[clr] = 257*clr_tbl[clr*n_clr_elems+1];
+ blue_tbl[clr] = 257*clr_tbl[clr*n_clr_elems];
+ }
+
+ _TIFFfree(clr_tbl);
+ break;
+ case 16:
+ case 24:
+ nbands = 3;
+ depth = info_hdr.iBitCount / nbands;
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ case 32:
+ nbands = 3;
+ depth = 8;
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ default:
+ break;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Create output file. */
+/* -------------------------------------------------------------------- */
+
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, nbands);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, depth);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+
+ if (red_tbl && green_tbl && blue_tbl) {
+ TIFFSetField(out, TIFFTAG_COLORMAP,
+ red_tbl, green_tbl, blue_tbl);
+ }
+
+ if (compression == (uint16) -1)
+ compression = COMPRESSION_PACKBITS;
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB
+ && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Read uncompressed image data. */
+/* -------------------------------------------------------------------- */
+
+ if (info_hdr.iCompression == BMPC_RGB) {
+ uint32 offset, size;
+ char *scanbuf;
+
+ /* XXX: Avoid integer overflow. We can calculate size
+ * in one step using
+ *
+ * size = ((width * info_hdr.iBitCount + 31) & ~31) / 8
+ *
+ * formulae, but we should check for overflow
+ * conditions during calculation.
+ */
+ size = width * info_hdr.iBitCount + 31;
+ if (!width || !info_hdr.iBitCount
+ || (size - 31) / info_hdr.iBitCount != width ) {
+ TIFFError(infilename,
+ "Wrong image parameters; can't "
+ "allocate space for scanline buffer");
+ goto bad3;
+ }
+ size = (size & ~31) / 8;
+
+ scanbuf = (char *) _TIFFmalloc(size);
+ if (!scanbuf) {
+ TIFFError(infilename,
+ "Can't allocate space for scanline buffer");
+ goto bad3;
+ }
+
+ for (row = 0; row < length; row++) {
+ if (info_hdr.iHeight > 0)
+ offset = file_hdr.iOffBits+(length-row-1)*size;
+ else
+ offset = file_hdr.iOffBits + row * size;
+ if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+ TIFFError(infilename,
+ "scanline %lu: Seek error",
+ (unsigned long) row);
+ break;
+ }
+
+ if (read(fd, scanbuf, size) < 0) {
+ TIFFError(infilename,
+ "scanline %lu: Read error",
+ (unsigned long) row);
+ break;
+ }
+
+ rearrangePixels(scanbuf, width, info_hdr.iBitCount);
+
+ if (TIFFWriteScanline(out, scanbuf, row, 0)<0) {
+ TIFFError(infilename,
+ "scanline %lu: Write error",
+ (unsigned long) row);
+ break;
+ }
+ }
+
+ _TIFFfree(scanbuf);
+
+/* -------------------------------------------------------------------- */
+/* Read compressed image data. */
+/* -------------------------------------------------------------------- */
+
+ } else if ( info_hdr.iCompression == BMPC_RLE8
+ || info_hdr.iCompression == BMPC_RLE4 ) {
+ uint32 i, j, k, runlength;
+ uint32 compr_size, uncompr_size;
+ unsigned char *comprbuf;
+ unsigned char *uncomprbuf;
+
+ compr_size = file_hdr.iSize - file_hdr.iOffBits;
+ uncompr_size = width * length;
+ comprbuf = (unsigned char *) _TIFFmalloc( compr_size );
+ if (!comprbuf) {
+ TIFFError(infilename,
+ "Can't allocate space for compressed scanline buffer");
+ goto bad3;
+ }
+ uncomprbuf = (unsigned char *)_TIFFmalloc(uncompr_size);
+ if (!uncomprbuf) {
+ TIFFError(infilename,
+ "Can't allocate space for uncompressed scanline buffer");
+ goto bad3;
+ }
+
+ lseek(fd, file_hdr.iOffBits, SEEK_SET);
+ read(fd, comprbuf, compr_size);
+ i = 0;
+ j = 0;
+ if (info_hdr.iBitCount == 8) { /* RLE8 */
+ while(j < uncompr_size && i < compr_size) {
+ if ( comprbuf[i] ) {
+ runlength = comprbuf[i++];
+ while( runlength > 0
+ && j < uncompr_size
+ && i < compr_size ) {
+ uncomprbuf[j++] = comprbuf[i];
+ runlength--;
+ }
+ i++;
+ } else {
+ i++;
+ if (comprbuf[i] == 0) /* Next scanline */
+ i++;
+ else if (comprbuf[i] == 1) /* End of image */
+ break;
+ else if (comprbuf[i] == 2) { /* Move to... */
+ i++;
+ if (i < compr_size - 1) {
+ j+=comprbuf[i]+comprbuf[i+1]*width;
+ i += 2;
+ }
+ else
+ break;
+ } else { /* Absolute mode */
+ runlength = comprbuf[i++];
+ for (k = 0; k < runlength && j < uncompr_size && i < compr_size; k++)
+ uncomprbuf[j++] = comprbuf[i++];
+ if ( k & 0x01 )
+ i++;
+ }
+ }
+ }
+ }
+ else { /* RLE4 */
+ while( j < uncompr_size && i < compr_size ) {
+ if ( comprbuf[i] ) {
+ runlength = comprbuf[i++];
+ while( runlength > 0 && j < uncompr_size && i < compr_size ) {
+ if ( runlength & 0x01 )
+ uncomprbuf[j++] = (comprbuf[i] & 0xF0) >> 4;
+ else
+ uncomprbuf[j++] = comprbuf[i] & 0x0F;
+ runlength--;
+ }
+ i++;
+ } else {
+ i++;
+ if (comprbuf[i] == 0) /* Next scanline */
+ i++;
+ else if (comprbuf[i] == 1) /* End of image */
+ break;
+ else if (comprbuf[i] == 2) { /* Move to... */
+ i++;
+ if (i < compr_size - 1) {
+ j+=comprbuf[i]+comprbuf[i+1]*width;
+ i += 2;
+ }
+ else
+ break;
+ } else { /* Absolute mode */
+ runlength = comprbuf[i++];
+ for (k = 0; k < runlength && j < uncompr_size && i < compr_size; k++) {
+ if (k & 0x01)
+ uncomprbuf[j++] = comprbuf[i++] & 0x0F;
+ else
+ uncomprbuf[j++] = (comprbuf[i] & 0xF0) >> 4;
+ }
+ if (k & 0x01)
+ i++;
+ }
+ }
+ }
+ }
+
+ _TIFFfree(comprbuf);
+
+ for (row = 0; row < length; row++) {
+ if (TIFFWriteScanline(out,
+ uncomprbuf + (length - row - 1) * width,
+ row, 0) < 0) {
+ TIFFError(infilename,
+ "scanline %lu: Write error.\n",
+ (unsigned long) row);
+ }
+ }
+
+ _TIFFfree(uncomprbuf);
+ }
+ TIFFWriteDirectory(out);
+ if (blue_tbl) {
+ _TIFFfree(blue_tbl);
+ blue_tbl=NULL;
+ }
+ if (green_tbl) {
+ _TIFFfree(green_tbl);
+ green_tbl=NULL;
+ }
+ if (red_tbl) {
+ _TIFFfree(red_tbl);
+ red_tbl=NULL;
+ }
+ }
+
+bad3:
+ if (blue_tbl)
+ _TIFFfree(blue_tbl);
+bad2:
+ if (green_tbl)
+ _TIFFfree(green_tbl);
+bad1:
+ if (red_tbl)
+ _TIFFfree(red_tbl);
+bad:
+ close(fd);
+
+ if (out)
+ TIFFClose(out);
+ return 0;
+}
+
+/*
+ * Image data in BMP file stored in BGR (or ABGR) format. We should rearrange
+ * pixels to RGB (RGBA) format.
+ */
+static void
+rearrangePixels(char *buf, uint32 width, uint32 bit_count)
+{
+ char tmp;
+ uint32 i;
+
+ switch(bit_count) {
+ case 16: /* FIXME: need a sample file */
+ break;
+ case 24:
+ for (i = 0; i < width; i++, buf += 3) {
+ tmp = *buf;
+ *buf = *(buf + 2);
+ *(buf + 2) = tmp;
+ }
+ break;
+ case 32:
+ {
+ char *buf1 = buf;
+
+ for (i = 0; i < width; i++, buf += 4) {
+ tmp = *buf;
+ *buf1++ = *(buf + 2);
+ *buf1++ = *(buf + 1);
+ *buf1++ = tmp;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (strcmp(opt, "none") == 0)
+ compression = COMPRESSION_NONE;
+ else if (strcmp(opt, "packbits") == 0)
+ compression = COMPRESSION_PACKBITS;
+ else if (strncmp(opt, "jpeg", 4) == 0) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strncmp(opt, "lzw", 3) == 0) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strncmp(opt, "zip", 3) == 0) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+static char* stuff[] = {
+"bmp2tiff --- convert Windows BMP files to TIFF",
+"usage: bmp2tiff [options] input.bmp [input2.bmp ...] output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts]compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+" -o out.tif write output to out.tif",
+" -h this help message",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/fax2ps.c b/tiff/tools/fax2ps.c
new file mode 100644
index 0000000..b2611b9
--- /dev/null
+++ b/tiff/tools/fax2ps.c
@@ -0,0 +1,446 @@
+/* $Id: fax2ps.c,v 1.22.2.1 2010-06-08 18:50:43 bfriesen Exp $" */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#include "tif_config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+float defxres = 204.; /* default x resolution (pixels/inch) */
+float defyres = 98.; /* default y resolution (lines/inch) */
+const float half = 0.5;
+const float points = 72.0;
+float pageWidth = 0; /* image page width (inches) */
+float pageHeight = 0; /* image page length (inches) */
+int scaleToPage = 0; /* if true, scale raster to page dimensions */
+int totalPages = 0; /* total # pages printed */
+int row; /* current output row */
+int maxline = 512; /* max output line of PostScript */
+
+/*
+ * Turn a bit-mapped scanline into the appropriate sequence
+ * of PostScript characters to be rendered.
+ *
+ * Original version written by Bret D. Whissel,
+ * Florida State University Meteorology Department
+ * March 13-15, 1995.
+ */
+static void
+printruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
+{
+ static struct {
+ char white, black;
+ unsigned short width;
+ } WBarr[] = {
+ { 'd', 'n', 512 }, { 'e', 'o', 256 }, { 'f', 'p', 128 },
+ { 'g', 'q', 64 }, { 'h', 'r', 32 }, { 'i', 's', 16 },
+ { 'j', 't', 8 }, { 'k', 'u', 4 }, { 'l', 'v', 2 },
+ { 'm', 'w', 1 }
+ };
+ static char* svalue =
+ " !\"#$&'*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abc";
+ int colormode = 1; /* 0 for white, 1 for black */
+ uint32 runlength = 0;
+ int n = maxline;
+ uint32 x = 0;
+ int l;
+
+ (void) buf;
+ printf("%d m(", row++);
+ while (runs < erun) {
+ if (runlength <= 0) {
+ colormode ^= 1;
+ runlength = *runs++;
+ if (x+runlength > lastx)
+ runlength = runs[-1] = lastx-x;
+ x += runlength;
+ if (!colormode && runs == erun)
+ break; /* don't bother printing the final white run */
+ }
+ /*
+ * If a runlength is greater than 6 pixels, then spit out
+ * black or white characters until the runlength drops to
+ * 6 or less. Once a runlength is <= 6, then combine black
+ * and white runlengths until a 6-pixel pattern is obtained.
+ * Then write out the special character. Six-pixel patterns
+ * were selected since 64 patterns is the largest power of
+ * two less than the 92 "easily printable" PostScript
+ * characters (i.e., no escape codes or octal chars).
+ */
+ l = 0;
+ while (runlength > 6) { /* Run is greater than six... */
+ if (runlength >= WBarr[l].width) {
+ if (n == 0) {
+ putchar('\n');
+ n = maxline;
+ }
+ putchar(colormode ? WBarr[l].black : WBarr[l].white), n--;
+ runlength -= WBarr[l].width;
+ } else
+ l++;
+ }
+ while (runlength > 0 && runlength <= 6) {
+ uint32 bitsleft = 6;
+ int t = 0;
+ while (bitsleft) {
+ if (runlength <= bitsleft) {
+ if (colormode)
+ t |= ((1 << runlength)-1) << (bitsleft-runlength);
+ bitsleft -= runlength;
+ runlength = 0;
+ if (bitsleft) {
+ if (runs >= erun)
+ break;
+ colormode ^= 1;
+ runlength = *runs++;
+ if (x+runlength > lastx)
+ runlength = runs[-1] = lastx-x;
+ x += runlength;
+ }
+ } else { /* runlength exceeds bits left */
+ if (colormode)
+ t |= ((1 << bitsleft)-1);
+ runlength -= bitsleft;
+ bitsleft = 0;
+ }
+ }
+ if (n == 0) {
+ putchar('\n');
+ n = maxline;
+ }
+ putchar(svalue[t]), n--;
+ }
+ }
+ printf(")s\n");
+}
+
+/*
+ * Create a special PostScript font for printing FAX documents. By taking
+ * advantage of the font-cacheing mechanism, a substantial speed-up in
+ * rendering time is realized.
+ */
+static void
+emitFont(FILE* fd)
+{
+ static const char* fontPrologue[] = {
+ "/newfont 10 dict def newfont begin /FontType 3 def /FontMatrix [1",
+ "0 0 1 0 0] def /FontBBox [0 0 512 1] def /Encoding 256 array def",
+ "0 1 31{Encoding exch /255 put}for 120 1 255{Encoding exch /255",
+ "put}for Encoding 37 /255 put Encoding 40 /255 put Encoding 41 /255",
+ "put Encoding 92 /255 put /count 0 def /ls{Encoding exch count 3",
+ "string cvs cvn put /count count 1 add def}def 32 1 36{ls}for",
+ "38 1 39{ls}for 42 1 91{ls}for 93 1 99{ls}for /count 100",
+ "def 100 1 119{ls}for /CharDict 5 dict def CharDict begin /white",
+ "{dup 255 eq{pop}{1 dict begin 100 sub neg 512 exch bitshift",
+ "/cw exch def cw 0 0 0 cw 1 setcachedevice end}ifelse}def /black",
+ "{dup 255 eq{pop}{1 dict begin 110 sub neg 512 exch bitshift",
+ "/cw exch def cw 0 0 0 cw 1 setcachedevice 0 0 moveto cw 0 rlineto",
+ "0 1 rlineto cw neg 0 rlineto closepath fill end}ifelse}def /numbuild",
+ "{dup 255 eq{pop}{6 0 0 0 6 1 setcachedevice 0 1 5{0 moveto",
+ "dup 32 and 32 eq{1 0 rlineto 0 1 rlineto -1 0 rlineto closepath",
+ "fill newpath}if 1 bitshift}for pop}ifelse}def /.notdef {}",
+ "def /255 {}def end /BuildChar{exch begin dup 110 ge{Encoding",
+ "exch get 3 string cvs cvi CharDict /black get}{dup 100 ge {Encoding",
+ "exch get 3 string cvs cvi CharDict /white get}{Encoding exch get",
+ "3 string cvs cvi CharDict /numbuild get}ifelse}ifelse exec end",
+ "}def end /Bitfont newfont definefont 1 scalefont setfont",
+ NULL
+ };
+ int i;
+ for (i = 0; fontPrologue[i] != NULL; i++)
+ fprintf(fd, "%s\n", fontPrologue[i]);
+}
+
+void
+printTIF(TIFF* tif, uint16 pageNumber)
+{
+ uint32 w, h;
+ uint16 unit, compression;
+ float xres, yres, scale = 1.0;
+ tstrip_t s, ns;
+ time_t creation_time;
+
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
+ if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression)
+ || compression < COMPRESSION_CCITTRLE
+ || compression > COMPRESSION_CCITT_T6)
+ return;
+ if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) || !xres) {
+ TIFFWarning(TIFFFileName(tif),
+ "No x-resolution, assuming %g dpi", defxres);
+ xres = defxres;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) || !yres) {
+ TIFFWarning(TIFFFileName(tif),
+ "No y-resolution, assuming %g lpi", defyres);
+ yres = defyres; /* XXX */
+ }
+ if (TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &unit) &&
+ unit == RESUNIT_CENTIMETER) {
+ xres *= 2.54F;
+ yres *= 2.54F;
+ }
+ if (pageWidth == 0)
+ pageWidth = w / xres;
+ if (pageHeight == 0)
+ pageHeight = h / yres;
+
+ printf("%%!PS-Adobe-3.0\n");
+ printf("%%%%Creator: fax2ps\n");
+#ifdef notdef
+ printf("%%%%Title: %s\n", file);
+#endif
+ creation_time = time(0);
+ printf("%%%%CreationDate: %s", ctime(&creation_time));
+ printf("%%%%Origin: 0 0\n");
+ printf("%%%%BoundingBox: 0 0 %u %u\n",
+ (int)(pageWidth * points), (int)(pageHeight * points)); /* XXX */
+ printf("%%%%Pages: (atend)\n");
+ printf("%%%%EndComments\n");
+ printf("%%%%BeginProlog\n");
+ emitFont(stdout);
+ printf("/d{bind def}def\n"); /* bind and def proc */
+ printf("/m{0 exch moveto}d\n");
+ printf("/s{show}d\n");
+ printf("/p{showpage}d \n"); /* end page */
+ printf("%%%%EndProlog\n");
+ printf("%%%%Page: \"%u\" %u\n", pageNumber, pageNumber);
+ printf("/$pageTop save def gsave\n");
+ if (scaleToPage)
+ scale = pageHeight / (h/yres) < pageWidth / (w/xres) ?
+ pageHeight / (h/yres) : pageWidth / (w/xres);
+ printf("%g %g translate\n",
+ points * (pageWidth - scale*w/xres) * half,
+ points * (scale*h/yres + (pageHeight - scale*h/yres) * half));
+ printf("%g %g scale\n", points/xres*scale, -points/yres*scale);
+ printf("0 setgray\n");
+ TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, printruns);
+ ns = TIFFNumberOfStrips(tif);
+ row = 0;
+ for (s = 0; s < ns; s++)
+ (void) TIFFReadEncodedStrip(tif, s, (tdata_t) NULL, (tsize_t) -1);
+ printf("p\n");
+ printf("grestore $pageTop restore\n");
+ totalPages++;
+}
+
+#define GetPageNumber(tif) \
+TIFFGetField(tif, TIFFTAG_PAGENUMBER, &pn, &ptotal)
+
+int
+findPage(TIFF* tif, uint16 pageNumber)
+{
+ uint16 pn = (uint16) -1;
+ uint16 ptotal = (uint16) -1;
+ if (GetPageNumber(tif)) {
+ while (pn != pageNumber && TIFFReadDirectory(tif) && GetPageNumber(tif))
+ ;
+ return (pn == pageNumber);
+ } else
+ return (TIFFSetDirectory(tif, (tdir_t)(pageNumber-1)));
+}
+
+void
+fax2ps(TIFF* tif, uint16 npages, uint16* pages, char* filename)
+{
+ if (npages > 0) {
+ uint16 pn, ptotal;
+ int i;
+
+ if (!GetPageNumber(tif))
+ fprintf(stderr, "%s: No page numbers, counting directories.\n",
+ filename);
+ for (i = 0; i < npages; i++) {
+ if (findPage(tif, pages[i]))
+ printTIF(tif, pages[i]);
+ else
+ fprintf(stderr, "%s: No page number %d\n", filename, pages[i]);
+ }
+ } else {
+ uint16 pageNumber = 0;
+ do
+ printTIF(tif, pageNumber++);
+ while (TIFFReadDirectory(tif));
+ }
+}
+
+#undef GetPageNumber
+
+static int
+pcompar(const void* va, const void* vb)
+{
+ const int* pa = (const int*) va;
+ const int* pb = (const int*) vb;
+ return (*pa - *pb);
+}
+
+static void usage(int code);
+
+int
+main(int argc, char** argv)
+{
+ extern int optind;
+ extern char* optarg;
+ uint16 *pages = NULL, npages = 0, pageNumber;
+ int c, dowarnings = 0; /* if 1, enable library warnings */
+ TIFF* tif;
+
+ while ((c = getopt(argc, argv, "l:p:x:y:W:H:wS")) != -1)
+ switch (c) {
+ case 'H': /* page height */
+ pageHeight = (float)atof(optarg);
+ break;
+ case 'S': /* scale to page */
+ scaleToPage = 1;
+ break;
+ case 'W': /* page width */
+ pageWidth = (float)atof(optarg);
+ break;
+ case 'p': /* print specific page */
+ pageNumber = (uint16)atoi(optarg);
+ if (pages)
+ pages = (uint16*) realloc(pages, (npages+1)*sizeof(uint16));
+ else
+ pages = (uint16*) malloc(sizeof(uint16));
+ pages[npages++] = pageNumber;
+ break;
+ case 'w':
+ dowarnings = 1;
+ break;
+ case 'x':
+ defxres = (float)atof(optarg);
+ break;
+ case 'y':
+ defyres = (float)atof(optarg);
+ break;
+ case 'l':
+ maxline = atoi(optarg);
+ break;
+ case '?':
+ usage(-1);
+ }
+ if (npages > 0)
+ qsort(pages, npages, sizeof(uint16), pcompar);
+ if (!dowarnings)
+ TIFFSetWarningHandler(0);
+ if (optind < argc) {
+ do {
+ tif = TIFFOpen(argv[optind], "r");
+ if (tif) {
+ fax2ps(tif, npages, pages, argv[optind]);
+ TIFFClose(tif);
+ } else
+ fprintf(stderr, "%s: Can not open, or not a TIFF file.\n",
+ argv[optind]);
+ } while (++optind < argc);
+ } else {
+ int n;
+ FILE* fd;
+ char buf[16*1024];
+
+ fd = tmpfile();
+ if (fd == NULL) {
+ fprintf(stderr, "Could not create temporary file, exiting.\n");
+ fclose(fd);
+ exit(-2);
+ }
+#if defined(HAVE_SETMODE) && defined(O_BINARY)
+ setmode(fileno(stdin), O_BINARY);
+#endif
+ while ((n = read(fileno(stdin), buf, sizeof (buf))) > 0)
+ write(fileno(fd), buf, n);
+ lseek(fileno(fd), 0, SEEK_SET);
+#if defined(_WIN32) && defined(USE_WIN32_FILEIO)
+ tif = TIFFFdOpen(_get_osfhandle(fileno(fd)), "temp", "r");
+#else
+ tif = TIFFFdOpen(fileno(fd), "temp", "r");
+#endif
+ if (tif) {
+ fax2ps(tif, npages, pages, "<stdin>");
+ TIFFClose(tif);
+ } else
+ fprintf(stderr, "Can not open, or not a TIFF file.\n");
+ fclose(fd);
+ }
+ printf("%%%%Trailer\n");
+ printf("%%%%Pages: %u\n", totalPages);
+ printf("%%%%EOF\n");
+
+ return (0);
+}
+
+char* stuff[] = {
+"usage: fax2ps [options] [input.tif ...]",
+"where options are:",
+" -w suppress warning messages",
+" -l chars set maximum output line length for generated PostScript",
+" -p page# select page to print (can use multiple times)",
+" -x xres set default horizontal resolution of input data (dpi)",
+" -y yres set default vertical resolution of input data (lpi)",
+" -S scale output to page size",
+" -W width set output page width (inches), default is 8.5",
+" -H height set output page height (inches), default is 11",
+NULL
+};
+
+static void
+usage(int code)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(code);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/fax2tiff.c b/tiff/tools/fax2tiff.c
new file mode 100644
index 0000000..951b568
--- /dev/null
+++ b/tiff/tools/fax2tiff.c
@@ -0,0 +1,465 @@
+/* $Id: fax2tiff.c,v 1.19.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * Convert a CCITT Group 3 or 4 FAX file to TIFF Group 3 or 4 format.
+ */
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h> /* should have atof & getopt */
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffiop.h"
+
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
+
+TIFF *faxTIFF;
+char *rowbuf;
+char *refbuf;
+
+uint32 xsize = 1728;
+int verbose;
+int stretch;
+uint16 badfaxrun;
+uint32 badfaxlines;
+
+int copyFaxFile(TIFF* tifin, TIFF* tifout);
+static void usage(void);
+
+int
+main(int argc, char* argv[])
+{
+ FILE *in;
+ TIFF *out = NULL;
+ TIFFErrorHandler whandler = NULL;
+ int compression_in = COMPRESSION_CCITTFAX3;
+ int compression_out = COMPRESSION_CCITTFAX3;
+ int fillorder_in = FILLORDER_LSB2MSB;
+ int fillorder_out = FILLORDER_LSB2MSB;
+ uint32 group3options_in = 0; /* 1d-encoded */
+ uint32 group3options_out = 0; /* 1d-encoded */
+ uint32 group4options_in = 0; /* compressed */
+ uint32 group4options_out = 0; /* compressed */
+ uint32 defrowsperstrip = (uint32) 0;
+ uint32 rowsperstrip;
+ int photometric_in = PHOTOMETRIC_MINISWHITE;
+ int photometric_out = PHOTOMETRIC_MINISWHITE;
+ int mode = FAXMODE_CLASSF;
+ int rows;
+ int c;
+ int pn, npages;
+ float resY = 196.0;
+ extern int optind;
+ extern char* optarg;
+
+
+ while ((c = getopt(argc, argv, "R:X:o:1234ABLMPUW5678abcflmprsuvwz?")) != -1)
+ switch (c) {
+ /* input-related options */
+ case '3': /* input is g3-encoded */
+ compression_in = COMPRESSION_CCITTFAX3;
+ break;
+ case '4': /* input is g4-encoded */
+ compression_in = COMPRESSION_CCITTFAX4;
+ break;
+ case 'U': /* input is uncompressed (g3 and g4) */
+ group3options_in |= GROUP3OPT_UNCOMPRESSED;
+ group4options_in |= GROUP4OPT_UNCOMPRESSED;
+ break;
+ case '1': /* input is 1d-encoded (g3 only) */
+ group3options_in &= ~GROUP3OPT_2DENCODING;
+ break;
+ case '2': /* input is 2d-encoded (g3 only) */
+ group3options_in |= GROUP3OPT_2DENCODING;
+ break;
+ case 'P': /* input has not-aligned EOL (g3 only) */
+ group3options_in &= ~GROUP3OPT_FILLBITS;
+ break;
+ case 'A': /* input has aligned EOL (g3 only) */
+ group3options_in |= GROUP3OPT_FILLBITS;
+ break;
+ case 'W': /* input has 0 mean white */
+ photometric_in = PHOTOMETRIC_MINISWHITE;
+ break;
+ case 'B': /* input has 0 mean black */
+ photometric_in = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 'L': /* input has lsb-to-msb fillorder */
+ fillorder_in = FILLORDER_LSB2MSB;
+ break;
+ case 'M': /* input has msb-to-lsb fillorder */
+ fillorder_in = FILLORDER_MSB2LSB;
+ break;
+ case 'R': /* input resolution */
+ resY = (float) atof(optarg);
+ break;
+ case 'X': /* input width */
+ xsize = (uint32) atoi(optarg);
+ break;
+
+ /* output-related options */
+ case '7': /* generate g3-encoded output */
+ compression_out = COMPRESSION_CCITTFAX3;
+ break;
+ case '8': /* generate g4-encoded output */
+ compression_out = COMPRESSION_CCITTFAX4;
+ break;
+ case 'u': /* generate uncompressed output (g3 and g4) */
+ group3options_out |= GROUP3OPT_UNCOMPRESSED;
+ group4options_out |= GROUP4OPT_UNCOMPRESSED;
+ break;
+ case '5': /* generate 1d-encoded output (g3 only) */
+ group3options_out &= ~GROUP3OPT_2DENCODING;
+ break;
+ case '6': /* generate 2d-encoded output (g3 only) */
+ group3options_out |= GROUP3OPT_2DENCODING;
+ break;
+ case 'c': /* generate "classic" g3 format */
+ mode = FAXMODE_CLASSIC;
+ break;
+ case 'f': /* generate Class F format */
+ mode = FAXMODE_CLASSF;
+ break;
+ case 'm': /* output's fillorder is msb-to-lsb */
+ fillorder_out = FILLORDER_MSB2LSB;
+ break;
+ case 'l': /* output's fillorder is lsb-to-msb */
+ fillorder_out = FILLORDER_LSB2MSB;
+ break;
+ case 'o':
+ out = TIFFOpen(optarg, "w");
+ if (out == NULL) {
+ fprintf(stderr,
+ "%s: Can not create or open %s\n",
+ argv[0], optarg);
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'a': /* generate EOL-aligned output (g3 only) */
+ group3options_out |= GROUP3OPT_FILLBITS;
+ break;
+ case 'p': /* generate not EOL-aligned output (g3 only) */
+ group3options_out &= ~GROUP3OPT_FILLBITS;
+ break;
+ case 'r': /* rows/strip */
+ defrowsperstrip = atol(optarg);
+ break;
+ case 's': /* stretch image by dup'ng scanlines */
+ stretch = 1;
+ break;
+ case 'w': /* undocumented -- for testing */
+ photometric_out = PHOTOMETRIC_MINISWHITE;
+ break;
+ case 'b': /* undocumented -- for testing */
+ photometric_out = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 'z': /* undocumented -- for testing */
+ compression_out = COMPRESSION_LZW;
+ break;
+ case 'v': /* -v for info */
+ verbose++;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ npages = argc - optind;
+ if (npages < 1)
+ usage();
+
+ rowbuf = _TIFFmalloc(TIFFhowmany8(xsize));
+ refbuf = _TIFFmalloc(TIFFhowmany8(xsize));
+ if (rowbuf == NULL || refbuf == NULL) {
+ fprintf(stderr, "%s: Not enough memory\n", argv[0]);
+ return (EXIT_FAILURE);
+ }
+
+ if (out == NULL) {
+ out = TIFFOpen("fax.tif", "w");
+ if (out == NULL) {
+ fprintf(stderr, "%s: Can not create fax.tif\n",
+ argv[0]);
+ return (EXIT_FAILURE);
+ }
+ }
+
+ faxTIFF = TIFFClientOpen("(FakeInput)", "w",
+ /* TIFFClientOpen() fails if we don't set existing value here */
+ TIFFClientdata(out),
+ TIFFGetReadProc(out), TIFFGetWriteProc(out),
+ TIFFGetSeekProc(out), TIFFGetCloseProc(out),
+ TIFFGetSizeProc(out), TIFFGetMapFileProc(out),
+ TIFFGetUnmapFileProc(out));
+ if (faxTIFF == NULL) {
+ fprintf(stderr, "%s: Can not create fake input file\n",
+ argv[0]);
+ return (EXIT_FAILURE);
+ }
+ TIFFSetMode(faxTIFF, O_RDONLY);
+ TIFFSetField(faxTIFF, TIFFTAG_IMAGEWIDTH, xsize);
+ TIFFSetField(faxTIFF, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(faxTIFF, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(faxTIFF, TIFFTAG_FILLORDER, fillorder_in);
+ TIFFSetField(faxTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(faxTIFF, TIFFTAG_PHOTOMETRIC, photometric_in);
+ TIFFSetField(faxTIFF, TIFFTAG_YRESOLUTION, resY);
+ TIFFSetField(faxTIFF, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+
+ /* NB: this must be done after directory info is setup */
+ TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, compression_in);
+ if (compression_in == COMPRESSION_CCITTFAX3)
+ TIFFSetField(faxTIFF, TIFFTAG_GROUP3OPTIONS, group3options_in);
+ else if (compression_in == COMPRESSION_CCITTFAX4)
+ TIFFSetField(faxTIFF, TIFFTAG_GROUP4OPTIONS, group4options_in);
+ for (pn = 0; optind < argc; pn++, optind++) {
+ in = fopen(argv[optind], "rb");
+ if (in == NULL) {
+ fprintf(stderr,
+ "%s: %s: Can not open\n", argv[0], argv[optind]);
+ continue;
+ }
+#if defined(_WIN32) && defined(USE_WIN32_FILEIO)
+ TIFFSetClientdata(faxTIFF, (thandle_t)_get_osfhandle(fileno(in)));
+#else
+ TIFFSetClientdata(faxTIFF, (thandle_t)fileno(in));
+#endif
+ TIFFSetFileName(faxTIFF, (const char*)argv[optind]);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, xsize);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression_out);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric_out);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
+ switch (compression_out) {
+ /* g3 */
+ case COMPRESSION_CCITTFAX3:
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS,
+ group3options_out);
+ TIFFSetField(out, TIFFTAG_FAXMODE, mode);
+ rowsperstrip =
+ (defrowsperstrip)?defrowsperstrip:(uint32)-1L;
+ break;
+
+ /* g4 */
+ case COMPRESSION_CCITTFAX4:
+ TIFFSetField(out, TIFFTAG_GROUP4OPTIONS,
+ group4options_out);
+ TIFFSetField(out, TIFFTAG_FAXMODE, mode);
+ rowsperstrip =
+ (defrowsperstrip)?defrowsperstrip:(uint32)-1L;
+ break;
+
+ default:
+ rowsperstrip = (defrowsperstrip) ?
+ defrowsperstrip : TIFFDefaultStripSize(out, 0);
+ }
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder_out);
+ TIFFSetField(out, TIFFTAG_SOFTWARE, "fax2tiff");
+ TIFFSetField(out, TIFFTAG_XRESOLUTION, 204.0);
+ if (!stretch) {
+ TIFFGetField(faxTIFF, TIFFTAG_YRESOLUTION, &resY);
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, resY);
+ } else
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, 196.);
+ TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pn, npages);
+
+ if (!verbose)
+ whandler = TIFFSetWarningHandler(NULL);
+ rows = copyFaxFile(faxTIFF, out);
+ fclose(in);
+ if (!verbose)
+ (void) TIFFSetWarningHandler(whandler);
+
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, rows);
+
+ if (verbose) {
+ fprintf(stderr, "%s:\n", argv[optind]);
+ fprintf(stderr, "%d rows in input\n", rows);
+ fprintf(stderr, "%ld total bad rows\n",
+ (long) badfaxlines);
+ fprintf(stderr, "%d max consecutive bad rows\n", badfaxrun);
+ }
+ if (compression_out == COMPRESSION_CCITTFAX3 &&
+ mode == FAXMODE_CLASSF) {
+ TIFFSetField(out, TIFFTAG_BADFAXLINES, badfaxlines);
+ TIFFSetField(out, TIFFTAG_CLEANFAXDATA, badfaxlines ?
+ CLEANFAXDATA_REGENERATED : CLEANFAXDATA_CLEAN);
+ TIFFSetField(out, TIFFTAG_CONSECUTIVEBADFAXLINES, badfaxrun);
+ }
+ TIFFWriteDirectory(out);
+ }
+ TIFFClose(out);
+ _TIFFfree(rowbuf);
+ _TIFFfree(refbuf);
+ return (EXIT_SUCCESS);
+}
+
+int
+copyFaxFile(TIFF* tifin, TIFF* tifout)
+{
+ uint32 row;
+ uint32 linesize = TIFFhowmany8(xsize);
+ uint16 badrun;
+ int ok;
+
+ tifin->tif_rawdatasize = TIFFGetFileSize(tifin);
+ tifin->tif_rawdata = _TIFFmalloc(tifin->tif_rawdatasize);
+ if (tifin->tif_rawdata == NULL) {
+ TIFFError(tifin->tif_name, "Not enough memory");
+ return (0);
+ }
+ if (!ReadOK(tifin, tifin->tif_rawdata, tifin->tif_rawdatasize)) {
+ TIFFError(tifin->tif_name, "Read error at scanline 0");
+ return (0);
+ }
+ tifin->tif_rawcp = tifin->tif_rawdata;
+ tifin->tif_rawcc = tifin->tif_rawdatasize;
+
+ (*tifin->tif_setupdecode)(tifin);
+ (*tifin->tif_predecode)(tifin, (tsample_t) 0);
+ tifin->tif_row = 0;
+ badfaxlines = 0;
+ badfaxrun = 0;
+
+ _TIFFmemset(refbuf, 0, linesize);
+ row = 0;
+ badrun = 0; /* current run of bad lines */
+ while (tifin->tif_rawcc > 0) {
+ ok = (*tifin->tif_decoderow)(tifin, (tdata_t) rowbuf,
+ linesize, 0);
+ if (!ok) {
+ badfaxlines++;
+ badrun++;
+ /* regenerate line from previous good line */
+ _TIFFmemcpy(rowbuf, refbuf, linesize);
+ } else {
+ if (badrun > badfaxrun)
+ badfaxrun = badrun;
+ badrun = 0;
+ _TIFFmemcpy(refbuf, rowbuf, linesize);
+ }
+ tifin->tif_row++;
+
+ if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) {
+ fprintf(stderr, "%s: Write error at row %ld.\n",
+ tifout->tif_name, (long) row);
+ break;
+ }
+ row++;
+ if (stretch) {
+ if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) {
+ fprintf(stderr, "%s: Write error at row %ld.\n",
+ tifout->tif_name, (long) row);
+ break;
+ }
+ row++;
+ }
+ }
+ if (badrun > badfaxrun)
+ badfaxrun = badrun;
+ _TIFFfree(tifin->tif_rawdata);
+ return (row);
+}
+
+char* stuff[] = {
+"usage: fax2tiff [options] input.raw...",
+"where options are:",
+" -3 input data is G3-encoded [default]",
+" -4 input data is G4-encoded",
+" -U input data is uncompressed (G3 or G4)",
+" -1 input data is 1D-encoded (G3 only) [default]",
+" -2 input data is 2D-encoded (G3 only)",
+" -P input is not EOL-aligned (G3 only) [default]",
+" -A input is EOL-aligned (G3 only)",
+" -M input data has MSB2LSB bit order",
+" -L input data has LSB2MSB bit order [default]",
+" -B input data has min 0 means black",
+" -W input data has min 0 means white [default]",
+" -R # input data has # resolution (lines/inch) [default is 196]",
+" -X # input data has # width [default is 1728]",
+"",
+" -o out.tif write output to out.tif",
+" -7 generate G3-encoded output [default]",
+" -8 generate G4-encoded output",
+" -u generate uncompressed output (G3 or G4)",
+" -5 generate 1D-encoded output (G3 only)",
+" -6 generate 2D-encoded output (G3 only) [default]",
+" -p generate not EOL-aligned output (G3 only)",
+" -a generate EOL-aligned output (G3 only) [default]",
+" -c generate \"classic\" TIFF format",
+" -f generate TIFF Class F (TIFF/F) format [default]",
+" -m output fill order is MSB2LSB",
+" -l output fill order is LSB2MSB [default]",
+" -r # make each strip have no more than # rows",
+" -s stretch image by duplicating scanlines",
+" -v print information about conversion work",
+" -z generate LZW compressed output",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(EXIT_FAILURE);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/gif2tiff.c b/tiff/tools/gif2tiff.c
new file mode 100644
index 0000000..9c2cfa4
--- /dev/null
+++ b/tiff/tools/gif2tiff.c
@@ -0,0 +1,522 @@
+/* $Id: gif2tiff.c,v 1.8.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * convert a GIF file into a TIFF file.
+ * based on Paul Haeberli's fromgif program which in turn is
+ * based on a GIF file reader by Marcel J.E. Mol March 23 1989
+ *
+ * if input is 320 by 200 pixel aspect is probably 1.2
+ * if input is 640 350 pixel aspect is probably 1.37
+ *
+ */
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define GIFGAMMA (1.5) /* smaller makes output img brighter */
+#define IMAX 0xffff /* max intensity value */
+#define EXTRAFUDGE 128 /* some people write BAD .gif files */
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+unsigned short gamtab[256];
+
+void
+makegamtab(float gam)
+{
+ int i;
+
+ for(i=0; i<256; i++)
+ gamtab[i] = (unsigned short) (IMAX*pow(i/255.0,gam)+0.5);
+}
+
+char* stuff[] = {
+"usage: gif2tiff [options] input.gif output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+#define COLSIZE 256
+
+unsigned char *stackp;
+unsigned int prefix[4096];
+unsigned char suffix[4096];
+unsigned char stack[4096];
+int datasize,codesize,codemask; /* Decoder working variables */
+int clear,eoi; /* Special code values */
+int avail, oldcode;
+
+FILE *infile;
+int global; /* Is there a global color map? */
+int globalbits; /* Number of bits of global colors */
+unsigned char globalmap[COLSIZE][3];/* RGB values for global color map */
+unsigned char *raster; /* Decoded image data */
+unsigned long width, height;
+unsigned short red[COLSIZE];
+unsigned short green[COLSIZE];
+unsigned short blue[COLSIZE];
+char *filename, *imagename;
+
+static uint16 compression = COMPRESSION_PACKBITS;
+static uint16 predictor = 0;
+static uint32 rowsperstrip = (uint32) -1;
+static int processCompressOptions(char*);
+
+int convert(void);
+int checksignature(void);
+void readscreen(void);
+int readgifimage(char*);
+void readextension(void);
+int readraster(void);
+int process(int, unsigned char**);
+void initcolors(unsigned char [COLSIZE][3], int);
+void rasterize(int, char*);
+
+int
+main(int argc, char* argv[])
+{
+ extern int optind;
+ extern char *optarg;
+ int c, status;
+
+ while ((c = getopt(argc, argv, "c:r:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+
+ makegamtab(GIFGAMMA);
+ filename = argv[optind];
+ imagename = argv[optind+1];
+ if ((infile = fopen(imagename, "rb")) != NULL) {
+ int c;
+ fclose(infile);
+ printf("overwrite %s? ", imagename); fflush(stdout);
+ c = getc(stdin);
+ if (c != 'y' && c != 'Y')
+ return (1);
+ }
+ if ((infile = fopen(filename, "rb")) == NULL) {
+ perror(filename);
+ return (1);
+ }
+ status = convert();
+ fclose(infile);
+ return (status);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+int
+convert(void)
+{
+ int ch;
+ char* mode = "w";
+
+ if (!checksignature())
+ return (-1);
+ readscreen();
+ while ((ch = getc(infile)) != ';' && ch != EOF) {
+ switch (ch) {
+ case '\0': break; /* this kludge for non-standard files */
+ case ',': if (!readgifimage(mode))
+ return (-1);
+ mode = "a"; /* subsequent images append */
+ break;
+ case '!': readextension();
+ break;
+ default: fprintf(stderr, "illegal GIF block type\n");
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+int
+checksignature(void)
+{
+ char buf[6];
+
+ fread(buf,1,6,infile);
+ if (strncmp(buf,"GIF",3)) {
+ fprintf(stderr, "file is not a GIF file\n");
+ return 0;
+ }
+ if (strncmp(&buf[3],"87a",3)) {
+ fprintf(stderr, "unknown GIF version number\n");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * readscreen -
+ * Get information which is global to all the images stored
+ * in the file
+ */
+void
+readscreen(void)
+{
+ unsigned char buf[7];
+
+ fread(buf,1,7,infile);
+ global = buf[4] & 0x80;
+ if (global) {
+ globalbits = (buf[4] & 0x07) + 1;
+ fread(globalmap,3,1<<globalbits,infile);
+ }
+}
+
+int
+readgifimage(char* mode)
+{
+ unsigned char buf[9];
+ int local, interleaved;
+ unsigned char localmap[256][3];
+ int localbits;
+ int status;
+
+ if (fread(buf, 1, 9, infile) == 0) {
+ perror(filename);
+ return (0);
+ }
+ width = buf[4] + (buf[5] << 8);
+ height = buf[6] + (buf[7] << 8);
+ local = buf[8] & 0x80;
+ interleaved = buf[8] & 0x40;
+
+ if (local == 0 && global == 0) {
+ fprintf(stderr, "no colormap present for image\n");
+ return (0);
+ }
+ if ((raster = (unsigned char*) _TIFFmalloc(width*height+EXTRAFUDGE)) == NULL) {
+ fprintf(stderr, "not enough memory for image\n");
+ return (0);
+ }
+ if (local) {
+ localbits = (buf[8] & 0x7) + 1;
+
+ fprintf(stderr, " local colors: %d\n", 1<<localbits);
+
+ fread(localmap, 3, 1<<localbits, infile);
+ initcolors(localmap, 1<<localbits);
+ } else if (global) {
+ initcolors(globalmap, 1<<globalbits);
+ }
+ if ((status = readraster()))
+ rasterize(interleaved, mode);
+ _TIFFfree(raster);
+ return status;
+}
+
+/*
+ * readextension -
+ * Read a GIF extension block (and do nothing with it).
+ *
+ */
+void
+readextension(void)
+{
+ int count;
+ char buf[255];
+
+ (void) getc(infile);
+ while ((count = getc(infile)))
+ fread(buf, 1, count, infile);
+}
+
+/*
+ * readraster -
+ * Decode a raster image
+ *
+ */
+int
+readraster(void)
+{
+ unsigned char *fill = raster;
+ unsigned char buf[255];
+ register int bits=0;
+ register unsigned long datum=0;
+ register unsigned char *ch;
+ register int count, code;
+ int status = 1;
+
+ datasize = getc(infile);
+ clear = 1 << datasize;
+ eoi = clear + 1;
+ avail = clear + 2;
+ oldcode = -1;
+ codesize = datasize + 1;
+ codemask = (1 << codesize) - 1;
+ for (code = 0; code < clear; code++) {
+ prefix[code] = 0;
+ suffix[code] = code;
+ }
+ stackp = stack;
+ for (count = getc(infile); count > 0; count = getc(infile)) {
+ fread(buf,1,count,infile);
+ for (ch=buf; count-- > 0; ch++) {
+ datum += (unsigned long) *ch << bits;
+ bits += 8;
+ while (bits >= codesize) {
+ code = datum & codemask;
+ datum >>= codesize;
+ bits -= codesize;
+ if (code == eoi) { /* This kludge put in */
+ goto exitloop; /* because some GIF files*/
+ } /* aren't standard */
+ if (!process(code, &fill)) {
+ status = 0;
+ goto exitloop;
+ }
+ }
+ }
+ if (fill >= raster + width*height) {
+ fprintf(stderr, "raster full before eoi code\n");
+ break;
+ }
+ }
+exitloop:
+ if (fill != raster + width*height) {
+ fprintf(stderr, "warning: wrong rastersize: %ld bytes\n",
+ (long) (fill-raster));
+ fprintf(stderr, " instead of %ld bytes\n",
+ (long) width*height);
+ }
+ return status;
+}
+
+/*
+ * process -
+ * Process a compression code. "clear" resets the code table.
+ * Otherwise make a new code table entry, and output the bytes
+ * associated with the code.
+ */
+int
+process(register int code, unsigned char** fill)
+{
+ int incode;
+ static unsigned char firstchar;
+
+ if (code == clear) {
+ codesize = datasize + 1;
+ codemask = (1 << codesize) - 1;
+ avail = clear + 2;
+ oldcode = -1;
+ return 1;
+ }
+
+ if (oldcode == -1) {
+ *(*fill)++ = suffix[code];
+ firstchar = oldcode = code;
+ return 1;
+ }
+ if (code > avail) {
+ fprintf(stderr, "code %d too large for %d\n", code, avail);
+ return 0;
+ }
+
+ incode = code;
+ if (code == avail) { /* the first code is always < avail */
+ *stackp++ = firstchar;
+ code = oldcode;
+ }
+ while (code > clear) {
+ *stackp++ = suffix[code];
+ code = prefix[code];
+ }
+
+ *stackp++ = firstchar = suffix[code];
+ prefix[avail] = oldcode;
+ suffix[avail] = firstchar;
+ avail++;
+
+ if (((avail & codemask) == 0) && (avail < 4096)) {
+ codesize++;
+ codemask += avail;
+ }
+ oldcode = incode;
+ do {
+ *(*fill)++ = *--stackp;
+ } while (stackp > stack);
+ return 1;
+}
+
+/*
+ * initcolors -
+ * Convert a color map (local or global) to arrays with R, G and B
+ * values.
+ *
+ */
+void
+initcolors(unsigned char colormap[COLSIZE][3], int ncolors)
+{
+ register int i;
+
+ for (i = 0; i < ncolors; i++) {
+ red[i] = gamtab[colormap[i][0]];
+ green[i] = gamtab[colormap[i][1]];
+ blue[i] = gamtab[colormap[i][2]];
+ }
+}
+
+void
+rasterize(int interleaved, char* mode)
+{
+ register unsigned long row;
+ unsigned char *newras;
+ unsigned char *ras;
+ TIFF *tif;
+ tstrip_t strip;
+ tsize_t stripsize;
+
+ if ((newras = (unsigned char*) _TIFFmalloc(width*height+EXTRAFUDGE)) == NULL) {
+ fprintf(stderr, "not enough memory for image\n");
+ return;
+ }
+#define DRAWSEGMENT(offset, step) { \
+ for (row = offset; row < height; row += step) { \
+ _TIFFmemcpy(newras + row*width, ras, width);\
+ ras += width; \
+ } \
+ }
+ ras = raster;
+ if (interleaved) {
+ DRAWSEGMENT(0, 8);
+ DRAWSEGMENT(4, 8);
+ DRAWSEGMENT(2, 4);
+ DRAWSEGMENT(1, 2);
+ } else
+ DRAWSEGMENT(0, 1);
+#undef DRAWSEGMENT
+
+ tif = TIFFOpen(imagename, mode);
+ if (!tif) {
+ TIFFError(imagename,"Can not open output image");
+ exit(-1);
+ }
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32) height);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,
+ rowsperstrip = TIFFDefaultStripSize(tif, rowsperstrip));
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ strip = 0;
+ stripsize = TIFFStripSize(tif);
+ for (row=0; row<height; row += rowsperstrip) {
+ if (TIFFWriteEncodedStrip(tif, strip, newras+row*width, stripsize) < 0)
+ break;
+ strip++;
+ }
+ TIFFClose(tif);
+
+ _TIFFfree(newras);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/pal2rgb.c b/tiff/tools/pal2rgb.c
new file mode 100644
index 0000000..ea5803f
--- /dev/null
+++ b/tiff/tools/pal2rgb.c
@@ -0,0 +1,431 @@
+/* $Id: pal2rgb.c,v 1.10.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+static void usage(void);
+static void cpTags(TIFF* in, TIFF* out);
+
+static int
+checkcmap(int n, uint16* r, uint16* g, uint16* b)
+{
+ while (n-- > 0)
+ if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+ return (16);
+ fprintf(stderr, "Warning, assuming 8-bit colormap.\n");
+ return (8);
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+
+static uint16 compression = (uint16) -1;
+static uint16 predictor = 0;
+static int quality = 75; /* JPEG quality */
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int processCompressOptions(char*);
+
+int
+main(int argc, char* argv[])
+{
+ uint16 bitspersample, shortv;
+ uint32 imagewidth, imagelength;
+ uint16 config = PLANARCONFIG_CONTIG;
+ uint32 rowsperstrip = (uint32) -1;
+ uint16 photometric = PHOTOMETRIC_RGB;
+ uint16 *rmap, *gmap, *bmap;
+ uint32 row;
+ int cmap = -1;
+ TIFF *in, *out;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "C:c:p:r:")) != -1)
+ switch (c) {
+ case 'C': /* force colormap interpretation */
+ cmap = atoi(optarg);
+ break;
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ config = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ config = PLANARCONFIG_CONTIG;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+ in = TIFFOpen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &shortv) ||
+ shortv != PHOTOMETRIC_PALETTE) {
+ fprintf(stderr, "%s: Expecting a palette image.\n",
+ argv[optind]);
+ return (-1);
+ }
+ if (!TIFFGetField(in, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
+ fprintf(stderr,
+ "%s: No colormap (not a valid palette image).\n",
+ argv[optind]);
+ return (-1);
+ }
+ bitspersample = 0;
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8) {
+ fprintf(stderr, "%s: Sorry, can only handle 8-bit images.\n",
+ argv[optind]);
+ return (-1);
+ }
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-2);
+ cpTags(in, out);
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
+ if (compression != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ else
+ TIFFGetField(in, TIFFTAG_COMPRESSION, &compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ else
+ photometric = PHOTOMETRIC_RGB;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip));
+ (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
+ if (cmap == -1)
+ cmap = checkcmap(1<<bitspersample, rmap, gmap, bmap);
+ if (cmap == 16) {
+ /*
+ * Convert 16-bit colormap to 8-bit.
+ */
+ int i;
+
+ for (i = (1<<bitspersample)-1; i >= 0; i--) {
+#define CVT(x) (((x) * 255) / ((1L<<16)-1))
+ rmap[i] = CVT(rmap[i]);
+ gmap[i] = CVT(gmap[i]);
+ bmap[i] = CVT(bmap[i]);
+ }
+ }
+ { unsigned char *ibuf, *obuf;
+ register unsigned char* pp;
+ register uint32 x;
+ ibuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(in));
+ obuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(out));
+ switch (config) {
+ case PLANARCONFIG_CONTIG:
+ for (row = 0; row < imagelength; row++) {
+ if (!TIFFReadScanline(in, ibuf, row, 0))
+ goto done;
+ pp = obuf;
+ for (x = 0; x < imagewidth; x++) {
+ *pp++ = (unsigned char) rmap[ibuf[x]];
+ *pp++ = (unsigned char) gmap[ibuf[x]];
+ *pp++ = (unsigned char) bmap[ibuf[x]];
+ }
+ if (!TIFFWriteScanline(out, obuf, row, 0))
+ goto done;
+ }
+ break;
+ case PLANARCONFIG_SEPARATE:
+ for (row = 0; row < imagelength; row++) {
+ if (!TIFFReadScanline(in, ibuf, row, 0))
+ goto done;
+ for (pp = obuf, x = 0; x < imagewidth; x++)
+ *pp++ = (unsigned char) rmap[ibuf[x]];
+ if (!TIFFWriteScanline(out, obuf, row, 0))
+ goto done;
+ for (pp = obuf, x = 0; x < imagewidth; x++)
+ *pp++ = (unsigned char) gmap[ibuf[x]];
+ if (!TIFFWriteScanline(out, obuf, row, 0))
+ goto done;
+ for (pp = obuf, x = 0; x < imagewidth; x++)
+ *pp++ = (unsigned char) bmap[ibuf[x]];
+ if (!TIFFWriteScanline(out, obuf, row, 0))
+ goto done;
+ }
+ break;
+ }
+ _TIFFfree(ibuf);
+ _TIFFfree(obuf);
+ }
+done:
+ (void) TIFFClose(in);
+ (void) TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+#undef CopyField4
+#undef CopyField3
+#undef CopyField2
+#undef CopyField
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_IMAGEWIDTH, 1, TIFF_LONG },
+ { TIFFTAG_IMAGELENGTH, 1, TIFF_LONG },
+ { TIFFTAG_BITSPERSAMPLE, 1, TIFF_SHORT },
+ { TIFFTAG_COMPRESSION, 1, TIFF_SHORT },
+ { TIFFTAG_FILLORDER, 1, TIFF_SHORT },
+ { TIFFTAG_ROWSPERSTRIP, 1, TIFF_LONG },
+ { TIFFTAG_GROUP3OPTIONS, 1, TIFF_LONG },
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_ORIENTATION, 1, TIFF_SHORT },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_PAGENUMBER, 2, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, 1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_BADFAXLINES, 1, TIFF_LONG },
+ { TIFFTAG_CLEANFAXDATA, 1, TIFF_SHORT },
+ { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_INKNAMES, 1, TIFF_ASCII },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+static void
+cpTags(TIFF* in, TIFF* out)
+{
+ struct cpTag *p;
+ for (p = tags; p < &tags[NTAGS]; p++)
+ cpTag(in, out, p->tag, p->count, p->type);
+}
+#undef NTAGS
+
+char* stuff[] = {
+"usage: pal2rgb [options] input.tif output.tif",
+"where options are:",
+" -p contig pack samples contiguously (e.g. RGBRGB...)",
+" -p separate store samples separately (e.g. RRR...GGG...BBB...)",
+" -r # make each strip have no more than # rows",
+" -C 8 assume 8-bit colormap values (instead of 16-bit)",
+" -C 16 assume 16-bit colormap values",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/ppm2tiff.c b/tiff/tools/ppm2tiff.c
new file mode 100644
index 0000000..6078459
--- /dev/null
+++ b/tiff/tools/ppm2tiff.c
@@ -0,0 +1,362 @@
+/* $Id: ppm2tiff.c,v 1.13.2.2 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+static uint16 compression = COMPRESSION_PACKBITS;
+static uint16 predictor = 0;
+static int quality = 75; /* JPEG quality */
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static uint32 g3opts;
+
+static void usage(void);
+static int processCompressOptions(char*);
+
+static void
+BadPPM(char* file)
+{
+ fprintf(stderr, "%s: Not a PPM file.\n", file);
+ exit(-2);
+}
+
+int
+main(int argc, char* argv[])
+{
+ uint16 photometric = 0;
+ uint32 rowsperstrip = (uint32) -1;
+ double resolution = -1;
+ unsigned char *buf = NULL;
+ tsize_t linebytes = 0;
+ uint16 spp = 1;
+ uint16 bpp = 8;
+ TIFF *out;
+ FILE *in;
+ unsigned int w, h, prec, row;
+ char *infile;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ if (argc < 2) {
+ fprintf(stderr, "%s: Too few arguments\n", argv[0]);
+ usage();
+ }
+ while ((c = getopt(argc, argv, "c:r:R:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'R': /* resolution */
+ resolution = atof(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+
+ if (optind + 2 < argc) {
+ fprintf(stderr, "%s: Too many arguments\n", argv[0]);
+ usage();
+ }
+
+ /*
+ * If only one file is specified, read input from
+ * stdin; otherwise usage is: ppm2tiff input output.
+ */
+ if (argc - optind > 1) {
+ infile = argv[optind++];
+ in = fopen(infile, "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: Can not open.\n", infile);
+ return (-1);
+ }
+ } else {
+ infile = "<stdin>";
+ in = stdin;
+#if defined(HAVE_SETMODE) && defined(O_BINARY)
+ setmode(fileno(stdin), O_BINARY);
+#endif
+ }
+
+ if (fgetc(in) != 'P')
+ BadPPM(infile);
+ switch (fgetc(in)) {
+ case '4': /* it's a PBM file */
+ bpp = 1;
+ spp = 1;
+ photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ case '5': /* it's a PGM file */
+ bpp = 8;
+ spp = 1;
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case '6': /* it's a PPM file */
+ bpp = 8;
+ spp = 3;
+ photometric = PHOTOMETRIC_RGB;
+ if (compression == COMPRESSION_JPEG &&
+ jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ break;
+ default:
+ BadPPM(infile);
+ }
+
+ /* Parse header */
+ while(1) {
+ if (feof(in))
+ BadPPM(infile);
+ c = fgetc(in);
+ /* Skip whitespaces (blanks, TABs, CRs, LFs) */
+ if (strchr(" \t\r\n", c))
+ continue;
+
+ /* Check for comment line */
+ if (c == '#') {
+ do {
+ c = fgetc(in);
+ } while(!(strchr("\r\n", c) || feof(in)));
+ continue;
+ }
+
+ ungetc(c, in);
+ break;
+ }
+ switch (bpp) {
+ case 1:
+ if (fscanf(in, " %u %u", &w, &h) != 2)
+ BadPPM(infile);
+ if (fgetc(in) != '\n')
+ BadPPM(infile);
+ break;
+ case 8:
+ if (fscanf(in, " %u %u %u", &w, &h, &prec) != 3)
+ BadPPM(infile);
+ if (fgetc(in) != '\n' || prec != 255)
+ BadPPM(infile);
+ break;
+ }
+ out = TIFFOpen(argv[optind], "w");
+ if (out == NULL)
+ return (-4);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) w);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) h);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, spp);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bpp);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ case COMPRESSION_CCITTFAX3:
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts);
+ break;
+ }
+ switch (bpp) {
+ case 1:
+ linebytes = (spp * w + (8 - 1)) / 8;
+ if (rowsperstrip == (uint32) -1) {
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, h);
+ } else {
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ }
+ break;
+ case 8:
+ linebytes = spp * w;
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ break;
+ }
+ if (TIFFScanlineSize(out) > linebytes)
+ buf = (unsigned char *)_TIFFmalloc(linebytes);
+ else
+ buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));
+ if (resolution > 0) {
+ TIFFSetField(out, TIFFTAG_XRESOLUTION, resolution);
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, resolution);
+ TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ }
+ for (row = 0; row < h; row++) {
+ if (fread(buf, linebytes, 1, in) != 1) {
+ fprintf(stderr, "%s: scanline %lu: Read error.\n",
+ infile, (unsigned long) row);
+ break;
+ }
+ if (TIFFWriteScanline(out, buf, row, 0) < 0)
+ break;
+ }
+ (void) TIFFClose(out);
+ if (buf)
+ _TIFFfree(buf);
+ return (0);
+}
+
+static void
+processG3Options(char* cp)
+{
+ g3opts = 0;
+ if( (cp = strchr(cp, ':')) ) {
+ do {
+ cp++;
+ if (strneq(cp, "1d", 2))
+ g3opts &= ~GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "2d", 2))
+ g3opts |= GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "fill", 4))
+ g3opts |= GROUP3OPT_FILLBITS;
+ else
+ usage();
+ } while( (cp = strchr(cp, ':')) );
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while (cp)
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "g3", 2)) {
+ processG3Options(opt);
+ compression = COMPRESSION_CCITTFAX3;
+ } else if (streq(opt, "g4")) {
+ compression = COMPRESSION_CCITTFAX4;
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+char* stuff[] = {
+"usage: ppm2tiff [options] input.ppm output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+" -R # set x&y resolution (dpi)",
+"",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding (the default)",
+" -c g3[:opts] compress output with CCITT Group 3 encoding",
+" -c g4 compress output with CCITT Group 4 encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/ras2tiff.c b/tiff/tools/ras2tiff.c
new file mode 100644
index 0000000..e108b94
--- /dev/null
+++ b/tiff/tools/ras2tiff.c
@@ -0,0 +1,306 @@
+/* $Id: ras2tiff.c,v 1.15.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "rasterfile.h"
+#include "tiffio.h"
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+static uint16 compression = (uint16) -1;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+static uint16 predictor = 0;
+
+static void usage(void);
+static int processCompressOptions(char*);
+
+int
+main(int argc, char* argv[])
+{
+ unsigned char* buf;
+ long row;
+ tsize_t linebytes, scanline;
+ TIFF *out;
+ FILE *in;
+ struct rasterfile h;
+ uint16 photometric;
+ uint16 config = PLANARCONFIG_CONTIG;
+ uint32 rowsperstrip = (uint32) -1;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:r:h")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'h':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+ in = fopen(argv[optind], "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: Can not open.\n", argv[optind]);
+ return (-1);
+ }
+ if (fread(&h, sizeof (h), 1, in) != 1) {
+ fprintf(stderr, "%s: Can not read header.\n", argv[optind]);
+ return (-2);
+ }
+ if (strcmp(h.ras_magic, RAS_MAGIC) == 0) {
+#ifndef WORDS_BIGENDIAN
+ TIFFSwabLong((uint32 *)&h.ras_width);
+ TIFFSwabLong((uint32 *)&h.ras_height);
+ TIFFSwabLong((uint32 *)&h.ras_depth);
+ TIFFSwabLong((uint32 *)&h.ras_length);
+ TIFFSwabLong((uint32 *)&h.ras_type);
+ TIFFSwabLong((uint32 *)&h.ras_maptype);
+ TIFFSwabLong((uint32 *)&h.ras_maplength);
+#endif
+ } else if (strcmp(h.ras_magic, RAS_MAGIC_INV) == 0) {
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabLong((uint32 *)&h.ras_width);
+ TIFFSwabLong((uint32 *)&h.ras_height);
+ TIFFSwabLong((uint32 *)&h.ras_depth);
+ TIFFSwabLong((uint32 *)&h.ras_length);
+ TIFFSwabLong((uint32 *)&h.ras_type);
+ TIFFSwabLong((uint32 *)&h.ras_maptype);
+ TIFFSwabLong((uint32 *)&h.ras_maplength);
+#endif
+ } else {
+ fprintf(stderr, "%s: Not a rasterfile.\n", argv[optind]);
+ return (-3);
+ }
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-4);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) h.ras_width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) h.ras_height);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, h.ras_depth > 8 ? 3 : 1);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, h.ras_depth > 1 ? 8 : 1);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ if (h.ras_maptype != RMT_NONE) {
+ uint16* red;
+ register uint16* map;
+ register int i, j;
+ int mapsize;
+
+ buf = (unsigned char *)_TIFFmalloc(h.ras_maplength);
+ if (buf == NULL) {
+ fprintf(stderr, "No space to read in colormap.\n");
+ return (-5);
+ }
+ if (fread(buf, h.ras_maplength, 1, in) != 1) {
+ fprintf(stderr, "%s: Read error on colormap.\n",
+ argv[optind]);
+ return (-6);
+ }
+ mapsize = 1<<h.ras_depth;
+ if (h.ras_maplength > mapsize*3) {
+ fprintf(stderr,
+ "%s: Huh, %ld colormap entries, should be %d?\n",
+ argv[optind], h.ras_maplength, mapsize*3);
+ return (-7);
+ }
+ red = (uint16*)_TIFFmalloc(mapsize * 3 * sizeof (uint16));
+ if (red == NULL) {
+ fprintf(stderr, "No space for colormap.\n");
+ return (-8);
+ }
+ map = red;
+ for (j = 0; j < 3; j++) {
+#define SCALE(x) (((x)*((1L<<16)-1))/255)
+ for (i = h.ras_maplength/3; i-- > 0;)
+ *map++ = SCALE(*buf++);
+ if ((i = h.ras_maplength/3) < mapsize) {
+ i = mapsize - i;
+ _TIFFmemset(map, 0, i*sizeof (uint16));
+ map += i;
+ }
+ }
+ TIFFSetField(out, TIFFTAG_COLORMAP,
+ red, red + mapsize, red + 2*mapsize);
+ photometric = PHOTOMETRIC_PALETTE;
+ if (compression == (uint16) -1)
+ compression = COMPRESSION_PACKBITS;
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ } else {
+ /* XXX this is bogus... */
+ photometric = h.ras_depth == 24 ?
+ PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
+ if (compression == (uint16) -1)
+ compression = COMPRESSION_LZW;
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ }
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ linebytes = ((h.ras_depth*h.ras_width+15) >> 3) &~ 1;
+ scanline = TIFFScanlineSize(out);
+ if (scanline > linebytes) {
+ buf = (unsigned char *)_TIFFmalloc(scanline);
+ _TIFFmemset(buf+linebytes, 0, scanline-linebytes);
+ } else
+ buf = (unsigned char *)_TIFFmalloc(linebytes);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ for (row = 0; row < h.ras_height; row++) {
+ if (fread(buf, linebytes, 1, in) != 1) {
+ fprintf(stderr, "%s: scanline %ld: Read error.\n",
+ argv[optind], row);
+ break;
+ }
+ if (h.ras_type == RT_STANDARD && h.ras_depth == 24) {
+ tsize_t cc = h.ras_width;
+ unsigned char* cp = buf;
+#define SWAP(a,b) { unsigned char t = (a); (a) = (b); (b) = t; }
+ do {
+ SWAP(cp[0], cp[2]);
+ cp += 3;
+ } while (--cc);
+ }
+ if (TIFFWriteScanline(out, buf, row, 0) < 0)
+ break;
+ }
+ (void) TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+char* stuff[] = {
+"usage: ras2tiff [options] input.ras output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+" -h this help message",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/rasterfile.h b/tiff/tools/rasterfile.h
new file mode 100644
index 0000000..7f214a5
--- /dev/null
+++ b/tiff/tools/rasterfile.h
@@ -0,0 +1,49 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/tools/rasterfile.h,v 1.3.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Description of header for files containing raster images
+ */
+struct rasterfile {
+ char ras_magic[4]; /* magic number */
+ long ras_width; /* width (pixels) of image */
+ long ras_height; /* height (pixels) of image */
+ long ras_depth; /* depth (1, 8, or 24 bits) of pixel */
+ long ras_length; /* length (bytes) of image */
+ long ras_type; /* type of file; see RT_* below */
+ long ras_maptype; /* type of colormap; see RMT_* below */
+ long ras_maplength; /* length (bytes) of following map */
+ /* color map follows for ras_maplength bytes, followed by image */
+};
+#define RAS_MAGIC "\x59\xa6\x6a\x95"
+#define RAS_MAGIC_INV "\x95\x6a\xa6\x59"
+
+ /* Sun supported ras_type's */
+#define RT_OLD 0 /* Raw pixrect image in 68000 byte order */
+#define RT_STANDARD 1 /* Raw pixrect image in 68000 byte order */
+#define RT_BYTE_ENCODED 2 /* Run-length compression of bytes */
+#define RT_EXPERIMENTAL 0xffff /* Reserved for testing */
+
+ /* Sun registered ras_maptype's */
+#define RMT_RAW 2
+ /* Sun supported ras_maptype's */
+#define RMT_NONE 0 /* ras_maplength is expected to be 0 */
+#define RMT_EQUAL_RGB 1 /* red[ras_maplength/3],green[],blue[] */
+
+/*
+ * NOTES:
+ * Each line of the image is rounded out to a multiple of 16 bits.
+ * This corresponds to the rounding convention used by the memory pixrect
+ * package (/usr/include/pixrect/memvar.h) of the SunWindows system.
+ * The ras_encoding field (always set to 0 by Sun's supported software)
+ * was renamed to ras_length in release 2.0. As a result, rasterfiles
+ * of type 0 generated by the old software claim to have 0 length; for
+ * compatibility, code reading rasterfiles must be prepared to compute the
+ * true length from the width, height, and depth fields.
+ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/raw2tiff.c b/tiff/tools/raw2tiff.c
new file mode 100644
index 0000000..17eb0e4
--- /dev/null
+++ b/tiff/tools/raw2tiff.c
@@ -0,0 +1,647 @@
+/* $Id: raw2tiff.c,v 1.23.2.1 2010-06-08 18:50:44 bfriesen Exp $
+ *
+ * Project: libtiff tools
+ * Purpose: Convert raw byte sequences in TIFF images
+ * Author: Andrey Kiselev, dron@ak4719.spb.edu
+ *
+ ******************************************************************************
+ * Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <math.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+typedef enum {
+ PIXEL,
+ BAND
+} InterleavingType;
+
+static uint16 compression = (uint16) -1;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+static uint16 predictor = 0;
+
+static void swapBytesInScanline(void *, uint32, TIFFDataType);
+static int guessSize(int, TIFFDataType, off_t, uint32, int,
+ uint32 *, uint32 *);
+static double correlation(void *, void *, uint32, TIFFDataType);
+static void usage(void);
+static int processCompressOptions(char*);
+
+int
+main(int argc, char* argv[])
+{
+ uint32 width = 0, length = 0, linebytes, bufsize;
+ uint32 nbands = 1; /* number of bands in input image*/
+ off_t hdr_size = 0; /* size of the header to skip */
+ TIFFDataType dtype = TIFF_BYTE;
+ int16 depth = 1; /* bytes per pixel in input image */
+ int swab = 0; /* byte swapping flag */
+ InterleavingType interleaving = 0; /* interleaving type flag */
+ uint32 rowsperstrip = (uint32) -1;
+ uint16 photometric = PHOTOMETRIC_MINISBLACK;
+ uint16 config = PLANARCONFIG_CONTIG;
+ uint16 fillorder = FILLORDER_LSB2MSB;
+ int fd;
+ char *outfilename = NULL;
+ TIFF *out;
+
+ uint32 row, col, band;
+ int c;
+ unsigned char *buf = NULL, *buf1 = NULL;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:r:H:w:l:b:d:LMp:si:o:h")) != -1) {
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'H': /* size of input image file header */
+ hdr_size = atoi(optarg);
+ break;
+ case 'w': /* input image width */
+ width = atoi(optarg);
+ break;
+ case 'l': /* input image length */
+ length = atoi(optarg);
+ break;
+ case 'b': /* number of bands in input image */
+ nbands = atoi(optarg);
+ break;
+ case 'd': /* type of samples in input image */
+ if (strncmp(optarg, "byte", 4) == 0)
+ dtype = TIFF_BYTE;
+ else if (strncmp(optarg, "short", 5) == 0)
+ dtype = TIFF_SHORT;
+ else if (strncmp(optarg, "long", 4) == 0)
+ dtype = TIFF_LONG;
+ else if (strncmp(optarg, "sbyte", 5) == 0)
+ dtype = TIFF_SBYTE;
+ else if (strncmp(optarg, "sshort", 6) == 0)
+ dtype = TIFF_SSHORT;
+ else if (strncmp(optarg, "slong", 5) == 0)
+ dtype = TIFF_SLONG;
+ else if (strncmp(optarg, "float", 5) == 0)
+ dtype = TIFF_FLOAT;
+ else if (strncmp(optarg, "double", 6) == 0)
+ dtype = TIFF_DOUBLE;
+ else
+ dtype = TIFF_BYTE;
+ depth = TIFFDataWidth(dtype);
+ break;
+ case 'L': /* input has lsb-to-msb fillorder */
+ fillorder = FILLORDER_LSB2MSB;
+ break;
+ case 'M': /* input has msb-to-lsb fillorder */
+ fillorder = FILLORDER_MSB2LSB;
+ break;
+ case 'p': /* photometric interpretation */
+ if (strncmp(optarg, "miniswhite", 10) == 0)
+ photometric = PHOTOMETRIC_MINISWHITE;
+ else if (strncmp(optarg, "minisblack", 10) == 0)
+ photometric = PHOTOMETRIC_MINISBLACK;
+ else if (strncmp(optarg, "rgb", 3) == 0)
+ photometric = PHOTOMETRIC_RGB;
+ else if (strncmp(optarg, "cmyk", 4) == 0)
+ photometric = PHOTOMETRIC_SEPARATED;
+ else if (strncmp(optarg, "ycbcr", 5) == 0)
+ photometric = PHOTOMETRIC_YCBCR;
+ else if (strncmp(optarg, "cielab", 6) == 0)
+ photometric = PHOTOMETRIC_CIELAB;
+ else if (strncmp(optarg, "icclab", 6) == 0)
+ photometric = PHOTOMETRIC_ICCLAB;
+ else if (strncmp(optarg, "itulab", 6) == 0)
+ photometric = PHOTOMETRIC_ITULAB;
+ else
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 's': /* do we need to swap bytes? */
+ swab = 1;
+ break;
+ case 'i': /* type of interleaving */
+ if (strncmp(optarg, "pixel", 4) == 0)
+ interleaving = PIXEL;
+ else if (strncmp(optarg, "band", 6) == 0)
+ interleaving = BAND;
+ else
+ interleaving = 0;
+ break;
+ case 'o':
+ outfilename = optarg;
+ break;
+ case 'h':
+ usage();
+ default:
+ break;
+ }
+ }
+
+ if (argc - optind < 2)
+ usage();
+
+ fd = open(argv[optind], O_RDONLY|O_BINARY, 0);
+ if (fd < 0) {
+ fprintf(stderr, "%s: %s: Cannot open input file.\n",
+ argv[0], argv[optind]);
+ return (-1);
+ }
+
+ if (guessSize(fd, dtype, hdr_size, nbands, swab, &width, &length) < 0)
+ return 1;
+
+ if (outfilename == NULL)
+ outfilename = argv[optind+1];
+ out = TIFFOpen(outfilename, "w");
+ if (out == NULL) {
+ fprintf(stderr, "%s: %s: Cannot open file for output.\n",
+ argv[0], outfilename);
+ return (-1);
+ }
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, nbands);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, depth * 8);
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ switch (dtype) {
+ case TIFF_BYTE:
+ case TIFF_SHORT:
+ case TIFF_LONG:
+ TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ break;
+ case TIFF_SBYTE:
+ case TIFF_SSHORT:
+ case TIFF_SLONG:
+ TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
+ break;
+ case TIFF_FLOAT:
+ case TIFF_DOUBLE:
+ TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
+ break;
+ default:
+ TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_VOID);
+ break;
+ }
+ if (compression == (uint16) -1)
+ compression = COMPRESSION_PACKBITS;
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB
+ && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ switch(interleaving) {
+ case BAND: /* band interleaved data */
+ linebytes = width * depth;
+ buf = (unsigned char *)_TIFFmalloc(linebytes);
+ break;
+ case PIXEL: /* pixel interleaved data */
+ default:
+ linebytes = width * nbands * depth;
+ break;
+ }
+ bufsize = width * nbands * depth;
+ buf1 = (unsigned char *)_TIFFmalloc(bufsize);
+
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ if (rowsperstrip > length) {
+ rowsperstrip = length;
+ }
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip );
+
+ lseek(fd, hdr_size, SEEK_SET); /* Skip the file header */
+ for (row = 0; row < length; row++) {
+ switch(interleaving) {
+ case BAND: /* band interleaved data */
+ for (band = 0; band < nbands; band++) {
+ lseek(fd,
+ hdr_size + (length*band+row)*linebytes,
+ SEEK_SET);
+ if (read(fd, buf, linebytes) < 0) {
+ fprintf(stderr,
+ "%s: %s: scanline %lu: Read error.\n",
+ argv[0], argv[optind],
+ (unsigned long) row);
+ break;
+ }
+ if (swab) /* Swap bytes if needed */
+ swapBytesInScanline(buf, width, dtype);
+ for (col = 0; col < width; col++)
+ memcpy(buf1 + (col*nbands+band)*depth,
+ buf + col * depth, depth);
+ }
+ break;
+ case PIXEL: /* pixel interleaved data */
+ default:
+ if (read(fd, buf1, bufsize) < 0) {
+ fprintf(stderr,
+ "%s: %s: scanline %lu: Read error.\n",
+ argv[0], argv[optind],
+ (unsigned long) row);
+ break;
+ }
+ if (swab) /* Swap bytes if needed */
+ swapBytesInScanline(buf1, width, dtype);
+ break;
+ }
+
+ if (TIFFWriteScanline(out, buf1, row, 0) < 0) {
+ fprintf(stderr, "%s: %s: scanline %lu: Write error.\n",
+ argv[0], outfilename, (unsigned long) row);
+ break;
+ }
+ }
+ if (buf)
+ _TIFFfree(buf);
+ if (buf1)
+ _TIFFfree(buf1);
+ TIFFClose(out);
+ return (0);
+}
+
+static void
+swapBytesInScanline(void *buf, uint32 width, TIFFDataType dtype)
+{
+ switch (dtype) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*)buf,
+ (unsigned long)width);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ TIFFSwabArrayOfLong((uint32*)buf,
+ (unsigned long)width);
+ break;
+ /* case TIFF_FLOAT: */ /* FIXME */
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*)buf,
+ (unsigned long)width);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+guessSize(int fd, TIFFDataType dtype, off_t hdr_size, uint32 nbands,
+ int swab, uint32 *width, uint32 *length)
+{
+ const float longt = 40.0; /* maximum possible height/width ratio */
+ char *buf1, *buf2;
+ struct stat filestat;
+ uint32 w, h, scanlinesize, imagesize;
+ uint32 depth = TIFFDataWidth(dtype);
+ float cor_coef = 0, tmp;
+
+ fstat(fd, &filestat);
+
+ if (filestat.st_size < hdr_size) {
+ fprintf(stderr, "Too large header size specified.\n");
+ return -1;
+ }
+
+ imagesize = (filestat.st_size - hdr_size) / nbands / depth;
+
+ if (*width != 0 && *length == 0) {
+ fprintf(stderr, "Image height is not specified.\n");
+
+ *length = imagesize / *width;
+
+ fprintf(stderr, "Height is guessed as %lu.\n",
+ (unsigned long)*length);
+
+ return 1;
+ } else if (*width == 0 && *length != 0) {
+ fprintf(stderr, "Image width is not specified.\n");
+
+ *width = imagesize / *length;
+
+ fprintf(stderr, "Width is guessed as %lu.\n",
+ (unsigned long)*width);
+
+ return 1;
+ } else if (*width == 0 && *length == 0) {
+ fprintf(stderr, "Image width and height are not specified.\n");
+
+ for (w = (uint32) sqrt(imagesize / longt);
+ w < sqrt(imagesize * longt);
+ w++) {
+ if (imagesize % w == 0) {
+ scanlinesize = w * depth;
+ buf1 = _TIFFmalloc(scanlinesize);
+ buf2 = _TIFFmalloc(scanlinesize);
+ h = imagesize / w;
+ lseek(fd, hdr_size + (int)(h/2)*scanlinesize,
+ SEEK_SET);
+ read(fd, buf1, scanlinesize);
+ read(fd, buf2, scanlinesize);
+ if (swab) {
+ swapBytesInScanline(buf1, w, dtype);
+ swapBytesInScanline(buf2, w, dtype);
+ }
+ tmp = (float) fabs(correlation(buf1, buf2,
+ w, dtype));
+ if (tmp > cor_coef) {
+ cor_coef = tmp;
+ *width = w, *length = h;
+ }
+
+ _TIFFfree(buf1);
+ _TIFFfree(buf2);
+ }
+ }
+
+ fprintf(stderr,
+ "Width is guessed as %lu, height is guessed as %lu.\n",
+ (unsigned long)*width, (unsigned long)*length);
+
+ return 1;
+ } else {
+ if (filestat.st_size<(off_t)(hdr_size+(*width)*(*length)*nbands*depth)) {
+ fprintf(stderr, "Input file too small.\n");
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+/* Calculate correlation coefficient between two numeric vectors */
+static double
+correlation(void *buf1, void *buf2, uint32 n_elem, TIFFDataType dtype)
+{
+ double X, Y, M1 = 0.0, M2 = 0.0, D1 = 0.0, D2 = 0.0, K = 0.0;
+ uint32 i;
+
+ switch (dtype) {
+ case TIFF_BYTE:
+ default:
+ for (i = 0; i < n_elem; i++) {
+ X = ((unsigned char *)buf1)[i];
+ Y = ((unsigned char *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_SBYTE:
+ for (i = 0; i < n_elem; i++) {
+ X = ((signed char *)buf1)[i];
+ Y = ((signed char *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_SHORT:
+ for (i = 0; i < n_elem; i++) {
+ X = ((uint16 *)buf1)[i];
+ Y = ((uint16 *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_SSHORT:
+ for (i = 0; i < n_elem; i++) {
+ X = ((int16 *)buf1)[i];
+ Y = ((int16 *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_LONG:
+ for (i = 0; i < n_elem; i++) {
+ X = ((uint32 *)buf1)[i];
+ Y = ((uint32 *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_SLONG:
+ for (i = 0; i < n_elem; i++) {
+ X = ((int32 *)buf1)[i];
+ Y = ((int32 *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_FLOAT:
+ for (i = 0; i < n_elem; i++) {
+ X = ((float *)buf1)[i];
+ Y = ((float *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_DOUBLE:
+ for (i = 0; i < n_elem; i++) {
+ X = ((double *)buf1)[i];
+ Y = ((double *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ }
+
+ M1 /= n_elem;
+ M2 /= n_elem;
+ D1 -= M1 * M1 * n_elem;
+ D2 -= M2 * M2 * n_elem;
+ K = (K - M1 * M2 * n_elem) / sqrt(D1 * D2);
+
+ return K;
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (strcmp(opt, "none") == 0)
+ compression = COMPRESSION_NONE;
+ else if (strcmp(opt, "packbits") == 0)
+ compression = COMPRESSION_PACKBITS;
+ else if (strncmp(opt, "jpeg", 4) == 0) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strncmp(opt, "lzw", 3) == 0) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strncmp(opt, "zip", 3) == 0) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+static char* stuff[] = {
+"raw2tiff --- tool for converting raw byte sequences in TIFF images",
+"usage: raw2tiff [options] input.raw output.tif",
+"where options are:",
+" -L input data has LSB2MSB bit order (default)",
+" -M input data has MSB2LSB bit order",
+" -r # make each strip have no more than # rows",
+" -H # size of input image file header in bytes (0 by default)",
+" -w # width of input image in pixels",
+" -l # length of input image in lines",
+" -b # number of bands in input image (1 by default)",
+"",
+" -d data_type type of samples in input image",
+"where data_type may be:",
+" byte 8-bit unsigned integer (default)",
+" short 16-bit unsigned integer",
+" long 32-bit unsigned integer",
+" sbyte 8-bit signed integer",
+" sshort 16-bit signed integer",
+" slong 32-bit signed integer",
+" float 32-bit IEEE floating point",
+" double 64-bit IEEE floating point",
+"",
+" -p photo photometric interpretation (color space) of the input image",
+"where photo may be:",
+" miniswhite white color represented with 0 value",
+" minisblack black color represented with 0 value (default)",
+" rgb image has RGB color model",
+" cmyk image has CMYK (separated) color model",
+" ycbcr image has YCbCr color model",
+" cielab image has CIE L*a*b color model",
+" icclab image has ICC L*a*b color model",
+" itulab image has ITU L*a*b color model",
+"",
+" -s swap bytes fetched from input file",
+"",
+" -i config type of samples interleaving in input image",
+"where config may be:",
+" pixel pixel interleaved data (default)",
+" band band interleaved data",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+" -o out.tif write output to out.tif",
+" -h this help message",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/rgb2ycbcr.c b/tiff/tools/rgb2ycbcr.c
new file mode 100644
index 0000000..0b30b51
--- /dev/null
+++ b/tiff/tools/rgb2ycbcr.c
@@ -0,0 +1,382 @@
+/* $Id: rgb2ycbcr.c,v 1.9.2.2 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffiop.h"
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define roundup(x, y) (howmany(x,y)*((uint32)(y)))
+
+#define LumaRed ycbcrCoeffs[0]
+#define LumaGreen ycbcrCoeffs[1]
+#define LumaBlue ycbcrCoeffs[2]
+
+uint16 compression = COMPRESSION_PACKBITS;
+uint32 rowsperstrip = (uint32) -1;
+
+uint16 horizSubSampling = 2; /* YCbCr horizontal subsampling */
+uint16 vertSubSampling = 2; /* YCbCr vertical subsampling */
+float ycbcrCoeffs[3] = { .299F, .587F, .114F };
+/* default coding range is CCIR Rec 601-1 with no headroom/footroom */
+float refBlackWhite[6] = { 0.F, 255.F, 128.F, 255.F, 128.F, 255.F };
+
+static int tiffcvt(TIFF* in, TIFF* out);
+static void usage(int code);
+static void setupLumaTables(void);
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *in, *out;
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "c:h:r:v:z")) != -1)
+ switch (c) {
+ case 'c':
+ if (streq(optarg, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(optarg, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (streq(optarg, "lzw"))
+ compression = COMPRESSION_LZW;
+ else if (streq(optarg, "jpeg"))
+ compression = COMPRESSION_JPEG;
+ else if (streq(optarg, "zip"))
+ compression = COMPRESSION_ADOBE_DEFLATE;
+ else
+ usage(-1);
+ break;
+ case 'h':
+ horizSubSampling = atoi(optarg);
+ break;
+ case 'v':
+ vertSubSampling = atoi(optarg);
+ break;
+ case 'r':
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'z': /* CCIR Rec 601-1 w/ headroom/footroom */
+ refBlackWhite[0] = 16.;
+ refBlackWhite[1] = 235.;
+ refBlackWhite[2] = 128.;
+ refBlackWhite[3] = 240.;
+ refBlackWhite[4] = 128.;
+ refBlackWhite[5] = 240.;
+ break;
+ case '?':
+ usage(0);
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage(-1);
+ out = TIFFOpen(argv[argc-1], "w");
+ if (out == NULL)
+ return (-2);
+ setupLumaTables();
+ for (; optind < argc-1; optind++) {
+ in = TIFFOpen(argv[optind], "r");
+ if (in != NULL) {
+ do {
+ if (!tiffcvt(in, out) ||
+ !TIFFWriteDirectory(out)) {
+ (void) TIFFClose(out);
+ return (1);
+ }
+ } while (TIFFReadDirectory(in));
+ (void) TIFFClose(in);
+ }
+ }
+ (void) TIFFClose(out);
+ return (0);
+}
+
+float *lumaRed;
+float *lumaGreen;
+float *lumaBlue;
+float D1, D2;
+int Yzero;
+
+static float*
+setupLuma(float c)
+{
+ float *v = (float *)_TIFFmalloc(256 * sizeof (float));
+ int i;
+ for (i = 0; i < 256; i++)
+ v[i] = c * i;
+ return (v);
+}
+
+static unsigned
+V2Code(float f, float RB, float RW, int CR)
+{
+ unsigned int c = (unsigned int)((((f)*(RW-RB)/CR)+RB)+.5);
+ return (c > 255 ? 255 : c);
+}
+
+static void
+setupLumaTables(void)
+{
+ lumaRed = setupLuma(LumaRed);
+ lumaGreen = setupLuma(LumaGreen);
+ lumaBlue = setupLuma(LumaBlue);
+ D1 = 1.F/(2.F - 2.F*LumaBlue);
+ D2 = 1.F/(2.F - 2.F*LumaRed);
+ Yzero = V2Code(0, refBlackWhite[0], refBlackWhite[1], 255);
+}
+
+static void
+cvtClump(unsigned char* op, uint32* raster, uint32 ch, uint32 cw, uint32 w)
+{
+ float Y, Cb = 0, Cr = 0;
+ uint32 j, k;
+ /*
+ * Convert ch-by-cw block of RGB
+ * to YCbCr and sample accordingly.
+ */
+ for (k = 0; k < ch; k++) {
+ for (j = 0; j < cw; j++) {
+ uint32 RGB = (raster - k*w)[j];
+ Y = lumaRed[TIFFGetR(RGB)] +
+ lumaGreen[TIFFGetG(RGB)] +
+ lumaBlue[TIFFGetB(RGB)];
+ /* accumulate chrominance */
+ Cb += (TIFFGetB(RGB) - Y) * D1;
+ Cr += (TIFFGetR(RGB) - Y) * D2;
+ /* emit luminence */
+ *op++ = V2Code(Y,
+ refBlackWhite[0], refBlackWhite[1], 255);
+ }
+ for (; j < horizSubSampling; j++)
+ *op++ = Yzero;
+ }
+ for (; k < vertSubSampling; k++) {
+ for (j = 0; j < horizSubSampling; j++)
+ *op++ = Yzero;
+ }
+ /* emit sampled chrominance values */
+ *op++ = V2Code(Cb / (ch*cw), refBlackWhite[2], refBlackWhite[3], 127);
+ *op++ = V2Code(Cr / (ch*cw), refBlackWhite[4], refBlackWhite[5], 127);
+}
+#undef LumaRed
+#undef LumaGreen
+#undef LumaBlue
+#undef V2Code
+
+/*
+ * Convert a strip of RGB data to YCbCr and
+ * sample to generate the output data.
+ */
+static void
+cvtStrip(unsigned char* op, uint32* raster, uint32 nrows, uint32 width)
+{
+ uint32 x;
+ int clumpSize = vertSubSampling * horizSubSampling + 2;
+ uint32 *tp;
+
+ for (; nrows >= vertSubSampling; nrows -= vertSubSampling) {
+ tp = raster;
+ for (x = width; x >= horizSubSampling; x -= horizSubSampling) {
+ cvtClump(op, tp,
+ vertSubSampling, horizSubSampling, width);
+ op += clumpSize;
+ tp += horizSubSampling;
+ }
+ if (x > 0) {
+ cvtClump(op, tp, vertSubSampling, x, width);
+ op += clumpSize;
+ }
+ raster -= vertSubSampling*width;
+ }
+ if (nrows > 0) {
+ tp = raster;
+ for (x = width; x >= horizSubSampling; x -= horizSubSampling) {
+ cvtClump(op, tp, nrows, horizSubSampling, width);
+ op += clumpSize;
+ tp += horizSubSampling;
+ }
+ if (x > 0)
+ cvtClump(op, tp, nrows, x, width);
+ }
+}
+
+static int
+cvtRaster(TIFF* tif, uint32* raster, uint32 width, uint32 height)
+{
+ uint32 y;
+ tstrip_t strip = 0;
+ tsize_t cc, acc;
+ unsigned char* buf;
+ uint32 rwidth = roundup(width, horizSubSampling);
+ uint32 rheight = roundup(height, vertSubSampling);
+ uint32 nrows = (rowsperstrip > rheight ? rheight : rowsperstrip);
+ uint32 rnrows = roundup(nrows,vertSubSampling);
+
+ cc = rnrows*rwidth +
+ 2*((rnrows*rwidth) / (horizSubSampling*vertSubSampling));
+ buf = (unsigned char*)_TIFFmalloc(cc);
+ for (y = height; (int32) y > 0; y -= nrows) {
+ uint32 nr = (y > nrows ? nrows : y);
+ cvtStrip(buf, raster + (y-1)*width, nr, width);
+ nr = roundup(nr, vertSubSampling);
+ acc = nr*rwidth +
+ 2*((nr*rwidth)/(horizSubSampling*vertSubSampling));
+ if (!TIFFWriteEncodedStrip(tif, strip++, buf, acc)) {
+ _TIFFfree(buf);
+ return (0);
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+static int
+tiffcvt(TIFF* in, TIFF* out)
+{
+ uint32 width, height; /* image width & height */
+ uint32* raster; /* retrieve RGBA image */
+ uint16 shortv;
+ float floatv;
+ char *stringv;
+ uint32 longv;
+
+ size_t pixel_count;
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+ pixel_count = width * height;
+
+ /* XXX: Check the integer overflow. */
+ if (!width || !height || pixel_count / width != height) {
+ TIFFError(TIFFFileName(in),
+ "Malformed input file; "
+ "can't allocate buffer for raster of %lux%lu size",
+ (unsigned long)width, (unsigned long)height);
+ return 0;
+ }
+
+ raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32),
+ "raster buffer");
+ if (raster == 0) {
+ TIFFError(TIFFFileName(in),
+ "Requested buffer size is %lu elements %lu each",
+ (unsigned long)pixel_count,
+ (unsigned long)sizeof(uint32));
+ return (0);
+ }
+
+ if (!TIFFReadRGBAImage(in, width, height, raster, 0)) {
+ _TIFFfree(raster);
+ return (0);
+ }
+
+ CopyField(TIFFTAG_SUBFILETYPE, longv);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ if (compression == COMPRESSION_JPEG)
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
+ CopyField(TIFFTAG_FILLORDER, shortv);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ { char buf[2048];
+ char *cp = strrchr(TIFFFileName(in), '/');
+ sprintf(buf, "YCbCr conversion of %s", cp ? cp+1 : TIFFFileName(in));
+ TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, buf);
+ }
+ TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
+ CopyField(TIFFTAG_DOCUMENTNAME, stringv);
+
+ TIFFSetField(out, TIFFTAG_REFERENCEBLACKWHITE, refBlackWhite);
+ TIFFSetField(out, TIFFTAG_YCBCRSUBSAMPLING,
+ horizSubSampling, vertSubSampling);
+ TIFFSetField(out, TIFFTAG_YCBCRPOSITIONING, YCBCRPOSITION_CENTERED);
+ TIFFSetField(out, TIFFTAG_YCBCRCOEFFICIENTS, ycbcrCoeffs);
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ return (cvtRaster(out, raster, width, height));
+}
+
+char* stuff[] = {
+ "usage: rgb2ycbcr [-c comp] [-r rows] [-h N] [-v N] input... output\n",
+ "where comp is one of the following compression algorithms:\n",
+ " jpeg\t\tJPEG encoding\n",
+ " lzw\t\tLempel-Ziv & Welch encoding\n",
+ " zip\t\tdeflate encoding\n",
+ " packbits\tPackBits encoding (default)\n",
+ " none\t\tno compression\n",
+ "and the other options are:\n",
+ " -r\trows/strip\n",
+ " -h\thorizontal sampling factor (1,2,4)\n",
+ " -v\tvertical sampling factor (1,2,4)\n",
+ NULL
+};
+
+static void
+usage(int code)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(code);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/sgi2tiff.c b/tiff/tools/sgi2tiff.c
new file mode 100644
index 0000000..2a495e1
--- /dev/null
+++ b/tiff/tools/sgi2tiff.c
@@ -0,0 +1,335 @@
+/* $Id: sgi2tiff.c,v 1.5.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gl/image.h>
+#include <ctype.h>
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+static short config = PLANARCONFIG_CONTIG;
+static uint16 compression = COMPRESSION_PACKBITS;
+static uint16 predictor = 0;
+static uint16 fillorder = 0;
+static uint32 rowsperstrip = (uint32) -1;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+static uint16 photometric;
+
+static void usage(void);
+static int cpContig(IMAGE*, TIFF*);
+static int cpSeparate(IMAGE*, TIFF*);
+static int processCompressOptions(char*);
+
+/* XXX image library has no prototypes */
+extern IMAGE* iopen(const char*, const char*);
+extern void iclose(IMAGE*);
+extern void getrow(IMAGE*, short*, int, int);
+
+int
+main(int argc, char* argv[])
+{
+ IMAGE *in;
+ TIFF *out;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:p:r:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'f': /* fill order */
+ if (streq(optarg, "lsb2msb"))
+ fillorder = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ fillorder = FILLORDER_MSB2LSB;
+ else
+ usage();
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ config = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ config = PLANARCONFIG_CONTIG;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+ in = iopen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-2);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) in->xsize);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) in->ysize);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ if (in->zsize == 1)
+ photometric = PHOTOMETRIC_MINISBLACK;
+ else
+ photometric = PHOTOMETRIC_RGB;
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ if (fillorder != 0)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, in->zsize);
+ if (in->zsize > 3) {
+ uint16 v[1];
+ v[0] = EXTRASAMPLE_UNASSALPHA;
+ TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v);
+ }
+ TIFFSetField(out, TIFFTAG_MINSAMPLEVALUE, (uint16) in->min);
+ TIFFSetField(out, TIFFTAG_MAXSAMPLEVALUE, (uint16) in->max);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ if (config != PLANARCONFIG_SEPARATE)
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ else /* force 1 row/strip for library limitation */
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 1L);
+ if (in->name[0] != '\0')
+ TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, in->name);
+ if (config == PLANARCONFIG_CONTIG)
+ cpContig(in, out);
+ else
+ cpSeparate(in, out);
+ (void) iclose(in);
+ (void) TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ defcompression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+static int
+cpContig(IMAGE* in, TIFF* out)
+{
+ tdata_t buf = _TIFFmalloc(TIFFScanlineSize(out));
+ short *r = NULL;
+ int x, y;
+
+ if (in->zsize == 3) {
+ short *g, *b;
+
+ r = (short *)_TIFFmalloc(3 * in->xsize * sizeof (short));
+ g = r + in->xsize;
+ b = g + in->xsize;
+ for (y = in->ysize-1; y >= 0; y--) {
+ uint8* pp = (uint8*) buf;
+
+ getrow(in, r, y, 0);
+ getrow(in, g, y, 1);
+ getrow(in, b, y, 2);
+ for (x = 0; x < in->xsize; x++) {
+ pp[0] = r[x];
+ pp[1] = g[x];
+ pp[2] = b[x];
+ pp += 3;
+ }
+ if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0)
+ goto bad;
+ }
+ } else if (in->zsize == 4) {
+ short *g, *b, *a;
+
+ r = (short *)_TIFFmalloc(4 * in->xsize * sizeof (short));
+ g = r + in->xsize;
+ b = g + in->xsize;
+ a = b + in->xsize;
+ for (y = in->ysize-1; y >= 0; y--) {
+ uint8* pp = (uint8*) buf;
+
+ getrow(in, r, y, 0);
+ getrow(in, g, y, 1);
+ getrow(in, b, y, 2);
+ getrow(in, a, y, 3);
+ for (x = 0; x < in->xsize; x++) {
+ pp[0] = r[x];
+ pp[1] = g[x];
+ pp[2] = b[x];
+ pp[3] = a[x];
+ pp += 4;
+ }
+ if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0)
+ goto bad;
+ }
+ } else {
+ uint8* pp = (uint8*) buf;
+
+ r = (short *)_TIFFmalloc(in->xsize * sizeof (short));
+ for (y = in->ysize-1; y >= 0; y--) {
+ getrow(in, r, y, 0);
+ for (x = in->xsize-1; x >= 0; x--)
+ pp[x] = r[x];
+ if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0)
+ goto bad;
+ }
+ }
+ if (r)
+ _TIFFfree(r);
+ _TIFFfree(buf);
+ return (1);
+bad:
+ if (r)
+ _TIFFfree(r);
+ _TIFFfree(buf);
+ return (0);
+}
+
+static int
+cpSeparate(IMAGE* in, TIFF* out)
+{
+ tdata_t buf = _TIFFmalloc(TIFFScanlineSize(out));
+ short *r = (short *)_TIFFmalloc(in->xsize * sizeof (short));
+ uint8* pp = (uint8*) buf;
+ int x, y, z;
+
+ for (z = 0; z < in->zsize; z++) {
+ for (y = in->ysize-1; y >= 0; y--) {
+ getrow(in, r, y, z);
+ for (x = 0; x < in->xsize; x++)
+ pp[x] = r[x];
+ if (TIFFWriteScanline(out, buf, in->ysize-y-1, z) < 0)
+ goto bad;
+ }
+ }
+ _TIFFfree(r);
+ _TIFFfree(buf);
+ return (1);
+bad:
+ _TIFFfree(r);
+ _TIFFfree(buf);
+ return (0);
+}
+
+char* stuff[] = {
+"usage: sgi2tiff [options] input.rgb output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+"",
+" -p contig pack samples contiguously (e.g. RGBRGB...)",
+" -p separate store samples separately (e.g. RRR...GGG...BBB...)",
+"",
+" -f lsb2msb force lsb-to-msb FillOrder for output",
+" -f msb2lsb force msb-to-lsb FillOrder for output",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts]compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/sgisv.c b/tiff/tools/sgisv.c
new file mode 100644
index 0000000..75f1022
--- /dev/null
+++ b/tiff/tools/sgisv.c
@@ -0,0 +1,316 @@
+/* $Id: sgisv.c,v 1.5.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gl.h>
+#include <ctype.h>
+
+#include "tiffio.h"
+
+typedef unsigned char unsigned char;
+typedef unsigned long uint32;
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+uint32 rowsperstrip = (uint32) -1;
+uint16 compression = COMPRESSION_PACKBITS;
+uint16 config = PLANARCONFIG_CONTIG;
+uint16 predictor = 0;
+int xmaxscreen;
+int ymaxscreen;
+uint16 photometric = PHOTOMETRIC_RGB;
+int jpegcolormode = JPEGCOLORMODE_RGB;
+int quality = 75; /* JPEG quality */
+
+static void usage(void);
+static void tiffsv(char*, int, int, int, int);
+
+int
+main(int argc, char* argv[])
+{
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:p:r:")) != -1)
+ switch (c) {
+ case 'b': /* save as b&w */
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 'c': /* compression scheme */
+ if (streq(optarg, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(optarg, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(optarg, "jpeg", 4)) {
+ char* cp = strchr(optarg, ':');
+ if (cp && isdigit(cp[1]))
+ quality = atoi(cp+1);
+ if (cp && strchr(cp, 'r'))
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ compression = COMPRESSION_JPEG;
+ } else if (strneq(optarg, "lzw", 3)) {
+ char* cp = strchr(optarg, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else
+ usage();
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ config = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ config = PLANARCONFIG_CONTIG;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 1 && argc - optind != 5)
+ usage();
+ xmaxscreen = getgdesc(GD_XPMAX)-1;
+ ymaxscreen = getgdesc(GD_YPMAX)-1;
+ foreground();
+ noport();
+ winopen("tiffsv");
+ if (argc - optind == 5)
+ tiffsv(argv[optind],
+ atoi(argv[optind+1]), atoi(argv[optind+2]),
+ atoi(argv[optind+3]), atoi(argv[optind+4]));
+ else
+ tiffsv(argv[optind], 0, xmaxscreen, 0, ymaxscreen);
+ return (0);
+}
+
+char* stuff[] = {
+"usage: tiffsv [options] outimage.tif [x1 x2 y1 y2] [-b]",
+"where options are:",
+" -p contig pack samples contiguously (e.g. RGBRGB...)",
+" -p separate store samples separately (e.g. RRR...GGG...BBB...)",
+"",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c jpeg[:opts]compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"",
+"LZW options:",
+" # set predictor value for Lempel-Ziv & Welch encoding",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+static void
+svRGBSeparate(TIFF* tif, uint32* ss, int xsize, int ysize)
+{
+ tsize_t stripsize = TIFFStripSize(tif);
+ unsigned char *rbuf = (unsigned char *)_TIFFmalloc(3*stripsize);
+ unsigned char *gbuf = rbuf + stripsize;
+ unsigned char *bbuf = gbuf + stripsize;
+ register int y;
+
+ for (y = 0; y <= ysize; y += rowsperstrip) {
+ unsigned char *rp, *gp, *bp;
+ register int x;
+ register uint32 n;
+
+ n = rowsperstrip;
+ if (n > ysize-y+1)
+ n = ysize-y+1;
+ rp = rbuf; gp = gbuf; bp = bbuf;
+ do {
+ for (x = 0; x <= xsize; x++) {
+ uint32 v = ss[x];
+ rp[x] = v;
+ gp[x] = v >> 8;
+ bp[x] = v >> 16;
+ }
+ rp += xsize+1, gp += xsize+1, bp += xsize+1;
+ ss += xsize+1;
+ } while (--n);
+ if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,0),
+ rbuf, stripsize) < 0)
+ break;
+ if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,1),
+ gbuf, stripsize) < 0)
+ break;
+ if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,2),
+ bbuf, stripsize) < 0)
+ break;
+ }
+ _TIFFfree(rbuf);
+}
+
+static void
+svRGBContig(TIFF* tif, uint32* ss, int xsize, int ysize)
+{
+ register int x, y;
+ tsize_t stripsize = TIFFStripSize(tif);
+ unsigned char *strip = (unsigned char *)_TIFFmalloc(stripsize);
+
+ for (y = 0; y <= ysize; y += rowsperstrip) {
+ register unsigned char *pp = strip;
+ register uint32 n;
+
+ n = rowsperstrip;
+ if (n > ysize-y+1)
+ n = ysize-y+1;
+ do {
+ for (x = 0; x <= xsize; x++) {
+ uint32 v = ss[x];
+ pp[0] = v;
+ pp[1] = v >> 8;
+ pp[2] = v >> 16;
+ pp += 3;
+ }
+ ss += xsize+1;
+ } while (--n);
+ if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,0),
+ strip, stripsize) < 0)
+ break;
+ }
+ _TIFFfree(strip);
+}
+
+#undef RED
+#undef GREEN
+#undef BLUE
+#define CVT(x) (((x)*255)/100)
+#define RED CVT(28) /* 28% */
+#define GREEN CVT(59) /* 59% */
+#define BLUE CVT(11) /* 11% */
+
+static void
+svGrey(TIFF* tif, uint32* ss, int xsize, int ysize)
+{
+ register int x, y;
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif));
+
+ for (y = 0; y <= ysize; y++) {
+ for (x = 0; x <= xsize; x++) {
+ unsigned char *cp = (unsigned char *)&ss[x];
+ buf[x] = (RED*cp[3] + GREEN*cp[2] + BLUE*cp[1]) >> 8;
+ }
+ if (TIFFWriteScanline(tif, buf, (uint32) y, 0) < 0)
+ break;
+ ss += xsize+1;
+ }
+ _TIFFfree(buf);
+}
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define ABS(x) ((x)<0?-(x):(x))
+
+static void
+tiffsv(char* name, int x1, int x2, int y1, int y2)
+{
+ TIFF *tif;
+ int xsize, ysize;
+ int xorg, yorg;
+ uint32 *scrbuf;
+
+ xorg = MIN(x1,x2);
+ yorg = MIN(y1,y2);
+ if (xorg<0)
+ xorg = 0;
+ if (yorg<0)
+ yorg = 0;
+ xsize = ABS(x2-x1);
+ ysize = ABS(y2-y1);
+ if (xorg+xsize > xmaxscreen)
+ xsize = xmaxscreen-xorg;
+ if (yorg+ysize > ymaxscreen)
+ ysize = ymaxscreen-yorg;
+ tif = TIFFOpen(name, "w");
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) (xsize+1));
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32) (ysize+1));
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL,
+ photometric == PHOTOMETRIC_RGB ? 3 : 1);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, config);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ if (predictor != 0)
+ TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
+ rowsperstrip = TIFFDefaultStripSize(tif, rowsperstrip);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ scrbuf = (uint32 *)_TIFFmalloc((xsize+1)*(ysize+1)*sizeof (uint32));
+ readdisplay(xorg, yorg, xorg+xsize, yorg+ysize, scrbuf, RD_FREEZE);
+ if (photometric == PHOTOMETRIC_RGB) {
+ if (config == PLANARCONFIG_SEPARATE)
+ svRGBSeparate(tif, scrbuf, xsize, ysize);
+ else
+ svRGBContig(tif, scrbuf, xsize, ysize);
+ } else
+ svGrey(tif, scrbuf, xsize, ysize);
+ (void) TIFFClose(tif);
+ _TIFFfree((char *)scrbuf);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/thumbnail.c b/tiff/tools/thumbnail.c
new file mode 100644
index 0000000..e9e51a3
--- /dev/null
+++ b/tiff/tools/thumbnail.c
@@ -0,0 +1,639 @@
+/* $Id: thumbnail.c,v 1.9.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1994-1997 Sam Leffler
+ * Copyright (c) 1994-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+
+#ifndef TIFFhowmany8
+# define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
+#endif
+
+typedef enum {
+ EXP50,
+ EXP60,
+ EXP70,
+ EXP80,
+ EXP90,
+ EXP,
+ LINEAR
+} Contrast;
+
+static uint32 tnw = 216; /* thumbnail width */
+static uint32 tnh = 274; /* thumbnail height */
+static Contrast contrast = LINEAR; /* current contrast */
+static uint8* thumbnail;
+
+static int cpIFD(TIFF*, TIFF*);
+static int generateThumbnail(TIFF*, TIFF*);
+static void initScale();
+static void usage(void);
+
+extern char* optarg;
+extern int optind;
+
+int
+main(int argc, char* argv[])
+{
+ TIFF* in;
+ TIFF* out;
+ int c;
+
+ while ((c = getopt(argc, argv, "w:h:c:")) != -1) {
+ switch (c) {
+ case 'w': tnw = strtoul(optarg, NULL, 0); break;
+ case 'h': tnh = strtoul(optarg, NULL, 0); break;
+ case 'c': contrast = streq(optarg, "exp50") ? EXP50 :
+ streq(optarg, "exp60") ? EXP60 :
+ streq(optarg, "exp70") ? EXP70 :
+ streq(optarg, "exp80") ? EXP80 :
+ streq(optarg, "exp90") ? EXP90 :
+ streq(optarg, "exp") ? EXP :
+ streq(optarg, "linear")? LINEAR :
+ EXP;
+ break;
+ default: usage();
+ }
+ }
+ if (argc-optind != 2)
+ usage();
+
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return 2;
+ in = TIFFOpen(argv[optind], "r");
+
+ thumbnail = (uint8*) _TIFFmalloc(tnw * tnh);
+ if (!thumbnail) {
+ TIFFError(TIFFFileName(in),
+ "Can't allocate space for thumbnail buffer.");
+ return 1;
+ }
+
+ if (in != NULL) {
+ initScale();
+ do {
+ if (!generateThumbnail(in, out))
+ goto bad;
+ if (!cpIFD(in, out) || !TIFFWriteDirectory(out))
+ goto bad;
+ } while (TIFFReadDirectory(in));
+ (void) TIFFClose(in);
+ }
+ (void) TIFFClose(out);
+ return 0;
+bad:
+ (void) TIFFClose(out);
+ return 1;
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+#undef CopyField4
+#undef CopyField3
+#undef CopyField2
+#undef CopyField
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_IMAGEWIDTH, 1, TIFF_LONG },
+ { TIFFTAG_IMAGELENGTH, 1, TIFF_LONG },
+ { TIFFTAG_BITSPERSAMPLE, 1, TIFF_SHORT },
+ { TIFFTAG_COMPRESSION, 1, TIFF_SHORT },
+ { TIFFTAG_FILLORDER, 1, TIFF_SHORT },
+ { TIFFTAG_SAMPLESPERPIXEL, 1, TIFF_SHORT },
+ { TIFFTAG_ROWSPERSTRIP, 1, TIFF_LONG },
+ { TIFFTAG_PLANARCONFIG, 1, TIFF_SHORT },
+ { TIFFTAG_GROUP3OPTIONS, 1, TIFF_LONG },
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_PHOTOMETRIC, 1, TIFF_SHORT },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_ORIENTATION, 1, TIFF_SHORT },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_PAGENUMBER, 2, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, 1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_BADFAXLINES, 1, TIFF_LONG },
+ { TIFFTAG_CLEANFAXDATA, 1, TIFF_SHORT },
+ { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_INKNAMES, 1, TIFF_ASCII },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_EXTRASAMPLES, (uint16) -1, TIFF_SHORT },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+static void
+cpTags(TIFF* in, TIFF* out)
+{
+ struct cpTag *p;
+ for (p = tags; p < &tags[NTAGS]; p++)
+ cpTag(in, out, p->tag, p->count, p->type);
+}
+#undef NTAGS
+
+static int
+cpStrips(TIFF* in, TIFF* out)
+{
+ tsize_t bufsize = TIFFStripSize(in);
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
+
+ if (buf) {
+ tstrip_t s, ns = TIFFNumberOfStrips(in);
+ tsize_t *bytecounts;
+
+ TIFFGetField(in, TIFFTAG_STRIPBYTECOUNTS, &bytecounts);
+ for (s = 0; s < ns; s++) {
+ if (bytecounts[s] > bufsize) {
+ buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[s]);
+ if (!buf)
+ goto bad;
+ bufsize = bytecounts[s];
+ }
+ if (TIFFReadRawStrip(in, s, buf, bytecounts[s]) < 0 ||
+ TIFFWriteRawStrip(out, s, buf, bytecounts[s]) < 0) {
+ _TIFFfree(buf);
+ return 0;
+ }
+ }
+ _TIFFfree(buf);
+ return 1;
+ }
+
+bad:
+ TIFFError(TIFFFileName(in),
+ "Can't allocate space for strip buffer.");
+ return 0;
+}
+
+static int
+cpTiles(TIFF* in, TIFF* out)
+{
+ tsize_t bufsize = TIFFTileSize(in);
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
+
+ if (buf) {
+ ttile_t t, nt = TIFFNumberOfTiles(in);
+ tsize_t *bytecounts;
+
+ TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts);
+ for (t = 0; t < nt; t++) {
+ if (bytecounts[t] > bufsize) {
+ buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[t]);
+ if (!buf)
+ goto bad;
+ bufsize = bytecounts[t];
+ }
+ if (TIFFReadRawTile(in, t, buf, bytecounts[t]) < 0 ||
+ TIFFWriteRawTile(out, t, buf, bytecounts[t]) < 0) {
+ _TIFFfree(buf);
+ return 0;
+ }
+ }
+ _TIFFfree(buf);
+ return 1;
+ }
+
+bad:
+ TIFFError(TIFFFileName(in),
+ "Can't allocate space for tile buffer.");
+ return (0);
+}
+
+static int
+cpIFD(TIFF* in, TIFF* out)
+{
+ cpTags(in, out);
+ if (TIFFIsTiled(in)) {
+ if (!cpTiles(in, out))
+ return (0);
+ } else {
+ if (!cpStrips(in, out))
+ return (0);
+ }
+ return (1);
+}
+
+static uint16 photometric; /* current photometric of raster */
+static uint16 filterWidth; /* filter width in pixels */
+static uint32 stepSrcWidth; /* src image stepping width */
+static uint32 stepDstWidth; /* dest stepping width */
+static uint8* src0; /* horizontal bit stepping (start) */
+static uint8* src1; /* horizontal bit stepping (middle) */
+static uint8* src2; /* horizontal bit stepping (end) */
+static uint32* rowoff; /* row offset for stepping */
+static uint8 cmap[256]; /* colormap indexes */
+static uint8 bits[256]; /* count of bits set */
+
+static void
+setupBitsTables()
+{
+ int i;
+ for (i = 0; i < 256; i++) {
+ int n = 0;
+ if (i&0x01) n++;
+ if (i&0x02) n++;
+ if (i&0x04) n++;
+ if (i&0x08) n++;
+ if (i&0x10) n++;
+ if (i&0x20) n++;
+ if (i&0x40) n++;
+ if (i&0x80) n++;
+ bits[i] = n;
+ }
+}
+
+static int clamp(float v, int low, int high)
+ { return (v < low ? low : v > high ? high : (int)v); }
+
+#ifndef M_E
+#define M_E 2.7182818284590452354
+#endif
+
+static void
+expFill(float pct[], uint32 p, uint32 n)
+{
+ uint32 i;
+ uint32 c = (p * n) / 100;
+ for (i = 1; i < c; i++)
+ pct[i] = (float) (1-exp(i/((double)(n-1)))/ M_E);
+ for (; i < n; i++)
+ pct[i] = 0.;
+}
+
+static void
+setupCmap()
+{
+ float pct[256]; /* known to be large enough */
+ uint32 i;
+ pct[0] = 1; /* force white */
+ switch (contrast) {
+ case EXP50: expFill(pct, 50, 256); break;
+ case EXP60: expFill(pct, 60, 256); break;
+ case EXP70: expFill(pct, 70, 256); break;
+ case EXP80: expFill(pct, 80, 256); break;
+ case EXP90: expFill(pct, 90, 256); break;
+ case EXP: expFill(pct, 100, 256); break;
+ case LINEAR:
+ for (i = 1; i < 256; i++)
+ pct[i] = 1-((float)i)/(256-1);
+ break;
+ }
+ switch (photometric) {
+ case PHOTOMETRIC_MINISWHITE:
+ for (i = 0; i < 256; i++)
+ cmap[i] = clamp(255*pct[(256-1)-i], 0, 255);
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ for (i = 0; i < 256; i++)
+ cmap[i] = clamp(255*pct[i], 0, 255);
+ break;
+ }
+}
+
+static void
+initScale()
+{
+ src0 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
+ src1 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
+ src2 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
+ rowoff = (uint32*) _TIFFmalloc(sizeof (uint32) * tnw);
+ filterWidth = 0;
+ stepDstWidth = stepSrcWidth = 0;
+ setupBitsTables();
+}
+
+/*
+ * Calculate the horizontal accumulation parameteres
+ * according to the widths of the src and dst images.
+ */
+static void
+setupStepTables(uint32 sw)
+{
+ if (stepSrcWidth != sw || stepDstWidth != tnw) {
+ int step = sw;
+ int limit = tnw;
+ int err = 0;
+ uint32 sx = 0;
+ uint32 x;
+ int fw;
+ uint8 b;
+ for (x = 0; x < tnw; x++) {
+ uint32 sx0 = sx;
+ err += step;
+ while (err >= limit) {
+ err -= limit;
+ sx++;
+ }
+ rowoff[x] = sx0 >> 3;
+ fw = sx - sx0; /* width */
+ b = (fw < 8) ? 0xff<<(8-fw) : 0xff;
+ src0[x] = b >> (sx0&7);
+ fw -= 8 - (sx0&7);
+ if (fw < 0)
+ fw = 0;
+ src1[x] = fw >> 3;
+ fw -= (fw>>3)<<3;
+ src2[x] = 0xff << (8-fw);
+ }
+ stepSrcWidth = sw;
+ stepDstWidth = tnw;
+ }
+}
+
+static void
+setrow(uint8* row, uint32 nrows, const uint8* rows[])
+{
+ uint32 x;
+ uint32 area = nrows * filterWidth;
+ for (x = 0; x < tnw; x++) {
+ uint32 mask0 = src0[x];
+ uint32 fw = src1[x];
+ uint32 mask1 = src1[x];
+ uint32 off = rowoff[x];
+ uint32 acc = 0;
+ uint32 y, i;
+ for (y = 0; y < nrows; y++) {
+ const uint8* src = rows[y] + off;
+ acc += bits[*src++ & mask0];
+ switch (fw) {
+ default:
+ for (i = fw; i > 8; i--)
+ acc += bits[*src++];
+ /* fall thru... */
+ case 8: acc += bits[*src++];
+ case 7: acc += bits[*src++];
+ case 6: acc += bits[*src++];
+ case 5: acc += bits[*src++];
+ case 4: acc += bits[*src++];
+ case 3: acc += bits[*src++];
+ case 2: acc += bits[*src++];
+ case 1: acc += bits[*src++];
+ case 0: break;
+ }
+ acc += bits[*src & mask1];
+ }
+ *row++ = cmap[(255*acc)/area];
+ }
+}
+
+/*
+ * Install the specified image. The
+ * image is resized to fit the display page using
+ * a box filter. The resultant pixels are mapped
+ * with a user-selectable contrast curve.
+ */
+static void
+setImage1(const uint8* br, uint32 rw, uint32 rh)
+{
+ int step = rh;
+ int limit = tnh;
+ int err = 0;
+ int bpr = TIFFhowmany8(rw);
+ int sy = 0;
+ uint8* row = thumbnail;
+ uint32 dy;
+ for (dy = 0; dy < tnh; dy++) {
+ const uint8* rows[256];
+ uint32 nrows = 1;
+ fprintf(stderr, "bpr=%d, sy=%d, bpr*sy=%d\n", bpr, sy, bpr*sy);
+ rows[0] = br + bpr*sy;
+ err += step;
+ while (err >= limit) {
+ err -= limit;
+ sy++;
+ if (err >= limit)
+ rows[nrows++] = br + bpr*sy;
+ }
+ setrow(row, nrows, rows);
+ row += tnw;
+ }
+}
+
+static void
+setImage(const uint8* br, uint32 rw, uint32 rh)
+{
+ filterWidth = (uint16) ceil((double) rw / (double) tnw);
+ setupStepTables(rw);
+ setImage1(br, rw, rh);
+}
+
+static int
+generateThumbnail(TIFF* in, TIFF* out)
+{
+ unsigned char* raster;
+ unsigned char* rp;
+ uint32 sw, sh, rps;
+ uint16 bps, spp;
+ tsize_t rowsize, rastersize;
+ tstrip_t s, ns = TIFFNumberOfStrips(in);
+ uint32 diroff[1];
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &sw);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &sh);
+ TIFFGetFieldDefaulted(in, TIFFTAG_BITSPERSAMPLE, &bps);
+ TIFFGetFieldDefaulted(in, TIFFTAG_SAMPLESPERPIXEL, &spp);
+ TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rps);
+ if (spp != 1 || bps != 1)
+ return 0;
+ rowsize = TIFFScanlineSize(in);
+ rastersize = sh * rowsize;
+ fprintf(stderr, "rastersize=%u\n", (unsigned int)rastersize);
+ raster = (unsigned char*)_TIFFmalloc(rastersize);
+ if (!raster) {
+ TIFFError(TIFFFileName(in),
+ "Can't allocate space for raster buffer.");
+ return 0;
+ }
+ rp = raster;
+ for (s = 0; s < ns; s++) {
+ (void) TIFFReadEncodedStrip(in, s, rp, -1);
+ rp += rps * rowsize;
+ }
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric);
+ setupCmap();
+ setImage(raster, sw, sh);
+ _TIFFfree(raster);
+
+ TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) tnw);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) tnh);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (uint16) 8);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (uint16) 1);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ cpTag(in, out, TIFFTAG_SOFTWARE, (uint16) -1, TIFF_ASCII);
+ cpTag(in, out, TIFFTAG_IMAGEDESCRIPTION, (uint16) -1, TIFF_ASCII);
+ cpTag(in, out, TIFFTAG_DATETIME, (uint16) -1, TIFF_ASCII);
+ cpTag(in, out, TIFFTAG_HOSTCOMPUTER, (uint16) -1, TIFF_ASCII);
+ diroff[0] = 0;
+ TIFFSetField(out, TIFFTAG_SUBIFD, 1, diroff);
+ return (TIFFWriteEncodedStrip(out, 0, thumbnail, tnw*tnh) != -1 &&
+ TIFFWriteDirectory(out) != -1);
+}
+
+char* stuff[] = {
+"usage: thumbnail [options] input.tif output.tif",
+"where options are:",
+" -h # specify thumbnail image height (default is 274)",
+" -w # specify thumbnail image width (default is 216)",
+"",
+" -c linear use linear contrast curve",
+" -c exp50 use 50% exponential contrast curve",
+" -c exp60 use 60% exponential contrast curve",
+" -c exp70 use 70% exponential contrast curve",
+" -c exp80 use 80% exponential contrast curve",
+" -c exp90 use 90% exponential contrast curve",
+" -c exp use pure exponential contrast curve",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiff2bw.c b/tiff/tools/tiff2bw.c
new file mode 100644
index 0000000..9e1e23a
--- /dev/null
+++ b/tiff/tools/tiff2bw.c
@@ -0,0 +1,467 @@
+/* $Id: tiff2bw.c,v 1.12.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+/* x% weighting -> fraction of full color */
+#define PCT(x) (((x)*255+127)/100)
+int RED = PCT(30); /* 30% */
+int GREEN = PCT(59); /* 59% */
+int BLUE = PCT(11); /* 11% */
+
+static void usage(void);
+static int processCompressOptions(char*);
+
+static void
+compresscontig(unsigned char* out, unsigned char* rgb, uint32 n)
+{
+ register int v, red = RED, green = GREEN, blue = BLUE;
+
+ while (n-- > 0) {
+ v = red*(*rgb++);
+ v += green*(*rgb++);
+ v += blue*(*rgb++);
+ *out++ = v>>8;
+ }
+}
+
+static void
+compresssep(unsigned char* out,
+ unsigned char* r, unsigned char* g, unsigned char* b, uint32 n)
+{
+ register uint32 red = RED, green = GREEN, blue = BLUE;
+
+ while (n-- > 0)
+ *out++ = (unsigned char)
+ ((red*(*r++) + green*(*g++) + blue*(*b++)) >> 8);
+}
+
+static int
+checkcmap(TIFF* tif, int n, uint16* r, uint16* g, uint16* b)
+{
+ while (n-- > 0)
+ if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+ return (16);
+ TIFFWarning(TIFFFileName(tif), "Assuming 8-bit colormap");
+ return (8);
+}
+
+static void
+compresspalette(unsigned char* out, unsigned char* data, uint32 n, uint16* rmap, uint16* gmap, uint16* bmap)
+{
+ register int v, red = RED, green = GREEN, blue = BLUE;
+
+ while (n-- > 0) {
+ unsigned int ix = *data++;
+ v = red*rmap[ix];
+ v += green*gmap[ix];
+ v += blue*bmap[ix];
+ *out++ = v>>8;
+ }
+}
+
+static uint16 compression = (uint16) -1;
+static uint16 predictor = 0;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+
+static void cpTags(TIFF* in, TIFF* out);
+
+int
+main(int argc, char* argv[])
+{
+ uint32 rowsperstrip = (uint32) -1;
+ TIFF *in, *out;
+ uint32 w, h;
+ uint16 samplesperpixel;
+ uint16 bitspersample;
+ uint16 config;
+ uint16 photometric;
+ uint16* red;
+ uint16* green;
+ uint16* blue;
+ tsize_t rowsize;
+ register uint32 row;
+ register tsample_t s;
+ unsigned char *inbuf, *outbuf;
+ char thing[1024];
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "c:r:R:G:B:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'R':
+ RED = PCT(atoi(optarg));
+ break;
+ case 'G':
+ GREEN = PCT(atoi(optarg));
+ break;
+ case 'B':
+ BLUE = PCT(atoi(optarg));
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage();
+ in = TIFFOpen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ photometric = 0;
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric);
+ if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE ) {
+ fprintf(stderr,
+ "%s: Bad photometric; can only handle RGB and Palette images.\n",
+ argv[optind]);
+ return (-1);
+ }
+ TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (samplesperpixel != 1 && samplesperpixel != 3) {
+ fprintf(stderr, "%s: Bad samples/pixel %u.\n",
+ argv[optind], samplesperpixel);
+ return (-1);
+ }
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8) {
+ fprintf(stderr,
+ " %s: Sorry, only handle 8-bit samples.\n", argv[optind]);
+ return (-1);
+ }
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config);
+
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-1);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, w);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, h);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ cpTags(in, out);
+ if (compression != (uint16) -1) {
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ }
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ sprintf(thing, "B&W version of %s", argv[optind]);
+ TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, thing);
+ TIFFSetField(out, TIFFTAG_SOFTWARE, "tiff2bw");
+ outbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+
+#define pack(a,b) ((a)<<8 | (b))
+ switch (pack(photometric, config)) {
+ case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
+ case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
+ TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue);
+ /*
+ * Convert 16-bit colormap to 8-bit (unless it looks
+ * like an old-style 8-bit colormap).
+ */
+ if (checkcmap(in, 1<<bitspersample, red, green, blue) == 16) {
+ int i;
+#define CVT(x) (((x) * 255L) / ((1L<<16)-1))
+ for (i = (1<<bitspersample)-1; i >= 0; i--) {
+ red[i] = CVT(red[i]);
+ green[i] = CVT(green[i]);
+ blue[i] = CVT(blue[i]);
+ }
+#undef CVT
+ }
+ inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ for (row = 0; row < h; row++) {
+ if (TIFFReadScanline(in, inbuf, row, 0) < 0)
+ break;
+ compresspalette(outbuf, inbuf, w, red, green, blue);
+ if (TIFFWriteScanline(out, outbuf, row, 0) < 0)
+ break;
+ }
+ break;
+ case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
+ inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ for (row = 0; row < h; row++) {
+ if (TIFFReadScanline(in, inbuf, row, 0) < 0)
+ break;
+ compresscontig(outbuf, inbuf, w);
+ if (TIFFWriteScanline(out, outbuf, row, 0) < 0)
+ break;
+ }
+ break;
+ case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE):
+ rowsize = TIFFScanlineSize(in);
+ inbuf = (unsigned char *)_TIFFmalloc(3*rowsize);
+ for (row = 0; row < h; row++) {
+ for (s = 0; s < 3; s++)
+ if (TIFFReadScanline(in,
+ inbuf+s*rowsize, row, s) < 0)
+ return (-1);
+ compresssep(outbuf,
+ inbuf, inbuf+rowsize, inbuf+2*rowsize, w);
+ if (TIFFWriteScanline(out, outbuf, row, 0) < 0)
+ break;
+ }
+ break;
+ }
+#undef pack
+ TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+#undef CopyField4
+#undef CopyField3
+#undef CopyField2
+#undef CopyField
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, 1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES,(uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_EXTRASAMPLES, (uint16) -1, TIFF_SHORT },
+ { TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_STONITS, 1, TIFF_DOUBLE },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+static void
+cpTags(TIFF* in, TIFF* out)
+{
+ struct cpTag *p;
+ for (p = tags; p < &tags[NTAGS]; p++)
+ cpTag(in, out, p->tag, p->count, p->type);
+}
+#undef NTAGS
+
+char* stuff[] = {
+"usage: tiff2bw [options] input.tif output.tif",
+"where options are:",
+" -R % use #% from red channel",
+" -G % use #% from green channel",
+" -B % use #% from blue channel",
+"",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c g3[:opts] compress output with CCITT Group 3 encoding",
+" -c g4 compress output with CCITT Group 4 encoding",
+" -c none use no compression algorithm on output",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiff2pdf.c b/tiff/tools/tiff2pdf.c
new file mode 100644
index 0000000..b1886c6
--- /dev/null
+++ b/tiff/tools/tiff2pdf.c
@@ -0,0 +1,5405 @@
+/* $Id: tiff2pdf.c,v 1.37.2.10 2010-06-13 19:18:41 fwarmerdam Exp $
+ *
+ * tiff2pdf - converts a TIFF image to a PDF document
+ *
+ * Copyright (c) 2003 Ross Finlayson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the name of
+ * Ross Finlayson may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Ross Finlayson.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL ROSS FINLAYSON BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define TIFF2PDF_MODULE "tiff2pdf"
+
+#define PS_UNIT_SIZE 72.0F
+
+/* This type is of PDF color spaces. */
+typedef enum {
+ T2P_CS_BILEVEL = 0x01, /* Bilevel, black and white */
+ T2P_CS_GRAY = 0x02, /* Single channel */
+ T2P_CS_RGB = 0x04, /* Three channel tristimulus RGB */
+ T2P_CS_CMYK = 0x08, /* Four channel CMYK print inkset */
+ T2P_CS_LAB = 0x10, /* Three channel L*a*b* color space */
+ T2P_CS_PALETTE = 0x1000,/* One of the above with a color map */
+ T2P_CS_CALGRAY = 0x20, /* Calibrated single channel */
+ T2P_CS_CALRGB = 0x40, /* Calibrated three channel tristimulus RGB */
+ T2P_CS_ICCBASED = 0x80 /* ICC profile color specification */
+} t2p_cs_t;
+
+/* This type is of PDF compression types. */
+typedef enum{
+ T2P_COMPRESS_NONE=0x00
+#ifdef CCITT_SUPPORT
+ , T2P_COMPRESS_G4=0x01
+#endif
+#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
+ , T2P_COMPRESS_JPEG=0x02
+#endif
+#ifdef ZIP_SUPPORT
+ , T2P_COMPRESS_ZIP=0x04
+#endif
+} t2p_compress_t;
+
+/* This type is whether TIFF image data can be used in PDF without transcoding. */
+typedef enum{
+ T2P_TRANSCODE_RAW=0x01, /* The raw data from the input can be used without recompressing */
+ T2P_TRANSCODE_ENCODE=0x02 /* The data from the input is perhaps unencoded and reencoded */
+} t2p_transcode_t;
+
+/* This type is of information about the data samples of the input image. */
+typedef enum{
+ T2P_SAMPLE_NOTHING=0x0000, /* The unencoded samples are normal for the output colorspace */
+ T2P_SAMPLE_ABGR_TO_RGB=0x0001, /* The unencoded samples are the result of ReadRGBAImage */
+ T2P_SAMPLE_RGBA_TO_RGB=0x0002, /* The unencoded samples are contiguous RGBA */
+ T2P_SAMPLE_RGBAA_TO_RGB=0x0004, /* The unencoded samples are RGBA with premultiplied alpha */
+ T2P_SAMPLE_YCBCR_TO_RGB=0x0008,
+ T2P_SAMPLE_YCBCR_TO_LAB=0x0010,
+ T2P_SAMPLE_REALIZE_PALETTE=0x0020, /* The unencoded samples are indexes into the color map */
+ T2P_SAMPLE_SIGNED_TO_UNSIGNED=0x0040, /* The unencoded samples are signed instead of unsignd */
+ T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED=0x0040, /* The L*a*b* samples have a* and b* signed */
+ T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG=0x0100 /* The unencoded samples are separate instead of contiguous */
+} t2p_sample_t;
+
+/* This type is of error status of the T2P struct. */
+typedef enum{
+ T2P_ERR_OK = 0, /* This is the value of t2p->t2p_error when there is no error */
+ T2P_ERR_ERROR = 1 /* This is the value of t2p->t2p_error when there was an error */
+} t2p_err_t;
+
+/* This struct defines a logical page of a TIFF. */
+typedef struct {
+ tdir_t page_directory;
+ uint32 page_number;
+ ttile_t page_tilecount;
+ uint32 page_extra;
+} T2P_PAGE;
+
+/* This struct defines a PDF rectangle's coordinates. */
+typedef struct {
+ float x1;
+ float y1;
+ float x2;
+ float y2;
+ float mat[9];
+} T2P_BOX;
+
+/* This struct defines a tile of a PDF. */
+typedef struct {
+ T2P_BOX tile_box;
+} T2P_TILE;
+
+/* This struct defines information about the tiles on a PDF page. */
+typedef struct {
+ ttile_t tiles_tilecount;
+ uint32 tiles_tilewidth;
+ uint32 tiles_tilelength;
+ uint32 tiles_tilecountx;
+ uint32 tiles_tilecounty;
+ uint32 tiles_edgetilewidth;
+ uint32 tiles_edgetilelength;
+ T2P_TILE* tiles_tiles;
+} T2P_TILES;
+
+/* This struct is the context of a function to generate PDF from a TIFF. */
+typedef struct {
+ t2p_err_t t2p_error;
+ T2P_PAGE* tiff_pages;
+ T2P_TILES* tiff_tiles;
+ tdir_t tiff_pagecount;
+ uint16 tiff_compression;
+ uint16 tiff_photometric;
+ uint16 tiff_fillorder;
+ uint16 tiff_bitspersample;
+ uint16 tiff_samplesperpixel;
+ uint16 tiff_planar;
+ uint32 tiff_width;
+ uint32 tiff_length;
+ float tiff_xres;
+ float tiff_yres;
+ uint16 tiff_orientation;
+ toff_t tiff_dataoffset;
+ tsize_t tiff_datasize;
+ uint16 tiff_resunit;
+ uint16 pdf_centimeters;
+ uint16 pdf_overrideres;
+ uint16 pdf_overridepagesize;
+ float pdf_defaultxres;
+ float pdf_defaultyres;
+ float pdf_xres;
+ float pdf_yres;
+ float pdf_defaultpagewidth;
+ float pdf_defaultpagelength;
+ float pdf_pagewidth;
+ float pdf_pagelength;
+ float pdf_imagewidth;
+ float pdf_imagelength;
+ T2P_BOX pdf_mediabox;
+ T2P_BOX pdf_imagebox;
+ uint16 pdf_majorversion;
+ uint16 pdf_minorversion;
+ uint32 pdf_catalog;
+ uint32 pdf_pages;
+ uint32 pdf_info;
+ uint32 pdf_palettecs;
+ uint16 pdf_fitwindow;
+ uint32 pdf_startxref;
+ unsigned char* pdf_fileid;
+ unsigned char* pdf_datetime;
+ unsigned char* pdf_creator;
+ unsigned char* pdf_author;
+ unsigned char* pdf_title;
+ unsigned char* pdf_subject;
+ unsigned char* pdf_keywords;
+ t2p_cs_t pdf_colorspace;
+ uint16 pdf_colorspace_invert;
+ uint16 pdf_switchdecode;
+ uint16 pdf_palettesize;
+ unsigned char* pdf_palette;
+ int pdf_labrange[4];
+ t2p_compress_t pdf_defaultcompression;
+ uint16 pdf_defaultcompressionquality;
+ t2p_compress_t pdf_compression;
+ uint16 pdf_compressionquality;
+ uint16 pdf_nopassthrough;
+ t2p_transcode_t pdf_transcode;
+ t2p_sample_t pdf_sample;
+ uint32* pdf_xrefoffsets;
+ uint32 pdf_xrefcount;
+ tdir_t pdf_page;
+#ifdef OJPEG_SUPPORT
+ tdata_t pdf_ojpegdata;
+ uint32 pdf_ojpegdatalength;
+ uint32 pdf_ojpegiflength;
+#endif
+ float tiff_whitechromaticities[2];
+ float tiff_primarychromaticities[6];
+ float tiff_referenceblackwhite[2];
+ float* tiff_transferfunction[3];
+ int pdf_image_interpolate; /* 0 (default) : do not interpolate,
+ 1 : interpolate */
+ uint16 tiff_transferfunctioncount;
+ uint32 pdf_icccs;
+ uint32 tiff_iccprofilelength;
+ tdata_t tiff_iccprofile;
+
+ /* fields for custom read/write procedures */
+ FILE *outputfile;
+ int outputdisable;
+ tsize_t outputwritten;
+} T2P;
+
+/* These functions are called by main. */
+
+void tiff2pdf_usage(void);
+int tiff2pdf_match_paper_size(float*, float*, char*);
+
+/* These functions are used to generate a PDF from a TIFF. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+T2P* t2p_init(void);
+void t2p_validate(T2P*);
+tsize_t t2p_write_pdf(T2P*, TIFF*, TIFF*);
+void t2p_free(T2P*);
+
+#ifdef __cplusplus
+}
+#endif
+
+void t2p_read_tiff_init(T2P*, TIFF*);
+int t2p_cmp_t2p_page(const void*, const void*);
+void t2p_read_tiff_data(T2P*, TIFF*);
+void t2p_read_tiff_size(T2P*, TIFF*);
+void t2p_read_tiff_size_tile(T2P*, TIFF*, ttile_t);
+int t2p_tile_is_right_edge(T2P_TILES, ttile_t);
+int t2p_tile_is_bottom_edge(T2P_TILES, ttile_t);
+int t2p_tile_is_edge(T2P_TILES, ttile_t);
+int t2p_tile_is_corner_edge(T2P_TILES, ttile_t);
+tsize_t t2p_readwrite_pdf_image(T2P*, TIFF*, TIFF*);
+tsize_t t2p_readwrite_pdf_image_tile(T2P*, TIFF*, TIFF*, ttile_t);
+#ifdef OJPEG_SUPPORT
+int t2p_process_ojpeg_tables(T2P*, TIFF*);
+#endif
+#ifdef JPEG_SUPPORT
+int t2p_process_jpeg_strip(unsigned char*, tsize_t*, unsigned char*, tsize_t*, tstrip_t, uint32);
+#endif
+void t2p_tile_collapse_left(tdata_t, tsize_t, uint32, uint32, uint32);
+void t2p_write_advance_directory(T2P*, TIFF*);
+tsize_t t2p_sample_planar_separate_to_contig(T2P*, unsigned char*, unsigned char*, tsize_t);
+tsize_t t2p_sample_realize_palette(T2P*, unsigned char*);
+tsize_t t2p_sample_abgr_to_rgb(tdata_t, uint32);
+tsize_t t2p_sample_rgba_to_rgb(tdata_t, uint32);
+tsize_t t2p_sample_rgbaa_to_rgb(tdata_t, uint32);
+tsize_t t2p_sample_lab_signed_to_unsigned(tdata_t, uint32);
+tsize_t t2p_write_pdf_header(T2P*, TIFF*);
+tsize_t t2p_write_pdf_obj_start(uint32, TIFF*);
+tsize_t t2p_write_pdf_obj_end(TIFF*);
+tsize_t t2p_write_pdf_name(unsigned char*, TIFF*);
+tsize_t t2p_write_pdf_string(unsigned char*, TIFF*);
+tsize_t t2p_write_pdf_stream(tdata_t, tsize_t, TIFF*);
+tsize_t t2p_write_pdf_stream_start(TIFF*);
+tsize_t t2p_write_pdf_stream_end(TIFF*);
+tsize_t t2p_write_pdf_stream_dict(tsize_t, uint32, TIFF*);
+tsize_t t2p_write_pdf_stream_dict_start(TIFF*);
+tsize_t t2p_write_pdf_stream_dict_end(TIFF*);
+tsize_t t2p_write_pdf_stream_length(tsize_t, TIFF*);
+tsize_t t2p_write_pdf_catalog(T2P*, TIFF*);
+tsize_t t2p_write_pdf_info(T2P*, TIFF*, TIFF*);
+void t2p_pdf_currenttime(T2P*);
+void t2p_pdf_tifftime(T2P*, TIFF*);
+tsize_t t2p_write_pdf_pages(T2P*, TIFF*);
+tsize_t t2p_write_pdf_page(uint32, T2P*, TIFF*);
+void t2p_compose_pdf_page(T2P*);
+void t2p_compose_pdf_page_orient(T2P_BOX*, uint16);
+void t2p_compose_pdf_page_orient_flip(T2P_BOX*, uint16);
+tsize_t t2p_write_pdf_page_content(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_stream_dict(ttile_t, T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_cs(T2P*, TIFF*);
+tsize_t t2p_write_pdf_transfer(T2P*, TIFF*);
+tsize_t t2p_write_pdf_transfer_dict(T2P*, TIFF*, uint16);
+tsize_t t2p_write_pdf_transfer_stream(T2P*, TIFF*, uint16);
+tsize_t t2p_write_pdf_xobject_calcs(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_icccs(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_icccs_dict(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_icccs_stream(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_cs_stream(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_decode(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_stream_filter(ttile_t, T2P*, TIFF*);
+tsize_t t2p_write_pdf_xreftable(T2P*, TIFF*);
+tsize_t t2p_write_pdf_trailer(T2P*, TIFF*);
+
+static void
+t2p_disable(TIFF *tif)
+{
+ T2P *t2p = (T2P*) TIFFClientdata(tif);
+ t2p->outputdisable = 1;
+}
+
+static void
+t2p_enable(TIFF *tif)
+{
+ T2P *t2p = (T2P*) TIFFClientdata(tif);
+ t2p->outputdisable = 0;
+}
+
+/*
+ * Procs for TIFFClientOpen
+ */
+
+static tsize_t
+t2pReadFile(TIFF *tif, tdata_t data, tsize_t size)
+{
+ thandle_t client = TIFFClientdata(tif);
+ TIFFReadWriteProc proc = TIFFGetReadProc(tif);
+ if (proc)
+ return proc(client, data, size);
+ return -1;
+}
+
+static tsize_t
+t2pWriteFile(TIFF *tif, tdata_t data, tsize_t size)
+{
+ thandle_t client = TIFFClientdata(tif);
+ TIFFReadWriteProc proc = TIFFGetWriteProc(tif);
+ if (proc)
+ return proc(client, data, size);
+ return -1;
+}
+
+static toff_t
+t2pSeekFile(TIFF *tif, toff_t offset, int whence)
+{
+ thandle_t client = TIFFClientdata(tif);
+ TIFFSeekProc proc = TIFFGetSeekProc(tif);
+ if (proc)
+ return proc(client, offset, whence);
+ return -1;
+}
+
+static tsize_t
+t2p_readproc(thandle_t handle, tdata_t data, tsize_t size)
+{
+ (void) handle, (void) data, (void) size;
+ return -1;
+}
+
+static tsize_t
+t2p_writeproc(thandle_t handle, tdata_t data, tsize_t size)
+{
+ T2P *t2p = (T2P*) handle;
+ if (t2p->outputdisable <= 0 && t2p->outputfile) {
+ tsize_t written = fwrite(data, 1, size, t2p->outputfile);
+ t2p->outputwritten += written;
+ return written;
+ }
+ return size;
+}
+
+static toff_t
+t2p_seekproc(thandle_t handle, toff_t offset, int whence)
+{
+ T2P *t2p = (T2P*) handle;
+ if (t2p->outputdisable <= 0 && t2p->outputfile)
+ return fseek(t2p->outputfile, offset, whence);
+ return offset;
+}
+
+static int
+t2p_closeproc(thandle_t handle)
+{
+ (void) handle;
+ return 0;
+}
+
+static toff_t
+t2p_sizeproc(thandle_t handle)
+{
+ (void) handle;
+ return -1;
+}
+
+static int
+t2p_mapproc(thandle_t handle, tdata_t *data, toff_t *offset)
+{
+ (void) handle, (void) data, (void) offset;
+ return -1;
+}
+
+static void
+t2p_unmapproc(thandle_t handle, tdata_t data, toff_t offset)
+{
+ (void) handle, (void) data, (void) offset;
+}
+
+/*
+
+ This is the main function.
+
+ The program converts one TIFF file to one PDF file, including multiple page
+ TIFF files, tiled TIFF files, black and white. grayscale, and color TIFF
+ files that contain data of TIFF photometric interpretations of bilevel,
+ grayscale, RGB, YCbCr, CMYK separation, and ICC L*a*b* as supported by
+ libtiff and PDF.
+
+ If you have multiple TIFF files to convert into one PDF file then use tiffcp
+ or other program to concatenate the files into a multiple page TIFF file.
+ If the input TIFF file is of huge dimensions (greater than 10000 pixels height
+ or width) convert the input image to a tiled TIFF if it is not already.
+
+ The standard output is standard output. Set the output file name with the
+ "-o output.pdf" option.
+
+ All black and white files are compressed into a single strip CCITT G4 Fax
+ compressed PDF, unless tiled, where tiled black and white images are
+ compressed into tiled CCITT G4 Fax compressed PDF, libtiff CCITT support
+ is assumed.
+
+ Color and grayscale data can be compressed using either JPEG compression,
+ ITU-T T.81, or Zip/Deflate LZ77 compression, per PNG 1.2 and RFC 1951. Set
+ the compression type using the -j or -z options. JPEG compression support
+ requires that libtiff be configured with JPEG support, and Zip/Deflate
+ compression support requires that libtiff is configured with Zip support,
+ in tiffconf.h. Use only one or the other of -j and -z. The -q option
+ sets the image compression quality, that is 1-100 with libjpeg JPEG
+ compression and one of 1, 10, 11, 12, 13, 14, or 15 for PNG group compression
+ predictor methods, add 100, 200, ..., 900 to set zlib compression quality 1-9.
+ PNG Group differencing predictor methods are not currently implemented.
+
+ If the input TIFF contains single strip CCITT G4 Fax compressed information,
+ then that is written to the PDF file without transcoding, unless the options
+ of no compression and no passthrough are set, -d and -n.
+
+ If the input TIFF contains JPEG or single strip Zip/Deflate compressed
+ information, and they are configured, then that is written to the PDF file
+ without transcoding, unless the options of no compression and no passthrough
+ are set.
+
+ The default page size upon which the TIFF image is placed is determined by
+ the resolution and extent of the image data. Default values for the TIFF
+ image resolution can be set using the -x and -y options. The page size can
+ be set using the -p option for paper size, or -w and -l for paper width and
+ length, then each page of the TIFF image is centered on its page. The
+ distance unit for default resolution and page width and length can be set
+ by the -u option, the default unit is inch.
+
+ Various items of the output document information can be set with the -e, -c,
+ -a, -t, -s, and -k tags. Setting the argument of the option to "" for these
+ tags causes the relevant document information field to be not written. Some
+ of the document information values otherwise get their information from the
+ input TIFF image, the software, author, document name, and image description.
+
+ The output PDF file conforms to the PDF 1.1 specification or PDF 1.2 if using
+ Zip/Deflate compression.
+
+ The Portable Document Format (PDF) specification is copyrighted by Adobe
+ Systems, Incorporated. Todos derechos reservados.
+
+ Here is a listing of the usage example and the options to the tiff2pdf
+ program that is part of the libtiff distribution. Options followed by
+ a colon have a required argument.
+
+ usage: tiff2pdf [options] input.tif
+
+ options:
+ -o: output to file name
+
+ -j: compress with JPEG (requires libjpeg configured with libtiff)
+ -z: compress with Zip/Deflate (requires zlib configured with libtiff)
+ -q: compression quality
+ -n: no compressed data passthrough
+ -d: do not compress (decompress)
+ -i: invert colors
+ -u: set distance unit, 'i' for inch, 'm' for centimeter
+ -x: set x resolution default
+ -y: set y resolution default
+ -w: width in units
+ -l: length in units
+ -r: 'd' for resolution default, 'o' for resolution override
+ -p: paper size, eg "letter", "legal", "a4"
+ -f: set pdf "fit window" user preference
+ -b: set PDF "Interpolate" user preference
+ -e: date, overrides image or current date/time default, YYYYMMDDHHMMSS
+ -c: creator, overrides image software default
+ -a: author, overrides image artist default
+ -t: title, overrides image document name default
+ -s: subject, overrides image image description default
+ -k: keywords
+
+ -h: usage
+
+ examples:
+
+ tiff2pdf -o output.pdf input.tiff
+
+ The above example would generate the file output.pdf from input.tiff.
+
+ tiff2pdf input.tiff
+
+ The above example would generate PDF output from input.tiff and write it
+ to standard output.
+
+ tiff2pdf -j -p letter -o output.pdf input.tiff
+
+ The above example would generate the file output.pdf from input.tiff,
+ putting the image pages on a letter sized page, compressing the output
+ with JPEG.
+
+ Please report bugs through:
+
+ http://bugzilla.remotesensing.org/buglist.cgi?product=libtiff
+
+ See also libtiff.3t, tiffcp.
+ */
+
+int main(int argc, char** argv){
+
+ extern char *optarg;
+ extern int optind;
+ const char *outfilename = NULL;
+ T2P *t2p = NULL;
+ TIFF *input = NULL, *output = NULL;
+ tsize_t written = 0;
+ int c;
+
+ t2p = t2p_init();
+
+ if (t2p == NULL){
+ TIFFError(TIFF2PDF_MODULE, "Can't initialize context");
+ goto fail;
+ }
+
+ while (argv &&
+ (c = getopt(argc, argv,
+ "o:q:u:x:y:w:l:r:p:e:c:a:t:s:k:jzndifbh")) != -1){
+ switch (c) {
+ case 'o':
+ outfilename = optarg;
+ break;
+#ifdef JPEG_SUPPORT
+ case 'j':
+ t2p->pdf_defaultcompression=T2P_COMPRESS_JPEG;
+ break;
+#endif
+#ifndef JPEG_SUPPORT
+ case 'j':
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "JPEG support in libtiff required for JPEG compression, ignoring option");
+ break;
+#endif
+#ifdef ZIP_SUPPORT
+ case 'z':
+ t2p->pdf_defaultcompression=T2P_COMPRESS_ZIP;
+ break;
+#endif
+#ifndef ZIP_SUPPORT
+ case 'z':
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "Zip support in libtiff required for Zip compression, ignoring option");
+ break;
+#endif
+ case 'q':
+ t2p->pdf_defaultcompressionquality=atoi(optarg);
+ break;
+ case 'n':
+ t2p->pdf_nopassthrough=1;
+ break;
+ case 'd':
+ t2p->pdf_defaultcompression=T2P_COMPRESS_NONE;
+ break;
+ case 'u':
+ if(optarg[0]=='m'){
+ t2p->pdf_centimeters=1;
+ }
+ break;
+ case 'x':
+ t2p->pdf_defaultxres =
+ (float)atof(optarg) / (t2p->pdf_centimeters?2.54F:1.0F);
+ break;
+ case 'y':
+ t2p->pdf_defaultyres =
+ (float)atof(optarg) / (t2p->pdf_centimeters?2.54F:1.0F);
+ break;
+ case 'w':
+ t2p->pdf_overridepagesize=1;
+ t2p->pdf_defaultpagewidth =
+ ((float)atof(optarg) * PS_UNIT_SIZE) / (t2p->pdf_centimeters?2.54F:1.0F);
+ break;
+ case 'l':
+ t2p->pdf_overridepagesize=1;
+ t2p->pdf_defaultpagelength =
+ ((float)atof(optarg) * PS_UNIT_SIZE) / (t2p->pdf_centimeters?2.54F:1.0F);
+ break;
+ case 'r':
+ if(optarg[0]=='o'){
+ t2p->pdf_overrideres=1;
+ }
+ break;
+ case 'p':
+ if(tiff2pdf_match_paper_size(
+ &(t2p->pdf_defaultpagewidth),
+ &(t2p->pdf_defaultpagelength),
+ optarg)){
+ t2p->pdf_overridepagesize=1;
+ } else {
+ TIFFWarning(TIFF2PDF_MODULE,
+ "Unknown paper size %s, ignoring option",
+ optarg);
+ }
+ break;
+ case 'i':
+ t2p->pdf_colorspace_invert=1;
+ break;
+ case 'f':
+ t2p->pdf_fitwindow=1;
+ break;
+ case 'e':
+ t2p->pdf_datetime =
+ (unsigned char*)_TIFFmalloc(17);
+ if(t2p->pdf_datetime==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ 17);
+ goto fail;
+ }
+ if(strlen(optarg)==0){
+ t2p->pdf_datetime[0] = 0;
+ } else {
+ if(strlen(optarg)>14){optarg[14]=0;}
+ t2p->pdf_datetime[0] = 'D';
+ t2p->pdf_datetime[1] = ':';
+ strcpy((char *)t2p->pdf_datetime + 2,
+ optarg);
+ }
+ break;
+ case 'c':
+ t2p->pdf_creator = (unsigned char *)
+ _TIFFmalloc(strlen(optarg) + 1);
+ if(t2p->pdf_creator==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg) + 1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_creator, optarg);
+ t2p->pdf_creator[strlen(optarg)] = 0;
+ break;
+ case 'a':
+ t2p->pdf_author = (unsigned char *)
+ _TIFFmalloc(strlen(optarg) + 1);
+ if(t2p->pdf_author==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg) + 1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_author, optarg);
+ t2p->pdf_author[strlen(optarg)]=0;
+ break;
+ case 't':
+ t2p->pdf_title = (unsigned char*)
+ _TIFFmalloc(strlen(optarg)+1);
+ if(t2p->pdf_title==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg) + 1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_title, optarg);
+ t2p->pdf_title[strlen(optarg)] = 0;
+ break;
+ case 's':
+ t2p->pdf_subject = (unsigned char*)
+ _TIFFmalloc(strlen(optarg) + 1);
+ if(t2p->pdf_subject==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg)+1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_subject, optarg);
+ t2p->pdf_subject[strlen(optarg)]=0;
+ break;
+ case 'k':
+ t2p->pdf_keywords = (unsigned char*)
+ _TIFFmalloc(strlen(optarg) + 1);
+ if(t2p->pdf_keywords==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg) + 1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_keywords, optarg);
+ t2p->pdf_keywords[strlen(optarg)] = 0;
+ break;
+ case 'b':
+ t2p->pdf_image_interpolate = 1;
+ break;
+ case 'h':
+ case '?':
+ tiff2pdf_usage();
+ goto success;
+ break;
+ }
+ }
+
+ /*
+ * Input
+ */
+ if(argc > optind) {
+ input = TIFFOpen(argv[optind++], "r");
+ if (input==NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't open input file %s for reading",
+ argv[optind-1]);
+ goto fail;
+ }
+ } else {
+ TIFFError(TIFF2PDF_MODULE, "No input file specified");
+ tiff2pdf_usage();
+ goto fail;
+ }
+
+ if(argc > optind) {
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for multiple input files");
+ tiff2pdf_usage();
+ goto fail;
+ }
+
+ /*
+ * Output
+ */
+ t2p->outputdisable = 0;
+ if (outfilename) {
+ t2p->outputfile = fopen(outfilename, "wb");
+ if (t2p->outputfile == NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't open output file %s for writing",
+ outfilename);
+ goto fail;
+ }
+ } else {
+ outfilename = "-";
+ t2p->outputfile = stdout;
+ }
+
+ output = TIFFClientOpen(outfilename, "w", (thandle_t) t2p,
+ t2p_readproc, t2p_writeproc, t2p_seekproc,
+ t2p_closeproc, t2p_sizeproc,
+ t2p_mapproc, t2p_unmapproc );
+ if (output == NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't initialize output descriptor");
+ goto fail;
+ }
+
+ /*
+ * Validate
+ */
+ t2p_validate(t2p);
+ t2pSeekFile(output, (toff_t) 0, SEEK_SET);
+
+ /*
+ * Write
+ */
+ written = t2p_write_pdf(t2p, input, output);
+ if (t2p->t2p_error != 0) {
+ TIFFError(TIFF2PDF_MODULE,
+ "An error occurred creating output PDF file");
+ goto fail;
+ }
+
+success:
+ if (output != NULL)
+ TIFFClose(output);
+ if (t2p != NULL)
+ t2p_free(t2p);
+ return(EXIT_SUCCESS);
+
+fail:
+ if(input != NULL)
+ TIFFClose(input);
+ if (output != NULL)
+ TIFFClose(output);
+ if (t2p != NULL)
+ t2p_free(t2p);
+ return(EXIT_FAILURE);
+
+}
+
+void tiff2pdf_usage(){
+ char* lines[]={
+ "usage: tiff2pdf [options] input.tiff",
+ "options:",
+ " -o: output to file name",
+#ifdef JPEG_SUPPORT
+ " -j: compress with JPEG",
+#endif
+#ifdef ZIP_SUPPORT
+ " -z: compress with Zip/Deflate",
+#endif
+ " -q: compression quality",
+ " -n: no compressed data passthrough",
+ " -d: do not compress (decompress)",
+ " -i: invert colors",
+ " -u: set distance unit, 'i' for inch, 'm' for centimeter",
+ " -x: set x resolution default in dots per unit",
+ " -y: set y resolution default in dots per unit",
+ " -w: width in units",
+ " -l: length in units",
+ " -r: 'd' for resolution default, 'o' for resolution override",
+ " -p: paper size, eg \"letter\", \"legal\", \"A4\"",
+ " -f: set PDF \"Fit Window\" user preference",
+ " -e: date, overrides image or current date/time default, YYYYMMDDHHMMSS",
+ " -c: sets document creator, overrides image software default",
+ " -a: sets document author, overrides image artist default",
+ " -t: sets document title, overrides image document name default",
+ " -s: sets document subject, overrides image image description default",
+ " -k: sets document keywords",
+ " -b: set PDF \"Interpolate\" user preference",
+ " -h: usage",
+ NULL
+ };
+ int i=0;
+
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i=0;lines[i]!=NULL;i++){
+ fprintf(stderr, "%s\n", lines[i]);
+ }
+
+ return;
+}
+
+int tiff2pdf_match_paper_size(float* width, float* length, char* papersize){
+
+ size_t i, len;
+ const char* sizes[]={
+ "LETTER", "A4", "LEGAL",
+ "EXECUTIVE", "LETTER", "LEGAL", "LEDGER", "TABLOID",
+ "A", "B", "C", "D", "E", "F", "G", "H", "J", "K",
+ "A10", "A9", "A8", "A7", "A6", "A5", "A4", "A3", "A2", "A1", "A0",
+ "2A0", "4A0", "2A", "4A",
+ "B10", "B9", "B8", "B7", "B6", "B5", "B4", "B3", "B2", "B1", "B0",
+ "JISB10", "JISB9", "JISB8", "JISB7", "JISB6", "JISB5", "JISB4",
+ "JISB3", "JISB2", "JISB1", "JISB0",
+ "C10", "C9", "C8", "C7", "C6", "C5", "C4", "C3", "C2", "C1", "C0",
+ "RA2", "RA1", "RA0", "SRA4", "SRA3", "SRA2", "SRA1", "SRA0",
+ "A3EXTRA", "A4EXTRA",
+ "STATEMENT", "FOLIO", "QUARTO",
+ NULL
+ } ;
+ const int widths[]={
+ 612, 595, 612,
+ 522, 612,612,792,792,
+ 612,792,1224,1584,2448,2016,792,2016,2448,2880,
+ 74,105,147,210,298,420,595,842,1191,1684,2384,3370,4768,3370,4768,
+ 88,125,176,249,354,499,709,1001,1417,2004,2835,
+ 91,128,181,258,363,516,729,1032,1460,2064,2920,
+ 79,113,162,230,323,459,649,918,1298,1298,2599,
+ 1219,1729,2438,638,907,1276,1814,2551,
+ 914,667,
+ 396, 612, 609,
+ 0
+ };
+ const int lengths[]={
+ 792,842,1008,
+ 756,792,1008,1224,1224,
+ 792,1224,1584,2448,3168,2880,6480,10296,12672,10296,
+ 105,147,210,298,420,595,842,1191,1684,2384,3370,4768,6741,4768,6741,
+ 125,176,249,354,499,709,1001,1417,2004,2835,4008,
+ 128,181,258,363,516,729,1032,1460,2064,2920,4127,
+ 113,162,230,323,459,649,918,1298,1837,1837,3677,
+ 1729,2438,3458,907,1276,1814,2551,3628,
+ 1262,914,
+ 612, 936, 780,
+ 0
+ };
+
+ len=strlen(papersize);
+ for(i=0;i<len;i++){
+ papersize[i]=toupper(papersize[i]);
+ }
+ for(i=0;sizes[i]!=NULL; i++){
+ if (strcmp( (const char*)papersize, sizes[i])==0){
+ *width=(float)widths[i];
+ *length=(float)lengths[i];
+ return(1);
+ }
+ }
+
+ return(0);
+}
+
+/*
+ This function allocates and initializes a T2P context struct pointer.
+*/
+
+T2P* t2p_init(){
+
+ T2P* t2p = (T2P*) _TIFFmalloc(sizeof(T2P));
+ if(t2p==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_init",
+ sizeof(T2P));
+ return( (T2P*) NULL );
+ }
+ _TIFFmemset(t2p, 0x00, sizeof(T2P));
+ t2p->pdf_majorversion=1;
+ t2p->pdf_minorversion=1;
+ t2p->pdf_defaultxres=300.0;
+ t2p->pdf_defaultyres=300.0;
+ t2p->pdf_defaultpagewidth=612.0;
+ t2p->pdf_defaultpagelength=792.0;
+ t2p->pdf_xrefcount=3; /* Catalog, Info, Pages */
+
+ return(t2p);
+}
+
+/*
+ This function frees a T2P context struct pointer and any allocated data fields of it.
+*/
+
+void t2p_free(T2P* t2p){
+
+ int i=0;
+
+ if(t2p != NULL){
+ if(t2p->pdf_xrefoffsets != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_xrefoffsets);
+ }
+ if(t2p->tiff_pages != NULL){
+ _TIFFfree( (tdata_t) t2p->tiff_pages);
+ }
+ for(i=0;i<t2p->tiff_pagecount;i++){
+ if(t2p->tiff_tiles[i].tiles_tiles != NULL){
+ _TIFFfree( (tdata_t) t2p->tiff_tiles[i].tiles_tiles);
+ }
+ }
+ if(t2p->tiff_tiles != NULL){
+ _TIFFfree( (tdata_t) t2p->tiff_tiles);
+ }
+ if(t2p->pdf_palette != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_palette);
+ }
+ if(t2p->pdf_fileid != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_fileid);
+ }
+ if(t2p->pdf_datetime != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_datetime);
+ }
+ if(t2p->pdf_creator != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_creator);
+ }
+ if(t2p->pdf_author != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_author);
+ }
+ if(t2p->pdf_title != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_title);
+ }
+ if(t2p->pdf_subject != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_subject);
+ }
+ if(t2p->pdf_keywords != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_keywords);
+ }
+#ifdef OJPEG_SUPPORT
+ if(t2p->pdf_ojpegdata != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_ojpegdata);
+ }
+#endif
+ _TIFFfree( (tdata_t) t2p );
+ }
+
+ return;
+}
+
+/*
+ This function validates the values of a T2P context struct pointer
+ before calling t2p_write_pdf with it.
+*/
+
+void t2p_validate(T2P* t2p){
+
+#ifdef JPEG_SUPPORT
+ if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
+ if(t2p->pdf_defaultcompressionquality>100 ||
+ t2p->pdf_defaultcompressionquality<1){
+ t2p->pdf_defaultcompressionquality=0;
+ }
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if(t2p->pdf_defaultcompression==T2P_COMPRESS_ZIP){
+ uint16 m=t2p->pdf_defaultcompressionquality%100;
+ if(t2p->pdf_defaultcompressionquality/100 > 9 ||
+ (m>1 && m<10) || m>15){
+ t2p->pdf_defaultcompressionquality=0;
+ }
+ if(t2p->pdf_defaultcompressionquality%100 !=0){
+ t2p->pdf_defaultcompressionquality/=100;
+ t2p->pdf_defaultcompressionquality*=100;
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "PNG Group predictor differencing not implemented, assuming compression quality %u",
+ t2p->pdf_defaultcompressionquality);
+ }
+ t2p->pdf_defaultcompressionquality%=100;
+ if(t2p->pdf_minorversion<2){t2p->pdf_minorversion=2;}
+ }
+#endif
+ (void)0;
+
+ return;
+}
+
+
+/*
+ This function scans the input TIFF file for pages. It attempts
+ to determine which IFD's of the TIFF file contain image document
+ pages. For each, it gathers some information that has to do
+ with the output of the PDF document as a whole.
+*/
+
+void t2p_read_tiff_init(T2P* t2p, TIFF* input){
+
+ tdir_t directorycount=0;
+ tdir_t i=0;
+ uint16 pagen=0;
+ uint16 paged=0;
+ uint16 xuint16=0;
+
+ directorycount=TIFFNumberOfDirectories(input);
+ t2p->tiff_pages = (T2P_PAGE*) _TIFFmalloc(directorycount * sizeof(T2P_PAGE));
+ if(t2p->tiff_pages==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for tiff_pages array, %s",
+ directorycount * sizeof(T2P_PAGE),
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ _TIFFmemset( t2p->tiff_pages, 0x00, directorycount * sizeof(T2P_PAGE));
+ t2p->tiff_tiles = (T2P_TILES*) _TIFFmalloc(directorycount * sizeof(T2P_TILES));
+ if(t2p->tiff_tiles==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for tiff_tiles array, %s",
+ directorycount * sizeof(T2P_TILES),
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ _TIFFmemset( t2p->tiff_tiles, 0x00, directorycount * sizeof(T2P_TILES));
+ for(i=0;i<directorycount;i++){
+ uint32 subfiletype = 0;
+
+ if(!TIFFSetDirectory(input, i)){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't set directory %u of input file %s",
+ i,
+ TIFFFileName(input));
+ return;
+ }
+ if(TIFFGetField(input, TIFFTAG_PAGENUMBER, &pagen, &paged)){
+ if((pagen>paged) && (paged != 0)){
+ t2p->tiff_pages[t2p->tiff_pagecount].page_number =
+ paged;
+ } else {
+ t2p->tiff_pages[t2p->tiff_pagecount].page_number =
+ pagen;
+ }
+ goto ispage2;
+ }
+ if(TIFFGetField(input, TIFFTAG_SUBFILETYPE, &subfiletype)){
+ if ( ((subfiletype & FILETYPE_PAGE) != 0)
+ || (subfiletype == 0)){
+ goto ispage;
+ } else {
+ goto isnotpage;
+ }
+ }
+ if(TIFFGetField(input, TIFFTAG_OSUBFILETYPE, &subfiletype)){
+ if ((subfiletype == OFILETYPE_IMAGE)
+ || (subfiletype == OFILETYPE_PAGE)
+ || (subfiletype == 0) ){
+ goto ispage;
+ } else {
+ goto isnotpage;
+ }
+ }
+ ispage:
+ t2p->tiff_pages[t2p->tiff_pagecount].page_number=t2p->tiff_pagecount;
+ ispage2:
+ t2p->tiff_pages[t2p->tiff_pagecount].page_directory=i;
+ if(TIFFIsTiled(input)){
+ t2p->tiff_pages[t2p->tiff_pagecount].page_tilecount =
+ TIFFNumberOfTiles(input);
+ }
+ t2p->tiff_pagecount++;
+ isnotpage:
+ (void)0;
+ }
+
+ qsort((void*) t2p->tiff_pages, t2p->tiff_pagecount,
+ sizeof(T2P_PAGE), t2p_cmp_t2p_page);
+
+ for(i=0;i<t2p->tiff_pagecount;i++){
+ t2p->pdf_xrefcount += 5;
+ TIFFSetDirectory(input, t2p->tiff_pages[i].page_directory );
+ if((TIFFGetField(input, TIFFTAG_PHOTOMETRIC, &xuint16)
+ && (xuint16==PHOTOMETRIC_PALETTE))
+ || TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)) {
+ t2p->tiff_pages[i].page_extra++;
+ t2p->pdf_xrefcount++;
+ }
+#ifdef ZIP_SUPPORT
+ if (TIFFGetField(input, TIFFTAG_COMPRESSION, &xuint16)) {
+ if( (xuint16== COMPRESSION_DEFLATE ||
+ xuint16== COMPRESSION_ADOBE_DEFLATE) &&
+ ((t2p->tiff_pages[i].page_tilecount != 0)
+ || TIFFNumberOfStrips(input)==1) &&
+ (t2p->pdf_nopassthrough==0) ){
+ if(t2p->pdf_minorversion<2){t2p->pdf_minorversion=2;}
+ }
+ }
+#endif
+ if (TIFFGetField(input, TIFFTAG_TRANSFERFUNCTION,
+ &(t2p->tiff_transferfunction[0]),
+ &(t2p->tiff_transferfunction[1]),
+ &(t2p->tiff_transferfunction[2]))) {
+ if(t2p->tiff_transferfunction[1] !=
+ t2p->tiff_transferfunction[0]) {
+ t2p->tiff_transferfunctioncount = 3;
+ t2p->tiff_pages[i].page_extra += 4;
+ t2p->pdf_xrefcount += 4;
+ } else {
+ t2p->tiff_transferfunctioncount = 1;
+ t2p->tiff_pages[i].page_extra += 2;
+ t2p->pdf_xrefcount += 2;
+ }
+ if(t2p->pdf_minorversion < 2)
+ t2p->pdf_minorversion = 2;
+ } else {
+ t2p->tiff_transferfunctioncount=0;
+ }
+ if( TIFFGetField(
+ input,
+ TIFFTAG_ICCPROFILE,
+ &(t2p->tiff_iccprofilelength),
+ &(t2p->tiff_iccprofile)) != 0){
+ t2p->tiff_pages[i].page_extra++;
+ t2p->pdf_xrefcount++;
+ if(t2p->pdf_minorversion<3){t2p->pdf_minorversion=3;}
+ }
+ t2p->tiff_tiles[i].tiles_tilecount=
+ t2p->tiff_pages[i].page_tilecount;
+ if( (TIFFGetField(input, TIFFTAG_PLANARCONFIG, &xuint16) != 0)
+ && (xuint16 == PLANARCONFIG_SEPARATE ) ){
+ TIFFGetField(input, TIFFTAG_SAMPLESPERPIXEL, &xuint16);
+ t2p->tiff_tiles[i].tiles_tilecount/= xuint16;
+ }
+ if( t2p->tiff_tiles[i].tiles_tilecount > 0){
+ t2p->pdf_xrefcount +=
+ (t2p->tiff_tiles[i].tiles_tilecount -1)*2;
+ TIFFGetField(input,
+ TIFFTAG_TILEWIDTH,
+ &( t2p->tiff_tiles[i].tiles_tilewidth) );
+ TIFFGetField(input,
+ TIFFTAG_TILELENGTH,
+ &( t2p->tiff_tiles[i].tiles_tilelength) );
+ t2p->tiff_tiles[i].tiles_tiles =
+ (T2P_TILE*) _TIFFmalloc(
+ t2p->tiff_tiles[i].tiles_tilecount
+ * sizeof(T2P_TILE) );
+ if( t2p->tiff_tiles[i].tiles_tiles == NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_read_tiff_init, %s",
+ t2p->tiff_tiles[i].tiles_tilecount * sizeof(T2P_TILE),
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ }
+ }
+
+ return;
+}
+
+/*
+ * This function is used by qsort to sort a T2P_PAGE* array of page structures
+ * by page number.
+ */
+
+int t2p_cmp_t2p_page(const void* e1, const void* e2){
+
+ return( ((T2P_PAGE*)e1)->page_number - ((T2P_PAGE*)e2)->page_number );
+}
+
+/*
+ This function sets the input directory to the directory of a given
+ page and determines information about the image. It checks
+ the image characteristics to determine if it is possible to convert
+ the image data into a page of PDF output, setting values of the T2P
+ struct for this page. It determines what color space is used in
+ the output PDF to represent the image.
+
+ It determines if the image can be converted as raw data without
+ requiring transcoding of the image data.
+*/
+
+void t2p_read_tiff_data(T2P* t2p, TIFF* input){
+
+ int i=0;
+ uint16* r;
+ uint16* g;
+ uint16* b;
+ uint16* a;
+ uint16 xuint16;
+ uint16* xuint16p;
+ float* xfloatp;
+
+ t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
+ t2p->pdf_sample = T2P_SAMPLE_NOTHING;
+ t2p->pdf_switchdecode = t2p->pdf_colorspace_invert;
+
+
+ TIFFSetDirectory(input, t2p->tiff_pages[t2p->pdf_page].page_directory);
+
+ TIFFGetField(input, TIFFTAG_IMAGEWIDTH, &(t2p->tiff_width));
+ if(t2p->tiff_width == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with zero width",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+
+ TIFFGetField(input, TIFFTAG_IMAGELENGTH, &(t2p->tiff_length));
+ if(t2p->tiff_length == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with zero length",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+
+ if(TIFFGetField(input, TIFFTAG_COMPRESSION, &(t2p->tiff_compression)) == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with no compression tag",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+
+ }
+ if( TIFFIsCODECConfigured(t2p->tiff_compression) == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with compression type %u: not configured",
+ TIFFFileName(input),
+ t2p->tiff_compression
+ );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+
+ }
+
+ TIFFGetFieldDefaulted(input, TIFFTAG_BITSPERSAMPLE, &(t2p->tiff_bitspersample));
+ switch(t2p->tiff_bitspersample){
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ case 0:
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "Image %s has 0 bits per sample, assuming 1",
+ TIFFFileName(input));
+ t2p->tiff_bitspersample=1;
+ break;
+ default:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with %u bits per sample",
+ TIFFFileName(input),
+ t2p->tiff_bitspersample);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+
+ TIFFGetFieldDefaulted(input, TIFFTAG_SAMPLESPERPIXEL, &(t2p->tiff_samplesperpixel));
+ if(t2p->tiff_samplesperpixel>4){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with %u samples per pixel",
+ TIFFFileName(input),
+ t2p->tiff_samplesperpixel);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ if(t2p->tiff_samplesperpixel==0){
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "Image %s has 0 samples per pixel, assuming 1",
+ TIFFFileName(input));
+ t2p->tiff_samplesperpixel=1;
+ }
+
+ if(TIFFGetField(input, TIFFTAG_SAMPLEFORMAT, &xuint16) != 0 ){
+ switch(xuint16){
+ case 0:
+ case 1:
+ case 4:
+ break;
+ default:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with sample format %u",
+ TIFFFileName(input),
+ xuint16);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ break;
+ }
+ }
+
+ TIFFGetFieldDefaulted(input, TIFFTAG_FILLORDER, &(t2p->tiff_fillorder));
+
+ if(TIFFGetField(input, TIFFTAG_PHOTOMETRIC, &(t2p->tiff_photometric)) == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with no photometric interpretation tag",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+
+ }
+
+ switch(t2p->tiff_photometric){
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ if (t2p->tiff_bitspersample==1){
+ t2p->pdf_colorspace=T2P_CS_BILEVEL;
+ if(t2p->tiff_photometric==PHOTOMETRIC_MINISWHITE){
+ t2p->pdf_switchdecode ^= 1;
+ }
+ } else {
+ t2p->pdf_colorspace=T2P_CS_GRAY;
+ if(t2p->tiff_photometric==PHOTOMETRIC_MINISWHITE){
+ t2p->pdf_switchdecode ^= 1;
+ }
+ }
+ break;
+ case PHOTOMETRIC_RGB:
+ t2p->pdf_colorspace=T2P_CS_RGB;
+ if(t2p->tiff_samplesperpixel == 3){
+ break;
+ }
+ if(TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)){
+ if(xuint16==1)
+ goto photometric_palette;
+ }
+ if(t2p->tiff_samplesperpixel > 3) {
+ if(t2p->tiff_samplesperpixel == 4) {
+ t2p->pdf_colorspace = T2P_CS_RGB;
+ if(TIFFGetField(input,
+ TIFFTAG_EXTRASAMPLES,
+ &xuint16, &xuint16p)
+ && xuint16 == 1) {
+ if(xuint16p[0] == EXTRASAMPLE_ASSOCALPHA){
+ t2p->pdf_sample=T2P_SAMPLE_RGBAA_TO_RGB;
+ break;
+ }
+ if(xuint16p[0] == EXTRASAMPLE_UNASSALPHA){
+ t2p->pdf_sample=T2P_SAMPLE_RGBA_TO_RGB;
+ break;
+ }
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "RGB image %s has 4 samples per pixel, assuming RGBA",
+ TIFFFileName(input));
+ break;
+ }
+ t2p->pdf_colorspace=T2P_CS_CMYK;
+ t2p->pdf_switchdecode ^= 1;
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "RGB image %s has 4 samples per pixel, assuming inverse CMYK",
+ TIFFFileName(input));
+ break;
+ } else {
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for RGB image %s with %u samples per pixel",
+ TIFFFileName(input),
+ t2p->tiff_samplesperpixel);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ break;
+ }
+ } else {
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for RGB image %s with %u samples per pixel",
+ TIFFFileName(input),
+ t2p->tiff_samplesperpixel);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ break;
+ }
+ case PHOTOMETRIC_PALETTE:
+ photometric_palette:
+ if(t2p->tiff_samplesperpixel!=1){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for palettized image %s with not one sample per pixel",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ t2p->pdf_colorspace=T2P_CS_RGB | T2P_CS_PALETTE;
+ t2p->pdf_palettesize=0x0001<<t2p->tiff_bitspersample;
+ if(!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b)){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Palettized image %s has no color map",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ if(t2p->pdf_palette != NULL){
+ _TIFFfree(t2p->pdf_palette);
+ t2p->pdf_palette=NULL;
+ }
+ t2p->pdf_palette = (unsigned char*)
+ _TIFFmalloc(t2p->pdf_palettesize*3);
+ if(t2p->pdf_palette==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_read_tiff_image, %s",
+ t2p->pdf_palettesize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ for(i=0;i<t2p->pdf_palettesize;i++){
+ t2p->pdf_palette[(i*3)] = (unsigned char) (r[i]>>8);
+ t2p->pdf_palette[(i*3)+1]= (unsigned char) (g[i]>>8);
+ t2p->pdf_palette[(i*3)+2]= (unsigned char) (b[i]>>8);
+ }
+ t2p->pdf_palettesize *= 3;
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ if(TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)){
+ if(xuint16==1){
+ goto photometric_palette_cmyk;
+ }
+ }
+ if( TIFFGetField(input, TIFFTAG_INKSET, &xuint16) ){
+ if(xuint16 != INKSET_CMYK){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s because its inkset is not CMYK",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ }
+ if(t2p->tiff_samplesperpixel==4){
+ t2p->pdf_colorspace=T2P_CS_CMYK;
+ } else {
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s because it has %u samples per pixel",
+ TIFFFileName(input),
+ t2p->tiff_samplesperpixel);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ break;
+ photometric_palette_cmyk:
+ if(t2p->tiff_samplesperpixel!=1){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for palettized CMYK image %s with not one sample per pixel",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ t2p->pdf_colorspace=T2P_CS_CMYK | T2P_CS_PALETTE;
+ t2p->pdf_palettesize=0x0001<<t2p->tiff_bitspersample;
+ if(!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b, &a)){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Palettized image %s has no color map",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ if(t2p->pdf_palette != NULL){
+ _TIFFfree(t2p->pdf_palette);
+ t2p->pdf_palette=NULL;
+ }
+ t2p->pdf_palette = (unsigned char*)
+ _TIFFmalloc(t2p->pdf_palettesize*4);
+ if(t2p->pdf_palette==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_read_tiff_image, %s",
+ t2p->pdf_palettesize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ for(i=0;i<t2p->pdf_palettesize;i++){
+ t2p->pdf_palette[(i*4)] = (unsigned char) (r[i]>>8);
+ t2p->pdf_palette[(i*4)+1]= (unsigned char) (g[i]>>8);
+ t2p->pdf_palette[(i*4)+2]= (unsigned char) (b[i]>>8);
+ t2p->pdf_palette[(i*4)+3]= (unsigned char) (a[i]>>8);
+ }
+ t2p->pdf_palettesize *= 4;
+ break;
+ case PHOTOMETRIC_YCBCR:
+ t2p->pdf_colorspace=T2P_CS_RGB;
+ if(t2p->tiff_samplesperpixel==1){
+ t2p->pdf_colorspace=T2P_CS_GRAY;
+ t2p->tiff_photometric=PHOTOMETRIC_MINISBLACK;
+ break;
+ }
+ t2p->pdf_sample=T2P_SAMPLE_YCBCR_TO_RGB;
+#ifdef JPEG_SUPPORT
+ if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
+ t2p->pdf_sample=T2P_SAMPLE_NOTHING;
+ }
+#endif
+ break;
+ case PHOTOMETRIC_CIELAB:
+ t2p->pdf_labrange[0]= -127;
+ t2p->pdf_labrange[1]= 127;
+ t2p->pdf_labrange[2]= -127;
+ t2p->pdf_labrange[3]= 127;
+ t2p->pdf_sample=T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
+ t2p->pdf_colorspace=T2P_CS_LAB;
+ break;
+ case PHOTOMETRIC_ICCLAB:
+ t2p->pdf_labrange[0]= 0;
+ t2p->pdf_labrange[1]= 255;
+ t2p->pdf_labrange[2]= 0;
+ t2p->pdf_labrange[3]= 255;
+ t2p->pdf_colorspace=T2P_CS_LAB;
+ break;
+ case PHOTOMETRIC_ITULAB:
+ t2p->pdf_labrange[0]=-85;
+ t2p->pdf_labrange[1]=85;
+ t2p->pdf_labrange[2]=-75;
+ t2p->pdf_labrange[3]=124;
+ t2p->pdf_sample=T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
+ t2p->pdf_colorspace=T2P_CS_LAB;
+ break;
+ case PHOTOMETRIC_LOGL:
+ case PHOTOMETRIC_LOGLUV:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with photometric interpretation LogL/LogLuv",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ default:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with photometric interpretation %u",
+ TIFFFileName(input),
+ t2p->tiff_photometric);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+
+ if(TIFFGetField(input, TIFFTAG_PLANARCONFIG, &(t2p->tiff_planar))){
+ switch(t2p->tiff_planar){
+ case 0:
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "Image %s has planar configuration 0, assuming 1",
+ TIFFFileName(input));
+ t2p->tiff_planar=PLANARCONFIG_CONTIG;
+ case PLANARCONFIG_CONTIG:
+ break;
+ case PLANARCONFIG_SEPARATE:
+ t2p->pdf_sample=T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG;
+ if(t2p->tiff_bitspersample!=8){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with separated planar configuration and %u bits per sample",
+ TIFFFileName(input),
+ t2p->tiff_bitspersample);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ break;
+ default:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with planar configuration %u",
+ TIFFFileName(input),
+ t2p->tiff_planar);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ }
+
+ TIFFGetFieldDefaulted(input, TIFFTAG_ORIENTATION,
+ &(t2p->tiff_orientation));
+ if(t2p->tiff_orientation>8){
+ TIFFWarning(TIFF2PDF_MODULE,
+ "Image %s has orientation %u, assuming 0",
+ TIFFFileName(input), t2p->tiff_orientation);
+ t2p->tiff_orientation=0;
+ }
+
+ if(TIFFGetField(input, TIFFTAG_XRESOLUTION, &(t2p->tiff_xres) ) == 0){
+ t2p->tiff_xres=0.0;
+ }
+ if(TIFFGetField(input, TIFFTAG_YRESOLUTION, &(t2p->tiff_yres) ) == 0){
+ t2p->tiff_yres=0.0;
+ }
+ TIFFGetFieldDefaulted(input, TIFFTAG_RESOLUTIONUNIT,
+ &(t2p->tiff_resunit));
+ if(t2p->tiff_resunit == RESUNIT_CENTIMETER) {
+ t2p->tiff_xres *= 2.54F;
+ t2p->tiff_yres *= 2.54F;
+ } else if (t2p->tiff_resunit != RESUNIT_INCH
+ && t2p->pdf_centimeters != 0) {
+ t2p->tiff_xres *= 2.54F;
+ t2p->tiff_yres *= 2.54F;
+ }
+
+ t2p_compose_pdf_page(t2p);
+
+ t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
+ if(t2p->pdf_nopassthrough==0){
+#ifdef CCITT_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_CCITTFAX4
+ ){
+ if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
+ t2p->pdf_transcode = T2P_TRANSCODE_RAW;
+ t2p->pdf_compression=T2P_COMPRESS_G4;
+ }
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if(t2p->tiff_compression== COMPRESSION_ADOBE_DEFLATE
+ || t2p->tiff_compression==COMPRESSION_DEFLATE){
+ if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
+ t2p->pdf_transcode = T2P_TRANSCODE_RAW;
+ t2p->pdf_compression=T2P_COMPRESS_ZIP;
+ }
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_OJPEG){
+ t2p->pdf_transcode = T2P_TRANSCODE_RAW;
+ t2p->pdf_compression=T2P_COMPRESS_JPEG;
+ t2p_process_ojpeg_tables(t2p, input);
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_JPEG){
+ t2p->pdf_transcode = T2P_TRANSCODE_RAW;
+ t2p->pdf_compression=T2P_COMPRESS_JPEG;
+ }
+#endif
+ (void)0;
+ }
+
+ if(t2p->pdf_transcode!=T2P_TRANSCODE_RAW){
+ t2p->pdf_compression = t2p->pdf_defaultcompression;
+ }
+
+#ifdef JPEG_SUPPORT
+ if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
+ if(t2p->pdf_colorspace & T2P_CS_PALETTE){
+ t2p->pdf_sample|=T2P_SAMPLE_REALIZE_PALETTE;
+ t2p->pdf_colorspace ^= T2P_CS_PALETTE;
+ t2p->tiff_pages[t2p->pdf_page].page_extra--;
+ }
+ }
+ if(t2p->tiff_compression==COMPRESSION_JPEG){
+ if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with JPEG compression and separated planar configuration",
+ TIFFFileName(input));
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return;
+ }
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_OJPEG){
+ if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with OJPEG compression and separated planar configuration",
+ TIFFFileName(input));
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return;
+ }
+ }
+#endif
+
+ if(t2p->pdf_sample & T2P_SAMPLE_REALIZE_PALETTE){
+ if(t2p->pdf_colorspace & T2P_CS_CMYK){
+ t2p->tiff_samplesperpixel=4;
+ t2p->tiff_photometric=PHOTOMETRIC_SEPARATED;
+ } else {
+ t2p->tiff_samplesperpixel=3;
+ t2p->tiff_photometric=PHOTOMETRIC_RGB;
+ }
+ }
+
+ if (TIFFGetField(input, TIFFTAG_TRANSFERFUNCTION,
+ &(t2p->tiff_transferfunction[0]),
+ &(t2p->tiff_transferfunction[1]),
+ &(t2p->tiff_transferfunction[2]))) {
+ if(t2p->tiff_transferfunction[1] !=
+ t2p->tiff_transferfunction[0]) {
+ t2p->tiff_transferfunctioncount=3;
+ } else {
+ t2p->tiff_transferfunctioncount=1;
+ }
+ } else {
+ t2p->tiff_transferfunctioncount=0;
+ }
+ if(TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp)!=0){
+ t2p->tiff_whitechromaticities[0]=xfloatp[0];
+ t2p->tiff_whitechromaticities[1]=xfloatp[1];
+ if(t2p->pdf_colorspace & T2P_CS_GRAY){
+ t2p->pdf_colorspace |= T2P_CS_CALGRAY;
+ }
+ if(t2p->pdf_colorspace & T2P_CS_RGB){
+ t2p->pdf_colorspace |= T2P_CS_CALRGB;
+ }
+ }
+ if(TIFFGetField(input, TIFFTAG_PRIMARYCHROMATICITIES, &xfloatp)!=0){
+ t2p->tiff_primarychromaticities[0]=xfloatp[0];
+ t2p->tiff_primarychromaticities[1]=xfloatp[1];
+ t2p->tiff_primarychromaticities[2]=xfloatp[2];
+ t2p->tiff_primarychromaticities[3]=xfloatp[3];
+ t2p->tiff_primarychromaticities[4]=xfloatp[4];
+ t2p->tiff_primarychromaticities[5]=xfloatp[5];
+ if(t2p->pdf_colorspace & T2P_CS_RGB){
+ t2p->pdf_colorspace |= T2P_CS_CALRGB;
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_LAB){
+ if(TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp) != 0){
+ t2p->tiff_whitechromaticities[0]=xfloatp[0];
+ t2p->tiff_whitechromaticities[1]=xfloatp[1];
+ } else {
+ t2p->tiff_whitechromaticities[0]=0.3457F; /* 0.3127F; */
+ t2p->tiff_whitechromaticities[1]=0.3585F; /* 0.3290F; */
+ }
+ }
+ if(TIFFGetField(input,
+ TIFFTAG_ICCPROFILE,
+ &(t2p->tiff_iccprofilelength),
+ &(t2p->tiff_iccprofile))!=0){
+ t2p->pdf_colorspace |= T2P_CS_ICCBASED;
+ } else {
+ t2p->tiff_iccprofilelength=0;
+ t2p->tiff_iccprofile=NULL;
+ }
+
+#ifdef CCITT_SUPPORT
+ if( t2p->tiff_bitspersample==1 &&
+ t2p->tiff_samplesperpixel==1){
+ t2p->pdf_compression = T2P_COMPRESS_G4;
+ }
+#endif
+
+
+ return;
+}
+
+/*
+ This function returns the necessary size of a data buffer to contain the raw or
+ uncompressed image data from the input TIFF for a page.
+*/
+
+void t2p_read_tiff_size(T2P* t2p, TIFF* input){
+
+ uint32* sbc=NULL;
+#if defined(JPEG_SUPPORT) || defined (OJPEG_SUPPORT)
+ unsigned char* jpt=NULL;
+ tstrip_t i=0;
+ tstrip_t stripcount=0;
+#endif
+#ifdef OJPEG_SUPPORT
+ tsize_t k = 0;
+#endif
+
+ if(t2p->pdf_transcode == T2P_TRANSCODE_RAW){
+#ifdef CCITT_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_G4 ){
+ TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc);
+ t2p->tiff_datasize=sbc[0];
+ return;
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_ZIP){
+ TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc);
+ t2p->tiff_datasize=sbc[0];
+ return;
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_OJPEG){
+ if(!TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Input file %s missing field: TIFFTAG_STRIPBYTECOUNTS",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ k += sbc[i];
+ }
+ if(TIFFGetField(input, TIFFTAG_JPEGIFOFFSET, &(t2p->tiff_dataoffset))){
+ if(t2p->tiff_dataoffset != 0){
+ if(TIFFGetField(input, TIFFTAG_JPEGIFBYTECOUNT, &(t2p->tiff_datasize))!=0){
+ if(t2p->tiff_datasize < k) {
+ t2p->pdf_ojpegiflength=t2p->tiff_datasize;
+ t2p->tiff_datasize+=k;
+ t2p->tiff_datasize+=6;
+ t2p->tiff_datasize+=2*stripcount;
+ TIFFWarning(TIFF2PDF_MODULE,
+ "Input file %s has short JPEG interchange file byte count",
+ TIFFFileName(input));
+ return;
+ }
+ return;
+ }else {
+ TIFFError(TIFF2PDF_MODULE,
+ "Input file %s missing field: TIFFTAG_JPEGIFBYTECOUNT",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ }
+ }
+ t2p->tiff_datasize+=k;
+ t2p->tiff_datasize+=2*stripcount;
+ t2p->tiff_datasize+=2048;
+ return;
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_JPEG) {
+ uint32 count = 0;
+ if(TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0 ){
+ if(count > 4){
+ t2p->tiff_datasize += count;
+ t2p->tiff_datasize -= 2; /* don't use EOI of header */
+ }
+ } else {
+ t2p->tiff_datasize = 2; /* SOI for first strip */
+ }
+ stripcount=TIFFNumberOfStrips(input);
+ if(!TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Input file %s missing field: TIFFTAG_STRIPBYTECOUNTS",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ for(i=0;i<stripcount;i++){
+ t2p->tiff_datasize += sbc[i];
+ t2p->tiff_datasize -=4; /* don't use SOI or EOI of strip */
+ }
+ t2p->tiff_datasize +=2; /* use EOI of last strip */
+ return;
+ }
+#endif
+ (void) 0;
+ }
+ t2p->tiff_datasize=TIFFScanlineSize(input) * t2p->tiff_length;
+ if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
+ t2p->tiff_datasize*= t2p->tiff_samplesperpixel;
+ }
+
+ return;
+}
+
+/*
+ This function returns the necessary size of a data buffer to contain the raw or
+ uncompressed image data from the input TIFF for a tile of a page.
+*/
+
+void t2p_read_tiff_size_tile(T2P* t2p, TIFF* input, ttile_t tile){
+
+ uint32* tbc = NULL;
+ uint16 edge=0;
+#ifdef JPEG_SUPPORT
+ unsigned char* jpt;
+#endif
+
+ edge |= t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
+ edge |= t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
+
+ if(t2p->pdf_transcode==T2P_TRANSCODE_RAW){
+ if(edge
+#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
+ && !(t2p->pdf_compression==T2P_COMPRESS_JPEG)
+#endif
+ ){
+ t2p->tiff_datasize=TIFFTileSize(input);
+ return;
+ } else {
+ TIFFGetField(input, TIFFTAG_TILEBYTECOUNTS, &tbc);
+ t2p->tiff_datasize=tbc[tile];
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_OJPEG){
+ t2p->tiff_datasize+=2048;
+ return;
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_JPEG) {
+ uint32 count = 0;
+ if(TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt)!=0){
+ if(count > 4){
+ t2p->tiff_datasize += count;
+ t2p->tiff_datasize -= 4; /* don't use EOI of header or SOI of tile */
+ }
+ }
+ }
+#endif
+ return;
+ }
+ }
+ t2p->tiff_datasize=TIFFTileSize(input);
+ if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
+ t2p->tiff_datasize*= t2p->tiff_samplesperpixel;
+ }
+
+ return;
+}
+
+/*
+ * This functions returns a non-zero value when the tile is on the right edge
+ * and does not have full imaged tile width.
+ */
+
+int t2p_tile_is_right_edge(T2P_TILES tiles, ttile_t tile){
+
+ if( ((tile+1) % tiles.tiles_tilecountx == 0)
+ && (tiles.tiles_edgetilewidth != 0) ){
+ return(1);
+ } else {
+ return(0);
+ }
+}
+
+/*
+ * This functions returns a non-zero value when the tile is on the bottom edge
+ * and does not have full imaged tile length.
+ */
+
+int t2p_tile_is_bottom_edge(T2P_TILES tiles, ttile_t tile){
+
+ if( ((tile+1) > (tiles.tiles_tilecount-tiles.tiles_tilecountx) )
+ && (tiles.tiles_edgetilelength != 0) ){
+ return(1);
+ } else {
+ return(0);
+ }
+}
+
+/*
+ * This function returns a non-zero value when the tile is a right edge tile
+ * or a bottom edge tile.
+ */
+
+int t2p_tile_is_edge(T2P_TILES tiles, ttile_t tile){
+
+ return(t2p_tile_is_right_edge(tiles, tile) | t2p_tile_is_bottom_edge(tiles, tile) );
+}
+
+/*
+ This function returns a non-zero value when the tile is a right edge tile and a bottom
+ edge tile.
+*/
+
+int t2p_tile_is_corner_edge(T2P_TILES tiles, ttile_t tile){
+
+ return(t2p_tile_is_right_edge(tiles, tile) & t2p_tile_is_bottom_edge(tiles, tile) );
+}
+
+
+/*
+ This function reads the raster image data from the input TIFF for an image and writes
+ the data to the output PDF XObject image dictionary stream. It returns the amount written
+ or zero on error.
+*/
+
+tsize_t t2p_readwrite_pdf_image(T2P* t2p, TIFF* input, TIFF* output){
+
+ tsize_t written=0;
+ unsigned char* buffer=NULL;
+ unsigned char* samplebuffer=NULL;
+ tsize_t bufferoffset=0;
+ tsize_t samplebufferoffset=0;
+ tsize_t read=0;
+ tstrip_t i=0;
+ tstrip_t j=0;
+ tstrip_t stripcount=0;
+ tsize_t stripsize=0;
+ tsize_t sepstripcount=0;
+ tsize_t sepstripsize=0;
+#ifdef OJPEG_SUPPORT
+ toff_t inputoffset=0;
+ uint16 h_samp=1;
+ uint16 v_samp=1;
+ uint16 ri=1;
+ uint32 rows=0;
+#endif
+#ifdef JPEG_SUPPORT
+ unsigned char* jpt;
+ float* xfloatp;
+ uint32* sbc;
+ unsigned char* stripbuffer;
+ tsize_t striplength=0;
+ uint32 max_striplength=0;
+#endif
+
+ if(t2p->pdf_transcode == T2P_TRANSCODE_RAW){
+#ifdef CCITT_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_G4){
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if (buffer == NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ TIFFReadRawStrip(input, 0, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ if (t2p->tiff_fillorder==FILLORDER_LSB2MSB){
+ /*
+ * make sure is lsb-to-msb
+ * bit-endianness fill order
+ */
+ TIFFReverseBits(buffer,
+ t2p->tiff_datasize);
+ }
+ t2pWriteFile(output, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if (t2p->pdf_compression == T2P_COMPRESS_ZIP) {
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer == NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ TIFFReadRawStrip(input, 0, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ if (t2p->tiff_fillorder==FILLORDER_LSB2MSB) {
+ TIFFReverseBits(buffer,
+ t2p->tiff_datasize);
+ }
+ t2pWriteFile(output, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_OJPEG) {
+
+ if(t2p->tiff_dataoffset != 0) {
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer == NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ if(t2p->pdf_ojpegiflength==0){
+ inputoffset=t2pSeekFile(input, 0,
+ SEEK_CUR);
+ t2pSeekFile(input,
+ t2p->tiff_dataoffset,
+ SEEK_SET);
+ t2pReadFile(input, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ t2pSeekFile(input, inputoffset,
+ SEEK_SET);
+ t2pWriteFile(output, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ } else {
+ inputoffset=t2pSeekFile(input, 0,
+ SEEK_CUR);
+ t2pSeekFile(input,
+ t2p->tiff_dataoffset,
+ SEEK_SET);
+ bufferoffset = t2pReadFile(input,
+ (tdata_t) buffer,
+ t2p->pdf_ojpegiflength);
+ t2p->pdf_ojpegiflength = 0;
+ t2pSeekFile(input, inputoffset,
+ SEEK_SET);
+ TIFFGetField(input,
+ TIFFTAG_YCBCRSUBSAMPLING,
+ &h_samp, &v_samp);
+ buffer[bufferoffset++]= 0xff;
+ buffer[bufferoffset++]= 0xdd;
+ buffer[bufferoffset++]= 0x00;
+ buffer[bufferoffset++]= 0x04;
+ h_samp*=8;
+ v_samp*=8;
+ ri=(t2p->tiff_width+h_samp-1) / h_samp;
+ TIFFGetField(input,
+ TIFFTAG_ROWSPERSTRIP,
+ &rows);
+ ri*=(rows+v_samp-1)/v_samp;
+ buffer[bufferoffset++]= (ri>>8) & 0xff;
+ buffer[bufferoffset++]= ri & 0xff;
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ if(i != 0 ){
+ buffer[bufferoffset++]=0xff;
+ buffer[bufferoffset++]=(0xd0 | ((i-1)%8));
+ }
+ bufferoffset+=TIFFReadRawStrip(input,
+ i,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset]),
+ -1);
+ }
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ }
+ } else {
+ if(! t2p->pdf_ojpegdata){
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for OJPEG image %s with bad tables",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ _TIFFmemcpy(buffer, t2p->pdf_ojpegdata, t2p->pdf_ojpegdatalength);
+ bufferoffset=t2p->pdf_ojpegdatalength;
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ if(i != 0){
+ buffer[bufferoffset++]=0xff;
+ buffer[bufferoffset++]=(0xd0 | ((i-1)%8));
+ }
+ bufferoffset+=TIFFReadRawStrip(input,
+ i,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset]),
+ -1);
+ }
+ if( ! ( (buffer[bufferoffset-1]==0xd9) && (buffer[bufferoffset-2]==0xff) ) ){
+ buffer[bufferoffset++]=0xff;
+ buffer[bufferoffset++]=0xd9;
+ }
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for OJPEG image %s with no JPEG File Interchange offset",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_JPEG) {
+ uint32 count = 0;
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ if (TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0) {
+ if(count > 4) {
+ _TIFFmemcpy(buffer, jpt, count);
+ bufferoffset += count - 2;
+ }
+ }
+ stripcount=TIFFNumberOfStrips(input);
+ TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc);
+ for(i=0;i<stripcount;i++){
+ if(sbc[i]>max_striplength) max_striplength=sbc[i];
+ }
+ stripbuffer = (unsigned char*)
+ _TIFFmalloc(max_striplength);
+ if(stripbuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ max_striplength,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ for(i=0;i<stripcount;i++){
+ striplength=TIFFReadRawStrip(input, i, (tdata_t) stripbuffer, -1);
+ if(!t2p_process_jpeg_strip(
+ stripbuffer,
+ &striplength,
+ buffer,
+ &bufferoffset,
+ i,
+ t2p->tiff_length)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't process JPEG data in input file %s",
+ TIFFFileName(input));
+ _TIFFfree(samplebuffer);
+ _TIFFfree(buffer);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ }
+ buffer[bufferoffset++]=0xff;
+ buffer[bufferoffset++]=0xd9;
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(stripbuffer);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ }
+#endif
+ (void)0;
+ }
+
+ if(t2p->pdf_sample==T2P_SAMPLE_NOTHING){
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ stripsize=TIFFStripSize(input);
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ read =
+ TIFFReadEncodedStrip(input,
+ i,
+ (tdata_t) &buffer[bufferoffset],
+ stripsize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding strip %u of %s",
+ i,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ bufferoffset+=read;
+ }
+ } else {
+ if(t2p->pdf_sample & T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG){
+
+ sepstripsize=TIFFStripSize(input);
+ sepstripcount=TIFFNumberOfStrips(input);
+
+ stripsize=sepstripsize*t2p->tiff_samplesperpixel;
+ stripcount=sepstripcount/t2p->tiff_samplesperpixel;
+
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ samplebuffer = (unsigned char*) _TIFFmalloc(stripsize);
+ if(samplebuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ for(i=0;i<stripcount;i++){
+ samplebufferoffset=0;
+ for(j=0;j<t2p->tiff_samplesperpixel;j++){
+ read =
+ TIFFReadEncodedStrip(input,
+ i + j*stripcount,
+ (tdata_t) &(samplebuffer[samplebufferoffset]),
+ sepstripsize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding strip %u of %s",
+ i + j*stripcount,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ samplebufferoffset+=read;
+ }
+ t2p_sample_planar_separate_to_contig(
+ t2p,
+ &(buffer[bufferoffset]),
+ samplebuffer,
+ samplebufferoffset);
+ bufferoffset+=samplebufferoffset;
+ }
+ _TIFFfree(samplebuffer);
+ goto dataready;
+ }
+
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ stripsize=TIFFStripSize(input);
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ read =
+ TIFFReadEncodedStrip(input,
+ i,
+ (tdata_t) &buffer[bufferoffset],
+ stripsize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding strip %u of %s",
+ i,
+ TIFFFileName(input));
+ _TIFFfree(samplebuffer);
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ bufferoffset+=read;
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_REALIZE_PALETTE){
+ samplebuffer=(unsigned char*)_TIFFrealloc(
+ (tdata_t) buffer,
+ t2p->tiff_datasize * t2p->tiff_samplesperpixel);
+ if(samplebuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ _TIFFfree(buffer);
+ } else {
+ buffer=samplebuffer;
+ t2p->tiff_datasize *= t2p->tiff_samplesperpixel;
+ }
+ t2p_sample_realize_palette(t2p, buffer);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_RGBA_TO_RGB){
+ t2p->tiff_datasize=t2p_sample_rgba_to_rgb(
+ (tdata_t)buffer,
+ t2p->tiff_width*t2p->tiff_length);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_RGBAA_TO_RGB){
+ t2p->tiff_datasize=t2p_sample_rgbaa_to_rgb(
+ (tdata_t)buffer,
+ t2p->tiff_width*t2p->tiff_length);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_YCBCR_TO_RGB){
+ samplebuffer=(unsigned char*)_TIFFrealloc(
+ (tdata_t)buffer,
+ t2p->tiff_width*t2p->tiff_length*4);
+ if(samplebuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ _TIFFfree(buffer);
+ return(0);
+ } else {
+ buffer=samplebuffer;
+ }
+ if(!TIFFReadRGBAImageOriented(
+ input,
+ t2p->tiff_width,
+ t2p->tiff_length,
+ (uint32*)buffer,
+ ORIENTATION_TOPLEFT,
+ 0)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't use TIFFReadRGBAImageOriented to extract RGB image from %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ t2p->tiff_datasize=t2p_sample_abgr_to_rgb(
+ (tdata_t) buffer,
+ t2p->tiff_width*t2p->tiff_length);
+
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED){
+ t2p->tiff_datasize=t2p_sample_lab_signed_to_unsigned(
+ (tdata_t)buffer,
+ t2p->tiff_width*t2p->tiff_length);
+ }
+ }
+
+dataready:
+
+ t2p_disable(output);
+ TIFFSetField(output, TIFFTAG_PHOTOMETRIC, t2p->tiff_photometric);
+ TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, t2p->tiff_bitspersample);
+ TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, t2p->tiff_samplesperpixel);
+ TIFFSetField(output, TIFFTAG_IMAGEWIDTH, t2p->tiff_width);
+ TIFFSetField(output, TIFFTAG_IMAGELENGTH, t2p->tiff_length);
+ TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, t2p->tiff_length);
+ TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(output, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+
+ switch(t2p->pdf_compression){
+ case T2P_COMPRESS_NONE:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ break;
+#ifdef CCITT_SUPPORT
+ case T2P_COMPRESS_G4:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
+ break;
+#endif
+#ifdef JPEG_SUPPORT
+ case T2P_COMPRESS_JPEG:
+ if(t2p->tiff_photometric==PHOTOMETRIC_YCBCR) {
+ uint16 hor = 0, ver = 0;
+ if (TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &hor, &ver) !=0 ) {
+ if(hor != 0 && ver != 0){
+ TIFFSetField(output, TIFFTAG_YCBCRSUBSAMPLING, hor, ver);
+ }
+ }
+ if(TIFFGetField(input, TIFFTAG_REFERENCEBLACKWHITE, &xfloatp)!=0){
+ TIFFSetField(output, TIFFTAG_REFERENCEBLACKWHITE, xfloatp);
+ }
+ }
+ if(TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_JPEG)==0){
+ TIFFError(TIFF2PDF_MODULE,
+ "Unable to use JPEG compression for input %s and output %s",
+ TIFFFileName(input),
+ TIFFFileName(output));
+ _TIFFfree(buffer);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ TIFFSetField(output, TIFFTAG_JPEGTABLESMODE, 0);
+
+ if(t2p->pdf_colorspace & (T2P_CS_RGB | T2P_CS_LAB)){
+ TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ if(t2p->tiff_photometric != PHOTOMETRIC_YCBCR){
+ TIFFSetField(output, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ } else {
+ TIFFSetField(output, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_GRAY){
+ (void)0;
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CMYK){
+ (void)0;
+ }
+ if(t2p->pdf_defaultcompressionquality != 0){
+ TIFFSetField(output,
+ TIFFTAG_JPEGQUALITY,
+ t2p->pdf_defaultcompressionquality);
+ }
+
+ break;
+#endif
+#ifdef ZIP_SUPPORT
+ case T2P_COMPRESS_ZIP:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
+ if(t2p->pdf_defaultcompressionquality%100 != 0){
+ TIFFSetField(output,
+ TIFFTAG_PREDICTOR,
+ t2p->pdf_defaultcompressionquality % 100);
+ }
+ if(t2p->pdf_defaultcompressionquality/100 != 0){
+ TIFFSetField(output,
+ TIFFTAG_ZIPQUALITY,
+ (t2p->pdf_defaultcompressionquality / 100));
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ t2p_enable(output);
+ t2p->outputwritten = 0;
+#ifdef JPEG_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_JPEG
+ && t2p->tiff_photometric == PHOTOMETRIC_YCBCR){
+ bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t)0,
+ buffer,
+ stripsize * stripcount);
+ } else
+#endif
+ {
+ bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t)0,
+ buffer,
+ t2p->tiff_datasize);
+ }
+ if (buffer != NULL) {
+ _TIFFfree(buffer);
+ buffer=NULL;
+ }
+
+ if (bufferoffset == (tsize_t)-1) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Error writing encoded strip to output PDF %s",
+ TIFFFileName(output));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+
+ written = t2p->outputwritten;
+ return(written);
+}
+
+/*
+ * This function reads the raster image data from the input TIFF for an image
+ * tile and writes the data to the output PDF XObject image dictionary stream
+ * for the tile. It returns the amount written or zero on error.
+ */
+
+tsize_t t2p_readwrite_pdf_image_tile(T2P* t2p, TIFF* input, TIFF* output, ttile_t tile){
+
+ uint16 edge=0;
+ tsize_t written=0;
+ unsigned char* buffer=NULL;
+ tsize_t bufferoffset=0;
+ unsigned char* samplebuffer=NULL;
+ tsize_t samplebufferoffset=0;
+ tsize_t read=0;
+ uint16 i=0;
+ ttile_t tilecount=0;
+ tsize_t tilesize=0;
+ ttile_t septilecount=0;
+ tsize_t septilesize=0;
+#ifdef JPEG_SUPPORT
+ unsigned char* jpt;
+ float* xfloatp;
+ uint32 xuint32=0;
+#endif
+
+ edge |= t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
+ edge |= t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
+
+ if( (t2p->pdf_transcode == T2P_TRANSCODE_RAW) && ((edge == 0)
+#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
+ || (t2p->pdf_compression == T2P_COMPRESS_JPEG)
+#endif
+ )
+ ){
+#ifdef CCITT_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_G4){
+ buffer= (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ TIFFReadRawTile(input, tile, (tdata_t) buffer, t2p->tiff_datasize);
+ if (t2p->tiff_fillorder==FILLORDER_LSB2MSB){
+ TIFFReverseBits(buffer, t2p->tiff_datasize);
+ }
+ t2pWriteFile(output, (tdata_t) buffer, t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_ZIP){
+ buffer= (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ TIFFReadRawTile(input, tile, (tdata_t) buffer, t2p->tiff_datasize);
+ if (t2p->tiff_fillorder==FILLORDER_LSB2MSB){
+ TIFFReverseBits(buffer, t2p->tiff_datasize);
+ }
+ t2pWriteFile(output, (tdata_t) buffer, t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_OJPEG){
+ if(! t2p->pdf_ojpegdata){
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for OJPEG image %s with "
+ "bad tables",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ buffer=(unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ _TIFFmemcpy(buffer, t2p->pdf_ojpegdata, t2p->pdf_ojpegdatalength);
+ if(edge!=0){
+ if(t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile)){
+ buffer[7]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength >> 8) & 0xff;
+ buffer[8]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength ) & 0xff;
+ }
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile)){
+ buffer[9]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth >> 8) & 0xff;
+ buffer[10]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth ) & 0xff;
+ }
+ }
+ bufferoffset=t2p->pdf_ojpegdatalength;
+ bufferoffset+=TIFFReadRawTile(input,
+ tile,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset]),
+ -1);
+ ((unsigned char*)buffer)[bufferoffset++]=0xff;
+ ((unsigned char*)buffer)[bufferoffset++]=0xd9;
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_JPEG){
+ unsigned char table_end[2];
+ uint32 count = 0;
+ buffer= (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0) {
+ if (count > 0) {
+ _TIFFmemcpy(buffer, jpt, count);
+ bufferoffset += count - 2;
+ table_end[0] = buffer[bufferoffset-2];
+ table_end[1] = buffer[bufferoffset-1];
+ }
+ if (count > 0) {
+ xuint32 = bufferoffset;
+ bufferoffset += TIFFReadRawTile(
+ input,
+ tile,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset-2]),
+ -1);
+ buffer[xuint32-2]=table_end[0];
+ buffer[xuint32-1]=table_end[1];
+ } else {
+ bufferoffset += TIFFReadRawTile(
+ input,
+ tile,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset]),
+ -1);
+ }
+ }
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ }
+#endif
+ (void)0;
+ }
+
+ if(t2p->pdf_sample==T2P_SAMPLE_NOTHING){
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for "
+ "t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+
+ read = TIFFReadEncodedTile(
+ input,
+ tile,
+ (tdata_t) &buffer[bufferoffset],
+ t2p->tiff_datasize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding tile %u of %s",
+ tile,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+
+ } else {
+
+ if(t2p->pdf_sample == T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG){
+ septilesize=TIFFTileSize(input);
+ septilecount=TIFFNumberOfTiles(input);
+ tilesize=septilesize*t2p->tiff_samplesperpixel;
+ tilecount=septilecount/t2p->tiff_samplesperpixel;
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ samplebuffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(samplebuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ samplebufferoffset=0;
+ for(i=0;i<t2p->tiff_samplesperpixel;i++){
+ read =
+ TIFFReadEncodedTile(input,
+ tile + i*tilecount,
+ (tdata_t) &(samplebuffer[samplebufferoffset]),
+ septilesize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding tile %u of %s",
+ tile + i*tilecount,
+ TIFFFileName(input));
+ _TIFFfree(samplebuffer);
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ samplebufferoffset+=read;
+ }
+ t2p_sample_planar_separate_to_contig(
+ t2p,
+ &(buffer[bufferoffset]),
+ samplebuffer,
+ samplebufferoffset);
+ bufferoffset+=samplebufferoffset;
+ _TIFFfree(samplebuffer);
+ }
+
+ if(buffer==NULL){
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ read = TIFFReadEncodedTile(
+ input,
+ tile,
+ (tdata_t) &buffer[bufferoffset],
+ t2p->tiff_datasize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding tile %u of %s",
+ tile,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_RGBA_TO_RGB){
+ t2p->tiff_datasize=t2p_sample_rgba_to_rgb(
+ (tdata_t)buffer,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth
+ *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_RGBAA_TO_RGB){
+ t2p->tiff_datasize=t2p_sample_rgbaa_to_rgb(
+ (tdata_t)buffer,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth
+ *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_YCBCR_TO_RGB){
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for YCbCr to RGB in tile for %s",
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED){
+ t2p->tiff_datasize=t2p_sample_lab_signed_to_unsigned(
+ (tdata_t)buffer,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth
+ *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+ }
+
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile) != 0){
+ t2p_tile_collapse_left(
+ buffer,
+ TIFFTileRowSize(input),
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+
+
+ t2p_disable(output);
+ TIFFSetField(output, TIFFTAG_PHOTOMETRIC, t2p->tiff_photometric);
+ TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, t2p->tiff_bitspersample);
+ TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, t2p->tiff_samplesperpixel);
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile) == 0){
+ TIFFSetField(
+ output,
+ TIFFTAG_IMAGEWIDTH,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
+ } else {
+ TIFFSetField(
+ output,
+ TIFFTAG_IMAGEWIDTH,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
+ }
+ if(t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile) == 0){
+ TIFFSetField(
+ output,
+ TIFFTAG_IMAGELENGTH,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ TIFFSetField(
+ output,
+ TIFFTAG_ROWSPERSTRIP,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ } else {
+ TIFFSetField(
+ output,
+ TIFFTAG_IMAGELENGTH,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
+ TIFFSetField(
+ output,
+ TIFFTAG_ROWSPERSTRIP,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
+ }
+ TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(output, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+
+ switch(t2p->pdf_compression){
+ case T2P_COMPRESS_NONE:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ break;
+#ifdef CCITT_SUPPORT
+ case T2P_COMPRESS_G4:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
+ break;
+#endif
+#ifdef JPEG_SUPPORT
+ case T2P_COMPRESS_JPEG:
+ if (t2p->tiff_photometric==PHOTOMETRIC_YCBCR) {
+ uint16 hor = 0, ver = 0;
+ if (TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &hor, &ver)!=0) {
+ if (hor != 0 && ver != 0) {
+ TIFFSetField(output, TIFFTAG_YCBCRSUBSAMPLING, hor, ver);
+ }
+ }
+ if(TIFFGetField(input, TIFFTAG_REFERENCEBLACKWHITE, &xfloatp)!=0){
+ TIFFSetField(output, TIFFTAG_REFERENCEBLACKWHITE, xfloatp);
+ }
+ }
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
+ TIFFSetField(output, TIFFTAG_JPEGTABLESMODE, 0); /* JPEGTABLESMODE_NONE */
+ if(t2p->pdf_colorspace & (T2P_CS_RGB | T2P_CS_LAB)){
+ TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ if(t2p->tiff_photometric != PHOTOMETRIC_YCBCR){
+ TIFFSetField(output, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ } else {
+ TIFFSetField(output, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_GRAY){
+ (void)0;
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CMYK){
+ (void)0;
+ }
+ if(t2p->pdf_defaultcompressionquality != 0){
+ TIFFSetField(output,
+ TIFFTAG_JPEGQUALITY,
+ t2p->pdf_defaultcompressionquality);
+ }
+ break;
+#endif
+#ifdef ZIP_SUPPORT
+ case T2P_COMPRESS_ZIP:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
+ if(t2p->pdf_defaultcompressionquality%100 != 0){
+ TIFFSetField(output,
+ TIFFTAG_PREDICTOR,
+ t2p->pdf_defaultcompressionquality % 100);
+ }
+ if(t2p->pdf_defaultcompressionquality/100 != 0){
+ TIFFSetField(output,
+ TIFFTAG_ZIPQUALITY,
+ (t2p->pdf_defaultcompressionquality / 100));
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ t2p_enable(output);
+ t2p->outputwritten = 0;
+ bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t) 0, buffer,
+ TIFFStripSize(output));
+ if (buffer != NULL) {
+ _TIFFfree(buffer);
+ buffer = NULL;
+ }
+ if (bufferoffset == -1) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Error writing encoded tile to output PDF %s",
+ TIFFFileName(output));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+
+ written = t2p->outputwritten;
+
+ return(written);
+}
+
+#ifdef OJPEG_SUPPORT
+int t2p_process_ojpeg_tables(T2P* t2p, TIFF* input){
+ uint16 proc=0;
+ void* q;
+ uint32 q_length=0;
+ void* dc;
+ uint32 dc_length=0;
+ void* ac;
+ uint32 ac_length=0;
+ uint16* lp;
+ uint16* pt;
+ uint16 h_samp=1;
+ uint16 v_samp=1;
+ unsigned char* ojpegdata;
+ uint16 table_count;
+ uint32 offset_table;
+ uint32 offset_ms_l;
+ uint32 code_count;
+ uint32 i=0;
+ uint32 dest=0;
+ uint16 ri=0;
+ uint32 rows=0;
+
+ if(!TIFFGetField(input, TIFFTAG_JPEGPROC, &proc)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGProc field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(proc!=JPEGPROC_BASELINE && proc!=JPEGPROC_LOSSLESS){
+ TIFFError(TIFF2PDF_MODULE,
+ "Bad JPEGProc field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(!TIFFGetField(input, TIFFTAG_JPEGQTABLES, &q_length, &q)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGQTables field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(q_length < (64U * t2p->tiff_samplesperpixel)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Bad JPEGQTables field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(!TIFFGetField(input, TIFFTAG_JPEGDCTABLES, &dc_length, &dc)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGDCTables field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(proc==JPEGPROC_BASELINE){
+ if(!TIFFGetField(input, TIFFTAG_JPEGACTABLES, &ac_length, &ac)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGACTables field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ } else {
+ if(!TIFFGetField(input, TIFFTAG_JPEGLOSSLESSPREDICTORS, &lp)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGLosslessPredictors field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(!TIFFGetField(input, TIFFTAG_JPEGPOINTTRANSFORM, &pt)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGPointTransform field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ }
+ if(!TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &h_samp, &v_samp)){
+ h_samp=1;
+ v_samp=1;
+ }
+ if(t2p->pdf_ojpegdata != NULL){
+ _TIFFfree(t2p->pdf_ojpegdata);
+ t2p->pdf_ojpegdata=NULL;
+ }
+ t2p->pdf_ojpegdata = _TIFFmalloc(2048);
+ if(t2p->pdf_ojpegdata == NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_process_ojpeg_tables, %s",
+ 2048,
+ TIFFFileName(input));
+ return(0);
+ }
+ _TIFFmemset(t2p->pdf_ojpegdata, 0x00, 2048);
+ t2p->pdf_ojpegdatalength = 0;
+ table_count=t2p->tiff_samplesperpixel;
+ if(proc==JPEGPROC_BASELINE){
+ if(table_count>2) table_count=2;
+ }
+ ojpegdata=(unsigned char*)t2p->pdf_ojpegdata;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xd8;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ if(proc==JPEGPROC_BASELINE){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xc0;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xc3;
+ }
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=(8 + 3*t2p->tiff_samplesperpixel);
+ ojpegdata[t2p->pdf_ojpegdatalength++]=(t2p->tiff_bitspersample & 0xff);
+ if(TIFFIsTiled(input)){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength >> 8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength ) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth >> 8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth ) & 0xff;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_length >> 8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_length ) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_width >> 8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_width ) & 0xff;
+ }
+ ojpegdata[t2p->pdf_ojpegdatalength++]=(t2p->tiff_samplesperpixel & 0xff);
+ for(i=0;i<t2p->tiff_samplesperpixel;i++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=i;
+ if(i==0){
+ ojpegdata[t2p->pdf_ojpegdatalength] |= h_samp<<4 & 0xf0;;
+ ojpegdata[t2p->pdf_ojpegdatalength++] |= v_samp & 0x0f;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++]= 0x11;
+ }
+ ojpegdata[t2p->pdf_ojpegdatalength++]=i;
+ }
+ for(dest=0;dest<t2p->tiff_samplesperpixel;dest++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xdb;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x43;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=dest;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength++]),
+ &(((unsigned char*)q)[64*dest]), 64);
+ t2p->pdf_ojpegdatalength+=64;
+ }
+ offset_table=0;
+ for(dest=0;dest<table_count;dest++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xc4;
+ offset_ms_l=t2p->pdf_ojpegdatalength;
+ t2p->pdf_ojpegdatalength+=2;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=dest & 0x0f;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength]),
+ &(((unsigned char*)dc)[offset_table]), 16);
+ code_count=0;
+ offset_table+=16;
+ for(i=0;i<16;i++){
+ code_count+=ojpegdata[t2p->pdf_ojpegdatalength++];
+ }
+ ojpegdata[offset_ms_l]=((19+code_count)>>8) & 0xff;
+ ojpegdata[offset_ms_l+1]=(19+code_count) & 0xff;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength]),
+ &(((unsigned char*)dc)[offset_table]), code_count);
+ offset_table+=code_count;
+ t2p->pdf_ojpegdatalength+=code_count;
+ }
+ if(proc==JPEGPROC_BASELINE){
+ offset_table=0;
+ for(dest=0;dest<table_count;dest++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xc4;
+ offset_ms_l=t2p->pdf_ojpegdatalength;
+ t2p->pdf_ojpegdatalength+=2;
+ ojpegdata[t2p->pdf_ojpegdatalength] |= 0x10;
+ ojpegdata[t2p->pdf_ojpegdatalength++] |=dest & 0x0f;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength]),
+ &(((unsigned char*)ac)[offset_table]), 16);
+ code_count=0;
+ offset_table+=16;
+ for(i=0;i<16;i++){
+ code_count+=ojpegdata[t2p->pdf_ojpegdatalength++];
+ }
+ ojpegdata[offset_ms_l]=((19+code_count)>>8) & 0xff;
+ ojpegdata[offset_ms_l+1]=(19+code_count) & 0xff;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength]),
+ &(((unsigned char*)ac)[offset_table]), code_count);
+ offset_table+=code_count;
+ t2p->pdf_ojpegdatalength+=code_count;
+ }
+ }
+ if(TIFFNumberOfStrips(input)>1){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xdd;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x04;
+ h_samp*=8;
+ v_samp*=8;
+ ri=(t2p->tiff_width+h_samp-1) / h_samp;
+ TIFFGetField(input, TIFFTAG_ROWSPERSTRIP, &rows);
+ ri*=(rows+v_samp-1)/v_samp;
+ ojpegdata[t2p->pdf_ojpegdatalength++]= (ri>>8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]= ri & 0xff;
+ }
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xda;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=(6 + 2*t2p->tiff_samplesperpixel);
+ ojpegdata[t2p->pdf_ojpegdatalength++]=t2p->tiff_samplesperpixel & 0xff;
+ for(i=0;i<t2p->tiff_samplesperpixel;i++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]= i & 0xff;
+ if(proc==JPEGPROC_BASELINE){
+ ojpegdata[t2p->pdf_ojpegdatalength] |=
+ ( ( (i>(table_count-1U)) ? (table_count-1U) : i) << 4U) & 0xf0;
+ ojpegdata[t2p->pdf_ojpegdatalength++] |=
+ ( (i>(table_count-1U)) ? (table_count-1U) : i) & 0x0f;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++] = (i << 4) & 0xf0;
+ }
+ }
+ if(proc==JPEGPROC_BASELINE){
+ t2p->pdf_ojpegdatalength++;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x3f;
+ t2p->pdf_ojpegdatalength++;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++]= (lp[0] & 0xff);
+ t2p->pdf_ojpegdatalength++;
+ ojpegdata[t2p->pdf_ojpegdatalength++]= (pt[0] & 0x0f);
+ }
+
+ return(1);
+}
+#endif
+
+#ifdef JPEG_SUPPORT
+int t2p_process_jpeg_strip(
+ unsigned char* strip,
+ tsize_t* striplength,
+ unsigned char* buffer,
+ tsize_t* bufferoffset,
+ tstrip_t no,
+ uint32 height){
+
+ tsize_t i=0;
+ uint16 ri =0;
+ uint16 v_samp=1;
+ uint16 h_samp=1;
+ int j=0;
+
+ i++;
+
+ while(i<(*striplength)){
+ switch( strip[i] ){
+ case 0xd8:
+ /* SOI - start of image */
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), 2);
+ *bufferoffset+=2;
+ i+=2;
+ break;
+ case 0xc0:
+ case 0xc1:
+ case 0xc3:
+ case 0xc9:
+ case 0xca:
+ if(no==0){
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), strip[i+2]+2);
+ for(j=0;j<buffer[*bufferoffset+9];j++){
+ if( (buffer[*bufferoffset+11+(2*j)]>>4) > h_samp)
+ h_samp = (buffer[*bufferoffset+11+(2*j)]>>4);
+ if( (buffer[*bufferoffset+11+(2*j)] & 0x0f) > v_samp)
+ v_samp = (buffer[*bufferoffset+11+(2*j)] & 0x0f);
+ }
+ v_samp*=8;
+ h_samp*=8;
+ ri=((( ((uint16)(buffer[*bufferoffset+5])<<8) |
+ (uint16)(buffer[*bufferoffset+6]) )+v_samp-1)/
+ v_samp);
+ ri*=((( ((uint16)(buffer[*bufferoffset+7])<<8) |
+ (uint16)(buffer[*bufferoffset+8]) )+h_samp-1)/
+ h_samp);
+ buffer[*bufferoffset+5]=
+ (unsigned char) ((height>>8) & 0xff);
+ buffer[*bufferoffset+6]=
+ (unsigned char) (height & 0xff);
+ *bufferoffset+=strip[i+2]+2;
+ i+=strip[i+2]+2;
+
+ buffer[(*bufferoffset)++]=0xff;
+ buffer[(*bufferoffset)++]=0xdd;
+ buffer[(*bufferoffset)++]=0x00;
+ buffer[(*bufferoffset)++]=0x04;
+ buffer[(*bufferoffset)++]=(ri >> 8) & 0xff;
+ buffer[(*bufferoffset)++]= ri & 0xff;
+ } else {
+ i+=strip[i+2]+2;
+ }
+ break;
+ case 0xc4:
+ case 0xdb:
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), strip[i+2]+2);
+ *bufferoffset+=strip[i+2]+2;
+ i+=strip[i+2]+2;
+ break;
+ case 0xda:
+ if(no==0){
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), strip[i+2]+2);
+ *bufferoffset+=strip[i+2]+2;
+ i+=strip[i+2]+2;
+ } else {
+ buffer[(*bufferoffset)++]=0xff;
+ buffer[(*bufferoffset)++]=
+ (unsigned char)(0xd0 | ((no-1)%8));
+ i+=strip[i+2]+2;
+ }
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), (*striplength)-i-1);
+ *bufferoffset+=(*striplength)-i-1;
+ return(1);
+ default:
+ i+=strip[i+2]+2;
+ }
+ }
+
+
+ return(0);
+}
+#endif
+
+/*
+ This functions converts a tilewidth x tilelength buffer of samples into an edgetilewidth x
+ tilelength buffer of samples.
+*/
+void t2p_tile_collapse_left(
+ tdata_t buffer,
+ tsize_t scanwidth,
+ uint32 tilewidth,
+ uint32 edgetilewidth,
+ uint32 tilelength){
+
+ uint32 i=0;
+ tsize_t edgescanwidth=0;
+
+ edgescanwidth = (scanwidth * edgetilewidth + (tilewidth - 1))/ tilewidth;
+ for(i=i;i<tilelength;i++){
+ _TIFFmemcpy(
+ &(((char*)buffer)[edgescanwidth*i]),
+ &(((char*)buffer)[scanwidth*i]),
+ edgescanwidth);
+ }
+
+ return;
+}
+
+
+/*
+ * This function calls TIFFWriteDirectory on the output after blanking its
+ * output by replacing the read, write, and seek procedures with empty
+ * implementations, then it replaces the original implementations.
+ */
+
+void
+t2p_write_advance_directory(T2P* t2p, TIFF* output)
+{
+ t2p_disable(output);
+ if(!TIFFWriteDirectory(output)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error writing virtual directory to output PDF %s",
+ TIFFFileName(output));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ t2p_enable(output);
+ return;
+}
+
+tsize_t t2p_sample_planar_separate_to_contig(
+ T2P* t2p,
+ unsigned char* buffer,
+ unsigned char* samplebuffer,
+ tsize_t samplebuffersize){
+
+ tsize_t stride=0;
+ tsize_t i=0;
+ tsize_t j=0;
+
+ stride=samplebuffersize/t2p->tiff_samplesperpixel;
+ for(i=0;i<stride;i++){
+ for(j=0;j<t2p->tiff_samplesperpixel;j++){
+ buffer[i*t2p->tiff_samplesperpixel + j] = samplebuffer[i + j*stride];
+ }
+ }
+
+ return(samplebuffersize);
+}
+
+tsize_t t2p_sample_realize_palette(T2P* t2p, unsigned char* buffer){
+
+ uint32 sample_count=0;
+ uint16 component_count=0;
+ uint32 palette_offset=0;
+ uint32 sample_offset=0;
+ uint32 i=0;
+ uint32 j=0;
+ sample_count=t2p->tiff_width*t2p->tiff_length;
+ component_count=t2p->tiff_samplesperpixel;
+
+ for(i=sample_count;i>0;i--){
+ palette_offset=buffer[i-1] * component_count;
+ sample_offset= (i-1) * component_count;
+ for(j=0;j<component_count;j++){
+ buffer[sample_offset+j]=t2p->pdf_palette[palette_offset+j];
+ }
+ }
+
+ return(0);
+}
+
+/*
+ This functions converts in place a buffer of ABGR interleaved data
+ into RGB interleaved data, discarding A.
+*/
+
+tsize_t t2p_sample_abgr_to_rgb(tdata_t data, uint32 samplecount)
+{
+ uint32 i=0;
+ uint32 sample=0;
+
+ for(i=0;i<samplecount;i++){
+ sample=((uint32*)data)[i];
+ ((char*)data)[i*3]= (char) (sample & 0xff);
+ ((char*)data)[i*3+1]= (char) ((sample>>8) & 0xff);
+ ((char*)data)[i*3+2]= (char) ((sample>>16) & 0xff);
+ }
+
+ return(i*3);
+}
+
+/*
+ * This functions converts in place a buffer of RGBA interleaved data
+ * into RGB interleaved data, discarding A.
+ */
+
+tsize_t
+t2p_sample_rgbaa_to_rgb(tdata_t data, uint32 samplecount)
+{
+ uint32 i;
+
+ for(i = 0; i < samplecount; i++)
+ memcpy((uint8*)data + i * 3, (uint8*)data + i * 4, 3);
+
+ return(i * 3);
+}
+
+/*
+ * This functions converts in place a buffer of RGBA interleaved data
+ * into RGB interleaved data, adding 255-A to each component sample.
+ */
+
+tsize_t
+t2p_sample_rgba_to_rgb(tdata_t data, uint32 samplecount)
+{
+ uint32 i = 0;
+ uint32 sample = 0;
+ uint8 alpha = 0;
+
+ for (i = 0; i < samplecount; i++) {
+ sample=((uint32*)data)[i];
+ alpha=(uint8)((255 - (sample & 0xff)));
+ ((uint8 *)data)[i * 3] = (uint8) ((sample >> 24) & 0xff) + alpha;
+ ((uint8 *)data)[i * 3 + 1] = (uint8) ((sample >> 16) & 0xff) + alpha;
+ ((uint8 *)data)[i * 3 + 2] = (uint8) ((sample >> 8) & 0xff) + alpha;
+
+ }
+
+ return (i * 3);
+}
+
+/*
+ This function converts the a and b samples of Lab data from signed
+ to unsigned.
+*/
+
+tsize_t t2p_sample_lab_signed_to_unsigned(tdata_t buffer, uint32 samplecount){
+
+ uint32 i=0;
+
+ for(i=0;i<samplecount;i++){
+ if( (((unsigned char*)buffer)[(i*3)+1] & 0x80) !=0){
+ ((unsigned char*)buffer)[(i*3)+1] =
+ (unsigned char)(0x80 + ((char*)buffer)[(i*3)+1]);
+ } else {
+ ((unsigned char*)buffer)[(i*3)+1] |= 0x80;
+ }
+ if( (((unsigned char*)buffer)[(i*3)+2] & 0x80) !=0){
+ ((unsigned char*)buffer)[(i*3)+2] =
+ (unsigned char)(0x80 + ((char*)buffer)[(i*3)+2]);
+ } else {
+ ((unsigned char*)buffer)[(i*3)+2] |= 0x80;
+ }
+ }
+
+ return(samplecount*3);
+}
+
+/*
+ This function writes the PDF header to output.
+*/
+
+tsize_t t2p_write_pdf_header(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ buflen=sprintf(buffer, "%%PDF-%u.%u ", t2p->pdf_majorversion&0xff, t2p->pdf_minorversion&0xff);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t)"\n%\342\343\317\323\n", 7);
+
+ return(written);
+}
+
+/*
+ This function writes the beginning of a PDF object to output.
+*/
+
+tsize_t t2p_write_pdf_obj_start(uint32 number, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ buflen=sprintf(buffer, "%lu", (unsigned long)number);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen );
+ written += t2pWriteFile(output, (tdata_t) " 0 obj\n", 7);
+
+ return(written);
+}
+
+/*
+ This function writes the end of a PDF object to output.
+*/
+
+tsize_t t2p_write_pdf_obj_end(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) "endobj\n", 7);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF name object to output.
+*/
+
+tsize_t t2p_write_pdf_name(unsigned char* name, TIFF* output){
+
+ tsize_t written=0;
+ uint32 i=0;
+ char buffer[64];
+ uint16 nextchar=0;
+ uint32 namelen=0;
+
+ namelen = strlen((char *)name);
+ if (namelen>126) {
+ namelen=126;
+ }
+ written += t2pWriteFile(output, (tdata_t) "/", 1);
+ for (i=0;i<namelen;i++){
+ if ( ((unsigned char)name[i]) < 0x21){
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ nextchar=1;
+ }
+ if ( ((unsigned char)name[i]) > 0x7E){
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ nextchar=1;
+ }
+ if (nextchar==0){
+ switch (name[i]){
+ case 0x23:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x25:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x28:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x29:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x2F:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x3C:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x3E:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x5B:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x5D:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x7B:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x7D:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ default:
+ written += t2pWriteFile(output, (tdata_t) &name[i], 1);
+ }
+ }
+ nextchar=0;
+ }
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF string object to output.
+*/
+
+tsize_t t2p_write_pdf_string(unsigned char* pdfstr, TIFF* output){
+
+ tsize_t written = 0;
+ uint32 i = 0;
+ char buffer[64];
+ uint32 len = 0;
+
+ len = strlen((char *)pdfstr);
+ written += t2pWriteFile(output, (tdata_t) "(", 1);
+ for (i=0; i<len; i++) {
+ if((pdfstr[i]&0x80) || (pdfstr[i]==127) || (pdfstr[i]<32)){
+ sprintf(buffer, "\\%.3hho", pdfstr[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 4);
+ } else {
+ switch (pdfstr[i]){
+ case 0x08:
+ written += t2pWriteFile(output, (tdata_t) "\\b", 2);
+ break;
+ case 0x09:
+ written += t2pWriteFile(output, (tdata_t) "\\t", 2);
+ break;
+ case 0x0A:
+ written += t2pWriteFile(output, (tdata_t) "\\n", 2);
+ break;
+ case 0x0C:
+ written += t2pWriteFile(output, (tdata_t) "\\f", 2);
+ break;
+ case 0x0D:
+ written += t2pWriteFile(output, (tdata_t) "\\r", 2);
+ break;
+ case 0x28:
+ written += t2pWriteFile(output, (tdata_t) "\\(", 2);
+ break;
+ case 0x29:
+ written += t2pWriteFile(output, (tdata_t) "\\)", 2);
+ break;
+ case 0x5C:
+ written += t2pWriteFile(output, (tdata_t) "\\\\", 2);
+ break;
+ default:
+ written += t2pWriteFile(output, (tdata_t) &pdfstr[i], 1);
+ }
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) ") ", 1);
+
+ return(written);
+}
+
+
+/*
+ This function writes a buffer of data to output.
+*/
+
+tsize_t t2p_write_pdf_stream(tdata_t buffer, tsize_t len, TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) buffer, len);
+
+ return(written);
+}
+
+/*
+ This functions writes the beginning of a PDF stream to output.
+*/
+
+tsize_t t2p_write_pdf_stream_start(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) "stream\n", 7);
+
+ return(written);
+}
+
+/*
+ This function writes the end of a PDF stream to output.
+*/
+
+tsize_t t2p_write_pdf_stream_end(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) "\nendstream\n", 11);
+
+ return(written);
+}
+
+/*
+ This function writes a stream dictionary for a PDF stream to output.
+*/
+
+tsize_t t2p_write_pdf_stream_dict(tsize_t len, uint32 number, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "/Length ", 8);
+ if(len!=0){
+ written += t2p_write_pdf_stream_length(len, output);
+ } else {
+ buflen=sprintf(buffer, "%lu", (unsigned long)number);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
+ }
+
+ return(written);
+}
+
+/*
+ This functions writes the beginning of a PDF stream dictionary to output.
+*/
+
+tsize_t t2p_write_pdf_stream_dict_start(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) "<< \n", 4);
+
+ return(written);
+}
+
+/*
+ This function writes the end of a PDF stream dictionary to output.
+*/
+
+tsize_t t2p_write_pdf_stream_dict_end(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) " >>\n", 4);
+
+ return(written);
+}
+
+/*
+ This function writes a number to output.
+*/
+
+tsize_t t2p_write_pdf_stream_length(tsize_t len, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ buflen=sprintf(buffer, "%lu", (unsigned long)len);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+
+ return(written);
+}
+
+/*
+ This function writes the PDF Catalog structure to output.
+*/
+
+tsize_t t2p_write_pdf_catalog(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output,
+ (tdata_t)"<< \n/Type /Catalog \n/Pages ",
+ 27);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_pages);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen );
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
+ if(t2p->pdf_fitwindow){
+ written += t2pWriteFile(output,
+ (tdata_t) "/ViewerPreferences <</FitWindow true>>\n",
+ 39);
+ }
+ written += t2pWriteFile(output, (tdata_t)">>\n", 3);
+
+ return(written);
+}
+
+/*
+ This function writes the PDF Info structure to output.
+*/
+
+tsize_t t2p_write_pdf_info(T2P* t2p, TIFF* input, TIFF* output){
+
+ tsize_t written = 0;
+ unsigned char* info;
+ char buffer[512];
+ int buflen = 0;
+
+ if(t2p->pdf_datetime==NULL){
+ t2p_pdf_tifftime(t2p, input);
+ }
+ if(strlen((char *)t2p->pdf_datetime) > 0){
+ written += t2pWriteFile(output, (tdata_t) "<< \n/CreationDate ", 18);
+ written += t2p_write_pdf_string(t2p->pdf_datetime, output);
+ written += t2pWriteFile(output, (tdata_t) "\n/ModDate ", 10);
+ written += t2p_write_pdf_string(t2p->pdf_datetime, output);
+ }
+ written += t2pWriteFile(output, (tdata_t) "\n/Producer ", 11);
+ _TIFFmemset((tdata_t)buffer, 0x00, sizeof(buffer));
+ buflen = sprintf(buffer, "libtiff / tiff2pdf - %d", TIFFLIB_VERSION);
+ written += t2p_write_pdf_string((unsigned char*)buffer, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ if(t2p->pdf_creator != NULL){
+ if(strlen((char *)t2p->pdf_creator)>0){
+ if(strlen((char *)t2p->pdf_creator) > 511) {
+ t2p->pdf_creator[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Creator ", 9);
+ written += t2p_write_pdf_string(t2p->pdf_creator, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ } else{
+ if( TIFFGetField(input, TIFFTAG_SOFTWARE, &info) != 0){
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Creator ", 9);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ if(t2p->pdf_author != NULL) {
+ if(strlen((char *)t2p->pdf_author) > 0) {
+ if(strlen((char *)t2p->pdf_author) > 511) {
+ t2p->pdf_author[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Author ", 8);
+ written += t2p_write_pdf_string(t2p->pdf_author, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ } else{
+ if( TIFFGetField(input, TIFFTAG_ARTIST, &info) != 0){
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Author ", 8);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ } else if ( TIFFGetField(input, TIFFTAG_COPYRIGHT, &info) != 0){
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Author ", 8);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ if(t2p->pdf_title != NULL) {
+ if(strlen((char *)t2p->pdf_title) > 0) {
+ if(strlen((char *)t2p->pdf_title) > 511) {
+ t2p->pdf_title[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Title ", 7);
+ written += t2p_write_pdf_string(t2p->pdf_title, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ } else{
+ if( TIFFGetField(input, TIFFTAG_DOCUMENTNAME, &info) != 0){
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Title ", 7);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ if(t2p->pdf_subject != NULL) {
+ if(strlen((char *)t2p->pdf_subject) > 0) {
+ if(strlen((char *)t2p->pdf_subject) > 511) {
+ t2p->pdf_subject[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Subject ", 9);
+ written += t2p_write_pdf_string(t2p->pdf_subject, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ } else {
+ if(TIFFGetField(input, TIFFTAG_IMAGEDESCRIPTION, &info) != 0) {
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Subject ", 9);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ if(t2p->pdf_keywords != NULL) {
+ if(strlen((char *)t2p->pdf_keywords) > 0) {
+ if(strlen((char *)t2p->pdf_keywords) > 511) {
+ t2p->pdf_keywords[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Keywords ", 10);
+ written += t2p_write_pdf_string(t2p->pdf_keywords, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) ">> \n", 4);
+
+ return(written);
+}
+
+/*
+ * This function fills a string of a T2P struct with the current time as a PDF
+ * date string, it is called by t2p_pdf_tifftime.
+ */
+
+void t2p_pdf_currenttime(T2P* t2p)
+{
+
+ struct tm* currenttime;
+ time_t timenow;
+
+ timenow=time(0);
+ currenttime=localtime(&timenow);
+ sprintf((char *)t2p->pdf_datetime, "D:%.4d%.2d%.2d%.2d%.2d%.2d",
+ (currenttime->tm_year+1900) % 65536,
+ (currenttime->tm_mon+1) % 256,
+ (currenttime->tm_mday) % 256,
+ (currenttime->tm_hour) % 256,
+ (currenttime->tm_min) % 256,
+ (currenttime->tm_sec) % 256);
+
+ return;
+}
+
+/*
+ * This function fills a string of a T2P struct with the date and time of a
+ * TIFF file if it exists or the current time as a PDF date string.
+ */
+
+void t2p_pdf_tifftime(T2P* t2p, TIFF* input){
+
+ char* datetime;
+
+ t2p->pdf_datetime = (unsigned char*) _TIFFmalloc(19);
+ if(t2p->pdf_datetime == NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_pdf_tiff_time", 17);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ t2p->pdf_datetime[16] = '\0';
+ if( TIFFGetField(input, TIFFTAG_DATETIME, &datetime) != 0
+ && (strlen(datetime) >= 19) ){
+ t2p->pdf_datetime[0]='D';
+ t2p->pdf_datetime[1]=':';
+ t2p->pdf_datetime[2]=datetime[0];
+ t2p->pdf_datetime[3]=datetime[1];
+ t2p->pdf_datetime[4]=datetime[2];
+ t2p->pdf_datetime[5]=datetime[3];
+ t2p->pdf_datetime[6]=datetime[5];
+ t2p->pdf_datetime[7]=datetime[6];
+ t2p->pdf_datetime[8]=datetime[8];
+ t2p->pdf_datetime[9]=datetime[9];
+ t2p->pdf_datetime[10]=datetime[11];
+ t2p->pdf_datetime[11]=datetime[12];
+ t2p->pdf_datetime[12]=datetime[14];
+ t2p->pdf_datetime[13]=datetime[15];
+ t2p->pdf_datetime[14]=datetime[17];
+ t2p->pdf_datetime[15]=datetime[18];
+ } else {
+ t2p_pdf_currenttime(t2p);
+ }
+
+ return;
+}
+
+/*
+ * This function writes a PDF Pages Tree structure to output.
+ */
+
+tsize_t t2p_write_pdf_pages(T2P* t2p, TIFF* output)
+{
+ tsize_t written=0;
+ tdir_t i=0;
+ char buffer[16];
+ int buflen=0;
+
+ int page=0;
+ written += t2pWriteFile(output,
+ (tdata_t) "<< \n/Type /Pages \n/Kids [ ", 26);
+ page = t2p->pdf_pages+1;
+ for (i=0;i<t2p->tiff_pagecount;i++){
+ buflen=sprintf(buffer, "%d", page);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ if ( ((i+1)%8)==0 ) {
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ page +=3;
+ page += t2p->tiff_pages[i].page_extra;
+ if(t2p->tiff_pages[i].page_tilecount>0){
+ page += (2 * t2p->tiff_pages[i].page_tilecount);
+ } else {
+ page +=2;
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) "] \n/Count ", 10);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%d", t2p->tiff_pagecount);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " \n>> \n", 6);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Page structure to output.
+*/
+
+tsize_t t2p_write_pdf_page(uint32 object, T2P* t2p, TIFF* output){
+
+ unsigned int i=0;
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "<<\n/Type /Page \n/Parent ", 24);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_pages);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
+ written += t2pWriteFile(output, (tdata_t) "/MediaBox [", 11);
+ buflen=sprintf(buffer, "%.4f",t2p->pdf_mediabox.x1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen=sprintf(buffer, "%.4f",t2p->pdf_mediabox.y1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen=sprintf(buffer, "%.4f",t2p->pdf_mediabox.x2);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen=sprintf(buffer, "%.4f",t2p->pdf_mediabox.y2);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "] \n", 3);
+ written += t2pWriteFile(output, (tdata_t) "/Contents ", 10);
+ buflen=sprintf(buffer, "%lu", (unsigned long)(object + 1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
+ written += t2pWriteFile(output, (tdata_t) "/Resources << \n", 15);
+ if( t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount != 0 ){
+ written += t2pWriteFile(output, (tdata_t) "/XObject <<\n", 12);
+ for(i=0;i<t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount;i++){
+ written += t2pWriteFile(output, (tdata_t) "/Im", 3);
+ buflen = sprintf(buffer, "%u", t2p->pdf_page+1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "_", 1);
+ buflen = sprintf(buffer, "%u", i+1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen = sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)(object+3+(2*i)+t2p->tiff_pages[t2p->pdf_page].page_extra));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ if(i%4==3){
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/XObject <<\n", 12);
+ written += t2pWriteFile(output, (tdata_t) "/Im", 3);
+ buflen = sprintf(buffer, "%u", t2p->pdf_page+1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen = sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)(object+3+(2*i)+t2p->tiff_pages[t2p->pdf_page].page_extra));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
+ }
+ if(t2p->tiff_transferfunctioncount != 0) {
+ written += t2pWriteFile(output, (tdata_t) "/ExtGState <<", 13);
+ t2pWriteFile(output, (tdata_t) "/GS1 ", 5);
+ buflen = sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)(object + 3));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ written += t2pWriteFile(output, (tdata_t) ">> \n", 4);
+ }
+ written += t2pWriteFile(output, (tdata_t) "/ProcSet [ ", 11);
+ if(t2p->pdf_colorspace == T2P_CS_BILEVEL
+ || t2p->pdf_colorspace == T2P_CS_GRAY
+ ){
+ written += t2pWriteFile(output, (tdata_t) "/ImageB ", 8);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/ImageC ", 8);
+ if(t2p->pdf_colorspace & T2P_CS_PALETTE){
+ written += t2pWriteFile(output, (tdata_t) "/ImageI ", 8);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) "]\n>>\n>>\n", 8);
+
+ return(written);
+}
+
+/*
+ This function composes the page size and image and tile locations on a page.
+*/
+
+void t2p_compose_pdf_page(T2P* t2p){
+
+ uint32 i=0;
+ uint32 i2=0;
+ T2P_TILE* tiles=NULL;
+ T2P_BOX* boxp=NULL;
+ uint32 tilecountx=0;
+ uint32 tilecounty=0;
+ uint32 tilewidth=0;
+ uint32 tilelength=0;
+ int istiled=0;
+ float f=0;
+
+ t2p->pdf_xres = t2p->tiff_xres;
+ t2p->pdf_yres = t2p->tiff_yres;
+ if(t2p->pdf_overrideres) {
+ t2p->pdf_xres = t2p->pdf_defaultxres;
+ t2p->pdf_yres = t2p->pdf_defaultyres;
+ }
+ if(t2p->pdf_xres == 0.0)
+ t2p->pdf_xres = t2p->pdf_defaultxres;
+ if(t2p->pdf_yres == 0.0)
+ t2p->pdf_yres = t2p->pdf_defaultyres;
+ if (t2p->tiff_resunit != RESUNIT_CENTIMETER /* RESUNIT_NONE and */
+ && t2p->tiff_resunit != RESUNIT_INCH) { /* other cases */
+ t2p->pdf_imagewidth = ((float)(t2p->tiff_width))/t2p->pdf_xres;
+ t2p->pdf_imagelength = ((float)(t2p->tiff_length))/t2p->pdf_yres;
+ } else {
+ t2p->pdf_imagewidth =
+ ((float)(t2p->tiff_width))*PS_UNIT_SIZE/t2p->pdf_xres;
+ t2p->pdf_imagelength =
+ ((float)(t2p->tiff_length))*PS_UNIT_SIZE/t2p->pdf_yres;
+ }
+ if(t2p->pdf_overridepagesize != 0) {
+ t2p->pdf_pagewidth = t2p->pdf_defaultpagewidth;
+ t2p->pdf_pagelength = t2p->pdf_defaultpagelength;
+ } else {
+ t2p->pdf_pagewidth = t2p->pdf_imagewidth;
+ t2p->pdf_pagelength = t2p->pdf_imagelength;
+ }
+ t2p->pdf_mediabox.x1=0.0;
+ t2p->pdf_mediabox.y1=0.0;
+ t2p->pdf_mediabox.x2=t2p->pdf_pagewidth;
+ t2p->pdf_mediabox.y2=t2p->pdf_pagelength;
+ t2p->pdf_imagebox.x1=0.0;
+ t2p->pdf_imagebox.y1=0.0;
+ t2p->pdf_imagebox.x2=t2p->pdf_imagewidth;
+ t2p->pdf_imagebox.y2=t2p->pdf_imagelength;
+ if(t2p->pdf_overridepagesize!=0){
+ t2p->pdf_imagebox.x1+=((t2p->pdf_pagewidth-t2p->pdf_imagewidth)/2.0F);
+ t2p->pdf_imagebox.y1+=((t2p->pdf_pagelength-t2p->pdf_imagelength)/2.0F);
+ t2p->pdf_imagebox.x2+=((t2p->pdf_pagewidth-t2p->pdf_imagewidth)/2.0F);
+ t2p->pdf_imagebox.y2+=((t2p->pdf_pagelength-t2p->pdf_imagelength)/2.0F);
+ }
+ if(t2p->tiff_orientation > 4){
+ f=t2p->pdf_mediabox.x2;
+ t2p->pdf_mediabox.x2=t2p->pdf_mediabox.y2;
+ t2p->pdf_mediabox.y2=f;
+ }
+ istiled=((t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount==0) ? 0 : 1;
+ if(istiled==0){
+ t2p_compose_pdf_page_orient(&(t2p->pdf_imagebox), t2p->tiff_orientation);
+ return;
+ } else {
+ tilewidth=(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilewidth;
+ tilelength=(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilelength;
+ tilecountx=(t2p->tiff_width +
+ tilewidth -1)/
+ tilewidth;
+ (t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecountx=tilecountx;
+ tilecounty=(t2p->tiff_length +
+ tilelength -1)/
+ tilelength;
+ (t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecounty=tilecounty;
+ (t2p->tiff_tiles[t2p->pdf_page]).tiles_edgetilewidth=
+ t2p->tiff_width % tilewidth;
+ (t2p->tiff_tiles[t2p->pdf_page]).tiles_edgetilelength=
+ t2p->tiff_length % tilelength;
+ tiles=(t2p->tiff_tiles[t2p->pdf_page]).tiles_tiles;
+ for(i2=0;i2<tilecounty-1;i2++){
+ for(i=0;i<tilecountx-1;i++){
+ boxp=&(tiles[i2*tilecountx+i].tile_box);
+ boxp->x1 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * i * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->x2 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * (i+1) * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->y1 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * (i2+1) * tilelength)
+ / (float)t2p->tiff_length);
+ boxp->y2 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * i2 * tilelength)
+ / (float)t2p->tiff_length);
+ }
+ boxp=&(tiles[i2*tilecountx+i].tile_box);
+ boxp->x1 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * i * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->x2 = t2p->pdf_imagebox.x2;
+ boxp->y1 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * (i2+1) * tilelength)
+ / (float)t2p->tiff_length);
+ boxp->y2 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * i2 * tilelength)
+ / (float)t2p->tiff_length);
+ }
+ for(i=0;i<tilecountx-1;i++){
+ boxp=&(tiles[i2*tilecountx+i].tile_box);
+ boxp->x1 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * i * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->x2 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * (i+1) * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->y1 = t2p->pdf_imagebox.y1;
+ boxp->y2 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * i2 * tilelength)
+ / (float)t2p->tiff_length);
+ }
+ boxp=&(tiles[i2*tilecountx+i].tile_box);
+ boxp->x1 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * i * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->x2 = t2p->pdf_imagebox.x2;
+ boxp->y1 = t2p->pdf_imagebox.y1;
+ boxp->y2 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * i2 * tilelength)
+ / (float)t2p->tiff_length);
+ }
+ if(t2p->tiff_orientation==0 || t2p->tiff_orientation==1){
+ for(i=0;i<(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount;i++){
+ t2p_compose_pdf_page_orient( &(tiles[i].tile_box) , 0);
+ }
+ return;
+ }
+ for(i=0;i<(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount;i++){
+ boxp=&(tiles[i].tile_box);
+ boxp->x1 -= t2p->pdf_imagebox.x1;
+ boxp->x2 -= t2p->pdf_imagebox.x1;
+ boxp->y1 -= t2p->pdf_imagebox.y1;
+ boxp->y2 -= t2p->pdf_imagebox.y1;
+ if(t2p->tiff_orientation==2 || t2p->tiff_orientation==3){
+ boxp->x1 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x1;
+ boxp->x2 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x2;
+ }
+ if(t2p->tiff_orientation==3 || t2p->tiff_orientation==4){
+ boxp->y1 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y1;
+ boxp->y2 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y2;
+ }
+ if(t2p->tiff_orientation==8 || t2p->tiff_orientation==5){
+ boxp->y1 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y1;
+ boxp->y2 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y2;
+ }
+ if(t2p->tiff_orientation==5 || t2p->tiff_orientation==6){
+ boxp->x1 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x1;
+ boxp->x2 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x2;
+ }
+ if(t2p->tiff_orientation > 4){
+ f=boxp->x1;
+ boxp->x1 = boxp->y1;
+ boxp->y1 = f;
+ f=boxp->x2;
+ boxp->x2 = boxp->y2;
+ boxp->y2 = f;
+ t2p_compose_pdf_page_orient_flip(boxp, t2p->tiff_orientation);
+ } else {
+ t2p_compose_pdf_page_orient(boxp, t2p->tiff_orientation);
+ }
+
+ }
+
+ return;
+}
+
+void t2p_compose_pdf_page_orient(T2P_BOX* boxp, uint16 orientation){
+
+ float m1[9];
+ float f=0.0;
+
+ if( boxp->x1 > boxp->x2){
+ f=boxp->x1;
+ boxp->x1=boxp->x2;
+ boxp->x2 = f;
+ }
+ if( boxp->y1 > boxp->y2){
+ f=boxp->y1;
+ boxp->y1=boxp->y2;
+ boxp->y2 = f;
+ }
+ boxp->mat[0]=m1[0]=boxp->x2-boxp->x1;
+ boxp->mat[1]=m1[1]=0.0;
+ boxp->mat[2]=m1[2]=0.0;
+ boxp->mat[3]=m1[3]=0.0;
+ boxp->mat[4]=m1[4]=boxp->y2-boxp->y1;
+ boxp->mat[5]=m1[5]=0.0;
+ boxp->mat[6]=m1[6]=boxp->x1;
+ boxp->mat[7]=m1[7]=boxp->y1;
+ boxp->mat[8]=m1[8]=1.0;
+ switch(orientation){
+ case 0:
+ case 1:
+ break;
+ case 2:
+ boxp->mat[0]=0.0F-m1[0];
+ boxp->mat[6]+=m1[0];
+ break;
+ case 3:
+ boxp->mat[0]=0.0F-m1[0];
+ boxp->mat[4]=0.0F-m1[4];
+ boxp->mat[6]+=m1[0];
+ boxp->mat[7]+=m1[4];
+ break;
+ case 4:
+ boxp->mat[4]=0.0F-m1[4];
+ boxp->mat[7]+=m1[4];
+ break;
+ case 5:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=0.0F-m1[0];
+ boxp->mat[3]=0.0F-m1[4];
+ boxp->mat[4]=0.0F;
+ boxp->mat[6]+=m1[4];
+ boxp->mat[7]+=m1[0];
+ break;
+ case 6:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=0.0F-m1[0];
+ boxp->mat[3]=m1[4];
+ boxp->mat[4]=0.0F;
+ boxp->mat[7]+=m1[0];
+ break;
+ case 7:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=m1[0];
+ boxp->mat[3]=m1[4];
+ boxp->mat[4]=0.0F;
+ break;
+ case 8:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=m1[0];
+ boxp->mat[3]=0.0F-m1[4];
+ boxp->mat[4]=0.0F;
+ boxp->mat[6]+=m1[4];
+ break;
+ }
+
+ return;
+}
+
+void t2p_compose_pdf_page_orient_flip(T2P_BOX* boxp, uint16 orientation){
+
+ float m1[9];
+ float f=0.0;
+
+ if( boxp->x1 > boxp->x2){
+ f=boxp->x1;
+ boxp->x1=boxp->x2;
+ boxp->x2 = f;
+ }
+ if( boxp->y1 > boxp->y2){
+ f=boxp->y1;
+ boxp->y1=boxp->y2;
+ boxp->y2 = f;
+ }
+ boxp->mat[0]=m1[0]=boxp->x2-boxp->x1;
+ boxp->mat[1]=m1[1]=0.0F;
+ boxp->mat[2]=m1[2]=0.0F;
+ boxp->mat[3]=m1[3]=0.0F;
+ boxp->mat[4]=m1[4]=boxp->y2-boxp->y1;
+ boxp->mat[5]=m1[5]=0.0F;
+ boxp->mat[6]=m1[6]=boxp->x1;
+ boxp->mat[7]=m1[7]=boxp->y1;
+ boxp->mat[8]=m1[8]=1.0F;
+ switch(orientation){
+ case 5:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=0.0F-m1[4];
+ boxp->mat[3]=0.0F-m1[0];
+ boxp->mat[4]=0.0F;
+ boxp->mat[6]+=m1[0];
+ boxp->mat[7]+=m1[4];
+ break;
+ case 6:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=0.0F-m1[4];
+ boxp->mat[3]=m1[0];
+ boxp->mat[4]=0.0F;
+ boxp->mat[7]+=m1[4];
+ break;
+ case 7:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=m1[4];
+ boxp->mat[3]=m1[0];
+ boxp->mat[4]=0.0F;
+ break;
+ case 8:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=m1[4];
+ boxp->mat[3]=0.0F-m1[0];
+ boxp->mat[4]=0.0F;
+ boxp->mat[6]+=m1[0];
+ break;
+ }
+
+ return;
+}
+
+/*
+ This function writes a PDF Contents stream to output.
+*/
+
+tsize_t t2p_write_pdf_page_content_stream(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ ttile_t i=0;
+ char buffer[512];
+ int buflen=0;
+ T2P_BOX box;
+
+ if(t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount>0){
+ for(i=0;i<t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount; i++){
+ box=t2p->tiff_tiles[t2p->pdf_page].tiles_tiles[i].tile_box;
+ buflen=sprintf(buffer,
+ "q %s %.4f %.4f %.4f %.4f %.4f %.4f cm /Im%d_%ld Do Q\n",
+ t2p->tiff_transferfunctioncount?"/GS1 gs ":"",
+ box.mat[0],
+ box.mat[1],
+ box.mat[3],
+ box.mat[4],
+ box.mat[6],
+ box.mat[7],
+ t2p->pdf_page + 1,
+ (long)(i + 1));
+ written += t2p_write_pdf_stream(buffer, buflen, output);
+ }
+ } else {
+ box=t2p->pdf_imagebox;
+ buflen=sprintf(buffer,
+ "q %s %.4f %.4f %.4f %.4f %.4f %.4f cm /Im%d Do Q\n",
+ t2p->tiff_transferfunctioncount?"/GS1 gs ":"",
+ box.mat[0],
+ box.mat[1],
+ box.mat[3],
+ box.mat[4],
+ box.mat[6],
+ box.mat[7],
+ t2p->pdf_page+1);
+ written += t2p_write_pdf_stream(buffer, buflen, output);
+ }
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject stream dictionary to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_stream_dict(ttile_t tile,
+ T2P* t2p,
+ TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2p_write_pdf_stream_dict(0, t2p->pdf_xrefcount+1, output);
+ written += t2pWriteFile(output,
+ (tdata_t) "/Type /XObject \n/Subtype /Image \n/Name /Im",
+ 42);
+ buflen=sprintf(buffer, "%u", t2p->pdf_page+1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ if(tile != 0){
+ written += t2pWriteFile(output, (tdata_t) "_", 1);
+ buflen=sprintf(buffer, "%lu", (unsigned long)tile);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ }
+ written += t2pWriteFile(output, (tdata_t) "\n/Width ", 8);
+ _TIFFmemset((tdata_t)buffer, 0x00, 16);
+ if(tile==0){
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->tiff_width);
+ } else {
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile-1)!=0){
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
+ } else {
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "\n/Height ", 9);
+ _TIFFmemset((tdata_t)buffer, 0x00, 16);
+ if(tile==0){
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->tiff_length);
+ } else {
+ if(t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile-1)!=0){
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
+ } else {
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "\n/BitsPerComponent ", 19);
+ _TIFFmemset((tdata_t)buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%u", t2p->tiff_bitspersample);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "\n/ColorSpace ", 13);
+ written += t2p_write_pdf_xobject_cs(t2p, output);
+ if (t2p->pdf_image_interpolate)
+ written += t2pWriteFile(output,
+ (tdata_t) "\n/Interpolate true", 18);
+ if( (t2p->pdf_switchdecode != 0)
+#ifdef CCITT_SUPPORT
+ && ! (t2p->pdf_colorspace == T2P_CS_BILEVEL
+ && t2p->pdf_compression == T2P_COMPRESS_G4)
+#endif
+ ){
+ written += t2p_write_pdf_xobject_decode(t2p, output);
+ }
+ written += t2p_write_pdf_xobject_stream_filter(tile, t2p, output);
+
+ return(written);
+}
+
+/*
+ * This function writes a PDF Image XObject Colorspace name to output.
+ */
+
+
+tsize_t t2p_write_pdf_xobject_cs(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[128];
+ int buflen=0;
+
+ float X_W=1.0;
+ float Y_W=1.0;
+ float Z_W=1.0;
+
+ if( (t2p->pdf_colorspace & T2P_CS_ICCBASED) != 0){
+ written += t2p_write_pdf_xobject_icccs(t2p, output);
+ return(written);
+ }
+ if( (t2p->pdf_colorspace & T2P_CS_PALETTE) != 0){
+ written += t2pWriteFile(output, (tdata_t) "[ /Indexed ", 11);
+ t2p->pdf_colorspace ^= T2P_CS_PALETTE;
+ written += t2p_write_pdf_xobject_cs(t2p, output);
+ t2p->pdf_colorspace |= T2P_CS_PALETTE;
+ buflen=sprintf(buffer, "%u", (0x0001 << t2p->tiff_bitspersample)-1 );
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_palettecs );
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ]\n", 7);
+ return(written);
+ }
+ if(t2p->pdf_colorspace & T2P_CS_BILEVEL){
+ written += t2pWriteFile(output, (tdata_t) "/DeviceGray \n", 13);
+ }
+ if(t2p->pdf_colorspace & T2P_CS_GRAY){
+ if(t2p->pdf_colorspace & T2P_CS_CALGRAY){
+ written += t2p_write_pdf_xobject_calcs(t2p, output);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/DeviceGray \n", 13);
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_RGB){
+ if(t2p->pdf_colorspace & T2P_CS_CALRGB){
+ written += t2p_write_pdf_xobject_calcs(t2p, output);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/DeviceRGB \n", 12);
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CMYK){
+ written += t2pWriteFile(output, (tdata_t) "/DeviceCMYK \n", 13);
+ }
+ if(t2p->pdf_colorspace & T2P_CS_LAB){
+ written += t2pWriteFile(output, (tdata_t) "[/Lab << \n", 10);
+ written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
+ X_W = t2p->tiff_whitechromaticities[0];
+ Y_W = t2p->tiff_whitechromaticities[1];
+ Z_W = 1.0F - (X_W + Y_W);
+ X_W /= Y_W;
+ Z_W /= Y_W;
+ Y_W = 1.0F;
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f] \n", X_W, Y_W, Z_W);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ X_W = 0.3457F; /* 0.3127F; */ /* D50, commented D65 */
+ Y_W = 0.3585F; /* 0.3290F; */
+ Z_W = 1.0F - (X_W + Y_W);
+ X_W /= Y_W;
+ Z_W /= Y_W;
+ Y_W = 1.0F;
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f] \n", X_W, Y_W, Z_W);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Range ", 7);
+ buflen=sprintf(buffer, "[%d %d %d %d] \n",
+ t2p->pdf_labrange[0],
+ t2p->pdf_labrange[1],
+ t2p->pdf_labrange[2],
+ t2p->pdf_labrange[3]);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) ">>] \n", 5);
+
+ }
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_transfer(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "<< /Type /ExtGState \n/TR ", 25);
+ if(t2p->tiff_transferfunctioncount == 1){
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)(t2p->pdf_xrefcount + 1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "[ ", 2);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)(t2p->pdf_xrefcount + 1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)(t2p->pdf_xrefcount + 2));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)(t2p->pdf_xrefcount + 3));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ written += t2pWriteFile(output, (tdata_t) "/Identity ] ", 12);
+ }
+
+ written += t2pWriteFile(output, (tdata_t) " >> \n", 5);
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_transfer_dict(T2P* t2p, TIFF* output, uint16 i){
+
+ tsize_t written=0;
+ char buffer[32];
+ int buflen=0;
+ (void)i; // XXX
+
+ written += t2pWriteFile(output, (tdata_t) "/FunctionType 0 \n", 17);
+ written += t2pWriteFile(output, (tdata_t) "/Domain [0.0 1.0] \n", 19);
+ written += t2pWriteFile(output, (tdata_t) "/Range [0.0 1.0] \n", 18);
+ buflen=sprintf(buffer, "/Size [%u] \n", (1<<t2p->tiff_bitspersample));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/BitsPerSample 16 \n", 19);
+ written += t2p_write_pdf_stream_dict(1<<(t2p->tiff_bitspersample+1), 0, output);
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_transfer_stream(T2P* t2p, TIFF* output, uint16 i){
+
+ tsize_t written=0;
+
+ written += t2p_write_pdf_stream(
+ t2p->tiff_transferfunction[i],
+ (1<<(t2p->tiff_bitspersample+1)),
+ output);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject Colorspace array to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_calcs(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[128];
+ int buflen=0;
+
+ float X_W=0.0;
+ float Y_W=0.0;
+ float Z_W=0.0;
+ float X_R=0.0;
+ float Y_R=0.0;
+ float Z_R=0.0;
+ float X_G=0.0;
+ float Y_G=0.0;
+ float Z_G=0.0;
+ float X_B=0.0;
+ float Y_B=0.0;
+ float Z_B=0.0;
+ float x_w=0.0;
+ float y_w=0.0;
+ float z_w=0.0;
+ float x_r=0.0;
+ float y_r=0.0;
+ float x_g=0.0;
+ float y_g=0.0;
+ float x_b=0.0;
+ float y_b=0.0;
+ float R=1.0;
+ float G=1.0;
+ float B=1.0;
+
+ written += t2pWriteFile(output, (tdata_t) "[", 1);
+ if(t2p->pdf_colorspace & T2P_CS_CALGRAY){
+ written += t2pWriteFile(output, (tdata_t) "/CalGray ", 9);
+ X_W = t2p->tiff_whitechromaticities[0];
+ Y_W = t2p->tiff_whitechromaticities[1];
+ Z_W = 1.0F - (X_W + Y_W);
+ X_W /= Y_W;
+ Z_W /= Y_W;
+ Y_W = 1.0F;
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CALRGB){
+ written += t2pWriteFile(output, (tdata_t) "/CalRGB ", 8);
+ x_w = t2p->tiff_whitechromaticities[0];
+ y_w = t2p->tiff_whitechromaticities[1];
+ x_r = t2p->tiff_primarychromaticities[0];
+ y_r = t2p->tiff_primarychromaticities[1];
+ x_g = t2p->tiff_primarychromaticities[2];
+ y_g = t2p->tiff_primarychromaticities[3];
+ x_b = t2p->tiff_primarychromaticities[4];
+ y_b = t2p->tiff_primarychromaticities[5];
+ z_w = y_w * ((x_g - x_b)*y_r - (x_r-x_b)*y_g + (x_r-x_g)*y_b);
+ Y_R = (y_r/R) * ((x_g-x_b)*y_w - (x_w-x_b)*y_g + (x_w-x_g)*y_b) / z_w;
+ X_R = Y_R * x_r / y_r;
+ Z_R = Y_R * (((1-x_r)/y_r)-1);
+ Y_G = ((0.0F-(y_g))/G) * ((x_r-x_b)*y_w - (x_w-x_b)*y_r + (x_w-x_r)*y_b) / z_w;
+ X_G = Y_G * x_g / y_g;
+ Z_G = Y_G * (((1-x_g)/y_g)-1);
+ Y_B = (y_b/B) * ((x_r-x_g)*y_w - (x_w-x_g)*y_r + (x_w-x_r)*y_g) / z_w;
+ X_B = Y_B * x_b / y_b;
+ Z_B = Y_B * (((1-x_b)/y_b)-1);
+ X_W = (X_R * R) + (X_G * G) + (X_B * B);
+ Y_W = (Y_R * R) + (Y_G * G) + (Y_B * B);
+ Z_W = (Z_R * R) + (Z_G * G) + (Z_B * B);
+ X_W /= Y_W;
+ Z_W /= Y_W;
+ Y_W = 1.0;
+ }
+ written += t2pWriteFile(output, (tdata_t) "<< \n", 4);
+ if(t2p->pdf_colorspace & T2P_CS_CALGRAY){
+ written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f] \n", X_W, Y_W, Z_W);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Gamma 2.2 \n", 12);
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CALRGB){
+ written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f] \n", X_W, Y_W, Z_W);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Matrix ", 8);
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f] \n",
+ X_R, Y_R, Z_R,
+ X_G, Y_G, Z_G,
+ X_B, Y_B, Z_B);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Gamma [2.2 2.2 2.2] \n", 22);
+ }
+ written += t2pWriteFile(output, (tdata_t) ">>] \n", 5);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject Colorspace array to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_icccs(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "[/ICCBased ", 11);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_icccs);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R] \n", 7);
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_xobject_icccs_dict(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "/N ", 3);
+ buflen=sprintf(buffer, "%u \n", t2p->tiff_samplesperpixel);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Alternate ", 11);
+ t2p->pdf_colorspace ^= T2P_CS_ICCBASED;
+ written += t2p_write_pdf_xobject_cs(t2p, output);
+ t2p->pdf_colorspace |= T2P_CS_ICCBASED;
+ written += t2p_write_pdf_stream_dict(t2p->tiff_iccprofilelength, 0, output);
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_xobject_icccs_stream(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2p_write_pdf_stream(
+ (tdata_t) t2p->tiff_iccprofile,
+ (tsize_t) t2p->tiff_iccprofilelength,
+ output);
+
+ return(written);
+}
+
+/*
+ This function writes a palette stream for an indexed color space to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_palettecs_stream(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2p_write_pdf_stream(
+ (tdata_t) t2p->pdf_palette,
+ (tsize_t) t2p->pdf_palettesize,
+ output);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject Decode array to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_decode(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ int i=0;
+
+ written += t2pWriteFile(output, (tdata_t) "/Decode [ ", 10);
+ for (i=0;i<t2p->tiff_samplesperpixel;i++){
+ written += t2pWriteFile(output, (tdata_t) "1 0 ", 4);
+ }
+ written += t2pWriteFile(output, (tdata_t) "]\n", 2);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject stream filter name and parameters to
+ output.
+*/
+
+tsize_t t2p_write_pdf_xobject_stream_filter(ttile_t tile, T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ if(t2p->pdf_compression==T2P_COMPRESS_NONE){
+ return(written);
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Filter ", 8);
+ switch(t2p->pdf_compression){
+#ifdef CCITT_SUPPORT
+ case T2P_COMPRESS_G4:
+ written += t2pWriteFile(output, (tdata_t) "/CCITTFaxDecode ", 16);
+ written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
+ written += t2pWriteFile(output, (tdata_t) "<< /K -1 ", 9);
+ if(tile==0){
+ written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)t2p->tiff_width);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)t2p->tiff_length);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ } else {
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile-1)==0){
+ written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ }
+ if(t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile-1)==0){
+ written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ }
+ }
+ if(t2p->pdf_switchdecode == 0){
+ written += t2pWriteFile(output, (tdata_t) " /BlackIs1 true ", 16);
+ }
+ written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
+ break;
+#endif
+#ifdef JPEG_SUPPORT
+ case T2P_COMPRESS_JPEG:
+ written += t2pWriteFile(output, (tdata_t) "/DCTDecode ", 11);
+
+ if(t2p->tiff_photometric != PHOTOMETRIC_YCBCR) {
+ written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
+ written += t2pWriteFile(output, (tdata_t) "<< /ColorTransform 0 >>\n", 24);
+ }
+ break;
+#endif
+#ifdef ZIP_SUPPORT
+ case T2P_COMPRESS_ZIP:
+ written += t2pWriteFile(output, (tdata_t) "/FlateDecode ", 13);
+ if(t2p->pdf_compressionquality%100){
+ written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
+ written += t2pWriteFile(output, (tdata_t) "<< /Predictor ", 14);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%u", t2p->pdf_compressionquality%100);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " /Columns ", 10);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen = sprintf(buffer, "%lu",
+ (unsigned long)t2p->tiff_width);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " /Colors ", 9);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%u", t2p->tiff_samplesperpixel);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " /BitsPerComponent ", 19);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%u", t2p->tiff_bitspersample);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return(written);
+}
+
+/*
+ This function writes a PDF xref table to output.
+*/
+
+tsize_t t2p_write_pdf_xreftable(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[21];
+ int buflen=0;
+ uint32 i=0;
+
+ written += t2pWriteFile(output, (tdata_t) "xref\n0 ", 7);
+ buflen=sprintf(buffer, "%lu", (unsigned long)(t2p->pdf_xrefcount + 1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " \n0000000000 65535 f \n", 22);
+ for (i=0;i<t2p->pdf_xrefcount;i++){
+ sprintf(buffer, "%.10lu 00000 n \n",
+ (unsigned long)t2p->pdf_xrefoffsets[i]);
+ written += t2pWriteFile(output, (tdata_t) buffer, 20);
+ }
+
+ return(written);
+}
+
+/*
+ * This function writes a PDF trailer to output.
+ */
+
+tsize_t t2p_write_pdf_trailer(T2P* t2p, TIFF* output)
+{
+
+ tsize_t written = 0;
+ char buffer[32];
+ int buflen = 0;
+ char fileidbuf[16];
+ int i = 0;
+
+ ((int*)fileidbuf)[0] = rand();
+ ((int*)fileidbuf)[1] = rand();
+ ((int*)fileidbuf)[2] = rand();
+ ((int*)fileidbuf)[3] = rand();
+ t2p->pdf_fileid = (unsigned char*)_TIFFmalloc(33);
+ if(t2p->pdf_fileid == NULL) {
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_write_pdf_trailer",
+ 33 );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ _TIFFmemset(t2p->pdf_fileid, 0x00, 33);
+ for (i = 0; i < 16; i++) {
+ sprintf((char *)t2p->pdf_fileid + 2 * i,
+ "%.2hhX", fileidbuf[i]);
+ }
+ written += t2pWriteFile(output, (tdata_t) "trailer\n<<\n/Size ", 17);
+ buflen = sprintf(buffer, "%lu", (unsigned long)(t2p->pdf_xrefcount+1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ _TIFFmemset(buffer, 0x00, 32);
+ written += t2pWriteFile(output, (tdata_t) "\n/Root ", 7);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_catalog);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ _TIFFmemset(buffer, 0x00, 32);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n/Info ", 12);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_info);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ _TIFFmemset(buffer, 0x00, 32);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n/ID[<", 11);
+ written += t2pWriteFile(output, (tdata_t) t2p->pdf_fileid, 32);
+ written += t2pWriteFile(output, (tdata_t) "><", 2);
+ written += t2pWriteFile(output, (tdata_t) t2p->pdf_fileid, 32);
+ written += t2pWriteFile(output, (tdata_t) ">]\n>>\nstartxref\n", 16);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_startxref);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ _TIFFmemset(buffer, 0x00, 32);
+ written += t2pWriteFile(output, (tdata_t) "\n%%EOF\n", 7);
+
+ return(written);
+}
+
+/*
+
+ This function writes a PDF to a file given a pointer to a TIFF.
+
+ The idea with using a TIFF* as output for a PDF file is that the file
+ can be created with TIFFClientOpen for memory-mapped use within the TIFF
+ library, and TIFFWriteEncodedStrip can be used to write compressed data to
+ the output. The output is not actually a TIFF file, it is a PDF file.
+
+ This function uses only t2pWriteFile and TIFFWriteEncodedStrip to write to
+ the output TIFF file. When libtiff would otherwise be writing data to the
+ output file, the write procedure of the TIFF structure is replaced with an
+ empty implementation.
+
+ The first argument to the function is an initialized and validated T2P
+ context struct pointer.
+
+ The second argument to the function is the TIFF* that is the input that has
+ been opened for reading and no other functions have been called upon it.
+
+ The third argument to the function is the TIFF* that is the output that has
+ been opened for writing. It has to be opened so that it hasn't written any
+ data to the output. If the output is seekable then it's OK to seek to the
+ beginning of the file. The function only writes to the output PDF and does
+ not seek. See the example usage in the main() function.
+
+ TIFF* output = TIFFOpen("output.pdf", "w");
+ assert(output != NULL);
+
+ if(output->tif_seekproc != NULL){
+ t2pSeekFile(output, (toff_t) 0, SEEK_SET);
+ }
+
+ This function returns the file size of the output PDF file. On error it
+ returns zero and the t2p->t2p_error variable is set to T2P_ERR_ERROR.
+
+ After this function completes, call t2p_free on t2p, TIFFClose on input,
+ and TIFFClose on output.
+*/
+
+tsize_t t2p_write_pdf(T2P* t2p, TIFF* input, TIFF* output){
+
+ tsize_t written=0;
+ ttile_t i2=0;
+ tsize_t streamlen=0;
+ uint16 i=0;
+
+ t2p_read_tiff_init(t2p, input);
+ if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
+ t2p->pdf_xrefoffsets= (uint32*) _TIFFmalloc(t2p->pdf_xrefcount * sizeof(uint32) );
+ if(t2p->pdf_xrefoffsets==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_write_pdf",
+ t2p->pdf_xrefcount * sizeof(uint32) );
+ return(written);
+ }
+ t2p->pdf_xrefcount=0;
+ t2p->pdf_catalog=1;
+ t2p->pdf_info=2;
+ t2p->pdf_pages=3;
+ written += t2p_write_pdf_header(t2p, output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_catalog=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_catalog(t2p, output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_info=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_info(t2p, input, output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_pages=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_pages(t2p, output);
+ written += t2p_write_pdf_obj_end(output);
+ for(t2p->pdf_page=0;t2p->pdf_page<t2p->tiff_pagecount;t2p->pdf_page++){
+ t2p_read_tiff_data(t2p, input);
+ if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_page(t2p->pdf_xrefcount, t2p, output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_stream_dict(0, t2p->pdf_xrefcount+1, output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ written += t2p_write_pdf_page_content_stream(t2p, output);
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_length(streamlen, output);
+ written += t2p_write_pdf_obj_end(output);
+ if(t2p->tiff_transferfunctioncount != 0){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_transfer(t2p, output);
+ written += t2p_write_pdf_obj_end(output);
+ for(i=0; i < t2p->tiff_transferfunctioncount; i++){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_transfer_dict(t2p, output, i);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ written += t2p_write_pdf_transfer_stream(t2p, output, i);
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ }
+ if( (t2p->pdf_colorspace & T2P_CS_PALETTE) != 0){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_palettecs=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_stream_dict(t2p->pdf_palettesize, 0, output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ written += t2p_write_pdf_xobject_palettecs_stream(t2p, output);
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ if( (t2p->pdf_colorspace & T2P_CS_ICCBASED) != 0){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_icccs=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_xobject_icccs_dict(t2p, output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ written += t2p_write_pdf_xobject_icccs_stream(t2p, output);
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ if(t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount !=0){
+ for(i2=0;i2<t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount;i2++){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_xobject_stream_dict(
+ i2+1,
+ t2p,
+ output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ t2p_read_tiff_size_tile(t2p, input, i2);
+ written += t2p_readwrite_pdf_image_tile(t2p, input, output, i2);
+ t2p_write_advance_directory(t2p, output);
+ if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_length(streamlen, output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ } else {
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_xobject_stream_dict(
+ 0,
+ t2p,
+ output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ t2p_read_tiff_size(t2p, input);
+ written += t2p_readwrite_pdf_image(t2p, input, output);
+ t2p_write_advance_directory(t2p, output);
+ if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_length(streamlen, output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ }
+ t2p->pdf_startxref = written;
+ written += t2p_write_pdf_xreftable(t2p, output);
+ written += t2p_write_pdf_trailer(t2p, output);
+ t2p_disable(output);
+
+ return(written);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiff2ps.c b/tiff/tools/tiff2ps.c
new file mode 100644
index 0000000..e16aa7f
--- /dev/null
+++ b/tiff/tools/tiff2ps.c
@@ -0,0 +1,2370 @@
+/* $Id: tiff2ps.c,v 1.35.2.4 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h> /* for atof */
+#include <math.h>
+#include <time.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+/*
+ * Revision history
+ *
+ * 2005-June-3
+ * Richard Nolde: Added support for rotations of 90, 180, 270
+ * and auto using -r <90|180|270|auto>. Auto picks the best
+ * fit for the image on the specified paper size (eg portrait
+ * or landscape) if -h or -w is specified. Rotation is in
+ * degrees counterclockwise since that is how Postscript does
+ * it. Auto rotates 90 degrees ccw to produce landscape.
+ *
+ * Added maxPageWidth option using -W flag. MaxPageHeight and
+ * MaxPageWidth are mutually exclusive since the aspect ratio
+ * cannot be maintained if you set both.
+ * Rewrote PlaceImage to allow maxPageHeight and maxPageWidth
+ * options to work with values smaller or larger than the
+ * physical paper size and still preserve the aspect ratio.
+ * This is accomplished by creating multiple pages across
+ * as well as down if need be.
+ *
+ * 2001-Mar-21
+ * I (Bruce A. Mallett) added this revision history comment ;)
+ *
+ * Fixed PS_Lvl2page() code which outputs non-ASCII85 raw
+ * data. Moved test for when to output a line break to
+ * *after* the output of a character. This just serves
+ * to fix an eye-nuisance where the first line of raw
+ * data was one character shorter than subsequent lines.
+ *
+ * Added an experimental ASCII85 encoder which can be used
+ * only when there is a single buffer of bytes to be encoded.
+ * This version is much faster at encoding a straight-line
+ * buffer of data because it can avoid alot of the loop
+ * overhead of the byte-by-bye version. To use this version
+ * you need to define EXP_ASCII85ENCODER (experimental ...).
+ *
+ * Added bug fix given by Michael Schmidt to PS_Lvl2page()
+ * in which an end-of-data marker ('>') was not being output
+ * when producing non-ASCII85 encoded PostScript Level 2
+ * data.
+ *
+ * Fixed PS_Lvl2colorspace() so that it no longer assumes that
+ * a TIFF having more than 2 planes is a CMYK. This routine
+ * no longer looks at the samples per pixel but instead looks
+ * at the "photometric" value. This change allows support of
+ * CMYK TIFFs.
+ *
+ * Modified the PostScript L2 imaging loop so as to test if
+ * the input stream is still open before attempting to do a
+ * flushfile on it. This was done because some RIPs close
+ * the stream after doing the image operation.
+ *
+ * Got rid of the realloc() being done inside a loop in the
+ * PSRawDataBW() routine. The code now walks through the
+ * byte-size array outside the loop to determine the largest
+ * size memory block that will be needed.
+ *
+ * Added "-m" switch to ask tiff2ps to, where possible, use the
+ * "imagemask" operator instead of the "image" operator.
+ *
+ * Added the "-i #" switch to allow interpolation to be disabled.
+ *
+ * Unrolled a loop or two to improve performance.
+ */
+
+/*
+ * Define EXP_ASCII85ENCODER if you want to use an experimental
+ * version of the ASCII85 encoding routine. The advantage of
+ * using this routine is that tiff2ps will convert to ASCII85
+ * encoding at between 3 and 4 times the speed as compared to
+ * using the old (non-experimental) encoder. The disadvantage
+ * is that you will be using a new (and unproven) encoding
+ * routine. So user beware, you have been warned!
+ */
+
+#define EXP_ASCII85ENCODER
+
+/*
+ * NB: this code assumes uint32 works with printf's %l[ud].
+ */
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define HORIZONTAL 1
+#define VERTICAL 2
+
+int ascii85 = FALSE; /* use ASCII85 encoding */
+int interpolate = TRUE; /* interpolate level2 image */
+int level2 = FALSE; /* generate PostScript level 2 */
+int level3 = FALSE; /* generate PostScript level 3 */
+int printAll = FALSE; /* print all images in file */
+int generateEPSF = TRUE; /* generate Encapsulated PostScript */
+int PSduplex = FALSE; /* enable duplex printing */
+int PStumble = FALSE; /* enable top edge binding */
+int PSavoiddeadzone = TRUE; /* enable avoiding printer deadzone */
+double maxPageHeight = 0; /* maximum height to select from image and print per page */
+double maxPageWidth = 0; /* maximum width to select from image and print per page */
+double splitOverlap = 0; /* amount for split pages to overlag */
+int rotate = FALSE; /* rotate image by angle 90, 180, 270 degrees */
+int rotation = 0; /* optional value for rotation angle */
+char *filename; /* input filename */
+int useImagemask = FALSE; /* Use imagemask instead of image operator */
+uint16 res_unit = 0; /* Resolution units: 2 - inches, 3 - cm */
+
+/*
+ * ASCII85 Encoding Support.
+ */
+unsigned char ascii85buf[10];
+int ascii85count;
+int ascii85breaklen;
+
+int TIFF2PS(FILE*, TIFF*, double, double, double, double, int);
+void PSpage(FILE*, TIFF*, uint32, uint32);
+void PSColorContigPreamble(FILE*, uint32, uint32, int);
+void PSColorSeparatePreamble(FILE*, uint32, uint32, int);
+void PSDataColorContig(FILE*, TIFF*, uint32, uint32, int);
+void PSDataColorSeparate(FILE*, TIFF*, uint32, uint32, int);
+void PSDataPalette(FILE*, TIFF*, uint32, uint32);
+void PSDataBW(FILE*, TIFF*, uint32, uint32);
+void PSRawDataBW(FILE*, TIFF*, uint32, uint32);
+void Ascii85Init(void);
+void Ascii85Put(unsigned char code, FILE* fd);
+void Ascii85Flush(FILE* fd);
+void PSHead(FILE*, TIFF*, uint32, uint32, double, double, double, double);
+void PSTail(FILE*, int);
+
+#if defined( EXP_ASCII85ENCODER)
+int Ascii85EncodeBlock( uint8 * ascii85_p, unsigned f_eod, const uint8 * raw_p, int raw_l );
+#endif
+
+static void usage(int);
+
+int
+main(int argc, char* argv[])
+{
+ int dirnum = -1, c, np = 0;
+ int centered = 0;
+ double bottommargin = 0;
+ double leftmargin = 0;
+ double pageWidth = 0;
+ double pageHeight = 0;
+ uint32 diroff = 0;
+ extern char *optarg;
+ extern int optind;
+ FILE* output = stdout;
+
+ while ((c = getopt(argc, argv, "b:d:h:H:W:L:i:w:l:o:O:r:acelmxyzps1238DT")) != -1)
+ switch (c) {
+ case 'b':
+ bottommargin = atof(optarg);
+ break;
+ case 'c':
+ centered = 1;
+ break;
+ case 'd':
+ dirnum = atoi(optarg);
+ break;
+ case 'D':
+ PSduplex = TRUE;
+ break;
+ case 'i':
+ interpolate = atoi(optarg) ? TRUE:FALSE;
+ break;
+ case 'T':
+ PStumble = TRUE;
+ break;
+ case 'e':
+ PSavoiddeadzone = FALSE;
+ generateEPSF = TRUE;
+ break;
+ case 'h':
+ pageHeight = atof(optarg);
+ break;
+ case 'H':
+ maxPageHeight = atof(optarg);
+ if (pageHeight==0) pageHeight = maxPageHeight;
+ break;
+ case 'W':
+ maxPageWidth = atof(optarg);
+ if (pageWidth==0) pageWidth = maxPageWidth;
+ break;
+ case 'L':
+ splitOverlap = atof(optarg);
+ break;
+ case 'm':
+ useImagemask = TRUE;
+ break;
+ case 'o':
+ diroff = (uint32) strtoul(optarg, NULL, 0);
+ break;
+ case 'O': /* XXX too bad -o is already taken */
+ output = fopen(optarg, "w");
+ if (output == NULL) {
+ fprintf(stderr,
+ "%s: %s: Cannot open output file.\n",
+ argv[0], optarg);
+ exit(-2);
+ }
+ break;
+ case 'l':
+ leftmargin = atof(optarg);
+ break;
+ case 'a':
+ printAll = TRUE;
+ /* fall thru... */
+ case 'p':
+ generateEPSF = FALSE;
+ break;
+ case 'r':
+ rotate = TRUE;
+ if (strcmp (optarg, "auto") == 0)
+ rotation = 0;
+ else
+ rotation = atoi(optarg);
+ switch (rotation)
+ {
+ case 0:
+ case 90:
+ case 180:
+ case 270:
+ break;
+ default:
+ fprintf (stderr, "Rotation angle must be 90, 180, 270 (degrees ccw) or auto\n");
+ exit (-2);
+ }
+ break;
+ case 's':
+ printAll = FALSE;
+ break;
+ case 'w':
+ pageWidth = atof(optarg);
+ break;
+ case 'z':
+ PSavoiddeadzone = FALSE;
+ break;
+ case '1':
+ level2 = FALSE;
+ level3 = FALSE;
+ ascii85 = FALSE;
+ break;
+ case '2':
+ level2 = TRUE;
+ ascii85 = TRUE; /* default to yes */
+ break;
+ case '3':
+ level3 = TRUE;
+ ascii85 = TRUE; /* default to yes */
+ break;
+ case '8':
+ ascii85 = FALSE;
+ break;
+ case 'x':
+ res_unit = RESUNIT_CENTIMETER;
+ break;
+ case 'y':
+ res_unit = RESUNIT_INCH;
+ break;
+ case '?':
+ usage(-1);
+ }
+ for (; argc - optind > 0; optind++) {
+ TIFF* tif = TIFFOpen(filename = argv[optind], "r");
+ if (tif != NULL) {
+ if (dirnum != -1
+ && !TIFFSetDirectory(tif, (tdir_t)dirnum))
+ return (-1);
+ else if (diroff != 0 &&
+ !TIFFSetSubDirectory(tif, diroff))
+ return (-1);
+ np = TIFF2PS(output, tif, pageWidth, pageHeight,
+ leftmargin, bottommargin, centered);
+ TIFFClose(tif);
+ }
+ }
+ if (np)
+ PSTail(output, np);
+ else
+ usage(-1);
+ if (output != stdout)
+ fclose(output);
+ return (0);
+}
+
+static uint16 samplesperpixel;
+static uint16 bitspersample;
+static uint16 planarconfiguration;
+static uint16 photometric;
+static uint16 compression;
+static uint16 extrasamples;
+static int alpha;
+
+static int
+checkImage(TIFF* tif)
+{
+ switch (photometric) {
+ case PHOTOMETRIC_YCBCR:
+ if ((compression == COMPRESSION_JPEG || compression == COMPRESSION_OJPEG)
+ && planarconfiguration == PLANARCONFIG_CONTIG) {
+ /* can rely on libjpeg to convert to RGB */
+ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE,
+ JPEGCOLORMODE_RGB);
+ photometric = PHOTOMETRIC_RGB;
+ } else {
+ if (level2 || level3)
+ break;
+ TIFFError(filename, "Can not handle image with %s",
+ "PhotometricInterpretation=YCbCr");
+ return (0);
+ }
+ /* fall thru... */
+ case PHOTOMETRIC_RGB:
+ if (alpha && bitspersample != 8) {
+ TIFFError(filename,
+ "Can not handle %d-bit/sample RGB image with alpha",
+ bitspersample);
+ return (0);
+ }
+ /* fall thru... */
+ case PHOTOMETRIC_SEPARATED:
+ case PHOTOMETRIC_PALETTE:
+ case PHOTOMETRIC_MINISBLACK:
+ case PHOTOMETRIC_MINISWHITE:
+ break;
+ case PHOTOMETRIC_LOGL:
+ case PHOTOMETRIC_LOGLUV:
+ if (compression != COMPRESSION_SGILOG &&
+ compression != COMPRESSION_SGILOG24) {
+ TIFFError(filename,
+ "Can not handle %s data with compression other than SGILog",
+ (photometric == PHOTOMETRIC_LOGL) ?
+ "LogL" : "LogLuv"
+ );
+ return (0);
+ }
+ /* rely on library to convert to RGB/greyscale */
+ TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
+ photometric = (photometric == PHOTOMETRIC_LOGL) ?
+ PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB;
+ bitspersample = 8;
+ break;
+ case PHOTOMETRIC_CIELAB:
+ /* fall thru... */
+ default:
+ TIFFError(filename,
+ "Can not handle image with PhotometricInterpretation=%d",
+ photometric);
+ return (0);
+ }
+ switch (bitspersample) {
+ case 1: case 2:
+ case 4: case 8:
+ case 16:
+ break;
+ default:
+ TIFFError(filename, "Can not handle %d-bit/sample image",
+ bitspersample);
+ return (0);
+ }
+ if (planarconfiguration == PLANARCONFIG_SEPARATE && extrasamples > 0)
+ TIFFWarning(filename, "Ignoring extra samples");
+ return (1);
+}
+
+#define PS_UNIT_SIZE 72.0F
+#define PSUNITS(npix,res) ((npix) * (PS_UNIT_SIZE / (res)))
+
+static char RGBcolorimage[] = "\
+/bwproc {\n\
+ rgbproc\n\
+ dup length 3 idiv string 0 3 0\n\
+ 5 -1 roll {\n\
+ add 2 1 roll 1 sub dup 0 eq {\n\
+ pop 3 idiv\n\
+ 3 -1 roll\n\
+ dup 4 -1 roll\n\
+ dup 3 1 roll\n\
+ 5 -1 roll put\n\
+ 1 add 3 0\n\
+ } { 2 1 roll } ifelse\n\
+ } forall\n\
+ pop pop pop\n\
+} def\n\
+/colorimage where {pop} {\n\
+ /colorimage {pop pop /rgbproc exch def {bwproc} image} bind def\n\
+} ifelse\n\
+";
+
+/*
+ * Adobe Photoshop requires a comment line of the form:
+ *
+ * %ImageData: <cols> <rows> <depth> <main channels> <pad channels>
+ * <block size> <1 for binary|2 for hex> "data start"
+ *
+ * It is claimed to be part of some future revision of the EPS spec.
+ */
+static void
+PhotoshopBanner(FILE* fd, uint32 w, uint32 h, int bs, int nc, char* startline)
+{
+ fprintf(fd, "%%ImageData: %ld %ld %d %d 0 %d 2 \"",
+ (long) w, (long) h, bitspersample, nc, bs);
+ fprintf(fd, startline, nc);
+ fprintf(fd, "\"\n");
+}
+
+/*
+ * pw : image width in pixels
+ * ph : image height in pixels
+ * pprw : image width in PS units (72 dpi)
+ * pprh : image height in PS units (72 dpi)
+ */
+static void
+setupPageState(TIFF* tif, uint32* pw, uint32* ph, double* pprw, double* pprh)
+{
+ float xres = 0.0F, yres = 0.0F;
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, pw);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, ph);
+ if (res_unit == 0)
+ TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &res_unit);
+ /*
+ * Calculate printable area.
+ */
+ if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres)
+ || fabs(xres) < 0.0000001)
+ xres = PS_UNIT_SIZE;
+ if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres)
+ || fabs(yres) < 0.0000001)
+ yres = PS_UNIT_SIZE;
+ switch (res_unit) {
+ case RESUNIT_CENTIMETER:
+ xres *= 2.54F, yres *= 2.54F;
+ break;
+ case RESUNIT_INCH:
+ break;
+ case RESUNIT_NONE:
+ default:
+ /*
+ * check that the resolution is not inches before scaling it
+ */
+ if (xres != PS_UNIT_SIZE || yres != PS_UNIT_SIZE)
+ xres *= PS_UNIT_SIZE, yres *= PS_UNIT_SIZE;
+ break;
+ }
+ *pprh = PSUNITS(*ph, yres);
+ *pprw = PSUNITS(*pw, xres);
+}
+
+static int
+isCCITTCompression(TIFF* tif)
+{
+ uint16 compress;
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
+ return (compress == COMPRESSION_CCITTFAX3 ||
+ compress == COMPRESSION_CCITTFAX4 ||
+ compress == COMPRESSION_CCITTRLE ||
+ compress == COMPRESSION_CCITTRLEW);
+}
+
+static tsize_t tf_bytesperrow;
+static tsize_t ps_bytesperrow;
+static tsize_t tf_rowsperstrip;
+static tsize_t tf_numberstrips;
+static char *hex = "0123456789abcdef";
+
+/*
+ * imagewidth & imageheight are 1/72 inches
+ * pagewidth & pageheight are inches
+ */
+int
+PlaceImage(TIFF *tif, FILE *fp, int *npages, uint32 w, uint32 h,
+ double pagewidth, double pageheight,
+ double imagewidth, double imageheight,
+ int splitpage, double lm, double bm, int cnt)
+{
+ int i = 0;
+ int ximages = 0;
+ int splitaxis = 0;
+ double xtran = 0;
+ double ytran = 0;
+ double xscale = 1;
+ double yscale = 1;
+ double left_margin = 0;
+ double bottom_margin = 0;
+ double left_offset = lm * PS_UNIT_SIZE;
+ double bottom_offset = bm * PS_UNIT_SIZE;
+ double splitwidth = 0;
+ double splitheight = 0;
+ double subimageheight = 0;
+ double subimagewidth = 0;
+ double overlap = 0;
+ double overlapspace = 0;
+
+ pagewidth *= PS_UNIT_SIZE;
+ pageheight *= PS_UNIT_SIZE;
+
+ splitheight = maxPageHeight * PS_UNIT_SIZE;
+ splitwidth = maxPageWidth * PS_UNIT_SIZE;
+ overlap = splitOverlap * PS_UNIT_SIZE;
+ /* These have to be mutually exclusive to maintain the aspect ratio */
+ if (splitheight != 0)
+ splitaxis = VERTICAL;
+ else {
+ if (splitwidth != 0)
+ splitaxis = HORIZONTAL;
+ else {
+ fprintf (stderr, "You must specify either a maximum page height or width\n");
+ return (0);
+ }
+ }
+
+ if (splitaxis == VERTICAL) {
+ if (imageheight <= splitheight) {
+ /* Simple case, no splitting or scaling for image height */
+ yscale = imageheight;
+ ytran = pageheight - imageheight;
+ } else { /* imageheight > splitheight */
+ subimageheight = imageheight - ((splitheight - overlap) * splitpage);
+
+ yscale = imageheight * (pageheight / splitheight);
+ ytran = pageheight - subimageheight * (pageheight / splitheight);
+
+ if (subimageheight > splitheight) {
+ splitpage++;
+ } else {
+ splitpage = 0;
+ }
+ }
+ bottom_offset += ytran / (cnt?2:1);
+ left_margin = left_offset / (cnt ? 2 : 1);
+ /*
+ * WIDTH: We can't rescale height based on width so we need to make multiple
+ * pages from each horizontal segment if the image is wider than pagewidth
+ */
+
+ ximages = ceil (imagewidth / pagewidth);
+ overlapspace = (ximages - 1) * overlap;
+ if (((imagewidth + overlapspace) * (pageheight / splitheight)) > (ximages * pagewidth)) {
+ ximages++;
+ overlapspace += overlap;
+ }
+ xscale = (imagewidth + overlapspace) * (pageheight / splitheight);
+ if (imagewidth <= pagewidth) {
+ left_offset = left_margin;
+ bottom_offset = bottom_margin;
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+ } else {
+ for (i = 0; i < ximages; i++) {
+ xtran = i * (pagewidth - ((i > 0) ? overlap : 0));
+ left_offset = -xtran + left_margin;
+
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+
+ if ( i < (ximages - 1)) {
+ PSpage(fp, tif, w, h);
+ fprintf(fp, "end\n");
+ fprintf(fp, "grestore\n");
+ fprintf(fp, "showpage\n");
+ (*npages)++;
+ fprintf(fp, "%%%%Page: %d %d\n", (*npages), (*npages));
+ fprintf(fp, "gsave\n");
+ fprintf(fp, "100 dict begin\n");
+ }
+ }
+ }
+ } else { /* splitaxis is HORIZONTAL */
+ ximages = ceil (imagewidth / splitwidth);
+ overlapspace = (ximages - 1) * overlap;
+ if (((imagewidth + overlapspace) * (pagewidth / splitwidth)) > (ximages * pagewidth)) {
+ ximages++;
+ overlapspace += overlap;
+ }
+ if (ximages == 1) {
+ /* Simple case, no splitting or scaling for image width */
+ xscale = imagewidth;
+ xtran = 0;
+ splitpage = 0;
+ } else {
+ subimagewidth = imagewidth - ((splitwidth - overlap) * splitpage);
+
+ xscale = imagewidth * (pagewidth / splitwidth);
+ xtran = imagewidth - (subimagewidth * (pagewidth / splitwidth));
+
+ splitheight = pageheight;
+ subimageheight = imageheight - ((splitheight - overlap) * splitpage);
+ yscale = (imageheight + overlapspace);
+ ytran = pageheight - subimageheight + (overlapspace * (pagewidth / splitwidth));
+
+ if (subimageheight > splitheight) {
+ splitpage++;
+ } else {
+ splitpage = 0;
+ }
+ }
+ bottom_margin = bottom_offset / (cnt ? 2 : 1);
+ bottom_offset = bottom_margin + ytran;
+ left_margin = left_offset / (cnt ? 2 : 1);
+ if (imagewidth <= pagewidth) {
+ left_offset = left_margin;
+ bottom_offset = bottom_margin;
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+ } else {
+ for (i = 0; i < ximages; i++) {
+ xtran = i * (pagewidth - ((i > 0) ? overlap : 0));
+ left_offset = left_margin - xtran;
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+ if ( i < (ximages - 1)) {
+ PSpage(fp, tif, w, h);
+ fprintf(fp, "end\n");
+ fprintf(fp, "grestore\n");
+ fprintf(fp, "showpage\n");
+ (*npages)++;
+ fprintf(fp, "%%%%Page: %d %d\n", (*npages), (*npages));
+ fprintf(fp, "gsave\n");
+ fprintf(fp, "100 dict begin\n");
+ }
+ }
+ }
+ }
+
+ if (rotate)
+ {
+ if (rotation == 180 )
+ {
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+ }
+ else
+ {
+ fprintf(fp, "%f %f translate\n", bottom_offset, left_offset);
+ fprintf(fp, "%f %f scale\n", yscale, xscale);
+ }
+ fprintf (fp, "1 1 translate %d rotate\n", rotation);
+ }
+
+ return splitpage;
+}
+
+/* returns the sequence number of the page processed */
+int
+TIFF2PS(FILE* fd, TIFF* tif,
+ double pw, double ph, double lm, double bm, int cnt)
+{
+ uint32 w = 0, h = 0;
+ float ox, oy;
+ double maxsource, maxtarget; /* Used for auto rotations */
+ double hcenter, vcenter; /* Used for centering */
+ double prw, prh; /* Original Image width and height in Postscript points */
+ double psw, psh; /* Scaled image width and height in Postscript points */
+ double xscale = 1.0, yscale = 1.0, scale = 1.0;
+ double left_offset = lm * PS_UNIT_SIZE;
+ double bottom_offset = bm * PS_UNIT_SIZE;
+ uint32 subfiletype;
+ uint16* sampleinfo;
+ static int npages = 0;
+ int split;
+
+ if (!TIFFGetField(tif, TIFFTAG_XPOSITION, &ox))
+ ox = 0;
+ if (!TIFFGetField(tif, TIFFTAG_YPOSITION, &oy))
+ oy = 0;
+ do {
+ tf_numberstrips = TIFFNumberOfStrips(tif);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP,
+ &tf_rowsperstrip);
+ setupPageState(tif, &w, &h, &prw, &prh);
+ if (pw != 0) {
+ psw = pw * PS_UNIT_SIZE;
+ if (res_unit == RESUNIT_CENTIMETER)
+ psw *= 2.54F;
+ }
+ else
+ psw = prw;
+
+ if (ph != 0) {
+ psh = ph * PS_UNIT_SIZE;
+ if (res_unit == RESUNIT_CENTIMETER)
+ psh *= 2.54F;
+ }
+ else
+ psh = prh;
+
+ /* auto rotate for best fit */
+ if (rotate && rotation == 0) {
+ maxsource = (prw >= prh) ? prw : prh;
+ maxtarget = (psw >= psh) ? psw : psh;
+ if (((maxsource == prw) && (maxtarget != psw)) ||
+ ((maxsource == prh) && (maxtarget != psh))) {
+ rotation = 90;
+ }
+ }
+
+ /* scaling depends on rotation and new page size */
+ switch (rotation) {
+ case 0:
+ case 180:
+ xscale = (psw - left_offset)/prw;
+ yscale = (psh - bottom_offset)/prh;
+ if (!npages)
+ PSHead(fd, tif, w, h, psw, psh, ox, oy);
+ break;
+ case 90:
+ case 270:
+ xscale = (psw - bottom_offset) /prh;
+ yscale = (psh - left_offset) /prw;
+ if (!npages)
+ PSHead(fd, tif, w, h, psh, psw, oy, ox);
+ break;
+ }
+ TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE,
+ &bitspersample);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL,
+ &samplesperpixel);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG,
+ &planarconfiguration);
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
+ &extrasamples, &sampleinfo);
+ alpha = (extrasamples == 1 &&
+ sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA);
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) {
+ switch (samplesperpixel - extrasamples) {
+ case 1:
+ if (isCCITTCompression(tif))
+ photometric = PHOTOMETRIC_MINISWHITE;
+ else
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 3:
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ case 4:
+ photometric = PHOTOMETRIC_SEPARATED;
+ break;
+ }
+ }
+ if (checkImage(tif)) {
+ tf_bytesperrow = TIFFScanlineSize(tif);
+ npages++;
+ fprintf(fd, "%%%%Page: %d %d\n", npages, npages);
+ if (!generateEPSF && ( level2 || level3 )) {
+ fprintf(fd,
+ "1 dict begin /PageSize [ %f %f ] def currentdict end setpagedevice\n",
+ psw, psh);
+ fputs(
+ "<<\n /Policies <<\n /PageSize 3\n >>\n>> setpagedevice\n",
+ fd);
+ }
+ fprintf(fd, "gsave\n");
+ fprintf(fd, "100 dict begin\n");
+ /* N.B. Setting maxPageHeight also sets ph if not set explicitly */
+ if (pw != 0 || ph != 0) {
+ if (maxPageHeight || maxPageWidth) { /* used -H or -W options */
+ split = PlaceImage(tif,fd,&npages,w,h,pw,ph,prw,prh,
+ 0,lm,bm,cnt);
+ while( split ) {
+ PSpage(fd, tif, w, h);
+ fprintf(fd, "end\n");
+ fprintf(fd, "grestore\n");
+ fprintf(fd, "showpage\n");
+ npages++;
+ fprintf(fd, "%%%%Page: %d %d\n",
+ npages, npages);
+ fprintf(fd, "gsave\n");
+ fprintf(fd, "100 dict begin\n");
+ split = PlaceImage(tif,fd,&npages,w,h,pw,ph,prw,prh,
+ split,lm,bm,cnt);
+ }
+ }
+ else {
+ /* NB: maintain image aspect ratio */
+ scale = (xscale < yscale) ? xscale : yscale;
+ if (scale > 1.0)
+ scale = 1.0;
+
+ /* Adjust offsets for centering */
+ if (cnt) {
+ switch (rotation) {
+ case 90:
+ case 270:
+ hcenter = (psw - prh * scale) / 2;
+ vcenter = (psh - prw * scale) / 2;
+ break;
+ case 0:
+ case 180:
+ default:
+ hcenter = (psw - prw * scale) / 2;
+ vcenter = (psh - prh * scale) / 2;
+ break;
+ }
+ }
+ else
+ hcenter = 0.0, vcenter = 0.0;
+ if (cnt)
+ fprintf (fd, "%f %f translate\n", hcenter, vcenter);
+ switch (rotation) {
+ case 0:
+ fprintf (fd, "%f %f scale\n", prw * scale, prh * scale);
+ break;
+ case 90:
+ fprintf (fd, "%f %f scale\n1 0 translate 90 rotate\n", prh * scale, prw * scale);
+ break;
+ case 180:
+ fprintf (fd, "%f %f scale\n1 1 translate 180 rotate\n", prw * scale, prh * scale);
+ break;
+ case 270:
+ fprintf (fd, "%f %f scale\n0 1 translate 270 rotate\n", prh * scale, prw * scale);
+ break;
+ default:
+ fprintf (stderr, "Unsupported angle. No rotation\n");
+ fprintf (fd, "%f %f scale\n", prw * scale, prh * scale);
+ break;
+ }
+ }
+ } else {
+ if (rotate)
+ {
+ /* Width and height have already been enchanged for 90/270 rotations */
+ switch (rotation) {
+ case 0:
+ fprintf (fd, "%f %f scale\n", prw, prh);
+ case 90:
+ fprintf (fd, "%f %f scale\n1 0 translate 90 rotate\n", prw, prh);
+ break;
+ case 180:
+ fprintf (fd, "%f %f scale\n1 1 translate 180 rotate\n", prw, prh);
+ break;
+ case 270:
+ fprintf (fd, "%f %f scale\n0 1 translate 270 rotate\n", prw, prh);
+ break;
+ default:
+ fprintf (stderr, "Unsupported angle. No rotation\n");
+ fprintf( fd, "%f %f scale\n", prw, prh);
+ break;
+ }
+ }
+ else
+ {
+ /* fprintf (stderr, "No rotation\n"); */
+ fprintf (fd, "%f %f scale\n", prw, prh);
+ }
+ }
+ PSpage(fd, tif, w, h);
+ fprintf(fd, "end\n");
+ fprintf(fd, "grestore\n");
+ fprintf(fd, "showpage\n");
+ }
+ if (generateEPSF)
+ break;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_SUBFILETYPE, &subfiletype);
+ } while (((subfiletype & FILETYPE_PAGE) || printAll) &&
+ TIFFReadDirectory(tif));
+
+ return(npages);
+}
+
+static char DuplexPreamble[] = "\
+%%BeginFeature: *Duplex True\n\
+systemdict begin\n\
+ /languagelevel where { pop languagelevel } { 1 } ifelse\n\
+ 2 ge { 1 dict dup /Duplex true put setpagedevice }\n\
+ { statusdict /setduplex known { statusdict begin setduplex true end } if\n\
+ } ifelse\n\
+end\n\
+%%EndFeature\n\
+";
+
+static char TumblePreamble[] = "\
+%%BeginFeature: *Tumble True\n\
+systemdict begin\n\
+ /languagelevel where { pop languagelevel } { 1 } ifelse\n\
+ 2 ge { 1 dict dup /Tumble true put setpagedevice }\n\
+ { statusdict /settumble known { statusdict begin true settumble end } if\n\
+ } ifelse\n\
+end\n\
+%%EndFeature\n\
+";
+
+static char AvoidDeadZonePreamble[] = "\
+gsave newpath clippath pathbbox grestore\n\
+ 4 2 roll 2 copy translate\n\
+ exch 3 1 roll sub 3 1 roll sub exch\n\
+ currentpagedevice /PageSize get aload pop\n\
+ exch 3 1 roll div 3 1 roll div abs exch abs\n\
+ 2 copy gt { exch } if pop\n\
+ dup 1 lt { dup scale } { pop } ifelse\n\
+";
+
+void
+PSHead(FILE *fd, TIFF *tif, uint32 w, uint32 h,
+ double pw, double ph, double ox, double oy)
+{
+ time_t t;
+
+ (void) tif; (void) w; (void) h;
+ t = time(0);
+ fprintf(fd, "%%!PS-Adobe-3.0%s\n", generateEPSF ? " EPSF-3.0" : "");
+ fprintf(fd, "%%%%Creator: tiff2ps\n");
+ fprintf(fd, "%%%%Title: %s\n", filename);
+ fprintf(fd, "%%%%CreationDate: %s", ctime(&t));
+ fprintf(fd, "%%%%DocumentData: Clean7Bit\n");
+ fprintf(fd, "%%%%Origin: %ld %ld\n", (long) ox, (long) oy);
+ /* NB: should use PageBoundingBox */
+ if (rotate && (rotation == 90 || rotation == 270))
+ fprintf(fd, "%%%%BoundingBox: 0 0 %ld %ld\n",
+ (long) ceil(ph), (long) ceil(pw));
+ else
+ fprintf(fd, "%%%%BoundingBox: 0 0 %ld %ld\n",
+ (long) ceil(pw), (long) ceil(ph));
+
+ fprintf(fd, "%%%%LanguageLevel: %d\n", (level3 ? 3 : (level2 ? 2 : 1)));
+ fprintf(fd, "%%%%Pages: (atend)\n");
+ fprintf(fd, "%%%%EndComments\n");
+ fprintf(fd, "%%%%BeginSetup\n");
+ if (PSduplex)
+ fprintf(fd, "%s", DuplexPreamble);
+ if (PStumble)
+ fprintf(fd, "%s", TumblePreamble);
+ if (PSavoiddeadzone && (level2 || level3))
+ fprintf(fd, "%s", AvoidDeadZonePreamble);
+ fprintf(fd, "%%%%EndSetup\n");
+}
+
+void
+PSTail(FILE *fd, int npages)
+{
+ fprintf(fd, "%%%%Trailer\n");
+ fprintf(fd, "%%%%Pages: %d\n", npages);
+ fprintf(fd, "%%%%EOF\n");
+}
+
+static int
+checkcmap(TIFF* tif, int n, uint16* r, uint16* g, uint16* b)
+{
+ (void) tif;
+ while (n-- > 0)
+ if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+ return (16);
+ TIFFWarning(filename, "Assuming 8-bit colormap");
+ return (8);
+}
+
+static void
+PS_Lvl2colorspace(FILE* fd, TIFF* tif)
+{
+ uint16 *rmap, *gmap, *bmap;
+ int i, num_colors;
+ const char * colorspace_p;
+
+ switch ( photometric )
+ {
+ case PHOTOMETRIC_SEPARATED:
+ colorspace_p = "CMYK";
+ break;
+
+ case PHOTOMETRIC_RGB:
+ colorspace_p = "RGB";
+ break;
+
+ default:
+ colorspace_p = "Gray";
+ }
+
+ /*
+ * Set up PostScript Level 2 colorspace according to
+ * section 4.8 in the PostScript refenence manual.
+ */
+ fputs("% PostScript Level 2 only.\n", fd);
+ if (photometric != PHOTOMETRIC_PALETTE) {
+ if (photometric == PHOTOMETRIC_YCBCR) {
+ /* MORE CODE HERE */
+ }
+ fprintf(fd, "/Device%s setcolorspace\n", colorspace_p );
+ return;
+ }
+
+ /*
+ * Set up an indexed/palette colorspace
+ */
+ num_colors = (1 << bitspersample);
+ if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
+ TIFFError(filename,
+ "Palette image w/o \"Colormap\" tag");
+ return;
+ }
+ if (checkcmap(tif, num_colors, rmap, gmap, bmap) == 16) {
+ /*
+ * Convert colormap to 8-bits values.
+ */
+#define CVT(x) (((x) * 255) / ((1L<<16)-1))
+ for (i = 0; i < num_colors; i++) {
+ rmap[i] = CVT(rmap[i]);
+ gmap[i] = CVT(gmap[i]);
+ bmap[i] = CVT(bmap[i]);
+ }
+#undef CVT
+ }
+ fprintf(fd, "[ /Indexed /DeviceRGB %d", num_colors - 1);
+ if (ascii85) {
+ Ascii85Init();
+ fputs("\n<~", fd);
+ ascii85breaklen -= 2;
+ } else
+ fputs(" <", fd);
+ for (i = 0; i < num_colors; i++) {
+ if (ascii85) {
+ Ascii85Put((unsigned char)rmap[i], fd);
+ Ascii85Put((unsigned char)gmap[i], fd);
+ Ascii85Put((unsigned char)bmap[i], fd);
+ } else {
+ fputs((i % 8) ? " " : "\n ", fd);
+ fprintf(fd, "%02x%02x%02x",
+ rmap[i], gmap[i], bmap[i]);
+ }
+ }
+ if (ascii85)
+ Ascii85Flush(fd);
+ else
+ fputs(">\n", fd);
+ fputs("] setcolorspace\n", fd);
+}
+
+static int
+PS_Lvl2ImageDict(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ int use_rawdata;
+ uint32 tile_width, tile_height;
+ uint16 predictor, minsamplevalue, maxsamplevalue;
+ int repeat_count;
+ char im_h[64], im_x[64], im_y[64];
+ char * imageOp = "image";
+
+ if ( useImagemask && (bitspersample == 1) )
+ imageOp = "imagemask";
+
+ (void)strcpy(im_x, "0");
+ (void)sprintf(im_y, "%lu", (long) h);
+ (void)sprintf(im_h, "%lu", (long) h);
+ tile_width = w;
+ tile_height = h;
+ if (TIFFIsTiled(tif)) {
+ repeat_count = TIFFNumberOfTiles(tif);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
+ if (tile_width > w || tile_height > h ||
+ (w % tile_width) != 0 || (h % tile_height != 0)) {
+ /*
+ * The tiles does not fit image width and height.
+ * Set up a clip rectangle for the image unit square.
+ */
+ fputs("0 0 1 1 rectclip\n", fd);
+ }
+ if (tile_width < w) {
+ fputs("/im_x 0 def\n", fd);
+ (void)strcpy(im_x, "im_x neg");
+ }
+ if (tile_height < h) {
+ fputs("/im_y 0 def\n", fd);
+ (void)sprintf(im_y, "%lu im_y sub", (unsigned long) h);
+ }
+ } else {
+ repeat_count = tf_numberstrips;
+ tile_height = tf_rowsperstrip;
+ if (tile_height > h)
+ tile_height = h;
+ if (repeat_count > 1) {
+ fputs("/im_y 0 def\n", fd);
+ fprintf(fd, "/im_h %lu def\n",
+ (unsigned long) tile_height);
+ (void)strcpy(im_h, "im_h");
+ (void)sprintf(im_y, "%lu im_y sub", (unsigned long) h);
+ }
+ }
+
+ /*
+ * Output start of exec block
+ */
+ fputs("{ % exec\n", fd);
+
+ if (repeat_count > 1)
+ fprintf(fd, "%d { %% repeat\n", repeat_count);
+
+ /*
+ * Output filter options and image dictionary.
+ */
+ if (ascii85)
+ fputs(" /im_stream currentfile /ASCII85Decode filter def\n",
+ fd);
+ fputs(" <<\n", fd);
+ fputs(" /ImageType 1\n", fd);
+ fprintf(fd, " /Width %lu\n", (unsigned long) tile_width);
+ /*
+ * Workaround for some software that may crash when last strip
+ * of image contains fewer number of scanlines than specified
+ * by the `/Height' variable. So for stripped images with multiple
+ * strips we will set `/Height' as `im_h', because one is
+ * recalculated for each strip - including the (smaller) final strip.
+ * For tiled images and images with only one strip `/Height' will
+ * contain number of scanlines in tile (or image height in case of
+ * one-stripped image).
+ */
+ if (TIFFIsTiled(tif) || tf_numberstrips == 1)
+ fprintf(fd, " /Height %lu\n", (unsigned long) tile_height);
+ else
+ fprintf(fd, " /Height im_h\n");
+
+ if (planarconfiguration == PLANARCONFIG_SEPARATE && samplesperpixel > 1)
+ fputs(" /MultipleDataSources true\n", fd);
+ fprintf(fd, " /ImageMatrix [ %lu 0 0 %ld %s %s ]\n",
+ (unsigned long) w, - (long)h, im_x, im_y);
+ fprintf(fd, " /BitsPerComponent %d\n", bitspersample);
+ fprintf(fd, " /Interpolate %s\n", interpolate ? "true" : "false");
+
+ switch (samplesperpixel - extrasamples) {
+ case 1:
+ switch (photometric) {
+ case PHOTOMETRIC_MINISBLACK:
+ fputs(" /Decode [0 1]\n", fd);
+ break;
+ case PHOTOMETRIC_MINISWHITE:
+ switch (compression) {
+ case COMPRESSION_CCITTRLE:
+ case COMPRESSION_CCITTRLEW:
+ case COMPRESSION_CCITTFAX3:
+ case COMPRESSION_CCITTFAX4:
+ /*
+ * Manage inverting with /Blackis1 flag
+ * since there migth be uncompressed parts
+ */
+ fputs(" /Decode [0 1]\n", fd);
+ break;
+ default:
+ /*
+ * ERROR...
+ */
+ fputs(" /Decode [1 0]\n", fd);
+ break;
+ }
+ break;
+ case PHOTOMETRIC_PALETTE:
+ TIFFGetFieldDefaulted(tif, TIFFTAG_MINSAMPLEVALUE,
+ &minsamplevalue);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_MAXSAMPLEVALUE,
+ &maxsamplevalue);
+ fprintf(fd, " /Decode [%u %u]\n",
+ minsamplevalue, maxsamplevalue);
+ break;
+ default:
+ /*
+ * ERROR ?
+ */
+ fputs(" /Decode [0 1]\n", fd);
+ break;
+ }
+ break;
+ case 3:
+ switch (photometric) {
+ case PHOTOMETRIC_RGB:
+ fputs(" /Decode [0 1 0 1 0 1]\n", fd);
+ break;
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ default:
+ /*
+ * ERROR??
+ */
+ fputs(" /Decode [0 1 0 1 0 1]\n", fd);
+ break;
+ }
+ break;
+ case 4:
+ /*
+ * ERROR??
+ */
+ fputs(" /Decode [0 1 0 1 0 1 0 1]\n", fd);
+ break;
+ }
+ fputs(" /DataSource", fd);
+ if (planarconfiguration == PLANARCONFIG_SEPARATE &&
+ samplesperpixel > 1)
+ fputs(" [", fd);
+ if (ascii85)
+ fputs(" im_stream", fd);
+ else
+ fputs(" currentfile /ASCIIHexDecode filter", fd);
+
+ use_rawdata = TRUE;
+ switch (compression) {
+ case COMPRESSION_NONE: /* 1: uncompressed */
+ break;
+ case COMPRESSION_CCITTRLE: /* 2: CCITT modified Huffman RLE */
+ case COMPRESSION_CCITTRLEW: /* 32771: #1 w/ word alignment */
+ case COMPRESSION_CCITTFAX3: /* 3: CCITT Group 3 fax encoding */
+ case COMPRESSION_CCITTFAX4: /* 4: CCITT Group 4 fax encoding */
+ fputs("\n\t<<\n", fd);
+ if (compression == COMPRESSION_CCITTFAX3) {
+ uint32 g3_options;
+
+ fputs("\t /EndOfLine true\n", fd);
+ fputs("\t /EndOfBlock false\n", fd);
+ if (!TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS,
+ &g3_options))
+ g3_options = 0;
+ if (g3_options & GROUP3OPT_2DENCODING)
+ fprintf(fd, "\t /K %s\n", im_h);
+ if (g3_options & GROUP3OPT_UNCOMPRESSED)
+ fputs("\t /Uncompressed true\n", fd);
+ if (g3_options & GROUP3OPT_FILLBITS)
+ fputs("\t /EncodedByteAlign true\n", fd);
+ }
+ if (compression == COMPRESSION_CCITTFAX4) {
+ uint32 g4_options;
+
+ fputs("\t /K -1\n", fd);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_GROUP4OPTIONS,
+ &g4_options);
+ if (g4_options & GROUP4OPT_UNCOMPRESSED)
+ fputs("\t /Uncompressed true\n", fd);
+ }
+ if (!(tile_width == w && w == 1728U))
+ fprintf(fd, "\t /Columns %lu\n",
+ (unsigned long) tile_width);
+ fprintf(fd, "\t /Rows %s\n", im_h);
+ if (compression == COMPRESSION_CCITTRLE ||
+ compression == COMPRESSION_CCITTRLEW) {
+ fputs("\t /EncodedByteAlign true\n", fd);
+ fputs("\t /EndOfBlock false\n", fd);
+ }
+ if (photometric == PHOTOMETRIC_MINISBLACK)
+ fputs("\t /BlackIs1 true\n", fd);
+ fprintf(fd, "\t>> /CCITTFaxDecode filter");
+ break;
+ case COMPRESSION_LZW: /* 5: Lempel-Ziv & Welch */
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PREDICTOR, &predictor);
+ if (predictor == 2) {
+ fputs("\n\t<<\n", fd);
+ fprintf(fd, "\t /Predictor %u\n", predictor);
+ fprintf(fd, "\t /Columns %lu\n",
+ (unsigned long) tile_width);
+ fprintf(fd, "\t /Colors %u\n", samplesperpixel);
+ fprintf(fd, "\t /BitsPerComponent %u\n",
+ bitspersample);
+ fputs("\t>>", fd);
+ }
+ fputs(" /LZWDecode filter", fd);
+ break;
+ case COMPRESSION_DEFLATE: /* 5: ZIP */
+ case COMPRESSION_ADOBE_DEFLATE:
+ if ( level3 ) {
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PREDICTOR, &predictor);
+ if (predictor > 1) {
+ fprintf(fd, "\t %% PostScript Level 3 only.");
+ fputs("\n\t<<\n", fd);
+ fprintf(fd, "\t /Predictor %u\n", predictor);
+ fprintf(fd, "\t /Columns %lu\n",
+ (unsigned long) tile_width);
+ fprintf(fd, "\t /Colors %u\n", samplesperpixel);
+ fprintf(fd, "\t /BitsPerComponent %u\n",
+ bitspersample);
+ fputs("\t>>", fd);
+ }
+ fputs(" /FlateDecode filter", fd);
+ } else {
+ use_rawdata = FALSE ;
+ }
+ break;
+ case COMPRESSION_PACKBITS: /* 32773: Macintosh RLE */
+ fputs(" /RunLengthDecode filter", fd);
+ use_rawdata = TRUE;
+ break;
+ case COMPRESSION_OJPEG: /* 6: !6.0 JPEG */
+ case COMPRESSION_JPEG: /* 7: %JPEG DCT compression */
+#ifdef notdef
+ /*
+ * Code not tested yet
+ */
+ fputs(" /DCTDecode filter", fd);
+ use_rawdata = TRUE;
+#else
+ use_rawdata = FALSE;
+#endif
+ break;
+ case COMPRESSION_NEXT: /* 32766: NeXT 2-bit RLE */
+ case COMPRESSION_THUNDERSCAN: /* 32809: ThunderScan RLE */
+ case COMPRESSION_PIXARFILM: /* 32908: Pixar companded 10bit LZW */
+ case COMPRESSION_JBIG: /* 34661: ISO JBIG */
+ use_rawdata = FALSE;
+ break;
+ case COMPRESSION_SGILOG: /* 34676: SGI LogL or LogLuv */
+ case COMPRESSION_SGILOG24: /* 34677: SGI 24-bit LogLuv */
+ use_rawdata = FALSE;
+ break;
+ default:
+ /*
+ * ERROR...
+ */
+ use_rawdata = FALSE;
+ break;
+ }
+ if (planarconfiguration == PLANARCONFIG_SEPARATE &&
+ samplesperpixel > 1) {
+ uint16 i;
+
+ /*
+ * NOTE: This code does not work yet...
+ */
+ for (i = 1; i < samplesperpixel; i++)
+ fputs(" dup", fd);
+ fputs(" ]", fd);
+ }
+
+ fprintf( fd, "\n >> %s\n", imageOp );
+ if (ascii85)
+ fputs(" im_stream status { im_stream flushfile } if\n", fd);
+ if (repeat_count > 1) {
+ if (tile_width < w) {
+ fprintf(fd, " /im_x im_x %lu add def\n",
+ (unsigned long) tile_width);
+ if (tile_height < h) {
+ fprintf(fd, " im_x %lu ge {\n",
+ (unsigned long) w);
+ fputs(" /im_x 0 def\n", fd);
+ fprintf(fd, " /im_y im_y %lu add def\n",
+ (unsigned long) tile_height);
+ fputs(" } if\n", fd);
+ }
+ }
+ if (tile_height < h) {
+ if (tile_width >= w) {
+ fprintf(fd, " /im_y im_y %lu add def\n",
+ (unsigned long) tile_height);
+ if (!TIFFIsTiled(tif)) {
+ fprintf(fd, " /im_h %lu im_y sub",
+ (unsigned long) h);
+ fprintf(fd, " dup %lu gt { pop",
+ (unsigned long) tile_height);
+ fprintf(fd, " %lu } if def\n",
+ (unsigned long) tile_height);
+ }
+ }
+ }
+ fputs("} repeat\n", fd);
+ }
+ /*
+ * End of exec function
+ */
+ fputs("}\n", fd);
+
+ return(use_rawdata);
+}
+
+/* Flip the byte order of buffers with 16 bit samples */
+static void
+PS_FlipBytes(unsigned char* buf, int count)
+{
+ int i;
+ unsigned char temp;
+
+ if (count <= 0 || bitspersample <= 8) {
+ return;
+ }
+
+ count--;
+
+ for (i = 0; i < count; i += 2) {
+ temp = buf[i];
+ buf[i] = buf[i + 1];
+ buf[i + 1] = temp;
+ }
+}
+
+#define MAXLINE 36
+
+int
+PS_Lvl2page(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ uint16 fillorder;
+ int use_rawdata, tiled_image, breaklen = MAXLINE;
+ uint32 chunk_no, num_chunks, *bc;
+ unsigned char *buf_data, *cp;
+ tsize_t chunk_size, byte_count;
+
+#if defined( EXP_ASCII85ENCODER )
+ int ascii85_l; /* Length, in bytes, of ascii85_p[] data */
+ uint8 * ascii85_p = 0; /* Holds ASCII85 encoded data */
+#endif
+
+ PS_Lvl2colorspace(fd, tif);
+ use_rawdata = PS_Lvl2ImageDict(fd, tif, w, h);
+
+/* See http://bugzilla.remotesensing.org/show_bug.cgi?id=80 */
+#ifdef ENABLE_BROKEN_BEGINENDDATA
+ fputs("%%BeginData:\n", fd);
+#endif
+ fputs("exec\n", fd);
+
+ tiled_image = TIFFIsTiled(tif);
+ if (tiled_image) {
+ num_chunks = TIFFNumberOfTiles(tif);
+ TIFFGetField(tif, TIFFTAG_TILEBYTECOUNTS, &bc);
+ } else {
+ num_chunks = TIFFNumberOfStrips(tif);
+ TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
+ }
+
+ if (use_rawdata) {
+ chunk_size = (tsize_t) bc[0];
+ for (chunk_no = 1; chunk_no < num_chunks; chunk_no++)
+ if ((tsize_t) bc[chunk_no] > chunk_size)
+ chunk_size = (tsize_t) bc[chunk_no];
+ } else {
+ if (tiled_image)
+ chunk_size = TIFFTileSize(tif);
+ else
+ chunk_size = TIFFStripSize(tif);
+ }
+ buf_data = (unsigned char *)_TIFFmalloc(chunk_size);
+ if (!buf_data) {
+ TIFFError(filename, "Can't alloc %u bytes for %s.",
+ chunk_size, tiled_image ? "tiles" : "strips");
+ return(FALSE);
+ }
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85 ) {
+ /*
+ * Allocate a buffer to hold the ASCII85 encoded data. Note
+ * that it is allocated with sufficient room to hold the
+ * encoded data (5*chunk_size/4) plus the EOD marker (+8)
+ * and formatting line breaks. The line breaks are more
+ * than taken care of by using 6*chunk_size/4 rather than
+ * 5*chunk_size/4.
+ */
+
+ ascii85_p = _TIFFmalloc( (chunk_size+(chunk_size/2)) + 8 );
+
+ if ( !ascii85_p ) {
+ _TIFFfree( buf_data );
+
+ TIFFError( filename, "Cannot allocate ASCII85 encoding buffer." );
+ return ( FALSE );
+ }
+ }
+#endif
+
+ TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
+ for (chunk_no = 0; chunk_no < num_chunks; chunk_no++) {
+ if (ascii85)
+ Ascii85Init();
+ else
+ breaklen = MAXLINE;
+ if (use_rawdata) {
+ if (tiled_image)
+ byte_count = TIFFReadRawTile(tif, chunk_no,
+ buf_data, chunk_size);
+ else
+ byte_count = TIFFReadRawStrip(tif, chunk_no,
+ buf_data, chunk_size);
+ if (fillorder == FILLORDER_LSB2MSB)
+ TIFFReverseBits(buf_data, byte_count);
+ } else {
+ if (tiled_image)
+ byte_count = TIFFReadEncodedTile(tif,
+ chunk_no, buf_data,
+ chunk_size);
+ else
+ byte_count = TIFFReadEncodedStrip(tif,
+ chunk_no, buf_data,
+ chunk_size);
+ }
+ if (byte_count < 0) {
+ TIFFError(filename, "Can't read %s %d.",
+ tiled_image ? "tile" : "strip", chunk_no);
+ if (ascii85)
+ Ascii85Put('\0', fd);
+ }
+ /*
+ * for 16 bits, the two bytes must be most significant
+ * byte first
+ */
+ if (bitspersample == 16 && !TIFFIsBigEndian(tif)) {
+ PS_FlipBytes(buf_data, byte_count);
+ }
+ /*
+ * For images with alpha, matte against a white background;
+ * i.e. Cback * (1 - Aimage) where Cback = 1. We will fill the
+ * lower part of the buffer with the modified values.
+ *
+ * XXX: needs better solution
+ */
+ if (alpha) {
+ int adjust, i, j = 0;
+ int ncomps = samplesperpixel - extrasamples;
+ for (i = 0; i < byte_count; i+=samplesperpixel) {
+ adjust = 255 - buf_data[i + ncomps];
+ switch (ncomps) {
+ case 1:
+ buf_data[j++] = buf_data[i] + adjust;
+ break;
+ case 2:
+ buf_data[j++] = buf_data[i] + adjust;
+ buf_data[j++] = buf_data[i+1] + adjust;
+ break;
+ case 3:
+ buf_data[j++] = buf_data[i] + adjust;
+ buf_data[j++] = buf_data[i+1] + adjust;
+ buf_data[j++] = buf_data[i+2] + adjust;
+ break;
+ }
+ }
+ byte_count -= j;
+ }
+
+ if (ascii85) {
+#if defined( EXP_ASCII85ENCODER )
+ ascii85_l = Ascii85EncodeBlock(ascii85_p, 1, buf_data, byte_count );
+
+ if ( ascii85_l > 0 )
+ fwrite( ascii85_p, ascii85_l, 1, fd );
+#else
+ for (cp = buf_data; byte_count > 0; byte_count--)
+ Ascii85Put(*cp++, fd);
+#endif
+ }
+ else
+ {
+ for (cp = buf_data; byte_count > 0; byte_count--) {
+ putc(hex[((*cp)>>4)&0xf], fd);
+ putc(hex[(*cp)&0xf], fd);
+ cp++;
+
+ if (--breaklen <= 0) {
+ putc('\n', fd);
+ breaklen = MAXLINE;
+ }
+ }
+ }
+
+ if ( !ascii85 ) {
+ if ( level2 || level3 )
+ putc( '>', fd );
+ putc('\n', fd);
+ }
+#if !defined( EXP_ASCII85ENCODER )
+ else
+ Ascii85Flush(fd);
+#endif
+ }
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85_p )
+ _TIFFfree( ascii85_p );
+#endif
+
+ _TIFFfree(buf_data);
+#ifdef ENABLE_BROKEN_BEGINENDDATA
+ fputs("%%EndData\n", fd);
+#endif
+ return(TRUE);
+}
+
+void
+PSpage(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ char * imageOp = "image";
+
+ if ( useImagemask && (bitspersample == 1) )
+ imageOp = "imagemask";
+
+ if ((level2 || level3) && PS_Lvl2page(fd, tif, w, h))
+ return;
+ ps_bytesperrow = tf_bytesperrow - (extrasamples * bitspersample / 8)*w;
+ switch (photometric) {
+ case PHOTOMETRIC_RGB:
+ if (planarconfiguration == PLANARCONFIG_CONTIG) {
+ fprintf(fd, "%s", RGBcolorimage);
+ PSColorContigPreamble(fd, w, h, 3);
+ PSDataColorContig(fd, tif, w, h, 3);
+ } else {
+ PSColorSeparatePreamble(fd, w, h, 3);
+ PSDataColorSeparate(fd, tif, w, h, 3);
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ /* XXX should emit CMYKcolorimage */
+ if (planarconfiguration == PLANARCONFIG_CONTIG) {
+ PSColorContigPreamble(fd, w, h, 4);
+ PSDataColorContig(fd, tif, w, h, 4);
+ } else {
+ PSColorSeparatePreamble(fd, w, h, 4);
+ PSDataColorSeparate(fd, tif, w, h, 4);
+ }
+ break;
+ case PHOTOMETRIC_PALETTE:
+ fprintf(fd, "%s", RGBcolorimage);
+ PhotoshopBanner(fd, w, h, 1, 3, "false 3 colorimage");
+ fprintf(fd, "/scanLine %ld string def\n",
+ (long) ps_bytesperrow * 3L);
+ fprintf(fd, "%lu %lu 8\n",
+ (unsigned long) w, (unsigned long) h);
+ fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n",
+ (unsigned long) w, (unsigned long) h, (unsigned long) h);
+ fprintf(fd, "{currentfile scanLine readhexstring pop} bind\n");
+ fprintf(fd, "false 3 colorimage\n");
+ PSDataPalette(fd, tif, w, h);
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ case PHOTOMETRIC_MINISWHITE:
+ PhotoshopBanner(fd, w, h, 1, 1, imageOp);
+ fprintf(fd, "/scanLine %ld string def\n",
+ (long) ps_bytesperrow);
+ fprintf(fd, "%lu %lu %d\n",
+ (unsigned long) w, (unsigned long) h, bitspersample);
+ fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n",
+ (unsigned long) w, (unsigned long) h, (unsigned long) h);
+ fprintf(fd,
+ "{currentfile scanLine readhexstring pop} bind\n");
+ fprintf(fd, "%s\n", imageOp);
+ PSDataBW(fd, tif, w, h);
+ break;
+ }
+ putc('\n', fd);
+}
+
+void
+PSColorContigPreamble(FILE* fd, uint32 w, uint32 h, int nc)
+{
+ ps_bytesperrow = nc * (tf_bytesperrow / samplesperpixel);
+ PhotoshopBanner(fd, w, h, 1, nc, "false %d colorimage");
+ fprintf(fd, "/line %ld string def\n", (long) ps_bytesperrow);
+ fprintf(fd, "%lu %lu %d\n",
+ (unsigned long) w, (unsigned long) h, bitspersample);
+ fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n",
+ (unsigned long) w, (unsigned long) h, (unsigned long) h);
+ fprintf(fd, "{currentfile line readhexstring pop} bind\n");
+ fprintf(fd, "false %d colorimage\n", nc);
+}
+
+void
+PSColorSeparatePreamble(FILE* fd, uint32 w, uint32 h, int nc)
+{
+ int i;
+
+ PhotoshopBanner(fd, w, h, ps_bytesperrow, nc, "true %d colorimage");
+ for (i = 0; i < nc; i++)
+ fprintf(fd, "/line%d %ld string def\n",
+ i, (long) ps_bytesperrow);
+ fprintf(fd, "%lu %lu %d\n",
+ (unsigned long) w, (unsigned long) h, bitspersample);
+ fprintf(fd, "[%lu 0 0 -%lu 0 %lu] \n",
+ (unsigned long) w, (unsigned long) h, (unsigned long) h);
+ for (i = 0; i < nc; i++)
+ fprintf(fd, "{currentfile line%d readhexstring pop}bind\n", i);
+ fprintf(fd, "true %d colorimage\n", nc);
+}
+
+#define DOBREAK(len, howmany, fd) \
+ if (((len) -= (howmany)) <= 0) { \
+ putc('\n', fd); \
+ (len) = MAXLINE-(howmany); \
+ }
+#define PUTHEX(c,fd) putc(hex[((c)>>4)&0xf],fd); putc(hex[(c)&0xf],fd)
+
+void
+PSDataColorContig(FILE* fd, TIFF* tif, uint32 w, uint32 h, int nc)
+{
+ uint32 row;
+ int breaklen = MAXLINE, cc, es = samplesperpixel - nc;
+ unsigned char *tf_buf;
+ unsigned char *cp, c;
+
+ (void) w;
+ tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for scanline buffer");
+ return;
+ }
+ for (row = 0; row < h; row++) {
+ if (TIFFReadScanline(tif, tf_buf, row, 0) < 0)
+ break;
+ cp = tf_buf;
+ /*
+ * for 16 bits, the two bytes must be most significant
+ * byte first
+ */
+ if (bitspersample == 16 && !HOST_BIGENDIAN) {
+ PS_FlipBytes(cp, tf_bytesperrow);
+ }
+ if (alpha) {
+ int adjust;
+ cc = 0;
+ for (; cc < tf_bytesperrow; cc += samplesperpixel) {
+ DOBREAK(breaklen, nc, fd);
+ /*
+ * For images with alpha, matte against
+ * a white background; i.e.
+ * Cback * (1 - Aimage)
+ * where Cback = 1.
+ */
+ adjust = 255 - cp[nc];
+ switch (nc) {
+ case 4: c = *cp++ + adjust; PUTHEX(c,fd);
+ case 3: c = *cp++ + adjust; PUTHEX(c,fd);
+ case 2: c = *cp++ + adjust; PUTHEX(c,fd);
+ case 1: c = *cp++ + adjust; PUTHEX(c,fd);
+ }
+ cp += es;
+ }
+ } else {
+ cc = 0;
+ for (; cc < tf_bytesperrow; cc += samplesperpixel) {
+ DOBREAK(breaklen, nc, fd);
+ switch (nc) {
+ case 4: c = *cp++; PUTHEX(c,fd);
+ case 3: c = *cp++; PUTHEX(c,fd);
+ case 2: c = *cp++; PUTHEX(c,fd);
+ case 1: c = *cp++; PUTHEX(c,fd);
+ }
+ cp += es;
+ }
+ }
+ }
+ _TIFFfree((char *) tf_buf);
+}
+
+void
+PSDataColorSeparate(FILE* fd, TIFF* tif, uint32 w, uint32 h, int nc)
+{
+ uint32 row;
+ int breaklen = MAXLINE, cc;
+ tsample_t s, maxs;
+ unsigned char *tf_buf;
+ unsigned char *cp, c;
+
+ (void) w;
+ tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for scanline buffer");
+ return;
+ }
+ maxs = (samplesperpixel > nc ? nc : samplesperpixel);
+ for (row = 0; row < h; row++) {
+ for (s = 0; s < maxs; s++) {
+ if (TIFFReadScanline(tif, tf_buf, row, s) < 0)
+ break;
+ for (cp = tf_buf, cc = 0; cc < tf_bytesperrow; cc++) {
+ DOBREAK(breaklen, 1, fd);
+ c = *cp++;
+ PUTHEX(c,fd);
+ }
+ }
+ }
+ _TIFFfree((char *) tf_buf);
+}
+
+#define PUTRGBHEX(c,fd) \
+ PUTHEX(rmap[c],fd); PUTHEX(gmap[c],fd); PUTHEX(bmap[c],fd)
+
+void
+PSDataPalette(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ uint16 *rmap, *gmap, *bmap;
+ uint32 row;
+ int breaklen = MAXLINE, cc, nc;
+ unsigned char *tf_buf;
+ unsigned char *cp, c;
+
+ (void) w;
+ if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
+ TIFFError(filename, "Palette image w/o \"Colormap\" tag");
+ return;
+ }
+ switch (bitspersample) {
+ case 8: case 4: case 2: case 1:
+ break;
+ default:
+ TIFFError(filename, "Depth %d not supported", bitspersample);
+ return;
+ }
+ nc = 3 * (8 / bitspersample);
+ tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for scanline buffer");
+ return;
+ }
+ if (checkcmap(tif, 1<<bitspersample, rmap, gmap, bmap) == 16) {
+ int i;
+#define CVT(x) ((unsigned short) (((x) * 255) / ((1U<<16)-1)))
+ for (i = (1<<bitspersample)-1; i >= 0; i--) {
+ rmap[i] = CVT(rmap[i]);
+ gmap[i] = CVT(gmap[i]);
+ bmap[i] = CVT(bmap[i]);
+ }
+#undef CVT
+ }
+ for (row = 0; row < h; row++) {
+ if (TIFFReadScanline(tif, tf_buf, row, 0) < 0)
+ break;
+ for (cp = tf_buf, cc = 0; cc < tf_bytesperrow; cc++) {
+ DOBREAK(breaklen, nc, fd);
+ switch (bitspersample) {
+ case 8:
+ c = *cp++; PUTRGBHEX(c, fd);
+ break;
+ case 4:
+ c = *cp++; PUTRGBHEX(c&0xf, fd);
+ c >>= 4; PUTRGBHEX(c, fd);
+ break;
+ case 2:
+ c = *cp++; PUTRGBHEX(c&0x3, fd);
+ c >>= 2; PUTRGBHEX(c&0x3, fd);
+ c >>= 2; PUTRGBHEX(c&0x3, fd);
+ c >>= 2; PUTRGBHEX(c, fd);
+ break;
+ case 1:
+ c = *cp++; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c, fd);
+ break;
+ }
+ }
+ }
+ _TIFFfree((char *) tf_buf);
+}
+
+void
+PSDataBW(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ int breaklen = MAXLINE;
+ unsigned char* tf_buf;
+ unsigned char* cp;
+ tsize_t stripsize = TIFFStripSize(tif);
+ tstrip_t s;
+
+#if defined( EXP_ASCII85ENCODER )
+ int ascii85_l; /* Length, in bytes, of ascii85_p[] data */
+ uint8 *ascii85_p = 0; /* Holds ASCII85 encoded data */
+#endif
+
+ (void) w; (void) h;
+ tf_buf = (unsigned char *) _TIFFmalloc(stripsize);
+ memset(tf_buf, 0, stripsize);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for scanline buffer");
+ return;
+ }
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85 ) {
+ /*
+ * Allocate a buffer to hold the ASCII85 encoded data. Note
+ * that it is allocated with sufficient room to hold the
+ * encoded data (5*stripsize/4) plus the EOD marker (+8)
+ * and formatting line breaks. The line breaks are more
+ * than taken care of by using 6*stripsize/4 rather than
+ * 5*stripsize/4.
+ */
+
+ ascii85_p = _TIFFmalloc( (stripsize+(stripsize/2)) + 8 );
+
+ if ( !ascii85_p ) {
+ _TIFFfree( tf_buf );
+
+ TIFFError( filename, "Cannot allocate ASCII85 encoding buffer." );
+ return;
+ }
+ }
+#endif
+
+ if (ascii85)
+ Ascii85Init();
+
+ for (s = 0; s < TIFFNumberOfStrips(tif); s++) {
+ int cc = TIFFReadEncodedStrip(tif, s, tf_buf, stripsize);
+ if (cc < 0) {
+ TIFFError(filename, "Can't read strip");
+ break;
+ }
+ cp = tf_buf;
+ if (photometric == PHOTOMETRIC_MINISWHITE) {
+ for (cp += cc; --cp >= tf_buf;)
+ *cp = ~*cp;
+ cp++;
+ }
+ /*
+ * for 16 bits, the two bytes must be most significant
+ * byte first
+ */
+ if (bitspersample == 16 && !HOST_BIGENDIAN) {
+ PS_FlipBytes(cp, cc);
+ }
+ if (ascii85) {
+#if defined( EXP_ASCII85ENCODER )
+ if (alpha) {
+ int adjust, i;
+ for (i = 0; i < cc; i+=2) {
+ adjust = 255 - cp[i + 1];
+ cp[i / 2] = cp[i] + adjust;
+ }
+ cc /= 2;
+ }
+
+ ascii85_l = Ascii85EncodeBlock( ascii85_p, 1, cp, cc );
+
+ if ( ascii85_l > 0 )
+ fwrite( ascii85_p, ascii85_l, 1, fd );
+#else
+ while (cc-- > 0)
+ Ascii85Put(*cp++, fd);
+#endif /* EXP_ASCII85_ENCODER */
+ } else {
+ unsigned char c;
+
+ if (alpha) {
+ int adjust;
+ while (cc-- > 0) {
+ DOBREAK(breaklen, 1, fd);
+ /*
+ * For images with alpha, matte against
+ * a white background; i.e.
+ * Cback * (1 - Aimage)
+ * where Cback = 1.
+ */
+ adjust = 255 - cp[1];
+ c = *cp++ + adjust; PUTHEX(c,fd);
+ cp++, cc--;
+ }
+ } else {
+ while (cc-- > 0) {
+ c = *cp++;
+ DOBREAK(breaklen, 1, fd);
+ PUTHEX(c, fd);
+ }
+ }
+ }
+ }
+
+ if ( !ascii85 )
+ {
+ if ( level2 || level3)
+ fputs(">\n", fd);
+ }
+#if !defined( EXP_ASCII85ENCODER )
+ else
+ Ascii85Flush(fd);
+#else
+ if ( ascii85_p )
+ _TIFFfree( ascii85_p );
+#endif
+
+ _TIFFfree(tf_buf);
+}
+
+void
+PSRawDataBW(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ uint32 *bc;
+ uint32 bufsize;
+ int breaklen = MAXLINE, cc;
+ uint16 fillorder;
+ unsigned char *tf_buf;
+ unsigned char *cp, c;
+ tstrip_t s;
+
+#if defined( EXP_ASCII85ENCODER )
+ int ascii85_l; /* Length, in bytes, of ascii85_p[] data */
+ uint8 * ascii85_p = 0; /* Holds ASCII85 encoded data */
+#endif
+
+ (void) w; (void) h;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
+ TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
+
+ /*
+ * Find largest strip:
+ */
+
+ bufsize = bc[0];
+
+ for ( s = 0; ++s < (tstrip_t)tf_numberstrips; ) {
+ if ( bc[s] > bufsize )
+ bufsize = bc[s];
+ }
+
+ tf_buf = (unsigned char*) _TIFFmalloc(bufsize);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for strip buffer");
+ return;
+ }
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85 ) {
+ /*
+ * Allocate a buffer to hold the ASCII85 encoded data. Note
+ * that it is allocated with sufficient room to hold the
+ * encoded data (5*bufsize/4) plus the EOD marker (+8)
+ * and formatting line breaks. The line breaks are more
+ * than taken care of by using 6*bufsize/4 rather than
+ * 5*bufsize/4.
+ */
+
+ ascii85_p = _TIFFmalloc( (bufsize+(bufsize/2)) + 8 );
+
+ if ( !ascii85_p ) {
+ _TIFFfree( tf_buf );
+
+ TIFFError( filename, "Cannot allocate ASCII85 encoding buffer." );
+ return;
+ }
+ }
+#endif
+
+ for (s = 0; s < (tstrip_t) tf_numberstrips; s++) {
+ cc = TIFFReadRawStrip(tif, s, tf_buf, bc[s]);
+ if (cc < 0) {
+ TIFFError(filename, "Can't read strip");
+ break;
+ }
+ if (fillorder == FILLORDER_LSB2MSB)
+ TIFFReverseBits(tf_buf, cc);
+ if (!ascii85) {
+ for (cp = tf_buf; cc > 0; cc--) {
+ DOBREAK(breaklen, 1, fd);
+ c = *cp++;
+ PUTHEX(c, fd);
+ }
+ fputs(">\n", fd);
+ breaklen = MAXLINE;
+ } else {
+ Ascii85Init();
+#if defined( EXP_ASCII85ENCODER )
+ ascii85_l = Ascii85EncodeBlock( ascii85_p, 1, tf_buf, cc );
+
+ if ( ascii85_l > 0 )
+ fwrite( ascii85_p, ascii85_l, 1, fd );
+#else
+ for (cp = tf_buf; cc > 0; cc--)
+ Ascii85Put(*cp++, fd);
+ Ascii85Flush(fd);
+#endif /* EXP_ASCII85ENCODER */
+ }
+ }
+ _TIFFfree((char *) tf_buf);
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85_p )
+ _TIFFfree( ascii85_p );
+#endif
+}
+
+void
+Ascii85Init(void)
+{
+ ascii85breaklen = 2*MAXLINE;
+ ascii85count = 0;
+}
+
+static char*
+Ascii85Encode(unsigned char* raw)
+{
+ static char encoded[6];
+ uint32 word;
+
+ word = (((raw[0]<<8)+raw[1])<<16) + (raw[2]<<8) + raw[3];
+ if (word != 0L) {
+ uint32 q;
+ uint16 w1;
+
+ q = word / (85L*85*85*85); /* actually only a byte */
+ encoded[0] = (char) (q + '!');
+
+ word -= q * (85L*85*85*85); q = word / (85L*85*85);
+ encoded[1] = (char) (q + '!');
+
+ word -= q * (85L*85*85); q = word / (85*85);
+ encoded[2] = (char) (q + '!');
+
+ w1 = (uint16) (word - q*(85L*85));
+ encoded[3] = (char) ((w1 / 85) + '!');
+ encoded[4] = (char) ((w1 % 85) + '!');
+ encoded[5] = '\0';
+ } else
+ encoded[0] = 'z', encoded[1] = '\0';
+ return (encoded);
+}
+
+void
+Ascii85Put(unsigned char code, FILE* fd)
+{
+ ascii85buf[ascii85count++] = code;
+ if (ascii85count >= 4) {
+ unsigned char* p;
+ int n;
+
+ for (n = ascii85count, p = ascii85buf; n >= 4; n -= 4, p += 4) {
+ char* cp;
+ for (cp = Ascii85Encode(p); *cp; cp++) {
+ putc(*cp, fd);
+ if (--ascii85breaklen == 0) {
+ putc('\n', fd);
+ ascii85breaklen = 2*MAXLINE;
+ }
+ }
+ }
+ _TIFFmemcpy(ascii85buf, p, n);
+ ascii85count = n;
+ }
+}
+
+void
+Ascii85Flush(FILE* fd)
+{
+ if (ascii85count > 0) {
+ char* res;
+ _TIFFmemset(&ascii85buf[ascii85count], 0, 3);
+ res = Ascii85Encode(ascii85buf);
+ fwrite(res[0] == 'z' ? "!!!!" : res, ascii85count + 1, 1, fd);
+ }
+ fputs("~>\n", fd);
+}
+#if defined( EXP_ASCII85ENCODER)
+
+#define A85BREAKCNTR ascii85breaklen
+#define A85BREAKLEN (2*MAXLINE)
+
+/*****************************************************************************
+*
+* Name: Ascii85EncodeBlock( ascii85_p, f_eod, raw_p, raw_l )
+*
+* Description: This routine will encode the raw data in the buffer described
+* by raw_p and raw_l into ASCII85 format and store the encoding
+* in the buffer given by ascii85_p.
+*
+* Parameters: ascii85_p - A buffer supplied by the caller which will
+* contain the encoded ASCII85 data.
+* f_eod - Flag: Nz means to end the encoded buffer with
+* an End-Of-Data marker.
+* raw_p - Pointer to the buffer of data to be encoded
+* raw_l - Number of bytes in raw_p[] to be encoded
+*
+* Returns: (int) < 0 Error, see errno
+* >= 0 Number of bytes written to ascii85_p[].
+*
+* Notes: An external variable given by A85BREAKCNTR is used to
+* determine when to insert newline characters into the
+* encoded data. As each byte is placed into ascii85_p this
+* external is decremented. If the variable is decrement to
+* or past zero then a newline is inserted into ascii85_p
+* and the A85BREAKCNTR is then reset to A85BREAKLEN.
+* Note: for efficiency reasons the A85BREAKCNTR variable
+* is not actually checked on *every* character
+* placed into ascii85_p but often only for every
+* 5 characters.
+*
+* THE CALLER IS RESPONSIBLE FOR ENSURING THAT ASCII85_P[] IS
+* SUFFICIENTLY LARGE TO THE ENCODED DATA!
+* You will need at least 5 * (raw_l/4) bytes plus space for
+* newline characters and space for an EOD marker (if
+* requested). A safe calculation is to use 6*(raw_l/4) + 8
+* to size ascii85_p.
+*
+*****************************************************************************/
+
+int Ascii85EncodeBlock( uint8 * ascii85_p, unsigned f_eod, const uint8 * raw_p, int raw_l )
+
+{
+ char ascii85[5]; /* Encoded 5 tuple */
+ int ascii85_l; /* Number of bytes written to ascii85_p[] */
+ int rc; /* Return code */
+ uint32 val32; /* Unencoded 4 tuple */
+
+ ascii85_l = 0; /* Nothing written yet */
+
+ if ( raw_p )
+ {
+ --raw_p; /* Prepare for pre-increment fetches */
+
+ for ( ; raw_l > 3; raw_l -= 4 )
+ {
+ val32 = *(++raw_p) << 24;
+ val32 += *(++raw_p) << 16;
+ val32 += *(++raw_p) << 8;
+ val32 += *(++raw_p);
+
+ if ( val32 == 0 ) /* Special case */
+ {
+ ascii85_p[ascii85_l] = 'z';
+ rc = 1;
+ }
+
+ else
+ {
+ ascii85[4] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[3] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[2] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[1] = (char) ((val32 % 85) + 33);
+ ascii85[0] = (char) ((val32 / 85) + 33);
+
+ _TIFFmemcpy( &ascii85_p[ascii85_l], ascii85, sizeof(ascii85) );
+ rc = sizeof(ascii85);
+ }
+
+ ascii85_l += rc;
+
+ if ( (A85BREAKCNTR -= rc) <= 0 )
+ {
+ ascii85_p[ascii85_l] = '\n';
+ ++ascii85_l;
+ A85BREAKCNTR = A85BREAKLEN;
+ }
+ }
+
+ /*
+ * Output any straggler bytes:
+ */
+
+ if ( raw_l > 0 )
+ {
+ int len; /* Output this many bytes */
+
+ len = raw_l + 1;
+ val32 = *++raw_p << 24; /* Prime the pump */
+
+ if ( --raw_l > 0 ) val32 += *(++raw_p) << 16;
+ if ( --raw_l > 0 ) val32 += *(++raw_p) << 8;
+
+ val32 /= 85;
+
+ ascii85[3] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[2] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[1] = (char) ((val32 % 85) + 33);
+ ascii85[0] = (char) ((val32 / 85) + 33);
+
+ _TIFFmemcpy( &ascii85_p[ascii85_l], ascii85, len );
+ ascii85_l += len;
+ }
+ }
+
+ /*
+ * If requested add an ASCII85 End Of Data marker:
+ */
+
+ if ( f_eod )
+ {
+ ascii85_p[ascii85_l++] = '~';
+ ascii85_p[ascii85_l++] = '>';
+ ascii85_p[ascii85_l++] = '\n';
+ }
+
+ return ( ascii85_l );
+
+} /* Ascii85EncodeBlock() */
+
+#endif /* EXP_ASCII85ENCODER */
+
+
+char* stuff[] = {
+"usage: tiff2ps [options] input.tif ...",
+"where options are:",
+" -1 generate PostScript Level 1 (default)",
+" -2 generate PostScript Level 2",
+" -3 generate PostScript Level 3",
+" -8 disable use of ASCII85 encoding with PostScript Level 2/3",
+" -a convert all directories in file (default is first)",
+" -b # set the bottom margin to # inches",
+" -c center image (-b and -l still add to this)",
+" -d # convert directory number #",
+" -D enable duplex printing (two pages per sheet of paper)",
+" -e generate Encapsulated PostScript (EPS) (implies -z)",
+" -h # assume printed page height is # inches (default 11)",
+" -w # assume printed page width is # inches (default 8.5)",
+" -H # split image if height is more than # inches",
+" -W # split image if width is more than # inches",
+" -L # overLap split images by # inches",
+" -i # enable/disable (Nz/0) pixel interpolation (default: enable)",
+" -l # set the left margin to # inches",
+" -m use \"imagemask\" operator instead of \"image\"",
+" -o # convert directory at file offset #",
+" -O file write PostScript to file instead of standard output",
+" -p generate regular PostScript",
+" -r # or auto rotate by 90, 180, 270 degrees or auto",
+" -s generate PostScript for a single image",
+" -T print pages for top edge binding",
+" -x override resolution units as centimeters",
+" -y override resolution units as inches",
+" -z enable printing in the deadzone (only for PostScript Level 2/3)",
+NULL
+};
+
+static void
+usage(int code)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(code);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiff2rgba.c b/tiff/tools/tiff2rgba.c
new file mode 100644
index 0000000..9ba2877
--- /dev/null
+++ b/tiff/tools/tiff2rgba.c
@@ -0,0 +1,548 @@
+/* $Id: tiff2rgba.c,v 1.13.2.3 2010-06-12 02:55:16 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffiop.h"
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define roundup(x, y) (howmany(x,y)*((uint32)(y)))
+
+uint16 compression = COMPRESSION_PACKBITS;
+uint32 rowsperstrip = (uint32) -1;
+int process_by_block = 0; /* default is whole image at once */
+int no_alpha = 0;
+
+
+static int tiffcvt(TIFF* in, TIFF* out);
+static void usage(int code);
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *in, *out;
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "c:r:t:bn")) != -1)
+ switch (c) {
+ case 'b':
+ process_by_block = 1;
+ break;
+
+ case 'c':
+ if (streq(optarg, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(optarg, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (streq(optarg, "lzw"))
+ compression = COMPRESSION_LZW;
+ else if (streq(optarg, "jpeg"))
+ compression = COMPRESSION_JPEG;
+ else if (streq(optarg, "zip"))
+ compression = COMPRESSION_DEFLATE;
+ else
+ usage(-1);
+ break;
+
+ case 'r':
+ rowsperstrip = atoi(optarg);
+ break;
+
+ case 't':
+ rowsperstrip = atoi(optarg);
+ break;
+
+ case 'n':
+ no_alpha = 1;
+ break;
+
+ case '?':
+ usage(0);
+ /*NOTREACHED*/
+ }
+
+ if (argc - optind < 2)
+ usage(-1);
+
+ out = TIFFOpen(argv[argc-1], "w");
+ if (out == NULL)
+ return (-2);
+
+ for (; optind < argc-1; optind++) {
+ in = TIFFOpen(argv[optind], "r");
+ if (in != NULL) {
+ do {
+ if (!tiffcvt(in, out) ||
+ !TIFFWriteDirectory(out)) {
+ (void) TIFFClose(out);
+ return (1);
+ }
+ } while (TIFFReadDirectory(in));
+ (void) TIFFClose(in);
+ }
+ }
+ (void) TIFFClose(out);
+ return (0);
+}
+
+#define multiply(a,b) TIFFSafeMultiply(tsize_t,a,b)
+
+static int
+cvt_by_tile( TIFF *in, TIFF *out )
+
+{
+ uint32* raster; /* retrieve RGBA image */
+ uint32 width, height; /* image width & height */
+ uint32 tile_width, tile_height;
+ uint32 row, col;
+ uint32 *wrk_line;
+ tsize_t raster_size;
+ int ok = 1;
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+
+ if( !TIFFGetField(in, TIFFTAG_TILEWIDTH, &tile_width)
+ || !TIFFGetField(in, TIFFTAG_TILELENGTH, &tile_height) ) {
+ TIFFError(TIFFFileName(in), "Source image not tiled");
+ return (0);
+ }
+
+ TIFFSetField(out, TIFFTAG_TILEWIDTH, tile_width );
+ TIFFSetField(out, TIFFTAG_TILELENGTH, tile_height );
+
+ /*
+ * Allocate tile buffer
+ */
+ raster_size = multiply(multiply(tile_width, tile_height), sizeof (uint32));
+ if (!raster_size) {
+ TIFFError(TIFFFileName(in),
+ "Can't allocate buffer for raster of size %lux%lu",
+ (unsigned long) tile_width, (unsigned long) tile_height);
+ return (0);
+ }
+ raster = (uint32*)_TIFFmalloc(raster_size);
+ if (raster == 0) {
+ TIFFError(TIFFFileName(in), "No space for raster buffer");
+ return (0);
+ }
+
+ /*
+ * Allocate a scanline buffer for swapping during the vertical
+ * mirroring pass. (Request can't overflow given prior checks.)
+ */
+ wrk_line = (uint32*)_TIFFmalloc(tile_width * sizeof (uint32));
+ if (!wrk_line) {
+ TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
+ ok = 0;
+ }
+
+ /*
+ * Loop over the tiles.
+ */
+ for( row = 0; ok && row < height; row += tile_height )
+ {
+ for( col = 0; ok && col < width; col += tile_width )
+ {
+ uint32 i_row;
+
+ /* Read the tile into an RGBA array */
+ if (!TIFFReadRGBATile(in, col, row, raster)) {
+ ok = 0;
+ break;
+ }
+
+
+ /*
+ * XXX: raster array has 4-byte unsigned integer type, that is why
+ * we should rearrange it here.
+ */
+#if HOST_BIGENDIAN
+ TIFFSwabArrayOfLong(raster, tile_width * tile_height);
+#endif
+
+ /*
+ * For some reason the TIFFReadRGBATile() function chooses the
+ * lower left corner as the origin. Vertically mirror scanlines.
+ */
+ for( i_row = 0; i_row < tile_height / 2; i_row++ )
+ {
+ uint32 *top_line, *bottom_line;
+
+ top_line = raster + tile_width * i_row;
+ bottom_line = raster + tile_width * (tile_height-i_row-1);
+
+ _TIFFmemcpy(wrk_line, top_line, 4*tile_width);
+ _TIFFmemcpy(top_line, bottom_line, 4*tile_width);
+ _TIFFmemcpy(bottom_line, wrk_line, 4*tile_width);
+ }
+
+ /*
+ * Write out the result in a tile.
+ */
+
+ if( TIFFWriteEncodedTile( out,
+ TIFFComputeTile( out, col, row, 0, 0),
+ raster,
+ 4 * tile_width * tile_height ) == -1 )
+ {
+ ok = 0;
+ break;
+ }
+ }
+ }
+
+ _TIFFfree( raster );
+ _TIFFfree( wrk_line );
+
+ return ok;
+}
+
+static int
+cvt_by_strip( TIFF *in, TIFF *out )
+
+{
+ uint32* raster; /* retrieve RGBA image */
+ uint32 width, height; /* image width & height */
+ uint32 row;
+ uint32 *wrk_line;
+ tsize_t raster_size;
+ int ok = 1;
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+
+ if( !TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip) ) {
+ TIFFError(TIFFFileName(in), "Source image not in strips");
+ return (0);
+ }
+
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ /*
+ * Allocate strip buffer
+ */
+ raster_size = multiply(multiply(width, rowsperstrip), sizeof (uint32));
+ if (!raster_size) {
+ TIFFError(TIFFFileName(in),
+ "Can't allocate buffer for raster of size %lux%lu",
+ (unsigned long) width, (unsigned long) rowsperstrip);
+ return (0);
+ }
+ raster = (uint32*)_TIFFmalloc(raster_size);
+ if (raster == 0) {
+ TIFFError(TIFFFileName(in), "No space for raster buffer");
+ return (0);
+ }
+
+ /*
+ * Allocate a scanline buffer for swapping during the vertical
+ * mirroring pass. (Request can't overflow given prior checks.)
+ */
+ wrk_line = (uint32*)_TIFFmalloc(width * sizeof (uint32));
+ if (!wrk_line) {
+ TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
+ ok = 0;
+ }
+
+ /*
+ * Loop over the strips.
+ */
+ for( row = 0; ok && row < height; row += rowsperstrip )
+ {
+ int rows_to_write, i_row;
+
+ /* Read the strip into an RGBA array */
+ if (!TIFFReadRGBAStrip(in, row, raster)) {
+ ok = 0;
+ break;
+ }
+
+ /*
+ * XXX: raster array has 4-byte unsigned integer type, that is why
+ * we should rearrange it here.
+ */
+#if HOST_BIGENDIAN
+ TIFFSwabArrayOfLong(raster, width * rowsperstrip);
+#endif
+
+ /*
+ * Figure out the number of scanlines actually in this strip.
+ */
+ if( row + rowsperstrip > height )
+ rows_to_write = height - row;
+ else
+ rows_to_write = rowsperstrip;
+
+ /*
+ * For some reason the TIFFReadRGBAStrip() function chooses the
+ * lower left corner as the origin. Vertically mirror scanlines.
+ */
+
+ for( i_row = 0; i_row < rows_to_write / 2; i_row++ )
+ {
+ uint32 *top_line, *bottom_line;
+
+ top_line = raster + width * i_row;
+ bottom_line = raster + width * (rows_to_write-i_row-1);
+
+ _TIFFmemcpy(wrk_line, top_line, 4*width);
+ _TIFFmemcpy(top_line, bottom_line, 4*width);
+ _TIFFmemcpy(bottom_line, wrk_line, 4*width);
+ }
+
+ /*
+ * Write out the result in a strip
+ */
+
+ if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster,
+ 4 * rows_to_write * width ) == -1 )
+ {
+ ok = 0;
+ break;
+ }
+ }
+
+ _TIFFfree( raster );
+ _TIFFfree( wrk_line );
+
+ return ok;
+}
+
+/*
+ * cvt_whole_image()
+ *
+ * read the whole image into one big RGBA buffer and then write out
+ * strips from that. This is using the traditional TIFFReadRGBAImage()
+ * API that we trust.
+ */
+
+static int
+cvt_whole_image( TIFF *in, TIFF *out )
+
+{
+ uint32* raster; /* retrieve RGBA image */
+ uint32 width, height; /* image width & height */
+ uint32 row;
+ size_t pixel_count;
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+ pixel_count = width * height;
+
+ /* XXX: Check the integer overflow. */
+ if (!width || !height || pixel_count / width != height) {
+ TIFFError(TIFFFileName(in),
+ "Malformed input file; can't allocate buffer for raster of %lux%lu size",
+ (unsigned long)width, (unsigned long)height);
+ return 0;
+ }
+
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32), "raster buffer");
+ if (raster == 0) {
+ TIFFError(TIFFFileName(in), "Requested buffer size is %lu elements %lu each",
+ (unsigned long)pixel_count, (unsigned long)sizeof(uint32));
+ return (0);
+ }
+
+ /* Read the image in one chunk into an RGBA array */
+ if (!TIFFReadRGBAImageOriented(in, width, height, raster,
+ ORIENTATION_TOPLEFT, 0)) {
+ _TIFFfree(raster);
+ return (0);
+ }
+
+ /*
+ * XXX: raster array has 4-byte unsigned integer type, that is why
+ * we should rearrange it here.
+ */
+#if HOST_BIGENDIAN
+ TIFFSwabArrayOfLong(raster, width * height);
+#endif
+
+ /*
+ * Do we want to strip away alpha components?
+ */
+ if (no_alpha)
+ {
+ size_t count = pixel_count;
+ unsigned char *src, *dst;
+
+ src = dst = (unsigned char *) raster;
+ while (count > 0)
+ {
+ *(dst++) = *(src++);
+ *(dst++) = *(src++);
+ *(dst++) = *(src++);
+ src++;
+ count--;
+ }
+ }
+
+ /*
+ * Write out the result in strips
+ */
+ for (row = 0; row < height; row += rowsperstrip)
+ {
+ unsigned char * raster_strip;
+ int rows_to_write;
+ int bytes_per_pixel;
+
+ if (no_alpha)
+ {
+ raster_strip = ((unsigned char *) raster) + 3 * row * width;
+ bytes_per_pixel = 3;
+ }
+ else
+ {
+ raster_strip = (unsigned char *) (raster + row * width);
+ bytes_per_pixel = 4;
+ }
+
+ if( row + rowsperstrip > height )
+ rows_to_write = height - row;
+ else
+ rows_to_write = rowsperstrip;
+
+ if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster_strip,
+ bytes_per_pixel * rows_to_write * width ) == -1 )
+ {
+ _TIFFfree( raster );
+ return 0;
+ }
+ }
+
+ _TIFFfree( raster );
+
+ return 1;
+}
+
+
+static int
+tiffcvt(TIFF* in, TIFF* out)
+{
+ uint32 width, height; /* image width & height */
+ uint16 shortv;
+ float floatv;
+ char *stringv;
+ uint32 longv;
+ uint16 v[1];
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+
+ CopyField(TIFFTAG_SUBFILETYPE, longv);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+
+ CopyField(TIFFTAG_FILLORDER, shortv);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+
+ if( no_alpha )
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
+ else
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 4);
+
+ if( !no_alpha )
+ {
+ v[0] = EXTRASAMPLE_ASSOCALPHA;
+ TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v);
+ }
+
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
+ CopyField(TIFFTAG_DOCUMENTNAME, stringv);
+
+ if( process_by_block && TIFFIsTiled( in ) )
+ return( cvt_by_tile( in, out ) );
+ else if( process_by_block )
+ return( cvt_by_strip( in, out ) );
+ else
+ return( cvt_whole_image( in, out ) );
+}
+
+static char* stuff[] = {
+ "usage: tiff2rgba [-c comp] [-r rows] [-b] input... output",
+ "where comp is one of the following compression algorithms:",
+ " jpeg\t\tJPEG encoding",
+ " zip\t\tLempel-Ziv & Welch encoding",
+ " lzw\t\tLempel-Ziv & Welch encoding",
+ " packbits\tPackBits encoding",
+ " none\t\tno compression",
+ "and the other options are:",
+ " -r\trows/strip",
+ " -b (progress by block rather than as a whole image)",
+ " -n don't emit alpha component.",
+ NULL
+};
+
+static void
+usage(int code)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(code);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffcmp.c b/tiff/tools/tiffcmp.c
new file mode 100644
index 0000000..9f73236
--- /dev/null
+++ b/tiff/tools/tiffcmp.c
@@ -0,0 +1,640 @@
+/* $Id: tiffcmp.c,v 1.13.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+static int stopondiff = 1;
+static int stoponfirsttag = 1;
+static uint16 bitspersample = 1;
+static uint16 samplesperpixel = 1;
+static uint16 sampleformat = SAMPLEFORMAT_UINT;
+static uint32 imagewidth;
+static uint32 imagelength;
+
+static void usage(void);
+static int tiffcmp(TIFF*, TIFF*);
+static int cmptags(TIFF*, TIFF*);
+static int ContigCompare(int, uint32, unsigned char*, unsigned char*, int);
+static int SeparateCompare(int, int, uint32, unsigned char*, unsigned char*);
+static void PrintIntDiff(uint32, int, uint32, uint32, uint32);
+static void PrintFloatDiff(uint32, int, uint32, double, double);
+
+static void leof(const char*, uint32, int);
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *tif1, *tif2;
+ int c, dirnum;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "ltz:")) != -1)
+ switch (c) {
+ case 'l':
+ stopondiff = 0;
+ break;
+ case 'z':
+ stopondiff = atoi(optarg);
+ break;
+ case 't':
+ stoponfirsttag = 0;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage();
+ tif1 = TIFFOpen(argv[optind], "r");
+ if (tif1 == NULL)
+ return (-1);
+ tif2 = TIFFOpen(argv[optind+1], "r");
+ if (tif2 == NULL)
+ return (-2);
+ dirnum = 0;
+ while (tiffcmp(tif1, tif2)) {
+ if (!TIFFReadDirectory(tif1)) {
+ if (!TIFFReadDirectory(tif2))
+ break;
+ printf("No more directories for %s\n",
+ TIFFFileName(tif1));
+ return (1);
+ } else if (!TIFFReadDirectory(tif2)) {
+ printf("No more directories for %s\n",
+ TIFFFileName(tif2));
+ return (1);
+ }
+ printf("Directory %d:\n", ++dirnum);
+ }
+
+ TIFFClose(tif1);
+ TIFFClose(tif2);
+ return (0);
+}
+
+char* stuff[] = {
+"usage: tiffcmp [options] file1 file2",
+"where options are:",
+" -l list each byte of image data that differs between the files",
+" -z # list specified number of bytes that differs between the files",
+" -t ignore any differences in directory tags",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+#define checkEOF(tif, row, sample) { \
+ leof(TIFFFileName(tif), row, sample); \
+ goto bad; \
+}
+
+static int CheckShortTag(TIFF*, TIFF*, int, char*);
+static int CheckShort2Tag(TIFF*, TIFF*, int, char*);
+static int CheckShortArrayTag(TIFF*, TIFF*, int, char*);
+static int CheckLongTag(TIFF*, TIFF*, int, char*);
+static int CheckFloatTag(TIFF*, TIFF*, int, char*);
+static int CheckStringTag(TIFF*, TIFF*, int, char*);
+
+static int
+tiffcmp(TIFF* tif1, TIFF* tif2)
+{
+ uint16 config1, config2;
+ tsize_t size1;
+ uint32 row;
+ tsample_t s;
+ unsigned char *buf1, *buf2;
+
+ if (!CheckShortTag(tif1, tif2, TIFFTAG_BITSPERSAMPLE, "BitsPerSample"))
+ return (0);
+ if (!CheckShortTag(tif1, tif2, TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel"))
+ return (0);
+ if (!CheckLongTag(tif1, tif2, TIFFTAG_IMAGEWIDTH, "ImageWidth"))
+ return (0);
+ if (!cmptags(tif1, tif2))
+ return (1);
+ (void) TIFFGetField(tif1, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ (void) TIFFGetField(tif1, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ (void) TIFFGetField(tif1, TIFFTAG_SAMPLEFORMAT, &sampleformat);
+ (void) TIFFGetField(tif1, TIFFTAG_IMAGEWIDTH, &imagewidth);
+ (void) TIFFGetField(tif1, TIFFTAG_IMAGELENGTH, &imagelength);
+ (void) TIFFGetField(tif1, TIFFTAG_PLANARCONFIG, &config1);
+ (void) TIFFGetField(tif2, TIFFTAG_PLANARCONFIG, &config2);
+ buf1 = (unsigned char *)_TIFFmalloc(size1 = TIFFScanlineSize(tif1));
+ buf2 = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif2));
+ if (buf1 == NULL || buf2 == NULL) {
+ fprintf(stderr, "No space for scanline buffers\n");
+ exit(-1);
+ }
+ if (config1 != config2 && bitspersample != 8 && samplesperpixel > 1) {
+ fprintf(stderr,
+"Can't handle different planar configuration w/ different bits/sample\n");
+ goto bad;
+ }
+#define pack(a,b) ((a)<<8)|(b)
+ switch (pack(config1, config2)) {
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG):
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
+ checkEOF(tif2, row, -1)
+ for (s = 0; s < samplesperpixel; s++) {
+ if (TIFFReadScanline(tif1, buf1, row, s) < 0)
+ checkEOF(tif1, row, s)
+ if (SeparateCompare(1, s, row, buf2, buf1) < 0)
+ goto bad1;
+ }
+ }
+ break;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE):
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
+ checkEOF(tif1, row, -1)
+ for (s = 0; s < samplesperpixel; s++) {
+ if (TIFFReadScanline(tif2, buf2, row, s) < 0)
+ checkEOF(tif2, row, s)
+ if (SeparateCompare(0, s, row, buf1, buf2) < 0)
+ goto bad1;
+ }
+ }
+ break;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE):
+ for (s = 0; s < samplesperpixel; s++)
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(tif1, buf1, row, s) < 0)
+ checkEOF(tif1, row, s)
+ if (TIFFReadScanline(tif2, buf2, row, s) < 0)
+ checkEOF(tif2, row, s)
+ if (ContigCompare(s, row, buf1, buf2, size1) < 0)
+ goto bad1;
+ }
+ break;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG):
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
+ checkEOF(tif1, row, -1)
+ if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
+ checkEOF(tif2, row, -1)
+ if (ContigCompare(-1, row, buf1, buf2, size1) < 0)
+ goto bad1;
+ }
+ break;
+ }
+ if (buf1) _TIFFfree(buf1);
+ if (buf2) _TIFFfree(buf2);
+ return (1);
+bad:
+ if (stopondiff)
+ exit(1);
+bad1:
+ if (buf1) _TIFFfree(buf1);
+ if (buf2) _TIFFfree(buf2);
+ return (0);
+}
+
+#define CmpShortField(tag, name) \
+ if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpShortField2(tag, name) \
+ if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpLongField(tag, name) \
+ if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpFloatField(tag, name) \
+ if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpStringField(tag, name) \
+ if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpShortArrayField(tag, name) \
+ if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+
+static int
+cmptags(TIFF* tif1, TIFF* tif2)
+{
+ CmpLongField(TIFFTAG_SUBFILETYPE, "SubFileType");
+ CmpLongField(TIFFTAG_IMAGEWIDTH, "ImageWidth");
+ CmpLongField(TIFFTAG_IMAGELENGTH, "ImageLength");
+ CmpShortField(TIFFTAG_BITSPERSAMPLE, "BitsPerSample");
+ CmpShortField(TIFFTAG_COMPRESSION, "Compression");
+ CmpShortField(TIFFTAG_PREDICTOR, "Predictor");
+ CmpShortField(TIFFTAG_PHOTOMETRIC, "PhotometricInterpretation");
+ CmpShortField(TIFFTAG_THRESHHOLDING, "Thresholding");
+ CmpShortField(TIFFTAG_FILLORDER, "FillOrder");
+ CmpShortField(TIFFTAG_ORIENTATION, "Orientation");
+ CmpShortField(TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel");
+ CmpShortField(TIFFTAG_MINSAMPLEVALUE, "MinSampleValue");
+ CmpShortField(TIFFTAG_MAXSAMPLEVALUE, "MaxSampleValue");
+ CmpShortField(TIFFTAG_SAMPLEFORMAT, "SampleFormat");
+ CmpFloatField(TIFFTAG_XRESOLUTION, "XResolution");
+ CmpFloatField(TIFFTAG_YRESOLUTION, "YResolution");
+ CmpLongField(TIFFTAG_GROUP3OPTIONS, "Group3Options");
+ CmpLongField(TIFFTAG_GROUP4OPTIONS, "Group4Options");
+ CmpShortField(TIFFTAG_RESOLUTIONUNIT, "ResolutionUnit");
+ CmpShortField(TIFFTAG_PLANARCONFIG, "PlanarConfiguration");
+ CmpLongField(TIFFTAG_ROWSPERSTRIP, "RowsPerStrip");
+ CmpFloatField(TIFFTAG_XPOSITION, "XPosition");
+ CmpFloatField(TIFFTAG_YPOSITION, "YPosition");
+ CmpShortField(TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit");
+ CmpShortField(TIFFTAG_COLORRESPONSEUNIT, "ColorResponseUnit");
+#ifdef notdef
+ { uint16 *graycurve;
+ CmpField(TIFFTAG_GRAYRESPONSECURVE, graycurve);
+ }
+ { uint16 *red, *green, *blue;
+ CmpField3(TIFFTAG_COLORRESPONSECURVE, red, green, blue);
+ }
+ { uint16 *red, *green, *blue;
+ CmpField3(TIFFTAG_COLORMAP, red, green, blue);
+ }
+#endif
+ CmpShortField2(TIFFTAG_PAGENUMBER, "PageNumber");
+ CmpStringField(TIFFTAG_ARTIST, "Artist");
+ CmpStringField(TIFFTAG_IMAGEDESCRIPTION,"ImageDescription");
+ CmpStringField(TIFFTAG_MAKE, "Make");
+ CmpStringField(TIFFTAG_MODEL, "Model");
+ CmpStringField(TIFFTAG_SOFTWARE, "Software");
+ CmpStringField(TIFFTAG_DATETIME, "DateTime");
+ CmpStringField(TIFFTAG_HOSTCOMPUTER, "HostComputer");
+ CmpStringField(TIFFTAG_PAGENAME, "PageName");
+ CmpStringField(TIFFTAG_DOCUMENTNAME, "DocumentName");
+ CmpShortField(TIFFTAG_MATTEING, "Matteing");
+ CmpShortArrayField(TIFFTAG_EXTRASAMPLES,"ExtraSamples");
+ return (1);
+}
+
+static int
+ContigCompare(int sample, uint32 row,
+ unsigned char* p1, unsigned char* p2, int size)
+{
+ uint32 pix;
+ int ppb = 8 / bitspersample;
+ int samples_to_test;
+
+ if (memcmp(p1, p2, size) == 0)
+ return 0;
+
+ samples_to_test = (sample == -1) ? samplesperpixel : 1;
+
+ switch (bitspersample) {
+ case 1: case 2: case 4: case 8:
+ {
+ unsigned char *pix1 = p1, *pix2 = p2;
+
+ for (pix = 0; pix < imagewidth; pix += ppb) {
+ int s;
+
+ for(s = 0; s < samples_to_test; s++) {
+ if (*pix1 != *pix2) {
+ if( sample == -1 )
+ PrintIntDiff(row, s, pix, *pix1, *pix2);
+ else
+ PrintIntDiff(row, sample, pix, *pix1, *pix2);
+ }
+
+ pix1++;
+ pix2++;
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+ uint16 *pix1 = (uint16 *)p1, *pix2 = (uint16 *)p2;
+
+ for (pix = 0; pix < imagewidth; pix++) {
+ int s;
+
+ for(s = 0; s < samples_to_test; s++) {
+ if (*pix1 != *pix2)
+ PrintIntDiff(row, sample, pix, *pix1, *pix2);
+
+ pix1++;
+ pix2++;
+ }
+ }
+ break;
+ }
+ case 32:
+ if (sampleformat == SAMPLEFORMAT_UINT
+ || sampleformat == SAMPLEFORMAT_INT) {
+ uint32 *pix1 = (uint32 *)p1, *pix2 = (uint32 *)p2;
+
+ for (pix = 0; pix < imagewidth; pix++) {
+ int s;
+
+ for(s = 0; s < samples_to_test; s++) {
+ if (*pix1 != *pix2) {
+ PrintIntDiff(row, sample, pix,
+ *pix1, *pix2);
+ }
+
+ pix1++;
+ pix2++;
+ }
+ }
+ } else if (sampleformat == SAMPLEFORMAT_IEEEFP) {
+ float *pix1 = (float *)p1, *pix2 = (float *)p2;
+
+ for (pix = 0; pix < imagewidth; pix++) {
+ int s;
+
+ for(s = 0; s < samples_to_test; s++) {
+ if (fabs(*pix1 - *pix2) < 0.000000000001) {
+ PrintFloatDiff(row, sample, pix,
+ *pix1, *pix2);
+ }
+
+ pix1++;
+ pix2++;
+ }
+ }
+ } else {
+ fprintf(stderr, "Sample format %d is not supported.\n",
+ sampleformat);
+ return -1;
+ }
+ break;
+ default:
+ fprintf(stderr, "Bit depth %d is not supported.\n", bitspersample);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+PrintIntDiff(uint32 row, int sample, uint32 pix, uint32 w1, uint32 w2)
+{
+ if (sample < 0)
+ sample = 0;
+ switch (bitspersample) {
+ case 1:
+ case 2:
+ case 4:
+ {
+ int32 mask1, mask2, s;
+
+ mask1 = ~((-1) << bitspersample);
+ s = (8 - bitspersample);
+ mask2 = mask1 << s;
+ for (; mask2 && pix < imagewidth;
+ mask2 >>= bitspersample, s -= bitspersample, pix++) {
+ if ((w1 & mask2) ^ (w2 & mask2)) {
+ printf(
+ "Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
+ (unsigned long) row,
+ (unsigned long) pix,
+ sample,
+ (unsigned int)((w1 >> s) & mask1),
+ (unsigned int)((w2 >> s) & mask1));
+ if (--stopondiff == 0)
+ exit(1);
+ }
+ }
+ break;
+ }
+ case 8:
+ printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
+ (unsigned long) row, (unsigned long) pix, sample,
+ (unsigned int) w1, (unsigned int) w2);
+ if (--stopondiff == 0)
+ exit(1);
+ break;
+ case 16:
+ printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
+ (unsigned long) row, (unsigned long) pix, sample,
+ (unsigned int) w1, (unsigned int) w2);
+ if (--stopondiff == 0)
+ exit(1);
+ break;
+ case 32:
+ printf("Scanline %lu, pixel %lu, sample %d: %08x %08x\n",
+ (unsigned long) row, (unsigned long) pix, sample,
+ (unsigned int) w1, (unsigned int) w2);
+ if (--stopondiff == 0)
+ exit(1);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+PrintFloatDiff(uint32 row, int sample, uint32 pix, double w1, double w2)
+{
+ if (sample < 0)
+ sample = 0;
+ switch (bitspersample) {
+ case 32:
+ printf("Scanline %lu, pixel %lu, sample %d: %g %g\n",
+ (long) row, (long) pix, sample, w1, w2);
+ if (--stopondiff == 0)
+ exit(1);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+SeparateCompare(int reversed, int sample, uint32 row,
+ unsigned char* cp1, unsigned char* p2)
+{
+ uint32 npixels = imagewidth;
+ int pixel;
+
+ cp1 += sample;
+ for (pixel = 0; npixels-- > 0; pixel++, cp1 += samplesperpixel, p2++) {
+ if (*cp1 != *p2) {
+ printf("Scanline %lu, pixel %lu, sample %ld: ",
+ (long) row, (long) pixel, (long) sample);
+ if (reversed)
+ printf("%02x %02x\n", *p2, *cp1);
+ else
+ printf("%02x %02x\n", *cp1, *p2);
+ if (--stopondiff == 0)
+ exit(1);
+ }
+ }
+
+ return 0;
+}
+
+static int
+checkTag(TIFF* tif1, TIFF* tif2, int tag, char* name, void* p1, void* p2)
+{
+
+ if (TIFFGetField(tif1, tag, p1)) {
+ if (!TIFFGetField(tif2, tag, p2)) {
+ printf("%s tag appears only in %s\n",
+ name, TIFFFileName(tif1));
+ return (0);
+ }
+ return (1);
+ } else if (TIFFGetField(tif2, tag, p2)) {
+ printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
+ return (0);
+ }
+ return (-1);
+}
+
+#define CHECK(cmp, fmt) { \
+ switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) { \
+ case 1: if (cmp) \
+ case -1: return (1); \
+ printf(fmt, name, v1, v2); \
+ } \
+ return (0); \
+}
+
+static int
+CheckShortTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ uint16 v1, v2;
+ CHECK(v1 == v2, "%s: %u %u\n");
+}
+
+static int
+CheckShort2Tag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ uint16 v11, v12, v21, v22;
+
+ if (TIFFGetField(tif1, tag, &v11, &v12)) {
+ if (!TIFFGetField(tif2, tag, &v21, &v22)) {
+ printf("%s tag appears only in %s\n",
+ name, TIFFFileName(tif1));
+ return (0);
+ }
+ if (v11 == v21 && v12 == v22)
+ return (1);
+ printf("%s: <%u,%u> <%u,%u>\n", name, v11, v12, v21, v22);
+ } else if (TIFFGetField(tif2, tag, &v21, &v22))
+ printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
+ else
+ return (1);
+ return (0);
+}
+
+static int
+CheckShortArrayTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ uint16 n1, *a1;
+ uint16 n2, *a2;
+
+ if (TIFFGetField(tif1, tag, &n1, &a1)) {
+ if (!TIFFGetField(tif2, tag, &n2, &a2)) {
+ printf("%s tag appears only in %s\n",
+ name, TIFFFileName(tif1));
+ return (0);
+ }
+ if (n1 == n2) {
+ char* sep;
+ uint16 i;
+
+ if (memcmp(a1, a2, n1 * sizeof(uint16)) == 0)
+ return (1);
+ printf("%s: value mismatch, <%u:", name, n1);
+ sep = "";
+ for (i = 0; i < n1; i++)
+ printf("%s%u", sep, a1[i]), sep = ",";
+ printf("> and <%u: ", n2);
+ sep = "";
+ for (i = 0; i < n2; i++)
+ printf("%s%u", sep, a2[i]), sep = ",";
+ printf(">\n");
+ } else
+ printf("%s: %u items in %s, %u items in %s", name,
+ n1, TIFFFileName(tif1),
+ n2, TIFFFileName(tif2)
+ );
+ } else if (TIFFGetField(tif2, tag, &n2, &a2))
+ printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
+ else
+ return (1);
+ return (0);
+}
+
+static int
+CheckLongTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ uint32 v1, v2;
+ CHECK(v1 == v2, "%s: %u %u\n");
+}
+
+static int
+CheckFloatTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ float v1, v2;
+ CHECK(v1 == v2, "%s: %g %g\n");
+}
+
+static int
+CheckStringTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ char *v1, *v2;
+ CHECK(strcmp(v1, v2) == 0, "%s: \"%s\" \"%s\"\n");
+}
+
+static void
+leof(const char* name, uint32 row, int s)
+{
+
+ printf("%s: EOF at scanline %lu", name, (unsigned long)row);
+ if (s >= 0)
+ printf(", sample %d", s);
+ printf("\n");
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffcp.c b/tiff/tools/tiffcp.c
new file mode 100644
index 0000000..48319fa
--- /dev/null
+++ b/tiff/tools/tiffcp.c
@@ -0,0 +1,1770 @@
+/* $Id: tiffcp.c,v 1.37.2.8 2010-06-11 20:50:55 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Revised: 2/18/01 BAR -- added syntax for extracting single images from
+ * multi-image TIFF files.
+ *
+ * New syntax is: sourceFileName,image#
+ *
+ * image# ranges from 0..<n-1> where n is the # of images in the file.
+ * There may be no white space between the comma and the filename or
+ * image number.
+ *
+ * Example: tiffcp source.tif,1 destination.tif
+ *
+ * Copies the 2nd image in source.tif to the destination.
+ *
+ *****
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ctype.h>
+#include <assert.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#if defined(VMS)
+# define unlink delete
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+#define TRUE 1
+#define FALSE 0
+
+static int outtiled = -1;
+static uint32 tilewidth;
+static uint32 tilelength;
+
+static uint16 config;
+static uint16 compression;
+static uint16 predictor;
+static uint16 fillorder;
+static uint16 orientation;
+static uint32 rowsperstrip;
+static uint32 g3opts;
+static int ignore = FALSE; /* if true, ignore read errors */
+static uint32 defg3opts = (uint32) -1;
+static int quality = 75; /* JPEG quality */
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static uint16 defcompression = (uint16) -1;
+static uint16 defpredictor = (uint16) -1;
+
+static int tiffcp(TIFF*, TIFF*);
+static int processCompressOptions(char*);
+static void usage(void);
+
+static char comma = ','; /* (default) comma separator character */
+static TIFF* bias = NULL;
+static int pageNum = 0;
+static int pageInSeq = 0;
+
+static int nextSrcImage (TIFF *tif, char **imageSpec)
+/*
+ seek to the next image specified in *imageSpec
+ returns 1 if success, 0 if no more images to process
+ *imageSpec=NULL if subsequent images should be processed in sequence
+*/
+{
+ if (**imageSpec == comma) { /* if not @comma, we've done all images */
+ char *start = *imageSpec + 1;
+ tdir_t nextImage = (tdir_t)strtol(start, imageSpec, 0);
+ if (start == *imageSpec) nextImage = TIFFCurrentDirectory (tif);
+ if (**imageSpec)
+ {
+ if (**imageSpec == comma) {
+ /* a trailing comma denotes remaining images in sequence */
+ if ((*imageSpec)[1] == '\0') *imageSpec = NULL;
+ }else{
+ fprintf (stderr,
+ "Expected a %c separated image # list after %s\n",
+ comma, TIFFFileName (tif));
+ exit (-4); /* syntax error */
+ }
+ }
+ if (TIFFSetDirectory (tif, nextImage)) return 1;
+ fprintf (stderr, "%s%c%d not found!\n",
+ TIFFFileName(tif), comma, (int) nextImage);
+ }
+ return 0;
+}
+
+
+static TIFF* openSrcImage (char **imageSpec)
+/*
+ imageSpec points to a pointer to a filename followed by optional ,image#'s
+ Open the TIFF file and assign *imageSpec to either NULL if there are
+ no images specified, or a pointer to the next image number text
+*/
+{
+ TIFF *tif;
+ char *fn = *imageSpec;
+ *imageSpec = strchr (fn, comma);
+ if (*imageSpec) { /* there is at least one image number specifier */
+ **imageSpec = '\0';
+ tif = TIFFOpen (fn, "r");
+ /* but, ignore any single trailing comma */
+ if (!(*imageSpec)[1]) {*imageSpec = NULL; return tif;}
+ if (tif) {
+ **imageSpec = comma; /* replace the comma */
+ if (!nextSrcImage(tif, imageSpec)) {
+ TIFFClose (tif);
+ tif = NULL;
+ }
+ }
+ }else
+ tif = TIFFOpen (fn, "r");
+ return tif;
+}
+
+
+int
+main(int argc, char* argv[])
+{
+ uint16 defconfig = (uint16) -1;
+ uint16 deffillorder = 0;
+ uint32 deftilewidth = (uint32) -1;
+ uint32 deftilelength = (uint32) -1;
+ uint32 defrowsperstrip = (uint32) 0;
+ uint32 diroff = 0;
+ TIFF* in;
+ TIFF* out;
+ char mode[10];
+ char* mp = mode;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ *mp++ = 'w';
+ *mp = '\0';
+ while ((c = getopt(argc, argv, ",:b:c:f:l:o:z:p:r:w:aistBLMCx")) != -1)
+ switch (c) {
+ case ',':
+ if (optarg[0] != '=') usage();
+ comma = optarg[1];
+ break;
+ case 'b': /* this file is bias image subtracted from others */
+ if (bias) {
+ fputs ("Only 1 bias image may be specified\n", stderr);
+ exit (-2);
+ }
+ {
+ uint16 samples = (uint16) -1;
+ char **biasFn = &optarg;
+ bias = openSrcImage (biasFn);
+ if (!bias) exit (-5);
+ if (TIFFIsTiled (bias)) {
+ fputs ("Bias image must be organized in strips\n", stderr);
+ exit (-7);
+ }
+ TIFFGetField(bias, TIFFTAG_SAMPLESPERPIXEL, &samples);
+ if (samples != 1) {
+ fputs ("Bias image must be monochrome\n", stderr);
+ exit (-7);
+ }
+ }
+ break;
+ case 'a': /* append to output */
+ mode[0] = 'a';
+ break;
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'f': /* fill order */
+ if (streq(optarg, "lsb2msb"))
+ deffillorder = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ deffillorder = FILLORDER_MSB2LSB;
+ else
+ usage();
+ break;
+ case 'i': /* ignore errors */
+ ignore = TRUE;
+ break;
+ case 'l': /* tile length */
+ outtiled = TRUE;
+ deftilelength = atoi(optarg);
+ break;
+ case 'o': /* initial directory offset */
+ diroff = strtoul(optarg, NULL, 0);
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ defconfig = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ defconfig = PLANARCONFIG_CONTIG;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ defrowsperstrip = atol(optarg);
+ break;
+ case 's': /* generate stripped output */
+ outtiled = FALSE;
+ break;
+ case 't': /* generate tiled output */
+ outtiled = TRUE;
+ break;
+ case 'w': /* tile width */
+ outtiled = TRUE;
+ deftilewidth = atoi(optarg);
+ break;
+ case 'B':
+ *mp++ = 'b'; *mp = '\0';
+ break;
+ case 'L':
+ *mp++ = 'l'; *mp = '\0';
+ break;
+ case 'M':
+ *mp++ = 'm'; *mp = '\0';
+ break;
+ case 'C':
+ *mp++ = 'c'; *mp = '\0';
+ break;
+ case 'x':
+ pageInSeq = 1;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage();
+ out = TIFFOpen(argv[argc-1], mode);
+ if (out == NULL)
+ return (-2);
+ if ((argc - optind) == 2)
+ pageNum = -1;
+ for (; optind < argc-1 ; optind++) {
+ char *imageCursor = argv[optind];
+ in = openSrcImage (&imageCursor);
+ if (in == NULL) {
+ (void) TIFFClose(out);
+ return (-3);
+ }
+ if (diroff != 0 && !TIFFSetSubDirectory(in, diroff)) {
+ TIFFError(TIFFFileName(in),
+ "Error, setting subdirectory at %#x", diroff);
+ (void) TIFFClose(in);
+ (void) TIFFClose(out);
+ return (1);
+ }
+ for (;;) {
+ config = defconfig;
+ compression = defcompression;
+ predictor = defpredictor;
+ fillorder = deffillorder;
+ rowsperstrip = defrowsperstrip;
+ tilewidth = deftilewidth;
+ tilelength = deftilelength;
+ g3opts = defg3opts;
+ if (!tiffcp(in, out) || !TIFFWriteDirectory(out)) {
+ (void) TIFFClose(in);
+ (void) TIFFClose(out);
+ return (1);
+ }
+ if (imageCursor) { /* seek next image directory */
+ if (!nextSrcImage(in, &imageCursor)) break;
+ }else
+ if (!TIFFReadDirectory(in)) break;
+ }
+ (void) TIFFClose(in);
+ }
+
+ (void) TIFFClose(out);
+ return (0);
+}
+
+
+static void
+processG3Options(char* cp)
+{
+ if( (cp = strchr(cp, ':')) ) {
+ if (defg3opts == (uint32) -1)
+ defg3opts = 0;
+ do {
+ cp++;
+ if (strneq(cp, "1d", 2))
+ defg3opts &= ~GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "2d", 2))
+ defg3opts |= GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "fill", 4))
+ defg3opts |= GROUP3OPT_FILLBITS;
+ else
+ usage();
+ } while( (cp = strchr(cp, ':')) );
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none")) {
+ defcompression = COMPRESSION_NONE;
+ } else if (streq(opt, "packbits")) {
+ defcompression = COMPRESSION_PACKBITS;
+ } else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ defcompression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "g3", 2)) {
+ processG3Options(opt);
+ defcompression = COMPRESSION_CCITTFAX3;
+ } else if (streq(opt, "g4")) {
+ defcompression = COMPRESSION_CCITTFAX4;
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ defpredictor = atoi(cp+1);
+ defcompression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ defpredictor = atoi(cp+1);
+ defcompression = COMPRESSION_ADOBE_DEFLATE;
+ } else if (strneq(opt, "jbig", 4)) {
+ defcompression = COMPRESSION_JBIG;
+ } else
+ return (0);
+ return (1);
+}
+
+char* stuff[] = {
+"usage: tiffcp [options] input... output",
+"where options are:",
+" -a append to output instead of overwriting",
+" -o offset set initial directory offset",
+" -p contig pack samples contiguously (e.g. RGBRGB...)",
+" -p separate store samples separately (e.g. RRR...GGG...BBB...)",
+" -s write output in strips",
+" -t write output in tiles",
+" -i ignore read errors",
+" -b file[,#] bias (dark) monochrome image to be subtracted from all others",
+" -,=% use % rather than , to separate image #'s (per Note below)",
+"",
+" -r # make each strip have no more than # rows",
+" -w # set output tile width (pixels)",
+" -l # set output tile length (pixels)",
+"",
+" -f lsb2msb force lsb-to-msb FillOrder for output",
+" -f msb2lsb force msb-to-lsb FillOrder for output",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c jbig compress output with ISO JBIG encoding",
+" -c packbits compress output with packbits encoding",
+" -c g3[:opts] compress output with CCITT Group 3 encoding",
+" -c g4 compress output with CCITT Group 4 encoding",
+" -c none use no compression algorithm on output",
+"",
+"Group 3 options:",
+" 1d use default CCITT Group 3 1D-encoding",
+" 2d use optional CCITT Group 3 2D-encoding",
+" fill byte-align EOL codes",
+"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+"",
+"Note that input filenames may be of the form filename,x,y,z",
+"where x, y, and z specify image numbers in the filename to copy.",
+"example: tiffcp -c none -b esp.tif,1 esp.tif,0 test.tif",
+" subtract 2nd image in esp.tif from 1st yielding uncompressed result test.tif",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, (uint16) -1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES,(uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_EXTRASAMPLES, (uint16) -1, TIFF_SHORT },
+ { TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_STONITS, 1, TIFF_DOUBLE },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+#define CopyTag(tag, count, type) cpTag(in, out, tag, count, type)
+
+typedef int (*copyFunc)
+ (TIFF* in, TIFF* out, uint32 l, uint32 w, uint16 samplesperpixel);
+static copyFunc pickCopyFunc(TIFF*, TIFF*, uint16, uint16);
+
+static int
+tiffcp(TIFF* in, TIFF* out)
+{
+ uint16 bitspersample, samplesperpixel;
+ uint16 input_compression, input_photometric;
+ copyFunc cf;
+ uint32 width, length;
+ struct cpTag* p;
+
+ CopyField(TIFFTAG_IMAGEWIDTH, width);
+ CopyField(TIFFTAG_IMAGELENGTH, length);
+ CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample);
+ CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
+ if (compression != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ else
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ TIFFGetFieldDefaulted(in, TIFFTAG_COMPRESSION, &input_compression);
+ TIFFGetFieldDefaulted(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
+ if (input_compression == COMPRESSION_JPEG) {
+ /* Force conversion to RGB */
+ TIFFSetField(in, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ } else if (input_photometric == PHOTOMETRIC_YCBCR) {
+ /* Otherwise, can't handle subsampled input */
+ uint16 subsamplinghor,subsamplingver;
+
+ TIFFGetFieldDefaulted(in, TIFFTAG_YCBCRSUBSAMPLING,
+ &subsamplinghor, &subsamplingver);
+ if (subsamplinghor!=1 || subsamplingver!=1) {
+ fprintf(stderr, "tiffcp: %s: Can't copy/convert subsampled image.\n",
+ TIFFFileName(in));
+ return FALSE;
+ }
+ }
+ if (compression == COMPRESSION_JPEG) {
+ if (input_photometric == PHOTOMETRIC_RGB &&
+ jpegcolormode == JPEGCOLORMODE_RGB)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
+ }
+ else if (compression == COMPRESSION_SGILOG
+ || compression == COMPRESSION_SGILOG24)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC,
+ samplesperpixel == 1 ?
+ PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
+ else
+ CopyTag(TIFFTAG_PHOTOMETRIC, 1, TIFF_SHORT);
+ if (fillorder != 0)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ else
+ CopyTag(TIFFTAG_FILLORDER, 1, TIFF_SHORT);
+ /*
+ * Will copy `Orientation' tag from input image
+ */
+ TIFFGetFieldDefaulted(in, TIFFTAG_ORIENTATION, &orientation);
+ switch (orientation) {
+ case ORIENTATION_BOTRIGHT:
+ case ORIENTATION_RIGHTBOT: /* XXX */
+ TIFFWarning(TIFFFileName(in), "using bottom-left orientation");
+ orientation = ORIENTATION_BOTLEFT;
+ /* fall thru... */
+ case ORIENTATION_LEFTBOT: /* XXX */
+ case ORIENTATION_BOTLEFT:
+ break;
+ case ORIENTATION_TOPRIGHT:
+ case ORIENTATION_RIGHTTOP: /* XXX */
+ default:
+ TIFFWarning(TIFFFileName(in), "using top-left orientation");
+ orientation = ORIENTATION_TOPLEFT;
+ /* fall thru... */
+ case ORIENTATION_LEFTTOP: /* XXX */
+ case ORIENTATION_TOPLEFT:
+ break;
+ }
+ TIFFSetField(out, TIFFTAG_ORIENTATION, orientation);
+ /*
+ * Choose tiles/strip for the output image according to
+ * the command line arguments (-tiles, -strips) and the
+ * structure of the input image.
+ */
+ if (outtiled == -1)
+ outtiled = TIFFIsTiled(in);
+ if (outtiled) {
+ /*
+ * Setup output file's tile width&height. If either
+ * is not specified, use either the value from the
+ * input image or, if nothing is defined, use the
+ * library default.
+ */
+ if (tilewidth == (uint32) -1)
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);
+ if (tilelength == (uint32) -1)
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);
+ TIFFDefaultTileSize(out, &tilewidth, &tilelength);
+ TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);
+ TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);
+ } else {
+ /*
+ * RowsPerStrip is left unspecified: use either the
+ * value from the input image or, if nothing is defined,
+ * use the library default.
+ */
+ if (rowsperstrip == (uint32) 0) {
+ if (!TIFFGetField(in, TIFFTAG_ROWSPERSTRIP,
+ &rowsperstrip)) {
+ rowsperstrip =
+ TIFFDefaultStripSize(out, rowsperstrip);
+ }
+ if (rowsperstrip > length && rowsperstrip != (uint32)-1)
+ rowsperstrip = length;
+ }
+ else if (rowsperstrip == (uint32) -1)
+ rowsperstrip = length;
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ }
+ if (config != (uint16) -1)
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ else
+ CopyField(TIFFTAG_PLANARCONFIG, config);
+ if (samplesperpixel <= 4)
+ CopyTag(TIFFTAG_TRANSFERFUNCTION, 4, TIFF_SHORT);
+ CopyTag(TIFFTAG_COLORMAP, 4, TIFF_SHORT);
+/* SMinSampleValue & SMaxSampleValue */
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_JBIG:
+ CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
+ CopyTag(TIFFTAG_FAXDCS, 1, TIFF_ASCII);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_ADOBE_DEFLATE:
+ case COMPRESSION_DEFLATE:
+ if (predictor != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ else
+ CopyField(TIFFTAG_PREDICTOR, predictor);
+ break;
+ case COMPRESSION_CCITTFAX3:
+ case COMPRESSION_CCITTFAX4:
+ if (compression == COMPRESSION_CCITTFAX3) {
+ if (g3opts != (uint32) -1)
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS,
+ g3opts);
+ else
+ CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);
+ } else
+ CopyTag(TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_BADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CLEANFAXDATA, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
+ break;
+ }
+ { uint32 len32;
+ void** data;
+ if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &len32, &data))
+ TIFFSetField(out, TIFFTAG_ICCPROFILE, len32, data);
+ }
+ { uint16 ninks;
+ const char* inknames;
+ if (TIFFGetField(in, TIFFTAG_NUMBEROFINKS, &ninks)) {
+ TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks);
+ if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) {
+ int inknameslen = strlen(inknames) + 1;
+ const char* cp = inknames;
+ while (ninks > 1) {
+ cp = strchr(cp, '\0');
+ if (cp) {
+ cp++;
+ inknameslen += (strlen(cp) + 1);
+ }
+ ninks--;
+ }
+ TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames);
+ }
+ }
+ }
+ {
+ unsigned short pg0, pg1;
+ if(pageInSeq == 1) {
+ if (pageNum < 0) /* only one input file */ {
+ if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1))
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
+ } else
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
+ } else
+ if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1)) {
+ if (pageNum < 0) /* only one input file */
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
+ else
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
+ }
+ }
+
+ for (p = tags; p < &tags[NTAGS]; p++)
+ CopyTag(p->tag, p->count, p->type);
+
+ cf = pickCopyFunc(in, out, bitspersample, samplesperpixel);
+ return (cf ? (*cf)(in, out, length, width, samplesperpixel) : FALSE);
+}
+
+/*
+ * Copy Functions.
+ */
+#define DECLAREcpFunc(x) \
+static int x(TIFF* in, TIFF* out, \
+ uint32 imagelength, uint32 imagewidth, tsample_t spp)
+
+#define DECLAREreadFunc(x) \
+static int x(TIFF* in, \
+ uint8* buf, uint32 imagelength, uint32 imagewidth, tsample_t spp)
+typedef int (*readFunc)(TIFF*, uint8*, uint32, uint32, tsample_t);
+
+#define DECLAREwriteFunc(x) \
+static int x(TIFF* out, \
+ uint8* buf, uint32 imagelength, uint32 imagewidth, tsample_t spp)
+typedef int (*writeFunc)(TIFF*, uint8*, uint32, uint32, tsample_t);
+
+/*
+ * Contig -> contig by scanline for rows/strip change.
+ */
+DECLAREcpFunc(cpContig2ContigByRow)
+{
+ tdata_t buf = _TIFFmalloc(TIFFScanlineSize(in));
+ uint32 row;
+
+ (void) imagewidth; (void) spp;
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, buf, row, 0) < 0 && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ if (TIFFWriteScanline(out, buf, row, 0) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+ _TIFFfree(buf);
+ return 1;
+bad:
+ _TIFFfree(buf);
+ return 0;
+}
+
+
+typedef void biasFn (void *image, void *bias, uint32 pixels);
+
+#define subtract(bits) \
+static void subtract##bits (void *i, void *b, uint32 pixels)\
+{\
+ uint##bits *image = i;\
+ uint##bits *bias = b;\
+ while (pixels--) {\
+ *image = *image > *bias ? *image-*bias : 0;\
+ image++, bias++; \
+ } \
+}
+
+subtract(8)
+subtract(16)
+subtract(32)
+
+static biasFn *lineSubtractFn (unsigned bits)
+{
+ switch (bits) {
+ case 8: return subtract8;
+ case 16: return subtract16;
+ case 32: return subtract32;
+ }
+ return NULL;
+}
+
+/*
+ * Contig -> contig by scanline while subtracting a bias image.
+ */
+DECLAREcpFunc(cpBiasedContig2Contig)
+{
+ if (spp == 1) {
+ tsize_t biasSize = TIFFScanlineSize(bias);
+ tsize_t bufSize = TIFFScanlineSize(in);
+ tdata_t buf, biasBuf;
+ uint32 biasWidth = 0, biasLength = 0;
+ TIFFGetField(bias, TIFFTAG_IMAGEWIDTH, &biasWidth);
+ TIFFGetField(bias, TIFFTAG_IMAGELENGTH, &biasLength);
+ if (biasSize == bufSize &&
+ imagelength == biasLength && imagewidth == biasWidth) {
+ uint16 sampleBits = 0;
+ biasFn *subtractLine;
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &sampleBits);
+ subtractLine = lineSubtractFn (sampleBits);
+ if (subtractLine) {
+ uint32 row;
+ buf = _TIFFmalloc(bufSize);
+ biasBuf = _TIFFmalloc(bufSize);
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, buf, row, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ if (TIFFReadScanline(bias, biasBuf, row, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read biased scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ subtractLine (buf, biasBuf, imagewidth);
+ if (TIFFWriteScanline(out, buf, row, 0) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+
+ _TIFFfree(buf);
+ _TIFFfree(biasBuf);
+ TIFFSetDirectory(bias,
+ TIFFCurrentDirectory(bias)); /* rewind */
+ return 1;
+bad:
+ _TIFFfree(buf);
+ _TIFFfree(biasBuf);
+ return 0;
+ } else {
+ TIFFError(TIFFFileName(in),
+ "No support for biasing %d bit pixels\n",
+ sampleBits);
+ return 0;
+ }
+ }
+ TIFFError(TIFFFileName(in),
+ "Bias image %s,%d\nis not the same size as %s,%d\n",
+ TIFFFileName(bias), TIFFCurrentDirectory(bias),
+ TIFFFileName(in), TIFFCurrentDirectory(in));
+ return 0;
+ } else {
+ TIFFError(TIFFFileName(in),
+ "Can't bias %s,%d as it has >1 Sample/Pixel\n",
+ TIFFFileName(in), TIFFCurrentDirectory(in));
+ return 0;
+ }
+
+}
+
+
+/*
+ * Strip -> strip for change in encoding.
+ */
+DECLAREcpFunc(cpDecodedStrips)
+{
+ tsize_t stripsize = TIFFStripSize(in);
+ tdata_t buf = _TIFFmalloc(stripsize);
+
+ (void) imagewidth; (void) spp;
+ if (buf) {
+ tstrip_t s, ns = TIFFNumberOfStrips(in);
+ uint32 row = 0;
+ for (s = 0; s < ns; s++) {
+ tsize_t cc = (row + rowsperstrip > imagelength) ?
+ TIFFVStripSize(in, imagelength - row) : stripsize;
+ if (TIFFReadEncodedStrip(in, s, buf, cc) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read strip %lu",
+ (unsigned long) s);
+ goto bad;
+ }
+ if (TIFFWriteEncodedStrip(out, s, buf, cc) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write strip %lu",
+ (unsigned long) s);
+ goto bad;
+ }
+ row += rowsperstrip;
+ }
+ _TIFFfree(buf);
+ return 1;
+ } else {
+ TIFFError(TIFFFileName(in),
+ "Error, can't allocate memory buffer of size %lu "
+ "to read strips", (unsigned long) stripsize);
+ return 0;
+ }
+
+bad:
+ _TIFFfree(buf);
+ return 0;
+}
+
+/*
+ * Separate -> separate by row for rows/strip change.
+ */
+DECLAREcpFunc(cpSeparate2SeparateByRow)
+{
+ tdata_t buf = _TIFFmalloc(TIFFScanlineSize(in));
+ uint32 row;
+ tsample_t s;
+
+ (void) imagewidth;
+ for (s = 0; s < spp; s++) {
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, buf, row, s) < 0 && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ if (TIFFWriteScanline(out, buf, row, s) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+ }
+ _TIFFfree(buf);
+ return 1;
+bad:
+ _TIFFfree(buf);
+ return 0;
+}
+
+/*
+ * Contig -> separate by row.
+ */
+DECLAREcpFunc(cpContig2SeparateByRow)
+{
+ tdata_t inbuf = _TIFFmalloc(TIFFScanlineSize(in));
+ tdata_t outbuf = _TIFFmalloc(TIFFScanlineSize(out));
+ register uint8 *inp, *outp;
+ register uint32 n;
+ uint32 row;
+ tsample_t s;
+
+ /* unpack channels */
+ for (s = 0; s < spp; s++) {
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, inbuf, row, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ inp = ((uint8*)inbuf) + s;
+ outp = (uint8*)outbuf;
+ for (n = imagewidth; n-- > 0;) {
+ *outp++ = *inp;
+ inp += spp;
+ }
+ if (TIFFWriteScanline(out, outbuf, row, s) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+ }
+ if (inbuf) _TIFFfree(inbuf);
+ if (outbuf) _TIFFfree(outbuf);
+ return 1;
+bad:
+ if (inbuf) _TIFFfree(inbuf);
+ if (outbuf) _TIFFfree(outbuf);
+ return 0;
+}
+
+/*
+ * Separate -> contig by row.
+ */
+DECLAREcpFunc(cpSeparate2ContigByRow)
+{
+ tdata_t inbuf = _TIFFmalloc(TIFFScanlineSize(in));
+ tdata_t outbuf = _TIFFmalloc(TIFFScanlineSize(out));
+ register uint8 *inp, *outp;
+ register uint32 n;
+ uint32 row;
+ tsample_t s;
+
+ for (row = 0; row < imagelength; row++) {
+ /* merge channels */
+ for (s = 0; s < spp; s++) {
+ if (TIFFReadScanline(in, inbuf, row, s) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ inp = (uint8*)inbuf;
+ outp = ((uint8*)outbuf) + s;
+ for (n = imagewidth; n-- > 0;) {
+ *outp = *inp++;
+ outp += spp;
+ }
+ }
+ if (TIFFWriteScanline(out, outbuf, row, 0) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+ if (inbuf) _TIFFfree(inbuf);
+ if (outbuf) _TIFFfree(outbuf);
+ return 1;
+bad:
+ if (inbuf) _TIFFfree(inbuf);
+ if (outbuf) _TIFFfree(outbuf);
+ return 0;
+}
+
+static void
+cpStripToTile(uint8* out, uint8* in,
+ uint32 rows, uint32 cols, int outskew, int inskew)
+{
+ while (rows-- > 0) {
+ uint32 j = cols;
+ while (j-- > 0)
+ *out++ = *in++;
+ out += outskew;
+ in += inskew;
+ }
+}
+
+static void
+cpContigBufToSeparateBuf(uint8* out, uint8* in,
+ uint32 rows, uint32 cols, int outskew, int inskew, tsample_t spp,
+ int bytes_per_sample )
+{
+ while (rows-- > 0) {
+ uint32 j = cols;
+ while (j-- > 0)
+ {
+ int n = bytes_per_sample;
+
+ while( n-- ) {
+ *out++ = *in++;
+ }
+ in += (spp-1) * bytes_per_sample;
+ }
+ out += outskew;
+ in += inskew;
+ }
+}
+
+static void
+cpSeparateBufToContigBuf(uint8* out, uint8* in,
+ uint32 rows, uint32 cols, int outskew, int inskew, tsample_t spp,
+ int bytes_per_sample)
+{
+ while (rows-- > 0) {
+ uint32 j = cols;
+ while (j-- > 0) {
+ int n = bytes_per_sample;
+
+ while( n-- ) {
+ *out++ = *in++;
+ }
+ out += (spp-1)*bytes_per_sample;
+ }
+ out += outskew;
+ in += inskew;
+ }
+}
+
+static int
+cpImage(TIFF* in, TIFF* out, readFunc fin, writeFunc fout,
+ uint32 imagelength, uint32 imagewidth, tsample_t spp)
+{
+ int status = 0;
+ tdata_t buf = NULL;
+ tsize_t scanlinesize = TIFFRasterScanlineSize(in);
+ tsize_t bytes = scanlinesize * (tsize_t)imagelength;
+ /*
+ * XXX: Check for integer overflow.
+ */
+ if (scanlinesize
+ && imagelength
+ && bytes / (tsize_t)imagelength == scanlinesize) {
+ buf = _TIFFmalloc(bytes);
+ if (buf) {
+ if ((*fin)(in, (uint8*)buf, imagelength,
+ imagewidth, spp)) {
+ status = (*fout)(out, (uint8*)buf,
+ imagelength, imagewidth, spp);
+ }
+ _TIFFfree(buf);
+ } else {
+ TIFFError(TIFFFileName(in),
+ "Error, can't allocate space for image buffer");
+ }
+ } else {
+ TIFFError(TIFFFileName(in), "Error, no space for image buffer");
+ }
+
+ return status;
+}
+
+DECLAREreadFunc(readContigStripsIntoBuffer)
+{
+ tsize_t scanlinesize = TIFFScanlineSize(in);
+ uint8* bufp = buf;
+ uint32 row;
+
+ (void) imagewidth; (void) spp;
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, (tdata_t) bufp, row, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ return 0;
+ }
+ bufp += scanlinesize;
+ }
+
+ return 1;
+}
+
+DECLAREreadFunc(readSeparateStripsIntoBuffer)
+{
+ int status = 1;
+ tsize_t scanlinesize = TIFFScanlineSize(in);
+ tdata_t scanline = _TIFFmalloc(scanlinesize);
+ if (!scanlinesize)
+ return 0;
+
+ (void) imagewidth;
+ if (scanline) {
+ uint8* bufp = (uint8*) buf;
+ uint32 row;
+ tsample_t s;
+ for (row = 0; row < imagelength; row++) {
+ /* merge channels */
+ for (s = 0; s < spp; s++) {
+ uint8* bp = bufp + s;
+ tsize_t n = scanlinesize;
+ uint8* sbuf = scanline;
+
+ if (TIFFReadScanline(in, scanline, row, s) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ status = 0;
+ goto done;
+ }
+ while (n-- > 0)
+ *bp = *sbuf++, bp += spp;
+ }
+ bufp += scanlinesize * spp;
+ }
+ }
+
+done:
+ _TIFFfree(scanline);
+ return status;
+}
+
+DECLAREreadFunc(readContigTilesIntoBuffer)
+{
+ int status = 1;
+ tdata_t tilebuf = _TIFFmalloc(TIFFTileSize(in));
+ uint32 imagew = TIFFScanlineSize(in);
+ uint32 tilew = TIFFTileRowSize(in);
+ int iskew = imagew - tilew;
+ uint8* bufp = (uint8*) buf;
+ uint32 tw, tl;
+ uint32 row;
+
+ (void) spp;
+ if (tilebuf == 0)
+ return 0;
+ (void) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
+ (void) TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
+
+ for (row = 0; row < imagelength; row += tl) {
+ uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
+ uint32 colb = 0;
+ uint32 col;
+
+ for (col = 0; col < imagewidth; col += tw) {
+ if (TIFFReadTile(in, tilebuf, col, row, 0, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read tile at %lu %lu",
+ (unsigned long) col,
+ (unsigned long) row);
+ status = 0;
+ goto done;
+ }
+ if (colb + tilew > imagew) {
+ uint32 width = imagew - colb;
+ uint32 oskew = tilew - width;
+ cpStripToTile(bufp + colb,
+ tilebuf, nrow, width,
+ oskew + iskew, oskew );
+ } else
+ cpStripToTile(bufp + colb,
+ tilebuf, nrow, tilew,
+ iskew, 0);
+ colb += tilew;
+ }
+ bufp += imagew * nrow;
+ }
+done:
+ _TIFFfree(tilebuf);
+ return status;
+}
+
+DECLAREreadFunc(readSeparateTilesIntoBuffer)
+{
+ int status = 1;
+ uint32 imagew = TIFFRasterScanlineSize(in);
+ uint32 tilew = TIFFTileRowSize(in);
+ int iskew = imagew - tilew*spp;
+ tdata_t tilebuf = _TIFFmalloc(TIFFTileSize(in));
+ uint8* bufp = (uint8*) buf;
+ uint32 tw, tl;
+ uint32 row;
+ uint16 bps, bytes_per_sample;
+
+ if (tilebuf == 0)
+ return 0;
+ (void) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
+ (void) TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
+ (void) TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bps);
+ assert( bps % 8 == 0 );
+ bytes_per_sample = bps/8;
+
+ for (row = 0; row < imagelength; row += tl) {
+ uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
+ uint32 colb = 0;
+ uint32 col;
+
+ for (col = 0; col < imagewidth; col += tw) {
+ tsample_t s;
+
+ for (s = 0; s < spp; s++) {
+ if (TIFFReadTile(in, tilebuf, col, row, 0, s) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read tile at %lu %lu, "
+ "sample %lu",
+ (unsigned long) col,
+ (unsigned long) row,
+ (unsigned long) s);
+ status = 0;
+ goto done;
+ }
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ if (colb + tilew*spp > imagew) {
+ uint32 width = imagew - colb;
+ int oskew = tilew*spp - width;
+ cpSeparateBufToContigBuf(
+ bufp+colb+s*bytes_per_sample,
+ tilebuf, nrow,
+ width/(spp*bytes_per_sample),
+ oskew + iskew,
+ oskew/spp, spp,
+ bytes_per_sample);
+ } else
+ cpSeparateBufToContigBuf(
+ bufp+colb+s*bytes_per_sample,
+ tilebuf, nrow, tw,
+ iskew, 0, spp,
+ bytes_per_sample);
+ }
+ colb += tilew*spp;
+ }
+ bufp += imagew * nrow;
+ }
+done:
+ _TIFFfree(tilebuf);
+ return status;
+}
+
+DECLAREwriteFunc(writeBufferToContigStrips)
+{
+ uint32 row, rowsperstrip;
+ tstrip_t strip = 0;
+
+ (void) imagewidth; (void) spp;
+ (void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ for (row = 0; row < imagelength; row += rowsperstrip) {
+ uint32 nrows = (row+rowsperstrip > imagelength) ?
+ imagelength-row : rowsperstrip;
+ tsize_t stripsize = TIFFVStripSize(out, nrows);
+ if (TIFFWriteEncodedStrip(out, strip++, buf, stripsize) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write strip %u", strip - 1);
+ return 0;
+ }
+ buf += stripsize;
+ }
+ return 1;
+}
+
+DECLAREwriteFunc(writeBufferToSeparateStrips)
+{
+ uint32 rowsize = imagewidth * spp;
+ uint32 rowsperstrip;
+ tdata_t obuf = _TIFFmalloc(TIFFStripSize(out));
+ tstrip_t strip = 0;
+ tsample_t s;
+
+ if (obuf == NULL)
+ return (0);
+ (void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ for (s = 0; s < spp; s++) {
+ uint32 row;
+ for (row = 0; row < imagelength; row += rowsperstrip) {
+ uint32 nrows = (row+rowsperstrip > imagelength) ?
+ imagelength-row : rowsperstrip;
+ tsize_t stripsize = TIFFVStripSize(out, nrows);
+
+ cpContigBufToSeparateBuf(
+ obuf, (uint8*) buf + row*rowsize + s,
+ nrows, imagewidth, 0, 0, spp, 1);
+ if (TIFFWriteEncodedStrip(out, strip++, obuf, stripsize) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write strip %u",
+ strip - 1);
+ _TIFFfree(obuf);
+ return 0;
+ }
+ }
+ }
+ _TIFFfree(obuf);
+ return 1;
+
+}
+
+DECLAREwriteFunc(writeBufferToContigTiles)
+{
+ uint32 imagew = TIFFScanlineSize(out);
+ uint32 tilew = TIFFTileRowSize(out);
+ int iskew = imagew - tilew;
+ tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
+ uint8* bufp = (uint8*) buf;
+ uint32 tl, tw;
+ uint32 row;
+
+ (void) spp;
+ if (obuf == NULL)
+ return 0;
+ (void) TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
+ (void) TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
+ for (row = 0; row < imagelength; row += tilelength) {
+ uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
+ uint32 colb = 0;
+ uint32 col;
+
+ for (col = 0; col < imagewidth; col += tw) {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ if (colb + tilew > imagew) {
+ uint32 width = imagew - colb;
+ int oskew = tilew - width;
+ cpStripToTile(obuf, bufp + colb, nrow, width,
+ oskew, oskew + iskew);
+ } else
+ cpStripToTile(obuf, bufp + colb, nrow, tilew,
+ 0, iskew);
+ if (TIFFWriteTile(out, obuf, col, row, 0, 0) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write tile at %lu %lu",
+ (unsigned long) col,
+ (unsigned long) row);
+ _TIFFfree(obuf);
+ return 0;
+ }
+ colb += tilew;
+ }
+ bufp += nrow * imagew;
+ }
+ _TIFFfree(obuf);
+ return 1;
+}
+
+DECLAREwriteFunc(writeBufferToSeparateTiles)
+{
+ uint32 imagew = TIFFScanlineSize(out);
+ tsize_t tilew = TIFFTileRowSize(out);
+ uint32 iimagew = TIFFRasterScanlineSize(out);
+ int iskew = iimagew - tilew*spp;
+ tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
+ uint8* bufp = (uint8*) buf;
+ uint32 tl, tw;
+ uint32 row;
+ uint16 bps, bytes_per_sample;
+
+ if (obuf == NULL)
+ return 0;
+ (void) TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
+ (void) TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
+ (void) TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
+ assert( bps % 8 == 0 );
+ bytes_per_sample = bps/8;
+
+ for (row = 0; row < imagelength; row += tl) {
+ uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
+ uint32 colb = 0;
+ uint32 col;
+
+ for (col = 0; col < imagewidth; col += tw) {
+ tsample_t s;
+ for (s = 0; s < spp; s++) {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ if (colb + tilew > imagew) {
+ uint32 width = (imagew - colb);
+ int oskew = tilew - width;
+
+ cpContigBufToSeparateBuf(obuf,
+ bufp + (colb*spp) + s,
+ nrow, width/bytes_per_sample,
+ oskew, (oskew*spp)+iskew, spp,
+ bytes_per_sample);
+ } else
+ cpContigBufToSeparateBuf(obuf,
+ bufp + (colb*spp) + s,
+ nrow, tilewidth,
+ 0, iskew, spp,
+ bytes_per_sample);
+ if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write tile at %lu %lu "
+ "sample %lu",
+ (unsigned long) col,
+ (unsigned long) row,
+ (unsigned long) s);
+ _TIFFfree(obuf);
+ return 0;
+ }
+ }
+ colb += tilew;
+ }
+ bufp += nrow * iimagew;
+ }
+ _TIFFfree(obuf);
+ return 1;
+}
+
+/*
+ * Contig strips -> contig tiles.
+ */
+DECLAREcpFunc(cpContigStrips2ContigTiles)
+{
+ return cpImage(in, out,
+ readContigStripsIntoBuffer,
+ writeBufferToContigTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig strips -> separate tiles.
+ */
+DECLAREcpFunc(cpContigStrips2SeparateTiles)
+{
+ return cpImage(in, out,
+ readContigStripsIntoBuffer,
+ writeBufferToSeparateTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate strips -> contig tiles.
+ */
+DECLAREcpFunc(cpSeparateStrips2ContigTiles)
+{
+ return cpImage(in, out,
+ readSeparateStripsIntoBuffer,
+ writeBufferToContigTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate strips -> separate tiles.
+ */
+DECLAREcpFunc(cpSeparateStrips2SeparateTiles)
+{
+ return cpImage(in, out,
+ readSeparateStripsIntoBuffer,
+ writeBufferToSeparateTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig strips -> contig tiles.
+ */
+DECLAREcpFunc(cpContigTiles2ContigTiles)
+{
+ return cpImage(in, out,
+ readContigTilesIntoBuffer,
+ writeBufferToContigTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig tiles -> separate tiles.
+ */
+DECLAREcpFunc(cpContigTiles2SeparateTiles)
+{
+ return cpImage(in, out,
+ readContigTilesIntoBuffer,
+ writeBufferToSeparateTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate tiles -> contig tiles.
+ */
+DECLAREcpFunc(cpSeparateTiles2ContigTiles)
+{
+ return cpImage(in, out,
+ readSeparateTilesIntoBuffer,
+ writeBufferToContigTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate tiles -> separate tiles (tile dimension change).
+ */
+DECLAREcpFunc(cpSeparateTiles2SeparateTiles)
+{
+ return cpImage(in, out,
+ readSeparateTilesIntoBuffer,
+ writeBufferToSeparateTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig tiles -> contig tiles (tile dimension change).
+ */
+DECLAREcpFunc(cpContigTiles2ContigStrips)
+{
+ return cpImage(in, out,
+ readContigTilesIntoBuffer,
+ writeBufferToContigStrips,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig tiles -> separate strips.
+ */
+DECLAREcpFunc(cpContigTiles2SeparateStrips)
+{
+ return cpImage(in, out,
+ readContigTilesIntoBuffer,
+ writeBufferToSeparateStrips,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate tiles -> contig strips.
+ */
+DECLAREcpFunc(cpSeparateTiles2ContigStrips)
+{
+ return cpImage(in, out,
+ readSeparateTilesIntoBuffer,
+ writeBufferToContigStrips,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate tiles -> separate strips.
+ */
+DECLAREcpFunc(cpSeparateTiles2SeparateStrips)
+{
+ return cpImage(in, out,
+ readSeparateTilesIntoBuffer,
+ writeBufferToSeparateStrips,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Select the appropriate copy function to use.
+ */
+static copyFunc
+pickCopyFunc(TIFF* in, TIFF* out, uint16 bitspersample, uint16 samplesperpixel)
+{
+ uint16 shortv;
+ uint32 w, l, tw, tl;
+ int bychunk;
+
+ (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
+ if (shortv != config && bitspersample != 8 && samplesperpixel > 1) {
+ fprintf(stderr,
+"%s: Cannot handle different planar configuration w/ bits/sample != 8\n",
+ TIFFFileName(in));
+ return (NULL);
+ }
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &l);
+ if (!(TIFFIsTiled(out) || TIFFIsTiled(in))) {
+ uint32 irps = (uint32) -1L;
+ TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &irps);
+ /* if biased, force decoded copying to allow image subtraction */
+ bychunk = !bias && (rowsperstrip == irps);
+ }else{ /* either in or out is tiled */
+ if (bias) {
+ fprintf(stderr,
+"%s: Cannot handle tiled configuration w/bias image\n",
+ TIFFFileName(in));
+ return (NULL);
+ }
+ if (TIFFIsTiled(out)) {
+ if (!TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw))
+ tw = w;
+ if (!TIFFGetField(in, TIFFTAG_TILELENGTH, &tl))
+ tl = l;
+ bychunk = (tw == tilewidth && tl == tilelength);
+ } else { /* out's not, so in must be tiled */
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
+ bychunk = (tw == w && tl == rowsperstrip);
+ }
+ }
+#define T 1
+#define F 0
+#define pack(a,b,c,d,e) ((long)(((a)<<11)|((b)<<3)|((c)<<2)|((d)<<1)|(e)))
+ switch(pack(shortv,config,TIFFIsTiled(in),TIFFIsTiled(out),bychunk)) {
+/* Strips -> Tiles */
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,T,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,T,T):
+ return cpContigStrips2ContigTiles;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,T,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,T,T):
+ return cpContigStrips2SeparateTiles;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,T,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,T,T):
+ return cpSeparateStrips2ContigTiles;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,T):
+ return cpSeparateStrips2SeparateTiles;
+/* Tiles -> Tiles */
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,T,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,T,T):
+ return cpContigTiles2ContigTiles;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,T,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,T,T):
+ return cpContigTiles2SeparateTiles;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,T,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,T,T):
+ return cpSeparateTiles2ContigTiles;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,T):
+ return cpSeparateTiles2SeparateTiles;
+/* Tiles -> Strips */
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,F,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,F,T):
+ return cpContigTiles2ContigStrips;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,F,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,F,T):
+ return cpContigTiles2SeparateStrips;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,F,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,F,T):
+ return cpSeparateTiles2ContigStrips;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,T):
+ return cpSeparateTiles2SeparateStrips;
+/* Strips -> Strips */
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,F,F):
+ return bias ? cpBiasedContig2Contig : cpContig2ContigByRow;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,F,T):
+ return cpDecodedStrips;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,F,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,F,T):
+ return cpContig2SeparateByRow;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,F,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,F,T):
+ return cpSeparate2ContigByRow;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,T):
+ return cpSeparate2SeparateByRow;
+ }
+#undef pack
+#undef F
+#undef T
+ fprintf(stderr, "tiffcp: %s: Don't know how to copy/convert image.\n",
+ TIFFFileName(in));
+ return (NULL);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffcrop.c b/tiff/tools/tiffcrop.c
new file mode 100644
index 0000000..fa057c5
--- /dev/null
+++ b/tiff/tools/tiffcrop.c
@@ -0,0 +1,9012 @@
+/* $Id: tiffcrop.c,v 1.3.2.12 2010-06-11 22:24:23 bfriesen Exp $ */
+
+/* tiffcrop.c -- a port of tiffcp.c extended to include manipulations of
+ * the image data through additional options listed below
+ *
+ * Original code:
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ * Additions (c) Richard Nolde 2006-2009
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS OR ANY OTHER COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
+ * OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Some portions of the current code are derived from tiffcp, primarly in
+ * the areas of lowlevel reading and writing of TAGS, scanlines and tiles though
+ * some of the original functions have been extended to support arbitrary bit
+ * depths. These functions are presented at the top of this file.
+ *
+ * Add support for the options below to extract sections of image(s)
+ * and to modify the whole image or selected portions of each image by
+ * rotations, mirroring, and colorscale/colormap inversion of selected
+ * types of TIFF images when appropriate. Some color model dependent
+ * functions are restricted to bilevel or 8 bit per sample data.
+ * See the man page for the full explanations.
+ *
+ * New Options:
+ * -h Display the syntax guide.
+ * -v Report the version and last build date for tiffcrop and libtiff.
+ * -z x1,y1,x2,y2:x3,y3,x4,y4:..xN,yN,xN + 1, yN + 1
+ * Specify a series of coordinates to define rectangular
+ * regions by the top left and lower right corners.
+ * -e c|d|i|m|s export mode for images and selections from input images
+ * combined All images and selections are written to a single file (default)
+ * with multiple selections from one image combined into a single image
+ * divided All images and selections are written to a single file
+ * with each selection from one image written to a new image
+ * image Each input image is written to a new file (numeric filename sequence)
+ * with multiple selections from the image combined into one image
+ * multiple Each input image is written to a new file (numeric filename sequence)
+ * with each selection from the image written to a new image
+ * separated Individual selections from each image are written to separate files
+ * -U units [in, cm, px ] inches, centimeters or pixels
+ * -H # Set horizontal resolution of output images to #
+ * -V # Set vertical resolution of output images to #
+ * -J # Horizontal margin of output page to # expressed in current
+ * units when sectioning image into columns x rows
+ * using the -S cols:rows option.
+ * -K # Vertical margin of output page to # expressed in current
+ * units when sectioning image into columns x rows
+ * using the -S cols:rows option.
+ * -X # Horizontal dimension of region to extract expressed in current
+ * units
+ * -Y # Vertical dimension of region to extract expressed in current
+ * units
+ * -O orient Orientation for output image, portrait, landscape, auto
+ * -P page Page size for output image segments, eg letter, legal, tabloid,
+ * etc.
+ * -S cols:rows Divide the image into equal sized segments using cols across
+ * and rows down
+ * -E t|l|r|b Edge to use as origin
+ * -m #,#,#,# Margins from edges for selection: top, left, bottom, right
+ * (commas separated)
+ * -Z #:#,#:# Zones of the image designated as zone X of Y,
+ * eg 1:3 would be first of three equal portions measured
+ * from reference edge
+ * -N odd|even|#,#-#,#|last
+ * Select sequences and/or ranges of images within file
+ * to process. The words odd or even may be used to specify
+ * all odd or even numbered images the word last may be used
+ * in place of a number in the sequence to indicate the final
+ * image in the file without knowing how many images there are.
+ * -R # Rotate image or crop selection by 90,180,or 270 degrees
+ * clockwise
+ * -F h|v Flip (mirror) image or crop selection horizontally
+ * or vertically
+ * -I [black|white|data|both]
+ * Invert color space, eg dark to light for bilevel and grayscale images
+ * If argument is white or black, set the PHOTOMETRIC_INTERPRETATION
+ * tag to MinIsBlack or MinIsWhite without altering the image data
+ * If the argument is data or both, the image data are modified:
+ * both inverts the data and the PHOTOMETRIC_INTERPRETATION tag,
+ * data inverts the data but not the PHOTOMETRIC_INTERPRETATION tag
+ * -D input:<filename1>,output:<filename2>,format:<raw|txt>,level:N,debug:N
+ * Dump raw data for input and/or output images to individual files
+ * in raw (binary) format or text (ASCII) representing binary data
+ * as strings of 1s and 0s. The filename arguments are used as stems
+ * from which individual files are created for each image. Text format
+ * includes annotations for image parameters and scanline info. Level
+ * selects which functions dump data, with higher numbers selecting
+ * lower level, scanline level routines. Debug reports a limited set
+ * of messages to monitor progess without enabling dump logs.
+ */
+
+static char tiffcrop_version_id[] = "2.2";
+static char tiffcrop_rev_date[] = "11-03-2009";
+
+#include "tif_config.h"
+#include "tiffiop.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#include "tiffio.h"
+
+#if defined(VMS)
+# define unlink delete
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#ifndef streq
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#endif
+#define strneq(a,b,n) (strncmp((a),(b),(n)) == 0)
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * Definitions and data structures required to support cropping and image
+ * manipulations.
+ */
+
+#define EDGE_TOP 1
+#define EDGE_LEFT 2
+#define EDGE_BOTTOM 3
+#define EDGE_RIGHT 4
+#define EDGE_CENTER 5
+
+#define MIRROR_HORIZ 1
+#define MIRROR_VERT 2
+#define MIRROR_BOTH 3
+#define ROTATECW_90 8
+#define ROTATECW_180 16
+#define ROTATECW_270 32
+#define ROTATE_ANY ROTATECW_90 || ROTATECW_180 || ROTATECW_270
+
+#define CROP_NONE 0
+#define CROP_MARGINS 1
+#define CROP_WIDTH 2
+#define CROP_LENGTH 4
+#define CROP_ZONES 8
+#define CROP_REGIONS 16
+#define CROP_ROTATE 32
+#define CROP_MIRROR 64
+#define CROP_INVERT 128
+
+/* Modes for writing out images and selections */
+#define ONE_FILE_COMPOSITE 0 /* One file, sections combined sections */
+#define ONE_FILE_SEPARATED 1 /* One file, sections to new IFDs */
+#define FILE_PER_IMAGE_COMPOSITE 2 /* One file per image, combined sections */
+#define FILE_PER_IMAGE_SEPARATED 3 /* One file per input image */
+#define FILE_PER_SELECTION 4 /* One file per selection */
+
+#define COMPOSITE_IMAGES 0 /* Selections combined into one image */
+#define SEPARATED_IMAGES 1 /* Selections saved to separate images */
+
+#define STRIP 1
+#define TILE 2
+
+#define MAX_REGIONS 8 /* number of regions to extract from a single page */
+#define MAX_OUTBUFFS 8 /* must match larger of zones or regions */
+#define MAX_SECTIONS 32 /* number of sections per page to write to output */
+#define MAX_IMAGES 2048 /* number of images in descrete list, not in the file */
+#define MAX_SAMPLES 8 /* maximum number of samples per pixel supported */
+#define MAX_BITS_PER_SAMPLE 64 /* maximum bit depth supported */
+
+#define DUMP_NONE 0
+#define DUMP_TEXT 1
+#define DUMP_RAW 2
+
+/* Offsets into buffer for margins and fixed width and length segments */
+struct offset {
+ uint32 tmargin;
+ uint32 lmargin;
+ uint32 bmargin;
+ uint32 rmargin;
+ uint32 crop_width;
+ uint32 crop_length;
+ uint32 startx;
+ uint32 endx;
+ uint32 starty;
+ uint32 endy;
+};
+
+/* Description of a zone within the image. Position 1 of 3 zones would be
+ * the first third of the image. These are computed after margins and
+ * width/length requests are applied so that you can extract multiple
+ * zones from within a larger region for OCR or barcode recognition.
+ */
+
+struct buffinfo {
+ uint32 size; /* size of this buffer */
+ unsigned char *buffer; /* address of the allocated buffer */
+};
+
+struct zone {
+ int position; /* ordinal of segment to be extracted */
+ int total; /* total equal sized divisions of crop area */
+ };
+
+struct pageseg {
+ uint32 x1; /* index of left edge */
+ uint32 x2; /* index of right edge */
+ uint32 y1; /* index of top edge */
+ uint32 y2; /* index of bottom edge */
+ int position; /* ordinal of segment to be extracted */
+ int total; /* total equal sized divisions of crop area */
+ uint32 buffsize; /* size of buffer needed to hold the cropped zone */
+};
+
+struct coordpairs {
+ double X1; /* index of left edge in current units */
+ double X2; /* index of right edge in current units */
+ double Y1; /* index of top edge in current units */
+ double Y2; /* index of bottom edge in current units */
+};
+
+struct region {
+ uint32 x1; /* pixel offset of left edge */
+ uint32 x2; /* pixel offset of right edge */
+ uint32 y1; /* pixel offset of top edge */
+ uint32 y2; /* picel offset of bottom edge */
+ uint32 width; /* width in pixels */
+ uint32 length; /* length in pixels */
+ uint32 buffsize; /* size of buffer needed to hold the cropped region */
+ unsigned char *buffptr; /* address of start of the region */
+};
+
+/* Cropping parameters from command line and image data
+ * Note: This should be renamed to proc_opts and expanded to include all current globals
+ * if possible, but each function that accesses global variables will have to be redone.
+ */
+struct crop_mask {
+ double width; /* Selection width for master crop region in requested units */
+ double length; /* Selection length for master crop region in requesed units */
+ double margins[4]; /* Top, left, bottom, right margins */
+ float xres; /* Horizontal resolution read from image*/
+ float yres; /* Vertical resolution read from image */
+ uint32 combined_width; /* Width of combined cropped zones */
+ uint32 combined_length; /* Length of combined cropped zones */
+ uint32 bufftotal; /* Size of buffer needed to hold all the cropped region */
+ uint16 img_mode; /* Composite or separate images created from zones or regions */
+ uint16 exp_mode; /* Export input images or selections to one or more files */
+ uint16 crop_mode; /* Crop options to be applied */
+ uint16 res_unit; /* Resolution unit for margins and selections */
+ uint16 edge_ref; /* Reference edge for sections extraction and combination */
+ uint16 rotation; /* Clockwise rotation of the extracted region or image */
+ uint16 mirror; /* Mirror extracted region or image horizontally or vertically */
+ uint16 invert; /* Invert the color map of image or region */
+ uint16 photometric; /* Status of photometric interpretation for inverted image */
+ uint16 selections; /* Number of regions or zones selected */
+ uint16 regions; /* Number of regions delimited by corner coordinates */
+ struct region regionlist[MAX_REGIONS]; /* Regions within page or master crop region */
+ uint16 zones; /* Number of zones delimited by Ordinal:Total requested */
+ struct zone zonelist[MAX_REGIONS]; /* Zones indices to define a region */
+ struct coordpairs corners[MAX_REGIONS]; /* Coordinates of upper left and lower right corner */
+};
+
+#define MAX_PAPERNAMES 49
+#define MAX_PAPERNAME_LENGTH 15
+#define DEFAULT_RESUNIT RESUNIT_INCH
+#define DEFAULT_PAGE_HEIGHT 14.0
+#define DEFAULT_PAGE_WIDTH 8.5
+#define DEFAULT_RESOLUTION 300
+#define DEFAULT_PAPER_SIZE "legal"
+
+#define ORIENTATION_NONE 0
+#define ORIENTATION_PORTRAIT 1
+#define ORIENTATION_LANDSCAPE 2
+#define ORIENTATION_SEASCAPE 4
+#define ORIENTATION_AUTO 16
+
+#define PAGE_MODE_NONE 0
+#define PAGE_MODE_RESOLUTION 1
+#define PAGE_MODE_PAPERSIZE 2
+#define PAGE_MODE_MARGINS 4
+#define PAGE_MODE_ROWSCOLS 8
+
+#define INVERT_DATA_ONLY 10
+#define INVERT_DATA_AND_TAG 11
+
+struct paperdef {
+ char name[MAX_PAPERNAME_LENGTH];
+ double width;
+ double length;
+ double asratio;
+ };
+
+/* European page sizes corrected from update sent by
+ * thomas . jarosch @ intra2net . com on 5/7/2010
+ * Paper Size Width Length Aspect Ratio */
+struct paperdef PaperTable[MAX_PAPERNAMES] = {
+ {"default", 8.500, 14.000, 0.607},
+ {"pa4", 8.264, 11.000, 0.751},
+ {"letter", 8.500, 11.000, 0.773},
+ {"legal", 8.500, 14.000, 0.607},
+ {"half-letter", 8.500, 5.514, 1.542},
+ {"executive", 7.264, 10.528, 0.690},
+ {"tabloid", 11.000, 17.000, 0.647},
+ {"11x17", 11.000, 17.000, 0.647},
+ {"ledger", 17.000, 11.000, 1.545},
+ {"archa", 9.000, 12.000, 0.750},
+ {"archb", 12.000, 18.000, 0.667},
+ {"archc", 18.000, 24.000, 0.750},
+ {"archd", 24.000, 36.000, 0.667},
+ {"arche", 36.000, 48.000, 0.750},
+ {"csheet", 17.000, 22.000, 0.773},
+ {"dsheet", 22.000, 34.000, 0.647},
+ {"esheet", 34.000, 44.000, 0.773},
+ {"superb", 11.708, 17.042, 0.687},
+ {"commercial", 4.139, 9.528, 0.434},
+ {"monarch", 3.889, 7.528, 0.517},
+ {"envelope-dl", 4.333, 8.681, 0.499},
+ {"envelope-c5", 6.389, 9.028, 0.708},
+ {"europostcard", 4.139, 5.833, 0.710},
+ {"a0", 33.110, 46.811, 0.707},
+ {"a1", 23.386, 33.110, 0.706},
+ {"a2", 16.535, 23.386, 0.707},
+ {"a3", 11.693, 16.535, 0.707},
+ {"a4", 8.268, 11.693, 0.707},
+ {"a5", 5.827, 8.268, 0.705},
+ {"a6", 4.134, 5.827, 0.709},
+ {"a7", 2.913, 4.134, 0.705},
+ {"a8", 2.047, 2.913, 0.703},
+ {"a9", 1.457, 2.047, 0.712},
+ {"a10", 1.024, 1.457, 0.703},
+ {"b0", 39.370, 55.669, 0.707},
+ {"b1", 27.835, 39.370, 0.707},
+ {"b2", 19.685, 27.835, 0.707},
+ {"b3", 13.898, 19.685, 0.706},
+ {"b4", 9.843, 13.898, 0.708},
+ {"b5", 6.929, 9.843, 0.704},
+ {"b6", 4.921, 6.929, 0.710},
+ {"c0", 36.102, 51.063, 0.707},
+ {"c1", 25.512, 36.102, 0.707},
+ {"c2", 18.031, 25.512, 0.707},
+ {"c3", 12.756, 18.031, 0.707},
+ {"c4", 9.016, 12.756, 0.707},
+ {"c5", 6.378, 9.016, 0.707},
+ {"c6", 4.488, 6.378, 0.704},
+ {"", 0.000, 0.000, 1.000},
+};
+
+/* Structure to define in input image parameters */
+struct image_data {
+ float xres;
+ float yres;
+ uint32 width;
+ uint32 length;
+ uint16 res_unit;
+ uint16 bps;
+ uint16 spp;
+ uint16 planar;
+ uint16 photometric;
+ uint16 orientation;
+ uint16 adjustments;
+};
+
+/* Structure to define the output image modifiers */
+struct pagedef {
+ char name[16];
+ double width; /* width in pixels */
+ double length; /* length in pixels */
+ double hmargin; /* margins to subtract from width of sections */
+ double vmargin; /* margins to subtract from height of sections */
+ double hres; /* horizontal resolution for output */
+ double vres; /* vertical resolution for output */
+ uint32 mode; /* bitmask of modifiers to page format */
+ uint16 res_unit; /* resolution unit for output image */
+ unsigned int rows; /* number of section rows */
+ unsigned int cols; /* number of section cols */
+ unsigned int orient; /* portrait, landscape, seascape, auto */
+};
+
+struct dump_opts {
+ int debug;
+ int format;
+ int level;
+ char mode[4];
+ char infilename[PATH_MAX + 1];
+ char outfilename[PATH_MAX + 1];
+ FILE *infile;
+ FILE *outfile;
+ };
+
+/* globals */
+static int outtiled = -1;
+static uint32 tilewidth = 0;
+static uint32 tilelength = 0;
+
+static uint16 config = 0;
+static uint16 compression = 0;
+static uint16 predictor = 0;
+static uint16 fillorder = 0;
+static uint32 rowsperstrip = 0;
+static uint32 g3opts = 0;
+static int ignore = FALSE; /* if true, ignore read errors */
+static uint32 defg3opts = (uint32) -1;
+static int quality = 100; /* JPEG quality */
+static int jpegcolormode = -1; /* was JPEGCOLORMODE_RGB; */
+static uint16 defcompression = (uint16) -1;
+static uint16 defpredictor = (uint16) -1;
+static int pageNum = 0;
+static int little_endian = 1;
+
+/* Functions adapted from tiffcp with additions or significant modifications */
+static int readContigStripsIntoBuffer (TIFF*, uint8*);
+static int readSeparateStripsIntoBuffer (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
+static int readContigTilesIntoBuffer (TIFF*, uint8*, uint32, uint32, uint32, uint32, tsample_t, uint16);
+static int readSeparateTilesIntoBuffer (TIFF*, uint8*, uint32, uint32, uint32, uint32, tsample_t, uint16);
+static int writeBufferToContigStrips (TIFF*, uint8*, uint32);
+static int writeBufferToContigTiles (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
+static int writeBufferToSeparateStrips (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
+static int writeBufferToSeparateTiles (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
+static int extractContigSamplesToBuffer (uint8 *, uint8 *, uint32, uint32, tsample_t,
+ uint16, uint16, struct dump_opts *);
+static int processCompressOptions(char*);
+static void usage(void);
+
+/* All other functions by Richard Nolde, not found in tiffcp */
+static void initImageData (struct image_data *);
+static void initCropMasks (struct crop_mask *);
+static void initPageSetup (struct pagedef *, struct pageseg *, struct buffinfo []);
+static void initDumpOptions(struct dump_opts *);
+
+/* Command line and file naming functions */
+void process_command_opts (int, char *[], char *, char *, uint32 *,
+ uint16 *, uint16 *, uint32 *, uint32 *, uint32 *,
+ struct crop_mask *, struct pagedef *,
+ struct dump_opts *,
+ unsigned int *, unsigned int *);
+static int update_output_file (TIFF **, char *, int, char *, unsigned int *);
+
+
+/* * High level functions for whole image manipulation */
+static int get_page_geometry (char *, struct pagedef*);
+static int computeInputPixelOffsets(struct crop_mask *, struct image_data *,
+ struct offset *);
+static int computeOutputPixelOffsets (struct crop_mask *, struct image_data *,
+ struct pagedef *, struct pageseg *,
+ struct dump_opts *);
+static int loadImage(TIFF *, struct image_data *, struct dump_opts *, unsigned char **);
+static int correct_orientation(struct image_data *, unsigned char **);
+static int getCropOffsets(struct image_data *, struct crop_mask *, struct dump_opts *);
+static int processCropSelections(struct image_data *, struct crop_mask *,
+ unsigned char **, struct buffinfo []);
+static int writeSelections(TIFF *, TIFF **, struct crop_mask *, struct image_data *,
+ struct dump_opts *, struct buffinfo [],
+ char *, char *, unsigned int*, unsigned int);
+
+/* Section functions */
+static int createImageSection(uint32, unsigned char **);
+static int extractImageSection(struct image_data *, struct pageseg *,
+ unsigned char *, unsigned char *);
+static int writeSingleSection(TIFF *, TIFF *, struct image_data *,
+ struct dump_opts *, uint32, uint32,
+ double, double, unsigned char *);
+static int writeImageSections(TIFF *, TIFF *, struct image_data *,
+ struct pagedef *, struct pageseg *,
+ struct dump_opts *, unsigned char *,
+ unsigned char **);
+/* Whole image functions */
+static int createCroppedImage(struct image_data *, struct crop_mask *,
+ unsigned char **, unsigned char **);
+static int writeCroppedImage(TIFF *, TIFF *, struct image_data *image,
+ struct dump_opts * dump,
+ uint32, uint32, unsigned char *, int, int);
+
+/* Image manipulation functions */
+static int rotateContigSamples8bits(uint16, uint16, uint16, uint32,
+ uint32, uint32, uint8 *, uint8 *);
+static int rotateContigSamples16bits(uint16, uint16, uint16, uint32,
+ uint32, uint32, uint8 *, uint8 *);
+static int rotateContigSamples24bits(uint16, uint16, uint16, uint32,
+ uint32, uint32, uint8 *, uint8 *);
+static int rotateContigSamples32bits(uint16, uint16, uint16, uint32,
+ uint32, uint32, uint8 *, uint8 *);
+static int rotateImage(uint16, struct image_data *, uint32 *, uint32 *,
+ unsigned char **);
+static int mirrorImage(uint16, uint16, uint16, uint32, uint32,
+ unsigned char *);
+static int invertImage(uint16, uint16, uint16, uint32, uint32,
+ unsigned char *);
+
+/* Functions to reverse the sequence of samples in a scanline */
+static int reverseSamples8bits (uint16, uint16, uint32, uint8 *, uint8 *);
+static int reverseSamples16bits (uint16, uint16, uint32, uint8 *, uint8 *);
+static int reverseSamples24bits (uint16, uint16, uint32, uint8 *, uint8 *);
+static int reverseSamples32bits (uint16, uint16, uint32, uint8 *, uint8 *);
+static int reverseSamplesBytes (uint16, uint16, uint32, uint8 *, uint8 *);
+
+/* Functions for manipulating individual samples in an image */
+static int extractSeparateRegion(struct image_data *, struct crop_mask *,
+ unsigned char *, unsigned char *, int);
+static int extractCompositeRegions(struct image_data *, struct crop_mask *,
+ unsigned char *, unsigned char *);
+static int extractContigSamples8bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamples16bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamples24bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamples32bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamplesBytes (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamplesShifted8bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32,
+ int);
+static int extractContigSamplesShifted16bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32,
+ int);
+static int extractContigSamplesShifted24bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32,
+ int);
+static int extractContigSamplesShifted32bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32,
+ int);
+static int extractContigSamplesToTileBuffer(uint8 *, uint8 *, uint32, uint32,
+ uint32, uint32, tsample_t, uint16,
+ uint16, uint16, struct dump_opts *);
+
+/* Functions to combine separate planes into interleaved planes */
+static int combineSeparateSamples8bits (uint8 *[], uint8 *, uint32, uint32,
+ uint16, uint16, FILE *, int, int);
+static int combineSeparateSamples16bits (uint8 *[], uint8 *, uint32, uint32,
+ uint16, uint16, FILE *, int, int);
+static int combineSeparateSamples24bits (uint8 *[], uint8 *, uint32, uint32,
+ uint16, uint16, FILE *, int, int);
+static int combineSeparateSamples32bits (uint8 *[], uint8 *, uint32, uint32,
+ uint16, uint16, FILE *, int, int);
+static int combineSeparateSamplesBytes (unsigned char *[], unsigned char *,
+ uint32, uint32, tsample_t, uint16,
+ FILE *, int, int);
+
+static int combineSeparateTileSamples8bits (uint8 *[], uint8 *, uint32, uint32,
+ uint32, uint32, uint16, uint16,
+ FILE *, int, int);
+static int combineSeparateTileSamples16bits (uint8 *[], uint8 *, uint32, uint32,
+ uint32, uint32, uint16, uint16,
+ FILE *, int, int);
+static int combineSeparateTileSamples24bits (uint8 *[], uint8 *, uint32, uint32,
+ uint32, uint32, uint16, uint16,
+ FILE *, int, int);
+static int combineSeparateTileSamples32bits (uint8 *[], uint8 *, uint32, uint32,
+ uint32, uint32, uint16, uint16,
+ FILE *, int, int);
+static int combineSeparateTileSamplesBytes (unsigned char *[], unsigned char *,
+ uint32, uint32, uint32, uint32,
+ tsample_t, uint16, FILE *, int, int);
+
+/* Dump functions for debugging */
+static void dump_info (FILE *, int, char *, char *, ...);
+static int dump_data (FILE *, int, char *, unsigned char *, uint32);
+static int dump_byte (FILE *, int, char *, unsigned char);
+static int dump_short (FILE *, int, char *, uint16);
+static int dump_long (FILE *, int, char *, uint32);
+static int dump_wide (FILE *, int, char *, uint64);
+static int dump_buffer (FILE *, int, uint32, uint32, uint32, unsigned char *);
+
+/* End function declarations */
+/* Functions derived in whole or in part from tiffcp */
+/* The following functions are taken largely intact from tiffcp */
+
+static char* stuff[] = {
+"usage: tiffcrop [options] source1 ... sourceN destination",
+"where options are:",
+" -h Print this syntax listing",
+" -v Print tiffcrop version identifier and last revision date",
+" ",
+" -a Append to output instead of overwriting",
+" -d offset Set initial directory offset, counting first image as one, not zero",
+" -p contig Pack samples contiguously (e.g. RGBRGB...)",
+" -p separate Store samples separately (e.g. RRR...GGG...BBB...)",
+" -s Write output in strips",
+" -t Write output in tiles",
+" -i Ignore read errors",
+" ",
+" -r # Make each strip have no more than # rows",
+" -w # Set output tile width (pixels)",
+" -l # Set output tile length (pixels)",
+" ",
+" -f lsb2msb Force lsb-to-msb FillOrder for output",
+" -f msb2lsb Force msb-to-lsb FillOrder for output",
+"",
+" -c lzw[:opts] Compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] Compress output with deflate encoding",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c packbits Compress output with packbits encoding",
+" -c g3[:opts] Compress output with CCITT Group 3 encoding",
+" -c g4 Compress output with CCITT Group 4 encoding",
+" -c none Use no compression algorithm on output",
+" ",
+"Group 3 options:",
+" 1d Use default CCITT Group 3 1D-encoding",
+" 2d Use optional CCITT Group 3 2D-encoding",
+" fill Byte-align EOL codes",
+"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
+" ",
+"JPEG options:",
+" # Set compression quality level (0-100, default 100)",
+" r Output color image as raw RGB rather than YCbCr",
+" a Output color image as RGB or YCbCr with auto detection",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+" ",
+"LZW and deflate options:",
+" # Set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+" ",
+"Page and selection options:",
+" -N odd|even|#,#-#,#|last sequences and ranges of images within file to process",
+" The words odd or even may be used to specify all odd or even numbered images.",
+" The word last may be used in place of a number in the sequence to indicate.",
+" The final image in the file without knowing how many images there are.",
+" Numbers are counted from one even though TIFF IFDs are counted from zero.",
+" ",
+" -E t|l|r|b edge to use as origin for width and length of crop region",
+" -U units [in, cm, px ] inches, centimeters or pixels",
+" ",
+" -m #,#,#,# margins from edges for selection: top, left, bottom, right separated by commas",
+" -X # horizontal dimension of region to extract expressed in current units",
+" -Y # vertical dimension of region to extract expressed in current units",
+" -Z #:#,#:# zones of the image designated as position X of Y,",
+" eg 1:3 would be first of three equal portions measured from reference edge",
+" -z x1,y1,x2,y2:...:xN,yN,xN+1,yN+1",
+" regions of the image designated by upper left and lower right coordinates",
+"",
+"Export grouping options:",
+" -e c|d|i|m|s export mode for images and selections from input images.",
+" When exporting a composite image from multiple zones or regions",
+" (combined and image modes), the selections must have equal sizes",
+" for the axis perpendicular to the edge specified with -E.",
+" c|combined All images and selections are written to a single file (default).",
+" with multiple selections from one image combined into a single image.",
+" d|divided All images and selections are written to a single file",
+" with each selection from one image written to a new image.",
+" i|image Each input image is written to a new file (numeric filename sequence)",
+" with multiple selections from the image combined into one image.",
+" m|multiple Each input image is written to a new file (numeric filename sequence)",
+" with each selection from the image written to a new image.",
+" s|separated Individual selections from each image are written to separate files.",
+"",
+"Output options:",
+" -H # Set horizontal resolution of output images to #",
+" -V # Set vertical resolution of output images to #",
+" -J # Set horizontal margin of output page to # expressed in current units",
+" when sectioning image into columns x rows using the -S cols:rows option",
+" -K # Set verticalal margin of output page to # expressed in current units",
+" when sectioning image into columns x rows using the -S cols:rows option",
+" ",
+" -O orient orientation for output image, portrait, landscape, auto",
+" -P page page size for output image segments, eg letter, legal, tabloid, etc",
+" use #.#x#.# to specify a custom page size in the currently defined units",
+" where #.# represents the width and length",
+" -S cols:rows Divide the image into equal sized segments using cols across and rows down.",
+" ",
+" -F hor|vert|both",
+" flip (mirror) image or region horizontally, vertically, or both",
+" -R # [90,180,or 270] degrees clockwise rotation of image or extracted region",
+" -I [black|white|data|both]",
+" invert color space, eg dark to light for bilevel and grayscale images",
+" If argument is white or black, set the PHOTOMETRIC_INTERPRETATION ",
+" tag to MinIsBlack or MinIsWhite without altering the image data",
+" If the argument is data or both, the image data are modified:",
+" both inverts the data and the PHOTOMETRIC_INTERPRETATION tag,",
+" data inverts the data but not the PHOTOMETRIC_INTERPRETATION tag",
+" ",
+"-D opt1:value1,opt2:value2,opt3:value3:opt4:value4",
+" Debug/dump program progress and/or data to non-TIFF files.",
+" Options include the following and must be joined as a comma",
+" separate list. The use of this option is generally limited to",
+" program debugging and development of future options.",
+" ",
+" debug:N Display limited program progress indicators where larger N",
+" increase the level of detail. Note: Tiffcrop may be compiled with",
+" -DDEVELMODE to enable additional very low level debug reporting.",
+"",
+" Format:txt|raw Format any logged data as ASCII text or raw binary ",
+" values. ASCII text dumps include strings of ones and zeroes",
+" representing the binary values in the image data plus identifying headers.",
+" ",
+" level:N Specify the level of detail presented in the dump files.",
+" This can vary from dumps of the entire input or output image data to dumps",
+" of data processed by specific functions. Current range of levels is 1 to 3.",
+" ",
+" input:full-path-to-directory/input-dumpname",
+" ",
+" output:full-path-to-directory/output-dumpnaem",
+" ",
+" When dump files are being written, each image will be written to a separate",
+" file with the name built by adding a numeric sequence value to the dumpname",
+" and an extension of .txt for ASCII dumps or .bin for binary dumps.",
+" ",
+" The four debug/dump options are independent, though it makes little sense to",
+" specify a dump file without specifying a detail level.",
+" ",
+NULL
+};
+
+/* This function could be modified to pass starting sample offset
+ * and number of samples as args to select fewer than spp
+ * from input image. These would then be passed to individual
+ * extractContigSampleXX routines.
+ */
+static int readContigTilesIntoBuffer (TIFF* in, uint8* buf,
+ uint32 imagelength,
+ uint32 imagewidth,
+ uint32 tw, uint32 tl,
+ tsample_t spp, uint16 bps)
+ {
+ int status = 1;
+ tsample_t sample = 0;
+ tsample_t count = spp;
+ uint32 row, col, trow;
+ uint32 nrow, ncol;
+ uint32 dst_rowsize, shift_width;
+ uint32 bytes_per_sample, bytes_per_pixel;
+ uint32 trailing_bits, prev_trailing_bits;
+ uint32 tile_rowsize = TIFFTileRowSize(in);
+ uint32 src_offset, dst_offset;
+ uint32 row_offset, col_offset;
+ uint8 *bufp = (uint8*) buf;
+ unsigned char *src = NULL;
+ unsigned char *dst = NULL;
+ tsize_t tbytes = 0, tile_buffsize = 0;
+ tsize_t tilesize = TIFFTileSize(in);
+ unsigned char *tilebuf = NULL;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+
+ if ((bps % 8) == 0)
+ shift_width = 0;
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+
+ tile_buffsize = tilesize;
+
+ if (tilesize < (tsize_t)(tl * tile_rowsize))
+ {
+#ifdef DEBUG2
+ TIFFError("readContigTilesIntoBuffer",
+ "Tilesize %lu is too small, using alternate calculation %u",
+ tilesize, tl * tile_rowsize);
+#endif
+ tile_buffsize = tl * tile_rowsize;
+ }
+
+ tilebuf = _TIFFmalloc(tile_buffsize);
+ if (tilebuf == 0)
+ return 0;
+
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ for (row = 0; row < imagelength; row += tl)
+ {
+ nrow = (row + tl > imagelength) ? imagelength - row : tl;
+ for (col = 0; col < imagewidth; col += tw)
+ {
+ tbytes = TIFFReadTile(in, tilebuf, col, row, 0, 0);
+ if (tbytes < tilesize && !ignore)
+ {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read tile at row %lu col %lu, Read %lu bytes of %lu",
+ (unsigned long) col, (unsigned long) row, (unsigned long)tbytes,
+ (unsigned long)tilesize);
+ status = 0;
+ _TIFFfree(tilebuf);
+ return status;
+ }
+
+ row_offset = row * dst_rowsize;
+ col_offset = ((col * bps * spp) + 7)/ 8;
+ bufp = buf + row_offset + col_offset;
+
+ if (col + tw > imagewidth)
+ ncol = imagewidth - col;
+ else
+ ncol = tw;
+
+ /* Each tile scanline will start on a byte boundary but it
+ * has to be merged into the scanline for the entire
+ * image buffer and the previous segment may not have
+ * ended on a byte boundary
+ */
+ /* Optimization for common bit depths, all samples */
+ if (((bps % 8) == 0) && (count == spp))
+ {
+ for (trow = 0; trow < nrow; trow++)
+ {
+ src_offset = trow * tile_rowsize;
+ _TIFFmemcpy (bufp, tilebuf + src_offset, (ncol * spp * bps) / 8);
+ bufp += (imagewidth * bps * spp) / 8;
+ }
+ }
+ else
+ {
+ /* Bit depths not a multiple of 8 and/or extract fewer than spp samples */
+ prev_trailing_bits = trailing_bits = 0;
+ trailing_bits = (ncol * bps * spp) % 8;
+
+ /* for (trow = 0; tl < nrow; trow++) */
+ for (trow = 0; trow < nrow; trow++)
+ {
+ src_offset = trow * tile_rowsize;
+ src = tilebuf + src_offset;
+ dst_offset = (row + trow) * dst_rowsize;
+ dst = buf + dst_offset + col_offset;
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, ncol, sample,
+ spp, bps, count, 0, ncol))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamplesShifted8bits (src, dst, ncol,
+ sample, spp,
+ bps, count,
+ 0, ncol,
+ prev_trailing_bits))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ }
+ else
+ if (extractContigSamplesShifted16bits (src, dst, ncol,
+ sample, spp,
+ bps, count,
+ 0, ncol,
+ prev_trailing_bits))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ case 2: if (extractContigSamplesShifted24bits (src, dst, ncol,
+ sample, spp,
+ bps, count,
+ 0, ncol,
+ prev_trailing_bits))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamplesShifted32bits (src, dst, ncol,
+ sample, spp,
+ bps, count,
+ 0, ncol,
+ prev_trailing_bits))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ default: TIFFError("readContigTilesIntoBuffer", "Unsupported bit depth %d", bps);
+ return 1;
+ }
+ }
+ prev_trailing_bits += trailing_bits;
+ if (prev_trailing_bits > 7)
+ prev_trailing_bits-= 8;
+ }
+ }
+ }
+
+ _TIFFfree(tilebuf);
+ return status;
+ }
+
+static int readSeparateTilesIntoBuffer (TIFF* in, uint8 *obuf,
+ uint32 imagelength, uint32 imagewidth,
+ uint32 tw, uint32 tl,
+ uint16 spp, uint16 bps)
+ {
+ int i, status = 1, sample;
+ int shift_width, bytes_per_pixel;
+ uint16 bytes_per_sample;
+ uint32 row, col; /* Current row and col of image */
+ uint32 nrow, ncol; /* Number of rows and cols in current tile */
+ uint32 row_offset, col_offset; /* Output buffer offsets */
+ tsize_t tbytes = 0, tilesize = TIFFTileSize(in);
+ tsample_t s;
+ uint8* bufp = (uint8*)obuf;
+ unsigned char *srcbuffs[MAX_SAMPLES];
+ unsigned char *tbuff = NULL;
+
+ bytes_per_sample = (bps + 7) / 8;
+
+ for (sample = 0; (sample < spp) && (sample < MAX_SAMPLES); sample++)
+ {
+ srcbuffs[sample] = NULL;
+ tbuff = (unsigned char *)_TIFFmalloc(tilesize + 8);
+ if (!tbuff)
+ {
+ TIFFError ("readSeparateTilesIntoBuffer",
+ "Unable to allocate tile read buffer for sample %d", sample);
+ for (i = 0; i < sample; i++)
+ _TIFFfree (srcbuffs[i]);
+ return 0;
+ }
+ srcbuffs[sample] = tbuff;
+ }
+ /* Each tile contains only the data for a single plane
+ * arranged in scanlines of tw * bytes_per_sample bytes.
+ */
+ for (row = 0; row < imagelength; row += tl)
+ {
+ nrow = (row + tl > imagelength) ? imagelength - row : tl;
+ for (col = 0; col < imagewidth; col += tw)
+ {
+ for (s = 0; s < spp; s++)
+ { /* Read each plane of a tile set into srcbuffs[s] */
+ tbytes = TIFFReadTile(in, srcbuffs[s], col, row, 0, s);
+ if (tbytes < 0 && !ignore)
+ {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read tile for row %lu col %lu, "
+ "sample %lu",
+ (unsigned long) col, (unsigned long) row,
+ (unsigned long) s);
+ status = 0;
+ for (sample = 0; (sample < spp) && (sample < MAX_SAMPLES); sample++)
+ {
+ tbuff = srcbuffs[sample];
+ if (tbuff != NULL)
+ _TIFFfree(tbuff);
+ }
+ return status;
+ }
+ }
+ /* Tiles on the right edge may be padded out to tw
+ * which must be a multiple of 16.
+ * Ncol represents the visible (non padding) portion.
+ */
+ if (col + tw > imagewidth)
+ ncol = imagewidth - col;
+ else
+ ncol = tw;
+
+ row_offset = row * (((imagewidth * spp * bps) + 7) / 8);
+ col_offset = ((col * spp * bps) + 7) / 8;
+ bufp = obuf + row_offset + col_offset;
+
+ if ((bps % 8) == 0)
+ {
+ if (combineSeparateTileSamplesBytes(srcbuffs, bufp, ncol, nrow, imagewidth,
+ tw, spp, bps, NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ }
+ else
+ {
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ switch (shift_width)
+ {
+ case 1: if (combineSeparateTileSamples8bits (srcbuffs, bufp, ncol, nrow,
+ imagewidth, tw, spp, bps,
+ NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ break;
+ case 2: if (combineSeparateTileSamples16bits (srcbuffs, bufp, ncol, nrow,
+ imagewidth, tw, spp, bps,
+ NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ break;
+ case 3: if (combineSeparateTileSamples24bits (srcbuffs, bufp, ncol, nrow,
+ imagewidth, tw, spp, bps,
+ NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8: if (combineSeparateTileSamples32bits (srcbuffs, bufp, ncol, nrow,
+ imagewidth, tw, spp, bps,
+ NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ break;
+ default: TIFFError ("readSeparateTilesIntoBuffer", "Unsupported bit depth: %d", bps);
+ status = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ for (sample = 0; (sample < spp) && (sample < MAX_SAMPLES); sample++)
+ {
+ tbuff = srcbuffs[sample];
+ if (tbuff != NULL)
+ _TIFFfree(tbuff);
+ }
+
+ return status;
+ }
+
+static int writeBufferToContigStrips(TIFF* out, uint8* buf, uint32 imagelength)
+ {
+ uint32 row, nrows, rowsperstrip;
+ tstrip_t strip = 0;
+ tsize_t stripsize;
+
+ TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ for (row = 0; row < imagelength; row += rowsperstrip)
+ {
+ nrows = (row + rowsperstrip > imagelength) ?
+ imagelength - row : rowsperstrip;
+ stripsize = TIFFVStripSize(out, nrows);
+ if (TIFFWriteEncodedStrip(out, strip++, buf, stripsize) < 0)
+ {
+ TIFFError(TIFFFileName(out), "Error, can't write strip %u", strip - 1);
+ return 1;
+ }
+ buf += stripsize;
+ }
+
+ return 0;
+ }
+
+/* Abandon plans to modify code so that plannar orientation separate images
+ * do not have all samples for each channel written before all samples
+ * for the next channel have been abandoned.
+ * Libtiff internals seem to depend on all data for a given sample
+ * being contiguous within a strip or tile when PLANAR_CONFIG is
+ * separate. All strips or tiles of a given plane are written
+ * before any strips or tiles of a different plane are stored.
+ */
+static int
+writeBufferToSeparateStrips (TIFF* out, uint8* buf,
+ uint32 length, uint32 width, uint16 spp,
+ struct dump_opts *dump)
+ {
+ uint8 *src;
+ uint16 bps;
+ uint32 row, nrows, rowsize, rowsperstrip;
+ uint32 bytes_per_sample;
+ tsample_t s;
+ tstrip_t strip = 0;
+ tsize_t stripsize = TIFFStripSize(out);
+ tsize_t rowstripsize, scanlinesize = TIFFScanlineSize(out);
+ tsize_t total_bytes = 0;
+ tdata_t obuf;
+
+ (void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ (void) TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
+ bytes_per_sample = (bps + 7) / 8;
+ rowsize = ((bps * spp * width) + 7) / 8; /* source has interleaved samples */
+ rowstripsize = rowsperstrip * bytes_per_sample * (width + 1);
+
+ obuf = _TIFFmalloc (rowstripsize);
+ if (obuf == NULL)
+ return 1;
+
+ for (s = 0; s < spp; s++)
+ {
+ for (row = 0; row < length; row += rowsperstrip)
+ {
+ nrows = (row + rowsperstrip > length) ? length - row : rowsperstrip;
+
+ stripsize = TIFFVStripSize(out, nrows);
+ src = buf + (row * rowsize);
+ total_bytes += stripsize;
+ memset (obuf, '\0', rowstripsize);
+ if (extractContigSamplesToBuffer(obuf, src, nrows, width, s, spp, bps, dump))
+ {
+ _TIFFfree(obuf);
+ return 1;
+ }
+ if ((dump->outfile != NULL) && (dump->level == 1))
+ {
+ dump_info(dump->outfile, dump->format,"",
+ "Sample %2d, Strip: %2d, bytes: %4d, Row %4d, bytes: %4d, Input offset: %6d",
+ s + 1, strip + 1, stripsize, row + 1, scanlinesize, src - buf);
+ dump_buffer(dump->outfile, dump->format, nrows, scanlinesize, row, obuf);
+ }
+
+ if (TIFFWriteEncodedStrip(out, strip++, obuf, stripsize) < 0)
+ {
+ TIFFError(TIFFFileName(out), "Error, can't write strip %u", strip - 1);
+ _TIFFfree(obuf);
+ return 1;
+ }
+ }
+ }
+
+ _TIFFfree(obuf);
+ return 0;
+}
+
+/* Extract all planes from contiguous buffer into a single tile buffer
+ * to be written out as a tile.
+ */
+static int writeBufferToContigTiles (TIFF* out, uint8* buf, uint32 imagelength,
+ uint32 imagewidth, tsample_t spp,
+ struct dump_opts* dump)
+ {
+ uint16 bps;
+ uint32 tl, tw;
+ uint32 row, col, nrow, ncol;
+ uint32 src_rowsize, col_offset;
+ uint32 tile_rowsize = TIFFTileRowSize(out);
+ uint8* bufp = (uint8*) buf;
+ tsize_t tile_buffsize = 0;
+ tsize_t tilesize = TIFFTileSize(out);
+ unsigned char *tilebuf = NULL;
+
+ TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
+ TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
+
+ tile_buffsize = tilesize;
+ if (tilesize < (tsize_t)(tl * tile_rowsize))
+ {
+#ifdef DEBUG2
+ TIFFError("writeBufferToContigTiles",
+ "Tilesize %lu is too small, using alternate calculation %u",
+ tilesize, tl * tile_rowsize);
+#endif
+ tile_buffsize = tl * tile_rowsize;
+ }
+
+ tilebuf = _TIFFmalloc(tile_buffsize);
+ if (tilebuf == 0)
+ return 1;
+
+ src_rowsize = ((imagewidth * spp * bps) + 7) / 8;
+ for (row = 0; row < imagelength; row += tl)
+ {
+ nrow = (row + tl > imagelength) ? imagelength - row : tl;
+ for (col = 0; col < imagewidth; col += tw)
+ {
+ /* Calculate visible portion of tile. */
+ if (col + tw > imagewidth)
+ ncol = imagewidth - col;
+ else
+ ncol = tw;
+
+ col_offset = (((col * bps * spp) + 7) / 8);
+ bufp = buf + (row * src_rowsize) + col_offset;
+ if (extractContigSamplesToTileBuffer(tilebuf, bufp, nrow, ncol, imagewidth,
+ tw, 0, spp, spp, bps, dump) > 0)
+ {
+ TIFFError("writeBufferToContigTiles",
+ "Unable to extract data to tile for row %lu, col %lu",
+ (unsigned long) row, (unsigned long)col);
+ _TIFFfree(tilebuf);
+ return 1;
+ }
+
+ if (TIFFWriteTile(out, tilebuf, col, row, 0, 0) < 0)
+ {
+ TIFFError("writeBufferToContigTiles",
+ "Cannot write tile at %lu %lu",
+ (unsigned long) col, (unsigned long) row);
+ _TIFFfree(tilebuf);
+ return 1;
+ }
+ }
+ }
+ _TIFFfree(tilebuf);
+
+ return 0;
+ } /* end writeBufferToContigTiles */
+
+/* Extract each plane from contiguous buffer into a single tile buffer
+ * to be written out as a tile.
+ */
+static int writeBufferToSeparateTiles (TIFF* out, uint8* buf, uint32 imagelength,
+ uint32 imagewidth, tsample_t spp,
+ struct dump_opts * dump)
+ {
+ tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
+ uint32 tl, tw;
+ uint32 row, col, nrow, ncol;
+ uint32 src_rowsize, col_offset;
+ uint16 bps;
+ tsample_t s;
+ uint8* bufp = (uint8*) buf;
+
+ if (obuf == NULL)
+ return 1;
+
+ TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
+ TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
+ src_rowsize = ((imagewidth * spp * bps) + 7) / 8;
+
+ for (row = 0; row < imagelength; row += tl)
+ {
+ nrow = (row + tl > imagelength) ? imagelength - row : tl;
+ for (col = 0; col < imagewidth; col += tw)
+ {
+ /* Calculate visible portion of tile. */
+ if (col + tw > imagewidth)
+ ncol = imagewidth - col;
+ else
+ ncol = tw;
+
+ col_offset = (((col * bps * spp) + 7) / 8);
+ bufp = buf + (row * src_rowsize) + col_offset;
+
+ for (s = 0; s < spp; s++)
+ {
+ if (extractContigSamplesToTileBuffer(obuf, bufp, nrow, ncol, imagewidth,
+ tw, s, 1, spp, bps, dump) > 0)
+ {
+ TIFFError("writeBufferToSeparateTiles",
+ "Unable to extract data to tile for row %lu, col %lu sample %d",
+ (unsigned long) row, (unsigned long)col, (int)s);
+ _TIFFfree(obuf);
+ return 1;
+ }
+
+ if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0)
+ {
+ TIFFError("writeBufferToseparateTiles",
+ "Cannot write tile at %lu %lu sample %lu",
+ (unsigned long) col, (unsigned long) row,
+ (unsigned long) s);
+ _TIFFfree(obuf);
+ return 1;
+ }
+ }
+ }
+ }
+ _TIFFfree(obuf);
+
+ return 0;
+ } /* end writeBufferToSeparateTiles */
+
+static void
+processG3Options(char* cp)
+{
+ if( (cp = strchr(cp, ':')) ) {
+ if (defg3opts == (uint32) -1)
+ defg3opts = 0;
+ do {
+ cp++;
+ if (strneq(cp, "1d", 2))
+ defg3opts &= ~GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "2d", 2))
+ defg3opts |= GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "fill", 4))
+ defg3opts |= GROUP3OPT_FILLBITS;
+ else
+ usage();
+ } while( (cp = strchr(cp, ':')) );
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+ {
+ char* cp = NULL;
+
+ if (strneq(opt, "none",4))
+ {
+ defcompression = COMPRESSION_NONE;
+ /* DELETE ME: This should not be needed */
+ cp = strchr(opt, ':');
+ if (cp)
+ {
+ if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else if (cp[1] == 'a' )
+ jpegcolormode = JPEGCOLORMODE_RGB;
+ }
+ /* end DELETE ME: */
+ }
+ else if (streq(opt, "packbits"))
+ {
+ defcompression = COMPRESSION_PACKBITS;
+ }
+ else if (strneq(opt, "jpeg", 4))
+ {
+ cp = strchr(opt, ':');
+ defcompression = COMPRESSION_JPEG;
+ while ( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else if (cp[1] == 'a' )
+ jpegcolormode = JPEGCOLORMODE_RGB;
+ else
+ usage();
+ cp = strchr(cp+1,':');
+ }
+ }
+ else if (strneq(opt, "g3", 2))
+ {
+ processG3Options(opt);
+ defcompression = COMPRESSION_CCITTFAX3;
+ }
+ else if (streq(opt, "g4"))
+ {
+ defcompression = COMPRESSION_CCITTFAX4;
+ }
+ else if (strneq(opt, "lzw", 3))
+ {
+ cp = strchr(opt, ':');
+ if (cp)
+ defpredictor = atoi(cp+1);
+ defcompression = COMPRESSION_LZW;
+ }
+ else if (strneq(opt, "zip", 3))
+ {
+ cp = strchr(opt, ':');
+ if (cp)
+ defpredictor = atoi(cp+1);
+ defcompression = COMPRESSION_ADOBE_DEFLATE;
+ }
+ else
+ return (0);
+
+ return (1);
+ }
+
+static void
+usage(void)
+ {
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "\n%s\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+ }
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, (uint16) -1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES,(uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_EXTRASAMPLES, (uint16) -1, TIFF_SHORT },
+ { TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_STONITS, 1, TIFF_DOUBLE },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+#define CopyTag(tag, count, type) cpTag(in, out, tag, count, type)
+
+/* Functions written by Richard Nolde, with exceptions noted. */
+void process_command_opts (int argc, char *argv[], char *mp, char *mode, uint32 *dirnum,
+ uint16 *defconfig, uint16 *deffillorder, uint32 *deftilewidth,
+ uint32 *deftilelength, uint32 *defrowsperstrip,
+ struct crop_mask *crop_data, struct pagedef *page,
+ struct dump_opts *dump,
+ unsigned int *imagelist, unsigned int *image_count )
+ {
+ int c, good_args = 0;
+ char *opt_offset = NULL; /* Position in string of value sought */
+ char *opt_ptr = NULL; /* Pointer to next token in option set */
+ char *sep = NULL; /* Pointer to a token separator */
+ unsigned int i, j, start, end;
+ extern int optind;
+ extern char* optarg;
+
+ *mp++ = 'w';
+ *mp = '\0';
+ while ((c = getopt(argc, argv,
+ "ac:d:e:f:hil:m:p:r:stvw:z:BCD:E:F:H:I:J:K:LMN:O:P:R:S:U:V:X:Y:Z:")) != -1)
+ {
+ good_args++;
+ switch (c) {
+ case 'a': mode[0] = 'a'; /* append to output */
+ break;
+ case 'c': if (!processCompressOptions(optarg)) /* compression scheme */
+ {
+ TIFFError ("Unknown compression option", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'd': start = strtoul(optarg, NULL, 0); /* initial IFD offset */
+ if (start == 0)
+ {
+ TIFFError ("","Directory offset must be greater than zero");
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ *dirnum = start - 1;
+ break;
+ case 'e': switch (tolower(optarg[0])) /* image export modes*/
+ {
+ case 'c': crop_data->exp_mode = ONE_FILE_COMPOSITE;
+ crop_data->img_mode = COMPOSITE_IMAGES;
+ break; /* Composite */
+ case 'd': crop_data->exp_mode = ONE_FILE_SEPARATED;
+ crop_data->img_mode = SEPARATED_IMAGES;
+ break; /* Divided */
+ case 'i': crop_data->exp_mode = FILE_PER_IMAGE_COMPOSITE;
+ crop_data->img_mode = COMPOSITE_IMAGES;
+ break; /* Image */
+ case 'm': crop_data->exp_mode = FILE_PER_IMAGE_SEPARATED;
+ crop_data->img_mode = SEPARATED_IMAGES;
+ break; /* Multiple */
+ case 's': crop_data->exp_mode = FILE_PER_SELECTION;
+ crop_data->img_mode = SEPARATED_IMAGES;
+ break; /* Sections */
+ default: TIFFError ("Unknown export mode","%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'f': if (streq(optarg, "lsb2msb")) /* fill order */
+ *deffillorder = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ *deffillorder = FILLORDER_MSB2LSB;
+ else
+ {
+ TIFFError ("Unknown fill order", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'h': usage();
+ break;
+ case 'i': ignore = TRUE; /* ignore errors */
+ break;
+ case 'l': outtiled = TRUE; /* tile length */
+ *deftilelength = atoi(optarg);
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ *defconfig = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ *defconfig = PLANARCONFIG_CONTIG;
+ else
+ {
+ TIFFError ("Unkown planar configuration", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'r': /* rows/strip */
+ *defrowsperstrip = atol(optarg);
+ break;
+ case 's': /* generate stripped output */
+ outtiled = FALSE;
+ break;
+ case 't': /* generate tiled output */
+ outtiled = TRUE;
+ break;
+ case 'v': TIFFError("Library Release", "%s", TIFFGetVersion());
+ TIFFError ("Tiffcrop version", "%s, last updated: %s",
+ tiffcrop_version_id, tiffcrop_rev_date);
+ TIFFError ("Tiffcp code", "Copyright (c) 1988-1997 Sam Leffler");
+ TIFFError (" ", "Copyright (c) 1991-1997 Silicon Graphics, Inc");
+ TIFFError ("Tiffcrop additions", "Copyright (c) 2007-2009 Richard Nolde");
+ exit (0);
+ break;
+ case 'w': /* tile width */
+ outtiled = TRUE;
+ *deftilewidth = atoi(optarg);
+ break;
+ case 'z': /* regions of an image specified as x1,y1,x2,y2:x3,y3,x4,y4 etc */
+ crop_data->crop_mode |= CROP_REGIONS;
+ for (i = 0, opt_ptr = strtok (optarg, ":");
+ ((opt_ptr != NULL) && (i < MAX_REGIONS));
+ (opt_ptr = strtok (NULL, ":")), i++)
+ {
+ crop_data->regions++;
+ if (sscanf(opt_ptr, "%lf,%lf,%lf,%lf",
+ &crop_data->corners[i].X1, &crop_data->corners[i].Y1,
+ &crop_data->corners[i].X2, &crop_data->corners[i].Y2) != 4)
+ {
+ TIFFError ("Unable to parse coordinates for region", "%d %s", i, optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ }
+ /* check for remaining elements over MAX_REGIONS */
+ if ((opt_ptr != NULL) && (i >= MAX_REGIONS))
+ {
+ TIFFError ("Region list exceeds limit of", "%d regions %s", MAX_REGIONS, optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);;
+ }
+ break;
+ /* options for file open modes */
+ case 'B': *mp++ = 'b'; *mp = '\0';
+ break;
+ case 'L': *mp++ = 'l'; *mp = '\0';
+ break;
+ case 'M': *mp++ = 'm'; *mp = '\0';
+ break;
+ case 'C': *mp++ = 'c'; *mp = '\0';
+ break;
+ /* options for Debugging / data dump */
+ case 'D': for (i = 0, opt_ptr = strtok (optarg, ",");
+ (opt_ptr != NULL);
+ (opt_ptr = strtok (NULL, ",")), i++)
+ {
+ opt_offset = strpbrk(opt_ptr, ":=");
+ /*
+ opt_offset = strchr(opt_ptr, ':');
+ */
+ if (opt_offset == NULL)
+ {
+ TIFFError("Invalid dump option", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+
+ *opt_offset = '\0';
+ /* convert option to lowercase */
+ end = strlen (opt_ptr);
+ for (i = 0; i < end; i++)
+ *(opt_ptr + i) = tolower(*(opt_ptr + i));
+ /* Look for dump format specification */
+ if (strncmp(opt_ptr, "for", 3) == 0)
+ {
+ /* convert value to lowercase */
+ end = strlen (opt_offset + 1);
+ for (i = 1; i <= end; i++)
+ *(opt_offset + i) = tolower(*(opt_offset + i));
+ /* check dump format value */
+ if (strncmp (opt_offset + 1, "txt", 3) == 0)
+ {
+ dump->format = DUMP_TEXT;
+ strcpy (dump->mode, "w");
+ }
+ else
+ {
+ if (strncmp(opt_offset + 1, "raw", 3) == 0)
+ {
+ dump->format = DUMP_RAW;
+ strcpy (dump->mode, "wb");
+ }
+ else
+ {
+ TIFFError("parse_command_opts", "Unknown dump format %s", opt_offset + 1);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ }
+ }
+ else
+ { /* Look for dump level specification */
+ if (strncmp (opt_ptr, "lev", 3) == 0)
+ dump->level = atoi(opt_offset + 1);
+ /* Look for input data dump file name */
+ if (strncmp (opt_ptr, "in", 2) == 0)
+ strncpy (dump->infilename, opt_offset + 1, PATH_MAX - 20);
+ /* Look for output data dump file name */
+ if (strncmp (opt_ptr, "out", 3) == 0)
+ strncpy (dump->outfilename, opt_offset + 1, PATH_MAX - 20);
+ if (strncmp (opt_ptr, "deb", 3) == 0)
+ dump->debug = atoi(opt_offset + 1);
+ }
+ }
+ if ((strlen(dump->infilename)) || (strlen(dump->outfilename)))
+ {
+ if (dump->level == 1)
+ TIFFError("","Defaulting to dump level 1, no data.");
+ if (dump->format == DUMP_NONE)
+ {
+ TIFFError("", "You must specify a dump format for dump files");
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ }
+ break;
+
+ /* image manipulation routine options */
+ case 'm': /* margins to exclude from selection, uppercase M was already used */
+ /* order of values must be TOP, LEFT, BOTTOM, RIGHT */
+ crop_data->crop_mode |= CROP_MARGINS;
+ for (i = 0, opt_ptr = strtok (optarg, ",:");
+ ((opt_ptr != NULL) && (i < 4));
+ (opt_ptr = strtok (NULL, ",:")), i++)
+ {
+ crop_data->margins[i] = atof(opt_ptr);
+ }
+ break;
+ case 'E': /* edge reference */
+ switch (tolower(optarg[0]))
+ {
+ case 't': crop_data->edge_ref = EDGE_TOP;
+ break;
+ case 'b': crop_data->edge_ref = EDGE_BOTTOM;
+ break;
+ case 'l': crop_data->edge_ref = EDGE_LEFT;
+ break;
+ case 'r': crop_data->edge_ref = EDGE_RIGHT;
+ break;
+ default: TIFFError ("Edge reference must be top, bottom, left, or right", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'F': /* flip eg mirror image or cropped segment, M was already used */
+ crop_data->crop_mode |= CROP_MIRROR;
+ switch (tolower(optarg[0]))
+ {
+ case 'h': crop_data->mirror = MIRROR_HORIZ;
+ break;
+ case 'v': crop_data->mirror = MIRROR_VERT;
+ break;
+ case 'b': crop_data->mirror = MIRROR_BOTH;
+ break;
+ default: TIFFError ("Flip mode must be horiz, vert, or both", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'H': /* set horizontal resolution to new value */
+ page->hres = atof (optarg);
+ page->mode |= PAGE_MODE_RESOLUTION;
+ break;
+ case 'I': /* invert the color space, eg black to white */
+ crop_data->crop_mode |= CROP_INVERT;
+ /* The PHOTOMETIC_INTERPRETATION tag may be updated */
+ if (streq(optarg, "black"))
+ {
+ crop_data->photometric = PHOTOMETRIC_MINISBLACK;
+ continue;
+ }
+ if (streq(optarg, "white"))
+ {
+ crop_data->photometric = PHOTOMETRIC_MINISWHITE;
+ continue;
+ }
+ if (streq(optarg, "data"))
+ {
+ crop_data->photometric = INVERT_DATA_ONLY;
+ continue;
+ }
+ if (streq(optarg, "both"))
+ {
+ crop_data->photometric = INVERT_DATA_AND_TAG;
+ continue;
+ }
+
+ TIFFError("Missing or unknown option for inverting PHOTOMETRIC_INTERPRETATION", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ break;
+ case 'J': /* horizontal margin for sectioned ouput pages */
+ page->hmargin = atof(optarg);
+ page->mode |= PAGE_MODE_MARGINS;
+ break;
+ case 'K': /* vertical margin for sectioned ouput pages*/
+ page->vmargin = atof(optarg);
+ page->mode |= PAGE_MODE_MARGINS;
+ break;
+ case 'N': /* list of images to process */
+ for (i = 0, opt_ptr = strtok (optarg, ",");
+ ((opt_ptr != NULL) && (i < MAX_IMAGES));
+ (opt_ptr = strtok (NULL, ",")))
+ { /* We do not know how many images are in file yet
+ * so we build a list to include the maximum allowed
+ * and follow it until we hit the end of the file.
+ * Image count is not accurate for odd, even, last
+ * so page numbers won't be valid either.
+ */
+ if (streq(opt_ptr, "odd"))
+ {
+ for (j = 1; j <= MAX_IMAGES; j += 2)
+ imagelist[i++] = j;
+ *image_count = (MAX_IMAGES - 1) / 2;
+ break;
+ }
+ else
+ {
+ if (streq(opt_ptr, "even"))
+ {
+ for (j = 2; j <= MAX_IMAGES; j += 2)
+ imagelist[i++] = j;
+ *image_count = MAX_IMAGES / 2;
+ break;
+ }
+ else
+ {
+ if (streq(opt_ptr, "last"))
+ imagelist[i++] = MAX_IMAGES;
+ else /* single value between commas */
+ {
+ sep = strpbrk(opt_ptr, ":-");
+ if (!sep)
+ imagelist[i++] = atoi(opt_ptr);
+ else
+ {
+ *sep = '\0';
+ start = atoi (opt_ptr);
+ if (!strcmp((sep + 1), "last"))
+ end = MAX_IMAGES;
+ else
+ end = atoi (sep + 1);
+ for (j = start; j <= end && j - start + i < MAX_IMAGES; j++)
+ imagelist[i++] = j;
+ }
+ }
+ }
+ }
+ }
+ *image_count = i;
+ break;
+ case 'O': /* page orientation */
+ switch (tolower(optarg[0]))
+ {
+ case 'a': page->orient = ORIENTATION_AUTO;
+ break;
+ case 'p': page->orient = ORIENTATION_PORTRAIT;
+ break;
+ case 'l': page->orient = ORIENTATION_LANDSCAPE;
+ break;
+ default: TIFFError ("Orientation must be portrait, landscape, or auto.", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'P': /* page size selection */
+ if (sscanf(optarg, "%lfx%lf", &page->width, &page->length) == 2)
+ {
+ strcpy (page->name, "Custom");
+ page->mode |= PAGE_MODE_PAPERSIZE;
+ break;
+ }
+ if (get_page_geometry (optarg, page))
+ {
+ if (!strcmp(optarg, "list"))
+ {
+ TIFFError("", "Name Width Length (in inches)");
+ for (i = 0; i < MAX_PAPERNAMES - 1; i++)
+ TIFFError ("", "%-15.15s %5.2f %5.2f",
+ PaperTable[i].name, PaperTable[i].width,
+ PaperTable[i].length);
+ exit (-1);
+ }
+
+ TIFFError ("Invalid paper size", "%s", optarg);
+ TIFFError ("", "Select one of:");
+ TIFFError("", "Name Width Length (in inches)");
+ for (i = 0; i < MAX_PAPERNAMES - 1; i++)
+ TIFFError ("", "%-15.15s %5.2f %5.2f",
+ PaperTable[i].name, PaperTable[i].width,
+ PaperTable[i].length);
+ exit (-1);
+ }
+ else
+ {
+ page->mode |= PAGE_MODE_PAPERSIZE;
+ }
+ break;
+ case 'R': /* rotate image or cropped segment */
+ crop_data->crop_mode |= CROP_ROTATE;
+ switch (strtoul(optarg, NULL, 0))
+ {
+ case 90: crop_data->rotation = (uint16)90;
+ break;
+ case 180: crop_data->rotation = (uint16)180;
+ break;
+ case 270: crop_data->rotation = (uint16)270;
+ break;
+ default: TIFFError ("Rotation must be 90, 180, or 270 degrees clockwise", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'S': /* subdivide into Cols:Rows sections, eg 3:2 would be 3 across and 2 down */
+ sep = strpbrk(optarg, ",:");
+ if (sep)
+ {
+ *sep = '\0';
+ page->cols = atoi(optarg);
+ page->rows = atoi(sep +1);
+ }
+ else
+ {
+ page->cols = atoi(optarg);
+ page->rows = atoi(optarg);
+ }
+ if ((page->cols * page->rows) > MAX_SECTIONS)
+ {
+ TIFFError ("Limit for subdivisions, ie rows x columns, exceeded", "%d", MAX_SECTIONS);
+ exit (-1);
+ }
+ page->mode |= PAGE_MODE_ROWSCOLS;
+ break;
+ case 'U': /* units for measurements and offsets */
+ if (streq(optarg, "in"))
+ {
+ crop_data->res_unit = RESUNIT_INCH;
+ page->res_unit = RESUNIT_INCH;
+ }
+ else if (streq(optarg, "cm"))
+ {
+ crop_data->res_unit = RESUNIT_CENTIMETER;
+ page->res_unit = RESUNIT_CENTIMETER;
+ }
+ else if (streq(optarg, "px"))
+ {
+ crop_data->res_unit = RESUNIT_NONE;
+ page->res_unit = RESUNIT_NONE;
+ }
+ else
+ {
+ TIFFError ("Illegal unit of measure","%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'V': /* set vertical resolution to new value */
+ page->vres = atof (optarg);
+ page->mode |= PAGE_MODE_RESOLUTION;
+ break;
+ case 'X': /* selection width */
+ crop_data->crop_mode |= CROP_WIDTH;
+ crop_data->width = atof(optarg);
+ break;
+ case 'Y': /* selection length */
+ crop_data->crop_mode |= CROP_LENGTH;
+ crop_data->length = atof(optarg);
+ break;
+ case 'Z': /* zones of an image X:Y read as zone X of Y */
+ crop_data->crop_mode |= CROP_ZONES;
+ for (i = 0, opt_ptr = strtok (optarg, ",");
+ ((opt_ptr != NULL) && (i < MAX_REGIONS));
+ (opt_ptr = strtok (NULL, ",")), i++)
+ {
+ crop_data->zones++;
+ opt_offset = strchr(opt_ptr, ':');
+ *opt_offset = '\0';
+ crop_data->zonelist[i].position = atoi(opt_ptr);
+ crop_data->zonelist[i].total = atoi(opt_offset + 1);
+ }
+ /* check for remaining elements over MAX_REGIONS */
+ if ((opt_ptr != NULL) && (i >= MAX_REGIONS))
+ {
+ TIFFError("Zone list exceeds region limit", "%d", MAX_REGIONS);
+ exit (-1);
+ }
+ break;
+ case '?': TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ /*NOTREACHED*/
+ }
+ }
+ } /* end process_command_opts */
+
+/* Start a new output file if one has not been previously opened or
+ * autoindex is set to non-zero. Update page and file counters
+ * so TIFFTAG PAGENUM will be correct in image.
+ */
+static int
+update_output_file (TIFF **tiffout, char *mode, int autoindex,
+ char *outname, unsigned int *page)
+ {
+ static int findex = 0; /* file sequence indicator */
+ char *sep;
+ char filenum[16];
+ char export_ext[16];
+ char exportname[PATH_MAX];
+
+ strcpy (export_ext, ".tiff");
+ if (autoindex && (*tiffout != NULL))
+ {
+ /* Close any export file that was previously opened */
+ TIFFClose (*tiffout);
+ *tiffout = NULL;
+ }
+
+ strncpy (exportname, outname, PATH_MAX - 15);
+ if (*tiffout == NULL) /* This is a new export file */
+ {
+ if (autoindex)
+ { /* create a new filename for each export */
+ findex++;
+ if ((sep = strstr(exportname, ".tif")) || (sep = strstr(exportname, ".TIF")))
+ {
+ strncpy (export_ext, sep, 5);
+ *sep = '\0';
+ }
+ else
+ strncpy (export_ext, ".tiff", 5);
+ export_ext[5] = '\0';
+
+ sprintf (filenum, "-%03d%s", findex, export_ext);
+ filenum[15] = '\0';
+ strncat (exportname, filenum, 14);
+ }
+
+ *tiffout = TIFFOpen(exportname, mode);
+ if (*tiffout == NULL)
+ {
+ TIFFError("update_output_file", "Unable to open output file %s\n", exportname);
+ return 1;
+ }
+ *page = 0;
+
+ return 0;
+ }
+ else
+ (*page)++;
+
+ return 0;
+ } /* end update_output_file */
+
+
+int
+main(int argc, char* argv[])
+ {
+ extern int optind;
+ uint16 defconfig = (uint16) -1;
+ uint16 deffillorder = 0;
+ uint32 deftilewidth = (uint32) 0;
+ uint32 deftilelength = (uint32) 0;
+ uint32 defrowsperstrip = (uint32) 0;
+ uint32 dirnum = 0;
+
+ TIFF *in = NULL;
+ TIFF *out = NULL;
+ char mode[10];
+ char *mp = mode;
+
+ /** RJN additions **/
+ struct image_data image; /* Image parameters for one image */
+ struct crop_mask crop; /* Cropping parameters for all images */
+ struct pagedef page; /* Page definition for output pages */
+ struct pageseg sections[MAX_SECTIONS]; /* Sections of one output page */
+ struct buffinfo seg_buffs[MAX_SECTIONS]; /* Segment buffer sizes and pointers */
+ struct dump_opts dump; /* Data dump options */
+ unsigned char *read_buff = NULL; /* Input image data buffer */
+ unsigned char *crop_buff = NULL; /* Crop area buffer */
+ unsigned char *sect_buff = NULL; /* Image section buffer */
+ unsigned char *sect_src = NULL; /* Image section buffer pointer */
+ unsigned int imagelist[MAX_IMAGES + 1]; /* individually specified images */
+ unsigned int image_count = 0;
+ unsigned int dump_images = 0;
+ unsigned int next_image = 0;
+ unsigned int next_page = 0;
+ unsigned int total_pages = 0;
+ unsigned int total_images = 0;
+ unsigned int end_of_input = FALSE;
+ int seg, length;
+ char temp_filename[PATH_MAX + 1];
+ memset (temp_filename, '\0', PATH_MAX + 1);
+ little_endian = *((unsigned char *)&little_endian) & '1';
+
+ initImageData(&image);
+ initCropMasks(&crop);
+ initPageSetup(&page, sections, seg_buffs);
+ initDumpOptions(&dump);
+
+ process_command_opts (argc, argv, mp, mode, &dirnum, &defconfig,
+ &deffillorder, &deftilewidth, &deftilelength, &defrowsperstrip,
+ &crop, &page, &dump, imagelist, &image_count);
+
+ if (argc - optind < 2)
+ usage();
+
+ if ((argc - optind) == 2)
+ pageNum = -1;
+ else
+ total_images = 0;
+ /* read multiple input files and write to output file(s) */
+ while (optind < argc - 1)
+ {
+ in = TIFFOpen (argv[optind], "r");
+ if (in == NULL)
+ return (-3);
+
+ /* If only one input file is specified, we can use directory count */
+ total_images = TIFFNumberOfDirectories(in);
+ if (image_count == 0)
+ {
+ dirnum = 0;
+ total_pages = total_images; /* Only valid with single input file */
+ }
+ else
+ {
+ dirnum = (tdir_t)(imagelist[next_image] - 1);
+ next_image++;
+
+ /* Total pages only valid for enumerated list of pages not derived
+ * using odd, even, or last keywords.
+ */
+ if (image_count > total_images)
+ image_count = total_images;
+
+ total_pages = image_count;
+ }
+
+ /* MAX_IMAGES is used for special case "last" in selection list */
+ if (dirnum == (MAX_IMAGES - 1))
+ dirnum = total_images - 1;
+
+ if (dirnum > (total_images))
+ {
+ TIFFError (TIFFFileName(in),
+ "Invalid image number %d, File contains only %d images",
+ (int)dirnum + 1, total_images);
+ if (out != NULL)
+ (void) TIFFClose(out);
+ return (1);
+ }
+
+ if (dirnum != 0 && !TIFFSetDirectory(in, (tdir_t)dirnum))
+ {
+ TIFFError(TIFFFileName(in),"Error, setting subdirectory at %d", dirnum);
+ if (out != NULL)
+ (void) TIFFClose(out);
+ return (1);
+ }
+
+ end_of_input = FALSE;
+ while (end_of_input == FALSE)
+ {
+ config = defconfig;
+ compression = defcompression;
+ predictor = defpredictor;
+ fillorder = deffillorder;
+ rowsperstrip = defrowsperstrip;
+ tilewidth = deftilewidth;
+ tilelength = deftilelength;
+ g3opts = defg3opts;
+
+ if (dump.format != DUMP_NONE)
+ {
+ /* manage input and/or output dump files here */
+ dump_images++;
+ length = strlen(dump.infilename);
+ if (length > 0)
+ {
+ if (dump.infile != NULL)
+ fclose (dump.infile);
+
+ sprintf (temp_filename, "%s-read-%03d.%s", dump.infilename, dump_images,
+ (dump.format == DUMP_TEXT) ? "txt" : "raw");
+ if ((dump.infile = fopen(temp_filename, dump.mode)) == NULL)
+ {
+ TIFFError ("Unable to open dump file for writing", "%s", temp_filename);
+ exit (-1);
+ }
+ dump_info(dump.infile, dump.format, "Reading image","%d from %s",
+ dump_images, TIFFFileName(in));
+ }
+ length = strlen(dump.outfilename);
+ if (length > 0)
+ {
+ if (dump.outfile != NULL)
+ fclose (dump.outfile);
+
+ sprintf (temp_filename, "%s-write-%03d.%s", dump.outfilename, dump_images,
+ (dump.format == DUMP_TEXT) ? "txt" : "raw");
+ if ((dump.outfile = fopen(temp_filename, dump.mode)) == NULL)
+ {
+ TIFFError ("Unable to open dump file for writing", "%s", temp_filename);
+ exit (-1);
+ }
+ dump_info(dump.outfile, dump.format, "Writing image","%d from %s",
+ dump_images, TIFFFileName(in));
+ }
+ }
+
+ if (dump.debug)
+ TIFFError("main", "Reading image %4d of %4d total pages.", dirnum + 1, total_pages);
+
+ if (loadImage(in, &image, &dump, &read_buff))
+ {
+ TIFFError("main", "Unable to load source image");
+ exit (-1);
+ }
+
+ /* Correct the image orientation if it was not ORIENTATION_TOPLEFT.
+ */
+ if (image.adjustments != 0)
+ {
+ if (correct_orientation(&image, &read_buff))
+ TIFFError("main", "Unable to correct image orientation");
+ }
+
+ if (getCropOffsets(&image, &crop, &dump))
+ {
+ TIFFError("main", "Unable to define crop regions");
+ exit (-1);
+ }
+
+ if (crop.selections > 0)
+ {
+ if (processCropSelections(&image, &crop, &read_buff, seg_buffs))
+ {
+ TIFFError("main", "Unable to process image selections");
+ exit (-1);
+ }
+ }
+ else /* Single image segment without zones or regions */
+ {
+ if (createCroppedImage(&image, &crop, &read_buff, &crop_buff))
+ {
+ TIFFError("main", "Unable to create output image");
+ exit (-1);
+ }
+ }
+ if (page.mode == PAGE_MODE_NONE)
+ { /* Whole image or sections not based on output page size */
+ if (crop.selections > 0)
+ {
+ writeSelections(in, &out, &crop, &image, &dump, seg_buffs,
+ mp, argv[argc - 1], &next_page, total_pages);
+ }
+ else /* One file all images and sections */
+ {
+ if (update_output_file (&out, mp, crop.exp_mode, argv[argc - 1],
+ &next_page))
+ exit (1);
+ if (writeCroppedImage(in, out, &image, &dump,crop.combined_width,
+ crop.combined_length, crop_buff, next_page, total_pages))
+ {
+ TIFFError("main", "Unable to write new image");
+ exit (-1);
+ }
+ }
+ }
+ else
+ {
+ /* If we used a crop buffer, our data is there, otherwise it is
+ * in the read_buffer
+ */
+ if (crop_buff != NULL)
+ sect_src = crop_buff;
+ else
+ sect_src = read_buff;
+ /* Break input image into pages or rows and columns */
+ if (computeOutputPixelOffsets(&crop, &image, &page, sections, &dump))
+ {
+ TIFFError("main", "Unable to compute output section data");
+ exit (-1);
+ }
+ /* If there are multiple files on the command line, the final one is assumed
+ * to be the output filename into which the images are written.
+ */
+ if (update_output_file (&out, mp, crop.exp_mode, argv[argc - 1], &next_page))
+ exit (1);
+
+ if (writeImageSections(in, out, &image, &page, sections, &dump, sect_src, &sect_buff))
+ {
+ TIFFError("main", "Unable to write image sections");
+ exit (-1);
+ }
+ }
+
+ /* No image list specified, just read the next image */
+ if (image_count == 0)
+ dirnum++;
+ else
+ {
+ dirnum = (tdir_t)(imagelist[next_image] - 1);
+ next_image++;
+ }
+
+ if (dirnum == MAX_IMAGES - 1)
+ dirnum = TIFFNumberOfDirectories(in) - 1;
+
+ if (!TIFFSetDirectory(in, (tdir_t)dirnum))
+ end_of_input = TRUE;
+ }
+ TIFFClose(in);
+ optind++;
+ }
+
+ /* If we did not use the read buffer as the crop buffer */
+ if (read_buff)
+ _TIFFfree(read_buff);
+
+ if (crop_buff)
+ _TIFFfree(crop_buff);
+
+ if (sect_buff)
+ _TIFFfree(sect_buff);
+
+ /* Clean up any segment buffers used for zones or regions */
+ for (seg = 0; seg < crop.selections; seg++)
+ _TIFFfree (seg_buffs[seg].buffer);
+
+ if (dump.format != DUMP_NONE)
+ {
+ if (dump.infile != NULL)
+ fclose (dump.infile);
+
+ if (dump.outfile != NULL)
+ {
+ dump_info (dump.outfile, dump.format, "", "Completed run for %s", TIFFFileName(out));
+ fclose (dump.outfile);
+ }
+ }
+
+ TIFFClose(out);
+
+ return (0);
+ } /* end main */
+
+
+/* Debugging functions */
+static int dump_data (FILE *dumpfile, int format, char *dump_tag, unsigned char *data, uint32 count)
+ {
+ int j, k;
+ uint32 i;
+ char dump_array[10];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (i = 0; i < count; i++)
+ {
+ for (j = 0, k = 7; j < 8; j++, k--)
+ {
+ bitset = (*(data + i)) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ }
+ dump_array[8] = '\0';
+ fprintf (dumpfile," %s", dump_array);
+ }
+ fprintf (dumpfile,"\n");
+ }
+ else
+ {
+ if ((fwrite (data, 1, count, dumpfile)) != count)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+
+static int dump_byte (FILE *dumpfile, int format, char *dump_tag, unsigned char data)
+ {
+ int j, k;
+ char dump_array[10];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (j = 0, k = 7; j < 8; j++, k--)
+ {
+ bitset = data & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ }
+ dump_array[8] = '\0';
+ fprintf (dumpfile," %s\n", dump_array);
+ }
+ else
+ {
+ if ((fwrite (&data, 1, 1, dumpfile)) != 1)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+
+static int dump_short (FILE *dumpfile, int format, char *dump_tag, uint16 data)
+ {
+ int j, k;
+ char dump_array[20];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (j = 0, k = 15; k >= 0; j++, k--)
+ {
+ bitset = data & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ if ((k % 8) == 0)
+ sprintf(&dump_array[++j], " ");
+ }
+ dump_array[17] = '\0';
+ fprintf (dumpfile," %s\n", dump_array);
+ }
+ else
+ {
+ if ((fwrite (&data, 2, 1, dumpfile)) != 2)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+
+static int dump_long (FILE *dumpfile, int format, char *dump_tag, uint32 data)
+ {
+ int j, k;
+ char dump_array[40];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (j = 0, k = 31; k >= 0; j++, k--)
+ {
+ bitset = data & (((uint32)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ if ((k % 8) == 0)
+ sprintf(&dump_array[++j], " ");
+ }
+ dump_array[35] = '\0';
+ fprintf (dumpfile," %s\n", dump_array);
+ }
+ else
+ {
+ if ((fwrite (&data, 4, 1, dumpfile)) != 4)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+ return (0);
+ }
+
+static int dump_wide (FILE *dumpfile, int format, char *dump_tag, uint64 data)
+ {
+ int j, k;
+ char dump_array[80];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (j = 0, k = 63; k >= 0; j++, k--)
+ {
+ bitset = data & (((uint64)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ if ((k % 8) == 0)
+ sprintf(&dump_array[++j], " ");
+ }
+ dump_array[71] = '\0';
+ fprintf (dumpfile," %s\n", dump_array);
+ }
+ else
+ {
+ if ((fwrite (&data, 8, 1, dumpfile)) != 8)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+
+static void dump_info(FILE *dumpfile, int format, char *prefix, char *msg, ...)
+ {
+ if (format == DUMP_TEXT)
+ {
+ va_list ap;
+ va_start(ap, msg);
+ fprintf(dumpfile, "%s ", prefix);
+ vfprintf(dumpfile, msg, ap);
+ fprintf(dumpfile, "\n");
+ }
+ }
+
+static int dump_buffer (FILE* dumpfile, int format, uint32 rows, uint32 width,
+ uint32 row, unsigned char *buff)
+ {
+ int j, k;
+ uint32 i;
+ unsigned char * dump_ptr;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ for (i = 0; i < rows; i++)
+ {
+ dump_ptr = buff + (i * width);
+ if (format == DUMP_TEXT)
+ dump_info (dumpfile, format, "",
+ "Row %4d, %d bytes at offset %d",
+ row + i + 1, width, row * width);
+
+ for (j = 0, k = width; k >= 10; j += 10, k -= 10, dump_ptr += 10)
+ dump_data (dumpfile, format, "", dump_ptr, 10);
+ if (k > 0)
+ dump_data (dumpfile, format, "", dump_ptr, k);
+ }
+ return (0);
+ }
+
+/* Extract one or more samples from an interleaved buffer. If count == 1,
+ * only the sample plane indicated by sample will be extracted. If count > 1,
+ * count samples beginning at sample will be extracted. Portions of a
+ * scanline can be extracted by specifying a start and end value.
+ */
+
+static int
+extractContigSamplesBytes (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int i, bytes_per_sample, sindex;
+ uint32 col, dst_rowsize, bit_offset;
+ uint32 src_byte, src_bit;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamplesBytes","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesBytes",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesBytes",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ dst_rowsize = (bps * (end - start) * count) / 8;
+
+ bytes_per_sample = (bps + 7) / 8;
+ /* Optimize case for copying all samples */
+ if (count == spp)
+ {
+ src = in + (start * spp * bytes_per_sample);
+ _TIFFmemcpy (dst, src, dst_rowsize);
+ }
+ else
+ {
+ for (col = start; col < end; col++)
+ {
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ bit_offset = col * bps * spp;
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+ src = in + src_byte;
+ for (i = 0; i < bytes_per_sample; i++)
+ *dst++ = *src++;
+ }
+ }
+ }
+
+ return (0);
+ } /* end extractContigSamplesBytes */
+
+static int
+extractContigSamples8bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint8 maskbits = 0, matchbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamples8bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamples8bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamples8bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = 0;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+ buff1 = buff2 = 0;
+ for (col = start; col < end; col++)
+ { /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (8 - src_bit - bps);
+ buff1 = ((*src) & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ }
+ else
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ ready_bits += bps;
+ }
+ }
+
+ while (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamples8bits */
+
+static int
+extractContigSamples16bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint16 maskbits = 0, matchbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamples16bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamples16bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamples16bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = 0;
+ maskbits = (uint16)-1 >> (16 - bps);
+
+ for (col = start; col < end; col++)
+ { /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (16 - src_bit - bps);
+
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+ if (ready_bits < 8) /* add another bps bits to the buffer */
+ {
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamples16bits */
+
+
+static int
+extractContigSamples24bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint32 maskbits = 0, matchbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((in == NULL) || (out == NULL))
+ {
+ TIFFError("extractContigSamples24bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamples24bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamples24bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = 0;
+ maskbits = (uint32)-1 >> ( 32 - bps);
+ for (col = start; col < end; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (32 - src_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ if (ready_bits < 16) /* add another bps bits to the buffer */
+ {
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamples24bits */
+
+static int
+extractContigSamples32bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int ready_bits = 0, sindex = 0, shift_width = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((in == NULL) || (out == NULL))
+ {
+ TIFFError("extractContigSamples32bits","Invalid input or output buffer");
+ return (1);
+ }
+
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamples32bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamples32bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ shift_width = ((bps + 7) / 8) + 1;
+ ready_bits = 0;
+ maskbits = (uint64)-1 >> ( 64 - bps);
+ for (col = start; col < end; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (64 - src_bit - bps);
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 32)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamples32bits */
+
+static int
+extractContigSamplesShifted8bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end,
+ int shift)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint8 maskbits = 0, matchbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamplesShifted8bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesShifted8bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesShifted8bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = shift;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+ buff1 = buff2 = 0;
+ for (col = start; col < end; col++)
+ { /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (8 - src_bit - bps);
+ buff1 = ((*src) & matchbits) << (src_bit);
+ if ((col == start) && (sindex == sample))
+ buff2 = *src & ((uint8)-1) << (shift);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ |= buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ }
+ else
+ buff2 = buff2 | (buff1 >> ready_bits);
+ ready_bits += bps;
+ }
+ }
+
+ while (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamplesShifted8bits */
+
+static int
+extractContigSamplesShifted16bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end,
+ int shift)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint16 maskbits = 0, matchbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamplesShifted16bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesShifted16bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesShifted16bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = shift;
+ maskbits = (uint16)-1 >> (16 - bps);
+ for (col = start; col < end; col++)
+ { /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (16 - src_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+
+ if ((col == start) && (sindex == sample))
+ buff2 = buff1 & ((uint16)-1) << (8 - shift);
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ if (ready_bits < 8) /* add another bps bits to the buffer */
+ buff2 = buff2 | (buff1 >> ready_bits);
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ }
+
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamplesShifted16bits */
+
+
+static int
+extractContigSamplesShifted24bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end,
+ int shift)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint32 maskbits = 0, matchbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((in == NULL) || (out == NULL))
+ {
+ TIFFError("extractContigSamplesShifted24bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesShifted24bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesShifted24bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = shift;
+ maskbits = (uint32)-1 >> ( 32 - bps);
+ for (col = start; col < end; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (32 - src_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+
+ if ((col == start) && (sindex == sample))
+ buff2 = buff1 & ((uint32)-1) << (16 - shift);
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ if (ready_bits < 16) /* add another bps bits to the buffer */
+ {
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamplesShifted24bits */
+
+static int
+extractContigSamplesShifted32bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end,
+ int shift)
+ {
+ int ready_bits = 0, sindex = 0, shift_width = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((in == NULL) || (out == NULL))
+ {
+ TIFFError("extractContigSamplesShifted32bits","Invalid input or output buffer");
+ return (1);
+ }
+
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesShifted32bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesShifted32bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ shift_width = ((bps + 7) / 8) + 1;
+ ready_bits = shift;
+ maskbits = (uint64)-1 >> ( 64 - bps);
+ for (col = start; col < end; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (64 - src_bit - bps);
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ if ((col == start) && (sindex == sample))
+ buff2 = buff3 & ((uint64)-1) << (32 - shift);
+
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ if (ready_bits < 32)
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamplesShifted32bits */
+
+static int
+extractContigSamplesToBuffer(uint8 *out, uint8 *in, uint32 rows, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ struct dump_opts *dump)
+ {
+ int shift_width, bytes_per_sample, bytes_per_pixel;
+ uint32 src_rowsize, src_offset, row, first_col = 0;
+ uint32 dst_rowsize, dst_offset;
+ tsample_t count = 1;
+ uint8 *src, *dst;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if ((bps % 8) == 0)
+ shift_width = 0;
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+ src_rowsize = ((bps * spp * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols) + 7) / 8;
+
+ if ((dump->outfile != NULL) && (dump->level == 4))
+ {
+ dump_info (dump->outfile, dump->format, "extractContigSamplesToBuffer",
+ "Sample %d, %d rows", sample + 1, rows + 1);
+ }
+ for (row = 0; row < rows; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = row * dst_rowsize;
+ src = in + src_offset;
+ dst = out + dst_offset;
+
+ /* pack the data into the scanline */
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamples8bits (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ }
+ else
+ if (extractContigSamples16bits (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ case 2: if (extractContigSamples24bits (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamples32bits (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ default: TIFFError ("extractContigSamplesToBuffer", "Unsupported bit depth: %d", bps);
+ return (1);
+ }
+ if ((dump->outfile != NULL) && (dump->level == 4))
+ dump_buffer(dump->outfile, dump->format, 1, dst_rowsize, row, dst);
+ }
+
+ return (0);
+ } /* end extractContigSamplesToBuffer */
+
+static int
+extractContigSamplesToTileBuffer(uint8 *out, uint8 *in, uint32 rows, uint32 cols,
+ uint32 imagewidth, uint32 tilewidth, tsample_t sample,
+ uint16 count, uint16 spp, uint16 bps, struct dump_opts *dump)
+ {
+ int shift_width, bytes_per_sample, bytes_per_pixel;
+ uint32 src_rowsize, src_offset, row;
+ uint32 dst_rowsize, dst_offset;
+ uint8 *src, *dst;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if ((bps % 8) == 0)
+ shift_width = 0;
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+
+ if ((dump->outfile != NULL) && (dump->level == 4))
+ {
+ dump_info (dump->outfile, dump->format, "extractContigSamplesToTileBuffer",
+ "Sample %d, %d rows", sample + 1, rows + 1);
+ }
+
+ src_rowsize = ((bps * spp * imagewidth) + 7) / 8;
+ dst_rowsize = ((bps * tilewidth * count) + 7) / 8;
+
+ for (row = 0; row < rows; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = row * dst_rowsize;
+ src = in + src_offset;
+ dst = out + dst_offset;
+
+ /* pack the data into the scanline */
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamples8bits (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ }
+ else
+ if (extractContigSamples16bits (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ case 2: if (extractContigSamples24bits (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamples32bits (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ default: TIFFError ("extractContigSamplesToTileBuffer", "Unsupported bit depth: %d", bps);
+ return (1);
+ }
+ if ((dump->outfile != NULL) && (dump->level == 4))
+ dump_buffer(dump->outfile, dump->format, 1, dst_rowsize, row, dst);
+ }
+
+ return (0);
+ } /* end extractContigSamplesToTileBuffer */
+
+static int readContigStripsIntoBuffer (TIFF* in, uint8* buf)
+ {
+ uint8* bufp = buf;
+ int32 bytes_read = 0;
+ uint16 strip, nstrips = TIFFNumberOfStrips(in);
+ uint32 stripsize = TIFFStripSize(in);
+ uint32 rows = 0;
+ uint32 rps = TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rps);
+ tsize_t scanline_size = TIFFScanlineSize(in);
+
+ for (strip = 0; strip < nstrips; strip++)
+ {
+ bytes_read = TIFFReadEncodedStrip (in, strip, bufp, -1);
+ rows = bytes_read / scanline_size;
+ if ((strip < (nstrips - 1)) && (bytes_read != (int32)stripsize))
+ TIFFError("", "Strip %d: read %lu bytes, strip size %lu",
+ (int)strip + 1, (unsigned long) bytes_read, (unsigned long)stripsize);
+
+ if (bytes_read < 0 && !ignore)
+ {
+ TIFFError("", "Error reading strip %lu after %lu rows",
+ (unsigned long) strip, (unsigned long)rows);
+ return 0;
+ }
+ bufp += bytes_read;
+ }
+
+ return 1;
+ } /* end readContigStripsIntoBuffer */
+
+static int
+combineSeparateSamplesBytes (unsigned char *srcbuffs[], unsigned char *out,
+ uint32 cols, uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int i, bytes_per_sample;
+ uint32 row, col, col_offset, src_rowsize, dst_rowsize, row_offset;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t s;
+
+ src = srcbuffs[0];
+ dst = out;
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamplesBytes","Invalid buffer address");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * spp * cols) + 7) / 8;
+ for (row = 0; row < rows; row++)
+ {
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ for (s = 0; s < spp; s++)
+ {
+ dump_info (dumpfile, format, "combineSeparateSamplesBytes","Input data, Sample %d", s);
+ dump_buffer(dumpfile, format, 1, cols, row, srcbuffs[s] + (row * src_rowsize));
+ }
+ }
+ dst = out + (row * dst_rowsize);
+ row_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ col_offset = row_offset + (col * (bps / 8));
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ src = srcbuffs[s] + col_offset;
+ for (i = 0; i < bytes_per_sample; i++)
+ *(dst + i) = *(src + i);
+ src += bytes_per_sample;
+ dst += bytes_per_sample;
+ }
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamplesBytes","Output data, combined samples");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamplesBytes */
+
+static int
+combineSeparateSamples8bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0;
+ int bytes_per_sample = 0;
+ uint32 src_rowsize, dst_rowsize, src_offset;
+ uint32 bit_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint8 maskbits = 0, matchbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[32];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamples8bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols * spp) + 7) / 8;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (8 - src_bit - bps);
+ /* load up next sample from each plane */
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ buff1 = ((*src) & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ strcpy (action, "Flush");
+ }
+ else
+ {
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Match bits", matchbits);
+ dump_byte (dumpfile, format, "Src bits", *src);
+ dump_byte (dumpfile, format, "Buff1 bits", buff1);
+ dump_byte (dumpfile, format, "Buff2 bits", buff2);
+ dump_info (dumpfile, format, "","%s", action);
+ }
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Final bits", buff1);
+ }
+ }
+
+ if ((dumpfile != NULL) && (level >= 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamples8bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamples8bits */
+
+static int
+combineSeparateSamples16bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0, bytes_per_sample = 0;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 bit_offset, src_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint16 maskbits = 0, matchbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamples16bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols * spp) + 7) / 8;
+ maskbits = (uint16)-1 >> (16 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (16 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+
+ dump_short (dumpfile, format, "Match bits", matchbits);
+ dump_data (dumpfile, format, "Src bits", src, 2);
+ dump_short (dumpfile, format, "Buff1 bits", buff1);
+ dump_short (dumpfile, format, "Buff2 bits", buff2);
+ dump_byte (dumpfile, format, "Write byte", bytebuff);
+ dump_info (dumpfile, format, "","Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ if (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Final bits", bytebuff);
+ }
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamples16bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamples16bits */
+
+static int
+combineSeparateSamples24bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0, bytes_per_sample = 0;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 bit_offset, src_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint32 maskbits = 0, matchbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamples24bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols * spp) + 7) / 8;
+ maskbits = (uint32)-1 >> ( 32 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (32 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 16)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "","Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "", "Ready bits: %2d", ready_bits);
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamples24bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamples24bits */
+
+static int
+combineSeparateSamples32bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0, bytes_per_sample = 0, shift_width = 0;
+ uint32 src_rowsize, dst_rowsize, bit_offset, src_offset;
+ uint32 src_byte = 0, src_bit = 0;
+ uint32 row, col;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamples32bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols * spp) + 7) / 8;
+ maskbits = (uint64)-1 >> ( 64 - bps);
+ shift_width = ((bps + 7) / 8) + 1;
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (64 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 32)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Sample %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_wide (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 8);
+ dump_wide (dumpfile, format, "Buff1 bits ", buff1);
+ dump_wide (dumpfile, format, "Buff2 bits ", buff2);
+ dump_info (dumpfile, format, "", "Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "", "Ready bits: %2d", ready_bits);
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamples32bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out);
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamples32bits */
+
+static int
+combineSeparateTileSamplesBytes (unsigned char *srcbuffs[], unsigned char *out,
+ uint32 cols, uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int i, bytes_per_sample;
+ uint32 row, col, col_offset, src_rowsize, dst_rowsize, src_offset;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t s;
+
+ src = srcbuffs[0];
+ dst = out;
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamplesBytes","Invalid buffer address");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = imagewidth * bytes_per_sample * spp;
+ for (row = 0; row < rows; row++)
+ {
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ for (s = 0; s < spp; s++)
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamplesBytes","Input data, Sample %d", s);
+ dump_buffer(dumpfile, format, 1, cols, row, srcbuffs[s] + (row * src_rowsize));
+ }
+ }
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+#ifdef DEVELMODE
+ TIFFError("","Tile row %4d, Src offset %6d Dst offset %6d",
+ row, src_offset, dst - out);
+#endif
+ for (col = 0; col < cols; col++)
+ {
+ col_offset = src_offset + (col * (bps / 8));
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ src = srcbuffs[s] + col_offset;
+ for (i = 0; i < bytes_per_sample; i++)
+ *(dst + i) = *(src + i);
+ dst += bytes_per_sample;
+ }
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamplesBytes","Output data, combined samples");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamplesBytes */
+
+static int
+combineSeparateTileSamples8bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0;
+ uint32 src_rowsize, dst_rowsize, src_offset;
+ uint32 bit_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint8 maskbits = 0, matchbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[32];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamples8bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (8 - src_bit - bps);
+ /* load up next sample from each plane */
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ buff1 = ((*src) & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ strcpy (action, "Flush");
+ }
+ else
+ {
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Match bits", matchbits);
+ dump_byte (dumpfile, format, "Src bits", *src);
+ dump_byte (dumpfile, format, "Buff1 bits", buff1);
+ dump_byte (dumpfile, format, "Buff2 bits", buff2);
+ dump_info (dumpfile, format, "","%s", action);
+ }
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Final bits", buff1);
+ }
+ }
+
+ if ((dumpfile != NULL) && (level >= 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamples8bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamples8bits */
+
+static int
+combineSeparateTileSamples16bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 bit_offset, src_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint16 maskbits = 0, matchbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamples16bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ maskbits = (uint16)-1 >> (16 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (16 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+
+ dump_short (dumpfile, format, "Match bits", matchbits);
+ dump_data (dumpfile, format, "Src bits", src, 2);
+ dump_short (dumpfile, format, "Buff1 bits", buff1);
+ dump_short (dumpfile, format, "Buff2 bits", buff2);
+ dump_byte (dumpfile, format, "Write byte", bytebuff);
+ dump_info (dumpfile, format, "","Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ if (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Final bits", bytebuff);
+ }
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamples16bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamples16bits */
+
+static int
+combineSeparateTileSamples24bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 bit_offset, src_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint32 maskbits = 0, matchbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamples24bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ maskbits = (uint32)-1 >> ( 32 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (32 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 16)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "","Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "", "Ready bits: %2d", ready_bits);
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamples24bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamples24bits */
+
+static int
+combineSeparateTileSamples32bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0, shift_width = 0;
+ uint32 src_rowsize, dst_rowsize, bit_offset, src_offset;
+ uint32 src_byte = 0, src_bit = 0;
+ uint32 row, col;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamples32bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ maskbits = (uint64)-1 >> ( 64 - bps);
+ shift_width = ((bps + 7) / 8) + 1;
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (64 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 32)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Sample %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_wide (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 8);
+ dump_wide (dumpfile, format, "Buff1 bits ", buff1);
+ dump_wide (dumpfile, format, "Buff2 bits ", buff2);
+ dump_info (dumpfile, format, "", "Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "", "Ready bits: %2d", ready_bits);
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamples32bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out);
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamples32bits */
+
+
+static int readSeparateStripsIntoBuffer (TIFF *in, uint8 *obuf, uint32 length,
+ uint32 width, uint16 spp,
+ struct dump_opts *dump)
+ {
+ int i, j, bytes_per_sample, bytes_per_pixel, shift_width, result = 1;
+ int32 bytes_read = 0;
+ uint16 bps, nstrips, planar, strips_per_sample;
+ uint32 src_rowsize, dst_rowsize, rows_processed, rps;
+ uint32 rows_this_strip = 0;
+ tsample_t s;
+ tstrip_t strip;
+ tsize_t scanlinesize = TIFFScanlineSize(in);
+ tsize_t stripsize = TIFFStripSize(in);
+ unsigned char *srcbuffs[MAX_SAMPLES];
+ unsigned char *buff = NULL;
+ unsigned char *dst = NULL;
+
+ if (obuf == NULL)
+ {
+ TIFFError("readSeparateStripsIntoBuffer","Invalid buffer argument");
+ return (0);
+ }
+
+ memset (srcbuffs, '\0', sizeof(srcbuffs));
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bps);
+ TIFFGetFieldDefaulted(in, TIFFTAG_PLANARCONFIG, &planar);
+ TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rps);
+ if (rps > length)
+ rps = length;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ src_rowsize = ((bps * width) + 7) / 8;
+ dst_rowsize = ((bps * width * spp) + 7) / 8;
+ dst = obuf;
+
+ if ((dump->infile != NULL) && (dump->level == 3))
+ {
+ dump_info (dump->infile, dump->format, "",
+ "Image width %d, length %d, Scanline size, %4d bytes",
+ width, length, scanlinesize);
+ dump_info (dump->infile, dump->format, "",
+ "Bits per sample %d, Samples per pixel %d, Shift width %d",
+ bps, spp, shift_width);
+ }
+
+ /* Libtiff seems to assume/require that data for separate planes are
+ * written one complete plane after another and not interleaved in any way.
+ * Multiple scanlines and possibly strips of the same plane must be
+ * written before data for any other plane.
+ */
+ nstrips = TIFFNumberOfStrips(in);
+ strips_per_sample = nstrips /spp;
+
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ srcbuffs[s] = NULL;
+ buff = _TIFFmalloc(stripsize);
+ if (!buff)
+ {
+ TIFFError ("readSeparateStripsIntoBuffer",
+ "Unable to allocate strip read buffer for sample %d", s);
+ for (i = 0; i < s; i++)
+ _TIFFfree (srcbuffs[i]);
+ return 0;
+ }
+ srcbuffs[s] = buff;
+ }
+
+ rows_processed = 0;
+ for (j = 0; (j < strips_per_sample) && (result == 1); j++)
+ {
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ buff = srcbuffs[s];
+ strip = (s * strips_per_sample) + j;
+ bytes_read = TIFFReadEncodedStrip (in, strip, buff, stripsize);
+ rows_this_strip = bytes_read / src_rowsize;
+ if (bytes_read < 0 && !ignore)
+ {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read strip %lu for sample %d",
+ (unsigned long) strip, s + 1);
+ result = 0;
+ break;
+ }
+#ifdef DEVELMODE
+ TIFFError("", "Strip %2d, read %5d bytes for %4d scanlines, shift width %d",
+ strip, bytes_read, rows_this_strip, shift_width);
+#endif
+ }
+
+ if (rps > rows_this_strip)
+ rps = rows_this_strip;
+ dst = obuf + (dst_rowsize * rows_processed);
+ if ((bps % 8) == 0)
+ {
+ if (combineSeparateSamplesBytes (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ }
+ else
+ {
+ switch (shift_width)
+ {
+ case 1: if (combineSeparateSamples8bits (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ break;
+ case 2: if (combineSeparateSamples16bits (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ break;
+ case 3: if (combineSeparateSamples24bits (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8: if (combineSeparateSamples32bits (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ break;
+ default: TIFFError ("readSeparateStripsIntoBuffer", "Unsupported bit depth: %d", bps);
+ result = 0;
+ break;
+ }
+ }
+
+ if ((rows_processed + rps) > length)
+ {
+ rows_processed = length;
+ rps = length - rows_processed;
+ }
+ else
+ rows_processed += rps;
+ }
+
+ /* free any buffers allocated for each plane or scanline and
+ * any temporary buffers
+ */
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ buff = srcbuffs[s];
+ if (buff != NULL)
+ _TIFFfree(buff);
+ }
+
+ return (result);
+ } /* end readSeparateStripsIntoBuffer */
+
+static int
+get_page_geometry (char *name, struct pagedef *page)
+ {
+ char *ptr;
+ int n;
+
+ for (ptr = name; *ptr; ptr++)
+ *ptr = (char)tolower((int)*ptr);
+
+ for (n = 0; n < MAX_PAPERNAMES; n++)
+ {
+ if (strcmp(name, PaperTable[n].name) == 0)
+ {
+ page->width = PaperTable[n].width;
+ page->length = PaperTable[n].length;
+ strncpy (page->name, PaperTable[n].name, 15);
+ page->name[15] = '\0';
+ return (0);
+ }
+ }
+
+ return (1);
+ }
+
+
+static void
+initPageSetup (struct pagedef *page, struct pageseg *pagelist,
+ struct buffinfo seg_buffs[])
+ {
+ int i;
+
+ strcpy (page->name, "");
+ page->mode = PAGE_MODE_NONE;
+ page->res_unit = RESUNIT_NONE;
+ page->hres = 0.0;
+ page->vres = 0.0;
+ page->width = 0.0;
+ page->length = 0.0;
+ page->hmargin = 0.0;
+ page->vmargin = 0.0;
+ page->rows = 0;
+ page->cols = 0;
+ page->orient = ORIENTATION_NONE;
+
+ for (i = 0; i < MAX_SECTIONS; i++)
+ {
+ pagelist[i].x1 = (uint32)0;
+ pagelist[i].x2 = (uint32)0;
+ pagelist[i].y1 = (uint32)0;
+ pagelist[i].y2 = (uint32)0;
+ pagelist[i].buffsize = (uint32)0;
+ pagelist[i].position = 0;
+ pagelist[i].total = 0;
+ }
+
+ for (i = 0; i < MAX_OUTBUFFS; i++)
+ {
+ seg_buffs[i].size = 0;
+ seg_buffs[i].buffer = NULL;
+ }
+ }
+
+static void
+initImageData (struct image_data *image)
+ {
+ image->xres = 0.0;
+ image->yres = 0.0;
+ image->width = 0;
+ image->length = 0;
+ image->res_unit = RESUNIT_NONE;
+ image->bps = 0;
+ image->spp = 0;
+ image->planar = 0;
+ image->photometric = 0;
+ image->orientation = 0;
+ image->adjustments = 0;
+ }
+
+static void
+initCropMasks (struct crop_mask *cps)
+ {
+ int i;
+
+ cps->crop_mode = CROP_NONE;
+ cps->res_unit = RESUNIT_NONE;
+ cps->edge_ref = EDGE_TOP;
+ cps->width = 0;
+ cps->length = 0;
+ for (i = 0; i < 4; i++)
+ cps->margins[i] = 0.0;
+ cps->bufftotal = (uint32)0;
+ cps->combined_width = (uint32)0;
+ cps->combined_length = (uint32)0;
+ cps->rotation = (uint16)0;
+ cps->photometric = INVERT_DATA_AND_TAG;
+ cps->mirror = (uint16)0;
+ cps->invert = (uint16)0;
+ cps->zones = (uint32)0;
+ cps->regions = (uint32)0;
+ for (i = 0; i < MAX_REGIONS; i++)
+ {
+ cps->corners[i].X1 = 0.0;
+ cps->corners[i].X2 = 0.0;
+ cps->corners[i].Y1 = 0.0;
+ cps->corners[i].Y2 = 0.0;
+ cps->regionlist[i].x1 = 0;
+ cps->regionlist[i].x2 = 0;
+ cps->regionlist[i].y1 = 0;
+ cps->regionlist[i].y2 = 0;
+ cps->regionlist[i].width = 0;
+ cps->regionlist[i].length = 0;
+ cps->regionlist[i].buffsize = 0;
+ cps->regionlist[i].buffptr = NULL;
+ cps->zonelist[i].position = 0;
+ cps->zonelist[i].total = 0;
+ }
+ cps->exp_mode = ONE_FILE_COMPOSITE;
+ cps->img_mode = COMPOSITE_IMAGES;
+ }
+
+static void initDumpOptions(struct dump_opts *dump)
+ {
+ dump->debug = 0;
+ dump->format = DUMP_NONE;
+ dump->level = 1;
+ sprintf (dump->mode, "w");
+ memset (dump->infilename, '\0', PATH_MAX + 1);
+ memset (dump->outfilename, '\0',PATH_MAX + 1);
+ dump->infile = NULL;
+ dump->outfile = NULL;
+ }
+
+/* Compute pixel offsets into the image for margins and fixed regions */
+static int
+computeInputPixelOffsets(struct crop_mask *crop, struct image_data *image,
+ struct offset *off)
+ {
+ double scale;
+ float xres, yres;
+ /* Values for these offsets are in pixels from start of image, not bytes,
+ * and are indexed from zero to width - 1 or length - 1 */
+ uint32 tmargin, bmargin, lmargin, rmargin;
+ uint32 startx, endx; /* offsets of first and last columns to extract */
+ uint32 starty, endy; /* offsets of first and last row to extract */
+ uint32 width, length, crop_width, crop_length;
+ uint32 i, max_width, max_length, zwidth, zlength, buffsize;
+ uint32 x1, x2, y1, y2;
+
+ if (image->res_unit != RESUNIT_INCH && image->res_unit != RESUNIT_CENTIMETER)
+ {
+ xres = 1.0;
+ yres = 1.0;
+ }
+ else
+ {
+ if (((image->xres == 0) || (image->yres == 0)) &&
+ (crop->res_unit != RESUNIT_NONE) &&
+ ((crop->crop_mode & CROP_REGIONS) || (crop->crop_mode & CROP_MARGINS) ||
+ (crop->crop_mode & CROP_LENGTH) || (crop->crop_mode & CROP_WIDTH)))
+ {
+ TIFFError("computeInputPixelOffsets", "Cannot compute margins or fixed size sections without image resolution");
+ TIFFError("computeInputPixelOffsets", "Specify units in pixels and try again");
+ return (-1);
+ }
+ xres = image->xres;
+ yres = image->yres;
+ }
+
+ /* Translate user units to image units */
+ scale = 1.0;
+ switch (crop->res_unit) {
+ case RESUNIT_CENTIMETER:
+ if (image->res_unit == RESUNIT_INCH)
+ scale = 1.0/2.54;
+ break;
+ case RESUNIT_INCH:
+ if (image->res_unit == RESUNIT_CENTIMETER)
+ scale = 2.54;
+ break;
+ case RESUNIT_NONE: /* Dimensions in pixels */
+ default:
+ break;
+ }
+
+ if (crop->crop_mode & CROP_REGIONS)
+ {
+ max_width = max_length = 0;
+ for (i = 0; i < crop->regions; i++)
+ {
+ if ((crop->res_unit == RESUNIT_INCH) || (crop->res_unit == RESUNIT_CENTIMETER))
+ {
+ x1 = (uint32) (crop->corners[i].X1 * scale * xres);
+ x2 = (uint32) (crop->corners[i].X2 * scale * xres);
+ y1 = (uint32) (crop->corners[i].Y1 * scale * yres);
+ y2 = (uint32) (crop->corners[i].Y2 * scale * yres);
+ }
+ else
+ {
+ x1 = (uint32) (crop->corners[i].X1);
+ x2 = (uint32) (crop->corners[i].X2);
+ y1 = (uint32) (crop->corners[i].Y1);
+ y2 = (uint32) (crop->corners[i].Y2);
+ }
+ if (x1 < 1)
+ crop->regionlist[i].x1 = 0;
+ else
+ crop->regionlist[i].x1 = (uint32) (x1 - 1);
+
+ if (x2 > image->width - 1)
+ crop->regionlist[i].x2 = image->width - 1;
+ else
+ crop->regionlist[i].x2 = (uint32) (x2 - 1);
+ zwidth = crop->regionlist[i].x2 - crop->regionlist[i].x1 + 1;
+
+ if (y1 < 1)
+ crop->regionlist[i].y1 = 0;
+ else
+ crop->regionlist[i].y1 = (uint32) (y1 - 1);
+
+ if (y2 > image->length - 1)
+ crop->regionlist[i].y2 = image->length - 1;
+ else
+ crop->regionlist[i].y2 = (uint32) (y2 - 1);
+
+ zlength = crop->regionlist[i].y2 - crop->regionlist[i].y1 + 1;
+
+ if (zwidth > max_width)
+ max_width = zwidth;
+ if (zlength > max_length)
+ max_length = zlength;
+
+ buffsize = (uint32)
+ (((zwidth * image->bps * image->spp + 7 ) / 8) * (zlength + 1));
+
+ crop->regionlist[i].buffsize = buffsize;
+ crop->bufftotal += buffsize;
+ if (crop->img_mode == COMPOSITE_IMAGES)
+ {
+ switch (crop->edge_ref)
+ {
+ case EDGE_LEFT:
+ case EDGE_RIGHT:
+ crop->combined_length = zlength;
+ crop->combined_width += zwidth;
+ break;
+ case EDGE_BOTTOM:
+ case EDGE_TOP: /* width from left, length from top */
+ default:
+ crop->combined_width = zwidth;
+ crop->combined_length += zlength;
+ break;
+ }
+ }
+ }
+ return (0);
+ }
+
+ /* Convert crop margins into offsets into image
+ * Margins are expressed as pixel rows and columns, not bytes
+ */
+ if (crop->crop_mode & CROP_MARGINS)
+ {
+ if (crop->res_unit != RESUNIT_INCH && crop->res_unit != RESUNIT_CENTIMETER)
+ { /* User has specified pixels as reference unit */
+ tmargin = (uint32)(crop->margins[0]);
+ lmargin = (uint32)(crop->margins[1]);
+ bmargin = (uint32)(crop->margins[2]);
+ rmargin = (uint32)(crop->margins[3]);
+ }
+ else
+ { /* inches or centimeters specified */
+ tmargin = (uint32)(crop->margins[0] * scale * yres);
+ lmargin = (uint32)(crop->margins[1] * scale * xres);
+ bmargin = (uint32)(crop->margins[2] * scale * yres);
+ rmargin = (uint32)(crop->margins[3] * scale * xres);
+ }
+
+ if ((lmargin + rmargin) > image->width)
+ {
+ TIFFError("computeInputPixelOffsets", "Combined left and right margins exceed image width");
+ lmargin = (uint32) 0;
+ rmargin = (uint32) 0;
+ return (-1);
+ }
+ if ((tmargin + bmargin) > image->length)
+ {
+ TIFFError("computeInputPixelOffsets", "Combined top and bottom margins exceed image length");
+ tmargin = (uint32) 0;
+ bmargin = (uint32) 0;
+ return (-1);
+ }
+ }
+ else
+ { /* no margins requested */
+ tmargin = (uint32) 0;
+ lmargin = (uint32) 0;
+ bmargin = (uint32) 0;
+ rmargin = (uint32) 0;
+ }
+
+ /* Width, height, and margins are expressed as pixel offsets into image */
+ if (crop->res_unit != RESUNIT_INCH && crop->res_unit != RESUNIT_CENTIMETER)
+ {
+ if (crop->crop_mode & CROP_WIDTH)
+ width = (uint32)crop->width;
+ else
+ width = image->width - lmargin - rmargin;
+
+ if (crop->crop_mode & CROP_LENGTH)
+ length = (uint32)crop->length;
+ else
+ length = image->length - tmargin - bmargin;
+ }
+ else
+ {
+ if (crop->crop_mode & CROP_WIDTH)
+ width = (uint32)(crop->width * scale * image->xres);
+ else
+ width = image->width - lmargin - rmargin;
+
+ if (crop->crop_mode & CROP_LENGTH)
+ length = (uint32)(crop->length * scale * image->yres);
+ else
+ length = image->length - tmargin - bmargin;
+ }
+
+ off->tmargin = tmargin;
+ off->bmargin = bmargin;
+ off->lmargin = lmargin;
+ off->rmargin = rmargin;
+
+ /* Calculate regions defined by margins, width, and length.
+ * Coordinates expressed as 0 to imagewidth - 1, imagelength - 1,
+ * since they are used to compute offsets into buffers */
+ switch (crop->edge_ref) {
+ case EDGE_BOTTOM:
+ startx = lmargin;
+ if ((startx + width) >= (image->width - rmargin))
+ endx = image->width - rmargin - 1;
+ else
+ endx = startx + width - 1;
+
+ endy = image->length - bmargin - 1;
+ if ((endy - length) <= tmargin)
+ starty = tmargin;
+ else
+ starty = endy - length + 1;
+ break;
+ case EDGE_RIGHT:
+ endx = image->width - rmargin - 1;
+ if ((endx - width) <= lmargin)
+ startx = lmargin;
+ else
+ startx = endx - width + 1;
+
+ starty = tmargin;
+ if ((starty + length) >= (image->length - bmargin))
+ endy = image->length - bmargin - 1;
+ else
+ endy = starty + length - 1;
+ break;
+ case EDGE_TOP: /* width from left, length from top */
+ case EDGE_LEFT:
+ default:
+ startx = lmargin;
+ if ((startx + width) >= (image->width - rmargin))
+ endx = image->width - rmargin - 1;
+ else
+ endx = startx + width - 1;
+
+ starty = tmargin;
+ if ((starty + length) >= (image->length - bmargin))
+ endy = image->length - bmargin - 1;
+ else
+ endy = starty + length - 1;
+ break;
+ }
+ off->startx = startx;
+ off->starty = starty;
+ off->endx = endx;
+ off->endy = endy;
+
+ crop_width = endx - startx + 1;
+ crop_length = endy - starty + 1;
+
+ if (crop_width <= 0)
+ {
+ TIFFError("computeInputPixelOffsets",
+ "Invalid left/right margins and /or image crop width requested");
+ return (-1);
+ }
+ if (crop_width > image->width)
+ crop_width = image->width;
+
+ if (crop_length <= 0)
+ {
+ TIFFError("computeInputPixelOffsets",
+ "Invalid top/bottom margins and /or image crop length requested");
+ return (-1);
+ }
+ if (crop_length > image->length)
+ crop_length = image->length;
+
+ off->crop_width = crop_width;
+ off->crop_length = crop_length;
+
+ return (0);
+ } /* end computeInputPixelOffsets */
+
+/*
+ * Translate crop options into pixel offsets for one or more regions of the image.
+ * Options are applied in this order: margins, specific width and length, zones,
+ * but all are optional. Margins are relative to each edge. Width, length and
+ * zones are relative to the specified reference edge. Zones are expressed as
+ * X:Y where X is the ordinal value in a set of Y equal sized portions. eg.
+ * 2:3 would indicate the middle third of the region qualified by margins and
+ * any explicit width and length specified. Regions are specified by coordinates
+ * of the top left and lower right corners with range 1 to width or height.
+ */
+
+static int
+getCropOffsets(struct image_data *image, struct crop_mask *crop, struct dump_opts *dump)
+ {
+ struct offset offsets;
+ int i;
+ int32 test2;
+ uint32 test, seg, total, need_buff = 0;
+ uint32 buffsize;
+ uint32 zwidth, zlength;
+
+ memset(&offsets, '\0', sizeof(struct offset));
+ crop->bufftotal = 0;
+ crop->combined_width = (uint32)0;
+ crop->combined_length = (uint32)0;
+ crop->selections = 0;
+
+ /* Compute pixel offsets if margins or fixed width or length specified */
+ if ((crop->crop_mode & CROP_MARGINS) ||
+ (crop->crop_mode & CROP_REGIONS) ||
+ (crop->crop_mode & CROP_LENGTH) ||
+ (crop->crop_mode & CROP_WIDTH))
+ {
+ if (computeInputPixelOffsets(crop, image, &offsets))
+ {
+ TIFFError ("getCropOffsets", "Unable to compute crop margins");
+ return (-1);
+ }
+ need_buff = TRUE;
+ crop->selections = crop->regions;
+ /* Regions are only calculated from top and left edges with no margins */
+ if (crop->crop_mode & CROP_REGIONS)
+ return (0);
+ }
+ else
+ { /* cropped area is the full image */
+ offsets.tmargin = 0;
+ offsets.lmargin = 0;
+ offsets.bmargin = 0;
+ offsets.rmargin = 0;
+ offsets.crop_width = image->width;
+ offsets.crop_length = image->length;
+ offsets.startx = 0;
+ offsets.endx = image->width - 1;
+ offsets.starty = 0;
+ offsets.endy = image->length - 1;
+ need_buff = FALSE;
+ }
+
+ if (dump->outfile != NULL)
+ {
+ dump_info (dump->outfile, dump->format, "", "Margins: Top: %d Left: %d Bottom: %d Right: %d",
+ offsets.tmargin, offsets.lmargin, offsets.bmargin, offsets.rmargin);
+ dump_info (dump->outfile, dump->format, "", "Crop region within margins: Adjusted Width: %6d Length: %6d",
+ offsets.crop_width, offsets.crop_length);
+ }
+
+ if (!(crop->crop_mode & CROP_ZONES)) /* no crop zones requested */
+ {
+ if (need_buff == FALSE) /* No margins or fixed width or length areas */
+ {
+ crop->selections = 0;
+ crop->combined_width = image->width;
+ crop->combined_length = image->length;
+ return (0);
+ }
+ else
+ {
+ /* Use one region for margins and fixed width or length areas
+ * even though it was not formally declared as a region.
+ */
+ crop->selections = 1;
+ crop->zones = 1;
+ crop->zonelist[0].total = 1;
+ crop->zonelist[0].position = 1;
+ }
+ }
+ else
+ crop->selections = crop->zones;
+
+ for (i = 0; i < crop->zones; i++)
+ {
+ seg = crop->zonelist[i].position;
+ total = crop->zonelist[i].total;
+
+ switch (crop->edge_ref)
+ {
+ case EDGE_LEFT: /* zones from left to right, length from top */
+ zlength = offsets.crop_length;
+ crop->regionlist[i].y1 = offsets.starty;
+ crop->regionlist[i].y2 = offsets.endy;
+
+ crop->regionlist[i].x1 = offsets.startx +
+ (uint32)(offsets.crop_width * 1.0 * (seg - 1) / total);
+ test = offsets.startx +
+ (uint32)(offsets.crop_width * 1.0 * seg / total);
+ if (test > image->width - 1)
+ crop->regionlist[i].x2 = image->width - 1;
+ else
+ crop->regionlist[i].x2 = test - 1;
+ zwidth = crop->regionlist[i].x2 - crop->regionlist[i].x1 + 1;
+
+ /* This is passed to extractCropZone or extractCompositeZones */
+ crop->combined_length = (uint32)zlength;
+ if (crop->exp_mode == COMPOSITE_IMAGES)
+ crop->combined_width += (uint32)zwidth;
+ else
+ crop->combined_width = (uint32)zwidth;
+ break;
+ case EDGE_BOTTOM: /* width from left, zones from bottom to top */
+ zwidth = offsets.crop_width;
+ crop->regionlist[i].x1 = offsets.startx;
+ crop->regionlist[i].x2 = offsets.endx;
+
+ test2 = offsets.endy - (uint32)(offsets.crop_length * 1.0 * seg / total);
+ if (test2 < 1 )
+ crop->regionlist[i].y1 = 0;
+ else
+ crop->regionlist[i].y1 = test2 + 1;
+
+ test = offsets.endy - (uint32)(offsets.crop_length * 1.0 * (seg - 1) / total);
+ if (test > (image->length - 1))
+ crop->regionlist[i].y2 = image->length - 1;
+ else
+ crop->regionlist[i].y2 = test;
+ zlength = crop->regionlist[i].y2 - crop->regionlist[i].y1 + 1;
+
+ /* This is passed to extractCropZone or extractCompositeZones */
+ if (crop->exp_mode == COMPOSITE_IMAGES)
+ crop->combined_length += (uint32)zlength;
+ else
+ crop->combined_length = (uint32)zlength;
+ crop->combined_width = (uint32)zwidth;
+ break;
+ case EDGE_RIGHT: /* zones from right to left, length from top */
+ zlength = offsets.crop_length;
+ crop->regionlist[i].y1 = offsets.starty;
+ crop->regionlist[i].y2 = offsets.endy;
+
+ crop->regionlist[i].x1 = offsets.startx +
+ (uint32)(offsets.crop_width * (total - seg) * 1.0 / total);
+ test = offsets.startx +
+ (uint32)(offsets.crop_width * (total - seg + 1) * 1.0 / total);
+
+ if (test > image->width - 1)
+ crop->regionlist[i].x2 = image->width - 1;
+ else
+ crop->regionlist[i].x2 = test - 1;
+ zwidth = crop->regionlist[i].x2 - crop->regionlist[i].x1 + 1;
+
+ /* This is passed to extractCropZone or extractCompositeZones */
+ crop->combined_length = (uint32)zlength;
+ if (crop->exp_mode == COMPOSITE_IMAGES)
+ crop->combined_width += (uint32)zwidth;
+ else
+ crop->combined_width = (uint32)zwidth;
+ break;
+ case EDGE_TOP: /* width from left, zones from top to bottom */
+ default:
+ zwidth = offsets.crop_width;
+ crop->regionlist[i].x1 = offsets.startx;
+ crop->regionlist[i].x2 = offsets.endx;
+
+ crop->regionlist[i].y1 = offsets.starty + (uint32)(offsets.crop_length * 1.0 * (seg - 1) / total);
+ test = offsets.starty + (uint32)(offsets.crop_length * 1.0 * seg / total);
+ if (test > image->length - 1)
+ crop->regionlist[i].y2 = image->length - 1;
+ else
+ crop->regionlist[i].y2 = test - 1;
+ zlength = crop->regionlist[i].y2 - crop->regionlist[i].y1 + 1;
+
+ /* This is passed to extractCropZone or extractCompositeZones */
+ if (crop->exp_mode == COMPOSITE_IMAGES)
+ crop->combined_length += (uint32)zlength;
+ else
+ crop->combined_length = (uint32)zlength;
+ crop->combined_width = (uint32)zwidth;
+ break;
+ } /* end switch statement */
+
+ buffsize = (uint32)
+ ((((zwidth * image->bps * image->spp) + 7 ) / 8) * (zlength + 1));
+ crop->regionlist[i].width = (uint32) zwidth;
+ crop->regionlist[i].length = (uint32) zlength;
+ crop->regionlist[i].buffsize = buffsize;
+ crop->bufftotal += buffsize;
+
+
+ if (dump->outfile != NULL)
+ dump_info (dump->outfile, dump->format, "", "Zone %d, width: %4d, length: %4d, x1: %4d x2: %4d y1: %4d y2: %4d",
+ i + 1, (uint32)zwidth, (uint32)zlength,
+ crop->regionlist[i].x1, crop->regionlist[i].x2,
+ crop->regionlist[i].y1, crop->regionlist[i].y2);
+ }
+
+ return (0);
+ } /* end getCropOffsets */
+
+
+static int
+computeOutputPixelOffsets (struct crop_mask *crop, struct image_data *image,
+ struct pagedef *page, struct pageseg *sections,
+ struct dump_opts* dump)
+ {
+ double scale;
+ double pwidth, plength; /* Output page width and length in user units*/
+ uint32 iwidth, ilength; /* Input image width and length in pixels*/
+ uint32 owidth, olength; /* Output image width and length in pixels*/
+ uint32 orows, ocols; /* rows and cols for output */
+ uint32 hmargin, vmargin; /* Horizontal and vertical margins */
+ uint32 x1, x2, y1, y2, line_bytes;
+ unsigned int orientation;
+ uint32 i, j, k;
+
+ scale = 1.0;
+ if (page->res_unit == RESUNIT_NONE)
+ page->res_unit = image->res_unit;
+
+ switch (image->res_unit) {
+ case RESUNIT_CENTIMETER:
+ if (page->res_unit == RESUNIT_INCH)
+ scale = 1.0/2.54;
+ break;
+ case RESUNIT_INCH:
+ if (page->res_unit == RESUNIT_CENTIMETER)
+ scale = 2.54;
+ break;
+ case RESUNIT_NONE: /* Dimensions in pixels */
+ default:
+ break;
+ }
+
+ /* get width, height, resolutions of input image selection */
+ if (crop->combined_width > 0)
+ iwidth = crop->combined_width;
+ else
+ iwidth = image->width;
+ if (crop->combined_length > 0)
+ ilength = crop->combined_length;
+ else
+ ilength = image->length;
+
+ if (page->hres <= 1.0)
+ page->hres = image->xres;
+ if (page->vres <= 1.0)
+ page->vres = image->yres;
+
+ if ((page->hres < 1.0) || (page->vres < 1.0))
+ {
+ TIFFError("computeOutputPixelOffsets",
+ "Invalid horizontal or vertical resolution specified or read from input image");
+ return (1);
+ }
+
+ /* If no page sizes are being specified, we just use the input image size to
+ * calculate maximum margins that can be taken from image.
+ */
+ if (page->width <= 0)
+ pwidth = iwidth;
+ else
+ pwidth = page->width;
+
+ if (page->length <= 0)
+ plength = ilength;
+ else
+ plength = page->length;
+
+ if (dump->debug)
+ {
+ TIFFError("", "Page size: %s, Vres: %3.2f, Hres: %3.2f, "
+ "Hmargin: %3.2f, Vmargin: %3.2f\n",
+ page->name, page->vres, page->hres,
+ page->hmargin, page->vmargin);
+ TIFFError("", "Res_unit: %d, Scale: %3.2f, Page width: %3.2f, length: %3.2f\n",
+ page->res_unit, scale, pwidth, plength);
+ }
+
+ /* compute margins at specified unit and resolution */
+ if (page->mode & PAGE_MODE_MARGINS)
+ {
+ if (page->res_unit == RESUNIT_INCH || page->res_unit == RESUNIT_CENTIMETER)
+ { /* inches or centimeters specified */
+ hmargin = (uint32)(page->hmargin * scale * page->hres * ((image->bps + 7)/ 8));
+ vmargin = (uint32)(page->vmargin * scale * page->vres * ((image->bps + 7)/ 8));
+ }
+ else
+ { /* Otherwise user has specified pixels as reference unit */
+ hmargin = (uint32)(page->hmargin * scale * ((image->bps + 7)/ 8));
+ vmargin = (uint32)(page->vmargin * scale * ((image->bps + 7)/ 8));
+ }
+
+ if ((hmargin * 2.0) > (pwidth * page->hres))
+ {
+ TIFFError("computeOutputPixelOffsets",
+ "Combined left and right margins exceed page width");
+ hmargin = (uint32) 0;
+ return (-1);
+ }
+ if ((vmargin * 2.0) > (plength * page->vres))
+ {
+ TIFFError("computeOutputPixelOffsets",
+ "Combined top and bottom margins exceed page length");
+ vmargin = (uint32) 0;
+ return (-1);
+ }
+ }
+ else
+ {
+ hmargin = 0;
+ vmargin = 0;
+ }
+
+ if (page->mode & PAGE_MODE_ROWSCOLS )
+ {
+ /* Maybe someday but not for now */
+ if (page->mode & PAGE_MODE_MARGINS)
+ TIFFError("computeOutputPixelOffsets",
+ "Output margins cannot be specified with rows and columns");
+
+ owidth = TIFFhowmany(iwidth, page->cols);
+ olength = TIFFhowmany(ilength, page->rows);
+ }
+ else
+ {
+ if (page->mode & PAGE_MODE_PAPERSIZE )
+ {
+ owidth = (uint32)((pwidth * page->hres) - (hmargin * 2));
+ olength = (uint32)((plength * page->vres) - (vmargin * 2));
+ }
+ else
+ {
+ owidth = (uint32)(iwidth - (hmargin * 2 * page->hres));
+ olength = (uint32)(ilength - (vmargin * 2 * page->vres));
+ }
+ }
+
+ if (owidth > iwidth)
+ owidth = iwidth;
+ if (olength > ilength)
+ olength = ilength;
+
+ /* Compute the number of pages required for Portrait or Landscape */
+ switch (page->orient)
+ {
+ case ORIENTATION_NONE:
+ case ORIENTATION_PORTRAIT:
+ ocols = TIFFhowmany(iwidth, owidth);
+ orows = TIFFhowmany(ilength, olength);
+ orientation = ORIENTATION_PORTRAIT;
+ break;
+
+ case ORIENTATION_LANDSCAPE:
+ ocols = TIFFhowmany(iwidth, olength);
+ orows = TIFFhowmany(ilength, owidth);
+ x1 = olength;
+ olength = owidth;
+ owidth = x1;
+ orientation = ORIENTATION_LANDSCAPE;
+ break;
+
+ case ORIENTATION_AUTO:
+ default:
+ x1 = TIFFhowmany(iwidth, owidth);
+ x2 = TIFFhowmany(ilength, olength);
+ y1 = TIFFhowmany(iwidth, olength);
+ y2 = TIFFhowmany(ilength, owidth);
+
+ if ( (x1 * x2) < (y1 * y2))
+ { /* Portrait */
+ ocols = x1;
+ orows = x2;
+ orientation = ORIENTATION_PORTRAIT;
+ }
+ else
+ { /* Landscape */
+ ocols = y1;
+ orows = y2;
+ x1 = olength;
+ olength = owidth;
+ owidth = x1;
+ orientation = ORIENTATION_LANDSCAPE;
+ }
+ }
+
+ if (ocols < 1)
+ ocols = 1;
+ if (orows < 1)
+ orows = 1;
+
+ /* If user did not specify rows and cols, set them from calcuation */
+ if (page->rows < 1)
+ page->rows = orows;
+ if (page->cols < 1)
+ page->cols = ocols;
+
+ line_bytes = TIFFhowmany8(owidth * image->bps) * image->spp;
+
+ if ((page->rows * page->cols) > MAX_SECTIONS)
+ {
+ TIFFError("computeOutputPixelOffsets",
+ "Rows and Columns exceed maximum sections\nIncrease resolution or reduce sections");
+ return (-1);
+ }
+
+ /* build the list of offsets for each output section */
+ for (k = 0, i = 0 && k <= MAX_SECTIONS; i < orows; i++)
+ {
+ y1 = (uint32)(olength * i);
+ y2 = (uint32)(olength * (i + 1) - 1);
+ if (y2 >= ilength)
+ y2 = ilength - 1;
+ for (j = 0; j < ocols; j++, k++)
+ {
+ x1 = (uint32)(owidth * j);
+ x2 = (uint32)(owidth * (j + 1) - 1);
+ if (x2 >= iwidth)
+ x2 = iwidth - 1;
+ sections[k].x1 = x1;
+ sections[k].x2 = x2;
+ sections[k].y1 = y1;
+ sections[k].y2 = y2;
+ sections[k].buffsize = line_bytes * olength;
+ sections[k].position = k + 1;
+ sections[k].total = orows * ocols;
+ }
+ }
+ return (0);
+ } /* end computeOutputPixelOffsets */
+
+static int
+loadImage(TIFF* in, struct image_data *image, struct dump_opts *dump, unsigned char **read_ptr)
+ {
+ uint32 i;
+ float xres = 0.0, yres = 0.0;
+ uint16 nstrips = 0, ntiles = 0, planar = 0;
+ uint16 bps = 0, spp = 0, res_unit = 0;
+ uint16 photometric = 0, orientation = 0, input_compression = 0;
+ uint32 width = 0, length = 0;
+ uint32 stsize = 0, tlsize = 0, buffsize = 0, scanlinesize = 0;
+ uint32 tw = 0, tl = 0; /* Tile width and length */
+ uint32 tile_rowsize = 0;
+ unsigned char *read_buff = NULL;
+ unsigned char *new_buff = NULL;
+ int readunit = 0;
+ static uint32 prev_readsize = 0;
+
+ TIFFGetFieldDefaulted(in, TIFFTAG_BITSPERSAMPLE, &bps);
+ TIFFGetFieldDefaulted(in, TIFFTAG_SAMPLESPERPIXEL, &spp);
+ TIFFGetFieldDefaulted(in, TIFFTAG_PLANARCONFIG, &planar);
+ TIFFGetFieldDefaulted(in, TIFFTAG_ORIENTATION, &orientation);
+ if (! TIFFGetFieldDefaulted(in, TIFFTAG_PHOTOMETRIC, &photometric))
+ TIFFError("loadImage","Image lacks Photometric interpreation tag");
+ if (! TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width))
+ TIFFError("loadimage","Image lacks image width tag");
+ if(! TIFFGetField(in, TIFFTAG_IMAGELENGTH, &length))
+ TIFFError("loadimage","Image lacks image length tag");
+ TIFFGetFieldDefaulted(in, TIFFTAG_XRESOLUTION, &xres);
+ TIFFGetFieldDefaulted(in, TIFFTAG_YRESOLUTION, &yres);
+ if (!TIFFGetFieldDefaulted(in, TIFFTAG_RESOLUTIONUNIT, &res_unit))
+ res_unit = RESUNIT_INCH;
+ if (!TIFFGetField(in, TIFFTAG_COMPRESSION, &input_compression))
+ input_compression = COMPRESSION_NONE;
+
+#ifdef DEBUG2
+ char compressionid[16];
+
+ switch (compression)
+ {
+ case COMPRESSION_NONE: /* 1 dump mode */
+ stcrcpy ("None/dump", compressionid);
+ break;
+ case COMPRESSION_CCITTRLE: /* 2 CCITT modified Huffman RLE */
+ stcrcpy ("Huffman RLE", compressionid);
+ break;
+ case COMPRESSION_CCITTFAX3: /* 3 CCITT Group 3 fax encoding */
+ case COMPRESSION_CCITT_T4: /* 3 CCITT T.4 (TIFF 6 name) */
+ stcrcpy ("Group3 Fax", compressionid);
+ break;
+ case COMPRESSION_CCITTFAX4: /* 4 CCITT Group 4 fax encoding */
+ case COMPRESSION_CCITT_T6: /* 4 CCITT T.6 (TIFF 6 name) */
+ stcrcpy ("Group4 Fax", compressionid);
+ break;
+ case COMPRESSION_LZW: /* 5 Lempel-Ziv & Welch */
+ stcrcpy ("LZW", compressionid);
+ break;
+ case COMPRESSION_OJPEG: /* 6 !6.0 JPEG */
+ stcrcpy ("Old Jpeg", compressionid);
+ break;
+ case COMPRESSION_JPEG: /* 7 %JPEG DCT compression */
+ stcrcpy ("New Jpeg", compressionid);
+ break;
+ case COMPRESSION_NEXT: /* 32766 NeXT 2-bit RLE */
+ stcrcpy ("Next RLE", compressionid);
+ break;
+ case COMPRESSION_CCITTRLEW: /* 32771 #1 w/ word alignment */
+ stcrcpy ("CITTRLEW", compressionid);
+ break;
+ case COMPRESSION_PACKBITS: /* 32773 Macintosh RLE */
+ stcrcpy ("Mac Packbits", compressionid);
+ break;
+ case COMPRESSION_THUNDERSCAN: /* 32809 ThunderScan RLE */
+ stcrcpy ("Thunderscan", compressionid);
+ break;
+ case COMPRESSION_IT8CTPAD: /* 32895 IT8 CT w/padding */
+ stcrcpy ("IT8 padded", compressionid);
+ break;
+ case COMPRESSION_IT8LW: /* 32896 IT8 Linework RLE */
+ stcrcpy ("IT8 RLE", compressionid);
+ break;
+ case COMPRESSION_IT8MP: /* 32897 IT8 Monochrome picture */
+ stcrcpy ("IT8 mono", compressionid);
+ break;
+ case COMPRESSION_IT8BL: /* 32898 IT8 Binary line art */
+ stcrcpy ("IT8 lineart", compressionid);
+ break;
+ case COMPRESSION_PIXARFILM: /* 32908 Pixar companded 10bit LZW */
+ stcrcpy ("Pixar 10 bit", compressionid);
+ break;
+ case COMPRESSION_PIXARLOG: /* 32909 Pixar companded 11bit ZIP */
+ stcrcpy ("Pixar 11bit", compressionid);
+ break;
+ case COMPRESSION_DEFLATE: /* 32946 Deflate compression */
+ stcrcpy ("Deflate", compressionid);
+ break;
+ case COMPRESSION_ADOBE_DEFLATE: /* 8 Deflate compression */
+ stcrcpy ("Adobe deflate", compressionid);
+ break;
+ default:
+ stcrcpy ("None/unknown", compressionid);
+ break;
+ }
+#endif
+ scanlinesize = TIFFScanlineSize(in);
+ image->bps = bps;
+ image->spp = spp;
+ image->planar = planar;
+ image->width = width;
+ image->length = length;
+ image->xres = xres;
+ image->yres = yres;
+ image->res_unit = res_unit;
+ image->photometric = photometric;
+
+#ifdef DEBUG2
+ char photmetricid[12];
+
+ switch (photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ strcpy (photometricid, "MinIsWhite");
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ strcpy (photometricid, "MinIsBlack");
+ break;
+ case PHOTOMETRIC_RGB:
+ strcpy (photometricid, "RGB");
+ break;
+ case PHOTOMETRIC_PALETTE:
+ strcpy (photometricid, "Palette");
+ break;
+ case PHOTOMETRIC_MASK:
+ strcpy (photometricid, "Mask");
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ strcpy (photometricid, "Separated");
+ break;
+ case PHOTOMETRIC_YCBCR:
+ strcpy (photometricid, "YCBCR");
+ break;
+ case PHOTOMETRIC_CIELAB:
+ strcpy (photometricid, "CIELab");
+ break;
+ case PHOTOMETRIC_ICCLAB:
+ strcpy (photometricid, "ICCLab");
+ break;
+ case PHOTOMETRIC_ITULAB:
+ strcpy (photometricid, "ITULab");
+ break;
+ case PHOTOMETRIC_LOGL:
+ strcpy (photometricid, "LogL");
+ break;
+ case PHOTOMETRIC_LOGLUV:
+ strcpy (photometricid, "LOGLuv");
+ break;
+ default:
+ strcpy (photometricid, "Unknown");
+ break;
+ }
+ TIFFError("loadImage", "Input photometric interpretation %s", photometricid);
+#endif
+
+ image->orientation = orientation;
+ switch (orientation)
+ {
+ case 0:
+ case ORIENTATION_TOPLEFT:
+ image->adjustments = 0;
+ break;
+ case ORIENTATION_TOPRIGHT:
+ image->adjustments = MIRROR_HORIZ;
+ break;
+ case ORIENTATION_BOTRIGHT:
+ image->adjustments = ROTATECW_180;
+ break;
+ case ORIENTATION_BOTLEFT:
+ image->adjustments = MIRROR_VERT;
+ break;
+ case ORIENTATION_LEFTTOP:
+ image->adjustments = MIRROR_VERT | ROTATECW_90;
+ break;
+ case ORIENTATION_RIGHTTOP:
+ image->adjustments = ROTATECW_90;
+ break;
+ case ORIENTATION_RIGHTBOT:
+ image->adjustments = MIRROR_VERT | ROTATECW_270;
+ break;
+ case ORIENTATION_LEFTBOT:
+ image->adjustments = ROTATECW_270;
+ break;
+ default:
+ image->adjustments = 0;
+ image->orientation = ORIENTATION_TOPLEFT;
+ }
+
+ if ((bps == 0) || (spp == 0))
+ {
+ TIFFError("loadImage", "Invalid samples per pixel (%d) or bits per sample (%d)",
+ spp, bps);
+ return (-1);
+ }
+
+ if (TIFFIsTiled(in))
+ {
+ readunit = TILE;
+ tlsize = TIFFTileSize(in);
+ ntiles = TIFFNumberOfTiles(in);
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
+
+ tile_rowsize = TIFFTileRowSize(in);
+ buffsize = tlsize * ntiles;
+
+ if (buffsize < (uint32)(ntiles * tl * tile_rowsize))
+ {
+ buffsize = ntiles * tl * tile_rowsize;
+#ifdef DEBUG2
+ TIFFError("loadImage",
+ "Tilesize %u is too small, using ntiles * tilelength * tilerowsize %lu",
+ tlsize, (unsigned long)buffsize);
+#endif
+ }
+
+ if (dump->infile != NULL)
+ dump_info (dump->infile, dump->format, "",
+ "Tilesize: %u, Number of Tiles: %u, Tile row size: %u",
+ tlsize, ntiles, tile_rowsize);
+ }
+ else
+ {
+ readunit = STRIP;
+ TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ stsize = TIFFStripSize(in);
+ nstrips = TIFFNumberOfStrips(in);
+ buffsize = stsize * nstrips;
+ if (buffsize < (uint32) (((length * width * spp * bps) + 7) / 8))
+ {
+ buffsize = ((length * width * spp * bps) + 7) / 8;
+#ifdef DEBUG2
+ TIFFError("loadImage",
+ "Stripsize %u is too small, using imagelength * width * spp * bps / 8 = %lu",
+ stsize, (unsigned long)buffsize);
+#endif
+ }
+
+ if (dump->infile != NULL)
+ dump_info (dump->infile, dump->format, "",
+ "Stripsize: %u, Number of Strips: %u, Rows per Strip: %u, Scanline size: %u",
+ stsize, nstrips, rowsperstrip, scanlinesize);
+ }
+
+ if (input_compression == COMPRESSION_JPEG)
+ {
+ jpegcolormode = JPEGCOLORMODE_RGB;
+ TIFFSetField(in, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ }
+
+ read_buff = *read_ptr;
+ if (!read_buff)
+ read_buff = (unsigned char *)_TIFFmalloc(buffsize);
+ else
+ {
+ if (prev_readsize < buffsize)
+ {
+ new_buff = _TIFFrealloc(read_buff, buffsize);
+ if (!new_buff)
+ {
+ free (read_buff);
+ read_buff = (unsigned char *)_TIFFmalloc(buffsize);
+ }
+ else
+ read_buff = new_buff;
+ }
+ }
+
+ if (!read_buff)
+ {
+ TIFFError("loadImage", "Unable to allocate/reallocate read buffer");
+ return (-1);
+ }
+
+ prev_readsize = buffsize;
+ *read_ptr = read_buff;
+
+ /* N.B. The read functions used copy separate plane data into a buffer as interleaved
+ * samples rather than separate planes so the same logic works to extract regions
+ * regardless of the way the data are organized in the input file.
+ */
+ switch (readunit) {
+ case STRIP:
+ if (planar == PLANARCONFIG_CONTIG)
+ {
+ if (!(readContigStripsIntoBuffer(in, read_buff)))
+ {
+ TIFFError("loadImage", "Unable to read contiguous strips into buffer");
+ return (-1);
+ }
+ }
+ else
+ {
+ if (!(readSeparateStripsIntoBuffer(in, read_buff, length, width, spp, dump)))
+ {
+ TIFFError("loadImage", "Unable to read separate strips into buffer");
+ return (-1);
+ }
+ }
+ break;
+
+ case TILE:
+ if (planar == PLANARCONFIG_CONTIG)
+ {
+ if (!(readContigTilesIntoBuffer(in, read_buff, length, width, tw, tl, spp, bps)))
+ {
+ TIFFError("loadImage", "Unable to read contiguous tiles into buffer");
+ return (-1);
+ }
+ }
+ else
+ {
+ if (!(readSeparateTilesIntoBuffer(in, read_buff, length, width, tw, tl, spp, bps)))
+ {
+ TIFFError("loadImage", "Unable to read separate tiles into buffer");
+ return (-1);
+ }
+ }
+ break;
+ default: TIFFError("loadImage", "Unsupported image file format");
+ return (-1);
+ break;
+ }
+ if ((dump->infile != NULL) && (dump->level == 2))
+ {
+ dump_info (dump->infile, dump->format, "loadImage",
+ "Image width %d, length %d, Raw image data, %4d bytes",
+ width, length, buffsize);
+ dump_info (dump->infile, dump->format, "",
+ "Bits per sample %d, Samples per pixel %d", bps, spp);
+
+ for (i = 0; i < length; i++)
+ dump_buffer(dump->infile, dump->format, 1, scanlinesize,
+ i, read_buff + (i * scanlinesize));
+ }
+ return (0);
+ } /* end loadImage */
+
+static int correct_orientation(struct image_data *image, unsigned char **work_buff_ptr)
+ {
+ uint16 mirror, rotation;
+ unsigned char *work_buff;
+
+ work_buff = *work_buff_ptr;
+ if ((image == NULL) || (work_buff == NULL))
+ {
+ TIFFError ("correct_orientatin", "Invalid image or buffer pointer");
+ return (-1);
+ }
+
+ if ((image->adjustments & MIRROR_HORIZ) || (image->adjustments & MIRROR_VERT))
+ {
+ mirror = (uint16)(image->adjustments & MIRROR_BOTH);
+ if (mirrorImage(image->spp, image->bps, mirror,
+ image->width, image->length, work_buff))
+ {
+ TIFFError ("correct_orientation", "Unable to mirror image");
+ return (-1);
+ }
+ }
+
+ if (image->adjustments & ROTATE_ANY)
+ {
+ if (image->adjustments & ROTATECW_90)
+ rotation = (uint16) 90;
+ else
+ if (image->adjustments & ROTATECW_180)
+ rotation = (uint16) 180;
+ else
+ if (image->adjustments & ROTATECW_270)
+ rotation = (uint16) 270;
+ else
+ {
+ TIFFError ("correct_orientation", "Invalid rotation value: %d",
+ image->adjustments & ROTATE_ANY);
+ return (-1);
+ }
+
+ if (rotateImage(rotation, image, &image->width, &image->length, work_buff_ptr))
+ {
+ TIFFError ("correct_orientation", "Unable to rotate image");
+ return (-1);
+ }
+ image->orientation = ORIENTATION_TOPLEFT;
+ }
+
+ return (0);
+ } /* end correct_orientation */
+
+
+/* Extract multiple zones from an image and combine into a single composite image */
+static int
+extractCompositeRegions(struct image_data *image, struct crop_mask *crop,
+ unsigned char *read_buff, unsigned char *crop_buff)
+ {
+ int shift_width, bytes_per_sample, bytes_per_pixel;
+ uint32 i, trailing_bits, prev_trailing_bits;
+ uint32 row, first_row, last_row, first_col, last_col;
+ uint32 src_rowsize, dst_rowsize, src_offset, dst_offset;
+ uint32 crop_width, crop_length, img_width, img_length;
+ uint32 prev_length, prev_width, composite_width;
+ uint16 bps, spp;
+ uint8 *src, *dst;
+ tsample_t count, sample = 0; /* Update to extract one or more samples */
+
+ img_width = image->width;
+ img_length = image->length;
+ bps = image->bps;
+ spp = image->spp;
+ count = spp;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if ((bps % 8) == 0)
+ shift_width = 0;
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+ src = read_buff;
+ dst = crop_buff;
+
+ /* These are setup for adding additional sections */
+ prev_width = prev_length = 0;
+ prev_trailing_bits = trailing_bits = 0;
+ composite_width = crop->combined_width;
+ crop->combined_width = 0;
+ crop->combined_length = 0;
+
+ for (i = 0; i < crop->selections; i++)
+ {
+ /* rows, columns, width, length are expressed in pixels */
+ first_row = crop->regionlist[i].y1;
+ last_row = crop->regionlist[i].y2;
+ first_col = crop->regionlist[i].x1;
+ last_col = crop->regionlist[i].x2;
+
+ crop_width = last_col - first_col + 1;
+ crop_length = last_row - first_row + 1;
+
+ /* These should not be needed for composite images */
+ crop->regionlist[i].width = crop_width;
+ crop->regionlist[i].length = crop_length;
+ crop->regionlist[i].buffptr = crop_buff;
+
+ src_rowsize = ((img_width * bps * spp) + 7) / 8;
+ dst_rowsize = (((crop_width * bps * count) + 7) / 8);
+
+ switch (crop->edge_ref)
+ {
+ default:
+ case EDGE_TOP:
+ case EDGE_BOTTOM:
+ if ((i > 0) && (crop_width != crop->regionlist[i - 1].width))
+ {
+ TIFFError ("extractCompositeRegions",
+ "Only equal width regions can be combined for -E top or bottom");
+ return (1);
+ }
+
+ crop->combined_width = crop_width;
+ crop->combined_length += crop_length;
+
+ for (row = first_row; row <= last_row; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = (row - first_row) * dst_rowsize;
+ src = read_buff + src_offset;
+ dst = crop_buff + dst_offset + (prev_length * dst_rowsize);
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, img_width, sample,
+ spp, bps, count, first_col,
+ last_col + 1))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamplesShifted8bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ }
+ else
+ if (extractContigSamplesShifted16bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 2: if (extractContigSamplesShifted24bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamplesShifted32bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ default: TIFFError("extractCompositeRegions", "Unsupported bit depth %d", bps);
+ return (1);
+ }
+ }
+ prev_length += crop_length;
+ break;
+ case EDGE_LEFT: /* splice the pieces of each row together, side by side */
+ case EDGE_RIGHT:
+ if ((i > 0) && (crop_length != crop->regionlist[i - 1].length))
+ {
+ TIFFError ("extractCompositeRegions",
+ "Only equal length regions can be combined for -E left or right");
+ return (1);
+ }
+ crop->combined_width += crop_width;
+ crop->combined_length = crop_length;
+ dst_rowsize = (((composite_width * bps * count) + 7) / 8);
+ trailing_bits = (crop_width * bps * count) % 8;
+ for (row = first_row; row <= last_row; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = (row - first_row) * dst_rowsize;
+ src = read_buff + src_offset;
+ dst = crop_buff + dst_offset + prev_width;
+
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamplesShifted8bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ }
+ else
+ if (extractContigSamplesShifted16bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 2: if (extractContigSamplesShifted24bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamplesShifted32bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ default: TIFFError("extractCompositeRegions", "Unsupported bit depth %d", bps);
+ return (1);
+ }
+ }
+ prev_width += (crop_width * bps * count) / 8;
+ prev_trailing_bits += trailing_bits;
+ if (prev_trailing_bits > 7)
+ prev_trailing_bits-= 8;
+ break;
+ }
+ }
+ if (crop->combined_width != composite_width)
+ TIFFError("combineSeparateRegions","Combined width does not match composite width");
+
+ return (0);
+ } /* end extractCompositeRegions */
+
+/* Copy a single region of input buffer to an output buffer.
+ * The read functions used copy separate plane data into a buffer
+ * as interleaved samples rather than separate planes so the same
+ * logic works to extract regions regardless of the way the data
+ * are organized in the input file. This function can be used to
+ * extract one or more samples from the input image by updating the
+ * parameters for starting sample and number of samples to copy in the
+ * fifth and eighth arguments of the call to extractContigSamples.
+ * They would be passed as new elements of the crop_mask struct.
+ */
+
+static int
+extractSeparateRegion(struct image_data *image, struct crop_mask *crop,
+ unsigned char *read_buff, unsigned char *crop_buff,
+ int region)
+ {
+ int shift_width, prev_trailing_bits = 0;
+ uint32 bytes_per_sample, bytes_per_pixel;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 row, first_row, last_row, first_col, last_col;
+ uint32 src_offset, dst_offset;
+ uint32 crop_width, crop_length, img_width, img_length;
+ uint16 bps, spp;
+ uint8 *src, *dst;
+ tsample_t count, sample = 0; /* Update to extract more or more samples */
+
+ img_width = image->width;
+ img_length = image->length;
+ bps = image->bps;
+ spp = image->spp;
+ count = spp;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if ((bps % 8) == 0)
+ shift_width = 0; /* Byte aligned data only */
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+
+ /* rows, columns, width, length are expressed in pixels */
+ first_row = crop->regionlist[region].y1;
+ last_row = crop->regionlist[region].y2;
+ first_col = crop->regionlist[region].x1;
+ last_col = crop->regionlist[region].x2;
+
+ crop_width = last_col - first_col + 1;
+ crop_length = last_row - first_row + 1;
+
+ crop->regionlist[region].width = crop_width;
+ crop->regionlist[region].length = crop_length;
+ crop->regionlist[region].buffptr = crop_buff;
+
+ src = read_buff;
+ dst = crop_buff;
+ src_rowsize = ((img_width * bps * spp) + 7) / 8;
+ dst_rowsize = (((crop_width * bps * spp) + 7) / 8);
+
+ for (row = first_row; row <= last_row; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = (row - first_row) * dst_rowsize;
+ src = read_buff + src_offset;
+ dst = crop_buff + dst_offset;
+
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, img_width, sample,
+ spp, bps, count, first_col,
+ last_col + 1))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamplesShifted8bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ }
+ else
+ if (extractContigSamplesShifted16bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 2: if (extractContigSamplesShifted24bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamplesShifted32bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ default: TIFFError("extractSeparateRegion", "Unsupported bit depth %d", bps);
+ return (1);
+ }
+ }
+
+ return (0);
+ } /* end extractSeparateRegion */
+
+static int
+extractImageSection(struct image_data *image, struct pageseg *section,
+ unsigned char *src_buff, unsigned char *sect_buff)
+ {
+ unsigned char bytebuff1, bytebuff2;
+ unsigned char *src, *dst;
+
+ uint32 img_width, img_length, img_rowsize;
+ uint32 j, shift1, shift2, trailing_bits;
+ uint32 row, first_row, last_row, first_col, last_col;
+ uint32 src_offset, dst_offset, row_offset, col_offset;
+ uint32 offset1, offset2, full_bytes;
+ uint32 sect_width, sect_length;
+ uint16 bps, spp;
+
+#ifdef DEVELMODE
+ int k;
+ unsigned char bitset;
+ static char *bitarray = NULL;
+#endif
+
+ img_width = image->width;
+ img_length = image->length;
+ bps = image->bps;
+ spp = image->spp;
+
+ src = src_buff;
+ dst = sect_buff;
+ src_offset = 0;
+ dst_offset = 0;
+
+#ifdef DEVELMODE
+ if (bitarray == NULL)
+ {
+ if ((bitarray = (char *)malloc(img_width)) == NULL)
+ {
+ TIFFError ("", "DEBUG: Unable to allocate debugging bitarray\n");
+ return (-1);
+ }
+ }
+#endif
+
+ /* rows, columns, width, length are expressed in pixels */
+ first_row = section->y1;
+ last_row = section->y2;
+ first_col = section->x1;
+ last_col = section->x2;
+
+ sect_width = last_col - first_col + 1;
+ sect_length = last_row - first_row + 1;
+ img_rowsize = ((img_width * bps + 7) / 8) * spp;
+ full_bytes = (sect_width * spp * bps) / 8; /* number of COMPLETE bytes per row in section */
+ trailing_bits = (sect_width * bps) % 8;
+
+#ifdef DEVELMODE
+ TIFFError ("", "First row: %d, last row: %d, First col: %d, last col: %d\n",
+ first_row, last_row, first_col, last_col);
+ TIFFError ("", "Image width: %d, Image length: %d, bps: %d, spp: %d\n",
+ img_width, img_length, bps, spp);
+ TIFFError ("", "Sect width: %d, Sect length: %d, full bytes: %d trailing bits %d\n",
+ sect_width, sect_length, full_bytes, trailing_bits);
+#endif
+
+ if ((bps % 8) == 0)
+ {
+ col_offset = first_col * spp * bps / 8;
+ for (row = first_row; row <= last_row; row++)
+ {
+ /* row_offset = row * img_width * spp * bps / 8; */
+ row_offset = row * img_rowsize;
+ src_offset = row_offset + col_offset;
+
+#ifdef DEVELMODE
+ TIFFError ("", "Src offset: %8d, Dst offset: %8d\n", src_offset, dst_offset);
+#endif
+ _TIFFmemcpy (sect_buff + dst_offset, src_buff + src_offset, full_bytes);
+ dst_offset += full_bytes;
+ }
+ }
+ else
+ { /* bps != 8 */
+ shift1 = spp * ((first_col * bps) % 8);
+ shift2 = spp * ((last_col * bps) % 8);
+ for (row = first_row; row <= last_row; row++)
+ {
+ /* pull out the first byte */
+ row_offset = row * img_rowsize;
+ offset1 = row_offset + (first_col * bps / 8);
+ offset2 = row_offset + (last_col * bps / 8);
+
+#ifdef DEVELMODE
+ for (j = 0, k = 7; j < 8; j++, k--)
+ {
+ bitset = *(src_buff + offset1) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ sprintf(&bitarray[8], " ");
+ sprintf(&bitarray[9], " ");
+ for (j = 10, k = 7; j < 18; j++, k--)
+ {
+ bitset = *(src_buff + offset2) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[18] = '\0';
+ TIFFError ("", "Row: %3d Offset1: %d, Shift1: %d, Offset2: %d, Shift2: %d\n",
+ row, offset1, shift1, offset2, shift2);
+#endif
+
+ bytebuff1 = bytebuff2 = 0;
+ if (shift1 == 0) /* the region is byte and sample alligned */
+ {
+ _TIFFmemcpy (sect_buff + dst_offset, src_buff + offset1, full_bytes);
+
+#ifdef DEVELMODE
+ TIFFError ("", " Alligned data src offset1: %8d, Dst offset: %8d\n", offset1, dst_offset);
+ sprintf(&bitarray[18], "\n");
+ sprintf(&bitarray[19], "\t");
+ for (j = 20, k = 7; j < 28; j++, k--)
+ {
+ bitset = *(sect_buff + dst_offset) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[28] = ' ';
+ bitarray[29] = ' ';
+#endif
+ dst_offset += full_bytes;
+
+ if (trailing_bits != 0)
+ {
+ bytebuff2 = src_buff[offset2] & ((unsigned char)255 << (7 - shift2));
+ sect_buff[dst_offset] = bytebuff2;
+#ifdef DEVELMODE
+ TIFFError ("", " Trailing bits src offset: %8d, Dst offset: %8d\n",
+ offset2, dst_offset);
+ for (j = 30, k = 7; j < 38; j++, k--)
+ {
+ bitset = *(sect_buff + dst_offset) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[38] = '\0';
+ TIFFError ("", "\tFirst and last bytes before and after masking:\n\t%s\n\n", bitarray);
+#endif
+ dst_offset++;
+ }
+ }
+ else /* each destination byte will have to be built from two source bytes*/
+ {
+#ifdef DEVELMODE
+ TIFFError ("", " Unalligned data src offset: %8d, Dst offset: %8d\n", offset1 , dst_offset);
+#endif
+ for (j = 0; j <= full_bytes; j++)
+ {
+ bytebuff1 = src_buff[offset1 + j] & ((unsigned char)255 >> shift1);
+ bytebuff2 = src_buff[offset1 + j + 1] & ((unsigned char)255 << (7 - shift1));
+ sect_buff[dst_offset + j] = (bytebuff1 << shift1) | (bytebuff2 >> (8 - shift1));
+ }
+#ifdef DEVELMODE
+ sprintf(&bitarray[18], "\n");
+ sprintf(&bitarray[19], "\t");
+ for (j = 20, k = 7; j < 28; j++, k--)
+ {
+ bitset = *(sect_buff + dst_offset) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[28] = ' ';
+ bitarray[29] = ' ';
+#endif
+ dst_offset += full_bytes;
+
+ if (trailing_bits != 0)
+ {
+#ifdef DEVELMODE
+ TIFFError ("", " Trailing bits src offset: %8d, Dst offset: %8d\n", offset1 + full_bytes, dst_offset);
+#endif
+ if (shift2 > shift1)
+ {
+ bytebuff1 = src_buff[offset1 + full_bytes] & ((unsigned char)255 << (7 - shift2));
+ bytebuff2 = bytebuff1 & ((unsigned char)255 << shift1);
+ sect_buff[dst_offset] = bytebuff2;
+#ifdef DEVELMODE
+ TIFFError ("", " Shift2 > Shift1\n");
+#endif
+ }
+ else
+ {
+ if (shift2 < shift1)
+ {
+ bytebuff2 = ((unsigned char)255 << (shift1 - shift2 - 1));
+ sect_buff[dst_offset] &= bytebuff2;
+#ifdef DEVELMODE
+ TIFFError ("", " Shift2 < Shift1\n");
+#endif
+ }
+#ifdef DEVELMODE
+ else
+ TIFFError ("", " Shift2 == Shift1\n");
+#endif
+ }
+ }
+#ifdef DEVELMODE
+ sprintf(&bitarray[28], " ");
+ sprintf(&bitarray[29], " ");
+ for (j = 30, k = 7; j < 38; j++, k--)
+ {
+ bitset = *(sect_buff + dst_offset) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[38] = '\0';
+ TIFFError ("", "\tFirst and last bytes before and after masking:\n\t%s\n\n", bitarray);
+#endif
+ dst_offset++;
+ }
+ }
+ }
+
+ return (0);
+ } /* end extractImageSection */
+
+static int
+writeSelections(TIFF *in, TIFF **out, struct crop_mask *crop,
+ struct image_data *image, struct dump_opts *dump,
+ struct buffinfo seg_buffs[], char *mp, char *filename,
+ unsigned int *page, unsigned int total_pages)
+ {
+ int i, page_count;
+ int autoindex = 0;
+ unsigned char *crop_buff = NULL;
+
+ /* Where we open a new file depends on the export mode */
+ switch (crop->exp_mode)
+ {
+ case ONE_FILE_COMPOSITE: /* Regions combined into single image */
+ autoindex = 0;
+ crop_buff = seg_buffs[0].buffer;
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+ page_count = total_pages;
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->combined_width,
+ crop->combined_length,
+ crop_buff, *page, total_pages))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ break;
+ case ONE_FILE_SEPARATED: /* Regions as separated images */
+ autoindex = 0;
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+ page_count = crop->selections * total_pages;
+ for (i = 0; i < crop->selections; i++)
+ {
+ crop_buff = seg_buffs[i].buffer;
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->regionlist[i].width,
+ crop->regionlist[i].length,
+ crop_buff, *page, page_count))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ }
+ break;
+ case FILE_PER_IMAGE_COMPOSITE: /* Regions as composite image */
+ autoindex = 1;
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+
+ crop_buff = seg_buffs[0].buffer;
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->combined_width,
+ crop->combined_length,
+ crop_buff, *page, total_pages))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ break;
+ case FILE_PER_IMAGE_SEPARATED: /* Regions as separated images */
+ autoindex = 1;
+ page_count = crop->selections;
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+
+ for (i = 0; i < crop->selections; i++)
+ {
+ crop_buff = seg_buffs[i].buffer;
+ /* Write the current region to the current file */
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->regionlist[i].width,
+ crop->regionlist[i].length,
+ crop_buff, *page, page_count))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ }
+ break;
+ case FILE_PER_SELECTION:
+ autoindex = 1;
+ page_count = 1;
+ for (i = 0; i < crop->selections; i++)
+ {
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+
+ crop_buff = seg_buffs[i].buffer;
+ /* Write the current region to the current file */
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->regionlist[i].width,
+ crop->regionlist[i].length,
+ crop_buff, *page, page_count))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ }
+ break;
+ default: return (1);
+ }
+
+ return (0);
+ } /* end writeRegions */
+
+static int
+writeImageSections(TIFF *in, TIFF *out, struct image_data *image,
+ struct pagedef *page, struct pageseg *sections,
+ struct dump_opts * dump, unsigned char *src_buff,
+ unsigned char **sect_buff_ptr)
+ {
+ double hres, vres;
+ uint32 i, k, width, length, sectsize;
+ unsigned char *sect_buff = *sect_buff_ptr;
+
+ hres = page->hres;
+ vres = page->vres;
+
+ k = page->cols * page->rows;
+ if ((k < 1) || (k > MAX_SECTIONS))
+ {
+ TIFFError("writeImageSections",
+ "%d Rows and Columns exceed maximum sections\nIncrease resolution or reduce sections", k);
+ return (-1);
+ }
+
+ for (i = 0; i < k; i++)
+ {
+ width = sections[i].x2 - sections[i].x1 + 1;
+ length = sections[i].y2 - sections[i].y1 + 1;
+ sectsize = (uint32)
+ ceil((width * image->bps + 7) / (double)8) * image->spp * length;
+ /* allocate a buffer if we don't have one already */
+ if (createImageSection(sectsize, sect_buff_ptr))
+ {
+ TIFFError("writeImageSections", "Unable to allocate section buffer");
+ exit (-1);
+ }
+ sect_buff = *sect_buff_ptr;
+
+ if (extractImageSection (image, &sections[i], src_buff, sect_buff))
+ {
+ TIFFError("writeImageSections", "Unable to extract image sections");
+ exit (-1);
+ }
+
+ /* call the write routine here instead of outside the loop */
+ if (writeSingleSection(in, out, image, dump, width, length, hres, vres, sect_buff))
+ {
+ TIFFError("writeImageSections", "Unable to write image section");
+ exit (-1);
+ }
+ }
+
+ return (0);
+ } /* end writeImageSections */
+
+/* Code in this function is heavily indebted to code in tiffcp
+ * with modifications by Richard Nolde to handle orientation correctly.
+ * It will have to be updated significantly if support is added to
+ * extract one or more samples from original image since the
+ * original code assumes we are always copying all samples.
+ */
+static int
+writeSingleSection(TIFF *in, TIFF *out, struct image_data *image,
+ struct dump_opts *dump, uint32 width, uint32 length,
+ double hres, double vres,
+ unsigned char *sect_buff)
+ {
+ uint16 bps, spp;
+ uint16 input_compression, input_photometric;
+ uint16 input_jpeg_colormode, input_planar;
+ struct cpTag* p;
+
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &spp);
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &bps);
+
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
+
+ CopyField(TIFFTAG_BITSPERSAMPLE, bps);
+ CopyField(TIFFTAG_SAMPLESPERPIXEL, spp);
+
+
+ TIFFGetField(in, TIFFTAG_COMPRESSION, &input_compression);
+ /* This is the global variable compression which is set
+ * if the user has specified a command line option for
+ * a compression option. Should be passed around in one
+ * of the parameters instead of as a global. If no user
+ * option specified it will still be (uint16) -1. */
+ if (compression != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ else
+ { /* OJPEG is no longer supported for writing so upgrade to JPEG */
+ if (input_compression == COMPRESSION_OJPEG)
+ {
+ TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
+ compression = COMPRESSION_JPEG;
+ }
+ else /* Use the compression from the input file */
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ }
+
+ TIFFGetField(in, TIFFTAG_JPEGCOLORMODE, &input_jpeg_colormode);
+#ifdef DEBUG2
+ TIFFError("writeSingleSection", "Input compression: %s",
+ (input_compression == COMPRESSION_OJPEG) ? "Old Jpeg" :
+ ((input_compression == COMPRESSION_JPEG) ? "New Jpeg" : "Non Jpeg"));
+#endif
+ if (compression == COMPRESSION_JPEG)
+ {
+ if ((input_photometric == PHOTOMETRIC_PALETTE) || /* color map indexed */
+ (input_photometric == PHOTOMETRIC_MASK)) /* $holdout mask */
+ {
+ TIFFError ("writeSingleSection",
+ "JPEG compression cannot be used with %s image data",
+ (input_photometric == PHOTOMETRIC_PALETTE) ?
+ "palette" : "mask");
+ return (-1);
+ }
+ if (input_photometric == PHOTOMETRIC_RGB)
+ {
+ if (jpegcolormode == JPEGCOLORMODE_RGB)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ }
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
+ }
+ else
+ {
+ if (compression == COMPRESSION_SGILOG || compression == COMPRESSION_SGILOG24)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, spp == 1 ?
+ PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, image->photometric);
+ }
+
+#ifdef DEBUG2
+ TIFFError("writeSingleSection", "Input photometric: %s",
+ (input_photmetric == PHOTMETRIC_RGB) ? "RGB" :
+ ((input_photometric == PHOTOMETRIC_YCBCR) ? "YCbCr" : "Not RGB or YCrCr"));
+#endif
+
+ if (((input_photometric == PHOTOMETRIC_LOGL) ||
+ (input_photometric == PHOTOMETRIC_LOGLUV)) &&
+ ((compression != COMPRESSION_SGILOG) &&
+ (compression != COMPRESSION_SGILOG24)))
+ {
+ TIFFError("writeCroppedImage",
+ "LogL and LogLuv source data require SGI_LOG or SGI_LOG24 compression");
+ return (-1);
+ }
+
+ if (fillorder != 0)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ else
+ CopyTag(TIFFTAG_FILLORDER, 1, TIFF_SHORT);
+
+ /* The loadimage function reads input orientation and sets
+ * image->orientation. The correct_image_orientation function
+ * applies the required rotation and mirror operations to
+ * present the data in TOPLEFT orientation and updates
+ * image->orientation if any transforms are performed,
+ * as per EXIF standard.
+ */
+ TIFFSetField(out, TIFFTAG_ORIENTATION, image->orientation);
+
+ /*
+ * Choose tiles/strip for the output image according to
+ * the command line arguments (-tiles, -strips) and the
+ * structure of the input image.
+ */
+ if (outtiled == -1)
+ outtiled = TIFFIsTiled(in);
+ if (outtiled) {
+ /*
+ * Setup output file's tile width&height. If either
+ * is not specified, use either the value from the
+ * input image or, if nothing is defined, use the
+ * library default.
+ */
+ if (tilewidth == (uint32) 0)
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);
+ if (tilelength == (uint32) 0)
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);
+
+ if (tilewidth == 0 || tilelength == 0)
+ TIFFDefaultTileSize(out, &tilewidth, &tilelength);
+ TIFFDefaultTileSize(out, &tilewidth, &tilelength);
+ TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);
+ TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);
+ } else {
+ /*
+ * RowsPerStrip is left unspecified: use either the
+ * value from the input image or, if nothing is defined,
+ * use the library default.
+ */
+ if (rowsperstrip == (uint32) 0)
+ {
+ if (!TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip))
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ if (compression != COMPRESSION_JPEG)
+ {
+ if (rowsperstrip > length)
+ rowsperstrip = length;
+ }
+ }
+ else
+ if (rowsperstrip == (uint32) -1)
+ rowsperstrip = length;
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ }
+
+ TIFFGetFieldDefaulted(in, TIFFTAG_PLANARCONFIG, &input_planar);
+ if (config != (uint16) -1)
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ else
+ CopyField(TIFFTAG_PLANARCONFIG, config);
+ if (spp <= 4)
+ CopyTag(TIFFTAG_TRANSFERFUNCTION, 4, TIFF_SHORT);
+ CopyTag(TIFFTAG_COLORMAP, 4, TIFF_SHORT);
+
+/* SMinSampleValue & SMaxSampleValue */
+ switch (compression) {
+ /* These are references to GLOBAL variables set by defaults
+ * and /or the compression flag
+ */
+ case COMPRESSION_JPEG:
+ if (((bps % 8) == 0) || ((bps % 12) == 0))
+ {
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ }
+ else
+ {
+ TIFFError("writeCroppedImage",
+ "JPEG compression requires 8 or 12 bits per sample");
+ return (-1);
+ }
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_ADOBE_DEFLATE:
+ case COMPRESSION_DEFLATE:
+ if (predictor != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ else
+ CopyField(TIFFTAG_PREDICTOR, predictor);
+ break;
+ case COMPRESSION_CCITTFAX3:
+ case COMPRESSION_CCITTFAX4:
+ if (compression == COMPRESSION_CCITTFAX3) {
+ if (g3opts != (uint32) -1)
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts);
+ else
+ CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);
+ } else
+ CopyTag(TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_BADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CLEANFAXDATA, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
+ break;
+ }
+ { uint32 len32;
+ void** data;
+ if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &len32, &data))
+ TIFFSetField(out, TIFFTAG_ICCPROFILE, len32, data);
+ }
+ { uint16 ninks;
+ const char* inknames;
+ if (TIFFGetField(in, TIFFTAG_NUMBEROFINKS, &ninks)) {
+ TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks);
+ if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) {
+ int inknameslen = strlen(inknames) + 1;
+ const char* cp = inknames;
+ while (ninks > 1) {
+ cp = strchr(cp, '\0');
+ if (cp) {
+ cp++;
+ inknameslen += (strlen(cp) + 1);
+ }
+ ninks--;
+ }
+ TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames);
+ }
+ }
+ }
+ {
+ unsigned short pg0, pg1;
+ if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1)) {
+ if (pageNum < 0) /* only one input file */
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
+ else
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
+ }
+ }
+
+ for (p = tags; p < &tags[NTAGS]; p++)
+ CopyTag(p->tag, p->count, p->type);
+
+ /* Update these since they are overwritten from input res by loop above */
+ TIFFSetField(out, TIFFTAG_XRESOLUTION, (float)hres);
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, (float)vres);
+
+ /* Compute the tile or strip dimensions and write to disk */
+ if (outtiled)
+ {
+ if (config == PLANARCONFIG_CONTIG)
+ writeBufferToContigTiles (out, sect_buff, length, width, spp, dump);
+ else
+ writeBufferToSeparateTiles (out, sect_buff, length, width, spp, dump);
+ }
+ else
+ {
+ if (config == PLANARCONFIG_CONTIG)
+ writeBufferToContigStrips (out, sect_buff, length);
+ else
+ writeBufferToSeparateStrips(out, sect_buff, length, width, spp, dump);
+ }
+
+ if (!TIFFWriteDirectory(out))
+ {
+ TIFFClose(out);
+ return (-1);
+ }
+
+ return (0);
+ } /* end writeSingleSection */
+
+
+/* Create a buffer to write one section at a time */
+static int
+createImageSection(uint32 sectsize, unsigned char **sect_buff_ptr)
+ {
+ unsigned char *sect_buff = NULL;
+ unsigned char *new_buff = NULL;
+ static uint32 prev_sectsize = 0;
+
+ sect_buff = *sect_buff_ptr;
+
+ if (!sect_buff)
+ {
+ sect_buff = (unsigned char *)_TIFFmalloc(sectsize);
+ *sect_buff_ptr = sect_buff;
+ _TIFFmemset(sect_buff, 0, sectsize);
+ }
+ else
+ {
+ if (prev_sectsize < sectsize)
+ {
+ new_buff = _TIFFrealloc(sect_buff, sectsize);
+ if (!new_buff)
+ {
+ free (sect_buff);
+ sect_buff = (unsigned char *)_TIFFmalloc(sectsize);
+ }
+ else
+ sect_buff = new_buff;
+
+ _TIFFmemset(sect_buff, 0, sectsize);
+ }
+ }
+
+ if (!sect_buff)
+ {
+ TIFFError("createImageSection", "Unable to allocate/reallocate section buffer");
+ return (-1);
+ }
+ prev_sectsize = sectsize;
+ *sect_buff_ptr = sect_buff;
+
+ return (0);
+ } /* end createImageSection */
+
+
+/* Process selections defined by regions, zones, margins, or fixed sized areas */
+static int
+processCropSelections(struct image_data *image, struct crop_mask *crop,
+ unsigned char **read_buff_ptr, struct buffinfo seg_buffs[])
+ {
+ int i;
+ uint32 width, length, total_width, total_length;
+ tsize_t cropsize;
+ unsigned char *crop_buff = NULL;
+ unsigned char *read_buff = NULL;
+ unsigned char *next_buff = NULL;
+ tsize_t prev_cropsize = 0;
+
+ read_buff = *read_buff_ptr;
+
+ if (crop->img_mode == COMPOSITE_IMAGES)
+ {
+ cropsize = crop->bufftotal;
+ crop_buff = seg_buffs[0].buffer;
+ if (!crop_buff)
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ else
+ {
+ prev_cropsize = seg_buffs[0].size;
+ if (prev_cropsize < cropsize)
+ {
+ next_buff = _TIFFrealloc(crop_buff, cropsize);
+ if (! next_buff)
+ {
+ _TIFFfree (crop_buff);
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ }
+ else
+ crop_buff = next_buff;
+ }
+ }
+
+ if (!crop_buff)
+ {
+ TIFFError("processCropSelections", "Unable to allocate/reallocate crop buffer");
+ return (-1);
+ }
+
+ _TIFFmemset(crop_buff, 0, cropsize);
+ seg_buffs[0].buffer = crop_buff;
+ seg_buffs[0].size = cropsize;
+
+ /* Checks for matching width or length as required */
+ if (extractCompositeRegions(image, crop, read_buff, crop_buff) != 0)
+ return (1);
+
+ if (crop->crop_mode & CROP_INVERT)
+ {
+ switch (crop->photometric)
+ {
+ /* Just change the interpretation */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = crop->photometric;
+ break;
+ case INVERT_DATA_ONLY:
+ case INVERT_DATA_AND_TAG:
+ if (invertImage(image->photometric, image->spp, image->bps,
+ crop->combined_width, crop->combined_length, crop_buff))
+ {
+ TIFFError("processCropSelections",
+ "Failed to invert colorspace for composite regions");
+ return (-1);
+ }
+ if (crop->photometric == INVERT_DATA_AND_TAG)
+ {
+ switch (image->photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ image->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+
+ /* Mirror and Rotate will not work with multiple regions unless they are the same width */
+ if (crop->crop_mode & CROP_MIRROR)
+ {
+ if (mirrorImage(image->spp, image->bps, crop->mirror,
+ crop->combined_width, crop->combined_length, crop_buff))
+ {
+ TIFFError("processCropSelections", "Failed to mirror composite regions %s",
+ (crop->rotation == MIRROR_HORIZ) ? "horizontally" : "vertically");
+ return (-1);
+ }
+ }
+
+ if (crop->crop_mode & CROP_ROTATE) /* rotate should be last as it can reallocate the buffer */
+ {
+ if (rotateImage(crop->rotation, image, &crop->combined_width,
+ &crop->combined_length, &crop_buff))
+ {
+ TIFFError("processCropSelections",
+ "Failed to rotate composite regions by %d degrees", crop->rotation);
+ return (-1);
+ }
+ seg_buffs[0].buffer = crop_buff;
+ seg_buffs[0].size = (((crop->combined_width * image->bps + 7 ) / 8)
+ * image->spp) * crop->combined_length;
+ }
+ }
+ else /* Separated Images */
+ {
+ total_width = total_length = 0;
+ for (i = 0; i < crop->selections; i++)
+ {
+ cropsize = crop->bufftotal;
+ crop_buff = seg_buffs[i].buffer;
+ if (!crop_buff)
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ else
+ {
+ prev_cropsize = seg_buffs[0].size;
+ if (prev_cropsize < cropsize)
+ {
+ next_buff = _TIFFrealloc(crop_buff, cropsize);
+ if (! next_buff)
+ {
+ _TIFFfree (crop_buff);
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ }
+ else
+ crop_buff = next_buff;
+ }
+ }
+
+ if (!crop_buff)
+ {
+ TIFFError("processCropSelections", "Unable to allocate/reallocate crop buffer");
+ return (-1);
+ }
+
+ _TIFFmemset(crop_buff, 0, cropsize);
+ seg_buffs[i].buffer = crop_buff;
+ seg_buffs[i].size = cropsize;
+
+ if (extractSeparateRegion(image, crop, read_buff, crop_buff, i))
+ {
+ TIFFError("processCropSelections", "Unable to extract cropped region %d from image", i);
+ return (-1);
+ }
+
+ width = crop->regionlist[i].width;
+ length = crop->regionlist[i].length;
+
+ if (crop->crop_mode & CROP_INVERT)
+ {
+ switch (crop->photometric)
+ {
+ /* Just change the interpretation */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = crop->photometric;
+ break;
+ case INVERT_DATA_ONLY:
+ case INVERT_DATA_AND_TAG:
+ if (invertImage(image->photometric, image->spp, image->bps,
+ width, length, crop_buff))
+ {
+ TIFFError("processCropSelections",
+ "Failed to invert colorspace for region");
+ return (-1);
+ }
+ if (crop->photometric == INVERT_DATA_AND_TAG)
+ {
+ switch (image->photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ image->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (crop->crop_mode & CROP_MIRROR)
+ {
+ if (mirrorImage(image->spp, image->bps, crop->mirror,
+ width, length, crop_buff))
+ {
+ TIFFError("processCropSelections", "Failed to mirror crop region %s",
+ (crop->rotation == MIRROR_HORIZ) ? "horizontally" : "vertically");
+ return (-1);
+ }
+ }
+
+ if (crop->crop_mode & CROP_ROTATE) /* rotate should be last as it can reallocate the buffer */
+ {
+ if (rotateImage(crop->rotation, image, &crop->regionlist[i].width,
+ &crop->regionlist[i].length, &crop_buff))
+ {
+ TIFFError("processCropSelections",
+ "Failed to rotate crop region by %d degrees", crop->rotation);
+ return (-1);
+ }
+ total_width += crop->regionlist[i].width;
+ total_length += crop->regionlist[i].length;
+ crop->combined_width = total_width;
+ crop->combined_length = total_length;
+ seg_buffs[i].buffer = crop_buff;
+ seg_buffs[i].size = (((crop->regionlist[i].width * image->bps + 7 ) / 8)
+ * image->spp) * crop->regionlist[i].length;
+ }
+ }
+ }
+ return (0);
+ } /* end processCropSelections */
+
+/* Copy the crop section of the data from the current image into a buffer
+ * and adjust the IFD values to reflect the new size. If no cropping is
+ * required, use the origial read buffer as the crop buffer.
+ *
+ * There is quite a bit of redundancy between this routine and the more
+ * specialized processCropSelections, but this provides
+ * the most optimized path when no Zones or Regions are required.
+ */
+static int
+createCroppedImage(struct image_data *image, struct crop_mask *crop,
+ unsigned char **read_buff_ptr, unsigned char **crop_buff_ptr)
+ {
+ tsize_t cropsize;
+ unsigned char *read_buff = NULL;
+ unsigned char *crop_buff = NULL;
+ unsigned char *new_buff = NULL;
+ static tsize_t prev_cropsize = 0;
+
+ read_buff = *read_buff_ptr;
+
+ /* process full image, no crop buffer needed */
+ crop_buff = read_buff;
+ *crop_buff_ptr = read_buff;
+ crop->combined_width = image->width;
+ crop->combined_length = image->length;
+
+ cropsize = crop->bufftotal;
+ crop_buff = *crop_buff_ptr;
+ if (!crop_buff)
+ {
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ *crop_buff_ptr = crop_buff;
+ _TIFFmemset(crop_buff, 0, cropsize);
+ prev_cropsize = cropsize;
+ }
+ else
+ {
+ if (prev_cropsize < cropsize)
+ {
+ new_buff = _TIFFrealloc(crop_buff, cropsize);
+ if (!new_buff)
+ {
+ free (crop_buff);
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ }
+ else
+ crop_buff = new_buff;
+ _TIFFmemset(crop_buff, 0, cropsize);
+ }
+ }
+
+ if (!crop_buff)
+ {
+ TIFFError("createCroppedImage", "Unable to allocate/reallocate crop buffer");
+ return (-1);
+ }
+ *crop_buff_ptr = crop_buff;
+
+ if (crop->crop_mode & CROP_INVERT)
+ {
+ switch (crop->photometric)
+ {
+ /* Just change the interpretation */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = crop->photometric;
+ break;
+ case INVERT_DATA_ONLY:
+ case INVERT_DATA_AND_TAG:
+ if (invertImage(image->photometric, image->spp, image->bps,
+ crop->combined_width, crop->combined_length, crop_buff))
+ {
+ TIFFError("createCroppedImage",
+ "Failed to invert colorspace for image or cropped selection");
+ return (-1);
+ }
+ if (crop->photometric == INVERT_DATA_AND_TAG)
+ {
+ switch (image->photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ image->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (crop->crop_mode & CROP_MIRROR)
+ {
+ if (mirrorImage(image->spp, image->bps, crop->mirror,
+ crop->combined_width, crop->combined_length, crop_buff))
+ {
+ TIFFError("createCroppedImage", "Failed to mirror image or cropped selection %s",
+ (crop->rotation == MIRROR_HORIZ) ? "horizontally" : "vertically");
+ return (-1);
+ }
+ }
+
+ if (crop->crop_mode & CROP_ROTATE) /* rotate should be last as it can reallocate the buffer */
+ {
+ if (rotateImage(crop->rotation, image, &crop->combined_width,
+ &crop->combined_length, crop_buff_ptr))
+ {
+ TIFFError("createCroppedImage",
+ "Failed to rotate image or cropped selection by %d degrees", crop->rotation);
+ return (-1);
+ }
+ }
+
+ if (crop_buff == read_buff) /* we used the read buffer for the crop buffer */
+ *read_buff_ptr = NULL; /* so we don't try to free it later */
+
+ return (0);
+ } /* end createCroppedImage */
+
+
+/* Code in this function is heavily indebted to code in tiffcp
+ * with modifications by Richard Nolde to handle orientation correctly.
+ * It will have to be updated significantly if support is added to
+ * extract one or more samples from original image since the
+ * original code assumes we are always copying all samples.
+ * Use of global variables for config, compression and others
+ * should be replaced by addition to the crop_mask struct (which
+ * will be renamed to proc_opts indicating that is controlls
+ * user supplied processing options, not just cropping) and
+ * then passed in as an argument.
+ */
+static int
+writeCroppedImage(TIFF *in, TIFF *out, struct image_data *image,
+ struct dump_opts *dump, uint32 width, uint32 length,
+ unsigned char *crop_buff, int pagenum, int total_pages)
+ {
+ uint16 bps, spp;
+ uint16 input_compression, input_photometric;
+ uint16 input_jpeg_colormode, input_planar;
+ struct cpTag* p;
+
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &spp);
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &bps);
+
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
+
+ CopyField(TIFFTAG_BITSPERSAMPLE, bps);
+ CopyField(TIFFTAG_SAMPLESPERPIXEL, spp);
+
+ TIFFGetField(in, TIFFTAG_COMPRESSION, &input_compression);
+ if (compression != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ else
+ {
+ if (input_compression == COMPRESSION_OJPEG)
+ {
+ TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
+ compression = COMPRESSION_JPEG;
+ }
+ else
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ }
+
+ TIFFGetField(in, TIFFTAG_JPEGCOLORMODE, &input_jpeg_colormode);
+#ifdef DEBUG2
+ TIFFError("writeCroppedImage", "Input compression: %s",
+ (input_compression == COMPRESSION_OJPEG) ? "Old Jpeg" :
+ ((input_compression == COMPRESSION_JPEG) ? "New Jpeg" : "Non Jpeg"));
+#endif
+ if (compression == COMPRESSION_JPEG)
+ {
+ if ((input_photometric == PHOTOMETRIC_PALETTE) || /* color map indexed */
+ (input_photometric == PHOTOMETRIC_MASK)) /* $holdout mask */
+ {
+ TIFFError ("writeCroppedImage",
+ "JPEG compression cannot be used with %s image data",
+ (input_photometric == PHOTOMETRIC_PALETTE) ?
+ "palette" : "mask");
+ return (-1);
+ }
+ if (input_photometric == PHOTOMETRIC_RGB)
+ {
+ if (jpegcolormode == JPEGCOLORMODE_RGB)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ }
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
+ }
+ else
+ {
+ if (compression == COMPRESSION_SGILOG || compression == COMPRESSION_SGILOG24)
+ {
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, spp == 1 ?
+ PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
+ }
+ else
+ {
+ if (input_compression == COMPRESSION_SGILOG ||
+ input_compression == COMPRESSION_SGILOG24)
+ {
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, spp == 1 ?
+ PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
+ }
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, image->photometric);
+ }
+ }
+
+ if (((input_photometric == PHOTOMETRIC_LOGL) ||
+ (input_photometric == PHOTOMETRIC_LOGLUV)) &&
+ ((compression != COMPRESSION_SGILOG) &&
+ (compression != COMPRESSION_SGILOG24)))
+ {
+ TIFFError("writeCroppedImage",
+ "LogL and LogLuv source data require SGI_LOG or SGI_LOG24 compression");
+ return (-1);
+ }
+
+ if (fillorder != 0)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ else
+ CopyTag(TIFFTAG_FILLORDER, 1, TIFF_SHORT);
+
+ /* The loadimage function reads input orientation and sets
+ * image->orientation. The correct_image_orientation function
+ * applies the required rotation and mirror operations to
+ * present the data in TOPLEFT orientation and updates
+ * image->orientation if any transforms are performed,
+ * as per EXIF standard.
+ */
+ TIFFSetField(out, TIFFTAG_ORIENTATION, image->orientation);
+
+ /*
+ * Choose tiles/strip for the output image according to
+ * the command line arguments (-tiles, -strips) and the
+ * structure of the input image.
+ */
+ if (outtiled == -1)
+ outtiled = TIFFIsTiled(in);
+ if (outtiled) {
+ /*
+ * Setup output file's tile width&height. If either
+ * is not specified, use either the value from the
+ * input image or, if nothing is defined, use the
+ * library default.
+ */
+ if (tilewidth == (uint32) 0)
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);
+ if (tilelength == (uint32) 0)
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);
+
+ if (tilewidth == 0 || tilelength == 0)
+ TIFFDefaultTileSize(out, &tilewidth, &tilelength);
+ TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);
+ TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);
+ } else {
+ /*
+ * RowsPerStrip is left unspecified: use either the
+ * value from the input image or, if nothing is defined,
+ * use the library default.
+ */
+ if (rowsperstrip == (uint32) 0)
+ {
+ if (!TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip))
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ if (compression != COMPRESSION_JPEG)
+ {
+ if (rowsperstrip > length)
+ rowsperstrip = length;
+ }
+ }
+ else
+ if (rowsperstrip == (uint32) -1)
+ rowsperstrip = length;
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ }
+
+ TIFFGetFieldDefaulted(in, TIFFTAG_PLANARCONFIG, &input_planar);
+ if (config != (uint16) -1)
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ else
+ CopyField(TIFFTAG_PLANARCONFIG, config);
+ if (spp <= 4)
+ CopyTag(TIFFTAG_TRANSFERFUNCTION, 4, TIFF_SHORT);
+ CopyTag(TIFFTAG_COLORMAP, 4, TIFF_SHORT);
+
+/* SMinSampleValue & SMaxSampleValue */
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (((bps % 8) == 0) || ((bps % 12) == 0))
+ {
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ }
+ else
+ {
+ TIFFError("writeCroppedImage",
+ "JPEG compression requires 8 or 12 bits per sample");
+ return (-1);
+ }
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_ADOBE_DEFLATE:
+ case COMPRESSION_DEFLATE:
+ if (predictor != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ else
+ CopyField(TIFFTAG_PREDICTOR, predictor);
+ break;
+ case COMPRESSION_CCITTFAX3:
+ case COMPRESSION_CCITTFAX4:
+ if (bps != 1)
+ {
+ TIFFError("writeCroppedImage",
+ "Group 3/4 compression is not usable with bps > 1");
+ return (-1);
+ }
+ if (compression == COMPRESSION_CCITTFAX3) {
+ if (g3opts != (uint32) -1)
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts);
+ else
+ CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);
+ } else
+ CopyTag(TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_BADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CLEANFAXDATA, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
+ break;
+ case COMPRESSION_NONE:
+ break;
+ default: break;
+ }
+ { uint32 len32;
+ void** data;
+ if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &len32, &data))
+ TIFFSetField(out, TIFFTAG_ICCPROFILE, len32, data);
+ }
+ { uint16 ninks;
+ const char* inknames;
+ if (TIFFGetField(in, TIFFTAG_NUMBEROFINKS, &ninks)) {
+ TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks);
+ if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) {
+ int inknameslen = strlen(inknames) + 1;
+ const char* cp = inknames;
+ while (ninks > 1) {
+ cp = strchr(cp, '\0');
+ if (cp) {
+ cp++;
+ inknameslen += (strlen(cp) + 1);
+ }
+ ninks--;
+ }
+ TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames);
+ }
+ }
+ }
+ {
+ unsigned short pg0, pg1;
+ if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1)) {
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pagenum, total_pages);
+ }
+ }
+
+ for (p = tags; p < &tags[NTAGS]; p++)
+ CopyTag(p->tag, p->count, p->type);
+
+ /* Compute the tile or strip dimensions and write to disk */
+ if (outtiled)
+ {
+ if (config == PLANARCONFIG_CONTIG)
+ {
+ if (writeBufferToContigTiles (out, crop_buff, length, width, spp, dump))
+ TIFFError("","Unable to write contiguous tile data for page %d", pagenum);
+ }
+ else
+ {
+ if (writeBufferToSeparateTiles (out, crop_buff, length, width, spp, dump))
+ TIFFError("","Unable to write separate tile data for page %d", pagenum);
+ }
+ }
+ else
+ {
+ if (config == PLANARCONFIG_CONTIG)
+ {
+ if (writeBufferToContigStrips (out, crop_buff, length))
+ TIFFError("","Unable to write contiguous strip data for page %d", pagenum);
+ }
+ else
+ {
+ if (writeBufferToSeparateStrips(out, crop_buff, length, width, spp, dump))
+ TIFFError("","Unable to write separate strip data for page %d", pagenum);
+ }
+ }
+
+ if (!TIFFWriteDirectory(out))
+ {
+ TIFFError("","Failed to write IFD for page number %d", pagenum);
+ TIFFClose(out);
+ return (-1);
+ }
+
+ return (0);
+ } /* end writeCroppedImage */
+
+static int
+rotateContigSamples8bits(uint16 rotation, uint16 spp, uint16 bps, uint32 width,
+ uint32 length, uint32 col, uint8 *src, uint8 *dst)
+ {
+ int ready_bits = 0;
+ uint32 src_byte = 0, src_bit = 0;
+ uint32 row, rowsize = 0, bit_offset = 0;
+ uint8 matchbits = 0, maskbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ uint8 *next;
+ tsample_t sample;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("rotateContigSamples8bits","Invalid src or destination buffer");
+ return (1);
+ }
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ ready_bits = 0;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+ buff1 = buff2 = 0;
+
+ for (row = 0; row < length ; row++)
+ {
+ bit_offset = col * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ switch (rotation)
+ {
+ case 90: next = src + src_byte - (row * rowsize);
+ break;
+ case 270: next = src + src_byte + (row * rowsize);
+ break;
+ default: TIFFError("rotateContigSamples8bits", "Invalid rotation %d", rotation);
+ return (1);
+ }
+ matchbits = maskbits << (8 - src_bit - bps);
+ buff1 = ((*next) & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ }
+ else
+ {
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ }
+
+ return (0);
+ } /* end rotateContigSamples8bits */
+
+
+static int
+rotateContigSamples16bits(uint16 rotation, uint16 spp, uint16 bps, uint32 width,
+ uint32 length, uint32 col, uint8 *src, uint8 *dst)
+ {
+ int ready_bits = 0;
+ uint32 row, rowsize, bit_offset;
+ uint32 src_byte = 0, src_bit = 0;
+ uint16 matchbits = 0, maskbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ uint8 *next;
+ tsample_t sample;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("rotateContigSamples16bits","Invalid src or destination buffer");
+ return (1);
+ }
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ ready_bits = 0;
+ maskbits = (uint16)-1 >> (16 - bps);
+ buff1 = buff2 = 0;
+ for (row = 0; row < length; row++)
+ {
+ bit_offset = col * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ switch (rotation)
+ {
+ case 90: next = src + src_byte - (row * rowsize);
+ break;
+ case 270: next = src + src_byte + (row * rowsize);
+ break;
+ default: TIFFError("rotateContigSamples8bits", "Invalid rotation %d", rotation);
+ return (1);
+ }
+ matchbits = maskbits << (16 - src_bit - bps);
+ if (little_endian)
+ buff1 = (next[0] << 8) | next[1];
+ else
+ buff1 = (next[1] << 8) | next[0];
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ }
+
+ return (0);
+ } /* end rotateContigSamples16bits */
+
+static int
+rotateContigSamples24bits(uint16 rotation, uint16 spp, uint16 bps, uint32 width,
+ uint32 length, uint32 col, uint8 *src, uint8 *dst)
+ {
+ int ready_bits = 0;
+ uint32 row, rowsize, bit_offset;
+ uint32 src_byte = 0, src_bit = 0;
+ uint32 matchbits = 0, maskbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ uint8 *next;
+ tsample_t sample;
+
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("rotateContigSamples24bits","Invalid src or destination buffer");
+ return (1);
+ }
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ ready_bits = 0;
+ maskbits = (uint32)-1 >> (32 - bps);
+ buff1 = buff2 = 0;
+ for (row = 0; row < length; row++)
+ {
+ bit_offset = col * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ switch (rotation)
+ {
+ case 90: next = src + src_byte - (row * rowsize);
+ break;
+ case 270: next = src + src_byte + (row * rowsize);
+ break;
+ default: TIFFError("rotateContigSamples8bits", "Invalid rotation %d", rotation);
+ return (1);
+ }
+ matchbits = maskbits << (32 - src_bit - bps);
+ if (little_endian)
+ buff1 = (next[0] << 24) | (next[1] << 16) | (next[2] << 8) | next[3];
+ else
+ buff1 = (next[3] << 24) | (next[2] << 16) | (next[1] << 8) | next[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 16)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end rotateContigSamples24bits */
+
+static int
+rotateContigSamples32bits(uint16 rotation, uint16 spp, uint16 bps, uint32 width,
+ uint32 length, uint32 col, uint8 *src, uint8 *dst)
+ {
+ int ready_bits = 0, shift_width = 0;
+ int bytes_per_sample, bytes_per_pixel;
+ uint32 row, rowsize, bit_offset;
+ uint32 src_byte, src_bit;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ uint8 *next;
+ tsample_t sample;
+
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("rotateContigSamples24bits","Invalid src or destination buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ ready_bits = 0;
+ maskbits = (uint64)-1 >> (64 - bps);
+ buff1 = buff2 = 0;
+ for (row = 0; row < length; row++)
+ {
+ bit_offset = col * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ switch (rotation)
+ {
+ case 90: next = src + src_byte - (row * rowsize);
+ break;
+ case 270: next = src + src_byte + (row * rowsize);
+ break;
+ default: TIFFError("rotateContigSamples8bits", "Invalid rotation %d", rotation);
+ return (1);
+ }
+ matchbits = maskbits << (64 - src_bit - bps);
+ if (little_endian)
+ {
+ longbuff1 = (next[0] << 24) | (next[1] << 16) | (next[2] << 8) | next[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (next[3] << 24) | (next[2] << 16) | (next[1] << 8) | next[0];
+ longbuff2 = longbuff1;
+ }
+
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ if (ready_bits < 32)
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end rotateContigSamples32bits */
+
+
+/* Rotate an image by a multiple of 90 degrees clockwise */
+static int
+rotateImage(uint16 rotation, struct image_data *image, uint32 *img_width,
+ uint32 *img_length, unsigned char **ibuff_ptr)
+ {
+ int shift_width;
+ uint32 bytes_per_pixel, bytes_per_sample;
+ uint32 row, rowsize, src_offset, dst_offset;
+ uint32 i, col, width, length;
+ uint32 colsize, buffsize, col_offset, pix_offset;
+ unsigned char *ibuff;
+ unsigned char *src;
+ unsigned char *dst;
+ uint16 spp, bps;
+ float res_temp;
+ unsigned char *rbuff = NULL;
+
+ width = *img_width;
+ length = *img_length;
+ spp = image->spp;
+ bps = image->bps;
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ colsize = ((bps * spp * length) + 7) / 8;
+ if ((colsize * width) > (rowsize * length))
+ buffsize = (colsize + 1) * width;
+ else
+ buffsize = (rowsize + 1) * length;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ switch (rotation)
+ {
+ case 0:
+ case 360: return (0);
+ case 90:
+ case 180:
+ case 270: break;
+ default: TIFFError("rotateImage", "Invalid rotation angle %d", rotation);
+ return (-1);
+ }
+
+ if (!(rbuff = (unsigned char *)_TIFFmalloc(buffsize)))
+ {
+ TIFFError("rotateImage", "Unable to allocate rotation buffer of %1u bytes", buffsize);
+ return (-1);
+ }
+ _TIFFmemset(rbuff, '\0', buffsize);
+
+ ibuff = *ibuff_ptr;
+ switch (rotation)
+ {
+ case 180: if ((bps % 8) == 0) /* byte alligned data */
+ {
+ src = ibuff;
+ pix_offset = (spp * bps) / 8;
+ for (row = 0; row < length; row++)
+ {
+ dst_offset = (length - row - 1) * rowsize;
+ for (col = 0; col < width; col++)
+ {
+ col_offset = (width - col - 1) * pix_offset;
+ dst = rbuff + dst_offset + col_offset;
+
+ for (i = 0; i < bytes_per_pixel; i++)
+ *dst++ = *src++;
+ }
+ }
+ }
+ else
+ { /* non 8 bit per sample data */
+ for (row = 0; row < length; row++)
+ {
+ src_offset = row * rowsize;
+ dst_offset = (length - row - 1) * rowsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ switch (shift_width)
+ {
+ case 1: if (bps == 1)
+ {
+ if (reverseSamples8bits(spp, bps, width, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ }
+ if (reverseSamples16bits(spp, bps, width, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 2: if (reverseSamples24bits(spp, bps, width, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (reverseSamples32bits(spp, bps, width, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ default: TIFFError("rotateImage","Unsupported bit depth %d", bps);
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ }
+ }
+ _TIFFfree(ibuff);
+ *(ibuff_ptr) = rbuff;
+ break;
+
+ case 90: if ((bps % 8) == 0) /* byte aligned data */
+ {
+ for (col = 0; col < width; col++)
+ {
+ src_offset = ((length - 1) * rowsize) + (col * bytes_per_pixel);
+ dst_offset = col * colsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ for (row = length; row > 0; row--)
+ {
+ for (i = 0; i < bytes_per_pixel; i++)
+ *dst++ = *(src + i);
+ src -= rowsize;
+ }
+ }
+ }
+ else
+ { /* non 8 bit per sample data */
+ for (col = 0; col < width; col++)
+ {
+ src_offset = (length - 1) * rowsize;
+ dst_offset = col * colsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ switch (shift_width)
+ {
+ case 1: if (bps == 1)
+ {
+ if (rotateContigSamples8bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ }
+ if (rotateContigSamples16bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 2: if (rotateContigSamples24bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (rotateContigSamples32bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ default: TIFFError("rotateImage","Unsupported bit depth %d", bps);
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ }
+ }
+ _TIFFfree(ibuff);
+ *(ibuff_ptr) = rbuff;
+
+ *img_width = length;
+ *img_length = width;
+ image->width = length;
+ image->length = width;
+ res_temp = image->xres;
+ image->xres = image->yres;
+ image->yres = res_temp;
+ break;
+
+ case 270: if ((bps % 8) == 0) /* byte aligned data */
+ {
+ for (col = 0; col < width; col++)
+ {
+ src_offset = col * bytes_per_pixel;
+ dst_offset = (width - col - 1) * colsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ for (row = length; row > 0; row--)
+ {
+ for (i = 0; i < bytes_per_pixel; i++)
+ *dst++ = *(src + i);
+ src += rowsize;
+ }
+ }
+ }
+ else
+ { /* non 8 bit per sample data */
+ for (col = 0; col < width; col++)
+ {
+ src_offset = 0;
+ dst_offset = (width - col - 1) * colsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ switch (shift_width)
+ {
+ case 1: if (bps == 1)
+ {
+ if (rotateContigSamples8bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ }
+ if (rotateContigSamples16bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 2: if (rotateContigSamples24bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (rotateContigSamples32bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ default: TIFFError("rotateImage","Unsupported bit depth %d", bps);
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ }
+ }
+ _TIFFfree(ibuff);
+ *(ibuff_ptr) = rbuff;
+
+ *img_width = length;
+ *img_length = width;
+ image->width = length;
+ image->length = width;
+ res_temp = image->xres;
+ image->xres = image->yres;
+ image->yres = res_temp;
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+ } /* end rotateImage */
+
+static int
+reverseSamples8bits (uint16 spp, uint16 bps, uint32 width,
+ uint8 *ibuff, uint8 *obuff)
+ {
+ int ready_bits = 0;
+ uint32 col;
+ uint32 src_byte, src_bit;
+ uint32 bit_offset = 0;
+ uint8 match_bits = 0, mask_bits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t sample;
+
+ if ((ibuff == NULL) || (obuff == NULL))
+ {
+ TIFFError("reverseSamples8bits","Invalid image or work buffer");
+ return (1);
+ }
+
+ ready_bits = 0;
+ mask_bits = (uint8)-1 >> ( 8 - bps);
+ dst = obuff;
+ for (col = width; col > 0; col--)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = (col - 1) * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ src = ibuff + src_byte;
+ match_bits = mask_bits << (8 - src_bit - bps);
+ buff1 = ((*src) & match_bits) << (src_bit);
+
+ if (ready_bits < 8)
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ else /* If we have a full buffer's worth, write it out */
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ }
+ ready_bits += bps;
+ }
+ }
+ if (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ }
+
+ return (0);
+ } /* end reverseSamples8bits */
+
+
+static int
+reverseSamples16bits (uint16 spp, uint16 bps, uint32 width,
+ uint8 *ibuff, uint8 *obuff)
+ {
+ int ready_bits = 0;
+ uint32 col;
+ uint32 src_byte = 0, high_bit = 0;
+ uint32 bit_offset = 0;
+ uint16 match_bits = 0, mask_bits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t sample;
+
+ if ((ibuff == NULL) || (obuff == NULL))
+ {
+ TIFFError("reverseSample16bits","Invalid image or work buffer");
+ return (1);
+ }
+
+ ready_bits = 0;
+ mask_bits = (uint16)-1 >> (16 - bps);
+ dst = obuff;
+ for (col = width; col > 0; col--)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = (col - 1) * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ high_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ high_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ src = ibuff + src_byte;
+ match_bits = mask_bits << (16 - high_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+ buff1 = (buff1 & match_bits) << (high_bit);
+
+ if (ready_bits < 8)
+ { /* add another bps bits to the buffer */
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ }
+
+ return (0);
+ } /* end reverseSamples16bits */
+
+static int
+reverseSamples24bits (uint16 spp, uint16 bps, uint32 width,
+ uint8 *ibuff, uint8 *obuff)
+ {
+ int ready_bits = 0;
+ uint32 col;
+ uint32 src_byte = 0, high_bit = 0;
+ uint32 bit_offset = 0;
+ uint32 match_bits = 0, mask_bits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t sample;
+
+ if ((ibuff == NULL) || (obuff == NULL))
+ {
+ TIFFError("reverseSamples24bits","Invalid image or work buffer");
+ return (1);
+ }
+
+ ready_bits = 0;
+ mask_bits = (uint32)-1 >> (32 - bps);
+ dst = obuff;
+ for (col = width; col > 0; col--)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = (col - 1) * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ high_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ high_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ src = ibuff + src_byte;
+ match_bits = mask_bits << (32 - high_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ buff1 = (buff1 & match_bits) << (high_bit);
+
+ if (ready_bits < 16)
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end reverseSamples24bits */
+
+
+static int
+reverseSamples32bits (uint16 spp, uint16 bps, uint32 width,
+ uint8 *ibuff, uint8 *obuff)
+ {
+ int ready_bits = 0, shift_width = 0;
+ int bytes_per_sample, bytes_per_pixel;
+ uint32 bit_offset;
+ uint32 src_byte = 0, high_bit = 0;
+ uint32 col;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 mask_bits = 0, match_bits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t sample;
+
+ if ((ibuff == NULL) || (obuff == NULL))
+ {
+ TIFFError("reverseSamples32bits","Invalid image or work buffer");
+ return (1);
+ }
+
+ ready_bits = 0;
+ mask_bits = (uint64)-1 >> (64 - bps);
+ dst = obuff;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ for (col = width; col > 0; col--)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = (col - 1) * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ high_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ high_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ src = ibuff + src_byte;
+ match_bits = mask_bits << (64 - high_bit - bps);
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & match_bits) << (high_bit);
+
+ if (ready_bits < 32)
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end reverseSamples32bits */
+
+static int
+reverseSamplesBytes (uint16 spp, uint16 bps, uint32 width,
+ uint8 *src, uint8 *dst)
+ {
+ int i;
+ uint32 col, bytes_per_pixel, col_offset;
+ uint8 bytebuff1;
+ unsigned char swapbuff[32];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("reverseSamplesBytes","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ switch (bps / 8)
+ {
+ case 8: /* Use memcpy for multiple bytes per sample data */
+ case 4:
+ case 3:
+ case 2: for (col = 0; col < (width / 2); col++)
+ {
+ col_offset = col * bytes_per_pixel;
+ _TIFFmemcpy (swapbuff, src + col_offset, bytes_per_pixel);
+ _TIFFmemcpy (src + col_offset, dst - col_offset - bytes_per_pixel, bytes_per_pixel);
+ _TIFFmemcpy (dst - col_offset - bytes_per_pixel, swapbuff, bytes_per_pixel);
+ }
+ break;
+ case 1: /* Use byte copy only for single byte per sample data */
+ for (col = 0; col < (width / 2); col++)
+ {
+ for (i = 0; i < spp; i++)
+ {
+ bytebuff1 = *src;
+ *src++ = *(dst - spp + i);
+ *(dst - spp + i) = bytebuff1;
+ }
+ dst -= spp;
+ }
+ break;
+ default: TIFFError("reverseSamplesBytes","Unsupported bit depth %d", bps);
+ return (1);
+ }
+ return (0);
+ } /* end reverseSamplesBytes */
+
+
+/* Mirror an image horizontally or vertically */
+static int
+mirrorImage(uint16 spp, uint16 bps, uint16 mirror, uint32 width, uint32 length, unsigned char *ibuff)
+ {
+ int shift_width;
+ uint32 bytes_per_pixel, bytes_per_sample;
+ uint32 row, rowsize, row_offset;
+ unsigned char *line_buff = NULL;
+ unsigned char *src;
+ unsigned char *dst;
+
+ src = ibuff;
+ rowsize = ((width * bps * spp) + 7) / 8;
+ switch (mirror)
+ {
+ case MIRROR_BOTH:
+ case MIRROR_VERT:
+ line_buff = (unsigned char *)_TIFFmalloc(rowsize);
+ if (line_buff == NULL)
+ {
+ TIFFError ("mirrorImage", "Unable to allocate mirror line buffer of %1u bytes", rowsize);
+ return (-1);
+ }
+
+ dst = ibuff + (rowsize * (length - 1));
+ for (row = 0; row < length / 2; row++)
+ {
+ _TIFFmemcpy(line_buff, src, rowsize);
+ _TIFFmemcpy(src, dst, rowsize);
+ _TIFFmemcpy(dst, line_buff, rowsize);
+ src += (rowsize);
+ dst -= (rowsize);
+ }
+ if (line_buff)
+ _TIFFfree(line_buff);
+ if (mirror == MIRROR_VERT)
+ break;
+ case MIRROR_HORIZ :
+ if ((bps % 8) == 0) /* byte alligned data */
+ {
+ for (row = 0; row < length; row++)
+ {
+ row_offset = row * rowsize;
+ src = ibuff + row_offset;
+ dst = ibuff + row_offset + rowsize;
+ if (reverseSamplesBytes(spp, bps, width, src, dst))
+ {
+ return (-1);
+ }
+ }
+ }
+ else
+ { /* non 8 bit per sample data */
+ if (!(line_buff = (unsigned char *)_TIFFmalloc(rowsize + 1)))
+ {
+ TIFFError("mirrorImage", "Unable to allocate mirror line buffer");
+ return (-1);
+ }
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ for (row = 0; row < length; row++)
+ {
+ row_offset = row * rowsize;
+ src = ibuff + row_offset;
+ _TIFFmemset (line_buff, '\0', rowsize);
+ switch (shift_width)
+ {
+ case 1: if (reverseSamples16bits(spp, bps, width, src, line_buff))
+ {
+ _TIFFfree(line_buff);
+ return (-1);
+ }
+ _TIFFmemcpy (src, line_buff, rowsize);
+ break;
+ case 2: if (reverseSamples24bits(spp, bps, width, src, line_buff))
+ {
+ _TIFFfree(line_buff);
+ return (-1);
+ }
+ _TIFFmemcpy (src, line_buff, rowsize);
+ break;
+ case 3:
+ case 4:
+ case 5: if (reverseSamples32bits(spp, bps, width, src, line_buff))
+ {
+ _TIFFfree(line_buff);
+ return (-1);
+ }
+ _TIFFmemcpy (src, line_buff, rowsize);
+ break;
+ default: TIFFError("mirrorImage","Unsupported bit depth %d", bps);
+ _TIFFfree(line_buff);
+ return (-1);
+ }
+ }
+ if (line_buff)
+ _TIFFfree(line_buff);
+ }
+ break;
+
+ default: TIFFError ("mirrorImage", "Invalid mirror axis %d", mirror);
+ return (-1);
+ break;
+ }
+
+ return (0);
+ }
+
+/* Invert the light and dark values for a bilevel or grayscale image */
+static int
+invertImage(uint16 photometric, uint16 spp, uint16 bps, uint32 width, uint32 length, unsigned char *work_buff)
+ {
+ uint32 row, col;
+ unsigned char bytebuff1, bytebuff2, bytebuff3, bytebuff4;
+ unsigned char *src;
+ uint16 *src_uint16;
+ uint32 *src_uint32;
+
+ if (spp != 1)
+ {
+ TIFFError("invertImage", "Image inversion not supported for more than one sample per pixel");
+ return (-1);
+ }
+
+ if (photometric != PHOTOMETRIC_MINISWHITE && photometric != PHOTOMETRIC_MINISBLACK)
+ {
+ TIFFError("invertImage", "Only black and white and grayscale images can be inverted");
+ return (-1);
+ }
+
+ src = work_buff;
+ if (src == NULL)
+ {
+ TIFFError ("invertImage", "Invalid crop buffer passed to invertImage");
+ return (-1);
+ }
+
+ switch (bps)
+ {
+ case 32: src_uint32 = (uint32 *)src;
+ for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ *src_uint32 = (uint32)0xFFFFFFFF - *src_uint32;
+ src_uint32++;
+ }
+ break;
+ case 16: src_uint16 = (uint16 *)src;
+ for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ *src_uint16 = (uint16)0xFFFF - *src_uint16;
+ src_uint16++;
+ }
+ break;
+ case 8: for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ *src = (uint8)255 - *src;
+ src++;
+ }
+ break;
+ case 4: for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ bytebuff1 = 16 - (uint8)(*src & 240 >> 4);
+ bytebuff2 = 16 - (*src & 15);
+ *src = bytebuff1 << 4 & bytebuff2;
+ src++;
+ }
+ break;
+ case 2: for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ bytebuff1 = 4 - (uint8)(*src & 192 >> 6);
+ bytebuff2 = 4 - (uint8)(*src & 48 >> 4);
+ bytebuff3 = 4 - (uint8)(*src & 12 >> 2);
+ bytebuff4 = 4 - (uint8)(*src & 3);
+ *src = (bytebuff1 << 6) || (bytebuff2 << 4) || (bytebuff3 << 2) || bytebuff4;
+ src++;
+ }
+ break;
+ case 1: for (row = 0; row < length; row++)
+ for (col = 0; col < width; col += 8 /(spp * bps))
+ {
+ *src = ~(*src);
+ src++;
+ }
+ break;
+ default: TIFFError("invertImage", "Unsupported bit depth %d", bps);
+ return (-1);
+ }
+
+ return (0);
+ }
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffdither.c b/tiff/tools/tiffdither.c
new file mode 100644
index 0000000..dee2a02
--- /dev/null
+++ b/tiff/tools/tiffdither.c
@@ -0,0 +1,332 @@
+/* $Id: tiffdither.c,v 1.9.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+
+uint32 imagewidth;
+uint32 imagelength;
+int threshold = 128;
+
+static void usage(void);
+
+/*
+ * Floyd-Steinberg error propragation with threshold.
+ * This code is stolen from tiffmedian.
+ */
+static void
+fsdither(TIFF* in, TIFF* out)
+{
+ unsigned char *outline, *inputline, *inptr;
+ short *thisline, *nextline, *tmpptr;
+ register unsigned char *outptr;
+ register short *thisptr, *nextptr;
+ register uint32 i, j;
+ uint32 imax, jmax;
+ int lastline, lastpixel;
+ int bit;
+ tsize_t outlinesize;
+
+ imax = imagelength - 1;
+ jmax = imagewidth - 1;
+ inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ thisline = (short *)_TIFFmalloc(imagewidth * sizeof (short));
+ nextline = (short *)_TIFFmalloc(imagewidth * sizeof (short));
+ outlinesize = TIFFScanlineSize(out);
+ outline = (unsigned char *) _TIFFmalloc(outlinesize);
+
+ /*
+ * Get first line
+ */
+ if (TIFFReadScanline(in, inputline, 0, 0) <= 0)
+ return;
+ inptr = inputline;
+ nextptr = nextline;
+ for (j = 0; j < imagewidth; ++j)
+ *nextptr++ = *inptr++;
+ for (i = 1; i < imagelength; ++i) {
+ tmpptr = thisline;
+ thisline = nextline;
+ nextline = tmpptr;
+ lastline = (i == imax);
+ if (TIFFReadScanline(in, inputline, i, 0) <= 0)
+ break;
+ inptr = inputline;
+ nextptr = nextline;
+ for (j = 0; j < imagewidth; ++j)
+ *nextptr++ = *inptr++;
+ thisptr = thisline;
+ nextptr = nextline;
+ _TIFFmemset(outptr = outline, 0, outlinesize);
+ bit = 0x80;
+ for (j = 0; j < imagewidth; ++j) {
+ register int v;
+
+ lastpixel = (j == jmax);
+ v = *thisptr++;
+ if (v < 0)
+ v = 0;
+ else if (v > 255)
+ v = 255;
+ if (v > threshold) {
+ *outptr |= bit;
+ v -= 255;
+ }
+ bit >>= 1;
+ if (bit == 0) {
+ outptr++;
+ bit = 0x80;
+ }
+ if (!lastpixel)
+ thisptr[0] += v * 7 / 16;
+ if (!lastline) {
+ if (j != 0)
+ nextptr[-1] += v * 3 / 16;
+ *nextptr++ += v * 5 / 16;
+ if (!lastpixel)
+ nextptr[0] += v / 16;
+ }
+ }
+ if (TIFFWriteScanline(out, outline, i-1, 0) < 0)
+ break;
+ }
+ _TIFFfree(inputline);
+ _TIFFfree(thisline);
+ _TIFFfree(nextline);
+ _TIFFfree(outline);
+}
+
+static uint16 compression = COMPRESSION_PACKBITS;
+static uint16 predictor = 0;
+static uint32 group3options = 0;
+
+static void
+processG3Options(char* cp)
+{
+ if ((cp = strchr(cp, ':'))) {
+ do {
+ cp++;
+ if (strneq(cp, "1d", 2))
+ group3options &= ~GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "2d", 2))
+ group3options |= GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "fill", 4))
+ group3options |= GROUP3OPT_FILLBITS;
+ else
+ usage();
+ } while ((cp = strchr(cp, ':')));
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "g3", 2)) {
+ processG3Options(opt);
+ compression = COMPRESSION_CCITTFAX3;
+ } else if (streq(opt, "g4"))
+ compression = COMPRESSION_CCITTFAX4;
+ else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *in, *out;
+ uint16 samplesperpixel, bitspersample = 1, shortv;
+ float floatv;
+ char thing[1024];
+ uint32 rowsperstrip = (uint32) -1;
+ int onestrip = 0;
+ uint16 fillorder = 0;
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "c:f:r:t:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'f': /* fill order */
+ if (streq(optarg, "lsb2msb"))
+ fillorder = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ fillorder = FILLORDER_MSB2LSB;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ onestrip = 0;
+ break;
+ case 't':
+ threshold = atoi(optarg);
+ if (threshold < 0)
+ threshold = 0;
+ else if (threshold > 255)
+ threshold = 255;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage();
+ in = TIFFOpen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (samplesperpixel != 1) {
+ fprintf(stderr, "%s: Not a b&w image.\n", argv[0]);
+ return (-1);
+ }
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8) {
+ fprintf(stderr,
+ " %s: Sorry, only handle 8-bit samples.\n", argv[0]);
+ return (-1);
+ }
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-1);
+ CopyField(TIFFTAG_IMAGEWIDTH, imagewidth);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, imagelength-1);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ if (fillorder)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ else
+ CopyField(TIFFTAG_FILLORDER, shortv);
+ sprintf(thing, "Dithered B&W version of %s", argv[optind]);
+ TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, thing);
+ CopyField(TIFFTAG_PHOTOMETRIC, shortv);
+ CopyField(TIFFTAG_ORIENTATION, shortv);
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ if (onestrip)
+ rowsperstrip = imagelength-1;
+ else
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ switch (compression) {
+ case COMPRESSION_CCITTFAX3:
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, group3options);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ fsdither(in, out);
+ TIFFClose(in);
+ TIFFClose(out);
+ return (0);
+}
+
+char* stuff[] = {
+"usage: tiffdither [options] input.tif output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+" -f lsb2msb force lsb-to-msb FillOrder for output",
+" -f msb2lsb force msb-to-lsb FillOrder for output",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c g3[:opts] compress output with CCITT Group 3 encoding",
+" -c g4 compress output with CCITT Group 4 encoding",
+" -c none use no compression algorithm on output",
+"",
+"Group 3 options:",
+" 1d use default CCITT Group 3 1D-encoding",
+" 2d use optional CCITT Group 3 2D-encoding",
+" fill byte-align EOL codes",
+"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffdump.c b/tiff/tools/tiffdump.c
new file mode 100644
index 0000000..5161189
--- /dev/null
+++ b/tiff/tools/tiffdump.c
@@ -0,0 +1,785 @@
+/* $Id: tiffdump.c,v 1.13.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+char* appname;
+char* curfile;
+int swabflag;
+int bigendian;
+int typeshift[14]; /* data type shift counts */
+long typemask[14]; /* data type masks */
+uint32 maxitems = 24; /* maximum indirect data items to print */
+
+char* bytefmt = "%s%#02x"; /* BYTE */
+char* sbytefmt = "%s%d"; /* SBYTE */
+char* shortfmt = "%s%u"; /* SHORT */
+char* sshortfmt = "%s%d"; /* SSHORT */
+char* longfmt = "%s%lu"; /* LONG */
+char* slongfmt = "%s%ld"; /* SLONG */
+char* rationalfmt = "%s%g"; /* RATIONAL */
+char* srationalfmt = "%s%g"; /* SRATIONAL */
+char* floatfmt = "%s%g"; /* FLOAT */
+char* doublefmt = "%s%g"; /* DOUBLE */
+char* ifdfmt = "%s%#04x"; /* IFD offset */
+
+static void dump(int, off_t);
+extern int optind;
+extern char* optarg;
+
+void
+usage()
+{
+ fprintf(stderr, "usage: %s [-h] [-o offset] [-m maxitems] file.tif ...\n", appname);
+ exit(-1);
+}
+
+int
+main(int argc, char* argv[])
+{
+ int one = 1, fd;
+ int multiplefiles = (argc > 1);
+ int c;
+ uint32 diroff = (uint32) 0;
+ bigendian = (*(char *)&one == 0);
+
+ appname = argv[0];
+ while ((c = getopt(argc, argv, "m:o:h")) != -1) {
+ switch (c) {
+ case 'h': /* print values in hex */
+ shortfmt = "%s%#x";
+ sshortfmt = "%s%#x";
+ longfmt = "%s%#lx";
+ slongfmt = "%s%#lx";
+ break;
+ case 'o':
+ diroff = (uint32) strtoul(optarg, NULL, 0);
+ break;
+ case 'm':
+ maxitems = strtoul(optarg, NULL, 0);
+ break;
+ default:
+ usage();
+ }
+ }
+ if (optind >= argc)
+ usage();
+ for (; optind < argc; optind++) {
+ fd = open(argv[optind], O_RDONLY|O_BINARY, 0);
+ if (fd < 0) {
+ perror(argv[0]);
+ return (-1);
+ }
+ if (multiplefiles)
+ printf("%s:\n", argv[optind]);
+ curfile = argv[optind];
+ swabflag = 0;
+ dump(fd, diroff);
+ close(fd);
+ }
+ return (0);
+}
+
+static TIFFHeader hdr;
+
+#define ord(e) ((int)e)
+
+/*
+ * Initialize shift & mask tables and byte
+ * swapping state according to the file
+ * byte order.
+ */
+static void
+InitByteOrder(int magic)
+{
+ typemask[0] = 0;
+ typemask[ord(TIFF_BYTE)] = 0xff;
+ typemask[ord(TIFF_SBYTE)] = 0xff;
+ typemask[ord(TIFF_UNDEFINED)] = 0xff;
+ typemask[ord(TIFF_SHORT)] = 0xffff;
+ typemask[ord(TIFF_SSHORT)] = 0xffff;
+ typemask[ord(TIFF_LONG)] = 0xffffffff;
+ typemask[ord(TIFF_SLONG)] = 0xffffffff;
+ typemask[ord(TIFF_IFD)] = 0xffffffff;
+ typemask[ord(TIFF_RATIONAL)] = 0xffffffff;
+ typemask[ord(TIFF_SRATIONAL)] = 0xffffffff;
+ typemask[ord(TIFF_FLOAT)] = 0xffffffff;
+ typemask[ord(TIFF_DOUBLE)] = 0xffffffff;
+ typeshift[0] = 0;
+ typeshift[ord(TIFF_LONG)] = 0;
+ typeshift[ord(TIFF_SLONG)] = 0;
+ typeshift[ord(TIFF_IFD)] = 0;
+ typeshift[ord(TIFF_RATIONAL)] = 0;
+ typeshift[ord(TIFF_SRATIONAL)] = 0;
+ typeshift[ord(TIFF_FLOAT)] = 0;
+ typeshift[ord(TIFF_DOUBLE)] = 0;
+ if (magic == TIFF_BIGENDIAN || magic == MDI_BIGENDIAN) {
+ typeshift[ord(TIFF_BYTE)] = 24;
+ typeshift[ord(TIFF_SBYTE)] = 24;
+ typeshift[ord(TIFF_SHORT)] = 16;
+ typeshift[ord(TIFF_SSHORT)] = 16;
+ swabflag = !bigendian;
+ } else {
+ typeshift[ord(TIFF_BYTE)] = 0;
+ typeshift[ord(TIFF_SBYTE)] = 0;
+ typeshift[ord(TIFF_SHORT)] = 0;
+ typeshift[ord(TIFF_SSHORT)] = 0;
+ swabflag = bigendian;
+ }
+}
+
+static off_t ReadDirectory(int, unsigned, off_t);
+static void ReadError(char*);
+static void Error(const char*, ...);
+static void Fatal(const char*, ...);
+
+static void
+dump(int fd, off_t diroff)
+{
+ unsigned i;
+
+ lseek(fd, (off_t) 0, 0);
+ if (read(fd, (char*) &hdr, sizeof (hdr)) != sizeof (hdr))
+ ReadError("TIFF header");
+ /*
+ * Setup the byte order handling.
+ */
+ if (hdr.tiff_magic != TIFF_BIGENDIAN && hdr.tiff_magic != TIFF_LITTLEENDIAN &&
+#if HOST_BIGENDIAN
+ // MDI is sensitive to the host byte order, unlike TIFF
+ MDI_BIGENDIAN != hdr.tiff_magic )
+#else
+ MDI_LITTLEENDIAN != hdr.tiff_magic )
+#endif
+ Fatal("Not a TIFF or MDI file, bad magic number %u (%#x)",
+ hdr.tiff_magic, hdr.tiff_magic);
+ InitByteOrder(hdr.tiff_magic);
+ /*
+ * Swap header if required.
+ */
+ if (swabflag) {
+ TIFFSwabShort(&hdr.tiff_version);
+ TIFFSwabLong(&hdr.tiff_diroff);
+ }
+ /*
+ * Now check version (if needed, it's been byte-swapped).
+ * Note that this isn't actually a version number, it's a
+ * magic number that doesn't change (stupid).
+ */
+ if (hdr.tiff_version != TIFF_VERSION)
+ Fatal("Not a TIFF file, bad version number %u (%#x)",
+ hdr.tiff_version, hdr.tiff_version);
+ printf("Magic: %#x <%s-endian> Version: %#x\n",
+ hdr.tiff_magic,
+ hdr.tiff_magic == TIFF_BIGENDIAN ? "big" : "little",
+ hdr.tiff_version);
+ if (diroff == 0)
+ diroff = hdr.tiff_diroff;
+ for (i = 0; diroff != 0; i++) {
+ if (i > 0)
+ putchar('\n');
+ diroff = ReadDirectory(fd, i, diroff);
+ }
+}
+
+static int datawidth[] = {
+ 0, /* nothing */
+ 1, /* TIFF_BYTE */
+ 1, /* TIFF_ASCII */
+ 2, /* TIFF_SHORT */
+ 4, /* TIFF_LONG */
+ 8, /* TIFF_RATIONAL */
+ 1, /* TIFF_SBYTE */
+ 1, /* TIFF_UNDEFINED */
+ 2, /* TIFF_SSHORT */
+ 4, /* TIFF_SLONG */
+ 8, /* TIFF_SRATIONAL */
+ 4, /* TIFF_FLOAT */
+ 8, /* TIFF_DOUBLE */
+ 4 /* TIFF_IFD */
+};
+#define NWIDTHS (sizeof (datawidth) / sizeof (datawidth[0]))
+static int TIFFFetchData(int, TIFFDirEntry*, void*);
+static void PrintTag(FILE*, uint16);
+static void PrintType(FILE*, uint16);
+static void PrintData(FILE*, uint16, uint32, unsigned char*);
+static void PrintByte(FILE*, const char*, TIFFDirEntry*);
+static void PrintShort(FILE*, const char*, TIFFDirEntry*);
+static void PrintLong(FILE*, const char*, TIFFDirEntry*);
+
+/*
+ * Read the next TIFF directory from a file
+ * and convert it to the internal format.
+ * We read directories sequentially.
+ */
+static off_t
+ReadDirectory(int fd, unsigned ix, off_t off)
+{
+ register TIFFDirEntry *dp;
+ register unsigned int n;
+ TIFFDirEntry *dir = 0;
+ uint16 dircount;
+ int space;
+ uint32 nextdiroff = 0;
+
+ if (off == 0) /* no more directories */
+ goto done;
+ if (lseek(fd, (off_t) off, 0) != off) {
+ Fatal("Seek error accessing TIFF directory");
+ goto done;
+ }
+ if (read(fd, (char*) &dircount, sizeof (uint16)) != sizeof (uint16)) {
+ ReadError("directory count");
+ goto done;
+ }
+ if (swabflag)
+ TIFFSwabShort(&dircount);
+ dir = (TIFFDirEntry *)_TIFFmalloc(dircount * sizeof (TIFFDirEntry));
+ if (dir == NULL) {
+ Fatal("No space for TIFF directory");
+ goto done;
+ }
+ n = read(fd, (char*) dir, dircount*sizeof (*dp));
+ if (n != dircount*sizeof (*dp)) {
+ n /= sizeof (*dp);
+ Error(
+ "Could only read %u of %u entries in directory at offset %#lx",
+ n, dircount, (unsigned long) off);
+ dircount = n;
+ }
+ if (read(fd, (char*) &nextdiroff, sizeof (uint32)) != sizeof (uint32))
+ nextdiroff = 0;
+ if (swabflag)
+ TIFFSwabLong(&nextdiroff);
+ printf("Directory %u: offset %lu (%#lx) next %lu (%#lx)\n", ix,
+ (unsigned long)off, (unsigned long)off,
+ (unsigned long)nextdiroff, (unsigned long)nextdiroff);
+ for (dp = dir, n = dircount; n > 0; n--, dp++) {
+ if (swabflag) {
+ TIFFSwabArrayOfShort(&dp->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dp->tdir_count, 2);
+ }
+ PrintTag(stdout, dp->tdir_tag);
+ putchar(' ');
+ PrintType(stdout, dp->tdir_type);
+ putchar(' ');
+ printf("%lu<", (unsigned long) dp->tdir_count);
+ if (dp->tdir_type >= NWIDTHS) {
+ printf(">\n");
+ continue;
+ }
+ space = dp->tdir_count * datawidth[dp->tdir_type];
+ if (space <= 0) {
+ printf(">\n");
+ Error("Invalid count for tag %u", dp->tdir_tag);
+ continue;
+ }
+ if (space <= 4) {
+ switch (dp->tdir_type) {
+ case TIFF_FLOAT:
+ case TIFF_UNDEFINED:
+ case TIFF_ASCII: {
+ unsigned char data[4];
+ _TIFFmemcpy(data, &dp->tdir_offset, 4);
+ if (swabflag)
+ TIFFSwabLong((uint32*) data);
+ PrintData(stdout,
+ dp->tdir_type, dp->tdir_count, data);
+ break;
+ }
+ case TIFF_BYTE:
+ PrintByte(stdout, bytefmt, dp);
+ break;
+ case TIFF_SBYTE:
+ PrintByte(stdout, sbytefmt, dp);
+ break;
+ case TIFF_SHORT:
+ PrintShort(stdout, shortfmt, dp);
+ break;
+ case TIFF_SSHORT:
+ PrintShort(stdout, sshortfmt, dp);
+ break;
+ case TIFF_LONG:
+ PrintLong(stdout, longfmt, dp);
+ break;
+ case TIFF_SLONG:
+ PrintLong(stdout, slongfmt, dp);
+ break;
+ case TIFF_IFD:
+ PrintLong(stdout, ifdfmt, dp);
+ break;
+ }
+ } else {
+ unsigned char *data = (unsigned char *)_TIFFmalloc(space);
+ if (data) {
+ if (TIFFFetchData(fd, dp, data)) {
+ if (dp->tdir_count > maxitems) {
+ PrintData(stdout, dp->tdir_type,
+ maxitems, data);
+ printf(" ...");
+ } else
+ PrintData(stdout, dp->tdir_type,
+ dp->tdir_count, data);
+ }
+ _TIFFfree(data);
+ } else
+ Error("No space for data for tag %u",
+ dp->tdir_tag);
+ }
+ printf(">\n");
+ }
+done:
+ if (dir)
+ _TIFFfree((char *)dir);
+ return (nextdiroff);
+}
+
+static struct tagname {
+ uint16 tag;
+ char* name;
+} tagnames[] = {
+ { TIFFTAG_SUBFILETYPE, "SubFileType" },
+ { TIFFTAG_OSUBFILETYPE, "OldSubFileType" },
+ { TIFFTAG_IMAGEWIDTH, "ImageWidth" },
+ { TIFFTAG_IMAGELENGTH, "ImageLength" },
+ { TIFFTAG_BITSPERSAMPLE, "BitsPerSample" },
+ { TIFFTAG_COMPRESSION, "Compression" },
+ { TIFFTAG_PHOTOMETRIC, "Photometric" },
+ { TIFFTAG_THRESHHOLDING, "Threshholding" },
+ { TIFFTAG_CELLWIDTH, "CellWidth" },
+ { TIFFTAG_CELLLENGTH, "CellLength" },
+ { TIFFTAG_FILLORDER, "FillOrder" },
+ { TIFFTAG_DOCUMENTNAME, "DocumentName" },
+ { TIFFTAG_IMAGEDESCRIPTION, "ImageDescription" },
+ { TIFFTAG_MAKE, "Make" },
+ { TIFFTAG_MODEL, "Model" },
+ { TIFFTAG_STRIPOFFSETS, "StripOffsets" },
+ { TIFFTAG_ORIENTATION, "Orientation" },
+ { TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel" },
+ { TIFFTAG_ROWSPERSTRIP, "RowsPerStrip" },
+ { TIFFTAG_STRIPBYTECOUNTS, "StripByteCounts" },
+ { TIFFTAG_MINSAMPLEVALUE, "MinSampleValue" },
+ { TIFFTAG_MAXSAMPLEVALUE, "MaxSampleValue" },
+ { TIFFTAG_XRESOLUTION, "XResolution" },
+ { TIFFTAG_YRESOLUTION, "YResolution" },
+ { TIFFTAG_PLANARCONFIG, "PlanarConfig" },
+ { TIFFTAG_PAGENAME, "PageName" },
+ { TIFFTAG_XPOSITION, "XPosition" },
+ { TIFFTAG_YPOSITION, "YPosition" },
+ { TIFFTAG_FREEOFFSETS, "FreeOffsets" },
+ { TIFFTAG_FREEBYTECOUNTS, "FreeByteCounts" },
+ { TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit" },
+ { TIFFTAG_GRAYRESPONSECURVE,"GrayResponseCurve" },
+ { TIFFTAG_GROUP3OPTIONS, "Group3Options" },
+ { TIFFTAG_GROUP4OPTIONS, "Group4Options" },
+ { TIFFTAG_RESOLUTIONUNIT, "ResolutionUnit" },
+ { TIFFTAG_PAGENUMBER, "PageNumber" },
+ { TIFFTAG_COLORRESPONSEUNIT,"ColorResponseUnit" },
+ { TIFFTAG_TRANSFERFUNCTION, "TransferFunction" },
+ { TIFFTAG_SOFTWARE, "Software" },
+ { TIFFTAG_DATETIME, "DateTime" },
+ { TIFFTAG_ARTIST, "Artist" },
+ { TIFFTAG_HOSTCOMPUTER, "HostComputer" },
+ { TIFFTAG_PREDICTOR, "Predictor" },
+ { TIFFTAG_WHITEPOINT, "Whitepoint" },
+ { TIFFTAG_PRIMARYCHROMATICITIES,"PrimaryChromaticities" },
+ { TIFFTAG_COLORMAP, "Colormap" },
+ { TIFFTAG_HALFTONEHINTS, "HalftoneHints" },
+ { TIFFTAG_TILEWIDTH, "TileWidth" },
+ { TIFFTAG_TILELENGTH, "TileLength" },
+ { TIFFTAG_TILEOFFSETS, "TileOffsets" },
+ { TIFFTAG_TILEBYTECOUNTS, "TileByteCounts" },
+ { TIFFTAG_BADFAXLINES, "BadFaxLines" },
+ { TIFFTAG_CLEANFAXDATA, "CleanFaxData" },
+ { TIFFTAG_CONSECUTIVEBADFAXLINES, "ConsecutiveBadFaxLines" },
+ { TIFFTAG_SUBIFD, "SubIFD" },
+ { TIFFTAG_INKSET, "InkSet" },
+ { TIFFTAG_INKNAMES, "InkNames" },
+ { TIFFTAG_NUMBEROFINKS, "NumberOfInks" },
+ { TIFFTAG_DOTRANGE, "DotRange" },
+ { TIFFTAG_TARGETPRINTER, "TargetPrinter" },
+ { TIFFTAG_EXTRASAMPLES, "ExtraSamples" },
+ { TIFFTAG_SAMPLEFORMAT, "SampleFormat" },
+ { TIFFTAG_SMINSAMPLEVALUE, "SMinSampleValue" },
+ { TIFFTAG_SMAXSAMPLEVALUE, "SMaxSampleValue" },
+ { TIFFTAG_JPEGPROC, "JPEGProcessingMode" },
+ { TIFFTAG_JPEGIFOFFSET, "JPEGInterchangeFormat" },
+ { TIFFTAG_JPEGIFBYTECOUNT, "JPEGInterchangeFormatLength" },
+ { TIFFTAG_JPEGRESTARTINTERVAL,"JPEGRestartInterval" },
+ { TIFFTAG_JPEGLOSSLESSPREDICTORS,"JPEGLosslessPredictors" },
+ { TIFFTAG_JPEGPOINTTRANSFORM,"JPEGPointTransform" },
+ { TIFFTAG_JPEGTABLES, "JPEGTables" },
+ { TIFFTAG_JPEGQTABLES, "JPEGQTables" },
+ { TIFFTAG_JPEGDCTABLES, "JPEGDCTables" },
+ { TIFFTAG_JPEGACTABLES, "JPEGACTables" },
+ { TIFFTAG_YCBCRCOEFFICIENTS,"YCbCrCoefficients" },
+ { TIFFTAG_YCBCRSUBSAMPLING, "YCbCrSubsampling" },
+ { TIFFTAG_YCBCRPOSITIONING, "YCbCrPositioning" },
+ { TIFFTAG_REFERENCEBLACKWHITE, "ReferenceBlackWhite" },
+ { TIFFTAG_REFPTS, "IgReferencePoints (Island Graphics)" },
+ { TIFFTAG_REGIONTACKPOINT, "IgRegionTackPoint (Island Graphics)" },
+ { TIFFTAG_REGIONWARPCORNERS,"IgRegionWarpCorners (Island Graphics)" },
+ { TIFFTAG_REGIONAFFINE, "IgRegionAffine (Island Graphics)" },
+ { TIFFTAG_MATTEING, "OBSOLETE Matteing (Silicon Graphics)" },
+ { TIFFTAG_DATATYPE, "OBSOLETE DataType (Silicon Graphics)" },
+ { TIFFTAG_IMAGEDEPTH, "ImageDepth (Silicon Graphics)" },
+ { TIFFTAG_TILEDEPTH, "TileDepth (Silicon Graphics)" },
+ { 32768, "OLD BOGUS Matteing tag" },
+ { TIFFTAG_COPYRIGHT, "Copyright" },
+ { TIFFTAG_ICCPROFILE, "ICC Profile" },
+ { TIFFTAG_JBIGOPTIONS, "JBIG Options" },
+ { TIFFTAG_STONITS, "StoNits" },
+};
+#define NTAGS (sizeof (tagnames) / sizeof (tagnames[0]))
+
+static void
+PrintTag(FILE* fd, uint16 tag)
+{
+ register struct tagname *tp;
+
+ for (tp = tagnames; tp < &tagnames[NTAGS]; tp++)
+ if (tp->tag == tag) {
+ fprintf(fd, "%s (%u)", tp->name, tag);
+ return;
+ }
+ fprintf(fd, "%u (%#x)", tag, tag);
+}
+
+static void
+PrintType(FILE* fd, uint16 type)
+{
+ static char *typenames[] = {
+ "0",
+ "BYTE",
+ "ASCII",
+ "SHORT",
+ "LONG",
+ "RATIONAL",
+ "SBYTE",
+ "UNDEFINED",
+ "SSHORT",
+ "SLONG",
+ "SRATIONAL",
+ "FLOAT",
+ "DOUBLE"
+ };
+#define NTYPES (sizeof (typenames) / sizeof (typenames[0]))
+
+ if (type < NTYPES)
+ fprintf(fd, "%s (%u)", typenames[type], type);
+ else
+ fprintf(fd, "%u (%#x)", type, type);
+}
+#undef NTYPES
+
+static void
+PrintByte(FILE* fd, const char* fmt, TIFFDirEntry* dp)
+{
+ char* sep = "";
+
+ if (hdr.tiff_magic == TIFF_BIGENDIAN) {
+ switch ((int)dp->tdir_count) {
+ case 4: fprintf(fd, fmt, sep, dp->tdir_offset&0xff);
+ sep = " ";
+ case 3: fprintf(fd, fmt, sep, (dp->tdir_offset>>8)&0xff);
+ sep = " ";
+ case 2: fprintf(fd, fmt, sep, (dp->tdir_offset>>16)&0xff);
+ sep = " ";
+ case 1: fprintf(fd, fmt, sep, dp->tdir_offset>>24);
+ }
+ } else {
+ switch ((int)dp->tdir_count) {
+ case 4: fprintf(fd, fmt, sep, dp->tdir_offset>>24);
+ sep = " ";
+ case 3: fprintf(fd, fmt, sep, (dp->tdir_offset>>16)&0xff);
+ sep = " ";
+ case 2: fprintf(fd, fmt, sep, (dp->tdir_offset>>8)&0xff);
+ sep = " ";
+ case 1: fprintf(fd, fmt, sep, dp->tdir_offset&0xff);
+ }
+ }
+}
+
+static void
+PrintShort(FILE* fd, const char* fmt, TIFFDirEntry* dp)
+{
+ char *sep = "";
+
+ if (hdr.tiff_magic == TIFF_BIGENDIAN) {
+ switch (dp->tdir_count) {
+ case 2: fprintf(fd, fmt, sep, dp->tdir_offset&0xffff);
+ sep = " ";
+ case 1: fprintf(fd, fmt, sep, dp->tdir_offset>>16);
+ }
+ } else {
+ switch (dp->tdir_count) {
+ case 2: fprintf(fd, fmt, sep, dp->tdir_offset>>16);
+ sep = " ";
+ case 1: fprintf(fd, fmt, sep, dp->tdir_offset&0xffff);
+ }
+ }
+}
+
+static void
+PrintLong(FILE* fd, const char* fmt, TIFFDirEntry* dp)
+{
+ fprintf(fd, fmt, "", (long) dp->tdir_offset);
+}
+
+#include <ctype.h>
+
+static void
+PrintASCII(FILE* fd, uint32 cc, const unsigned char* cp)
+{
+ for (; cc > 0; cc--, cp++) {
+ const char* tp;
+
+ if (isprint(*cp)) {
+ fputc(*cp, fd);
+ continue;
+ }
+ for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++)
+ if (*tp++ == *cp)
+ break;
+ if (*tp)
+ fprintf(fd, "\\%c", *tp);
+ else if (*cp)
+ fprintf(fd, "\\%03o", *cp);
+ else
+ fprintf(fd, "\\0");
+ }
+}
+
+static void
+PrintData(FILE* fd, uint16 type, uint32 count, unsigned char* data)
+{
+ char* sep = "";
+
+ switch (type) {
+ case TIFF_BYTE:
+ while (count-- > 0)
+ fprintf(fd, bytefmt, sep, *data++), sep = " ";
+ break;
+ case TIFF_SBYTE:
+ while (count-- > 0)
+ fprintf(fd, sbytefmt, sep, *(char *)data++), sep = " ";
+ break;
+ case TIFF_UNDEFINED:
+ while (count-- > 0)
+ fprintf(fd, bytefmt, sep, *data++), sep = " ";
+ break;
+ case TIFF_ASCII:
+ PrintASCII(fd, count, data);
+ break;
+ case TIFF_SHORT: {
+ uint16 *wp = (uint16*)data;
+ while (count-- > 0)
+ fprintf(fd, shortfmt, sep, *wp++), sep = " ";
+ break;
+ }
+ case TIFF_SSHORT: {
+ int16 *wp = (int16*)data;
+ while (count-- > 0)
+ fprintf(fd, sshortfmt, sep, *wp++), sep = " ";
+ break;
+ }
+ case TIFF_LONG: {
+ uint32 *lp = (uint32*)data;
+ while (count-- > 0) {
+ fprintf(fd, longfmt, sep, (unsigned long) *lp++);
+ sep = " ";
+ }
+ break;
+ }
+ case TIFF_SLONG: {
+ int32 *lp = (int32*)data;
+ while (count-- > 0)
+ fprintf(fd, slongfmt, sep, (long) *lp++), sep = " ";
+ break;
+ }
+ case TIFF_RATIONAL: {
+ uint32 *lp = (uint32*)data;
+ while (count-- > 0) {
+ if (lp[1] == 0)
+ fprintf(fd, "%sNan (%lu/%lu)", sep,
+ (unsigned long) lp[0],
+ (unsigned long) lp[1]);
+ else
+ fprintf(fd, rationalfmt, sep,
+ (double)lp[0] / (double)lp[1]);
+ sep = " ";
+ lp += 2;
+ }
+ break;
+ }
+ case TIFF_SRATIONAL: {
+ int32 *lp = (int32*)data;
+ while (count-- > 0) {
+ if (lp[1] == 0)
+ fprintf(fd, "%sNan (%ld/%ld)", sep,
+ (long) lp[0], (long) lp[1]);
+ else
+ fprintf(fd, srationalfmt, sep,
+ (double)lp[0] / (double)lp[1]);
+ sep = " ";
+ lp += 2;
+ }
+ break;
+ }
+ case TIFF_FLOAT: {
+ float *fp = (float *)data;
+ while (count-- > 0)
+ fprintf(fd, floatfmt, sep, *fp++), sep = " ";
+ break;
+ }
+ case TIFF_DOUBLE: {
+ double *dp = (double *)data;
+ while (count-- > 0)
+ fprintf(fd, doublefmt, sep, *dp++), sep = " ";
+ break;
+ }
+ case TIFF_IFD: {
+ uint32 *lp = (uint32*)data;
+ while (count-- > 0) {
+ fprintf(fd, ifdfmt, sep, (unsigned long) *lp++);
+ sep = " ";
+ }
+ break;
+ }
+ }
+}
+
+/*
+ * Fetch a contiguous directory item.
+ */
+static int
+TIFFFetchData(int fd, TIFFDirEntry* dir, void* cp)
+{
+ int cc, w;
+
+ w = (dir->tdir_type < NWIDTHS ? datawidth[dir->tdir_type] : 0);
+ cc = dir->tdir_count * w;
+ if (lseek(fd, (off_t)dir->tdir_offset, 0) != (off_t)-1
+ && read(fd, cp, cc) != -1) {
+ if (swabflag) {
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*) cp,
+ dir->tdir_count);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ case TIFF_IFD:
+ TIFFSwabArrayOfLong((uint32*) cp,
+ dir->tdir_count);
+ break;
+ case TIFF_RATIONAL:
+ TIFFSwabArrayOfLong((uint32*) cp,
+ 2*dir->tdir_count);
+ break;
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*) cp,
+ dir->tdir_count);
+ break;
+ }
+ }
+ return (cc);
+ }
+ Error("Error while reading data for tag %u", dir->tdir_tag);
+ return (0);
+}
+
+static void
+ReadError(char* what)
+{
+ Fatal("Error while reading %s", what);
+}
+
+#include <stdarg.h>
+
+static void
+vError(FILE* fd, const char* fmt, va_list ap)
+{
+ fprintf(fd, "%s: ", curfile);
+ vfprintf(fd, fmt, ap);
+ fprintf(fd, ".\n");
+}
+
+static void
+Error(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vError(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static void
+Fatal(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vError(stderr, fmt, ap);
+ va_end(ap);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffgt.c b/tiff/tools/tiffgt.c
new file mode 100644
index 0000000..ea9c3b1
--- /dev/null
+++ b/tiff/tools/tiffgt.c
@@ -0,0 +1,462 @@
+/* $Id: tiffgt.c,v 1.7.2.2 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ * Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if HAVE_APPLE_OPENGL_FRAMEWORK
+# include <OpenGL/gl.h>
+# include <GLUT/glut.h>
+#else
+# include <GL/gl.h>
+# include <GL/glut.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+static uint32 width = 0, height = 0; /* window width & height */
+static uint32* raster = NULL; /* displayable image */
+static TIFFRGBAImage img;
+static int order0 = 0, order;
+static uint16 photo0 = (uint16) -1, photo;
+static int stoponerr = 0; /* stop on read error */
+static int verbose = 0;
+#define TITLE_LENGTH 1024
+static char title[TITLE_LENGTH]; /* window title line */
+static uint32 xmax, ymax;
+static char** filelist = NULL;
+static int fileindex;
+static int filenum;
+static TIFFErrorHandler oerror;
+static TIFFErrorHandler owarning;
+
+static void cleanup_and_exit(void);
+static int initImage(void);
+static int prevImage(void);
+static int nextImage(void);
+static void setWindowSize(void);
+static void usage(void);
+static uint16 photoArg(const char*);
+static void raster_draw(void);
+static void raster_reshape(int, int);
+static void raster_keys(unsigned char, int, int);
+static void raster_special(int, int, int);
+
+extern char* optarg;
+extern int optind;
+static TIFF* tif = NULL;
+
+int
+main(int argc, char* argv[])
+{
+ int c;
+ int dirnum = -1;
+ uint32 diroff = 0;
+
+ oerror = TIFFSetErrorHandler(NULL);
+ owarning = TIFFSetWarningHandler(NULL);
+ while ((c = getopt(argc, argv, "d:o:p:eflmsvw?")) != -1)
+ switch (c) {
+ case 'd':
+ dirnum = atoi(optarg);
+ break;
+ case 'e':
+ oerror = TIFFSetErrorHandler(oerror);
+ break;
+ case 'l':
+ order0 = FILLORDER_LSB2MSB;
+ break;
+ case 'm':
+ order0 = FILLORDER_MSB2LSB;
+ break;
+ case 'o':
+ diroff = strtoul(optarg, NULL, 0);
+ break;
+ case 'p':
+ photo0 = photoArg(optarg);
+ break;
+ case 's':
+ stoponerr = 1;
+ break;
+ case 'w':
+ owarning = TIFFSetWarningHandler(owarning);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ filenum = argc - optind;
+ if ( filenum < 1)
+ usage();
+
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
+
+ /*
+ * Get the screen size
+ */
+ xmax = glutGet(GLUT_SCREEN_WIDTH);
+ ymax = glutGet(GLUT_SCREEN_HEIGHT);
+
+ /*
+ * Use 90% of the screen size
+ */
+ xmax = xmax - xmax / 10.0;
+ ymax = ymax - ymax / 10.0;
+
+ filelist = (char **) _TIFFmalloc(filenum * sizeof(char*));
+ if (!filelist) {
+ TIFFError(argv[0], "Can not allocate space for the file list.");
+ return 1;
+ }
+ _TIFFmemcpy(filelist, argv + optind, filenum * sizeof(char*));
+ fileindex = -1;
+ if (nextImage() < 0) {
+ _TIFFfree(filelist);
+ return 2;
+ }
+ /*
+ * Set initial directory if user-specified
+ * file was opened successfully.
+ */
+ if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum))
+ TIFFError(argv[0], "Error, seeking to directory %d", dirnum);
+ if (diroff != 0 && !TIFFSetSubDirectory(tif, diroff))
+ TIFFError(argv[0], "Error, setting subdirectory at %#x", diroff);
+ order = order0;
+ photo = photo0;
+ if (initImage() < 0){
+ _TIFFfree(filelist);
+ return 3;
+ }
+ /*
+ * Create a new window or reconfigure an existing
+ * one to suit the image to be displayed.
+ */
+ glutInitWindowSize(width, height);
+ snprintf(title, TITLE_LENGTH - 1, "%s [%u]", filelist[fileindex],
+ (unsigned int) TIFFCurrentDirectory(tif));
+ glutCreateWindow(title);
+ glutDisplayFunc(raster_draw);
+ glutReshapeFunc(raster_reshape);
+ glutKeyboardFunc(raster_keys);
+ glutSpecialFunc(raster_special);
+ glutMainLoop();
+
+ cleanup_and_exit();
+ return 0;
+}
+
+static void
+cleanup_and_exit(void)
+{
+ TIFFRGBAImageEnd(&img);
+ if (filelist != NULL)
+ _TIFFfree(filelist);
+ if (raster != NULL)
+ _TIFFfree(raster);
+ if (tif != NULL)
+ TIFFClose(tif);
+ exit(0);
+}
+
+static int
+initImage(void)
+{
+ uint32 w, h;
+
+ if (order)
+ TIFFSetField(tif, TIFFTAG_FILLORDER, order);
+ if (photo != (uint16) -1)
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photo);
+ if (!TIFFRGBAImageBegin(&img, tif, stoponerr, title)) {
+ TIFFError(filelist[fileindex], "%s", title);
+ TIFFClose(tif);
+ tif = NULL;
+ return -1;
+ }
+
+ /*
+ * Setup the image raster as required.
+ */
+ h = img.height;
+ w = img.width;
+ if (h > ymax) {
+ w = (int)(w * ((float)ymax / h));
+ h = ymax;
+ }
+ if (w > xmax) {
+ h = (int)(h * ((float)xmax / w));
+ w = xmax;
+ }
+
+ if (w != width || h != height) {
+ if (raster != NULL)
+ _TIFFfree(raster), raster = NULL;
+ raster = (uint32*) _TIFFmalloc(img.width * img.height * sizeof (uint32));
+ if (raster == NULL) {
+ width = height = 0;
+ TIFFError(filelist[fileindex], "No space for raster buffer");
+ cleanup_and_exit();
+ }
+ width = w;
+ height = h;
+ }
+ TIFFRGBAImageGet(&img, raster, img.width, img.height);
+#if HOST_BIGENDIAN
+ TIFFSwabArrayOfLong(raster,img.width*img.height);
+#endif
+ return 0;
+}
+
+static int
+prevImage(void)
+{
+ if (fileindex > 0)
+ fileindex--;
+ else if (tif)
+ return fileindex;
+ if (tif)
+ TIFFClose(tif);
+ tif = TIFFOpen(filelist[fileindex], "r");
+ if (tif == NULL)
+ return -1;
+ return fileindex;
+}
+
+static int
+nextImage(void)
+{
+ if (fileindex < filenum - 1)
+ fileindex++;
+ else if (tif)
+ return fileindex;
+ if (tif)
+ TIFFClose(tif);
+ tif = TIFFOpen(filelist[fileindex], "r");
+ if (tif == NULL)
+ return -1;
+ return fileindex;
+}
+
+static void
+setWindowSize(void)
+{
+ glutReshapeWindow(width, height);
+}
+
+static void
+raster_draw(void)
+{
+ glDrawPixels(img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *) raster);
+}
+
+static void
+raster_reshape(int win_w, int win_h)
+{
+ GLfloat xratio = (GLfloat)win_w/img.width;
+ GLfloat yratio = (GLfloat)win_h/img.height;
+ int ratio = (int)(((xratio > yratio)?xratio:yratio) * 100);
+
+ glPixelZoom(xratio, yratio);
+ glViewport(0, 0, win_w, win_h);
+ snprintf(title, 1024, "%s [%u] %d%%", filelist[fileindex],
+ (unsigned int) TIFFCurrentDirectory(tif), ratio);
+ glutSetWindowTitle(title);
+}
+
+static void
+raster_keys(unsigned char key, int x, int y)
+{
+ switch (key) {
+ case 'b': /* photometric MinIsBlack */
+ photo = PHOTOMETRIC_MINISBLACK;
+ initImage();
+ break;
+ case 'l': /* lsb-to-msb FillOrder */
+ order = FILLORDER_LSB2MSB;
+ initImage();
+ break;
+ case 'm': /* msb-to-lsb FillOrder */
+ order = FILLORDER_MSB2LSB;
+ initImage();
+ break;
+ case 'w': /* photometric MinIsWhite */
+ photo = PHOTOMETRIC_MINISWHITE;
+ initImage();
+ break;
+ case 'W': /* toggle warnings */
+ owarning = TIFFSetWarningHandler(owarning);
+ initImage();
+ break;
+ case 'E': /* toggle errors */
+ oerror = TIFFSetErrorHandler(oerror);
+ initImage();
+ break;
+ case 'z': /* reset to defaults */
+ case 'Z':
+ order = order0;
+ photo = photo0;
+ if (owarning == NULL)
+ owarning = TIFFSetWarningHandler(NULL);
+ if (oerror == NULL)
+ oerror = TIFFSetErrorHandler(NULL);
+ initImage();
+ break;
+ case 'q': /* exit */
+ case '\033':
+ cleanup_and_exit();
+ }
+ glutPostRedisplay();
+}
+
+static void
+raster_special(int key, int x, int y)
+{
+ switch (key) {
+ case GLUT_KEY_PAGE_UP: /* previous logical image */
+ if (TIFFCurrentDirectory(tif) > 0) {
+ if (TIFFSetDirectory(tif,
+ TIFFCurrentDirectory(tif)-1)) {
+ initImage();
+ setWindowSize();
+ }
+ } else {
+ TIFFRGBAImageEnd(&img);
+ prevImage();
+ initImage();
+ setWindowSize();
+ }
+ break;
+ case GLUT_KEY_PAGE_DOWN: /* next logical image */
+ if (!TIFFLastDirectory(tif)) {
+ if (TIFFReadDirectory(tif)) {
+ initImage();
+ setWindowSize();
+ }
+ } else {
+ TIFFRGBAImageEnd(&img);
+ nextImage();
+ initImage();
+ setWindowSize();
+ }
+ break;
+ case GLUT_KEY_HOME: /* 1st image in current file */
+ if (TIFFSetDirectory(tif, 0)) {
+ TIFFRGBAImageEnd(&img);
+ initImage();
+ setWindowSize();
+ }
+ break;
+ case GLUT_KEY_END: /* last image in current file */
+ TIFFRGBAImageEnd(&img);
+ while (!TIFFLastDirectory(tif))
+ TIFFReadDirectory(tif);
+ initImage();
+ setWindowSize();
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+
+char* stuff[] = {
+"usage: tiffgt [options] file.tif",
+"where options are:",
+" -c use colormap visual",
+" -d dirnum set initial directory (default is 0)",
+" -e enable display of TIFF error messages",
+" -l force lsb-to-msb FillOrder",
+" -m force msb-to-lsb FillOrder",
+" -o offset set initial directory offset",
+" -p photo override photometric interpretation",
+" -r use fullcolor visual",
+" -s stop decoding on first error (default is ignore errors)",
+" -v enable verbose mode",
+" -w enable display of TIFF warning messages",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+static uint16
+photoArg(const char* arg)
+{
+ if (strcmp(arg, "miniswhite") == 0)
+ return (PHOTOMETRIC_MINISWHITE);
+ else if (strcmp(arg, "minisblack") == 0)
+ return (PHOTOMETRIC_MINISBLACK);
+ else if (strcmp(arg, "rgb") == 0)
+ return (PHOTOMETRIC_RGB);
+ else if (strcmp(arg, "palette") == 0)
+ return (PHOTOMETRIC_PALETTE);
+ else if (strcmp(arg, "mask") == 0)
+ return (PHOTOMETRIC_MASK);
+ else if (strcmp(arg, "separated") == 0)
+ return (PHOTOMETRIC_SEPARATED);
+ else if (strcmp(arg, "ycbcr") == 0)
+ return (PHOTOMETRIC_YCBCR);
+ else if (strcmp(arg, "cielab") == 0)
+ return (PHOTOMETRIC_CIELAB);
+ else if (strcmp(arg, "logl") == 0)
+ return (PHOTOMETRIC_LOGL);
+ else if (strcmp(arg, "logluv") == 0)
+ return (PHOTOMETRIC_LOGLUV);
+ else
+ return ((uint16) -1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffinfo.c b/tiff/tools/tiffinfo.c
new file mode 100644
index 0000000..4d4ae64
--- /dev/null
+++ b/tiff/tools/tiffinfo.c
@@ -0,0 +1,456 @@
+/* $Id: tiffinfo.c,v 1.8.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcasecmp(a,b) == 0)
+
+int showdata = 0; /* show data */
+int rawdata = 0; /* show raw/decoded data */
+int showwords = 0; /* show data as bytes/words */
+int readdata = 0; /* read data in file */
+int stoponerr = 1; /* stop on first read error */
+
+static void usage(void);
+static void tiffinfo(TIFF*, uint16, long);
+
+int
+main(int argc, char* argv[])
+{
+ int dirnum = -1, multiplefiles, c;
+ uint16 order = 0;
+ TIFF* tif;
+ extern int optind;
+ extern char* optarg;
+ long flags = 0;
+ uint32 diroff = 0;
+ int chopstrips = 0; /* disable strip chopping */
+
+ while ((c = getopt(argc, argv, "f:o:cdDSjilmrsvwz0123456789")) != -1)
+ switch (c) {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ dirnum = atoi(&argv[optind-1][1]);
+ break;
+ case 'd':
+ showdata++;
+ /* fall thru... */
+ case 'D':
+ readdata++;
+ break;
+ case 'c':
+ flags |= TIFFPRINT_COLORMAP | TIFFPRINT_CURVES;
+ break;
+ case 'f': /* fill order */
+ if (streq(optarg, "lsb2msb"))
+ order = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ order = FILLORDER_MSB2LSB;
+ else
+ usage();
+ break;
+ case 'i':
+ stoponerr = 0;
+ break;
+ case 'o':
+ diroff = strtoul(optarg, NULL, 0);
+ break;
+ case 'j':
+ flags |= TIFFPRINT_JPEGQTABLES |
+ TIFFPRINT_JPEGACTABLES |
+ TIFFPRINT_JPEGDCTABLES;
+ break;
+ case 'r':
+ rawdata = 1;
+ break;
+ case 's':
+ flags |= TIFFPRINT_STRIPS;
+ break;
+ case 'w':
+ showwords = 1;
+ break;
+ case 'z':
+ chopstrips = 1;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (optind >= argc)
+ usage();
+ multiplefiles = (argc - optind > 1);
+ for (; optind < argc; optind++) {
+ if (multiplefiles)
+ printf("%s:\n", argv[optind]);
+ tif = TIFFOpen(argv[optind], chopstrips ? "rC" : "rc");
+ if (tif != NULL) {
+ if (dirnum != -1) {
+ if (TIFFSetDirectory(tif, (tdir_t) dirnum))
+ tiffinfo(tif, order, flags);
+ } else if (diroff != 0) {
+ if (TIFFSetSubDirectory(tif, diroff))
+ tiffinfo(tif, order, flags);
+ } else {
+ do {
+ uint32 offset;
+
+ tiffinfo(tif, order, flags);
+ if (TIFFGetField(tif, TIFFTAG_EXIFIFD,
+ &offset)) {
+ if (TIFFReadEXIFDirectory(tif, offset))
+ tiffinfo(tif, order, flags);
+ }
+ } while (TIFFReadDirectory(tif));
+ }
+ TIFFClose(tif);
+ }
+ }
+ return (0);
+}
+
+char* stuff[] = {
+"usage: tiffinfo [options] input...",
+"where options are:",
+" -D read data",
+" -i ignore read errors",
+" -c display data for grey/color response curve or colormap",
+" -d display raw/decoded image data",
+" -f lsb2msb force lsb-to-msb FillOrder for input",
+" -f msb2lsb force msb-to-lsb FillOrder for input",
+" -j show JPEG tables",
+" -o offset set initial directory offset",
+" -r read/display raw image data instead of decoded data",
+" -s display strip offsets and byte counts",
+" -w display raw data in words rather than bytes",
+" -z enable strip chopping",
+" -# set initial directory (first directory is # 0)",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+static void
+ShowStrip(tstrip_t strip, unsigned char* pp, uint32 nrow, tsize_t scanline)
+{
+ register tsize_t cc;
+
+ printf("Strip %lu:\n", (unsigned long) strip);
+ while (nrow-- > 0) {
+ for (cc = 0; cc < scanline; cc++) {
+ printf(" %02x", *pp++);
+ if (((cc+1) % 24) == 0)
+ putchar('\n');
+ }
+ putchar('\n');
+ }
+}
+
+void
+TIFFReadContigStripData(TIFF* tif)
+{
+ unsigned char *buf;
+ tsize_t scanline = TIFFScanlineSize(tif);
+
+ buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
+ if (buf) {
+ uint32 row, h;
+ uint32 rowsperstrip = (uint32)-1;
+
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ for (row = 0; row < h; row += rowsperstrip) {
+ uint32 nrow = (row+rowsperstrip > h ?
+ h-row : rowsperstrip);
+ tstrip_t strip = TIFFComputeStrip(tif, row, 0);
+ if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
+ if (stoponerr)
+ break;
+ } else if (showdata)
+ ShowStrip(strip, buf, nrow, scanline);
+ }
+ _TIFFfree(buf);
+ }
+}
+
+void
+TIFFReadSeparateStripData(TIFF* tif)
+{
+ unsigned char *buf;
+ tsize_t scanline = TIFFScanlineSize(tif);
+
+ buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
+ if (buf) {
+ uint32 row, h;
+ uint32 rowsperstrip = (uint32)-1;
+ tsample_t s, samplesperpixel;
+
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ for (row = 0; row < h; row += rowsperstrip) {
+ for (s = 0; s < samplesperpixel; s++) {
+ uint32 nrow = (row+rowsperstrip > h ?
+ h-row : rowsperstrip);
+ tstrip_t strip = TIFFComputeStrip(tif, row, s);
+ if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
+ if (stoponerr)
+ break;
+ } else if (showdata)
+ ShowStrip(strip, buf, nrow, scanline);
+ }
+ }
+ _TIFFfree(buf);
+ }
+}
+
+static void
+ShowTile(uint32 row, uint32 col, tsample_t sample,
+ unsigned char* pp, uint32 nrow, uint32 rowsize)
+{
+ uint32 cc;
+
+ printf("Tile (%lu,%lu", (unsigned long) row, (unsigned long) col);
+ if (sample != (tsample_t) -1)
+ printf(",%u", sample);
+ printf("):\n");
+ while (nrow-- > 0) {
+ for (cc = 0; cc < rowsize; cc++) {
+ printf(" %02x", *pp++);
+ if (((cc+1) % 24) == 0)
+ putchar('\n');
+ }
+ putchar('\n');
+ }
+}
+
+void
+TIFFReadContigTileData(TIFF* tif)
+{
+ unsigned char *buf;
+ tsize_t rowsize = TIFFTileRowSize(tif);
+
+ buf = (unsigned char *)_TIFFmalloc(TIFFTileSize(tif));
+ if (buf) {
+ uint32 tw, th, w, h;
+ uint32 row, col;
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+ for (row = 0; row < h; row += th) {
+ for (col = 0; col < w; col += tw) {
+ if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0) {
+ if (stoponerr)
+ break;
+ } else if (showdata)
+ ShowTile(row, col, (tsample_t) -1, buf, th, rowsize);
+ }
+ }
+ _TIFFfree(buf);
+ }
+}
+
+void
+TIFFReadSeparateTileData(TIFF* tif)
+{
+ unsigned char *buf;
+ tsize_t rowsize = TIFFTileRowSize(tif);
+
+ buf = (unsigned char *)_TIFFmalloc(TIFFTileSize(tif));
+ if (buf) {
+ uint32 tw, th, w, h;
+ uint32 row, col;
+ tsample_t s, samplesperpixel;
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+ TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ for (row = 0; row < h; row += th) {
+ for (col = 0; col < w; col += tw) {
+ for (s = 0; s < samplesperpixel; s++) {
+ if (TIFFReadTile(tif, buf, col, row, 0, s) < 0) {
+ if (stoponerr)
+ break;
+ } else if (showdata)
+ ShowTile(row, col, s, buf, th, rowsize);
+ }
+ }
+ }
+ _TIFFfree(buf);
+ }
+}
+
+void
+TIFFReadData(TIFF* tif)
+{
+ uint16 config;
+
+ TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
+ if (TIFFIsTiled(tif)) {
+ if (config == PLANARCONFIG_CONTIG)
+ TIFFReadContigTileData(tif);
+ else
+ TIFFReadSeparateTileData(tif);
+ } else {
+ if (config == PLANARCONFIG_CONTIG)
+ TIFFReadContigStripData(tif);
+ else
+ TIFFReadSeparateStripData(tif);
+ }
+}
+
+static void
+ShowRawBytes(unsigned char* pp, uint32 n)
+{
+ uint32 i;
+
+ for (i = 0; i < n; i++) {
+ printf(" %02x", *pp++);
+ if (((i+1) % 24) == 0)
+ printf("\n ");
+ }
+ putchar('\n');
+}
+
+static void
+ShowRawWords(uint16* pp, uint32 n)
+{
+ uint32 i;
+
+ for (i = 0; i < n; i++) {
+ printf(" %04x", *pp++);
+ if (((i+1) % 15) == 0)
+ printf("\n ");
+ }
+ putchar('\n');
+}
+
+void
+TIFFReadRawData(TIFF* tif, int bitrev)
+{
+ tstrip_t nstrips = TIFFNumberOfStrips(tif);
+ const char* what = TIFFIsTiled(tif) ? "Tile" : "Strip";
+ uint32* stripbc;
+
+ TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbc);
+ if (nstrips > 0) {
+ uint32 bufsize = stripbc[0];
+ tdata_t buf = _TIFFmalloc(bufsize);
+ tstrip_t s;
+
+ for (s = 0; s < nstrips; s++) {
+ if (stripbc[s] > bufsize) {
+ buf = _TIFFrealloc(buf, stripbc[s]);
+ bufsize = stripbc[s];
+ }
+ if (buf == NULL) {
+ fprintf(stderr,
+ "Cannot allocate buffer to read strip %lu\n",
+ (unsigned long) s);
+ break;
+ }
+ if (TIFFReadRawStrip(tif, s, buf, stripbc[s]) < 0) {
+ fprintf(stderr, "Error reading strip %lu\n",
+ (unsigned long) s);
+ if (stoponerr)
+ break;
+ } else if (showdata) {
+ if (bitrev) {
+ TIFFReverseBits(buf, stripbc[s]);
+ printf("%s %lu: (bit reversed)\n ",
+ what, (unsigned long) s);
+ } else
+ printf("%s %lu:\n ", what,
+ (unsigned long) s);
+ if (showwords)
+ ShowRawWords((uint16*) buf, stripbc[s]>>1);
+ else
+ ShowRawBytes((unsigned char*) buf, stripbc[s]);
+ }
+ }
+ if (buf != NULL)
+ _TIFFfree(buf);
+ }
+}
+
+static void
+tiffinfo(TIFF* tif, uint16 order, long flags)
+{
+ TIFFPrintDirectory(tif, stdout, flags);
+ if (!readdata)
+ return;
+ if (rawdata) {
+ if (order) {
+ uint16 o;
+ TIFFGetFieldDefaulted(tif,
+ TIFFTAG_FILLORDER, &o);
+ TIFFReadRawData(tif, o != order);
+ } else
+ TIFFReadRawData(tif, 0);
+ } else {
+ if (order)
+ TIFFSetField(tif, TIFFTAG_FILLORDER, order);
+ TIFFReadData(tif);
+ }
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffmedian.c b/tiff/tools/tiffmedian.c
new file mode 100644
index 0000000..be45a2e
--- /dev/null
+++ b/tiff/tools/tiffmedian.c
@@ -0,0 +1,902 @@
+/* $Id: tiffmedian.c,v 1.8.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Apply median cut on an image.
+ *
+ * tiffmedian [-c n] [-f] input output
+ * -C n - set colortable size. Default is 256.
+ * -f - use Floyd-Steinberg dithering.
+ * -c lzw - compress output with LZW
+ * -c none - use no compression on output
+ * -c packbits - use packbits compression on output
+ * -r n - create output with n rows/strip of data
+ * (by default the compression scheme and rows/strip are taken
+ * from the input file)
+ *
+ * Notes:
+ *
+ * [1] Floyd-Steinberg dither:
+ * I should point out that the actual fractions we used were, assuming
+ * you are at X, moving left to right:
+ *
+ * X 7/16
+ * 3/16 5/16 1/16
+ *
+ * Note that the error goes to four neighbors, not three. I think this
+ * will probably do better (at least for black and white) than the
+ * 3/8-3/8-1/4 distribution, at the cost of greater processing. I have
+ * seen the 3/8-3/8-1/4 distribution described as "our" algorithm before,
+ * but I have no idea who the credit really belongs to.
+
+ * Also, I should add that if you do zig-zag scanning (see my immediately
+ * previous message), it is sufficient (but not quite as good) to send
+ * half the error one pixel ahead (e.g. to the right on lines you scan
+ * left to right), and half one pixel straight down. Again, this is for
+ * black and white; I've not tried it with color.
+ * --
+ * Lou Steinberg
+ *
+ * [2] Color Image Quantization for Frame Buffer Display, Paul Heckbert,
+ * Siggraph '82 proceedings, pp. 297-307
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define MAX_CMAP_SIZE 256
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+#define COLOR_DEPTH 8
+#define MAX_COLOR 256
+
+#define B_DEPTH 5 /* # bits/pixel to use */
+#define B_LEN (1L<<B_DEPTH)
+
+#define C_DEPTH 2
+#define C_LEN (1L<<C_DEPTH) /* # cells/color to use */
+
+#define COLOR_SHIFT (COLOR_DEPTH-B_DEPTH)
+
+typedef struct colorbox {
+ struct colorbox *next, *prev;
+ int rmin, rmax;
+ int gmin, gmax;
+ int bmin, bmax;
+ uint32 total;
+} Colorbox;
+
+typedef struct {
+ int num_ents;
+ int entries[MAX_CMAP_SIZE][2];
+} C_cell;
+
+uint16 rm[MAX_CMAP_SIZE], gm[MAX_CMAP_SIZE], bm[MAX_CMAP_SIZE];
+int num_colors;
+uint32 histogram[B_LEN][B_LEN][B_LEN];
+Colorbox *freeboxes;
+Colorbox *usedboxes;
+C_cell **ColorCells;
+TIFF *in, *out;
+uint32 rowsperstrip = (uint32) -1;
+uint16 compression = (uint16) -1;
+uint16 bitspersample = 1;
+uint16 samplesperpixel;
+uint32 imagewidth;
+uint32 imagelength;
+uint16 predictor = 0;
+
+static void get_histogram(TIFF*, Colorbox*);
+static void splitbox(Colorbox*);
+static void shrinkbox(Colorbox*);
+static void map_colortable(void);
+static void quant(TIFF*, TIFF*);
+static void quant_fsdither(TIFF*, TIFF*);
+static Colorbox* largest_box(void);
+
+static void usage(void);
+static int processCompressOptions(char*);
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+
+int
+main(int argc, char* argv[])
+{
+ int i, dither = 0;
+ uint16 shortv, config, photometric;
+ Colorbox *box_list, *ptr;
+ float floatv;
+ uint32 longv;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ num_colors = MAX_CMAP_SIZE;
+ while ((c = getopt(argc, argv, "c:C:r:f")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'C': /* set colormap size */
+ num_colors = atoi(optarg);
+ if (num_colors > MAX_CMAP_SIZE) {
+ fprintf(stderr,
+ "-c: colormap too big, max %d\n",
+ MAX_CMAP_SIZE);
+ usage();
+ }
+ break;
+ case 'f': /* dither */
+ dither = 1;
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+ in = TIFFOpen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (bitspersample != 8 && bitspersample != 16) {
+ fprintf(stderr, "%s: Image must have at least 8-bits/sample\n",
+ argv[optind]);
+ return (-3);
+ }
+ if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) ||
+ photometric != PHOTOMETRIC_RGB || samplesperpixel < 3) {
+ fprintf(stderr, "%s: Image must have RGB data\n", argv[optind]);
+ return (-4);
+ }
+ TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config);
+ if (config != PLANARCONFIG_CONTIG) {
+ fprintf(stderr, "%s: Can only handle contiguous data packing\n",
+ argv[optind]);
+ return (-5);
+ }
+
+ /*
+ * STEP 1: create empty boxes
+ */
+ usedboxes = NULL;
+ box_list = freeboxes = (Colorbox *)_TIFFmalloc(num_colors*sizeof (Colorbox));
+ freeboxes[0].next = &freeboxes[1];
+ freeboxes[0].prev = NULL;
+ for (i = 1; i < num_colors-1; ++i) {
+ freeboxes[i].next = &freeboxes[i+1];
+ freeboxes[i].prev = &freeboxes[i-1];
+ }
+ freeboxes[num_colors-1].next = NULL;
+ freeboxes[num_colors-1].prev = &freeboxes[num_colors-2];
+
+ /*
+ * STEP 2: get histogram, initialize first box
+ */
+ ptr = freeboxes;
+ freeboxes = ptr->next;
+ if (freeboxes)
+ freeboxes->prev = NULL;
+ ptr->next = usedboxes;
+ usedboxes = ptr;
+ if (ptr->next)
+ ptr->next->prev = ptr;
+ get_histogram(in, ptr);
+
+ /*
+ * STEP 3: continually subdivide boxes until no more free
+ * boxes remain or until all colors assigned.
+ */
+ while (freeboxes != NULL) {
+ ptr = largest_box();
+ if (ptr != NULL)
+ splitbox(ptr);
+ else
+ freeboxes = NULL;
+ }
+
+ /*
+ * STEP 4: assign colors to all boxes
+ */
+ for (i = 0, ptr = usedboxes; ptr != NULL; ++i, ptr = ptr->next) {
+ rm[i] = ((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2;
+ gm[i] = ((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2;
+ bm[i] = ((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2;
+ }
+
+ /* We're done with the boxes now */
+ _TIFFfree(box_list);
+ freeboxes = usedboxes = NULL;
+
+ /*
+ * STEP 5: scan histogram and map all values to closest color
+ */
+ /* 5a: create cell list as described in Heckbert[2] */
+ ColorCells = (C_cell **)_TIFFmalloc(C_LEN*C_LEN*C_LEN*sizeof (C_cell*));
+ _TIFFmemset(ColorCells, 0, C_LEN*C_LEN*C_LEN*sizeof (C_cell*));
+ /* 5b: create mapping from truncated pixel space to color
+ table entries */
+ map_colortable();
+
+ /*
+ * STEP 6: scan image, match input values to table entries
+ */
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-2);
+
+ CopyField(TIFFTAG_SUBFILETYPE, longv);
+ CopyField(TIFFTAG_IMAGEWIDTH, longv);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (short)COLOR_DEPTH);
+ if (compression != (uint16)-1) {
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ } else
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, (short)PHOTOMETRIC_PALETTE);
+ CopyField(TIFFTAG_ORIENTATION, shortv);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (short)1);
+ CopyField(TIFFTAG_PLANARCONFIG, shortv);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ CopyField(TIFFTAG_MINSAMPLEVALUE, shortv);
+ CopyField(TIFFTAG_MAXSAMPLEVALUE, shortv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_XPOSITION, floatv);
+ CopyField(TIFFTAG_YPOSITION, floatv);
+
+ if (dither)
+ quant_fsdither(in, out);
+ else
+ quant(in, out);
+ /*
+ * Scale colormap to TIFF-required 16-bit values.
+ */
+#define SCALE(x) (((x)*((1L<<16)-1))/255)
+ for (i = 0; i < MAX_CMAP_SIZE; ++i) {
+ rm[i] = SCALE(rm[i]);
+ gm[i] = SCALE(gm[i]);
+ bm[i] = SCALE(bm[i]);
+ }
+ TIFFSetField(out, TIFFTAG_COLORMAP, rm, gm, bm);
+ (void) TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+char* stuff[] = {
+"usage: tiffmedian [options] input.tif output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+" -C # create a colormap with # entries",
+" -f use Floyd-Steinberg dithering",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+static void
+get_histogram(TIFF* in, Colorbox* box)
+{
+ register unsigned char *inptr;
+ register int red, green, blue;
+ register uint32 j, i;
+ unsigned char *inputline;
+
+ inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ if (inputline == NULL) {
+ fprintf(stderr, "No space for scanline buffer\n");
+ exit(-1);
+ }
+ box->rmin = box->gmin = box->bmin = 999;
+ box->rmax = box->gmax = box->bmax = -1;
+ box->total = imagewidth * imagelength;
+
+ { register uint32 *ptr = &histogram[0][0][0];
+ for (i = B_LEN*B_LEN*B_LEN; i-- > 0;)
+ *ptr++ = 0;
+ }
+ for (i = 0; i < imagelength; i++) {
+ if (TIFFReadScanline(in, inputline, i, 0) <= 0)
+ break;
+ inptr = inputline;
+ for (j = imagewidth; j-- > 0;) {
+ red = *inptr++ >> COLOR_SHIFT;
+ green = *inptr++ >> COLOR_SHIFT;
+ blue = *inptr++ >> COLOR_SHIFT;
+ if (red < box->rmin)
+ box->rmin = red;
+ if (red > box->rmax)
+ box->rmax = red;
+ if (green < box->gmin)
+ box->gmin = green;
+ if (green > box->gmax)
+ box->gmax = green;
+ if (blue < box->bmin)
+ box->bmin = blue;
+ if (blue > box->bmax)
+ box->bmax = blue;
+ histogram[red][green][blue]++;
+ }
+ }
+ _TIFFfree(inputline);
+}
+
+static Colorbox *
+largest_box(void)
+{
+ register Colorbox *p, *b;
+ register uint32 size;
+
+ b = NULL;
+ size = 0;
+ for (p = usedboxes; p != NULL; p = p->next)
+ if ((p->rmax > p->rmin || p->gmax > p->gmin ||
+ p->bmax > p->bmin) && p->total > size)
+ size = (b = p)->total;
+ return (b);
+}
+
+static void
+splitbox(Colorbox* ptr)
+{
+ uint32 hist2[B_LEN];
+ int first=0, last=0;
+ register Colorbox *new;
+ register uint32 *iptr, *histp;
+ register int i, j;
+ register int ir,ig,ib;
+ register uint32 sum, sum1, sum2;
+ enum { RED, GREEN, BLUE } axis;
+
+ /*
+ * See which axis is the largest, do a histogram along that
+ * axis. Split at median point. Contract both new boxes to
+ * fit points and return
+ */
+ i = ptr->rmax - ptr->rmin;
+ if (i >= ptr->gmax - ptr->gmin && i >= ptr->bmax - ptr->bmin)
+ axis = RED;
+ else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)
+ axis = GREEN;
+ else
+ axis = BLUE;
+ /* get histogram along longest axis */
+ switch (axis) {
+ case RED:
+ histp = &hist2[ptr->rmin];
+ for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+ *histp = 0;
+ for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+ iptr = &histogram[ir][ig][ptr->bmin];
+ for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
+ *histp += *iptr++;
+ }
+ histp++;
+ }
+ first = ptr->rmin;
+ last = ptr->rmax;
+ break;
+ case GREEN:
+ histp = &hist2[ptr->gmin];
+ for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+ *histp = 0;
+ for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+ iptr = &histogram[ir][ig][ptr->bmin];
+ for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
+ *histp += *iptr++;
+ }
+ histp++;
+ }
+ first = ptr->gmin;
+ last = ptr->gmax;
+ break;
+ case BLUE:
+ histp = &hist2[ptr->bmin];
+ for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
+ *histp = 0;
+ for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+ iptr = &histogram[ir][ptr->gmin][ib];
+ for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+ *histp += *iptr;
+ iptr += B_LEN;
+ }
+ }
+ histp++;
+ }
+ first = ptr->bmin;
+ last = ptr->bmax;
+ break;
+ }
+ /* find median point */
+ sum2 = ptr->total / 2;
+ histp = &hist2[first];
+ sum = 0;
+ for (i = first; i <= last && (sum += *histp++) < sum2; ++i)
+ ;
+ if (i == first)
+ i++;
+
+ /* Create new box, re-allocate points */
+ new = freeboxes;
+ freeboxes = new->next;
+ if (freeboxes)
+ freeboxes->prev = NULL;
+ if (usedboxes)
+ usedboxes->prev = new;
+ new->next = usedboxes;
+ usedboxes = new;
+
+ histp = &hist2[first];
+ for (sum1 = 0, j = first; j < i; j++)
+ sum1 += *histp++;
+ for (sum2 = 0, j = i; j <= last; j++)
+ sum2 += *histp++;
+ new->total = sum1;
+ ptr->total = sum2;
+
+ new->rmin = ptr->rmin;
+ new->rmax = ptr->rmax;
+ new->gmin = ptr->gmin;
+ new->gmax = ptr->gmax;
+ new->bmin = ptr->bmin;
+ new->bmax = ptr->bmax;
+ switch (axis) {
+ case RED:
+ new->rmax = i-1;
+ ptr->rmin = i;
+ break;
+ case GREEN:
+ new->gmax = i-1;
+ ptr->gmin = i;
+ break;
+ case BLUE:
+ new->bmax = i-1;
+ ptr->bmin = i;
+ break;
+ }
+ shrinkbox(new);
+ shrinkbox(ptr);
+}
+
+static void
+shrinkbox(Colorbox* box)
+{
+ register uint32 *histp;
+ register int ir, ig, ib;
+
+ if (box->rmax > box->rmin) {
+ for (ir = box->rmin; ir <= box->rmax; ++ir)
+ for (ig = box->gmin; ig <= box->gmax; ++ig) {
+ histp = &histogram[ir][ig][box->bmin];
+ for (ib = box->bmin; ib <= box->bmax; ++ib)
+ if (*histp++ != 0) {
+ box->rmin = ir;
+ goto have_rmin;
+ }
+ }
+ have_rmin:
+ if (box->rmax > box->rmin)
+ for (ir = box->rmax; ir >= box->rmin; --ir)
+ for (ig = box->gmin; ig <= box->gmax; ++ig) {
+ histp = &histogram[ir][ig][box->bmin];
+ ib = box->bmin;
+ for (; ib <= box->bmax; ++ib)
+ if (*histp++ != 0) {
+ box->rmax = ir;
+ goto have_rmax;
+ }
+ }
+ }
+have_rmax:
+ if (box->gmax > box->gmin) {
+ for (ig = box->gmin; ig <= box->gmax; ++ig)
+ for (ir = box->rmin; ir <= box->rmax; ++ir) {
+ histp = &histogram[ir][ig][box->bmin];
+ for (ib = box->bmin; ib <= box->bmax; ++ib)
+ if (*histp++ != 0) {
+ box->gmin = ig;
+ goto have_gmin;
+ }
+ }
+ have_gmin:
+ if (box->gmax > box->gmin)
+ for (ig = box->gmax; ig >= box->gmin; --ig)
+ for (ir = box->rmin; ir <= box->rmax; ++ir) {
+ histp = &histogram[ir][ig][box->bmin];
+ ib = box->bmin;
+ for (; ib <= box->bmax; ++ib)
+ if (*histp++ != 0) {
+ box->gmax = ig;
+ goto have_gmax;
+ }
+ }
+ }
+have_gmax:
+ if (box->bmax > box->bmin) {
+ for (ib = box->bmin; ib <= box->bmax; ++ib)
+ for (ir = box->rmin; ir <= box->rmax; ++ir) {
+ histp = &histogram[ir][box->gmin][ib];
+ for (ig = box->gmin; ig <= box->gmax; ++ig) {
+ if (*histp != 0) {
+ box->bmin = ib;
+ goto have_bmin;
+ }
+ histp += B_LEN;
+ }
+ }
+ have_bmin:
+ if (box->bmax > box->bmin)
+ for (ib = box->bmax; ib >= box->bmin; --ib)
+ for (ir = box->rmin; ir <= box->rmax; ++ir) {
+ histp = &histogram[ir][box->gmin][ib];
+ ig = box->gmin;
+ for (; ig <= box->gmax; ++ig) {
+ if (*histp != 0) {
+ box->bmax = ib;
+ goto have_bmax;
+ }
+ histp += B_LEN;
+ }
+ }
+ }
+have_bmax:
+ ;
+}
+
+static C_cell *
+create_colorcell(int red, int green, int blue)
+{
+ register int ir, ig, ib, i;
+ register C_cell *ptr;
+ int mindist, next_n;
+ register int tmp, dist, n;
+
+ ir = red >> (COLOR_DEPTH-C_DEPTH);
+ ig = green >> (COLOR_DEPTH-C_DEPTH);
+ ib = blue >> (COLOR_DEPTH-C_DEPTH);
+ ptr = (C_cell *)_TIFFmalloc(sizeof (C_cell));
+ *(ColorCells + ir*C_LEN*C_LEN + ig*C_LEN + ib) = ptr;
+ ptr->num_ents = 0;
+
+ /*
+ * Step 1: find all colors inside this cell, while we're at
+ * it, find distance of centermost point to furthest corner
+ */
+ mindist = 99999999;
+ for (i = 0; i < num_colors; ++i) {
+ if (rm[i]>>(COLOR_DEPTH-C_DEPTH) != ir ||
+ gm[i]>>(COLOR_DEPTH-C_DEPTH) != ig ||
+ bm[i]>>(COLOR_DEPTH-C_DEPTH) != ib)
+ continue;
+ ptr->entries[ptr->num_ents][0] = i;
+ ptr->entries[ptr->num_ents][1] = 0;
+ ++ptr->num_ents;
+ tmp = rm[i] - red;
+ if (tmp < (MAX_COLOR/C_LEN/2))
+ tmp = MAX_COLOR/C_LEN-1 - tmp;
+ dist = tmp*tmp;
+ tmp = gm[i] - green;
+ if (tmp < (MAX_COLOR/C_LEN/2))
+ tmp = MAX_COLOR/C_LEN-1 - tmp;
+ dist += tmp*tmp;
+ tmp = bm[i] - blue;
+ if (tmp < (MAX_COLOR/C_LEN/2))
+ tmp = MAX_COLOR/C_LEN-1 - tmp;
+ dist += tmp*tmp;
+ if (dist < mindist)
+ mindist = dist;
+ }
+
+ /*
+ * Step 3: find all points within that distance to cell.
+ */
+ for (i = 0; i < num_colors; ++i) {
+ if (rm[i] >> (COLOR_DEPTH-C_DEPTH) == ir &&
+ gm[i] >> (COLOR_DEPTH-C_DEPTH) == ig &&
+ bm[i] >> (COLOR_DEPTH-C_DEPTH) == ib)
+ continue;
+ dist = 0;
+ if ((tmp = red - rm[i]) > 0 ||
+ (tmp = rm[i] - (red + MAX_COLOR/C_LEN-1)) > 0 )
+ dist += tmp*tmp;
+ if ((tmp = green - gm[i]) > 0 ||
+ (tmp = gm[i] - (green + MAX_COLOR/C_LEN-1)) > 0 )
+ dist += tmp*tmp;
+ if ((tmp = blue - bm[i]) > 0 ||
+ (tmp = bm[i] - (blue + MAX_COLOR/C_LEN-1)) > 0 )
+ dist += tmp*tmp;
+ if (dist < mindist) {
+ ptr->entries[ptr->num_ents][0] = i;
+ ptr->entries[ptr->num_ents][1] = dist;
+ ++ptr->num_ents;
+ }
+ }
+
+ /*
+ * Sort color cells by distance, use cheap exchange sort
+ */
+ for (n = ptr->num_ents - 1; n > 0; n = next_n) {
+ next_n = 0;
+ for (i = 0; i < n; ++i)
+ if (ptr->entries[i][1] > ptr->entries[i+1][1]) {
+ tmp = ptr->entries[i][0];
+ ptr->entries[i][0] = ptr->entries[i+1][0];
+ ptr->entries[i+1][0] = tmp;
+ tmp = ptr->entries[i][1];
+ ptr->entries[i][1] = ptr->entries[i+1][1];
+ ptr->entries[i+1][1] = tmp;
+ next_n = i;
+ }
+ }
+ return (ptr);
+}
+
+static void
+map_colortable(void)
+{
+ register uint32 *histp = &histogram[0][0][0];
+ register C_cell *cell;
+ register int j, tmp, d2, dist;
+ int ir, ig, ib, i;
+
+ for (ir = 0; ir < B_LEN; ++ir)
+ for (ig = 0; ig < B_LEN; ++ig)
+ for (ib = 0; ib < B_LEN; ++ib, histp++) {
+ if (*histp == 0) {
+ *histp = -1;
+ continue;
+ }
+ cell = *(ColorCells +
+ (((ir>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
+ ((ig>>(B_DEPTH-C_DEPTH)) << C_DEPTH) +
+ (ib>>(B_DEPTH-C_DEPTH))));
+ if (cell == NULL )
+ cell = create_colorcell(
+ ir << COLOR_SHIFT,
+ ig << COLOR_SHIFT,
+ ib << COLOR_SHIFT);
+ dist = 9999999;
+ for (i = 0; i < cell->num_ents &&
+ dist > cell->entries[i][1]; ++i) {
+ j = cell->entries[i][0];
+ d2 = rm[j] - (ir << COLOR_SHIFT);
+ d2 *= d2;
+ tmp = gm[j] - (ig << COLOR_SHIFT);
+ d2 += tmp*tmp;
+ tmp = bm[j] - (ib << COLOR_SHIFT);
+ d2 += tmp*tmp;
+ if (d2 < dist) {
+ dist = d2;
+ *histp = j;
+ }
+ }
+ }
+}
+
+/*
+ * straight quantization. Each pixel is mapped to the colors
+ * closest to it. Color values are rounded to the nearest color
+ * table entry.
+ */
+static void
+quant(TIFF* in, TIFF* out)
+{
+ unsigned char *outline, *inputline;
+ register unsigned char *outptr, *inptr;
+ register uint32 i, j;
+ register int red, green, blue;
+
+ inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ outline = (unsigned char *)_TIFFmalloc(imagewidth);
+ for (i = 0; i < imagelength; i++) {
+ if (TIFFReadScanline(in, inputline, i, 0) <= 0)
+ break;
+ inptr = inputline;
+ outptr = outline;
+ for (j = 0; j < imagewidth; j++) {
+ red = *inptr++ >> COLOR_SHIFT;
+ green = *inptr++ >> COLOR_SHIFT;
+ blue = *inptr++ >> COLOR_SHIFT;
+ *outptr++ = (unsigned char)histogram[red][green][blue];
+ }
+ if (TIFFWriteScanline(out, outline, i, 0) < 0)
+ break;
+ }
+ _TIFFfree(inputline);
+ _TIFFfree(outline);
+}
+
+#define SWAP(type,a,b) { type p; p = a; a = b; b = p; }
+
+#define GetInputLine(tif, row, bad) \
+ if (TIFFReadScanline(tif, inputline, row, 0) <= 0) \
+ bad; \
+ inptr = inputline; \
+ nextptr = nextline; \
+ for (j = 0; j < imagewidth; ++j) { \
+ *nextptr++ = *inptr++; \
+ *nextptr++ = *inptr++; \
+ *nextptr++ = *inptr++; \
+ }
+#define GetComponent(raw, cshift, c) \
+ cshift = raw; \
+ if (cshift < 0) \
+ cshift = 0; \
+ else if (cshift >= MAX_COLOR) \
+ cshift = MAX_COLOR-1; \
+ c = cshift; \
+ cshift >>= COLOR_SHIFT;
+
+static void
+quant_fsdither(TIFF* in, TIFF* out)
+{
+ unsigned char *outline, *inputline, *inptr;
+ short *thisline, *nextline;
+ register unsigned char *outptr;
+ register short *thisptr, *nextptr;
+ register uint32 i, j;
+ uint32 imax, jmax;
+ int lastline, lastpixel;
+
+ imax = imagelength - 1;
+ jmax = imagewidth - 1;
+ inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ thisline = (short *)_TIFFmalloc(imagewidth * 3 * sizeof (short));
+ nextline = (short *)_TIFFmalloc(imagewidth * 3 * sizeof (short));
+ outline = (unsigned char *) _TIFFmalloc(TIFFScanlineSize(out));
+
+ GetInputLine(in, 0, goto bad); /* get first line */
+ for (i = 1; i <= imagelength; ++i) {
+ SWAP(short *, thisline, nextline);
+ lastline = (i >= imax);
+ if (i <= imax)
+ GetInputLine(in, i, break);
+ thisptr = thisline;
+ nextptr = nextline;
+ outptr = outline;
+ for (j = 0; j < imagewidth; ++j) {
+ int red, green, blue;
+ register int oval, r2, g2, b2;
+
+ lastpixel = (j == jmax);
+ GetComponent(*thisptr++, r2, red);
+ GetComponent(*thisptr++, g2, green);
+ GetComponent(*thisptr++, b2, blue);
+ oval = histogram[r2][g2][b2];
+ if (oval == -1) {
+ int ci;
+ register int cj, tmp, d2, dist;
+ register C_cell *cell;
+
+ cell = *(ColorCells +
+ (((r2>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
+ ((g2>>(B_DEPTH-C_DEPTH)) << C_DEPTH ) +
+ (b2>>(B_DEPTH-C_DEPTH))));
+ if (cell == NULL)
+ cell = create_colorcell(red,
+ green, blue);
+ dist = 9999999;
+ for (ci = 0; ci < cell->num_ents && dist > cell->entries[ci][1]; ++ci) {
+ cj = cell->entries[ci][0];
+ d2 = (rm[cj] >> COLOR_SHIFT) - r2;
+ d2 *= d2;
+ tmp = (gm[cj] >> COLOR_SHIFT) - g2;
+ d2 += tmp*tmp;
+ tmp = (bm[cj] >> COLOR_SHIFT) - b2;
+ d2 += tmp*tmp;
+ if (d2 < dist) {
+ dist = d2;
+ oval = cj;
+ }
+ }
+ histogram[r2][g2][b2] = oval;
+ }
+ *outptr++ = oval;
+ red -= rm[oval];
+ green -= gm[oval];
+ blue -= bm[oval];
+ if (!lastpixel) {
+ thisptr[0] += blue * 7 / 16;
+ thisptr[1] += green * 7 / 16;
+ thisptr[2] += red * 7 / 16;
+ }
+ if (!lastline) {
+ if (j != 0) {
+ nextptr[-3] += blue * 3 / 16;
+ nextptr[-2] += green * 3 / 16;
+ nextptr[-1] += red * 3 / 16;
+ }
+ nextptr[0] += blue * 5 / 16;
+ nextptr[1] += green * 5 / 16;
+ nextptr[2] += red * 5 / 16;
+ if (!lastpixel) {
+ nextptr[3] += blue / 16;
+ nextptr[4] += green / 16;
+ nextptr[5] += red / 16;
+ }
+ nextptr += 3;
+ }
+ }
+ if (TIFFWriteScanline(out, outline, i-1, 0) < 0)
+ break;
+ }
+bad:
+ _TIFFfree(inputline);
+ _TIFFfree(thisline);
+ _TIFFfree(nextline);
+ _TIFFfree(outline);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffset.c b/tiff/tools/tiffset.c
new file mode 100644
index 0000000..eb68924
--- /dev/null
+++ b/tiff/tools/tiffset.c
@@ -0,0 +1,325 @@
+/******************************************************************************
+ * $Id: tiffset.c,v 1.12.2.1 2010-06-08 18:50:44 bfriesen Exp $
+ *
+ * Project: libtiff tools
+ * Purpose: Mainline for setting metadata in existing TIFF files.
+ * Author: Frank Warmerdam, warmerdam@pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2000, Frank Warmerdam
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log: tiffset.c,v $
+ * Revision 1.12.2.1 2010-06-08 18:50:44 bfriesen
+ * * Add an emacs formatting mode footer to all source files so that
+ * emacs can be effectively used.
+ *
+ * Revision 1.12 2007/02/24 17:14:14 dron
+ * Properly handle tags with TIFF_VARIABLE writecount. As per bug
+ * http://bugzilla.remotesensing.org/show_bug.cgi?id=1350
+ *
+ * Revision 1.11 2005/09/13 14:13:42 dron
+ * Avoid warnings.
+ *
+ * Revision 1.10 2005/02/24 14:47:11 fwarmerdam
+ * Updated header.
+ *
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tiffio.h"
+
+static char* usageMsg[] = {
+"usage: tiffset [options] filename",
+"where options are:",
+" -s <tagname> [count] <value>... set the tag value",
+" -sf <tagname> <filename> read the tag value from file (for ASCII tags only)",
+NULL
+};
+
+static void
+usage(void)
+{
+ int i;
+ for (i = 0; usageMsg[i]; i++)
+ fprintf(stderr, "%s\n", usageMsg[i]);
+ exit(-1);
+}
+
+static const TIFFFieldInfo *
+GetField(TIFF *tiff, const char *tagname)
+{
+ const TIFFFieldInfo *fip;
+
+ if( atoi(tagname) > 0 )
+ fip = TIFFFieldWithTag(tiff, (ttag_t)atoi(tagname));
+ else
+ fip = TIFFFieldWithName(tiff, tagname);
+
+ if (!fip) {
+ fprintf( stderr, "Field name %s not recognised.\n", tagname );
+ return (TIFFFieldInfo *)NULL;
+ }
+
+ return fip;
+}
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *tiff;
+ int arg_index;
+
+ if (argc < 2)
+ usage();
+
+ tiff = TIFFOpen(argv[argc-1], "r+");
+ if (tiff == NULL)
+ return 2;
+
+ for( arg_index = 1; arg_index < argc-1; arg_index++ ) {
+ if (strcmp(argv[arg_index],"-s") == 0 && arg_index < argc-3) {
+ const TIFFFieldInfo *fip;
+ const char *tagname;
+
+ arg_index++;
+ tagname = argv[arg_index];
+ fip = GetField(tiff, tagname);
+
+ if (!fip)
+ return 3;
+
+ arg_index++;
+ if (fip->field_type == TIFF_ASCII) {
+ if (TIFFSetField(tiff, fip->field_tag, argv[arg_index]) != 1)
+ fprintf( stderr, "Failed to set %s=%s\n",
+ fip->field_name, argv[arg_index] );
+ } else if (fip->field_writecount > 0
+ || fip->field_writecount == TIFF_VARIABLE) {
+ int ret = 1;
+ short wc;
+
+ if (fip->field_writecount == TIFF_VARIABLE)
+ wc = atoi(argv[arg_index++]);
+ else
+ wc = fip->field_writecount;
+
+ if (argc - arg_index < wc) {
+ fprintf( stderr,
+ "Number of tag values is not enough. "
+ "Expected %d values for %s tag, got %d\n",
+ wc, fip->field_name, argc - arg_index);
+ return 4;
+ }
+
+ if (wc > 1) {
+ int i, size;
+ void *array;
+
+ switch (fip->field_type) {
+ /*
+ * XXX: We can't use TIFFDataWidth()
+ * to determine the space needed to store
+ * the value. For TIFF_RATIONAL values
+ * TIFFDataWidth() returns 8, but we use 4-byte
+ * float to represent rationals.
+ */
+ case TIFF_BYTE:
+ case TIFF_ASCII:
+ case TIFF_SBYTE:
+ case TIFF_UNDEFINED:
+ default:
+ size = 1;
+ break;
+
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ size = 2;
+ break;
+
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ case TIFF_IFD:
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ size = 4;
+ break;
+
+ case TIFF_DOUBLE:
+ size = 8;
+ break;
+ }
+
+ array = _TIFFmalloc(wc * size);
+ if (!array) {
+ fprintf(stderr, "No space for %s tag\n",
+ tagname);
+ return 4;
+ }
+
+ switch (fip->field_type) {
+ case TIFF_BYTE:
+ for (i = 0; i < wc; i++)
+ ((uint8 *)array)[i] = atoi(argv[arg_index+i]);
+ break;
+ case TIFF_SHORT:
+ for (i = 0; i < wc; i++)
+ ((uint16 *)array)[i] = atoi(argv[arg_index+i]);
+ break;
+ case TIFF_SBYTE:
+ for (i = 0; i < wc; i++)
+ ((int8 *)array)[i] = atoi(argv[arg_index+i]);
+ break;
+ case TIFF_SSHORT:
+ for (i = 0; i < wc; i++)
+ ((int16 *)array)[i] = atoi(argv[arg_index+i]);
+ break;
+ case TIFF_LONG:
+ for (i = 0; i < wc; i++)
+ ((uint32 *)array)[i] = atol(argv[arg_index+i]);
+ break;
+ case TIFF_SLONG:
+ case TIFF_IFD:
+ for (i = 0; i < wc; i++)
+ ((uint32 *)array)[i] = atol(argv[arg_index+i]);
+ break;
+ case TIFF_DOUBLE:
+ for (i = 0; i < wc; i++)
+ ((double *)array)[i] = atof(argv[arg_index+i]);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ for (i = 0; i < wc; i++)
+ ((float *)array)[i] = (float)atof(argv[arg_index+i]);
+ break;
+ default:
+ break;
+ }
+
+ if (fip->field_passcount) {
+ ret = TIFFSetField(tiff, fip->field_tag,
+ wc, array);
+ } else {
+ ret = TIFFSetField(tiff, fip->field_tag,
+ array);
+ }
+
+ _TIFFfree(array);
+ } else {
+ switch (fip->field_type) {
+ case TIFF_BYTE:
+ case TIFF_SHORT:
+ case TIFF_SBYTE:
+ case TIFF_SSHORT:
+ ret = TIFFSetField(tiff, fip->field_tag,
+ atoi(argv[arg_index++]));
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_IFD:
+ ret = TIFFSetField(tiff, fip->field_tag,
+ atol(argv[arg_index++]));
+ break;
+ case TIFF_DOUBLE:
+ ret = TIFFSetField(tiff, fip->field_tag,
+ atof(argv[arg_index++]));
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ ret = TIFFSetField(tiff, fip->field_tag,
+ (float)atof(argv[arg_index++]));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (ret != 1)
+ fprintf(stderr, "Failed to set %s\n", fip->field_name);
+ arg_index += wc;
+ }
+ } else if (strcmp(argv[arg_index],"-sf") == 0 && arg_index < argc-3) {
+ FILE *fp;
+ const TIFFFieldInfo *fip;
+ char *text;
+ int len;
+
+ arg_index++;
+ fip = GetField(tiff, argv[arg_index]);
+
+ if (!fip)
+ return 3;
+
+ if (fip->field_type != TIFF_ASCII) {
+ fprintf( stderr,
+ "Only ASCII tags can be set from file. "
+ "%s is not ASCII tag.\n", fip->field_name );
+ return 5;
+ }
+
+ arg_index++;
+ fp = fopen( argv[arg_index], "rt" );
+ if(fp == NULL) {
+ perror( argv[arg_index] );
+ continue;
+ }
+
+ text = (char *) malloc(1000000);
+ len = fread( text, 1, 999999, fp );
+ text[len] = '\0';
+
+ fclose( fp );
+
+ if(TIFFSetField( tiff, fip->field_tag, text ) != 1) {
+ fprintf(stderr, "Failed to set %s from file %s\n",
+ fip->field_name, argv[arg_index]);
+ }
+
+ _TIFFfree( text );
+ arg_index++;
+ } else {
+ fprintf(stderr, "Unrecognised option: %s\n",
+ argv[arg_index]);
+ usage();
+ }
+ }
+
+ TIFFRewriteDirectory(tiff);
+ TIFFClose(tiff);
+ return 0;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffsplit.c b/tiff/tools/tiffsplit.c
new file mode 100644
index 0000000..58288cd
--- /dev/null
+++ b/tiff/tools/tiffsplit.c
@@ -0,0 +1,297 @@
+/* $Id: tiffsplit.c,v 1.14.2.4 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1992-1997 Sam Leffler
+ * Copyright (c) 1992-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+
+#define PATH_LENGTH 8192
+
+static const char TIFF_SUFFIX[] = ".tif";
+
+static char fname[PATH_LENGTH];
+
+static int tiffcp(TIFF*, TIFF*);
+static void newfilename(void);
+static int cpStrips(TIFF*, TIFF*);
+static int cpTiles(TIFF*, TIFF*);
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *in, *out;
+
+ if (argc < 2) {
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ fprintf(stderr, "usage: tiffsplit input.tif [prefix]\n");
+ return (-3);
+ }
+ if (argc > 2) {
+ strncpy(fname, argv[2], sizeof(fname));
+ fname[sizeof(fname) - 1] = '\0';
+ }
+ in = TIFFOpen(argv[1], "r");
+ if (in != NULL) {
+ do {
+ size_t path_len;
+ char *path;
+
+ newfilename();
+
+ path_len = strlen(fname) + sizeof(TIFF_SUFFIX);
+ path = (char *) _TIFFmalloc(path_len);
+ strncpy(path, fname, path_len);
+ path[path_len - 1] = '\0';
+ strncat(path, TIFF_SUFFIX, path_len - strlen(path) - 1);
+ out = TIFFOpen(path, TIFFIsBigEndian(in)?"wb":"wl");
+ _TIFFfree(path);
+
+ if (out == NULL)
+ return (-2);
+ if (!tiffcp(in, out))
+ return (-1);
+ TIFFClose(out);
+ } while (TIFFReadDirectory(in));
+ (void) TIFFClose(in);
+ }
+ return (0);
+}
+
+static void
+newfilename(void)
+{
+ static int first = 1;
+ static long lastTurn;
+ static long fnum;
+ static short defname;
+ static char *fpnt;
+
+ if (first) {
+ if (fname[0]) {
+ fpnt = fname + strlen(fname);
+ defname = 0;
+ } else {
+ fname[0] = 'x';
+ fpnt = fname + 1;
+ defname = 1;
+ }
+ first = 0;
+ }
+#define MAXFILES 17576
+ if (fnum == MAXFILES) {
+ if (!defname || fname[0] == 'z') {
+ fprintf(stderr, "tiffsplit: too many files.\n");
+ exit(1);
+ }
+ fname[0]++;
+ fnum = 0;
+ }
+ if (fnum % 676 == 0) {
+ if (fnum != 0) {
+ /*
+ * advance to next letter every 676 pages
+ * condition for 'z'++ will be covered above
+ */
+ fpnt[0]++;
+ } else {
+ /*
+ * set to 'a' if we are on the very first file
+ */
+ fpnt[0] = 'a';
+ }
+ /*
+ * set the value of the last turning point
+ */
+ lastTurn = fnum;
+ }
+ /*
+ * start from 0 every 676 times (provided by lastTurn)
+ * this keeps us within a-z boundaries
+ */
+ fpnt[1] = (char)((fnum - lastTurn) / 26) + 'a';
+ /*
+ * cycle last letter every file, from a-z, then repeat
+ */
+ fpnt[2] = (char)(fnum % 26) + 'a';
+ fnum++;
+}
+
+static int
+tiffcp(TIFF* in, TIFF* out)
+{
+ uint16 bitspersample, samplesperpixel, compression, shortv, *shortav;
+ uint32 w, l;
+ float floatv;
+ char *stringv;
+ uint32 longv;
+
+ CopyField(TIFFTAG_SUBFILETYPE, longv);
+ CopyField(TIFFTAG_TILEWIDTH, w);
+ CopyField(TIFFTAG_TILELENGTH, l);
+ CopyField(TIFFTAG_IMAGEWIDTH, w);
+ CopyField(TIFFTAG_IMAGELENGTH, l);
+ CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample);
+ CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ if (compression == COMPRESSION_JPEG) {
+ uint16 count = 0;
+ void *table = NULL;
+ if (TIFFGetField(in, TIFFTAG_JPEGTABLES, &count, &table)
+ && count > 0 && table) {
+ TIFFSetField(out, TIFFTAG_JPEGTABLES, count, table);
+ }
+ }
+ CopyField(TIFFTAG_PHOTOMETRIC, shortv);
+ 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_GROUP3OPTIONS, longv);
+ CopyField(TIFFTAG_GROUP4OPTIONS, longv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ CopyField(TIFFTAG_PLANARCONFIG, shortv);
+ CopyField(TIFFTAG_ROWSPERSTRIP, longv);
+ CopyField(TIFFTAG_XPOSITION, floatv);
+ CopyField(TIFFTAG_YPOSITION, floatv);
+ CopyField(TIFFTAG_IMAGEDEPTH, longv);
+ CopyField(TIFFTAG_TILEDEPTH, longv);
+ CopyField(TIFFTAG_SAMPLEFORMAT, shortv);
+ CopyField2(TIFFTAG_EXTRASAMPLES, shortv, shortav);
+ { uint16 *red, *green, *blue;
+ CopyField3(TIFFTAG_COLORMAP, red, green, blue);
+ }
+ { uint16 shortv2;
+ CopyField2(TIFFTAG_PAGENUMBER, shortv, shortv2);
+ }
+ CopyField(TIFFTAG_ARTIST, stringv);
+ CopyField(TIFFTAG_IMAGEDESCRIPTION, stringv);
+ CopyField(TIFFTAG_MAKE, stringv);
+ CopyField(TIFFTAG_MODEL, stringv);
+ CopyField(TIFFTAG_SOFTWARE, stringv);
+ CopyField(TIFFTAG_DATETIME, stringv);
+ CopyField(TIFFTAG_HOSTCOMPUTER, stringv);
+ CopyField(TIFFTAG_PAGENAME, stringv);
+ CopyField(TIFFTAG_DOCUMENTNAME, stringv);
+ CopyField(TIFFTAG_BADFAXLINES, longv);
+ CopyField(TIFFTAG_CLEANFAXDATA, longv);
+ CopyField(TIFFTAG_CONSECUTIVEBADFAXLINES, longv);
+ CopyField(TIFFTAG_FAXRECVPARAMS, longv);
+ CopyField(TIFFTAG_FAXRECVTIME, longv);
+ CopyField(TIFFTAG_FAXSUBADDRESS, stringv);
+ CopyField(TIFFTAG_FAXDCS, stringv);
+ if (TIFFIsTiled(in))
+ return (cpTiles(in, out));
+ else
+ return (cpStrips(in, out));
+}
+
+static int
+cpStrips(TIFF* in, TIFF* out)
+{
+ tsize_t bufsize = TIFFStripSize(in);
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
+
+ if (buf) {
+ tstrip_t s, ns = TIFFNumberOfStrips(in);
+ uint32 *bytecounts;
+
+ TIFFGetField(in, TIFFTAG_STRIPBYTECOUNTS, &bytecounts);
+ for (s = 0; s < ns; s++) {
+ if (bytecounts[s] > (uint32)bufsize) {
+ buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[s]);
+ if (!buf)
+ return (0);
+ bufsize = bytecounts[s];
+ }
+ if (TIFFReadRawStrip(in, s, buf, bytecounts[s]) < 0 ||
+ TIFFWriteRawStrip(out, s, buf, bytecounts[s]) < 0) {
+ _TIFFfree(buf);
+ return (0);
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+cpTiles(TIFF* in, TIFF* out)
+{
+ tsize_t bufsize = TIFFTileSize(in);
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
+
+ if (buf) {
+ ttile_t t, nt = TIFFNumberOfTiles(in);
+ uint32 *bytecounts;
+
+ TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts);
+ for (t = 0; t < nt; t++) {
+ if (bytecounts[t] > (uint32) bufsize) {
+ buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[t]);
+ if (!buf)
+ return (0);
+ bufsize = bytecounts[t];
+ }
+ if (TIFFReadRawTile(in, t, buf, bytecounts[t]) < 0 ||
+ TIFFWriteRawTile(out, t, buf, bytecounts[t]) < 0) {
+ _TIFFfree(buf);
+ return (0);
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+ }
+ return (0);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/ycbcr.c b/tiff/tools/ycbcr.c
new file mode 100644
index 0000000..8f72447
--- /dev/null
+++ b/tiff/tools/ycbcr.c
@@ -0,0 +1,168 @@
+float ycbcrCoeffs[3] = { .299, .587, .114 };
+/* default coding range is CCIR Rec 601-1 with no headroom/footroom */
+unsigned long refBlackWhite[6] = { 0, 255, 128, 255, 128, 255 };
+
+#define LumaRed ycbcrCoeffs[0]
+#define LumaGreen ycbcrCoeffs[1]
+#define LumaBlue ycbcrCoeffs[2]
+
+long eRtotal = 0;
+long eGtotal = 0;
+long eBtotal = 0;
+long preveRtotal = 0;
+long preveGtotal = 0;
+long preveBtotal = 0;
+unsigned long AbseRtotal = 0;
+unsigned long AbseGtotal = 0;
+unsigned long AbseBtotal = 0;
+unsigned long eCodes = 0;
+unsigned long preveCodes = 0;
+unsigned long eBits = 0;
+unsigned long preveBits = 0;
+
+static void setupLumaTables();
+static int abs(int v) { return (v < 0 ? -v : v); }
+static double pct(int v,double range) { return (v*100. / range); }
+static void check(int R, int G, int B);
+
+float D1, D2;
+float D3, D4;
+float D5, D6;
+
+int
+main(int argc, char** argv)
+{
+ int R, G, B;
+
+ if (argc > 1) {
+ refBlackWhite[0] = 16;
+ refBlackWhite[1] = 235;
+ refBlackWhite[2] = 128;
+ refBlackWhite[3] = 240;
+ refBlackWhite[4] = 128;
+ refBlackWhite[5] = 240;
+ }
+ D3 = 2 - 2*LumaRed;
+ D4 = 2 - 2*LumaBlue;
+ D1 = 1. / D3;
+ D2 = 1. / D4;
+ D5 = D3*LumaRed / LumaGreen;
+ D6 = D4*LumaBlue / LumaGreen;
+ setupLumaTables();
+ for (R = 0; R < 256; R++) {
+ for (G = 0; G < 256; G++)
+ for (B = 0; B < 256; B++)
+ check(R, G, B);
+ printf("[%3u] c %u/%u b %u/%u (R %u/%d/%u G %u/%d/%u B %u/%d/%u)\n"
+ , R
+ , eCodes - preveCodes, eCodes
+ , eBits - preveBits, eBits
+ , abs(AbseRtotal - preveRtotal), eRtotal , AbseRtotal
+ , abs(AbseGtotal - preveGtotal), eGtotal , AbseGtotal
+ , abs(AbseBtotal - preveBtotal), eBtotal , AbseBtotal
+ );
+ preveRtotal = AbseRtotal;
+ preveGtotal = AbseGtotal;
+ preveBtotal = AbseBtotal;
+ preveCodes = eCodes;
+ preveBits = eBits;
+ }
+ printf("%u total codes\n", 256*256*256);
+ printf("total error: %u codes %u bits (R %d/%u G %d/%u B %d/%u)\n"
+ , eCodes
+ , eBits
+ , eRtotal , AbseRtotal
+ , eGtotal , AbseGtotal
+ , eBtotal , AbseBtotal
+ );
+ return (0);
+}
+
+float *lumaRed;
+float *lumaGreen;
+float *lumaBlue;
+
+static float*
+setupLuma(float c)
+{
+ float *v = (float *)_TIFFmalloc(256 * sizeof (float));
+ int i;
+ for (i = 0; i < 256; i++)
+ v[i] = c * i;
+ return (v);
+}
+
+static void
+setupLumaTables(void)
+{
+ lumaRed = setupLuma(LumaRed);
+ lumaGreen = setupLuma(LumaGreen);
+ lumaBlue = setupLuma(LumaBlue);
+}
+
+static unsigned
+V2Code(float f, unsigned long RB, unsigned long RW, int CR)
+{
+ unsigned int c = (unsigned int)((((f)*(RW-RB)/CR)+RB)+.5);
+ return (c > 255 ? 255 : c);
+}
+
+#define Code2V(c, RB, RW, CR) ((((c)-(int)RB)*(float)CR)/(float)(RW-RB))
+
+#define CLAMP(f,min,max) \
+ (int)((f)+.5 < (min) ? (min) : (f)+.5 > (max) ? (max) : (f)+.5)
+
+static
+void
+check(int R, int G, int B)
+{
+ float Y, Cb, Cr;
+ int iY, iCb, iCr;
+ float rY, rCb, rCr;
+ float rR, rG, rB;
+ int eR, eG, eB;
+
+ Y = lumaRed[R] + lumaGreen[G] + lumaBlue[B];
+ Cb = (B - Y)*D2;
+ Cr = (R - Y)*D1;
+ iY = V2Code(Y, refBlackWhite[0], refBlackWhite[1], 255);
+ iCb = V2Code(Cb, refBlackWhite[2], refBlackWhite[3], 127);
+ iCr = V2Code(Cr, refBlackWhite[4], refBlackWhite[5], 127);
+ rCb = Code2V(iCb, refBlackWhite[2], refBlackWhite[3], 127);
+ rCr = Code2V(iCr, refBlackWhite[4], refBlackWhite[5], 127);
+ rY = Code2V(iY, refBlackWhite[0], refBlackWhite[1], 255);
+ rR = rY + rCr*D3;
+ rB = rY + rCb*D4;
+ rG = rY - rCb*D6 - rCr*D5;
+ eR = R - CLAMP(rR,0,255);
+ eG = G - CLAMP(rG,0,255);
+ eB = B - CLAMP(rB,0,255);
+ if (abs(eR) > 1 || abs(eG) > 1 || abs(eB) > 1) {
+ printf("R %u G %u B %u", R, G, B);
+ printf(" Y %g Cb %g Cr %g", Y, Cb, Cr);
+ printf(" iY %u iCb %u iCr %u", iY, iCb, iCr);
+ printf("\n -> Y %g Cb %g Cr %g", rY, rCb, rCr);
+ printf(" R %g (%u) G %g (%u) B %g (%u) E=[%d %d %d])\n"
+ , rR, CLAMP(rR,0,255)
+ , rG, CLAMP(rG,0,255)
+ , rB, CLAMP(rB,0,255)
+ , eR, eG, eB
+ );
+ }
+ eRtotal += eR;
+ eGtotal += eG;
+ eBtotal += eB;
+ AbseRtotal += abs(eR);
+ AbseGtotal += abs(eG);
+ AbseBtotal += abs(eB);
+ if (eR | eG | eB)
+ eCodes++;
+ eBits += abs(eR) + abs(eG) + abs(eB);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */