]> granicus.if.org Git - libjpeg-turbo/commitdiff
Implement lossless crop feature from jpeg v7 and v8
authorDRC <dcommander@users.sourceforge.net>
Sun, 10 Oct 2010 02:15:56 +0000 (02:15 +0000)
committerDRC <dcommander@users.sourceforge.net>
Sun, 10 Oct 2010 02:15:56 +0000 (02:15 +0000)
git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@243 632fc199-4ca6-4c93-a231-07263d6284db

1  2 
Makefile.am
jcmarker.c
jcmaster.c
jerror.h
jpegcomp.h
jpegtran.1
jpegtran.c
testimgcrop.jpg
transupp.c

diff --cc Makefile.am
index 7a87d77f857dd26dc7fd41e9050d5d223cd1fcce,42cff57f7bc7629dd3e5c3574a58d91f59c9ea0b..ac8e65c33387e7e2167f5868569243d9ff62698f
 -## Process this file with automake to produce Makefile.in
 -#
 -#  Automake Makefile for the JPEG library
 -#
 -#  This file is written by Bob Friesenhahn, Guido Vollbeding
 -#
 -
 -# Sources to build library
 -LIBSOURCES = jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
 -        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
 -        jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
 -        jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
 -        jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
 -        jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
 -        jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
 -        jquant2.c jutils.c jmemmgr.c @MEMORYMGR@.c
 -
 -# System dependent sources
 -SYSDEPSOURCES = jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
 -
 -# Headers which are installed to support the library
 -INSTINCLUDES  = jerror.h jmorecfg.h jpeglib.h
 -
 -# Headers which are not installed
 -OTHERINCLUDES = cderror.h cdjpeg.h jdct.h jinclude.h jmemsys.h jpegint.h \
 -        jversion.h transupp.h
 -
 -# Manual pages (Automake uses 'MANS' for itself)
 -DISTMANS= cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
 -
 -# Other documentation files
 -DOCS= README install.txt usage.txt wizard.txt example.c libjpeg.txt \
 -        structure.txt coderules.txt filelist.txt change.log
 -
 -# Makefiles for various systems
 -MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
 -        makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
 -        makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
 -        makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
 -        maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
 -        makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
 -        makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
 -        makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
 -        makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
 -        makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
 -        makefile.mms makefile.vms makvms.opt
 -
 -# Configuration files
 -CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
 -        jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
 -        jconfig.vms
 -
 -# Support scripts for configure
 -CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
 -
 -# Miscellaneous support files
 -OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
 -        libjpeg.map
 -
 -# Test support files
 -TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
 -        testimgp.jpg
 -
 -# libtool libraries to build
 -lib_LTLIBRARIES = libjpeg.la
 -
 -# Library sources for libjpeg.la
 -libjpeg_la_SOURCES = $(LIBSOURCES)
 -
 -# LDFLAGS for libjpeg.la
 -libjpeg_la_LDFLAGS = -no-undefined \
 -        -version-info $(JPEG_LIB_VERSION)
 -
 -if HAVE_LD_VERSION_SCRIPT
 -  libjpeg_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libjpeg.map
 +lib_LTLIBRARIES = libjpeg.la libturbojpeg.la
 +libjpeg_la_LDFLAGS = -version-info ${JPEG_LIB_VERSION} -no-undefined
 +libturbojpeg_la_LDFLAGS = -avoid-version -no-undefined
 +include_HEADERS = jerror.h jmorecfg.h jpeglib.h turbojpeg.h
 +nodist_include_HEADERS = jconfig.h
 +
 +HDRS = jchuff.h jdct.h jdhuff.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
 +      jpegint.h jpeglib.h jversion.h jsimd.h jsimddct.h
 +
 +libjpeg_la_SOURCES = $(HDRS) jcapimin.c jcapistd.c jccoefct.c jccolor.c \
 +      jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
 +      jcomapi.c jcparam.c jcphuff.c jcprepct.c jcsample.c jctrans.c \
 +      jdapimin.c jdapistd.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
 +      jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
 +      jdmerge.c jdphuff.c jdpostct.c jdsample.c jdtrans.c jerror.c \
 +      jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c \
 +      jidctred.c jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c
 +
 +libturbojpeg_la_SOURCES = $(libjpeg_la_SOURCES) turbojpegl.c turbojpeg.h \
 +      turbojpeg-mapfile
 +
 +if VERSION_SCRIPT
 +
 +libturbojpeg_la_LDFLAGS += $(VERSION_SCRIPT_FLAG)$(srcdir)/turbojpeg-mapfile
 +
  endif
  
 -# Executables to build
 +if WITH_SIMD
 +
 +SUBDIRS = simd
 +libjpeg_la_LIBADD = simd/libsimd.la
 +libturbojpeg_la_LIBADD = simd/libsimd.la
 +
 +else
 +
 +libjpeg_la_SOURCES += jsimd_none.c
 +
 +endif
 +
 +TSTHDRS = rrutil.h rrtimer.h
 +
  bin_PROGRAMS = cjpeg djpeg jpegtran rdjpgcom wrjpgcom
 +noinst_PROGRAMS = jpgtest jpegut
 +
 +jpgtest_SOURCES = $(TSTHDRS) jpgtest.cxx bmp.h bmp.c
 +
 +jpgtest_LDADD = libturbojpeg.la
 +
 +jpegut_SOURCES = $(TSTHDRS) jpegut.c bmp.h bmp.c
 +
 +jpegut_LDADD = libturbojpeg.la
 +
 +cjpeg_SOURCES = cdjpeg.h cderror.h cdjpeg.c cjpeg.c rdbmp.c rdgif.c \
 +      rdppm.c rdswitch.c rdtarga.c 
 +
 +cjpeg_LDADD = libjpeg.la
 +
 +cjpeg_CFLAGS = -DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED \
 +      -DTARGA_SUPPORTED
 +
 +djpeg_SOURCES = cdjpeg.h cderror.h cdjpeg.c djpeg.c rdcolmap.c rdswitch.c \
 +      wrbmp.c wrgif.c wrppm.c wrtarga.c
 +
 +djpeg_LDADD = libjpeg.la
 +
 +djpeg_CFLAGS = -DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED \
 +      -DTARGA_SUPPORTED
 +
 +jpegtran_SOURCES = jpegtran.c rdswitch.c cdjpeg.c transupp.c transupp.h
 +
 +jpegtran_LDADD = libjpeg.la
  
 -# Executable sources & libs
 -cjpeg_SOURCES    = cjpeg.c rdppm.c rdgif.c rdtarga.c rdrle.c rdbmp.c \
 -        rdswitch.c cdjpeg.c
 -cjpeg_LDADD      = libjpeg.la
 -djpeg_SOURCES    = djpeg.c wrppm.c wrgif.c wrtarga.c wrrle.c wrbmp.c \
 -        rdcolmap.c cdjpeg.c
 -djpeg_LDADD      = libjpeg.la
 -jpegtran_SOURCES = jpegtran.c rdswitch.c cdjpeg.c transupp.c
 -jpegtran_LDADD   = libjpeg.la
  rdjpgcom_SOURCES = rdjpgcom.c
 +
 +rdjpgcom_LDADD = libjpeg.la
 +
  wrjpgcom_SOURCES = wrjpgcom.c
  
 -# Manual pages to install
 -man_MANS = $(DISTMANS)
 +wrjpgcom_LDADD = libjpeg.la
  
 -# Headers to install
 -include_HEADERS = $(INSTINCLUDES)
  
 -# Other distributed headers
 -noinst_HEADERS = $(OTHERINCLUDES)
 +dist_man1_MANS = cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
  
 -# Other distributed files
 -EXTRA_DIST =  $(DOCS) $(DISTMANS) $(MKFILES) $(CONFIGFILES) $(SYSDEPSOURCES) \
 -        $(OTHERFILES) $(TESTFILES)
 +DOCS= README install.doc usage.doc wizard.doc example.c libjpeg.doc \
 +      structure.doc coderules.doc filelist.doc jconfig.doc change.log \
 +      README-turbo.txt rdrle.c wrrle.c LICENSE.txt LGPL.txt BUILDING.txt \
 +      ChangeLog.txt
  
 -# Files to be cleaned
 -CLEANFILES = testout.ppm testout.bmp testout.jpg testoutp.ppm testoutp.jpg \
 -        testoutt.jpg
 +TESTFILES= testorig.jpg testorig.ppm testimg.bmp testimgflt.jpg \
 +      testimgfst.jpg testimgint.jpg testimgp.jpg testimgflt.ppm testimgfst.ppm \
 +      testimgint.ppm testimgflt-nosimd.jpg
  
 -# Install jconfig.h
 -install-data-local:
 -      $(mkinstalldirs) $(DESTDIR)$(includedir)
 -      $(INSTALL_HEADER) jconfig.h $(DESTDIR)$(includedir)/jconfig.h
 +EXTRA_DIST = win release $(DOCS) $(TESTFILES)
  
 -# Uninstall jconfig.h
 -uninstall-local:
 -      rm -f $(DESTDIR)$(includedir)/jconfig.h
 +dist-hook:
 +      rm -rf `find $(distdir) -name .svn`
  
 -# Run tests
 -test: check-local
 -check-local:
 -      rm -f testout*
 -      ./djpeg -dct int -ppm -outfile testout.ppm  $(srcdir)/testorig.jpg
 +
 +if WITH_SIMD
 +
 +test: testclean all
 +      ./jpegut
 +      ./cjpeg -dct int -outfile testoutint.jpg $(srcdir)/testorig.ppm
 +      ./cjpeg -dct fast -opt -outfile testoutfst.jpg $(srcdir)/testorig.ppm
 +      ./cjpeg -dct float -outfile testoutflt.jpg $(srcdir)/testorig.ppm
 +      cmp $(srcdir)/testimgint.jpg testoutint.jpg
 +      cmp $(srcdir)/testimgfst.jpg testoutfst.jpg
 +      cmp $(srcdir)/testimgflt.jpg testoutflt.jpg
 +      ./djpeg -dct int -fast -ppm -outfile testoutint.ppm $(srcdir)/testorig.jpg
 +      ./djpeg -dct fast -ppm -outfile testoutfst.ppm $(srcdir)/testorig.jpg
 +      ./djpeg -dct float -ppm -outfile testoutflt.ppm $(srcdir)/testorig.jpg
 +      cmp $(srcdir)/testimgint.ppm testoutint.ppm
 +      cmp $(srcdir)/testimgfst.ppm testoutfst.ppm
 +      cmp $(srcdir)/testimgflt.ppm testoutflt.ppm
 +      ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp  $(srcdir)/testorig.jpg
 +      cmp $(srcdir)/testimg.bmp testout.bmp
 +      ./cjpeg -dct int -progressive -outfile testoutp.jpg $(srcdir)/testorig.ppm
 +      cmp $(srcdir)/testimgp.jpg testoutp.jpg
 +      ./jpegtran -outfile testoutt.jpg testoutp.jpg
 +      cmp $(srcdir)/testimgint.jpg testoutt.jpg
++      ./jpegtran -crop 100x100+10+10 -transpose -perfect -outfile testoutcrop.jpg $(srcdir)/testorig.jpg
++      cmp $(srcdir)/testimgcrop.jpg testoutcrop.jpg
 +
 +else
 +
 +test: testclean all
 +      ./jpegut
 +      ./cjpeg -dct int -outfile testoutint.jpg $(srcdir)/testorig.ppm
 +      ./cjpeg -dct fast -opt -outfile testoutfst.jpg $(srcdir)/testorig.ppm
 +      ./cjpeg -dct float -outfile testoutflt.jpg $(srcdir)/testorig.ppm
 +      cmp $(srcdir)/testimgint.jpg testoutint.jpg
 +      cmp $(srcdir)/testimgfst.jpg testoutfst.jpg
 +      cmp $(srcdir)/testimgflt-nosimd.jpg testoutflt.jpg
 +      ./djpeg -dct int -fast -ppm -outfile testoutint.ppm $(srcdir)/testorig.jpg
 +      ./djpeg -dct fast -ppm -outfile testoutfst.ppm $(srcdir)/testorig.jpg
 +      ./djpeg -dct float -ppm -outfile testoutflt.ppm $(srcdir)/testorig.jpg
 +      cmp $(srcdir)/testimgint.ppm testoutint.ppm
 +      cmp $(srcdir)/testimgfst.ppm testoutfst.ppm
 +      cmp $(srcdir)/testorig.ppm testoutflt.ppm
        ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp  $(srcdir)/testorig.jpg
 -      ./cjpeg -dct int -outfile testout.jpg  $(srcdir)/testimg.ppm
 -      ./djpeg -dct int -ppm -outfile testoutp.ppm $(srcdir)/testprog.jpg
 -      ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg $(srcdir)/testimg.ppm
 -      ./jpegtran -outfile testoutt.jpg $(srcdir)/testprog.jpg
 -      cmp $(srcdir)/testimg.ppm testout.ppm
        cmp $(srcdir)/testimg.bmp testout.bmp
 -      cmp $(srcdir)/testimg.jpg testout.jpg
 -      cmp $(srcdir)/testimg.ppm testoutp.ppm
 +      ./cjpeg -dct int -progressive -outfile testoutp.jpg $(srcdir)/testorig.ppm
        cmp $(srcdir)/testimgp.jpg testoutp.jpg
 -      cmp $(srcdir)/testorig.jpg testoutt.jpg
 +      ./jpegtran -outfile testoutt.jpg testoutp.jpg
 +      cmp $(srcdir)/testimgint.jpg testoutt.jpg
++      ./jpegtran -crop 100x100+10+10 -transpose -perfect -outfile testoutcrop.jpg $(srcdir)/testorig.jpg
++      cmp $(srcdir)/testimgcrop.jpg testoutcrop.jpg
 +
 +endif
 +
 +testclean:
 +      rm -f testout*
 +      rm -f *_GRAYQ[0-9]*.bmp
 +      rm -f *_GRAYQ[0-9]*.ppm
 +      rm -f *_GRAYQ[0-9]*.jpg
 +      rm -f *_420Q[0-9]*.bmp
 +      rm -f *_420Q[0-9]*.ppm
 +      rm -f *_420Q[0-9]*.jpg
 +      rm -f *_422Q[0-9]*.bmp
 +      rm -f *_422Q[0-9]*.ppm
 +      rm -f *_422Q[0-9]*.jpg
 +      rm -f *_444Q[0-9]*.bmp
 +      rm -f *_444Q[0-9]*.ppm
 +      rm -f *_444Q[0-9]*.jpg
 +
 +rpm: all
 +      sh $(srcdir)/release/makerpm ${PACKAGE_NAME} ${VERSION} ${BUILD} \
 +              ${RPMARCH} ${srcdir}
 +
 +srpm: dist-gzip
 +      sh $(srcdir)/release/makesrpm ${PACKAGE_NAME} ${VERSION} ${BUILD} ${srcdir}
 +
 +deb: all
 +      sh $(srcdir)/release/makedpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} \
 +              ${DEBARCH} ${srcdir}
 +
 +if X86_64
 +
 +udmg: all
 +      sh $(srcdir)/release/makemacpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} \
 +              ${srcdir} universal
 +
 +endif
 +
 +dmg: all
 +      sh $(srcdir)/release/makemacpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} ${srcdir}
 +
 +if X86_64
 +
 +sunpkg: all
 +      sh $(srcdir)/release/makesunpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} \
 +              ${DEBARCH} ${srcdir} $(CC) $(CXX) combined
 +
 +nsi: all
 +      makensis -nocd -DVERSION=$(VERSION) -DAPPNAME=libjpeg-turbo-gcc64 \
 +              -DWLIBDIR=.libs -DWSRCDIR=$(srcdir) -DWBLDDIR=. -DWHDRDIR=. -DWIN64 \
 +              -DPLATFORM="GCC 64-bit" -DGCC $(srcdir)/release/libjpeg-turbo.nsi
 +
 +else
 +
 +sunpkg: all
 +      sh $(srcdir)/release/makesunpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} \
 +              ${DEBARCH} ${srcdir} $(CC) $(CXX)
 +
 +nsi: all
 +      makensis -nocd -DVERSION=$(VERSION) -DAPPNAME=libjpeg-turbo-gcc \
 +              -DWLIBDIR=.libs -DWSRCDIR=$(srcdir) -DWBLDDIR=. -DWHDRDIR=. \
 +              -DPLATFORM="GCC" -DGCC $(srcdir)/release/libjpeg-turbo.nsi
 +
 +endif
 +
 +cygwinpkg: all
 +      sh $(srcdir)/release/makecygwinpkg ${PACKAGE_NAME} ${VERSION} ${srcdir}
diff --cc jcmarker.c
index 3d1e6c6d524850e0d401fcec9f590d5648d13ee7,2e2898342459eac79e3e6c8b6a4681c93d09bcfb..b1c1e4581e5c6c566563894197fd493dc5f0dd6a
@@@ -2,6 -2,7 +2,7 @@@
   * jcmarker.c
   *
   * Copyright (C) 1991-1998, Thomas G. Lane.
 - * Modified 2003-2009 by Guido Vollbeding.
++ * Copyright (C) 2010, D. R. Commander.
   * This file is part of the Independent JPEG Group's software.
   * For conditions of distribution and use, see the accompanying README file.
   *
@@@ -11,6 -12,6 +12,7 @@@
  #define JPEG_INTERNALS
  #include "jinclude.h"
  #include "jpeglib.h"
++#include "jpegcomp.h"
  
  
  typedef enum {                        /* JPEG marker codes */
@@@ -285,13 -291,13 +287,13 @@@ emit_sof (j_compress_ptr cinfo, JPEG_MA
    emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
  
    /* Make sure image isn't bigger than SOF field can handle */
-   if ((long) cinfo->image_height > 65535L ||
-       (long) cinfo->image_width > 65535L)
 -  if ((long) cinfo->jpeg_height > 65535L ||
 -      (long) cinfo->jpeg_width > 65535L)
++  if ((long) cinfo->_jpeg_height > 65535L ||
++      (long) cinfo->_jpeg_width > 65535L)
      ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
  
    emit_byte(cinfo, cinfo->data_precision);
-   emit_2bytes(cinfo, (int) cinfo->image_height);
-   emit_2bytes(cinfo, (int) cinfo->image_width);
 -  emit_2bytes(cinfo, (int) cinfo->jpeg_height);
 -  emit_2bytes(cinfo, (int) cinfo->jpeg_width);
++  emit_2bytes(cinfo, (int) cinfo->_jpeg_height);
++  emit_2bytes(cinfo, (int) cinfo->_jpeg_width);
  
    emit_byte(cinfo, cinfo->num_components);
  
diff --cc jcmaster.c
index cf4e61422679e888f73c00abca50e2b831659692,660883f459a26fa488f109c4568b55db0f8fbd60..74df5556ce2d38a0c246a1f16bf3be891b6f0704
@@@ -16,6 -15,6 +16,7 @@@
  #define JPEG_INTERNALS
  #include "jinclude.h"
  #include "jpeglib.h"
++#include "jpegcomp.h"
  
  
  /* Private state */
@@@ -65,26 -216,27 +66,27 @@@ jpeg_calc_jpeg_dimensions (j_compress_p
  
  
  LOCAL(void)
- initial_setup (j_compress_ptr cinfo)
+ initial_setup (j_compress_ptr cinfo, boolean transcode_only)
  /* Do computations that are needed before master selection phase */
  {
 -  int ci, ssize;
 +  int ci;
    jpeg_component_info *compptr;
    long samplesperrow;
    JDIMENSION jd_samplesperrow;
  
 -  if (transcode_only)
 -    jpeg_calc_trans_dimensions(cinfo);
 -  else
 +#if JPEG_LIB_VERSION >= 70
-   jpeg_calc_jpeg_dimensions(cinfo);
++  if (!transcode_only)
+     jpeg_calc_jpeg_dimensions(cinfo);
 +#endif
  
    /* Sanity check on image dimensions */
-   if (cinfo->image_height <= 0 || cinfo->image_width <= 0
 -  if (cinfo->jpeg_height <= 0 || cinfo->jpeg_width <= 0 ||
 -      cinfo->num_components <= 0 || cinfo->input_components <= 0)
++  if (cinfo->_jpeg_height <= 0 || cinfo->_jpeg_width <= 0
 +      || cinfo->num_components <= 0 || cinfo->input_components <= 0)
      ERREXIT(cinfo, JERR_EMPTY_IMAGE);
  
    /* Make sure image isn't bigger than I can handle */
-   if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
-       (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
 -  if ((long) cinfo->jpeg_height > (long) JPEG_MAX_DIMENSION ||
 -      (long) cinfo->jpeg_width > (long) JPEG_MAX_DIMENSION)
++  if ((long) cinfo->_jpeg_height > (long) JPEG_MAX_DIMENSION ||
++      (long) cinfo->_jpeg_width > (long) JPEG_MAX_DIMENSION)
      ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
  
    /* Width of an input scanline must be representable as JDIMENSION. */
         ci++, compptr++) {
      /* Fill in the correct component_index value; don't rely on application */
      compptr->component_index = ci;
 -    /* In selecting the actual DCT scaling for each component, we try to
 -     * scale down the chroma components via DCT scaling rather than downsampling.
 -     * This saves time if the downsampler gets to use 1:1 scaling.
 -     * Note this code adapts subsampling ratios which are powers of 2.
 -     */
 -    ssize = 1;
 -#ifdef DCT_SCALING_SUPPORTED
 -    while (cinfo->min_DCT_h_scaled_size * ssize <=
 -         (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
 -         (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) {
 -      ssize = ssize * 2;
 -    }
 -#endif
 -    compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;
 -    ssize = 1;
 -#ifdef DCT_SCALING_SUPPORTED
 -    while (cinfo->min_DCT_v_scaled_size * ssize <=
 -         (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
 -         (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) {
 -      ssize = ssize * 2;
 -    }
 +    /* For compression, we never do DCT scaling. */
 +#if JPEG_LIB_VERSION >= 70
 +    compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = DCTSIZE;
 +#else
 +    compptr->DCT_scaled_size = DCTSIZE;
  #endif
 -    compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;
 -
 -    /* We don't support DCT ratios larger than 2. */
 -    if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)
 -      compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;
 -    else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)
 -      compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;
 -
      /* Size in DCT blocks */
      compptr->width_in_blocks = (JDIMENSION)
-       jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
 -      jdiv_round_up((long) cinfo->jpeg_width * (long) compptr->h_samp_factor,
 -                  (long) (cinfo->max_h_samp_factor * cinfo->block_size));
++      jdiv_round_up((long) cinfo->_jpeg_width * (long) compptr->h_samp_factor,
 +                  (long) (cinfo->max_h_samp_factor * DCTSIZE));
      compptr->height_in_blocks = (JDIMENSION)
-       jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
 -      jdiv_round_up((long) cinfo->jpeg_height * (long) compptr->v_samp_factor,
 -                  (long) (cinfo->max_v_samp_factor * cinfo->block_size));
++      jdiv_round_up((long) cinfo->_jpeg_height * (long) compptr->v_samp_factor,
 +                  (long) (cinfo->max_v_samp_factor * DCTSIZE));
      /* Size in samples */
      compptr->downsampled_width = (JDIMENSION)
-       jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
 -      jdiv_round_up((long) cinfo->jpeg_width *
 -                  (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),
 -                  (long) (cinfo->max_h_samp_factor * cinfo->block_size));
++      jdiv_round_up((long) cinfo->_jpeg_width * (long) compptr->h_samp_factor,
 +                  (long) cinfo->max_h_samp_factor);
      compptr->downsampled_height = (JDIMENSION)
-       jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
 -      jdiv_round_up((long) cinfo->jpeg_height *
 -                  (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),
 -                  (long) (cinfo->max_v_samp_factor * cinfo->block_size));
++      jdiv_round_up((long) cinfo->_jpeg_height * (long) compptr->v_samp_factor,
 +                  (long) cinfo->max_v_samp_factor);
      /* Mark component needed (this flag isn't actually used for compression) */
      compptr->component_needed = TRUE;
    }
     * main controller will call coefficient controller).
     */
    cinfo->total_iMCU_rows = (JDIMENSION)
-     jdiv_round_up((long) cinfo->image_height,
 -    jdiv_round_up((long) cinfo->jpeg_height,
 -                (long) (cinfo->max_v_samp_factor * cinfo->block_size));
++    jdiv_round_up((long) cinfo->_jpeg_height,
 +                (long) (cinfo->max_v_samp_factor*DCTSIZE));
  }
  
  
@@@ -377,11 -591,11 +379,11 @@@ per_scan_setup (j_compress_ptr cinfo
      
      /* Overall image size in MCUs */
      cinfo->MCUs_per_row = (JDIMENSION)
-       jdiv_round_up((long) cinfo->image_width,
 -      jdiv_round_up((long) cinfo->jpeg_width,
 -                  (long) (cinfo->max_h_samp_factor * cinfo->block_size));
++      jdiv_round_up((long) cinfo->_jpeg_width,
 +                  (long) (cinfo->max_h_samp_factor*DCTSIZE));
      cinfo->MCU_rows_in_scan = (JDIMENSION)
-       jdiv_round_up((long) cinfo->image_height,
 -      jdiv_round_up((long) cinfo->jpeg_height,
 -                  (long) (cinfo->max_v_samp_factor * cinfo->block_size));
++      jdiv_round_up((long) cinfo->_jpeg_height,
 +                  (long) (cinfo->max_v_samp_factor*DCTSIZE));
      
      cinfo->blocks_in_MCU = 0;
      
diff --cc jerror.h
index fc2fffeac297bcee557400beefb7b6ce790e79a7,1cfb2b19d85cd86bcccf975fcd037ba26e585f92..edbe9034bf915ff5e303e9d1c91a472b00ef8552
+++ b/jerror.h
@@@ -45,8 -44,11 +46,9 @@@ JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TY
  JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
  JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
  JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
+ JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
  JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
 -JMESSAGE(JERR_BAD_DCTSIZE, "DCT scaled block size %dx%d not supported")
 -JMESSAGE(JERR_BAD_DROP_SAMPLING,
 -       "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
 +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
  JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
  JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
  JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
diff --cc jpegcomp.h
index be5eb34a78ef50cbfa4f8b4b9bd6a83581547e25,0000000000000000000000000000000000000000..1b9e0a4fac4ea3e488b5238c504023af38c246cc
mode 100644,000000..100644
--- /dev/null
@@@ -1,18 -1,0 +1,26 @@@
 +/*
 + * jpegcomp.h
 + *
 + * Copyright (C) 2010, D. R. Commander
 + * For conditions of distribution and use, see the accompanying README file.
 + *
 + * JPEG compatibility macros
 + * These declarations are considered internal to the JPEG library; most
 + * applications using the library shouldn't need to include this file.
 + */
 +
 +#if JPEG_LIB_VERSION >= 70
 +#define _DCT_scaled_size DCT_h_scaled_size
 +#define _min_DCT_scaled_size min_DCT_h_scaled_size
++#define _min_DCT_h_scaled_size min_DCT_h_scaled_size
++#define _min_DCT_v_scaled_size min_DCT_v_scaled_size
++#define _jpeg_width jpeg_width
++#define _jpeg_height jpeg_height
 +#else
 +#define _DCT_scaled_size DCT_scaled_size
 +#define _min_DCT_scaled_size min_DCT_scaled_size
++#define _min_DCT_h_scaled_size min_DCT_scaled_size
++#define _min_DCT_v_scaled_size min_DCT_scaled_size
++#define _jpeg_width image_width
++#define _jpeg_height image_height
 +#endif
diff --cc jpegtran.1
index 6de18e2af960b0cb346ea1d4fd38002f3817460b,0ad1bbc84122849fece2351c77a80c35aa643cd3..355e4dadca3577b83c3b0ed8f92fd3a085949e89
@@@ -227,11 -274,11 +258,13 @@@ Communications of the ACM, April 1991 (
  .SH AUTHOR
  Independent JPEG Group
  .SH BUGS
 +Arithmetic coding is not supported for legal reasons.
 +.PP
  The transform options can't transform odd-size images perfectly.  Use
  .B \-trim
- if you don't like the results without it.
+ or
+ .B \-perfect
+ if you don't like the results.
  .PP
  The entire image is read into memory and then written out again, even in
  cases where this isn't really necessary.  Expect swapping on large images,
diff --cc jpegtran.c
index 20ef111b3f563539eba0cea2f0d5327e440b7b00,8cb3d807fbb977a64b4d3cb7c6fbe6b053d37b26..326973c97e203bcae094b9d493d3b05a7a62207c
@@@ -62,11 -63,16 +62,15 @@@ usage (void
  #ifdef C_PROGRESSIVE_SUPPORTED
    fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
  #endif
- #if TRANSFORMS_SUPPORTED
    fprintf(stderr, "Switches for modifying the image:\n");
+ #if TRANSFORMS_SUPPORTED
+   fprintf(stderr, "  -crop WxH+X+Y  Crop to a rectangular subarea\n");
    fprintf(stderr, "  -grayscale     Reduce to grayscale (omit color data)\n");
    fprintf(stderr, "  -flip [horizontal|vertical]  Mirror image (left-right or top-bottom)\n");
+   fprintf(stderr, "  -perfect       Fail if there is non-transformable edge blocks\n");
    fprintf(stderr, "  -rotate [90|180|270]         Rotate image (degrees clockwise)\n");
 -  fprintf(stderr, "  -scale M/N     Scale output image by fraction M/N, eg, 1/8\n");
+ #endif
+ #if TRANSFORMS_SUPPORTED
    fprintf(stderr, "  -transpose     Transpose image\n");
    fprintf(stderr, "  -transverse    Transverse transpose image\n");
    fprintf(stderr, "  -trim          Drop non-transformable edge blocks\n");
@@@ -130,10 -136,13 +134,12 @@@ parse_switches (j_compress_ptr cinfo, i
    /* Set up default JPEG parameters. */
    simple_progressive = FALSE;
    outfilename = NULL;
 -  scaleoption = NULL;
    copyoption = JCOPYOPT_DEFAULT;
    transformoption.transform = JXFORM_NONE;
+   transformoption.perfect = FALSE;
    transformoption.trim = FALSE;
    transformoption.force_grayscale = FALSE;
+   transformoption.crop = FALSE;
    cinfo->err->trace_level = 0;
  
    /* Scan command line options, adjust parameters */
diff --cc testimgcrop.jpg
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1e69c3ae96f1d6bb599644f1e45afac624638658
new file mode 100644 (file)
Binary files differ
diff --cc transupp.c
index 8c3857d3ba930483a52ed1d49b039a248183e9fd,4060544828ecc5c462f982f8b2c75fb19093bde7..0954715e30c73119bcbfe4912353c5ddbdd0342b
@@@ -2,6 -2,6 +2,7 @@@
   * transupp.c
   *
   * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding.
++ * Copyright (C) 2010, D. R. Commander.
   * This file is part of the Independent JPEG Group's software.
   * For conditions of distribution and use, see the accompanying README file.
   *
  #include "jinclude.h"
  #include "jpeglib.h"
  #include "transupp.h"         /* My own external interface */
++#include "jpegcomp.h"
+ #include <ctype.h>            /* to declare isdigit() */
++#if JPEG_LIB_VERSION >= 70
++#define dstinfo_min_DCT_h_scaled_size dstinfo->min_DCT_h_scaled_size
++#define dstinfo_min_DCT_v_scaled_size dstinfo->min_DCT_v_scaled_size
++#else
++#define dstinfo_min_DCT_h_scaled_size DCTSIZE
++#define dstinfo_min_DCT_v_scaled_size DCTSIZE
++#endif
 +
 +
  #if TRANSFORMS_SUPPORTED
  
  /*
@@@ -79,7 -133,8 +144,8 @@@ do_flip_h_no_crop (j_decompress_ptr src
     * mirroring by changing the signs of odd-numbered columns.
     * Partial iMCUs at the right edge are left untouched.
     */
-   MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
+   MCU_cols = srcinfo->output_width /
 -    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
++    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
  
    for (ci = 0; ci < dstinfo->num_components; ci++) {
      compptr = dstinfo->comp_info + ci;
            *ptr2++ = -temp1;
          }
        }
 -    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
+       if (x_crop_blocks > 0) {
+         /* Now left-justify the portion of the data to be kept.
+          * We can't use a single jcopy_block_row() call because that routine
+          * depends on memcpy(), whose behavior is unspecified for overlapping
+          * source and destination areas.  Sigh.
+          */
+         for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
+           jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
+                           buffer[offset_y] + blk_x,
+                           (JDIMENSION) 1);
+         }
+       }
+       }
+     }
+   }
+ }
+ LOCAL(void)
+ do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+          JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+          jvirt_barray_ptr *src_coef_arrays,
+          jvirt_barray_ptr *dst_coef_arrays)
+ /* Horizontal flip in general cropping case */
+ {
+   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+   JDIMENSION x_crop_blocks, y_crop_blocks;
+   int ci, k, offset_y;
+   JBLOCKARRAY src_buffer, dst_buffer;
+   JBLOCKROW src_row_ptr, dst_row_ptr;
+   JCOEFPTR src_ptr, dst_ptr;
+   jpeg_component_info *compptr;
+   /* Here we must output into a separate array because we can't touch
+    * different rows of a single virtual array simultaneously.  Otherwise,
+    * this is essentially the same as the routine above.
+    */
+   MCU_cols = srcinfo->output_width /
++    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+   for (ci = 0; ci < dstinfo->num_components; ci++) {
+     compptr = dstinfo->comp_info + ci;
+     comp_width = MCU_cols * compptr->h_samp_factor;
+     x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+     y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+        dst_blk_y += compptr->v_samp_factor) {
+       dst_buffer = (*srcinfo->mem->access_virt_barray)
+       ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+        (JDIMENSION) compptr->v_samp_factor, TRUE);
+       src_buffer = (*srcinfo->mem->access_virt_barray)
+       ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+        dst_blk_y + y_crop_blocks,
+        (JDIMENSION) compptr->v_samp_factor, FALSE);
+       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+       dst_row_ptr = dst_buffer[offset_y];
+       src_row_ptr = src_buffer[offset_y];
+       for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+         if (x_crop_blocks + dst_blk_x < comp_width) {
+           /* Do the mirrorable blocks */
+           dst_ptr = dst_row_ptr[dst_blk_x];
+           src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
+           /* this unrolled loop doesn't need to know which row it's on... */
+           for (k = 0; k < DCTSIZE2; k += 2) {
+             *dst_ptr++ = *src_ptr++;   /* copy even column */
+             *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
+           }
+         } else {
+           /* Copy last partial block(s) verbatim */
+           jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
+                           dst_row_ptr + dst_blk_x,
+                           (JDIMENSION) 1);
+         }
+       }
        }
      }
    }
@@@ -131,7 -264,8 +275,8 @@@ do_flip_v (j_decompress_ptr srcinfo, j_
     * of odd-numbered rows.
     * Partial iMCUs at the bottom edge are copied verbatim.
     */
-   MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+   MCU_rows = srcinfo->output_height /
 -    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
++    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
  
    for (ci = 0; ci < dstinfo->num_components; ci++) {
      compptr = dstinfo->comp_info + ci;
@@@ -246,7 -392,8 +403,8 @@@ do_rot_90 (j_decompress_ptr srcinfo, j_
     * at the (output) right edge properly.  They just get transposed and
     * not mirrored.
     */
-   MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
+   MCU_cols = srcinfo->output_height /
 -    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
++    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
  
    for (ci = 0; ci < dstinfo->num_components; ci++) {
      compptr = dstinfo->comp_info + ci;
@@@ -310,7 -473,8 +484,8 @@@ do_rot_270 (j_decompress_ptr srcinfo, j
     * at the (output) bottom edge properly.  They just get transposed and
     * not mirrored.
     */
-   MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+   MCU_rows = srcinfo->output_width /
 -    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
++    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
  
    for (ci = 0; ci < dstinfo->num_components; ci++) {
      compptr = dstinfo->comp_info + ci;
@@@ -371,8 -541,10 +552,10 @@@ do_rot_180 (j_decompress_ptr srcinfo, j
    JCOEFPTR src_ptr, dst_ptr;
    jpeg_component_info *compptr;
  
-   MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
-   MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+   MCU_cols = srcinfo->output_width /
 -    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
++    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+   MCU_rows = srcinfo->output_height /
 -    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
++    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
  
    for (ci = 0; ci < dstinfo->num_components; ci++) {
      compptr = dstinfo->comp_info + ci;
@@@ -475,8 -652,10 +663,10 @@@ do_transverse (j_decompress_ptr srcinfo
    JCOEFPTR src_ptr, dst_ptr;
    jpeg_component_info *compptr;
  
-   MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
-   MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+   MCU_cols = srcinfo->output_height /
 -    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
++    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+   MCU_rows = srcinfo->output_width /
 -    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
++    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
  
    for (ci = 0; ci < dstinfo->num_components; ci++) {
      compptr = dstinfo->comp_info + ci;
@@@ -568,69 -870,228 +881,233 @@@ GLOBAL(boolean
  jtransform_request_workspace (j_decompress_ptr srcinfo,
                              jpeg_transform_info *info)
  {
-   jvirt_barray_ptr *coef_arrays = NULL;
+   jvirt_barray_ptr *coef_arrays;
+   boolean need_workspace, transpose_it;
    jpeg_component_info *compptr;
-   int ci;
+   JDIMENSION xoffset, yoffset;
+   JDIMENSION width_in_iMCUs, height_in_iMCUs;
+   JDIMENSION width_in_blocks, height_in_blocks;
+   int ci, h_samp_factor, v_samp_factor;
  
+   /* Determine number of components in output image */
    if (info->force_grayscale &&
        srcinfo->jpeg_color_space == JCS_YCbCr &&
-       srcinfo->num_components == 3) {
+       srcinfo->num_components == 3)
      /* We'll only process the first component */
      info->num_components = 1;
-   } else {
+   else
      /* Process all the components */
      info->num_components = srcinfo->num_components;
 -        srcinfo->min_DCT_h_scaled_size,
 -        srcinfo->min_DCT_v_scaled_size,
+   /* Compute output image dimensions and related values. */
++#if JPEG_LIB_VERSION >= 80
+   jpeg_core_output_dimensions(srcinfo);
++#else
++  srcinfo->output_width = srcinfo->image_width;
++  srcinfo->output_height = srcinfo->image_height;
++#endif
+   /* Return right away if -perfect is given and transformation is not perfect.
+    */
+   if (info->perfect) {
+     if (info->num_components == 1) {
+       if (!jtransform_perfect_transform(srcinfo->output_width,
+         srcinfo->output_height,
 -        srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size,
 -        srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size,
++        srcinfo->_min_DCT_h_scaled_size,
++        srcinfo->_min_DCT_v_scaled_size,
+         info->transform))
+       return FALSE;
+     } else {
+       if (!jtransform_perfect_transform(srcinfo->output_width,
+         srcinfo->output_height,
++        srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size,
++        srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size,
+         info->transform))
+       return FALSE;
+     }
    }
  
 -      info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size;
 -      info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size;
+   /* If there is only one output component, force the iMCU size to be 1;
+    * else use the source iMCU size.  (This allows us to do the right thing
+    * when reducing color to grayscale, and also provides a handy way of
+    * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
+    */
+   switch (info->transform) {
+   case JXFORM_TRANSPOSE:
+   case JXFORM_TRANSVERSE:
+   case JXFORM_ROT_90:
+   case JXFORM_ROT_270:
+     info->output_width = srcinfo->output_height;
+     info->output_height = srcinfo->output_width;
+     if (info->num_components == 1) {
 -      srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
++      info->iMCU_sample_width = srcinfo->_min_DCT_v_scaled_size;
++      info->iMCU_sample_height = srcinfo->_min_DCT_h_scaled_size;
+     } else {
+       info->iMCU_sample_width =
 -      srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
++      srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
+       info->iMCU_sample_height =
 -      info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size;
 -      info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size;
++      srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
+     }
+     break;
+   default:
+     info->output_width = srcinfo->output_width;
+     info->output_height = srcinfo->output_height;
+     if (info->num_components == 1) {
 -      srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
++      info->iMCU_sample_width = srcinfo->_min_DCT_h_scaled_size;
++      info->iMCU_sample_height = srcinfo->_min_DCT_v_scaled_size;
+     } else {
+       info->iMCU_sample_width =
 -      srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
++      srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
+       info->iMCU_sample_height =
++      srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
+     }
+     break;
+   }
+   /* If cropping has been requested, compute the crop area's position and
+    * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
+    */
+   if (info->crop) {
+     /* Insert default values for unset crop parameters */
+     if (info->crop_xoffset_set == JCROP_UNSET)
+       info->crop_xoffset = 0; /* default to +0 */
+     if (info->crop_yoffset_set == JCROP_UNSET)
+       info->crop_yoffset = 0; /* default to +0 */
+     if (info->crop_xoffset >= info->output_width ||
+       info->crop_yoffset >= info->output_height)
+       ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+     if (info->crop_width_set == JCROP_UNSET)
+       info->crop_width = info->output_width - info->crop_xoffset;
+     if (info->crop_height_set == JCROP_UNSET)
+       info->crop_height = info->output_height - info->crop_yoffset;
+     /* Ensure parameters are valid */
+     if (info->crop_width <= 0 || info->crop_width > info->output_width ||
+       info->crop_height <= 0 || info->crop_height > info->output_height ||
+       info->crop_xoffset > info->output_width - info->crop_width ||
+       info->crop_yoffset > info->output_height - info->crop_height)
+       ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+     /* Convert negative crop offsets into regular offsets */
+     if (info->crop_xoffset_set == JCROP_NEG)
+       xoffset = info->output_width - info->crop_width - info->crop_xoffset;
+     else
+       xoffset = info->crop_xoffset;
+     if (info->crop_yoffset_set == JCROP_NEG)
+       yoffset = info->output_height - info->crop_height - info->crop_yoffset;
+     else
+       yoffset = info->crop_yoffset;
+     /* Now adjust so that upper left corner falls at an iMCU boundary */
+     info->output_width =
+       info->crop_width + (xoffset % info->iMCU_sample_width);
+     info->output_height =
+       info->crop_height + (yoffset % info->iMCU_sample_height);
+     /* Save x/y offsets measured in iMCUs */
+     info->x_crop_offset = xoffset / info->iMCU_sample_width;
+     info->y_crop_offset = yoffset / info->iMCU_sample_height;
+   } else {
+     info->x_crop_offset = 0;
+     info->y_crop_offset = 0;
+   }
+   /* Figure out whether we need workspace arrays,
+    * and if so whether they are transposed relative to the source.
+    */
+   need_workspace = FALSE;
+   transpose_it = FALSE;
    switch (info->transform) {
    case JXFORM_NONE:
+     if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
+       need_workspace = TRUE;
+     /* No workspace needed if neither cropping nor transforming */
+     break;
    case JXFORM_FLIP_H:
-     /* Don't need a workspace array */
+     if (info->trim)
+       trim_right_edge(info, srcinfo->output_width);
+     if (info->y_crop_offset != 0)
+       need_workspace = TRUE;
+     /* do_flip_h_no_crop doesn't need a workspace array */
      break;
    case JXFORM_FLIP_V:
-   case JXFORM_ROT_180:
-     /* Need workspace arrays having same dimensions as source image.
-      * Note that we allocate arrays padded out to the next iMCU boundary,
-      * so that transform routines need not worry about missing edge blocks.
-      */
-     coef_arrays = (jvirt_barray_ptr *)
-       (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
-       SIZEOF(jvirt_barray_ptr) * info->num_components);
-     for (ci = 0; ci < info->num_components; ci++) {
-       compptr = srcinfo->comp_info + ci;
-       coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
-       ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
-        (JDIMENSION) jround_up((long) compptr->width_in_blocks,
-                               (long) compptr->h_samp_factor),
-        (JDIMENSION) jround_up((long) compptr->height_in_blocks,
-                               (long) compptr->v_samp_factor),
-        (JDIMENSION) compptr->v_samp_factor);
-     }
+     if (info->trim)
+       trim_bottom_edge(info, srcinfo->output_height);
+     /* Need workspace arrays having same dimensions as source image. */
+     need_workspace = TRUE;
      break;
    case JXFORM_TRANSPOSE:
+     /* transpose does NOT have to trim anything */
+     /* Need workspace arrays having transposed dimensions. */
+     need_workspace = TRUE;
+     transpose_it = TRUE;
+     break;
    case JXFORM_TRANSVERSE:
+     if (info->trim) {
+       trim_right_edge(info, srcinfo->output_height);
+       trim_bottom_edge(info, srcinfo->output_width);
+     }
+     /* Need workspace arrays having transposed dimensions. */
+     need_workspace = TRUE;
+     transpose_it = TRUE;
+     break;
    case JXFORM_ROT_90:
+     if (info->trim)
+       trim_right_edge(info, srcinfo->output_height);
+     /* Need workspace arrays having transposed dimensions. */
+     need_workspace = TRUE;
+     transpose_it = TRUE;
+     break;
+   case JXFORM_ROT_180:
+     if (info->trim) {
+       trim_right_edge(info, srcinfo->output_width);
+       trim_bottom_edge(info, srcinfo->output_height);
+     }
+     /* Need workspace arrays having same dimensions as source image. */
+     need_workspace = TRUE;
+     break;
    case JXFORM_ROT_270:
-     /* Need workspace arrays having transposed dimensions.
-      * Note that we allocate arrays padded out to the next iMCU boundary,
-      * so that transform routines need not worry about missing edge blocks.
-      */
+     if (info->trim)
+       trim_bottom_edge(info, srcinfo->output_width);
+     /* Need workspace arrays having transposed dimensions. */
+     need_workspace = TRUE;
+     transpose_it = TRUE;
+     break;
+   }
+   /* Allocate workspace if needed.
+    * Note that we allocate arrays padded out to the next iMCU boundary,
+    * so that transform routines need not worry about missing edge blocks.
+    */
+   if (need_workspace) {
      coef_arrays = (jvirt_barray_ptr *)
        (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
-       SIZEOF(jvirt_barray_ptr) * info->num_components);
+               SIZEOF(jvirt_barray_ptr) * info->num_components);
+     width_in_iMCUs = (JDIMENSION)
+       jdiv_round_up((long) info->output_width,
+                   (long) info->iMCU_sample_width);
+     height_in_iMCUs = (JDIMENSION)
+       jdiv_round_up((long) info->output_height,
+                   (long) info->iMCU_sample_height);
      for (ci = 0; ci < info->num_components; ci++) {
        compptr = srcinfo->comp_info + ci;
+       if (info->num_components == 1) {
+       /* we're going to force samp factors to 1x1 in this case */
+       h_samp_factor = v_samp_factor = 1;
+       } else if (transpose_it) {
+       h_samp_factor = compptr->v_samp_factor;
+       v_samp_factor = compptr->h_samp_factor;
+       } else {
+       h_samp_factor = compptr->h_samp_factor;
+       v_samp_factor = compptr->v_samp_factor;
+       }
+       width_in_blocks = width_in_iMCUs * h_samp_factor;
+       height_in_blocks = height_in_iMCUs * v_samp_factor;
        coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
        ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
-        (JDIMENSION) jround_up((long) compptr->height_in_blocks,
-                               (long) compptr->v_samp_factor),
-        (JDIMENSION) jround_up((long) compptr->width_in_blocks,
-                               (long) compptr->h_samp_factor),
-        (JDIMENSION) compptr->h_samp_factor);
+        width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
      }
-     break;
-   }
-   info->workspace_coef_arrays = coef_arrays;
+     info->workspace_coef_arrays = coef_arrays;
+   } else
+     info->workspace_coef_arrays = NULL;
+   return TRUE;
  }
  
  
@@@ -642,14 -1103,13 +1119,14 @@@ transpose_critical_parameters (j_compre
    int tblno, i, j, ci, itemp;
    jpeg_component_info *compptr;
    JQUANT_TBL *qtblptr;
-   JDIMENSION dtemp;
+   JDIMENSION jtemp;
    UINT16 qtemp;
  
-   /* Transpose basic image dimensions */
-   dtemp = dstinfo->image_width;
+   /* Transpose image dimensions */
+   jtemp = dstinfo->image_width;
    dstinfo->image_width = dstinfo->image_height;
-   dstinfo->image_height = dtemp;
+   dstinfo->image_height = jtemp;
 +#if JPEG_LIB_VERSION >= 70
    itemp = dstinfo->min_DCT_h_scaled_size;
    dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
    dstinfo->min_DCT_v_scaled_size = itemp;
@@@ -760,48 -1336,52 +1354,59 @@@ jtransform_adjust_parameters (j_decompr
        /* Sorry, can't do it */
        ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
      }
+   } else if (info->num_components == 1) {
+     /* For a single-component source, we force the destination sampling factors
+      * to 1x1, with or without force_grayscale.  This is useful because some
+      * decoders choke on grayscale images with other sampling factors.
+      */
+     dstinfo->comp_info[0].h_samp_factor = 1;
+     dstinfo->comp_info[0].v_samp_factor = 1;
    }
  
-   /* Correct the destination's image dimensions etc if necessary */
+   /* Correct the destination's image dimensions as necessary
+    * for rotate/flip, resize, and crop operations.
+    */
++#if JPEG_LIB_VERSION >= 70
+   dstinfo->jpeg_width = info->output_width;
+   dstinfo->jpeg_height = info->output_height;
++#else
++  dstinfo->image_width = info->output_width;
++  dstinfo->image_height = info->output_height;
++#endif
+   /* Transpose destination image parameters */
    switch (info->transform) {
-   case JXFORM_NONE:
-     /* Nothing to do */
-     break;
-   case JXFORM_FLIP_H:
-     if (info->trim)
-       trim_right_edge(dstinfo);
-     break;
-   case JXFORM_FLIP_V:
-     if (info->trim)
-       trim_bottom_edge(dstinfo);
-     break;
    case JXFORM_TRANSPOSE:
-     transpose_critical_parameters(dstinfo);
-     /* transpose does NOT have to trim anything */
-     break;
    case JXFORM_TRANSVERSE:
-     transpose_critical_parameters(dstinfo);
-     if (info->trim) {
-       trim_right_edge(dstinfo);
-       trim_bottom_edge(dstinfo);
-     }
-     break;
    case JXFORM_ROT_90:
-     transpose_critical_parameters(dstinfo);
-     if (info->trim)
-       trim_right_edge(dstinfo);
-     break;
-   case JXFORM_ROT_180:
-     if (info->trim) {
-       trim_right_edge(dstinfo);
-       trim_bottom_edge(dstinfo);
-     }
-     break;
    case JXFORM_ROT_270:
      transpose_critical_parameters(dstinfo);
-     if (info->trim)
-       trim_bottom_edge(dstinfo);
      break;
+   default:
+     break;
+   }
+   /* Adjust Exif properties */
+   if (srcinfo->marker_list != NULL &&
+       srcinfo->marker_list->marker == JPEG_APP0+1 &&
+       srcinfo->marker_list->data_length >= 6 &&
+       GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
+       GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
+       GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
+       GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
+       GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
+       GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
+     /* Suppress output of JFIF marker */
+     dstinfo->write_JFIF_header = FALSE;
++#if JPEG_LIB_VERSION >= 70
+     /* Adjust Exif image parameters */
+     if (dstinfo->jpeg_width != srcinfo->image_width ||
+       dstinfo->jpeg_height != srcinfo->image_height)
+       /* Align data segment to start of TIFF structure for parsing */
+       adjust_exif_parameters(srcinfo->marker_list->data + 6,
+       srcinfo->marker_list->data_length - 6,
+       dstinfo->jpeg_width, dstinfo->jpeg_height);
++#endif
    }
  
    /* Return the appropriate output data set */