src/gui/image/qpnghandler.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    48 #include <qlist.h>
    48 #include <qlist.h>
    49 #include <qtextcodec.h>
    49 #include <qtextcodec.h>
    50 #include <qvariant.h>
    50 #include <qvariant.h>
    51 #include <qvector.h>
    51 #include <qvector.h>
    52 
    52 
       
    53 #ifdef QT_USE_BUNDLED_LIBPNG
       
    54 #include <../../3rdparty/libpng/png.h>
       
    55 #include <../../3rdparty/libpng/pngconf.h>
       
    56 #else
    53 #include <png.h>
    57 #include <png.h>
    54 #include <pngconf.h>
    58 #include <pngconf.h>
       
    59 #endif
    55 
    60 
    56 #ifdef Q_OS_WINCE
    61 #ifdef Q_OS_WINCE
    57 #define CALLBACK_CALL_TYPE        __cdecl
    62 #define CALLBACK_CALL_TYPE        __cdecl
    58 #else
    63 #else
    59 #define CALLBACK_CALL_TYPE
    64 #define CALLBACK_CALL_TYPE
   160 
   165 
   161     png_uint_32 width;
   166     png_uint_32 width;
   162     png_uint_32 height;
   167     png_uint_32 height;
   163     int bit_depth;
   168     int bit_depth;
   164     int color_type;
   169     int color_type;
       
   170     png_bytep trans_alpha = 0;
       
   171     png_color_16p trans_color_p = 0;
       
   172     int num_trans;
       
   173     png_colorp palette = 0;
       
   174     int num_palette;
   165     png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
   175     png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
   166 
   176 
   167     if (color_type == PNG_COLOR_TYPE_GRAY) {
   177     if (color_type == PNG_COLOR_TYPE_GRAY) {
   168         // Black & White or 8-bit grayscale
   178         // Black & White or 8-bit grayscale
   169         if (bit_depth == 1 && info_ptr->channels == 1) {
   179         if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) {
   170             png_set_invert_mono(png_ptr);
   180             png_set_invert_mono(png_ptr);
   171             png_read_update_info(png_ptr, info_ptr);
   181             png_read_update_info(png_ptr, info_ptr);
   172             if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) {
   182             if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) {
   173                 image = QImage(width, height, QImage::Format_Mono);
   183                 image = QImage(width, height, QImage::Format_Mono);
   174                 if (image.isNull())
   184                 if (image.isNull())
   205             image.setColorCount(ncols);
   215             image.setColorCount(ncols);
   206             for (int i=0; i<ncols; i++) {
   216             for (int i=0; i<ncols; i++) {
   207                 int c = i*255/(ncols-1);
   217                 int c = i*255/(ncols-1);
   208                 image.setColor(i, qRgba(c,c,c,0xff));
   218                 image.setColor(i, qRgba(c,c,c,0xff));
   209             }
   219             }
   210             if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
   220             if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
   211 #if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4)
   221                 const int g = trans_color_p->gray;
   212                 const int g = info_ptr->trans_values.gray;
       
   213 #else
       
   214                 const int g = info_ptr->trans_color.gray;
       
   215 #endif
       
   216                 if (g < ncols) {
   222                 if (g < ncols) {
   217                     image.setColor(g, 0);
   223                     image.setColor(g, 0);
   218                 }
   224                 }
   219             }
   225             }
   220         }
   226         }
   221     } else if (color_type == PNG_COLOR_TYPE_PALETTE
   227     } else if (color_type == PNG_COLOR_TYPE_PALETTE
   222                && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)
   228                && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)
   223                && info_ptr->num_palette <= 256)
   229                && num_palette <= 256)
   224     {
   230     {
   225         // 1-bit and 8-bit color
   231         // 1-bit and 8-bit color
   226         if (bit_depth != 1)
   232         if (bit_depth != 1)
   227             png_set_packing(png_ptr);
   233             png_set_packing(png_ptr);
   228         png_read_update_info(png_ptr, info_ptr);
   234         png_read_update_info(png_ptr, info_ptr);
   231         if (image.size() != QSize(width, height) || image.format() != format) {
   237         if (image.size() != QSize(width, height) || image.format() != format) {
   232             image = QImage(width, height, format);
   238             image = QImage(width, height, format);
   233             if (image.isNull())
   239             if (image.isNull())
   234                 return;
   240                 return;
   235         }
   241         }
   236         image.setColorCount(info_ptr->num_palette);
   242         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
       
   243         image.setColorCount(num_palette);
   237         int i = 0;
   244         int i = 0;
   238         if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
   245         if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) {
   239             while (i < info_ptr->num_trans) {
   246             while (i < num_trans) {
   240                 image.setColor(i, qRgba(
   247                 image.setColor(i, qRgba(
   241                     info_ptr->palette[i].red,
   248                     palette[i].red,
   242                     info_ptr->palette[i].green,
   249                     palette[i].green,
   243                     info_ptr->palette[i].blue,
   250                     palette[i].blue,
   244 #if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4)
   251                     trans_alpha[i]
   245                     info_ptr->trans[i]
       
   246 #else
       
   247                     info_ptr->trans_alpha[i]
       
   248 #endif
       
   249                    )
   252                    )
   250                );
   253                );
   251                 i++;
   254                 i++;
   252             }
   255             }
   253         }
   256         }
   254         while (i < info_ptr->num_palette) {
   257         while (i < num_palette) {
   255             image.setColor(i, qRgba(
   258             image.setColor(i, qRgba(
   256                 info_ptr->palette[i].red,
   259                 palette[i].red,
   257                 info_ptr->palette[i].green,
   260                 palette[i].green,
   258                 info_ptr->palette[i].blue,
   261                 palette[i].blue,
   259                 0xff
   262                 0xff
   260                )
   263                )
   261            );
   264            );
   262             i++;
   265             i++;
   263         }
   266         }
   529 QImage::Format QPngHandlerPrivate::readImageFormat()
   532 QImage::Format QPngHandlerPrivate::readImageFormat()
   530 {
   533 {
   531         QImage::Format format = QImage::Format_Invalid;
   534         QImage::Format format = QImage::Format_Invalid;
   532         png_uint_32 width, height;
   535         png_uint_32 width, height;
   533         int bit_depth, color_type;
   536         int bit_depth, color_type;
   534         if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) {
   537         png_colorp palette;
       
   538         int num_palette;
       
   539         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
       
   540         if (color_type == PNG_COLOR_TYPE_GRAY) {
   535             // Black & White or 8-bit grayscale
   541             // Black & White or 8-bit grayscale
   536             if (info_ptr->bit_depth == 1 && info_ptr->channels == 1) {
   542             if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) {
   537                 format = QImage::Format_Mono;
   543                 format = QImage::Format_Mono;
   538             } else if (info_ptr->bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
   544             } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
   539                 format = QImage::Format_ARGB32;
   545                 format = QImage::Format_ARGB32;
   540             } else {
   546             } else {
   541                 format = QImage::Format_Indexed8;
   547                 format = QImage::Format_Indexed8;
   542             }
   548             }
   543         } else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE
   549         } else if (color_type == PNG_COLOR_TYPE_PALETTE
   544                 && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)
   550                    && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)
   545                    && info_ptr->num_palette <= 256)
   551                    && num_palette <= 256)
   546         {
   552         {
   547             // 1-bit and 8-bit color
   553             // 1-bit and 8-bit color
   548             if (info_ptr->bit_depth != 1)
   554             if (bit_depth != 1)
   549                 png_set_packing(png_ptr);
   555                 png_set_packing(png_ptr);
   550             png_read_update_info(png_ptr, info_ptr);
   556             png_read_update_info(png_ptr, info_ptr);
   551             png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
   557             png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
   552             format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8;
   558             format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8;
   553         } else {
   559         } else {
   554             // 32-bit
   560             // 32-bit
   555             if (info_ptr->bit_depth == 16)
   561             if (bit_depth == 16)
   556                 png_set_strip_16(png_ptr);
   562                 png_set_strip_16(png_ptr);
   557 
   563 
   558             format = QImage::Format_ARGB32;
   564             format = QImage::Format_ARGB32;
   559             // Only add filler if no alpha, or we can get 5 channel data.
   565             // Only add filler if no alpha, or we can get 5 channel data.
   560             if (!(info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
   566             if (!(color_type & PNG_COLOR_MASK_ALPHA)
   561                 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
   567                 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
   562                 // We want 4 bytes, but it isn't an alpha channel
   568                 // We want 4 bytes, but it isn't an alpha channel
   563                 format = QImage::Format_RGB32;
   569                 format = QImage::Format_RGB32;
   564             }
   570             }
   565         }
   571         }
   646 #else
   652 #else
   647         QByteArray value = it.value().toUtf8();
   653         QByteArray value = it.value().toUtf8();
   648         text_ptr[i].text = qstrdup(value.constData());
   654         text_ptr[i].text = qstrdup(value.constData());
   649         text_ptr[i].text_length = 0;
   655         text_ptr[i].text_length = 0;
   650         text_ptr[i].itxt_length = value.size();
   656         text_ptr[i].itxt_length = value.size();
   651         text_ptr[i].lang = "UTF-8";
   657         text_ptr[i].lang = const_cast<char*>("UTF-8");
   652         text_ptr[i].lang_key = qstrdup(it.key().toUtf8().constData());
   658         text_ptr[i].lang_key = qstrdup(it.key().toUtf8().constData());
   653 #endif
   659 #endif
   654         ++i;
   660         ++i;
   655         ++it;
   661         ++it;
   656     }
   662     }
   733             quality = 9;
   739             quality = 9;
   734         }
   740         }
   735         png_set_compression_level(png_ptr, quality);
   741         png_set_compression_level(png_ptr, quality);
   736     }
   742     }
   737 
   743 
   738     if (gamma != 0.0) {
       
   739         png_set_gAMA(png_ptr, info_ptr, 1.0/gamma);
       
   740     }
       
   741 
       
   742     png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn);
   744     png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn);
   743 
       
   744     info_ptr->channels =
       
   745         (image.depth() == 32)
       
   746         ? (image.format() == QImage::Format_RGB32 ? 3 : 4)
       
   747         : 1;
       
   748 
   745 
   749     png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(),
   746     png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(),
   750         image.depth() == 1 ? 1 : 8 /* per channel */,
   747         image.depth() == 1 ? 1 : 8 /* per channel */,
   751         image.depth() == 32
   748         image.depth() == 32
   752             ? image.format() == QImage::Format_RGB32
   749             ? image.format() == QImage::Format_RGB32
   753                 ? PNG_COLOR_TYPE_RGB
   750                 ? PNG_COLOR_TYPE_RGB
   754                 : PNG_COLOR_TYPE_RGB_ALPHA
   751                 : PNG_COLOR_TYPE_RGB_ALPHA
   755             : PNG_COLOR_TYPE_PALETTE, 0, 0, 0);
   752             : PNG_COLOR_TYPE_PALETTE, 0, 0, 0);  // also sets #channels
   756 
   753 
   757 
   754     if (gamma != 0.0) {
   758     //png_set_sBIT(png_ptr, info_ptr, 8);
   755         png_set_gAMA(png_ptr, info_ptr, 1.0/gamma);
   759     info_ptr->sig_bit.red = 8;
   756     }
   760     info_ptr->sig_bit.green = 8;
   757 
   761     info_ptr->sig_bit.blue = 8;
   758     png_color_8 sig_bit;
       
   759     sig_bit.red = 8;
       
   760     sig_bit.green = 8;
       
   761     sig_bit.blue = 8;
       
   762     sig_bit.alpha = image.hasAlphaChannel() ? 8 : 0;
       
   763     png_set_sBIT(png_ptr, info_ptr, &sig_bit);
   762 
   764 
   763     if (image.format() == QImage::Format_MonoLSB)
   765     if (image.format() == QImage::Format_MonoLSB)
   764        png_set_packswap(png_ptr);
   766        png_set_packswap(png_ptr);
   765 
   767 
   766     png_colorp palette = 0;
       
   767     png_bytep copy_trans = 0;
       
   768     if (image.colorCount()) {
   768     if (image.colorCount()) {
   769         // Paletted
   769         // Paletted
   770         int num_palette = image.colorCount();
   770         int num_palette = qMin(256, image.colorCount());
   771         palette = new png_color[num_palette];
   771         png_color palette[256];
   772         png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
   772         png_byte trans[256];
   773         int* trans = new int[num_palette];
       
   774         int num_trans = 0;
   773         int num_trans = 0;
   775         for (int i=0; i<num_palette; i++) {
   774         for (int i=0; i<num_palette; i++) {
   776             QRgb rgb=image.color(i);
   775             QRgb rgba=image.color(i);
   777             info_ptr->palette[i].red = qRed(rgb);
   776             palette[i].red = qRed(rgba);
   778             info_ptr->palette[i].green = qGreen(rgb);
   777             palette[i].green = qGreen(rgba);
   779             info_ptr->palette[i].blue = qBlue(rgb);
   778             palette[i].blue = qBlue(rgba);
   780             trans[i] = rgb >> 24;
   779             trans[i] = qAlpha(rgba);
   781             if (trans[i] < 255) {
   780             if (trans[i] < 255) {
   782                 num_trans = i+1;
   781                 num_trans = i+1;
   783             }
   782             }
   784         }
   783         }
       
   784         png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
       
   785 
   785         if (num_trans) {
   786         if (num_trans) {
   786             copy_trans = new png_byte[num_trans];
   787             png_set_tRNS(png_ptr, info_ptr, trans, num_trans, 0);
   787             for (int i=0; i<num_trans; i++)
   788         }
   788                 copy_trans[i] = trans[i];
       
   789             png_set_tRNS(png_ptr, info_ptr, copy_trans, num_trans, 0);
       
   790         }
       
   791         delete [] trans;
       
   792     }
       
   793 
       
   794     if (image.format() != QImage::Format_RGB32) {
       
   795         info_ptr->sig_bit.alpha = 8;
       
   796     }
   789     }
   797 
   790 
   798     // Swap ARGB to RGBA (normal PNG format) before saving on
   791     // Swap ARGB to RGBA (normal PNG format) before saving on
   799     // BigEndian machines
   792     // BigEndian machines
   800     if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
   793     if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
   866     delete [] row_pointers;
   859     delete [] row_pointers;
   867 
   860 
   868     png_write_end(png_ptr, info_ptr);
   861     png_write_end(png_ptr, info_ptr);
   869     frames_written++;
   862     frames_written++;
   870 
   863 
   871     if (palette)
       
   872         delete [] palette;
       
   873     if (copy_trans)
       
   874         delete [] copy_trans;
       
   875 
       
   876     png_destroy_write_struct(&png_ptr, &info_ptr);
   864     png_destroy_write_struct(&png_ptr, &info_ptr);
   877 
   865 
   878     return true;
   866     return true;
   879 }
   867 }
   880 
   868 
   956     else if (option == Quality)
   944     else if (option == Quality)
   957         return d->quality;
   945         return d->quality;
   958     else if (option == Description)
   946     else if (option == Description)
   959         return d->description;
   947         return d->description;
   960     else if (option == Size)
   948     else if (option == Size)
   961         return QSize(d->info_ptr->width, d->info_ptr->height);
   949         return QSize(png_get_image_width(d->png_ptr, d->info_ptr),
       
   950                      png_get_image_height(d->png_ptr, d->info_ptr));
   962     else if (option == ImageFormat)
   951     else if (option == ImageFormat)
   963         return d->readImageFormat();
   952         return d->readImageFormat();
   964     return 0;
   953     return 0;
   965 }
   954 }
   966 
   955