Hello!

I've got two new patches for the cause.

The first one adds transparent PNG support to PNGWriter and SplashBitmap. The uses for this are varied and many, so I think it makes sense to add this to the mainline, even though I don't have the pdftoppm patch to go along with it. (We're using it in a custom SplashOutputDev.)

The second one fixes a nasty bug in SplashBitmap that causes "pdftoppm -jpeg" to randomly produce corrupt images. Currently SplashBitmap frees its temporary buffers and later calls ImgWriter::close(). Problem is libjpeg still uses these temporary buffers during jpeg_finish_compress(). So if they've been reclaimed - bad things happen. Usually libjpeg aborts and produces an image with the bottom fifty or so rows missing. The patch also fixes the SplashBitmap throwing a splashErrGeneric despite success, which was due to a missing question mark before writer->close().

Hope you find it useful.

Cheers,

Stefan Thomas
>From 4a535b3b4e5a95d90194a7a7075e0293d6b62156 Mon Sep 17 00:00:00 2001
From: Stefan Thomas <tho...@eload24.com>
Date: Fri, 9 Jul 2010 22:59:04 +0100
Subject: [PATCH 1/2] Add support for transparent PNGs to PNGWriter and 
SplashBitmap.

---
 goo/PNGWriter.cc       |    5 +-
 goo/PNGWriter.h        |    4 +-
 splash/SplashBitmap.cc |  130 ++++++++++++++++++++++++++++++++++++++++++++----
 splash/SplashBitmap.h  |    5 ++-
 splash/SplashTypes.h   |    3 +-
 5 files changed, 132 insertions(+), 15 deletions(-)

diff --git a/goo/PNGWriter.cc b/goo/PNGWriter.cc
index aebab9e..1aa9532 100644
--- a/goo/PNGWriter.cc
+++ b/goo/PNGWriter.cc
@@ -18,8 +18,9 @@
 
 #include "poppler/Error.h"
 
-PNGWriter::PNGWriter()
+PNGWriter::PNGWriter(GBool withAlphaChannel)
 {
+       this->withAlphaChannel = withAlphaChannel;
 }
 
 PNGWriter::~PNGWriter()
@@ -59,7 +60,7 @@ bool PNGWriter::init(FILE *f, int width, int height, int 
hDPI, int vDPI)
        png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
 
        png_byte bit_depth = 8;
-       png_byte color_type = PNG_COLOR_TYPE_RGB;
+       png_byte color_type = (withAlphaChannel) ? PNG_COLOR_TYPE_RGB_ALPHA : 
PNG_COLOR_TYPE_RGB;
        png_byte interlace_type = PNG_INTERLACE_NONE;
 
        png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, 
interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
diff --git a/goo/PNGWriter.h b/goo/PNGWriter.h
index 64ffc67..70bc86d 100644
--- a/goo/PNGWriter.h
+++ b/goo/PNGWriter.h
@@ -22,11 +22,12 @@
 #include <cstdio>
 #include <png.h>
 #include "ImgWriter.h"
+#include "goo/gtypes.h"
 
 class PNGWriter : public ImgWriter
 {
        public:
-               PNGWriter();
+               PNGWriter(GBool withAlphaChannel = gFalse);
                ~PNGWriter();
                
                bool init(FILE *f, int width, int height, int hDPI, int vDPI);
@@ -39,6 +40,7 @@ class PNGWriter : public ImgWriter
        private:
                png_structp png_ptr;
                png_infop info_ptr;
+               GBool withAlphaChannel;
 };
 
 #endif
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index f983439..84d8666 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -288,13 +288,20 @@ SplashError 
SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileN
 
 SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, 
int hDPI, int vDPI) {
   ImgWriter *writer;
-       SplashError e;
+  SplashError e;
+  
+  GBool withAlpha = gFalse;
   
   switch (format) {
     #ifdef ENABLE_LIBPNG
     case splashFormatPng:
          writer = new PNGWriter();
       break;
+    
+    case splashFormatPngAlpha:
+         writer = new PNGWriter(gTrue);
+         withAlpha = gTrue;
+      break;
     #endif
 
     #ifdef ENABLE_LIBJPEG
@@ -310,12 +317,15 @@ SplashError 
SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, in
       return splashErrGeneric;
   }
 
-       e = writeImgFile(writer, f, hDPI, vDPI);
-       delete writer;
-       return e;
+  e = writeImgFile(writer, f, hDPI, vDPI, withAlpha);
+  delete writer;
+  return e;
 }
 
-SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, 
int vDPI) {
+SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, 
int vDPI, GBool withAlpha)
+{
+  SplashError e;
+  
   if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != 
splashModeMono1 && mode != splashModeXBGR8) {
     error(-1, "unsupported SplashBitmap mode");
     return splashErrGeneric;
@@ -324,7 +334,24 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer, 
FILE *f, int hDPI, int
   if (!writer->init(f, width, height, hDPI, vDPI)) {
     return splashErrGeneric;
   }
+  
+  if (withAlpha) {
+    e = writeImgDataRGB(writer);
+  } else {
+    e = writeImgDataRGBA(writer);
+  }
+  
+  if (e) return e;
+  
+  if (writer->close()) {
+    return splashErrGeneric;
+  }
+
+  return splashOk;
+}
 
+SplashError SplashBitmap::writeImgDataRGB(ImgWriter *writer)
+{
   switch (mode) {
     case splashModeRGB8:
     {
@@ -408,10 +435,93 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer, 
FILE *f, int hDPI, int
     // can't happen
     break;
   }
-  
-  if (writer->close()) {
-    return splashErrGeneric;
-  }
+}
 
-  return splashOk;
+SplashError SplashBitmap::writeImgDataRGBA(ImgWriter *writer)
+{
+  unsigned char *row = new unsigned char[4 * width];
+      
+  switch (mode) {
+    case splashModeRGB8:
+    {
+      for (int y = 0; y < height; y++) {
+        // Convert into a PNG row
+        for (int x = 0; x < width; x++) {
+          row[4*x] = data[y * rowSize + 3*x];
+          row[4*x+1] = data[y * rowSize + 3*x + 1];
+          row[4*x+2] = data[y * rowSize + 3*x + 2];
+          row[4*x+3] = alpha[y * width + x];
+        }
+
+        if (!writer->writeRow(&row)) {
+          delete[] row;
+          return splashErrGeneric;
+        }
+      }
+    }
+    break;
+    
+    case splashModeXBGR8:
+    {
+      for (int y = 0; y < height; y++) {
+        // Convert into a PNG row
+        for (int x = 0; x < width; x++) {
+          row[4*x] = data[y * rowSize + x * 4 + 2];
+          row[4*x+1] = data[y * rowSize + x * 4 + 1];
+          row[4*x+2] = data[y * rowSize + x * 4];
+          row[4*x+3] = alpha[y * width + x];
+        }
+
+        if (!writer->writeRow(&row)) {
+          delete[] row;
+          return splashErrGeneric;
+        }
+      }
+    }
+    break;
+    
+    case splashModeMono8:
+    {
+      for (int y = 0; y < height; y++) {
+        // Convert into a PNG row
+        for (int x = 0; x < width; x++) {
+          row[4*x] = data[y * rowSize + x];
+          row[4*x+1] = data[y * rowSize + x];
+          row[4*x+2] = data[y * rowSize + x];
+          row[4*x+3] = alpha[y * width + x];
+        }
+
+        if (!writer->writeRow(&row)) {
+          delete[] row;
+          return splashErrGeneric;
+        }
+      }
+    }
+    break;
+    
+    case splashModeMono1:
+    {
+      for (int y = 0; y < height; y++) {
+        // Convert into a PNG row
+        for (int x = 0; x < width; x++) {
+          getPixel(x, y, &row[4*x]);
+          row[4*x+1] = row[4*x];
+          row[4*x+2] = row[4*x];
+          row[4*x+3] = alpha[y * width + x];
+        }
+
+        if (!writer->writeRow(&row)) {
+          delete[] row;
+          return splashErrGeneric;
+        }
+      }
+    }
+    break;
+    
+    default:
+    // can't happen
+    break;
+  }
+  
+  delete[] row;
 }
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index e741a91..ec5b397 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -65,13 +65,16 @@ public:
   
   SplashError writeImgFile(SplashImageFileFormat format, char *fileName, int 
hDPI, int vDPI);
   SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, 
int vDPI);
-  SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI);
+  SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI, 
GBool withAlpha = gFalse);
 
   void getPixel(int x, int y, SplashColorPtr pixel);
   Guchar getAlpha(int x, int y);
 
 private:
 
+  SplashError writeImgDataRGB(ImgWriter *writer);
+  SplashError writeImgDataRGBA(ImgWriter *writer);
+
   int width, height;           // size of bitmap
   int rowSize;                 // size of one row of data, in bytes
                                //   - negative for bottom-up bitmaps
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h
index 993dd46..3e34ea7 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -160,7 +160,8 @@ typedef int SplashError;
 
 enum SplashImageFileFormat {
   splashFormatJpeg,
-  splashFormatPng
+  splashFormatPng,
+  splashFormatPngAlpha
 };
 
 #endif
-- 
1.7.0.4

>From 6efd015f0f49da605caf74083bd48cc3e01df353 Mon Sep 17 00:00:00 2001
From: Stefan Thomas <tho...@eload24.com>
Date: Fri, 9 Jul 2010 23:46:36 +0100
Subject: [PATCH 2/2] Fixes bug where libjpeg would create corrupted/incomplete 
images.

This bug occurred when libjpeg tried to access temporary memory which had 
already been freed before ImgWriter->close() was called.
---
 splash/SplashBitmap.cc |   21 ++++++++++++++++-----
 1 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index 84d8666..e0fa788 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -335,17 +335,13 @@ SplashError SplashBitmap::writeImgFile(ImgWriter *writer, 
FILE *f, int hDPI, int
     return splashErrGeneric;
   }
   
-  if (withAlpha) {
+  if (!withAlpha) {
     e = writeImgDataRGB(writer);
   } else {
     e = writeImgDataRGBA(writer);
   }
   
   if (e) return e;
-  
-  if (writer->close()) {
-    return splashErrGeneric;
-  }
 
   return splashOk;
 }
@@ -367,6 +363,9 @@ SplashError SplashBitmap::writeImgDataRGB(ImgWriter *writer)
         delete[] row_pointers;
         return splashErrGeneric;
       }
+      if (!writer->close()) {
+        return splashErrGeneric;
+      }
       delete[] row_pointers;
     }
     break;
@@ -387,6 +386,9 @@ SplashError SplashBitmap::writeImgDataRGB(ImgWriter *writer)
           return splashErrGeneric;
         }
       }
+      if (!writer->close()) {
+        return splashErrGeneric;
+      }
       delete[] row;
     }
     break;
@@ -407,6 +409,9 @@ SplashError SplashBitmap::writeImgDataRGB(ImgWriter *writer)
           return splashErrGeneric;
         }
       }
+      if (!writer->close()) {
+        return splashErrGeneric;
+      }
       delete[] row;
     }
     break;
@@ -427,6 +432,9 @@ SplashError SplashBitmap::writeImgDataRGB(ImgWriter *writer)
           return splashErrGeneric;
         }
       }
+      if (!writer->close()) {
+        return splashErrGeneric;
+      }
       delete[] row;
     }
     break;
@@ -523,5 +531,8 @@ SplashError SplashBitmap::writeImgDataRGBA(ImgWriter 
*writer)
     break;
   }
   
+  if (!writer->close()) {
+    return splashErrGeneric;
+  }
   delete[] row;
 }
-- 
1.7.0.4

_______________________________________________
poppler mailing list
poppler@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to