[gs-commits] ghostpdl branch, master, updated. jbig2dec-0.14-2028-g321cf60

[email protected] (Robin Watts) Thu, 12 Dec 2019 17:37:42 +0000 (UTC)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
The ghostpdl branch, master has been updated
       via  321cf6026a05e31140a87cc83a2653b048550df4 (commit)
       via  b6f6adb5448fda1f33db4c92c030709618e4ee54 (commit)
       via  ae1cee743e56a7b654d9dbb2ea88ed90d48d298d (commit)
       via  ef66198ade77d5d551b3045cd36bed81c0b04f54 (commit)
       via  0c248ced8997dfe8f253a07fc6cc5f47837ca12e (commit)
      from  76bd0d75823a571130f340ab6231e064d1f997f7 (commit)

----------------------------------------------------------------------
commit 321cf6026a05e31140a87cc83a2653b048550df4
Author: Robin Watts <[email protected]>
Date:   Thu Dec 12 15:44:30 2019 +0000

    Fix arch.h dependency in cal build.
    
    This was causing parallel makes of CAL enabled builds to
    fail.

diff --git a/base/cal.mak b/base/cal.mak
index 07a5124..d38cb40 100644
--- a/base/cal.mak
+++ b/base/cal.mak
@@ -120,8 +120,8 @@ $(CAL_OBJ)$(CAL_PREFIX)blend.$(OBJ) : $(CAL_SRC)blend.c $(cal_HDRS) $(CAL_DEP) $
 
 cal_ets_h=$(CAL_SRC)cal_ets.h
 ca_ets_tm_h=$(CAL_SRC)cal_ets_tm.h
-$(GLOBJ)ets_1.$(OBJ) : $(CAL_SRC)cal_ets.c $(CAL_SRC)ets_template.c $(AK) \
- $(cal_ets_h) $(cal_ets_tm_h) $(LIB_MAK) $(MAKEDIRS)
+$(GLOBJ)ets_1.$(OBJ) : $(CAL_SRC)cal_ets.c $(CAL_SRC)ets_template.c \
+ $(cal_ets_h) $(cal_ets_tm_h) $(cal_HDRS) $(CAL_DEP) $(LIB_MAK)
 	$(GLCC) $(CAL_SSE4_2_CFLAGS) $(CAL_NEON_CFLAGS) $(GLO_)ets_1.$(OBJ) $(C_) $(CAL_SRC)cal_ets.c
 
 

----------------------------------------------------------------------
commit b6f6adb5448fda1f33db4c92c030709618e4ee54
Author: Robin Watts <[email protected]>
Date:   Fri Nov 29 17:48:29 2019 +0000

    Support for YCbCr, LogL, LOGLUV and paletted TIFFs.
    
    YCbCr TIFFs have to use TIFFRGBAImage as for the old JPEG
    encapsulation.

diff --git a/gpdl/tifftop.c b/gpdl/tifftop.c
index 746bf1d..d12a44b 100644
--- a/gpdl/tifftop.c
+++ b/gpdl/tifftop.c
@@ -71,6 +71,8 @@ typedef struct tiff_interp_instance_s {
     uint32_t           tile_width;
     uint32_t           tiled;
     uint32_t           compression;
+    uint32_t           photometric;
+    uint8_t           *palette;
 
     uint32_t           num_comps;
     uint32_t           byte_width;
@@ -84,8 +86,10 @@ typedef struct tiff_interp_instance_s {
     byte              *tiff_buffer;
     size_t             file_pos;
     TIFF              *handle;
+    int                is_rgba;
 
     byte              *samples;
+    byte              *proc_samples;
     jpeg_cust_mem_data jmem;
 } tiff_interp_instance_t;
 
@@ -471,6 +475,36 @@ tiff_jpeg_mem_callback(thandle_t tiff_)
 #endif /* SHARE_LIBTIFF == 0 */
 
 static int
+guess_pal_depth(int n, uint16_t *rmap, uint16_t *gmap, uint16_t *bmap)
+{
+    int i;
+    for (i = 0; i < n; i++) {
+        if (rmap[i] >= 256 || gmap[i] >= 256 || bmap[i] >= 256)
+            return 16;
+    }
+    return 8;
+}
+
+static void
+blend_alpha(tiff_interp_instance_t *tiff, int n)
+{
+    byte *p = tiff->samples;
+    const byte *q = (const byte *)tiff->samples;
+    int nc = tiff->num_comps;
+    int i;
+
+    while (n--) {
+        byte a = q[nc];
+        for (i = nc; i > 0; i--) {
+            int c = *q++ * a + 255*(255-a);
+            c += (c>>7);
+            *p++ = c>>8;
+        }
+        q++;
+    }
+}
+
+static int
 do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int eof)
 {
     tiff_interp_instance_t *tiff = (tiff_interp_instance_t *)impl->interp_client_data;
@@ -559,6 +593,9 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
             gs_color_space *cs;
             unsigned int used[GS_IMAGE_MAX_COMPONENTS];
             gs_string plane_data[GS_IMAGE_MAX_COMPONENTS];
+            int invert = 0;
+            int alpha = 0;
+            char emsg[1024];
 
             tiff->handle = TIFFClientOpen("dummy", "rm",
                                           (thandle_t)tiff,
@@ -575,9 +612,14 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
             }
 
             TIFFGetField(tiff->handle, TIFFTAG_COMPRESSION, &tiff->compression);
-            if (tiff->compression == COMPRESSION_JPEG){
+            if (tiff->compression == COMPRESSION_JPEG) {
                 TIFFSetField(tiff->handle, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
             }
+            TIFFGetField(tiff->handle, TIFFTAG_PHOTOMETRIC, &tiff->photometric);
+            if (tiff->photometric == PHOTOMETRIC_LOGL ||
+                tiff->photometric == PHOTOMETRIC_LOGLUV) {
+                TIFFSetField(tiff->handle, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
+            }
 #if defined(SHARE_LIBTIFF) && SHARE_LIBTIFF==0
             TIFFSetJpegMemFunction(tiff->handle,
                                    &tiff_jpeg_mem_callback);
@@ -622,8 +664,16 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                 tiff->byte_width = ((tiff->bpc * tiff->tile_width + 7)>>3) * tiff->num_comps;
             }
 
-            if (tiff->compression == COMPRESSION_OJPEG) {
+            /* Allocate 'samples' to hold the raw samples values read from libtiff.
+             * The exact size of this buffer depends on which of the multifarious
+             * read routines we are using. (Tiled/RGBAImage/Scanlines) */
+            if (tiff->compression == COMPRESSION_OJPEG ||
+                tiff->photometric == PHOTOMETRIC_YCBCR) {
+                tiff->is_rgba = 1;
                 tiff->samples = gs_alloc_bytes(tiff->memory, sizeof(uint32_t) * tiff->width * tiff->height, "tiff_image");
+                tiff->tile_width = tiff->width;
+                tiff->tile_height = tiff->height;
+                tiff->byte_width = ((tiff->bpc * tiff->num_comps * tiff->tile_width + 7)>>3);
             } else if (tiff->tiled) {
                 tiff->samples = gs_alloc_bytes(tiff->memory, TIFFTileSize(tiff->handle), "tiff_tile");
             } else {
@@ -633,9 +683,98 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                 tiff->state = ii_state_flush;
                 break;
             }
+            tiff->proc_samples = tiff->samples;
 
             /* FIXME: Need to allow for LAB, YUV etc too */
             tiff->bpp = tiff->bpc * tiff->num_comps;
+            switch(tiff->photometric) {
+            case PHOTOMETRIC_MINISWHITE:
+                invert = 1;
+                /* Fall through */
+            case PHOTOMETRIC_MINISBLACK:
+                if (tiff->num_comps != 1) {
+                    code = gs_error_unknownerror;
+                    goto fail_decode;
+                }
+                break;
+            case PHOTOMETRIC_RGB:
+                if (tiff->num_comps == 4) {
+                    alpha = 1;
+                    tiff->num_comps = 3;
+                    tiff->bpp = tiff->bpp * 3/4;
+                    tiff->byte_width = tiff->byte_width * 3/4;
+                } else if (tiff->num_comps != 3) {
+                    code = gs_error_unknownerror;
+                    goto fail_decode;
+                }
+                break;
+            case PHOTOMETRIC_PALETTE:
+            {
+                uint16_t *rmap, *gmap, *bmap;
+                int i, n = 1<<tiff->bpc;
+                if (tiff->num_comps != 1) {
+                    code = gs_error_unknownerror;
+                    goto fail_decode;
+                }
+                if (!TIFFGetField(tiff->handle, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
+                    code = gs_error_unknownerror;
+                    goto fail_decode;
+                }
+                tiff->palette = gs_alloc_bytes(tiff->memory, 3*n, "palette");
+                if (tiff->palette == NULL) {
+                    code = gs_error_unknownerror;
+                    goto fail_decode;
+                }
+                if (guess_pal_depth(n, rmap, gmap, bmap) == 8) {
+                    for (i=0; i < n; i++) {
+                        tiff->palette[3*i+0] = rmap[i];
+                        tiff->palette[3*i+1] = gmap[i];
+                        tiff->palette[3*i+2] = bmap[i];
+                    }
+                } else {
+                    for (i=0; i < n; i++) {
+                        tiff->palette[3*i+0] = rmap[i]*255/65535;
+                        tiff->palette[3*i+1] = gmap[i]*255/65535;
+                        tiff->palette[3*i+2] = bmap[i]*255/65535;
+                    }
+                }
+                tiff->bpc = 8;
+                tiff->num_comps = 3;
+                tiff->bpp = 24;
+                tiff->byte_width = tiff->tile_width * 3;
+                /* Now we need to make a "proc_samples" area to store the
+                 * processed samples in. */
+                if (tiff->is_rgba) {
+                    code = gs_error_unknownerror;
+                    goto fail_decode;
+                } else if (tiff->tiled) {
+                    tiff->proc_samples = gs_alloc_bytes(tiff->memory, tiff->tile_width * tiff->tile_height * 3, "tiff_tile");
+                } else {
+                    tiff->proc_samples = gs_alloc_bytes(tiff->memory, tiff->width * 3, "tiff_scan");
+                }
+                break;
+            }
+            case PHOTOMETRIC_MASK:
+                if (tiff->num_comps != 1) {
+                    code = gs_error_unknownerror;
+                    goto fail_decode;
+                }
+                break;
+            case PHOTOMETRIC_SEPARATED:
+            case PHOTOMETRIC_YCBCR:
+            case PHOTOMETRIC_CIELAB:
+            case PHOTOMETRIC_ICCLAB:
+            case PHOTOMETRIC_ITULAB:
+                if (tiff->num_comps != 3) {
+                    code = gs_error_unknownerror;
+                    goto fail_decode;
+                }
+                break;
+            case PHOTOMETRIC_CFA:
+            default:
+                tiff->state = ii_state_flush;
+                break;
+            }
             switch(tiff->num_comps) {
             default:
             case 1:
@@ -675,6 +814,7 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                     int y, s;
                     byte *row;
                     float xext, xoffset, yext, yoffset;
+                    int tremx, tremy;
 
                     tiff->penum = gs_image_enum_alloc(tiff->memory, "tiff_impl_process(penum)");
                     if (tiff->penum == NULL) {
@@ -715,27 +855,24 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
 
                     tiff->image.ImageMatrix.xx = tiff->xresolution / 72.0f;
                     tiff->image.ImageMatrix.yy = tiff->yresolution / 72.0f;
+                    if (invert) {
+                        tiff->image.Decode[0] = 1;
+                        tiff->image.Decode[1] = 0;
+                        tiff->image.Decode[2] = 1;
+                        tiff->image.Decode[3] = 0;
+                        tiff->image.Decode[4] = 1;
+                        tiff->image.Decode[5] = 0;
+                        tiff->image.Decode[6] = 1;
+                        tiff->image.Decode[7] = 0;
+                    }
 
-                    if (tiff->compression == COMPRESSION_OJPEG) {
-                        int n = tiff->width * tiff->height;
-                        byte *p;
-                        uint32_t *q;
-                        if (tiff->tiled)
-                            goto fail_decode;
+                    if (tiff->is_rgba) {
                         if (TIFFReadRGBAImage(tiff->handle, tiff->width, tiff->height,
                                               (uint32_t *)tiff->samples, 0) == 0) {
                             code = gs_error_unknownerror;
                             goto fail_decode;
                         }
-                        q = tiff->samples;
-                        p = (byte *)q;
-                        while (n--) {
-                            uint32_t v = *q++;
-                            p[0] = v;
-                            p[1] = (v>>8);
-                            p[2] = (v>>16);
-                            p += 3;
-                        }
+                        blend_alpha(tiff, tiff->tile_width * tiff->tile_height);
                     } else if (tiff->tiled) {
                         if (TIFFReadTile(tiff->handle, tiff->samples, tx, ty, 0, 0) == 0) {
                             code = gs_error_unknownerror;
@@ -745,6 +882,24 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                         tiff->image.format = gs_image_format_component_planar;
                     }
 
+                    if (!tiff->is_rgba && tiff->tiled) {
+                        if (tiff->palette) {
+                            int n = tiff->tile_width * tiff->tile_height;
+                            byte *q = tiff->samples;
+                            byte *p = tiff->proc_samples;
+                            while (n--) {
+                                byte *v = &tiff->palette[3 * *q++];
+                                p[0] = *v++;
+                                p[1] = *v++;
+                                p[2] = *v++;
+                                p += 3;
+                            }
+                        }
+                        if (alpha) {
+                            blend_alpha(tiff, tiff->tile_width);
+                        }
+                    }
+
                     code = gs_image_init(tiff->penum,
                                          &tiff->image,
                                          false,
@@ -755,29 +910,54 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                         return code;
                     }
 
-                    for (y = 0; y < tiff->tile_height; y++) {
-                        if (tiff->compression == COMPRESSION_OJPEG) {
-                            /* OJPEG appears to be upside down! */
-                            row = tiff->samples + tiff->byte_width * (tiff->tile_height-1-y);
+                    tremx = tiff->width - tx;
+                    if (tremx > tiff->tile_width)
+                        tremx = tiff->tile_width;
+                    tremy = tiff->height - ty;
+                    if (tremy > tiff->tile_height)
+                        tremy = tiff->tile_height;
+                    for (y = 0; y < tremy; y++) {
+                        if (tiff->is_rgba) {
+                            row = tiff->proc_samples + tiff->byte_width * (tiff->tile_height-1-y);
                         } else if (tiff->tiled) {
-                            row = tiff->samples + tiff->byte_width * y;
+                            row = tiff->proc_samples + tiff->byte_width * y;
                         } else if (planar == PLANARCONFIG_CONTIG) {
-                            row = tiff->samples;
+                            row = tiff->proc_samples;
                             if (TIFFReadScanline(tiff->handle, tiff->samples, ty+y, 0) == 0) {
                                 code = gs_error_unknownerror;
                                 goto fail_decode;
                             }
                         } else {
                             int span = tiff->byte_width / tiff->num_comps;
-                            row = tiff->samples;
+                            byte *in_row = tiff->samples;
+                            row = tiff->proc_samples;
                             for (s = 0; s < tiff->num_comps; s++) {
                                 plane_data[s].data = row;
                                 plane_data[s].size = span;
-                                row += span;
-                                if (TIFFReadScanline(tiff->handle, plane_data[s].data, ty+y, s) == 0) {
+                                if (TIFFReadScanline(tiff->handle, in_row, ty+y, s) == 0) {
                                     code = gs_error_unknownerror;
                                     goto fail_decode;
                                 }
+                                row += span;
+                                in_row += span;
+                            }
+                        }
+
+                        if (!tiff->tiled) {
+                            if (tiff->palette) {
+                                int n = tiff->tile_width;
+                                const byte *q = tiff->samples;
+                                byte *p = tiff->proc_samples;
+                                while (n--) {
+                                    byte *v = &tiff->palette[3 * *q++];
+                                    p[0] = *v++;
+                                    p[1] = *v++;
+                                    p[2] = *v++;
+                                    p += 3;
+                                }
+                            }
+                            if (alpha) {
+                                blend_alpha(tiff, tiff->tile_width);
                             }
                         }
 
@@ -820,9 +1000,20 @@ fail_decode:
                 tiff->penum = NULL;
             }
 
+            if (tiff->proc_samples && tiff->proc_samples != tiff->samples) {
+                gs_free_object(tiff->memory, tiff->proc_samples, "tiff_impl_process(samples)");
+                tiff->proc_samples = NULL;
+            }
+
             if (tiff->samples) {
                 gs_free_object(tiff->memory, tiff->samples, "tiff_impl_process(samples)");
                 tiff->samples = NULL;
+                tiff->proc_samples = NULL;
+            }
+
+            if (tiff->palette) {
+                gs_free_object(tiff->memory, tiff->palette, "tiff_impl_process(samples)");
+                tiff->palette = NULL;
             }
 
             if (tiff->tiff_buffer) {

----------------------------------------------------------------------
commit ae1cee743e56a7b654d9dbb2ea88ed90d48d298d
Author: Robin Watts <[email protected]>
Date:   Thu Nov 28 22:32:43 2019 +0000

    Further fixes for GPDL TIFF.
    
    Support JPEG encoded TIFFs (both old and new formats).
    
    Old JPEG format requires the whole image to be decoded to an
    RGBAImage in memory at once; looks like that's just a limitation
    of libtiff. This is particularly annoying because it looks like
    the internals of libtiff are prepared to do scanline extraction
    as you'd hope, but aren't exposed to the outside world.

diff --git a/base/msvclib.mak b/base/msvclib.mak
index 4824321..99a85de 100644
--- a/base/msvclib.mak
+++ b/base/msvclib.mak
@@ -384,7 +384,7 @@ TIFFSRCDIR=tiff$(D)
 TIFFCONFDIR=$(TIFFSRCDIR)
 TIFFCONFIG_SUFFIX=.vc
 TIFFPLATFORM=win32
-TIFFCFLAGS="-DJPEG_LIB_MK1_OR_12BIT=0"
+TIFF_CFLAGS=-DJPEG_SUPPORT -DOJPEG_SUPPORT -DJPEG_LIB_MK1_OR_12BIT=0
 !endif
 
 # Define which jbig2 library to use
diff --git a/base/tiff.mak b/base/tiff.mak
index 404e180..dec0e65 100644
--- a/base/tiff.mak
+++ b/base/tiff.mak
@@ -129,7 +129,7 @@ $(TIFFOBJ)tif_next.$(OBJ) : $(TIFFSRC)/libtiff/tif_next.c $(TIFFDEP)
 	$(TIFFCC) $(TIFFO_)tif_next.$(OBJ) $(C_) $(TIFFSRC)/libtiff/tif_next.c
 
 $(TIFFOBJ)tif_ojpeg.$(OBJ) : $(TIFFSRC)/libtiff/tif_ojpeg.c $(jconfig_h) $(TIFFDEP)
-	$(TIFFCC) $(TIFFO_)tif_ojpeg.$(OBJ) $(C_) $(TIFFSRC)/libtiff/tif_ojpeg.c
+	$(TIFFCC) $(I_)$(GLI_) $(TIFFO_)tif_ojpeg.$(OBJ) $(C_) $(TIFFSRC)/libtiff/tif_ojpeg.c
 
 $(TIFFOBJ)tif_open.$(OBJ) : $(TIFFSRC)/libtiff/tif_open.c $(TIFFDEP)
 	$(TIFFCC) $(TIFFO_)tif_open.$(OBJ) $(C_) $(TIFFSRC)/libtiff/tif_open.c
diff --git a/configure.ac b/configure.ac
index b29b08a..89682ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1446,10 +1446,8 @@ if test x"$SHARE_LIBTIFF" = x"0" ; then
         TIFFCFLAGS="-Wno-write-strings $CFLAGS_NMI $CFLAGS_NUD -DJPEG_LIB_MK1_OR_12BIT=0"
       fi
       # if we're building with our own libjpeg, or we have another libjpeg available, allow jpeg compression in TIFF
-      if test x"$TIFF_JPEG_INCLUDE" != x"src" ; then
-        TIFFCFLAGS="-DJPEG_SUPPORT -DJPEG_LIB_MK1_OR_12BIT=0 -I$TIFF_JPEG_INCLUDE $TIFFCFLAGS"
-      elif test x"$SHARE_LIBJPEG" = x"1" ; then
-        TIFFCFLAGS="-DJPEG_SUPPORT -DJPEG_LIB_MK1_OR_12BIT=0 $TIFFCFLAGS"
+      if test x"$SHARE_LIBJPEG" = x"1" ; then
+        TIFFCFLAGS="-DJPEG_SUPPORT -DOJPEG_SUPPORT -DJPEG_LIB_MK1_OR_12BIT=0 $TIFFCFLAGS"
       fi
 
       echo
diff --git a/gpdl/gpdl.mak b/gpdl/gpdl.mak
index 3695415..e29c53a 100644
--- a/gpdl/gpdl.mak
+++ b/gpdl/gpdl.mak
@@ -25,27 +25,27 @@ GPDLO_=$(O_)$(GPDLOBJ)
 GLGEN=$(GLGENDIR)$(D)
 
 GPDL_PSI_TOP_OBJ_FILE=psitop.$(OBJ)
-GPDL_PSI_TOP_OBJ=$(GPDLOBJ)/$(GPDL_PSI_TOP_OBJ_FILE)
+GPDL_PSI_TOP_OBJ=$(GPDLOBJ)$(GPDL_PSI_TOP_OBJ_FILE)
 
 GPDL_URF_TOP_OBJ_FILE=urftop.$(OBJ)
 
 GPDL_JPG_TOP_OBJ_FILE=jpgtop.$(OBJ)
-GPDL_JPG_TOP_OBJ=$(GPDLOBJ)/$(GPDL_JPG_TOP_OBJ_FILE)
+GPDL_JPG_TOP_OBJ=$(GPDLOBJ)$(GPDL_JPG_TOP_OBJ_FILE)
 
 GPDL_PWG_TOP_OBJ_FILE=pwgtop.$(OBJ)
-GPDL_PWG_TOP_OBJ=$(GPDLOBJ)/$(GPDL_PWG_TOP_OBJ_FILE)
+GPDL_PWG_TOP_OBJ=$(GPDLOBJ)$(GPDL_PWG_TOP_OBJ_FILE)
 
 GPDL_TIFF_TOP_OBJ_FILE=tifftop.$(OBJ)
-GPDL_TIFF_TOP_OBJ=$(GPDLOBJ)/$(GPDL_TIFF_TOP_OBJ_FILE)
+GPDL_TIFF_TOP_OBJ=$(GPDLOBJ)$(GPDL_TIFF_TOP_OBJ_FILE)
 
 GPDL_JBIG2_TOP_OBJ_FILE=jbig2top.$(OBJ)
-GPDL_JBIG2_TOP_OBJ=$(GPDLOBJ)/$(GPDL_JBIG2_TOP_OBJ_FILE)
+GPDL_JBIG2_TOP_OBJ=$(GPDLOBJ)$(GPDL_JBIG2_TOP_OBJ_FILE)
 
 GPDL_JP2K_TOP_OBJ_FILE=jp2ktop.$(OBJ)
-GPDL_JP2K_TOP_OBJ=$(GPDLOBJ)/$(GPDL_JP2K_TOP_OBJ_FILE)
+GPDL_JP2K_TOP_OBJ=$(GPDLOBJ)$(GPDL_JP2K_TOP_OBJ_FILE)
 
 GPDL_PNG_TOP_OBJ_FILE=pngtop.$(OBJ)
-GPDL_PNG_TOP_OBJ=$(GPDLOBJ)/$(GPDL_PNG_TOP_OBJ_FILE)
+GPDL_PNG_TOP_OBJ=$(GPDLOBJ)$(GPDL_PNG_TOP_OBJ_FILE)
 
 GPDL_PSI_TOP_OBJS=\
 	$(GPDL_PNG_TOP_OBJ)\
@@ -110,10 +110,18 @@ $(GPDL_PWG_TOP_OBJ): $(GPDLSRC)pwgtop.c $(AK)\
  $(spwgx_h) $(pltop_h) $(gsicc_manage_h) $(gspaint_h) $(plmain_h)
 	$(GPDLCC) $(GPDLSRC)pwgtop.c $(GPDLO_)$(GPDL_PWG_TOP_OBJ_FILE)
 
-$(GPDL_TIFF_TOP_OBJ): $(GPDLSRC)tifftop.c $(AK)\
+$(GPDLOBJ)tifftop_0.$(OBJ): $(GPDLSRC)tifftop.c $(AK)\
  $(gxdevice_h) $(gserrors_h) $(gsstate_h) $(strimpl_h) $(gscoord_h)\
- $(pltop_h) $(gsicc_manage_h) $(gspaint_h) $(plmain_h)
-	$(GPDLCC) $(II)$(TI_)$(_I) $(GPDLSRC)tifftop.c $(GPDLO_)$(GPDL_TIFF_TOP_OBJ_FILE)
+ $(pltop_h) $(gsicc_manage_h) $(gspaint_h) $(plmain_h) $(jmemcust_h)
+	$(GPDLCC) $(D_)SHARE_LIBTIFF=0 $(II)$(TI_)$(_I) $(II)$(JI_)$(_I) $(GPDLSRC)tifftop.c $(GPDLO_)tifftop_0.$(OBJ)
+
+$(GPDLOBJ)tifftop_1.$(OBJ): $(GPDLSRC)tifftop.c $(AK)\
+ $(gxdevice_h) $(gserrors_h) $(gsstate_h) $(strimpl_h) $(gscoord_h)\
+ $(pltop_h) $(gsicc_manage_h) $(gspaint_h) $(plmain_h) $(jmemcust_h)
+	$(GPDLCC) $(D_)SHARE_LIBTIFF=1 $(II)$(TI_)$(_I) $(II)$(JI_)$(_I) $(GPDLSRC)tifftop.c $(GPDLO_)tifftop_1.$(OBJ)
+
+$(GPDL_TIFF_TOP_OBJ): $(GPDLOBJ)tifftop_$(SHARE_LIBTIFF).$(OBJ)
+	$(CP_) $(GPDLOBJ)tifftop_$(SHARE_LIBTIFF).$(OBJ) $(GPDL_TIFF_TOP_OBJ)
 
 $(GPDL_JBIG2_TOP_OBJ): $(GPDLSRC)jbig2top.c $(AK)\
  $(gxdevice_h) $(gserrors_h) $(gsstate_h) $(strimpl_h) $(gscoord_h)\
diff --git a/gpdl/tifftop.c b/gpdl/tifftop.c
index e4b59d0..746bf1d 100644
--- a/gpdl/tifftop.c
+++ b/gpdl/tifftop.c
@@ -26,6 +26,8 @@
 #include "gspaint.h"
 #include "plmain.h"
 #include "tiffio.h"
+#include "jmemcust.h"
+#include "gsmchunk.h"
 
 /* Forward decls */
 
@@ -68,6 +70,7 @@ typedef struct tiff_interp_instance_s {
     uint32_t           tile_height;
     uint32_t           tile_width;
     uint32_t           tiled;
+    uint32_t           compression;
 
     uint32_t           num_comps;
     uint32_t           byte_width;
@@ -83,7 +86,7 @@ typedef struct tiff_interp_instance_s {
     TIFF              *handle;
 
     byte              *samples;
-
+    jpeg_cust_mem_data jmem;
 } tiff_interp_instance_t;
 
 static int
@@ -414,6 +417,59 @@ static toff_t tifsSizeProc(thandle_t tiff_)
     return tiff->buffer_full;
 }
 
+#if defined(SHARE_LIBTIFF) && SHARE_LIBTIFF==0
+static void *gs_j_mem_alloc(j_common_ptr cinfo, size_t size)
+{
+    gs_memory_t *mem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv);
+
+    return(gs_alloc_bytes(mem, size, "JPEG allocation"));
+}
+
+static void gs_j_mem_free(j_common_ptr cinfo, void *object, size_t size)
+{
+    gs_memory_t *mem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv);
+
+    gs_free_object(mem, object, "JPEG free");
+}
+
+static long gs_j_mem_init (j_common_ptr cinfo)
+{
+    gs_memory_t *mem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv);
+    gs_memory_t *cmem = NULL;
+
+    if (gs_memory_chunk_wrap(&(cmem), mem) < 0) {
+        return (-1);
+    }
+
+    (void)jpeg_cust_mem_set_private(GET_CUST_MEM_DATA(cinfo), cmem);
+
+    return 0;
+}
+
+static void gs_j_mem_term (j_common_ptr cinfo)
+{
+    gs_memory_t *cmem = (gs_memory_t *)(GET_CUST_MEM_DATA(cinfo)->priv);
+    gs_memory_t *mem = gs_memory_chunk_target(cmem);
+
+    gs_memory_chunk_release(cmem);
+
+    (void)jpeg_cust_mem_set_private(GET_CUST_MEM_DATA(cinfo), mem);
+}
+
+static void *
+tiff_jpeg_mem_callback(thandle_t tiff_)
+{
+    tiff_interp_instance_t *tiff = (tiff_interp_instance_t *)tiff_;
+
+    (void)jpeg_cust_mem_init(&tiff->jmem, (void *)tiff->memory,
+                             gs_j_mem_init, gs_j_mem_term, NULL,
+                            gs_j_mem_alloc, gs_j_mem_free,
+                            gs_j_mem_alloc, gs_j_mem_free, NULL);
+
+    return &tiff->jmem;
+}
+#endif /* SHARE_LIBTIFF == 0 */
+
 static int
 do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int eof)
 {
@@ -518,6 +574,15 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                 break;
             }
 
+            TIFFGetField(tiff->handle, TIFFTAG_COMPRESSION, &tiff->compression);
+            if (tiff->compression == COMPRESSION_JPEG){
+                TIFFSetField(tiff->handle, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+            }
+#if defined(SHARE_LIBTIFF) && SHARE_LIBTIFF==0
+            TIFFSetJpegMemFunction(tiff->handle,
+                                   &tiff_jpeg_mem_callback);
+#endif
+
             TIFFGetField(tiff->handle, TIFFTAG_IMAGEWIDTH, &tiff->width);
             TIFFGetField(tiff->handle, TIFFTAG_IMAGELENGTH, &tiff->height);
             TIFFGetField(tiff->handle, TIFFTAG_TILEWIDTH, &tiff->tile_width);
@@ -557,7 +622,9 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                 tiff->byte_width = ((tiff->bpc * tiff->tile_width + 7)>>3) * tiff->num_comps;
             }
 
-            if (tiff->tiled) {
+            if (tiff->compression == COMPRESSION_OJPEG) {
+                tiff->samples = gs_alloc_bytes(tiff->memory, sizeof(uint32_t) * tiff->width * tiff->height, "tiff_image");
+            } else if (tiff->tiled) {
                 tiff->samples = gs_alloc_bytes(tiff->memory, TIFFTileSize(tiff->handle), "tiff_tile");
             } else {
                 tiff->samples = gs_alloc_bytes(tiff->memory, tiff->byte_width, "tiff_scan");
@@ -637,10 +704,8 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                         code = gs_translate(tiff->pgs, xoffset, -yoffset);
                     if (code >= 0)
                         code = gs_scale(tiff->pgs, scale, -scale);
-                    if (code < 0) {
-                        tiff->state = ii_state_flush;
-                        break;
-                    }
+                    if (code < 0)
+                        goto fail_decode;
 
                     memset(&tiff->image, 0, sizeof(tiff->image));
                     gs_image_t_init(&tiff->image, cs);
@@ -651,8 +716,31 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                     tiff->image.ImageMatrix.xx = tiff->xresolution / 72.0f;
                     tiff->image.ImageMatrix.yy = tiff->yresolution / 72.0f;
 
-                    if (tiff->tiled) {
-                        TIFFReadTile(tiff->handle, tiff->samples, tx, ty, 0, 0);
+                    if (tiff->compression == COMPRESSION_OJPEG) {
+                        int n = tiff->width * tiff->height;
+                        byte *p;
+                        uint32_t *q;
+                        if (tiff->tiled)
+                            goto fail_decode;
+                        if (TIFFReadRGBAImage(tiff->handle, tiff->width, tiff->height,
+                                              (uint32_t *)tiff->samples, 0) == 0) {
+                            code = gs_error_unknownerror;
+                            goto fail_decode;
+                        }
+                        q = tiff->samples;
+                        p = (byte *)q;
+                        while (n--) {
+                            uint32_t v = *q++;
+                            p[0] = v;
+                            p[1] = (v>>8);
+                            p[2] = (v>>16);
+                            p += 3;
+                        }
+                    } else if (tiff->tiled) {
+                        if (TIFFReadTile(tiff->handle, tiff->samples, tx, ty, 0, 0) == 0) {
+                            code = gs_error_unknownerror;
+                            goto fail_decode;
+                        }
                     } else if (planar != PLANARCONFIG_CONTIG) {
                         tiff->image.format = gs_image_format_component_planar;
                     }
@@ -668,11 +756,17 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                     }
 
                     for (y = 0; y < tiff->tile_height; y++) {
-                        if (tiff->tiled) {
+                        if (tiff->compression == COMPRESSION_OJPEG) {
+                            /* OJPEG appears to be upside down! */
+                            row = tiff->samples + tiff->byte_width * (tiff->tile_height-1-y);
+                        } else if (tiff->tiled) {
                             row = tiff->samples + tiff->byte_width * y;
                         } else if (planar == PLANARCONFIG_CONTIG) {
                             row = tiff->samples;
-                            TIFFReadScanline(tiff->handle, tiff->samples, ty+y, 0);
+                            if (TIFFReadScanline(tiff->handle, tiff->samples, ty+y, 0) == 0) {
+                                code = gs_error_unknownerror;
+                                goto fail_decode;
+                            }
                         } else {
                             int span = tiff->byte_width / tiff->num_comps;
                             row = tiff->samples;
@@ -680,7 +774,10 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                                 plane_data[s].data = row;
                                 plane_data[s].size = span;
                                 row += span;
-                                TIFFReadScanline(tiff->handle, plane_data[s].data, ty+y, s);
+                                if (TIFFReadScanline(tiff->handle, plane_data[s].data, ty+y, s) == 0) {
+                                    code = gs_error_unknownerror;
+                                    goto fail_decode;
+                                }
                             }
                         }
 
@@ -690,8 +787,8 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                             code = gs_image_next(tiff->penum, row, tiff->byte_width, used);
                         }
                         if (code < 0) {
-                            tiff->state = ii_state_flush;
-                            break;
+                            code = gs_error_unknownerror;
+                            goto fail_decode;
                         }
                     }
                     code = gs_image_cleanup_and_free_enum(tiff->penum, tiff->pgs);
@@ -706,6 +803,9 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
             (void)pl_finish_page(tiff->memory->gs_lib_ctx->top_of_system,
                                  tiff->pgs, 1, true);
             break;
+fail_decode:
+            tiff->state = ii_state_flush;
+            break;
         }
         default:
         case ii_state_flush:
diff --git a/psi/msvc.mak b/psi/msvc.mak
index 793d50d..87ad100 100644
--- a/psi/msvc.mak
+++ b/psi/msvc.mak
@@ -659,7 +659,7 @@ TIFFSRCDIR=tiff$(D)
 TIFFCONFDIR=$(TIFFSRCDIR)
 TIFFCONFIG_SUFFIX=.vc
 TIFFPLATFORM=win32
-TIFFCFLAGS="-DJPEG_SUPPORT -DJPEG_LIB_MK1_OR_12BIT=0 -I./jpeg"
+TIFF_CFLAGS=-DJPEG_SUPPORT -DOJPEG_SUPPORT -DJPEG_LIB_MK1_OR_12BIT=0
 ENABLE_TIFF=$(D_)TIFF_INCLUDED$(_D)
 !endif
 

----------------------------------------------------------------------
commit ef66198ade77d5d551b3045cd36bed81c0b04f54
Author: Robin Watts <[email protected]>
Date:   Thu Dec 12 17:26:02 2019 +0000

    Changes to libtiff for gpdl.
    
    1) Ensure that libtiff doesn't mess with 'boolean' in GS builds
    on Windows. Without this, the jpeg structures used by our JPEG
    lib build are different in size when called from gs and libtiff,
    resulting in runtime errors.
    
    2) Update libtiff so that it can correctly call into the jpeg
    library so that memory operations happen from our pools, not
    malloc/free. Slightly horrid in that this is more complex with
    OJPEG than JPEG files.

diff --git a/tiff/libtiff/tif_jpeg.c b/tiff/libtiff/tif_jpeg.c
index 93ae2ea..d49b904 100644
--- a/tiff/libtiff/tif_jpeg.c
+++ b/tiff/libtiff/tif_jpeg.c
@@ -65,6 +65,10 @@ int TIFFJPEGIsFullStripRequired_12(TIFF* tif);
 # define XMD_H 1
 #endif
 
+/* If we are building for GS, do NOT mess with boolean - we want it to be int on all platforms.
+ */
+#define GS_TIFF_BUILD
+#ifndef GS_TIFF_BUILD
 /*
    The windows RPCNDR.H file defines boolean, but defines it with the
    unsigned char size.  You should compile JPEG library using appropriate
@@ -85,6 +89,7 @@ int TIFFJPEGIsFullStripRequired_12(TIFF* tif);
 # endif
 # define HAVE_BOOLEAN            /* prevent jmorecfg.h from redefining it */
 #endif
+#endif
 
 #include "jpeglib.h"
 #include "jerror.h"
@@ -290,15 +295,19 @@ TIFFjpeg_create_compress(JPEGState* sp)
 }
 
 static int
-TIFFjpeg_create_decompress(JPEGState* sp)
+TIFFjpeg_create_decompress(JPEGState* sp, TIFF *tif)
 {
 	/* initialize JPEG error handling */
 	sp->cinfo.d.err = jpeg_std_error(&sp->err);
 	sp->err.error_exit = TIFFjpeg_error_exit;
 	sp->err.output_message = TIFFjpeg_output_message;
 
-	/* set client_data to avoid UMR warning from tools like Purify */
-	sp->cinfo.d.client_data = NULL;
+        /* GS extension */
+	if (tif->get_jpeg_mem_ptr)
+		sp->cinfo.d.client_data = tif->get_jpeg_mem_ptr(tif->tif_clientdata);
+	else
+		/* set client_data to avoid UMR warning from tools like Purify */
+		sp->cinfo.d.client_data = NULL;
 
 	return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d));
 }
@@ -1065,7 +1074,7 @@ int TIFFJPEGIsFullStripRequired(TIFF* tif)
     memset(&state, 0, sizeof(JPEGState));
     state.tif = tif;
 
-    TIFFjpeg_create_decompress(&state);
+    TIFFjpeg_create_decompress(&state, tif);
 
     TIFFjpeg_data_src(&state);
 
@@ -2443,7 +2452,7 @@ static int JPEGInitializeLibJPEG( TIFF * tif, int decompress )
      * Initialize libjpeg.
      */
     if ( decompress ) {
-        if (!TIFFjpeg_create_decompress(sp))
+        if (!TIFFjpeg_create_decompress(sp, tif))
             return (0);
     } else {
         if (!TIFFjpeg_create_compress(sp))
diff --git a/tiff/libtiff/tif_ojpeg.c b/tiff/libtiff/tif_ojpeg.c
index bf0d1a2..a3d4513 100644
--- a/tiff/libtiff/tif_ojpeg.c
+++ b/tiff/libtiff/tif_ojpeg.c
@@ -204,6 +204,10 @@ static const TIFFField ojpegFields[] = {
 # define XMD_H 1
 #endif
 
+/* If we are building for GS, do NOT mess with boolean - we want it to be int on all platforms.
+ */
+#define GS_TIFF_BUILD
+#ifndef GS_TIFF_BUILD
 /* Define "boolean" as unsigned char, not int, per Windows custom. */
 #if defined(__WIN32__) && !defined(__MINGW32__)
 # ifndef __RPCNDR_H__            /* don't conflict if rpcndr.h already read */
@@ -211,9 +215,13 @@ static const TIFFField ojpegFields[] = {
 # endif
 # define HAVE_BOOLEAN            /* prevent jmorecfg.h from redefining it */
 #endif
+#endif
 
 #include "jpeglib.h"
 #include "jerror.h"
+#ifdef GS_TIFF_BUILD
+#include "jmemcust.h"
+#endif
 
 typedef struct jpeg_error_mgr jpeg_error_mgr;
 typedef struct jpeg_common_struct jpeg_common_struct;
@@ -242,8 +250,8 @@ typedef enum {
 
 typedef struct {
 	TIFF* tif;
-        int decoder_ok;
-        int error_in_raw_data_decoding;
+	int decoder_ok;
+	int error_in_raw_data_decoding;
 	#ifndef LIBJPEG_ENCAP_EXTERNAL
 	JMP_BUF exit_jmpbuf;
 	#endif
@@ -334,6 +342,10 @@ typedef struct {
 	OJPEGStateOutState out_state;
 	uint8 out_buffer[OJPEG_BUFFER];
 	uint8* skip_buffer;
+#ifdef GS_TIFF_BUILD
+	jpeg_cust_mem_data jmem;
+	jpeg_cust_mem_data *jmem_parent;
+#endif
 } OJPEGState;
 
 static int OJPEGVGetField(TIFF* tif, uint32 tag, va_list ap);
@@ -423,7 +435,7 @@ TIFFInitOJPEG(TIFF* tif, int scheme)
 
 	assert(scheme==COMPRESSION_OJPEG);
 
-        /*
+	/*
 	 * Merge codec-specific tag information.
 	 */
 	if (!_TIFFMergeFields(tif, ojpegFields, TIFFArrayCount(ojpegFields))) {
@@ -1194,6 +1206,91 @@ OJPEGReadSecondarySos(TIFF* tif, uint16 s)
 	return(1);
 }
 
+#ifdef GS_TIFF_BUILD
+#define TIFF_FROM_CINFO(cinfo) \
+	((TIFF *)GET_CUST_MEM_DATA(cinfo)->priv)
+
+static void *j_mem_get_small(j_common_ptr cinfo, size_t size)
+{
+	jpeg_cust_mem_data *jc = GET_CUST_MEM_DATA(cinfo);
+	TIFF *tif = (TIFF *)jc->priv;
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	void *ret;
+
+	cinfo->client_data = sp->jmem_parent;
+	ret = sp->jmem_parent->j_mem_get_small(cinfo, size);
+	cinfo->client_data = jc;
+
+	return ret;
+}
+
+static void *j_mem_get_large(j_common_ptr cinfo, size_t size)
+{
+	jpeg_cust_mem_data *jc = GET_CUST_MEM_DATA(cinfo);
+	TIFF *tif = (TIFF *)jc->priv;
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	void *ret;
+
+	cinfo->client_data = sp->jmem_parent;
+	ret = sp->jmem_parent->j_mem_get_large(cinfo, size);
+	cinfo->client_data = jc;
+
+	return ret;
+}
+
+static void j_mem_free_small(j_common_ptr cinfo, void *object, size_t size)
+{
+	jpeg_cust_mem_data *jc = GET_CUST_MEM_DATA(cinfo);
+	TIFF *tif = (TIFF *)jc->priv;
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+
+	cinfo->client_data = sp->jmem_parent;
+	sp->jmem_parent->j_mem_free_small(cinfo, object, size);
+	cinfo->client_data = jc;
+}
+
+static void j_mem_free_large(j_common_ptr cinfo, void *object, size_t size)
+{
+	jpeg_cust_mem_data *jc = GET_CUST_MEM_DATA(cinfo);
+	TIFF *tif = (TIFF *)jc->priv;
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+
+	cinfo->client_data = sp->jmem_parent;
+	sp->jmem_parent->j_mem_free_large(cinfo, object, size);
+	cinfo->client_data = jc;
+}
+
+static long j_mem_init (j_common_ptr cinfo)
+{
+	jpeg_cust_mem_data *jc = GET_CUST_MEM_DATA(cinfo);
+	TIFF *tif = (TIFF *)jc->priv;
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+	long ret;
+
+	cinfo->client_data = sp->jmem_parent;
+	ret = sp->jmem_parent->j_mem_init(cinfo);
+	cinfo->client_data = jc;
+
+	return ret;
+}
+
+static void j_mem_term (j_common_ptr cinfo)
+{
+	jpeg_cust_mem_data *jc = GET_CUST_MEM_DATA(cinfo);
+	TIFF *tif = (TIFF *)jc->priv;
+	OJPEGState* sp=(OJPEGState*)tif->tif_data;
+
+	cinfo->client_data = sp->jmem_parent;
+	sp->jmem_parent->j_mem_term(cinfo);
+	cinfo->client_data = jc;
+}
+#else
+
+#define TIFF_FROM_CINFO(cinfo) \
+	((TIFF *)GET_CUST_MEM_DATA(cinfo))
+
+#endif
+
 static int
 OJPEGWriteHeaderInfo(TIFF* tif)
 {
@@ -1210,7 +1307,17 @@ OJPEGWriteHeaderInfo(TIFF* tif)
 	sp->libjpeg_jpeg_error_mgr.output_message=OJPEGLibjpegJpegErrorMgrOutputMessage;
 	sp->libjpeg_jpeg_error_mgr.error_exit=OJPEGLibjpegJpegErrorMgrErrorExit;
 	sp->libjpeg_jpeg_decompress_struct.err=&(sp->libjpeg_jpeg_error_mgr);
+	/* set client_data to avoid UMR warning from tools like Purify */
+#ifdef GS_TIFF_BUILD
+	sp->jmem_parent = tif->get_jpeg_mem_ptr(tif->tif_clientdata);
+	(void)jpeg_cust_mem_init(&sp->jmem, (void *)tif,
+				 j_mem_init, j_mem_term, NULL,
+				 j_mem_get_small, j_mem_free_small,
+				 j_mem_get_large, j_mem_free_large, NULL);
+	sp->libjpeg_jpeg_decompress_struct.client_data=&sp->jmem;
+#else
 	sp->libjpeg_jpeg_decompress_struct.client_data=(void*)tif;
+#endif
 	if (jpeg_create_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0)
 		return(0);
 	sp->libjpeg_session_active=1;
@@ -2531,18 +2638,20 @@ jpeg_encap_unwind(TIFF* tif)
 static void
 OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo)
 {
+        TIFF *tif = TIFF_FROM_CINFO(cinfo);
 	char buffer[JMSG_LENGTH_MAX];
 	(*cinfo->err->format_message)(cinfo,buffer);
-	TIFFWarningExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg","%s",buffer);
+	TIFFWarningExt(tif->tif_clientdata,"LibJpeg","%s",buffer);
 }
 
 static void
 OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo)
 {
+        TIFF *tif = TIFF_FROM_CINFO(cinfo);
 	char buffer[JMSG_LENGTH_MAX];
 	(*cinfo->err->format_message)(cinfo,buffer);
-	TIFFErrorExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg","%s",buffer);
-	jpeg_encap_unwind((TIFF*)(cinfo->client_data));
+	TIFFErrorExt(tif->tif_clientdata,"LibJpeg","%s",buffer);
+	jpeg_encap_unwind(tif);
 }
 
 static void
@@ -2554,7 +2663,7 @@ OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo)
 static boolean
 OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo)
 {
-	TIFF* tif=(TIFF*)cinfo->client_data;
+        TIFF *tif = TIFF_FROM_CINFO(cinfo);
 	OJPEGState* sp=(OJPEGState*)tif->tif_data;
 	void* mem=0;
 	uint32 len=0U;
@@ -2571,7 +2680,7 @@ OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo)
 static void
 OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes)
 {
-	TIFF* tif=(TIFF*)cinfo->client_data;
+        TIFF *tif = TIFF_FROM_CINFO(cinfo);
 	(void)num_bytes;
 	TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error");
 	jpeg_encap_unwind(tif);
@@ -2584,7 +2693,7 @@ OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_b
 static boolean
 OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired)
 {
-	TIFF* tif=(TIFF*)cinfo->client_data;
+        TIFF *tif = TIFF_FROM_CINFO(cinfo);
 	(void)desired;
 	TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error");
 	jpeg_encap_unwind(tif);
diff --git a/tiff/libtiff/tif_open.c b/tiff/libtiff/tif_open.c
index 3cb53d4..ffe7835 100644
--- a/tiff/libtiff/tif_open.c
+++ b/tiff/libtiff/tif_open.c
@@ -731,6 +731,14 @@ TIFFGetUnmapFileProc(TIFF* tif)
 	return (tif->tif_unmapproc);
 }
 
+void
+TIFFSetJpegMemFunction(TIFF *tif,
+                       void *(*fn)(thandle_t))
+{
+    tif->get_jpeg_mem_ptr = fn;
+}
+
+
 /* vim: set ts=8 sts=8 sw=8 noet: */
 /*
  * Local Variables:
diff --git a/tiff/libtiff/tiffio.h b/tiff/libtiff/tiffio.h
index 198481d..a626a76 100644
--- a/tiff/libtiff/tiffio.h
+++ b/tiff/libtiff/tiffio.h
@@ -414,6 +414,9 @@ extern int TIFFRewriteDirectory(TIFF *);
 extern int TIFFDeferStrileArrayWriting(TIFF *);
 extern int TIFFForceStrileArrayWriting(TIFF* );
 
+/* Extra function to allow JPEG memory use to be controlled */
+extern void TIFFSetJpegMemFunction(TIFF *, void *(*fn)(thandle_t));
+
 #if defined(c_plusplus) || defined(__cplusplus)
 extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0);
 extern int TIFFReadScanline(TIFF* tif, void* buf, uint32 row, uint16 sample = 0);
diff --git a/tiff/libtiff/tiffiop.h b/tiff/libtiff/tiffiop.h
index 5da1a51..900f478 100644
--- a/tiff/libtiff/tiffiop.h
+++ b/tiff/libtiff/tiffiop.h
@@ -2,23 +2,23 @@
  * Copyright (c) 1988-1997 Sam Leffler
  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
  *
- * Permission to use, copy, modify, distribute, and sell this software and 
+ * 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.  
- * 
+ *
+ * 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 
+ * 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.
  */
 
@@ -61,7 +61,7 @@
 #ifdef HAVE_ASSERT_H
 # include <assert.h>
 #else
-# define assert(x) 
+# define assert(x)
 #endif
 
 #ifdef HAVE_SEARCH_H
@@ -240,6 +240,7 @@ struct tiff {
 	 * setting up an old tag extension scheme. */
 	TIFFFieldArray*      tif_fieldscompat;
 	size_t               tif_nfieldscompat;
+	void                *(*get_jpeg_mem_ptr)(thandle_t);
 };
 
 #define isPseudoTag(t) (t > 0xffff)            /* is tag value normal or pseudo */

----------------------------------------------------------------------
commit 0c248ced8997dfe8f253a07fc6cc5f47837ca12e
Author: Robin Watts <[email protected]>
Date:   Thu Nov 28 10:52:49 2019 +0000

    Fixes for GPDL TIFF support.
    
    Support tiled TIFFs, planar TIFFs, and TIFFs where the resolution
    isn't properly specified.

diff --git a/gpdl/tifftop.c b/gpdl/tifftop.c
index 1028afc..e4b59d0 100644
--- a/gpdl/tifftop.c
+++ b/gpdl/tifftop.c
@@ -67,6 +67,7 @@ typedef struct tiff_interp_instance_s {
     uint32_t           yresolution;
     uint32_t           tile_height;
     uint32_t           tile_width;
+    uint32_t           tiled;
 
     uint32_t           num_comps;
     uint32_t           byte_width;
@@ -500,7 +501,8 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
             short planar;
             float f, scale;
             gs_color_space *cs;
-            unsigned int used;
+            unsigned int used[GS_IMAGE_MAX_COMPONENTS];
+            gs_string plane_data[GS_IMAGE_MAX_COMPONENTS];
 
             tiff->handle = TIFFClientOpen("dummy", "rm",
                                           (thandle_t)tiff,
@@ -523,20 +525,44 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
             TIFFGetField(tiff->handle, TIFFTAG_BITSPERSAMPLE, &tiff->bpc);
             TIFFGetField(tiff->handle, TIFFTAG_SAMPLESPERPIXEL, &tiff->num_comps);
             TIFFGetField(tiff->handle, TIFFTAG_PLANARCONFIG, &planar);
+            f = 0;
             TIFFGetField(tiff->handle, TIFFTAG_XRESOLUTION, &f);
             tiff->xresolution = (uint32_t)(f+0.5);
+            f = 0;
             TIFFGetField(tiff->handle, TIFFTAG_YRESOLUTION, &f);
             tiff->yresolution = (uint32_t)(f+0.5);
 
-            if (TIFFIsTiled(tiff->handle)) {
-                tiff->samples = gs_alloc_bytes(tiff->memory, TIFFTileSize(tiff->handle), "tiff_tile");
-            } else {
+            if (tiff->xresolution == 0)
+                tiff->yresolution = tiff->xresolution;
+            if (tiff->yresolution == 0)
+                tiff->xresolution = tiff->yresolution;
+            if (tiff->xresolution == 0)
+                tiff->xresolution = tiff->yresolution = 72;
+            if (tiff->width == 0 || tiff->height == 0 || tiff->bpc == 0 || tiff->num_comps == 0 ||
+                !(planar == PLANARCONFIG_CONTIG || planar == PLANARCONFIG_SEPARATE)) {
+                tiff->state = ii_state_flush;
+                break;
+            }
+
+            tiff->tiled = TIFFIsTiled(tiff->handle);
+
+            if (!tiff->tiled) {
                 tiff->tile_width = tiff->width;
                 tiff->tile_height = tiff->height;
-                tiff->samples = gs_alloc_bytes(tiff->memory, TIFFScanlineSize(tiff->handle), "tiff_scan");
+            }
+
+            if (tiff->tiled || planar == PLANARCONFIG_CONTIG) {
+                tiff->byte_width = ((tiff->bpc * tiff->num_comps * tiff->tile_width + 7)>>3);
+            } else {
+                tiff->byte_width = ((tiff->bpc * tiff->tile_width + 7)>>3) * tiff->num_comps;
+            }
+
+            if (tiff->tiled) {
+                tiff->samples = gs_alloc_bytes(tiff->memory, TIFFTileSize(tiff->handle), "tiff_tile");
+            } else {
+                tiff->samples = gs_alloc_bytes(tiff->memory, tiff->byte_width, "tiff_scan");
             }
             if (tiff->samples == NULL) {
-                TIFFClose(tiff->handle);
                 tiff->state = ii_state_flush;
                 break;
             }
@@ -571,17 +597,13 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                 break;
             }
 
-            if (TIFFIsTiled(tiff->handle) || planar == PLANARCONFIG_CONTIG) {
-                tiff->byte_width = ((tiff->bpc * tiff->num_comps * tiff->tile_width + 7)>>3);
-            } else {
-                tiff->byte_width = ((tiff->bpc * tiff->tile_width + 7)>>3) * tiff->num_comps;
-            }
             code = gs_erasepage(tiff->pgs);
             if (code < 0) {
                 tiff->state = ii_state_flush;
                 return code;
             }
-            for (ty = 0; ty < tiff->height; ty += tiff->tile_height)
+
+            for (ty = 0; ty < tiff->height; ty += tiff->tile_height) {
                 for (tx = 0; tx < tiff->width; tx += tiff->tile_width) {
                     int y, s;
                     byte *row;
@@ -629,6 +651,12 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                     tiff->image.ImageMatrix.xx = tiff->xresolution / 72.0f;
                     tiff->image.ImageMatrix.yy = tiff->yresolution / 72.0f;
 
+                    if (tiff->tiled) {
+                        TIFFReadTile(tiff->handle, tiff->samples, tx, ty, 0, 0);
+                    } else if (planar != PLANARCONFIG_CONTIG) {
+                        tiff->image.format = gs_image_format_component_planar;
+                    }
+
                     code = gs_image_init(tiff->penum,
                                          &tiff->image,
                                          false,
@@ -639,24 +667,28 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                         return code;
                     }
 
-                    if (TIFFIsTiled(tiff->handle)) {
-                        TIFFReadTile(tiff->handle, tiff->samples, tx, ty, 0, 0);
-                    }
-
                     for (y = 0; y < tiff->tile_height; y++) {
-                        if (TIFFIsTiled(tiff->handle)) {
+                        if (tiff->tiled) {
                             row = tiff->samples + tiff->byte_width * y;
                         } else if (planar == PLANARCONFIG_CONTIG) {
                             row = tiff->samples;
                             TIFFReadScanline(tiff->handle, tiff->samples, ty+y, 0);
                         } else {
-                            int span = tiff->byte_width / tiff->num_comps; /* FIXME: Avoid division */
+                            int span = tiff->byte_width / tiff->num_comps;
                             row = tiff->samples;
-                            for (s = 0; s < tiff->num_comps; s++)
-                                TIFFReadScanline(tiff->handle, tiff->samples + span*s, ty+y, s);
+                            for (s = 0; s < tiff->num_comps; s++) {
+                                plane_data[s].data = row;
+                                plane_data[s].size = span;
+                                row += span;
+                                TIFFReadScanline(tiff->handle, plane_data[s].data, ty+y, s);
+                            }
                         }
 
-                        code = gs_image_next(tiff->penum, row, tiff->byte_width, &used);
+                        if (tiff->image.format == gs_image_format_component_planar) {
+                            code = gs_image_next_planes(tiff->penum, (gs_const_string *)&plane_data[0], used);
+                        } else {
+                            code = gs_image_next(tiff->penum, row, tiff->byte_width, used);
+                        }
                         if (code < 0) {
                             tiff->state = ii_state_flush;
                             break;
@@ -668,6 +700,7 @@ do_impl_process(pl_interp_implementation_t * impl, stream_cursor_read * pr, int
                         tiff->state = ii_state_flush;
                         break;
                     }
+                }
             }
             tiff->state = ii_state_flush;
             (void)pl_finish_page(tiff->memory->gs_lib_ctx->top_of_system,


Summary of changes:
 base/cal.mak             |   4 +-
 base/msvclib.mak         |   2 +-
 base/tiff.mak            |   2 +-
 configure.ac             |   6 +-
 gpdl/gpdl.mak            |  28 ++--
 gpdl/tifftop.c           | 388 +++++++++++++++++++++++++++++++++++++++++++----
 psi/msvc.mak             |   2 +-
 tiff/libtiff/tif_jpeg.c  |  19 ++-
 tiff/libtiff/tif_ojpeg.c | 127 ++++++++++++++--
 tiff/libtiff/tif_open.c  |   8 +
 tiff/libtiff/tiffio.h    |   3 +
 tiff/libtiff/tiffiop.h   |  19 +--
 12 files changed, 534 insertions(+), 74 deletions(-)