Changeset 846 for trunk/src/gui/image/qpnghandler.cpp
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/src/gui/image/qpnghandler.cpp
r651 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 51 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 57 #include <png.h> 54 58 #include <pngconf.h> 59 #endif 55 60 56 61 #ifdef Q_OS_WINCE … … 77 82 Never to grayscale. 78 83 */ 84 85 class QPngHandlerPrivate 86 { 87 public: 88 enum State { 89 Ready, 90 ReadHeader, 91 ReadingEnd, 92 Error 93 }; 94 95 QPngHandlerPrivate(QPngHandler *qq) 96 : gamma(0.0), quality(2), png_ptr(0), info_ptr(0), 97 end_info(0), row_pointers(0), state(Ready), q(qq) 98 { } 99 100 float gamma; 101 int quality; 102 QString description; 103 104 png_struct *png_ptr; 105 png_info *info_ptr; 106 png_info *end_info; 107 png_byte **row_pointers; 108 109 bool readPngHeader(); 110 bool readPngImage(QImage *image); 111 112 QImage::Format readImageFormat(); 113 114 State state; 115 116 QPngHandler *q; 117 }; 118 79 119 80 120 #if defined(Q_C_CALLBACKS) … … 114 154 void CALLBACK_CALL_TYPE iod_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) 115 155 { 116 QIODevice *in = (QIODevice *)png_get_io_ptr(png_ptr); 156 QPngHandlerPrivate *d = (QPngHandlerPrivate *)png_get_io_ptr(png_ptr); 157 QIODevice *in = d->q->device(); 158 159 if (d->state == QPngHandlerPrivate::ReadingEnd && !in->isSequential() && (in->size() - in->pos()) < 4 && length == 4) { 160 // Workaround for certain malformed PNGs that lack the final crc bytes 161 uchar endcrc[4] = { 0xae, 0x42, 0x60, 0x82 }; 162 qMemCopy(data, endcrc, 4); 163 in->seek(in->size()); 164 return; 165 } 117 166 118 167 while (length) { … … 163 212 int bit_depth; 164 213 int color_type; 214 png_bytep trans_alpha = 0; 215 png_color_16p trans_color_p = 0; 216 int num_trans; 217 png_colorp palette = 0; 218 int num_palette; 165 219 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); 166 220 167 221 if (color_type == PNG_COLOR_TYPE_GRAY) { 168 222 // Black & White or 8-bit grayscale 169 if (bit_depth == 1 && info_ptr->channels== 1) {223 if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { 170 224 png_set_invert_mono(png_ptr); 171 225 png_read_update_info(png_ptr, info_ptr); … … 208 262 image.setColor(i, qRgba(c,c,c,0xff)); 209 263 } 210 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 211 #if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4) 212 const int g = info_ptr->trans_values.gray; 213 #else 214 const int g = info_ptr->trans_color.gray; 215 #endif 264 if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) { 265 const int g = trans_color_p->gray; 216 266 if (g < ncols) { 217 267 image.setColor(g, 0); … … 220 270 } 221 271 } else if (color_type == PNG_COLOR_TYPE_PALETTE 222 && png_get_ valid(png_ptr, info_ptr, PNG_INFO_PLTE)223 && info_ptr->num_palette <= 256)272 && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) 273 && num_palette <= 256) 224 274 { 225 275 // 1-bit and 8-bit color … … 234 284 return; 235 285 } 236 image.setColorCount(info_ptr->num_palette); 286 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); 287 image.setColorCount(num_palette); 237 288 int i = 0; 238 if (png_get_ valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {239 while (i < info_ptr->num_trans) {289 if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) { 290 while (i < num_trans) { 240 291 image.setColor(i, qRgba( 241 info_ptr->palette[i].red, 242 info_ptr->palette[i].green, 243 info_ptr->palette[i].blue, 244 #if PNG_LIBPNG_VER_MAJOR < 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 4) 245 info_ptr->trans[i] 246 #else 247 info_ptr->trans_alpha[i] 248 #endif 292 palette[i].red, 293 palette[i].green, 294 palette[i].blue, 295 trans_alpha[i] 249 296 ) 250 297 ); … … 252 299 } 253 300 } 254 while (i < info_ptr->num_palette) {301 while (i < num_palette) { 255 302 image.setColor(i, qRgba( 256 info_ptr->palette[i].red,257 info_ptr->palette[i].green,258 info_ptr->palette[i].blue,303 palette[i].red, 304 palette[i].green, 305 palette[i].blue, 259 306 0xff 260 307 ) … … 312 359 #endif 313 360 314 class QPngHandlerPrivate315 {316 public:317 enum State {318 Ready,319 ReadHeader,320 Error321 };322 323 QPngHandlerPrivate(QPngHandler *qq)324 : gamma(0.0), quality(2), png_ptr(0), info_ptr(0),325 end_info(0), row_pointers(0), state(Ready), q(qq)326 { }327 328 float gamma;329 int quality;330 QString description;331 332 png_struct *png_ptr;333 png_info *info_ptr;334 png_info *end_info;335 png_byte **row_pointers;336 337 bool readPngHeader();338 bool readPngImage(QImage *image);339 340 QImage::Format readImageFormat();341 342 State state;343 344 QPngHandler *q;345 };346 361 347 362 /*! … … 377 392 } 378 393 379 png_set_read_fn(png_ptr, q->device(), iod_read_fn);394 png_set_read_fn(png_ptr, this, iod_read_fn); 380 395 png_read_info(png_ptr, info_ptr); 381 396 … … 387 402 while (num_text--) { 388 403 QString key, value; 389 #if defined(PNG_iTXt_SUPPORTED) 404 #if defined(PNG_iTXt_SUPPORTED) && !defined(QT_NO_TEXTCODEC) 390 405 if (text_ptr->lang) { 391 406 QTextCodec *codec = QTextCodec::codecForName(text_ptr->lang); … … 503 518 #endif 504 519 520 state = ReadingEnd; 505 521 png_read_end(png_ptr, end_info); 506 522 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); … … 532 548 png_uint_32 width, height; 533 549 int bit_depth, color_type; 534 if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY) { 550 png_colorp palette; 551 int num_palette; 552 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); 553 if (color_type == PNG_COLOR_TYPE_GRAY) { 535 554 // Black & White or 8-bit grayscale 536 if ( info_ptr->bit_depth == 1 && info_ptr->channels== 1) {555 if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { 537 556 format = QImage::Format_Mono; 538 } else if ( info_ptr->bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {557 } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 539 558 format = QImage::Format_ARGB32; 540 559 } else { 541 560 format = QImage::Format_Indexed8; 542 561 } 543 } else if ( info_ptr->color_type == PNG_COLOR_TYPE_PALETTE544 && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)545 && info_ptr->num_palette <= 256)562 } else if (color_type == PNG_COLOR_TYPE_PALETTE 563 && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) 564 && num_palette <= 256) 546 565 { 547 566 // 1-bit and 8-bit color 548 if ( info_ptr->bit_depth != 1)567 if (bit_depth != 1) 549 568 png_set_packing(png_ptr); 550 569 png_read_update_info(png_ptr, info_ptr); … … 553 572 } else { 554 573 // 32-bit 555 if ( info_ptr->bit_depth == 16)574 if (bit_depth == 16) 556 575 png_set_strip_16(png_ptr); 557 576 558 577 format = QImage::Format_ARGB32; 559 578 // Only add filler if no alpha, or we can get 5 channel data. 560 if (!( info_ptr->color_type & PNG_COLOR_MASK_ALPHA)579 if (!(color_type & PNG_COLOR_MASK_ALPHA) 561 580 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 562 581 // We want 4 bytes, but it isn't an alpha channel … … 649 668 text_ptr[i].text_length = 0; 650 669 text_ptr[i].itxt_length = value.size(); 651 text_ptr[i].lang = "UTF-8";670 text_ptr[i].lang = const_cast<char*>("UTF-8"); 652 671 text_ptr[i].lang_key = qstrdup(it.key().toUtf8().constData()); 653 672 #endif … … 673 692 } 674 693 675 bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image _in, int quality_in, const QString &description,694 bool Q_INTERNAL_WIN_NO_THROW QPNGImageWriter::writeImage(const QImage& image, int quality_in, const QString &description, 676 695 int off_x_in, int off_y_in) 677 696 { … … 679 698 Q_UNUSED(description); 680 699 #endif 681 682 QImage image;683 switch (image_in.format()) {684 case QImage::Format_ARGB32_Premultiplied:685 case QImage::Format_ARGB4444_Premultiplied:686 case QImage::Format_ARGB8555_Premultiplied:687 case QImage::Format_ARGB8565_Premultiplied:688 case QImage::Format_ARGB6666_Premultiplied:689 image = image_in.convertToFormat(QImage::Format_ARGB32);690 break;691 case QImage::Format_RGB16:692 case QImage::Format_RGB444:693 case QImage::Format_RGB555:694 case QImage::Format_RGB666:695 case QImage::Format_RGB888:696 image = image_in.convertToFormat(QImage::Format_RGB32);697 break;698 default:699 image = image_in;700 break;701 }702 700 703 701 QPoint offset = image.offset(); … … 707 705 png_structp png_ptr; 708 706 png_infop info_ptr; 709 png_bytep* row_pointers;710 707 711 708 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0); … … 736 733 } 737 734 735 png_set_write_fn(png_ptr, (void*)this, qpiw_write_fn, qpiw_flush_fn); 736 737 738 int color_type = 0; 739 if (image.colorCount()) 740 color_type = PNG_COLOR_TYPE_PALETTE; 741 else if (image.hasAlphaChannel()) 742 color_type = PNG_COLOR_TYPE_RGB_ALPHA; 743 else 744 color_type = PNG_COLOR_TYPE_RGB; 745 746 png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), 747 image.depth() == 1 ? 1 : 8, // per channel 748 color_type, 0, 0, 0); // sets #channels 749 738 750 if (gamma != 0.0) { 739 751 png_set_gAMA(png_ptr, info_ptr, 1.0/gamma); 740 752 } 741 753 742 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 749 png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), 750 image.depth() == 1 ? 1 : 8 /* per channel */, 751 image.depth() == 32 752 ? image.format() == QImage::Format_RGB32 753 ? PNG_COLOR_TYPE_RGB 754 : PNG_COLOR_TYPE_RGB_ALPHA 755 : PNG_COLOR_TYPE_PALETTE, 0, 0, 0); 756 757 758 //png_set_sBIT(png_ptr, info_ptr, 8); 759 info_ptr->sig_bit.red = 8; 760 info_ptr->sig_bit.green = 8; 761 info_ptr->sig_bit.blue = 8; 754 png_color_8 sig_bit; 755 sig_bit.red = 8; 756 sig_bit.green = 8; 757 sig_bit.blue = 8; 758 sig_bit.alpha = image.hasAlphaChannel() ? 8 : 0; 759 png_set_sBIT(png_ptr, info_ptr, &sig_bit); 762 760 763 761 if (image.format() == QImage::Format_MonoLSB) 764 762 png_set_packswap(png_ptr); 765 763 766 png_colorp palette = 0;767 png_bytep copy_trans = 0;768 764 if (image.colorCount()) { 769 765 // Paletted 770 int num_palette = image.colorCount(); 771 palette = new png_color[num_palette]; 772 png_set_PLTE(png_ptr, info_ptr, palette, num_palette); 773 int* trans = new int[num_palette]; 766 int num_palette = qMin(256, image.colorCount()); 767 png_color palette[256]; 768 png_byte trans[256]; 774 769 int num_trans = 0; 775 770 for (int i=0; i<num_palette; i++) { 776 QRgb rgb =image.color(i);777 info_ptr->palette[i].red = qRed(rgb);778 info_ptr->palette[i].green = qGreen(rgb);779 info_ptr->palette[i].blue = qBlue(rgb);780 trans[i] = rgb >> 24;771 QRgb rgba=image.color(i); 772 palette[i].red = qRed(rgba); 773 palette[i].green = qGreen(rgba); 774 palette[i].blue = qBlue(rgba); 775 trans[i] = qAlpha(rgba); 781 776 if (trans[i] < 255) { 782 777 num_trans = i+1; 783 778 } 784 779 } 780 png_set_PLTE(png_ptr, info_ptr, palette, num_palette); 781 785 782 if (num_trans) { 786 copy_trans = new png_byte[num_trans]; 787 for (int i=0; i<num_trans; i++) 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; 783 png_set_tRNS(png_ptr, info_ptr, trans, num_trans, 0); 784 } 796 785 } 797 786 … … 802 791 } 803 792 804 // Qt==ARGB==Big(ARGB)==Little(BGRA) 805 if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { 793 // Qt==ARGB==Big(ARGB)==Little(BGRA). But RGB888 is RGB regardless 794 if (QSysInfo::ByteOrder == QSysInfo::LittleEndian 795 && image.format() != QImage::Format_RGB888) { 806 796 png_set_bgr(png_ptr); 807 797 } … … 828 818 png_set_packing(png_ptr); 829 819 830 if ( image.format() == QImage::Format_RGB32)820 if (color_type == PNG_COLOR_TYPE_RGB && image.format() != QImage::Format_RGB888) 831 821 png_set_filler(png_ptr, 0, 832 822 QSysInfo::ByteOrder == QSysInfo::BigEndian ? … … 849 839 } 850 840 851 png_uint_32 width; 852 png_uint_32 height; 853 int bit_depth; 854 int color_type; 855 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 856 0, 0, 0); 857 858 const uchar *data = (static_cast<const QImage *>(&image))->bits(); 859 int bpl = image.bytesPerLine(); 860 row_pointers = new png_bytep[height]; 861 uint y; 862 for (y=0; y<height; y++) { 863 row_pointers[y] = (png_bytep)(data + y * bpl); 864 } 865 png_write_image(png_ptr, row_pointers); 866 delete [] row_pointers; 841 int height = image.height(); 842 int width = image.width(); 843 switch (image.format()) { 844 case QImage::Format_Mono: 845 case QImage::Format_MonoLSB: 846 case QImage::Format_Indexed8: 847 case QImage::Format_RGB32: 848 case QImage::Format_ARGB32: 849 case QImage::Format_RGB888: 850 { 851 png_bytep* row_pointers = new png_bytep[height]; 852 for (int y=0; y<height; y++) 853 row_pointers[y] = (png_bytep)image.constScanLine(y); 854 png_write_image(png_ptr, row_pointers); 855 delete [] row_pointers; 856 } 857 break; 858 default: 859 { 860 QImage::Format fmt = image.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32; 861 QImage row; 862 png_bytep row_pointers[1]; 863 for (int y=0; y<height; y++) { 864 row = image.copy(0, y, width, 1).convertToFormat(fmt); 865 row_pointers[0] = png_bytep(row.constScanLine(0)); 866 png_write_rows(png_ptr, row_pointers, 1); 867 } 868 } 869 break; 870 } 867 871 868 872 png_write_end(png_ptr, info_ptr); 869 873 frames_written++; 870 871 if (palette)872 delete [] palette;873 if (copy_trans)874 delete [] copy_trans;875 874 876 875 png_destroy_write_struct(&png_ptr, &info_ptr); … … 905 904 bool QPngHandler::canRead() const 906 905 { 907 if (d->state == QPngHandlerPrivate::Ready) { 908 if (!canRead(device())) 909 return false; 906 if (d->state == QPngHandlerPrivate::Ready && !canRead(device())) 907 return false; 908 909 if (d->state != QPngHandlerPrivate::Error) { 910 910 setFormat("png"); 911 911 return true; 912 912 } 913 return d->state != QPngHandlerPrivate::Error; 913 914 return false; 914 915 } 915 916 … … 959 960 return d->description; 960 961 else if (option == Size) 961 return QSize(d->info_ptr->width, d->info_ptr->height); 962 return QSize(png_get_image_width(d->png_ptr, d->info_ptr), 963 png_get_image_height(d->png_ptr, d->info_ptr)); 962 964 else if (option == ImageFormat) 963 965 return d->readImageFormat();
Note:
See TracChangeset
for help on using the changeset viewer.