filters

kis_png_converter.cc

00001 /*
00002  *  Copyright (c) 2005 Cyrille Berger <cberger@cberger.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018  */
00019  
00020  // A big thank to Glenn Randers-Pehrson for it's wonderfull documentation of libpng available at http://www.libpng.org/pub/png/libpng-1.2.5-manual.html
00021 #include "kis_png_converter.h"
00022 
00023 #include <stdio.h>
00024 
00025 #include <qfile.h>
00026 
00027 #include <kapplication.h>
00028 #include <kmessagebox.h>
00029 #include <klocale.h>
00030 
00031 #include <KoDocumentInfo.h>
00032 
00033 #include <kio/netaccess.h>
00034 
00035 #include <kis_abstract_colorspace.h>
00036 #include <kis_colorspace_factory_registry.h>
00037 #include <kis_doc.h>
00038 #include <kis_image.h>
00039 #include <kis_iterators_pixel.h>
00040 #include <kis_layer.h>
00041 #include <kis_meta_registry.h>
00042 #include <kis_profile.h>
00043 #include <kis_paint_layer.h>
00044 #include <kis_group_layer.h>
00045 
00046 namespace {
00047 
00048     const Q_UINT8 PIXEL_BLUE = 0;
00049     const Q_UINT8 PIXEL_GREEN = 1;
00050     const Q_UINT8 PIXEL_RED = 2;
00051     const Q_UINT8 PIXEL_ALPHA = 3;
00052 
00053     
00054     int getColorTypeforColorSpace( KisColorSpace * cs , bool alpha)
00055     {
00056         if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") )
00057         {
00058             return alpha ? PNG_COLOR_TYPE_GRAY_ALPHA : PNG_COLOR_TYPE_GRAY;
00059         }
00060         if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") )
00061         {
00062             return alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
00063         }
00064 
00065         KMessageBox::error(0, i18n("The selected image format does not support the colorspace of the image (%1)\nPlease choose another format or convert to a different colorspace").arg(cs->id().name()) ) ;
00066         return -1;
00067 
00068     }
00069 
00070     
00071     QString getColorSpaceForColorType(int color_type,int color_nb_bits) {
00072         if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
00073         {
00074             switch(color_nb_bits)
00075             {
00076                 case 8:
00077                     return "GRAYA";
00078                 case 16:
00079                     return "GRAYA16";
00080             }
00081         } else if(color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_RGB) {
00082             switch(color_nb_bits)
00083             {
00084                 case 8:
00085                     return "RGBA";
00086                 case 16:
00087                     return "RGBA16";
00088             }
00089         } else if(color_type ==  PNG_COLOR_TYPE_PALETTE) {
00090             return "RGBA"; // <-- we will convert the index image to RGBA
00091         }
00092         return "";
00093     }
00094 
00095 
00096     void fillText(png_text* p_text, char* key, QString& text)
00097     {
00098         p_text->compression = PNG_TEXT_COMPRESSION_zTXt;
00099         p_text->key = key;
00100         char* textc = new char[text.length()+1];
00101         strcpy(textc, text.ascii());
00102         p_text->text = textc;
00103         p_text->text_length = text.length()+1;
00104     }
00105 
00106 }
00107 
00108 KisPNGConverter::KisPNGConverter(KisDoc *doc, KisUndoAdapter *adapter)
00109 {
00110     Q_ASSERT(doc);
00111     Q_ASSERT(adapter);
00112     
00113     m_doc = doc;
00114     m_adapter = adapter;
00115     m_stop = false;
00116     m_max_row = 0;
00117     m_img = 0;
00118 }
00119 
00120 KisPNGConverter::~KisPNGConverter()
00121 {
00122 }
00123 
00124 KisImageBuilder_Result KisPNGConverter::decode(const KURL& uri)
00125 {
00126     kdDebug(41008) << "Start decoding PNG File" << endl;
00127     // open the file
00128     kdDebug(41008) << QFile::encodeName(uri.path()) << " " << uri.path() << " " << uri << endl;
00129     FILE *fp = fopen(QFile::encodeName(uri.path()), "rb");
00130     if (!fp)
00131     {
00132         return (KisImageBuilder_RESULT_NOT_EXIST);
00133     }
00134     png_byte signature[8];
00135     fread(signature, 1, 8, fp);
00136     if (!png_check_sig(signature, 8))
00137     {
00138         return (KisImageBuilder_RESULT_BAD_FETCH);
00139     }
00140 
00141     // Initialize the internal structures
00142     png_structp png_ptr =  png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
00143     if (!KisImageBuilder_RESULT_FAILURE)
00144         return (KisImageBuilder_RESULT_FAILURE);
00145 
00146     png_infop info_ptr = png_create_info_struct(png_ptr);
00147     if (!info_ptr)
00148     {
00149         png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00150         return (KisImageBuilder_RESULT_FAILURE);
00151     }
00152 
00153     png_infop end_info = png_create_info_struct(png_ptr);
00154     if (!end_info)
00155     {
00156         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00157         return (KisImageBuilder_RESULT_FAILURE);
00158     }
00159 
00160     // Catch errors
00161     if (setjmp(png_jmpbuf(png_ptr)))
00162     {
00163         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00164         fclose(fp);
00165         return (KisImageBuilder_RESULT_FAILURE);
00166     }
00167     
00168     png_init_io(png_ptr, fp);
00169     png_set_sig_bytes(png_ptr, 8);
00170     
00171     // read all PNG info up to image data
00172     png_read_info(png_ptr, info_ptr);
00173 
00174     // Read information about the png
00175     png_uint_32 width, height;
00176     int color_nb_bits, color_type;
00177     png_get_IHDR(png_ptr, info_ptr, &width, &height, &color_nb_bits, &color_type, NULL, NULL, NULL);
00178 
00179     // swap byteorder on little endian machines.
00180     #ifndef WORDS_BIGENDIAN
00181     if (color_nb_bits > 8 )
00182         png_set_swap(png_ptr);
00183     #endif
00184 
00185     // Determine the colorspace
00186     QString csName = getColorSpaceForColorType(color_type, color_nb_bits);
00187     if(csName.isEmpty()) {
00188         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00189         return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
00190     }
00191     bool hasalpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA);
00192     
00193     // Read image profile
00194     png_charp profile_name, profile_data;
00195     int compression_type;
00196     png_uint_32 proflen;
00197     
00198     KisProfile* profile = 0;
00199     if(png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen))
00200     {
00201         QByteArray profile_rawdata;
00202         // XXX: Hardcoded for icc type -- is that correct for us?
00203         if (QString::compare(profile_name, "icc") == 0) {
00204             profile_rawdata.resize(proflen);
00205             memcpy(profile_rawdata.data(), profile_data, proflen);
00206             profile = new KisProfile(profile_rawdata);
00207             Q_CHECK_PTR(profile);
00208             if (profile) {
00209                 kdDebug(41008) << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo() << endl;
00210                 if(!profile->isSuitableForOutput())
00211                 {
00212                     kdDebug(41008) << "the profile is not suitable for output and therefore cannot be used in krita, we need to convert the image to a standard profile" << endl; // TODO: in ko2 popup a selection menu to inform the user
00213                 }
00214             }
00215         }
00216     }
00217 
00218     // Retrieve a pointer to the colorspace
00219     KisColorSpace* cs;
00220     if (profile && profile->isSuitableForOutput())
00221     {
00222         kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
00223         cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
00224     }
00225     else
00226         cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
00227 
00228     if(cs == 0)
00229     {
00230         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00231         return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
00232     }
00233     
00234     // Create the cmsTransform if needed 
00235     cmsHTRANSFORM transform = 0;
00236     if(profile && !profile->isSuitableForOutput())
00237     {
00238         transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
00239                                        cs->getProfile()->profile() , cs->colorSpaceType(),
00240                                        INTENT_PERCEPTUAL, 0);
00241     }
00242 
00243     // Read comments/texts...
00244     png_text* text_ptr;
00245     int num_comments;
00246     png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
00247     KoDocumentInfo * info = m_doc->documentInfo();
00248     KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
00249     KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author"));
00250     kdDebug(41008) << "There are " << num_comments << " comments in the text" << endl;
00251     for(int i = 0; i < num_comments; i++)
00252     {
00253         kdDebug(41008) << "key is " << text_ptr[i].key << " containing " << text_ptr[i].text << endl;
00254         if(QString::compare(text_ptr[i].key, "title") == 0)
00255         {
00256                 aboutPage->setTitle(text_ptr[i].text);
00257         } else if(QString::compare(text_ptr[i].key, "abstract")  == 0)
00258         {
00259                 aboutPage->setAbstract(text_ptr[i].text);
00260         } else if(QString::compare(text_ptr[i].key, "author") == 0)
00261         {
00262                 authorPage->setFullName(text_ptr[i].text);
00263         }
00264     }
00265     
00266     // Read image data
00267     png_bytepp row_pointers = new png_bytep[height];
00268     png_uint_32 row_index = 0;
00269     try
00270     {
00271         png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00272         for(; row_index < height; row_index++)
00273         {
00274             row_pointers[row_index] = new png_byte[rowbytes];
00275         }
00276     }
00277     catch(std::bad_alloc& e)
00278     {
00279         // new png_byte[] may raise such an exception if the image
00280         // is invalid / to large.
00281         kdDebug(41008) << "bad alloc: " << e.what() << endl;
00282         // Free only the already allocated png_byte instances.
00283         for (png_uint_32 y = 0; y < row_index; y++) {
00284             delete[] row_pointers[y];
00285         }
00286         delete [] row_pointers;
00287         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00288         return (KisImageBuilder_RESULT_FAILURE);
00289     }
00290     
00291     // Read the palette if the file is indexed
00292     png_colorp palette ;
00293     int num_palette;
00294     if(color_type == PNG_COLOR_TYPE_PALETTE) {
00295         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
00296     }
00297 //     png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL );
00298 //     png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); // By using this function libpng will take care of freeing memory
00299     png_read_image(png_ptr, row_pointers);
00300     
00301     // Finish reading the file
00302     png_read_end(png_ptr, end_info);
00303     fclose(fp);
00304     
00305     // Creating the KisImageSP
00306     if( ! m_img) {
00307         m_img = new KisImage(m_doc->undoAdapter(), width, height, cs, "built image");
00308         m_img->blockSignals(true); // Don't send out signals while we're building the image
00309         Q_CHECK_PTR(m_img);
00310         if(profile && !profile->isSuitableForOutput())
00311         {
00312             m_img -> addAnnotation( profile->annotation() );
00313         }
00314     }
00315 
00316     KisPaintLayer* layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), Q_UINT8_MAX);
00317     for (png_uint_32 y = 0; y < height; y++) {
00318         KisHLineIterator it = layer -> paintDevice() -> createHLineIterator(0, y, width, true);
00319         switch(color_type)
00320         {
00321             case PNG_COLOR_TYPE_GRAY:
00322             case PNG_COLOR_TYPE_GRAY_ALPHA:
00323                 if(color_nb_bits == 16)
00324                 {
00325                     Q_UINT16 *src = reinterpret_cast<Q_UINT16 *>(row_pointers[y]);
00326                     while (!it.isDone()) {
00327                         Q_UINT16 *d = reinterpret_cast<Q_UINT16 *>(it.rawData());
00328                         d[0] = *(src++);
00329                         if(transform) cmsDoTransform(transform, d, d, 1);
00330                         if(hasalpha) d[1] = *(src++);
00331                         else d[1] = Q_UINT16_MAX;
00332                         ++it;
00333                     }
00334                 } else {
00335                     Q_UINT8 *src = row_pointers[y];
00336                     while (!it.isDone()) {
00337                         Q_UINT8 *d = it.rawData();
00338                         d[0] = *(src++);
00339                         if(transform) cmsDoTransform(transform, d, d, 1);
00340                         if(hasalpha) d[1] = *(src++);
00341                         else d[1] = Q_UINT8_MAX;
00342                         ++it;
00343                     }
00344                 }
00345                 //FIXME:should be able to read 1 and 4 bits depth and scale them to 8 bits
00346                 break;
00347             case PNG_COLOR_TYPE_RGB:
00348             case PNG_COLOR_TYPE_RGB_ALPHA:
00349                 if(color_nb_bits == 16)
00350                 {
00351                     Q_UINT16 *src = reinterpret_cast<Q_UINT16 *>(row_pointers[y]);
00352                     while (!it.isDone()) {
00353                         Q_UINT16 *d = reinterpret_cast<Q_UINT16 *>(it.rawData());
00354                         d[2] = *(src++);
00355                         d[1] = *(src++);
00356                         d[0] = *(src++);
00357                         if(transform) cmsDoTransform(transform, d, d, 1);
00358                         if(hasalpha) d[3] = *(src++);
00359                         else d[3] = Q_UINT16_MAX;
00360                         ++it;
00361                     }
00362                 } else {
00363                     Q_UINT8 *src = row_pointers[y];
00364                     while (!it.isDone()) {
00365                         Q_UINT8 *d = it.rawData();
00366                         d[2] = *(src++);
00367                         d[1] = *(src++);
00368                         d[0] = *(src++);
00369                         if(transform) cmsDoTransform(transform, d, d, 1);
00370                         if(hasalpha) d[3] = *(src++);
00371                         else d[3] = Q_UINT8_MAX;
00372                         ++it;
00373                     }
00374                 }
00375                 break;
00376             case PNG_COLOR_TYPE_PALETTE:
00377                 switch(color_nb_bits)
00378                 {
00379                     case 8:
00380                     {
00381                         Q_UINT8 *src = row_pointers[y];
00382                         while (!it.isDone()) {
00383                             Q_UINT8 *d = it.rawData();
00384                             png_color c = palette[*(src++)];
00385                             d[2] = c.red;
00386                             d[1] = c.green;
00387                             d[0] = c.blue;
00388                             d[3] = Q_UINT8_MAX;
00389                             ++it;
00390                         }
00391                         break;
00392                     }
00393                     default: // TODO:support for 1,2 and 4 bits
00394                         return KisImageBuilder_RESULT_UNSUPPORTED;
00395                 }
00396                 
00397                 break;
00398             default:
00399                 return KisImageBuilder_RESULT_UNSUPPORTED;
00400         }
00401     }
00402     m_img->addLayer(layer, m_img->rootLayer(), 0);
00403 
00404     // Freeing memory
00405     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00406     
00407     for (png_uint_32 y = 0; y < height; y++) {
00408         delete[] row_pointers[y];
00409     }
00410     delete [] row_pointers;
00411     
00412     return KisImageBuilder_RESULT_OK;
00413 
00414 }
00415 
00416 KisImageBuilder_Result KisPNGConverter::buildImage(const KURL& uri)
00417 {
00418     kdDebug(41008) << QFile::encodeName(uri.path()) << " " << uri.path() << " " << uri << endl;
00419     if (uri.isEmpty())
00420         return KisImageBuilder_RESULT_NO_URI;
00421 
00422     if (!KIO::NetAccess::exists(uri, false, qApp -> mainWidget())) {
00423         return KisImageBuilder_RESULT_NOT_EXIST;
00424     }
00425 
00426     // We're not set up to handle asynchronous loading at the moment.
00427     KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
00428     QString tmpFile;
00429 
00430     if (KIO::NetAccess::download(uri, tmpFile, qApp -> mainWidget())) {
00431         KURL uriTF;
00432         uriTF.setPath( tmpFile );
00433         result = decode(uriTF);
00434         KIO::NetAccess::removeTempFile(tmpFile);
00435     }
00436 
00437     return result;
00438 }
00439 
00440 
00441 KisImageSP KisPNGConverter::image()
00442 {
00443     return m_img;
00444 }
00445 
00446 
00447 KisImageBuilder_Result KisPNGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, int compression, bool interlace, bool alpha)
00448 {
00449     kdDebug(41008) << "Start writing PNG File" << endl;
00450     if (!layer)
00451         return KisImageBuilder_RESULT_INVALID_ARG;
00452 
00453     KisImageSP img = layer -> image();
00454     if (!img)
00455         return KisImageBuilder_RESULT_EMPTY;
00456 
00457     if (uri.isEmpty())
00458         return KisImageBuilder_RESULT_NO_URI;
00459 
00460     if (!uri.isLocalFile())
00461         return KisImageBuilder_RESULT_NOT_LOCAL;
00462     // Open file for writing
00463     FILE *fp = fopen(QFile::encodeName(uri.path()), "wb");
00464     if (!fp)
00465     {
00466         return (KisImageBuilder_RESULT_FAILURE);
00467     }
00468     int height = img->height();
00469     int width = img->width();
00470     // Initialize structures
00471     png_structp png_ptr =  png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
00472     if (!png_ptr)
00473     {
00474         KIO::del(uri);
00475         return (KisImageBuilder_RESULT_FAILURE);
00476     }
00477 
00478     png_infop info_ptr = png_create_info_struct(png_ptr);
00479     if (!info_ptr)
00480     {
00481         KIO::del(uri);
00482         png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00483         return (KisImageBuilder_RESULT_FAILURE);
00484     }
00485 
00486     // If an error occurs during writing, libpng will jump here
00487     if (setjmp(png_jmpbuf(png_ptr)))
00488     {
00489         KIO::del(uri);
00490         png_destroy_write_struct(&png_ptr, &info_ptr);
00491         fclose(fp);
00492         return (KisImageBuilder_RESULT_FAILURE);
00493     }
00494     // Initialize the writing
00495     png_init_io(png_ptr, fp);
00496     // Setup the progress function
00497 // FIXME    png_set_write_status_fn(png_ptr, progress);
00498 //     setProgressTotalSteps(100/*height*/);
00499             
00500 
00501     /* set the zlib compression level */
00502     png_set_compression_level(png_ptr, compression);
00503 
00504     /* set other zlib parameters */
00505     png_set_compression_mem_level(png_ptr, 8);
00506     png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
00507     png_set_compression_window_bits(png_ptr, 15);
00508     png_set_compression_method(png_ptr, 8);
00509     png_set_compression_buffer_size(png_ptr, 8192);
00510     
00511     int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
00512     int color_type = getColorTypeforColorSpace(img->colorSpace(), alpha);
00513     
00514     if(color_type == -1)
00515     {
00516         return KisImageBuilder_RESULT_UNSUPPORTED;
00517     }
00518     
00519     int interlacetype = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
00520     
00521     png_set_IHDR(png_ptr, info_ptr,
00522                  width,
00523                  height,
00524                  color_nb_bits,
00525                  color_type, interlacetype,
00526                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00527     
00528     png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
00529     
00530     // Save annotation
00531     vKisAnnotationSP_it it = annotationsStart;
00532     while(it != annotationsEnd) {
00533         if (!(*it) || (*it) -> type() == QString()) {
00534             kdDebug(41008) << "Warning: empty annotation" << endl;
00535             ++it;
00536             continue;
00537         }
00538 
00539         kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
00540 
00541         if ((*it) -> type().startsWith("krita_attribute:")) { // Attribute
00542             // FIXME: it should be possible to save krita_attributes in the "CHUNKs"
00543             kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl;
00544         } else { // Profile
00545             char* name = new char[(*it)->type().length()+1];
00546             strcpy(name, (*it)->type().ascii());
00547             png_set_iCCP(png_ptr, info_ptr, name, PNG_COMPRESSION_TYPE_BASE, (char*)(*it)->annotation().data(), (*it) -> annotation() . size());
00548         }
00549         ++it;
00550     }
00551 
00552     // read comments from the document information
00553     png_text texts[3];
00554     int nbtexts = 0;
00555     KoDocumentInfo * info = m_doc->documentInfo();
00556     KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
00557     QString title = aboutPage->title();
00558     if(!title.isEmpty())
00559     {
00560         fillText(texts+nbtexts, "title", title);
00561         nbtexts++;
00562     }
00563     QString abstract = aboutPage->abstract();
00564     if(!abstract.isEmpty())
00565     {
00566         fillText(texts+nbtexts, "abstract", abstract);
00567         nbtexts++;
00568     }
00569     KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author" ));
00570     QString author = authorPage->fullName();
00571     if(!author.isEmpty())
00572     {
00573         fillText(texts+nbtexts, "author", author);
00574         nbtexts++;
00575     }
00576     
00577     png_set_text(png_ptr, info_ptr, texts, nbtexts);
00578     
00579     // Save the information to the file
00580     png_write_info(png_ptr, info_ptr);
00581     png_write_flush(png_ptr);
00582 
00583     // swap byteorder on little endian machines.
00584     #ifndef WORDS_BIGENDIAN
00585     if (color_nb_bits > 8 )
00586         png_set_swap(png_ptr);
00587     #endif
00588 
00589     // Write the PNG
00590 //     png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
00591     
00592     // Fill the data structure
00593     png_byte** row_pointers= new png_byte*[height];
00594     
00595     for (int y = 0; y < height; y++) {
00596         KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
00597         row_pointers[y] = new png_byte[width*layer->paintDevice()->pixelSize()];
00598         switch(color_type)
00599         {
00600             case PNG_COLOR_TYPE_GRAY:
00601             case PNG_COLOR_TYPE_GRAY_ALPHA:
00602                 if(color_nb_bits == 16)
00603                 {
00604                     Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(row_pointers[y]);
00605                     while (!it.isDone()) {
00606                         const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00607                         *(dst++) = d[0];
00608                         if(alpha) *(dst++) = d[1];
00609                         ++it;
00610                     }
00611                 } else {
00612                     Q_UINT8 *dst = row_pointers[y];
00613                     while (!it.isDone()) {
00614                         const Q_UINT8 *d = it.rawData();
00615                         *(dst++) = d[0];
00616                         if(alpha) *(dst++) = d[1];
00617                         ++it;
00618                     }
00619                 }
00620                 break;
00621             case PNG_COLOR_TYPE_RGB:
00622             case PNG_COLOR_TYPE_RGB_ALPHA:
00623                 if(color_nb_bits == 16)
00624                 {
00625                     Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(row_pointers[y]);
00626                     while (!it.isDone()) {
00627                         const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00628                         *(dst++) = d[2];
00629                         *(dst++) = d[1];
00630                         *(dst++) = d[0];
00631                         if(alpha) *(dst++) = d[3];
00632                         ++it;
00633                     }
00634                 } else {
00635                     Q_UINT8 *dst = row_pointers[y];
00636                     while (!it.isDone()) {
00637                         const Q_UINT8 *d = it.rawData();
00638                         *(dst++) = d[2];
00639                         *(dst++) = d[1];
00640                         *(dst++) = d[0];
00641                         if(alpha) *(dst++) = d[3];
00642                         ++it;
00643                     }
00644                 }
00645                 break;
00646             default:
00647                 KIO::del(uri);
00648                 return KisImageBuilder_RESULT_UNSUPPORTED;
00649         }
00650     }
00651     
00652     png_write_image(png_ptr, row_pointers);
00653 
00654     // Writting is over
00655     png_write_end(png_ptr, info_ptr);
00656     
00657     // Free memory
00658     png_destroy_write_struct(&png_ptr, &info_ptr);
00659     for (int y = 0; y < height; y++) {
00660         delete[] row_pointers[y];
00661     }
00662     delete[] row_pointers;
00663 
00664     fclose(fp);
00665     
00666     return KisImageBuilder_RESULT_OK;
00667 }
00668 
00669 
00670 void KisPNGConverter::cancel()
00671 {
00672     m_stop = true;
00673 }
00674 
00675 void KisPNGConverter::progress(png_structp png_ptr, png_uint_32 row_number, int pass)
00676 {
00677     if(png_ptr == NULL || row_number > PNG_MAX_UINT || pass > 7) return;
00678 //     setProgress(row_number);
00679 }
00680 
00681 
00682 #include "kis_png_converter.moc"
00683 
KDE Home | KDE Accessibility Home | Description of Access Keys