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