src/gui/image/qpnghandler.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
--- a/src/gui/image/qpnghandler.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/gui/image/qpnghandler.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -50,8 +50,13 @@
 #include <qvariant.h>
 #include <qvector.h>
 
+#ifdef QT_USE_BUNDLED_LIBPNG
+#include <../../3rdparty/libpng/png.h>
+#include <../../3rdparty/libpng/pngconf.h>
+#else
 #include <png.h>
 #include <pngconf.h>
+#endif
 
 #ifdef Q_OS_WINCE
 #define CALLBACK_CALL_TYPE        __cdecl
@@ -162,11 +167,16 @@
     png_uint_32 height;
     int bit_depth;
     int color_type;
+    png_bytep trans_alpha = 0;
+    png_color_16p trans_color_p = 0;
+    int num_trans;
+    png_colorp palette = 0;
+    int num_palette;
     png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
 
     if (color_type == PNG_COLOR_TYPE_GRAY) {
         // Black & White or 8-bit grayscale
-        if (bit_depth == 1 && info_ptr->channels == 1) {
+        if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) {
             png_set_invert_mono(png_ptr);
             png_read_update_info(png_ptr, info_ptr);
             if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) {
@@ -207,20 +217,16 @@
                 int c = i*255/(ncols-1);
                 image.setColor(i, qRgba(c,c,c,0xff));
             }
-            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
-#if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4)
-                const int g = info_ptr->trans_values.gray;
-#else
-                const int g = info_ptr->trans_color.gray;
-#endif
+            if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
+                const int g = trans_color_p->gray;
                 if (g < ncols) {
                     image.setColor(g, 0);
                 }
             }
         }
     } else if (color_type == PNG_COLOR_TYPE_PALETTE
-               && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)
-               && info_ptr->num_palette <= 256)
+               && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)
+               && num_palette <= 256)
     {
         // 1-bit and 8-bit color
         if (bit_depth != 1)
@@ -233,29 +239,26 @@
             if (image.isNull())
                 return;
         }
-        image.setColorCount(info_ptr->num_palette);
+        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
+        image.setColorCount(num_palette);
         int i = 0;
-        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
-            while (i < info_ptr->num_trans) {
+        if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) {
+            while (i < num_trans) {
                 image.setColor(i, qRgba(
-                    info_ptr->palette[i].red,
-                    info_ptr->palette[i].green,
-                    info_ptr->palette[i].blue,
-#if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4)
-                    info_ptr->trans[i]
-#else
-                    info_ptr->trans_alpha[i]
-#endif
+                    palette[i].red,
+                    palette[i].green,
+                    palette[i].blue,
+                    trans_alpha[i]
                    )
                );
                 i++;
             }
         }
-        while (i < info_ptr->num_palette) {
+        while (i < num_palette) {
             image.setColor(i, qRgba(
-                info_ptr->palette[i].red,
-                info_ptr->palette[i].green,
-                info_ptr->palette[i].blue,
+                palette[i].red,
+                palette[i].green,
+                palette[i].blue,
                 0xff
                )
            );
@@ -531,33 +534,36 @@
         QImage::Format format = QImage::Format_Invalid;
         png_uint_32 width, height;
         int bit_depth, color_type;
-        if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) {
+        png_colorp palette;
+        int num_palette;
+        png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
+        if (color_type == PNG_COLOR_TYPE_GRAY) {
             // Black & White or 8-bit grayscale
-            if (info_ptr->bit_depth == 1 && info_ptr->channels == 1) {
+            if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) {
                 format = QImage::Format_Mono;
-            } else if (info_ptr->bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+            } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
                 format = QImage::Format_ARGB32;
             } else {
                 format = QImage::Format_Indexed8;
             }
-        } else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE
-                && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)
-                   && info_ptr->num_palette <= 256)
+        } else if (color_type == PNG_COLOR_TYPE_PALETTE
+                   && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)
+                   && num_palette <= 256)
         {
             // 1-bit and 8-bit color
-            if (info_ptr->bit_depth != 1)
+            if (bit_depth != 1)
                 png_set_packing(png_ptr);
             png_read_update_info(png_ptr, info_ptr);
             png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
             format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8;
         } else {
             // 32-bit
-            if (info_ptr->bit_depth == 16)
+            if (bit_depth == 16)
                 png_set_strip_16(png_ptr);
 
             format = QImage::Format_ARGB32;
             // Only add filler if no alpha, or we can get 5 channel data.
-            if (!(info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+            if (!(color_type & PNG_COLOR_MASK_ALPHA)
                 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
                 // We want 4 bytes, but it isn't an alpha channel
                 format = QImage::Format_RGB32;
@@ -648,7 +654,7 @@
         text_ptr[i].text = qstrdup(value.constData());
         text_ptr[i].text_length = 0;
         text_ptr[i].itxt_length = value.size();
-        text_ptr[i].lang = "UTF-8";
+        text_ptr[i].lang = const_cast<char*>("UTF-8");
         text_ptr[i].lang_key = qstrdup(it.key().toUtf8().constData());
 #endif
         ++i;
@@ -735,64 +741,51 @@
         png_set_compression_level(png_ptr, quality);
     }
 
-    if (gamma != 0.0) {
-        png_set_gAMA(png_ptr, info_ptr, 1.0/gamma);
-    }
-
     png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn);
 
-    info_ptr->channels =
-        (image.depth() == 32)
-        ? (image.format() == QImage::Format_RGB32 ? 3 : 4)
-        : 1;
-
     png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(),
         image.depth() == 1 ? 1 : 8 /* per channel */,
         image.depth() == 32
             ? image.format() == QImage::Format_RGB32
                 ? PNG_COLOR_TYPE_RGB
                 : PNG_COLOR_TYPE_RGB_ALPHA
-            : PNG_COLOR_TYPE_PALETTE, 0, 0, 0);
+            : PNG_COLOR_TYPE_PALETTE, 0, 0, 0);  // also sets #channels
 
+    if (gamma != 0.0) {
+        png_set_gAMA(png_ptr, info_ptr, 1.0/gamma);
+    }
 
-    //png_set_sBIT(png_ptr, info_ptr, 8);
-    info_ptr->sig_bit.red = 8;
-    info_ptr->sig_bit.green = 8;
-    info_ptr->sig_bit.blue = 8;
+    png_color_8 sig_bit;
+    sig_bit.red = 8;
+    sig_bit.green = 8;
+    sig_bit.blue = 8;
+    sig_bit.alpha = image.hasAlphaChannel() ? 8 : 0;
+    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
 
     if (image.format() == QImage::Format_MonoLSB)
        png_set_packswap(png_ptr);
 
-    png_colorp palette = 0;
-    png_bytep copy_trans = 0;
     if (image.colorCount()) {
         // Paletted
-        int num_palette = image.colorCount();
-        palette = new png_color[num_palette];
-        png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
-        int* trans = new int[num_palette];
+        int num_palette = qMin(256, image.colorCount());
+        png_color palette[256];
+        png_byte trans[256];
         int num_trans = 0;
         for (int i=0; i<num_palette; i++) {
-            QRgb rgb=image.color(i);
-            info_ptr->palette[i].red = qRed(rgb);
-            info_ptr->palette[i].green = qGreen(rgb);
-            info_ptr->palette[i].blue = qBlue(rgb);
-            trans[i] = rgb >> 24;
+            QRgb rgba=image.color(i);
+            palette[i].red = qRed(rgba);
+            palette[i].green = qGreen(rgba);
+            palette[i].blue = qBlue(rgba);
+            trans[i] = qAlpha(rgba);
             if (trans[i] < 255) {
                 num_trans = i+1;
             }
         }
+        png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
+
         if (num_trans) {
-            copy_trans = new png_byte[num_trans];
-            for (int i=0; i<num_trans; i++)
-                copy_trans[i] = trans[i];
-            png_set_tRNS(png_ptr, info_ptr, copy_trans, num_trans, 0);
+            png_set_tRNS(png_ptr, info_ptr, trans, num_trans, 0);
         }
-        delete [] trans;
-    }
-
-    if (image.format() != QImage::Format_RGB32) {
-        info_ptr->sig_bit.alpha = 8;
     }
 
     // Swap ARGB to RGBA (normal PNG format) before saving on
@@ -868,11 +861,6 @@
     png_write_end(png_ptr, info_ptr);
     frames_written++;
 
-    if (palette)
-        delete [] palette;
-    if (copy_trans)
-        delete [] copy_trans;
-
     png_destroy_write_struct(&png_ptr, &info_ptr);
 
     return true;
@@ -958,7 +946,8 @@
     else if (option == Description)
         return d->description;
     else if (option == Size)
-        return QSize(d->info_ptr->width, d->info_ptr->height);
+        return QSize(png_get_image_width(d->png_ptr, d->info_ptr),
+                     png_get_image_height(d->png_ptr, d->info_ptr));
     else if (option == ImageFormat)
         return d->readImageFormat();
     return 0;