00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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("Cannot export images in %1.\n").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";
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 class KisPNGStream {
00125 public:
00126 KisPNGStream(Q_UINT8* buf, Q_UINT32 depth ) : m_posinc(8),m_depth(depth), m_buf(buf) { *m_buf = 0;};
00127 int nextValue()
00128 {
00129 if( m_posinc == 0)
00130 {
00131 m_posinc = 8;
00132 m_buf++;
00133 }
00134 m_posinc -= m_depth;
00135 return (( (*m_buf) >> (m_posinc) ) & ( ( 1 << m_depth ) - 1 ) );
00136 }
00137 void setNextValue(int v)
00138 {
00139 if( m_posinc == 0)
00140 {
00141 m_posinc = 8;
00142 m_buf++;
00143 *m_buf = 0;
00144 }
00145 m_posinc -= m_depth;
00146 *m_buf = (v << m_posinc) | *m_buf;
00147 }
00148 private:
00149 Q_UINT32 m_posinc, m_depth;
00150 Q_UINT8* m_buf;
00151 };
00152
00153 KisImageBuilder_Result KisPNGConverter::decode(const KURL& uri)
00154 {
00155 kdDebug(41008) << "Start decoding PNG File" << endl;
00156
00157 kdDebug(41008) << QFile::encodeName(uri.path()) << " " << uri.path() << " " << uri << endl;
00158 FILE *fp = fopen(QFile::encodeName(uri.path()), "rb");
00159 if (!fp)
00160 {
00161 return (KisImageBuilder_RESULT_NOT_EXIST);
00162 }
00163 png_byte signature[8];
00164 fread(signature, 1, 8, fp);
00165 if (!png_check_sig(signature, 8))
00166 {
00167 return (KisImageBuilder_RESULT_BAD_FETCH);
00168 }
00169
00170
00171 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
00172 if (!KisImageBuilder_RESULT_FAILURE)
00173 return (KisImageBuilder_RESULT_FAILURE);
00174
00175 png_infop info_ptr = png_create_info_struct(png_ptr);
00176 if (!info_ptr)
00177 {
00178 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00179 return (KisImageBuilder_RESULT_FAILURE);
00180 }
00181
00182 png_infop end_info = png_create_info_struct(png_ptr);
00183 if (!end_info)
00184 {
00185 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00186 return (KisImageBuilder_RESULT_FAILURE);
00187 }
00188
00189
00190 if (setjmp(png_jmpbuf(png_ptr)))
00191 {
00192 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00193 fclose(fp);
00194 return (KisImageBuilder_RESULT_FAILURE);
00195 }
00196
00197 png_init_io(png_ptr, fp);
00198 png_set_sig_bytes(png_ptr, 8);
00199
00200
00201 png_read_info(png_ptr, info_ptr);
00202
00203
00204 png_uint_32 width, height;
00205 int color_nb_bits, color_type, interlace_type;
00206 png_get_IHDR(png_ptr, info_ptr, &width, &height, &color_nb_bits, &color_type, &interlace_type, NULL, NULL);
00207 kdDebug(41008) << "it's an " << color_nb_bits << " depth image" << endl;
00208
00209
00210 #ifndef WORDS_BIGENDIAN
00211 if (color_nb_bits > 8 )
00212 png_set_swap(png_ptr);
00213 #endif
00214
00215
00216 QString csName = getColorSpaceForColorType(color_type, color_nb_bits);
00217 if(csName.isEmpty()) {
00218 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00219 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
00220 }
00221 bool hasalpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA);
00222
00223
00224 png_charp profile_name, profile_data;
00225 int compression_type;
00226 png_uint_32 proflen;
00227 int number_of_passes = 1;
00228
00229 if (interlace_type == PNG_INTERLACE_ADAM7)
00230 number_of_passes = png_set_interlace_handling(png_ptr);
00231
00232 KisProfile* profile = 0;
00233 if(png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen))
00234 {
00235 QByteArray profile_rawdata;
00236
00237 if (QString::compare(profile_name, "icc") == 0) {
00238 profile_rawdata.resize(proflen);
00239 memcpy(profile_rawdata.data(), profile_data, proflen);
00240 profile = new KisProfile(profile_rawdata);
00241 Q_CHECK_PTR(profile);
00242 if (profile) {
00243 kdDebug(41008) << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo() << endl;
00244 if(!profile->isSuitableForOutput())
00245 {
00246 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;
00247 }
00248 }
00249 }
00250 }
00251
00252
00253 KisColorSpace* cs;
00254 if (profile && profile->isSuitableForOutput())
00255 {
00256 kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
00257 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
00258 }
00259 else
00260 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
00261
00262 if(cs == 0)
00263 {
00264 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00265 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
00266 }
00267
00268
00269 cmsHTRANSFORM transform = 0;
00270 if(profile && !profile->isSuitableForOutput())
00271 {
00272 transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
00273 cs->getProfile()->profile() , cs->colorSpaceType(),
00274 INTENT_PERCEPTUAL, 0);
00275 }
00276
00277
00278 png_text* text_ptr;
00279 int num_comments;
00280 png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
00281 KoDocumentInfo * info = m_doc->documentInfo();
00282 KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
00283 KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author"));
00284 kdDebug(41008) << "There are " << num_comments << " comments in the text" << endl;
00285 for(int i = 0; i < num_comments; i++)
00286 {
00287 kdDebug(41008) << "key is " << text_ptr[i].key << " containing " << text_ptr[i].text << endl;
00288 if(QString::compare(text_ptr[i].key, "title") == 0)
00289 {
00290 aboutPage->setTitle(text_ptr[i].text);
00291 } else if(QString::compare(text_ptr[i].key, "abstract") == 0)
00292 {
00293 aboutPage->setAbstract(text_ptr[i].text);
00294 } else if(QString::compare(text_ptr[i].key, "author") == 0)
00295 {
00296 authorPage->setFullName(text_ptr[i].text);
00297 }
00298 }
00299
00300
00301 png_bytep row_pointer = 0;
00302 try
00303 {
00304 png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00305 row_pointer = new png_byte[rowbytes];
00306 }
00307 catch(std::bad_alloc& e)
00308 {
00309
00310
00311 kdDebug(41008) << "bad alloc: " << e.what() << endl;
00312
00313 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00314 return (KisImageBuilder_RESULT_FAILURE);
00315 }
00316
00317
00318 png_colorp palette ;
00319 int num_palette;
00320 if(color_type == PNG_COLOR_TYPE_PALETTE) {
00321 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 if( ! m_img) {
00333 m_img = new KisImage(m_doc->undoAdapter(), width, height, cs, "built image");
00334 m_img->blockSignals(true);
00335 Q_CHECK_PTR(m_img);
00336 if(profile && !profile->isSuitableForOutput())
00337 {
00338 m_img -> addAnnotation( profile->annotation() );
00339 }
00340 }
00341
00342 KisPaintLayer* layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), Q_UINT8_MAX);
00343 for (int i = 0; i < number_of_passes; i++)
00344 {
00345 for (png_uint_32 y = 0; y < height; y++) {
00346 KisHLineIterator it = layer -> paintDevice() -> createHLineIterator(0, y, width, true);
00347 png_read_rows(png_ptr, &row_pointer, NULL, 1);
00348
00349 switch(color_type)
00350 {
00351 case PNG_COLOR_TYPE_GRAY:
00352 case PNG_COLOR_TYPE_GRAY_ALPHA:
00353 if(color_nb_bits == 16)
00354 {
00355 Q_UINT16 *src = reinterpret_cast<Q_UINT16 *>(row_pointer);
00356 while (!it.isDone()) {
00357 Q_UINT16 *d = reinterpret_cast<Q_UINT16 *>(it.rawData());
00358 d[0] = *(src++);
00359 if(transform) cmsDoTransform(transform, d, d, 1);
00360 if(hasalpha) d[1] = *(src++);
00361 else d[1] = Q_UINT16_MAX;
00362 ++it;
00363 }
00364 } else {
00365 Q_UINT8 *src = row_pointer;
00366 while (!it.isDone()) {
00367 Q_UINT8 *d = it.rawData();
00368 d[0] = *(src++);
00369 if(transform) cmsDoTransform(transform, d, d, 1);
00370 if(hasalpha) d[1] = *(src++);
00371 else d[1] = Q_UINT8_MAX;
00372 ++it;
00373 }
00374 }
00375
00376 break;
00377 case PNG_COLOR_TYPE_RGB:
00378 case PNG_COLOR_TYPE_RGB_ALPHA:
00379 if(color_nb_bits == 16)
00380 {
00381 Q_UINT16 *src = reinterpret_cast<Q_UINT16 *>(row_pointer);
00382 while (!it.isDone()) {
00383 Q_UINT16 *d = reinterpret_cast<Q_UINT16 *>(it.rawData());
00384 d[2] = *(src++);
00385 d[1] = *(src++);
00386 d[0] = *(src++);
00387 if(transform) cmsDoTransform(transform, d, d, 1);
00388 if(hasalpha) d[3] = *(src++);
00389 else d[3] = Q_UINT16_MAX;
00390 ++it;
00391 }
00392 } else {
00393 Q_UINT8 *src = row_pointer;
00394 while (!it.isDone()) {
00395 Q_UINT8 *d = it.rawData();
00396 d[2] = *(src++);
00397 d[1] = *(src++);
00398 d[0] = *(src++);
00399 if(transform) cmsDoTransform(transform, d, d, 1);
00400 if(hasalpha) d[3] = *(src++);
00401 else d[3] = Q_UINT8_MAX;
00402 ++it;
00403 }
00404 }
00405 break;
00406 case PNG_COLOR_TYPE_PALETTE:
00407 {
00408 KisPNGStream stream(row_pointer, color_nb_bits);
00409 while (!it.isDone()) {
00410 Q_UINT8 *d = it.rawData();
00411 png_color c = palette[ stream.nextValue() ];
00412 d[2] = c.red;
00413 d[1] = c.green;
00414 d[0] = c.blue;
00415 d[3] = Q_UINT8_MAX;
00416 ++it;
00417 }
00418 }
00419 break;
00420 default:
00421 return KisImageBuilder_RESULT_UNSUPPORTED;
00422 }
00423 }
00424 }
00425 m_img->addLayer(layer, m_img->rootLayer(), 0);
00426
00427 png_read_end(png_ptr, end_info);
00428 fclose(fp);
00429
00430
00431 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00432
00433 delete [] row_pointer;
00434
00435 return KisImageBuilder_RESULT_OK;
00436
00437 }
00438
00439 KisImageBuilder_Result KisPNGConverter::buildImage(const KURL& uri)
00440 {
00441 kdDebug(41008) << QFile::encodeName(uri.path()) << " " << uri.path() << " " << uri << endl;
00442 if (uri.isEmpty())
00443 return KisImageBuilder_RESULT_NO_URI;
00444
00445 if (!KIO::NetAccess::exists(uri, false, qApp -> mainWidget())) {
00446 return KisImageBuilder_RESULT_NOT_EXIST;
00447 }
00448
00449
00450 KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
00451 QString tmpFile;
00452
00453 if (KIO::NetAccess::download(uri, tmpFile, qApp -> mainWidget())) {
00454 KURL uriTF;
00455 uriTF.setPath( tmpFile );
00456 result = decode(uriTF);
00457 KIO::NetAccess::removeTempFile(tmpFile);
00458 }
00459
00460 return result;
00461 }
00462
00463
00464 KisImageSP KisPNGConverter::image()
00465 {
00466 return m_img;
00467 }
00468
00469 KisImageBuilder_Result KisPNGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, int compression, bool interlace, bool alpha)
00470 {
00471 kdDebug(41008) << "Start writing PNG File" << endl;
00472 if (!layer)
00473 return KisImageBuilder_RESULT_INVALID_ARG;
00474
00475 KisImageSP img = layer -> image();
00476 if (!img)
00477 return KisImageBuilder_RESULT_EMPTY;
00478
00479 if (uri.isEmpty())
00480 return KisImageBuilder_RESULT_NO_URI;
00481
00482 if (!uri.isLocalFile())
00483 return KisImageBuilder_RESULT_NOT_LOCAL;
00484
00485 FILE *fp = fopen(QFile::encodeName(uri.path()), "wb");
00486 if (!fp)
00487 {
00488 return (KisImageBuilder_RESULT_FAILURE);
00489 }
00490 int height = img->height();
00491 int width = img->width();
00492
00493 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
00494 if (!png_ptr)
00495 {
00496 KIO::del(uri);
00497 return (KisImageBuilder_RESULT_FAILURE);
00498 }
00499
00500 png_infop info_ptr = png_create_info_struct(png_ptr);
00501 if (!info_ptr)
00502 {
00503 KIO::del(uri);
00504 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00505 return (KisImageBuilder_RESULT_FAILURE);
00506 }
00507
00508
00509 if (setjmp(png_jmpbuf(png_ptr)))
00510 {
00511 KIO::del(uri);
00512 png_destroy_write_struct(&png_ptr, &info_ptr);
00513 fclose(fp);
00514 return (KisImageBuilder_RESULT_FAILURE);
00515 }
00516
00517 png_init_io(png_ptr, fp);
00518
00519
00520
00521
00522
00523
00524 png_set_compression_level(png_ptr, compression);
00525
00526
00527 png_set_compression_mem_level(png_ptr, 8);
00528 png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
00529 png_set_compression_window_bits(png_ptr, 15);
00530 png_set_compression_method(png_ptr, 8);
00531 png_set_compression_buffer_size(png_ptr, 8192);
00532
00533 int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
00534 int color_type = getColorTypeforColorSpace(layer->paintDevice()->colorSpace(), alpha);
00535
00536 if(color_type == -1)
00537 {
00538 return KisImageBuilder_RESULT_UNSUPPORTED;
00539 }
00540
00541
00542 png_colorp palette ;
00543 int num_palette = 0;
00544 if(!alpha && layer->paintDevice()->colorSpace()->id() == KisID("RGBA") )
00545 {
00546 palette = new png_color[255];
00547 KisRectIteratorPixel it = layer->paintDevice()->createRectIterator(0,0, img->width(), img->height(), false);
00548 bool toomuchcolor = false;
00549 while( !it.isDone() )
00550 {
00551 const Q_UINT8* c = it.rawData();
00552 bool findit = false;
00553 for(int i = 0; i < num_palette; i++)
00554 {
00555 if(palette[i].red == c[2] &&
00556 palette[i].green == c[1] &&
00557 palette[i].blue == c[0] )
00558 {
00559 findit = true;
00560 break;
00561 }
00562 }
00563 if(!findit)
00564 {
00565 if( num_palette == 255)
00566 {
00567 toomuchcolor = true;
00568 break;
00569 }
00570 palette[num_palette].red = c[2];
00571 palette[num_palette].green = c[1];
00572 palette[num_palette].blue = c[0];
00573 num_palette++;
00574 }
00575 ++it;
00576 }
00577 if(!toomuchcolor)
00578 {
00579 kdDebug(41008) << "Found a palette of " << num_palette << " colors" << endl;
00580 color_type = PNG_COLOR_TYPE_PALETTE;
00581 if( num_palette <= 2)
00582 {
00583 color_nb_bits = 1;
00584 } else if( num_palette <= 4)
00585 {
00586 color_nb_bits = 2;
00587 } else if( num_palette <= 16)
00588 {
00589 color_nb_bits = 4;
00590 } else {
00591 color_nb_bits = 8;
00592 }
00593 } else {
00594 delete palette;
00595 }
00596 }
00597
00598 int interlacetype = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
00599
00600 png_set_IHDR(png_ptr, info_ptr,
00601 width,
00602 height,
00603 color_nb_bits,
00604 color_type, interlacetype,
00605 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00606
00607 png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
00608
00609 if( color_type == PNG_COLOR_TYPE_PALETTE)
00610 {
00611 png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
00612 }
00613
00614 vKisAnnotationSP_it it = annotationsStart;
00615 while(it != annotationsEnd) {
00616 if (!(*it) || (*it) -> type() == QString()) {
00617 kdDebug(41008) << "Warning: empty annotation" << endl;
00618 ++it;
00619 continue;
00620 }
00621
00622 kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
00623
00624 if ((*it) -> type().startsWith("krita_attribute:")) {
00625
00626 kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl;
00627 } else {
00628 char* name = new char[(*it)->type().length()+1];
00629 strcpy(name, (*it)->type().ascii());
00630 png_set_iCCP(png_ptr, info_ptr, name, PNG_COMPRESSION_TYPE_BASE, (char*)(*it)->annotation().data(), (*it) -> annotation() . size());
00631 }
00632 ++it;
00633 }
00634
00635
00636 png_text texts[3];
00637 int nbtexts = 0;
00638 KoDocumentInfo * info = m_doc->documentInfo();
00639 KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
00640 QString title = aboutPage->title();
00641 if(!title.isEmpty())
00642 {
00643 fillText(texts+nbtexts, "title", title);
00644 nbtexts++;
00645 }
00646 QString abstract = aboutPage->abstract();
00647 if(!abstract.isEmpty())
00648 {
00649 fillText(texts+nbtexts, "abstract", abstract);
00650 nbtexts++;
00651 }
00652 KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author" ));
00653 QString author = authorPage->fullName();
00654 if(!author.isEmpty())
00655 {
00656 fillText(texts+nbtexts, "author", author);
00657 nbtexts++;
00658 }
00659
00660 png_set_text(png_ptr, info_ptr, texts, nbtexts);
00661
00662
00663 png_write_info(png_ptr, info_ptr);
00664 png_write_flush(png_ptr);
00665
00666
00667 #ifndef WORDS_BIGENDIAN
00668 if (color_nb_bits > 8 )
00669 png_set_swap(png_ptr);
00670 #endif
00671
00672
00673
00674
00675
00676 png_byte** row_pointers= new png_byte*[height];
00677
00678 for (int y = 0; y < height; y++) {
00679 KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
00680 row_pointers[y] = new png_byte[width*layer->paintDevice()->pixelSize()];
00681 switch(color_type)
00682 {
00683 case PNG_COLOR_TYPE_GRAY:
00684 case PNG_COLOR_TYPE_GRAY_ALPHA:
00685 if(color_nb_bits == 16)
00686 {
00687 Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(row_pointers[y]);
00688 while (!it.isDone()) {
00689 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00690 *(dst++) = d[0];
00691 if(alpha) *(dst++) = d[1];
00692 ++it;
00693 }
00694 } else {
00695 Q_UINT8 *dst = row_pointers[y];
00696 while (!it.isDone()) {
00697 const Q_UINT8 *d = it.rawData();
00698 *(dst++) = d[0];
00699 if(alpha) *(dst++) = d[1];
00700 ++it;
00701 }
00702 }
00703 break;
00704 case PNG_COLOR_TYPE_RGB:
00705 case PNG_COLOR_TYPE_RGB_ALPHA:
00706 if(color_nb_bits == 16)
00707 {
00708 Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(row_pointers[y]);
00709 while (!it.isDone()) {
00710 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00711 *(dst++) = d[2];
00712 *(dst++) = d[1];
00713 *(dst++) = d[0];
00714 if(alpha) *(dst++) = d[3];
00715 ++it;
00716 }
00717 } else {
00718 Q_UINT8 *dst = row_pointers[y];
00719 while (!it.isDone()) {
00720 const Q_UINT8 *d = it.rawData();
00721 *(dst++) = d[2];
00722 *(dst++) = d[1];
00723 *(dst++) = d[0];
00724 if(alpha) *(dst++) = d[3];
00725 ++it;
00726 }
00727 }
00728 break;
00729 case PNG_COLOR_TYPE_PALETTE:
00730 {
00731 Q_UINT8 *dst = row_pointers[y];
00732 KisPNGStream writestream(dst, color_nb_bits);
00733 while (!it.isDone()) {
00734 const Q_UINT8 *d = it.rawData();
00735 int i;
00736 for(i = 0; i < num_palette; i++)
00737 {
00738 if(palette[i].red == d[2] &&
00739 palette[i].green == d[1] &&
00740 palette[i].blue == d[0] )
00741 {
00742 break;
00743 }
00744 }
00745 writestream.setNextValue(i);
00746 ++it;
00747 }
00748 }
00749 break;
00750 default:
00751 kdDebug(41008) << "Unsupported color type for writting : " << color_type << endl;
00752 KIO::del(uri);
00753 return KisImageBuilder_RESULT_UNSUPPORTED;
00754 }
00755 }
00756
00757 png_write_image(png_ptr, row_pointers);
00758
00759
00760
00761 png_write_end(png_ptr, info_ptr);
00762
00763
00764 png_destroy_write_struct(&png_ptr, &info_ptr);
00765 for (int y = 0; y < height; y++) {
00766 delete[] row_pointers[y];
00767 }
00768 delete[] row_pointers;
00769
00770 if( color_type == PNG_COLOR_TYPE_PALETTE)
00771 {
00772 delete palette;
00773 }
00774
00775 fclose(fp);
00776
00777 return KisImageBuilder_RESULT_OK;
00778 }
00779
00780
00781 void KisPNGConverter::cancel()
00782 {
00783 m_stop = true;
00784 }
00785
00786 void KisPNGConverter::progress(png_structp png_ptr, png_uint_32 row_number, int pass)
00787 {
00788 if(png_ptr == NULL || row_number > PNG_MAX_UINT || pass > 7) return;
00789
00790 }
00791
00792
00793 #include "kis_png_converter.moc"
00794