You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/filters/chalk/png/kis_png_converter.cpp

808 lines
27 KiB

/*
* Copyright (c) 2005-2006 Cyrille Berger <cberger@cberger.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
// 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
#include "kis_png_converter.h"
#include <stdio.h>
#include <tqfile.h>
#include <tdeapplication.h>
#include <tdemessagebox.h>
#include <tdelocale.h>
#include <KoDocumentInfo.h>
#include <tdeio/netaccess.h>
#include <kis_abstract_colorspace.h>
#include <kis_colorspace_factory_registry.h>
#include <kis_doc.h>
#include <kis_image.h>
#include <kis_iterators_pixel.h>
#include <kis_layer.h>
#include <kis_meta_registry.h>
#include <kis_profile.h>
#include <kis_paint_layer.h>
#include <kis_group_layer.h>
#include <zlib.h>
namespace {
const TQ_UINT8 PIXEL_BLUE = 0;
const TQ_UINT8 PIXEL_GREEN = 1;
const TQ_UINT8 PIXEL_RED = 2;
const TQ_UINT8 PIXEL_ALPHA = 3;
int getColorTypeforColorSpace( KisColorSpace * cs , bool alpha)
{
if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") )
{
return alpha ? PNG_COLOR_TYPE_GRAY_ALPHA : PNG_COLOR_TYPE_GRAY;
}
if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") )
{
return alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
}
KMessageBox::error(0, i18n("Cannot export images in %1.\n").arg(cs->id().name()) ) ;
return -1;
}
TQString getColorSpaceForColorType(int color_type,int color_nb_bits) {
if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
switch(color_nb_bits)
{
case 8:
return "GRAYA";
case 16:
return "GRAYA16";
}
} else if(color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_RGB) {
switch(color_nb_bits)
{
case 8:
return "RGBA";
case 16:
return "RGBA16";
}
} else if(color_type == PNG_COLOR_TYPE_PALETTE) {
return "RGBA"; // <-- we will convert the index image to RGBA
}
return "";
}
void fillText(png_text* p_text, char* key, TQString& text)
{
p_text->compression = PNG_TEXT_COMPRESSION_zTXt;
p_text->key = key;
char* textc = new char[text.length()+1];
strcpy(textc, text.ascii());
p_text->text = textc;
p_text->text_length = text.length()+1;
}
}
KisPNGConverter::KisPNGConverter(KisDoc *doc, KisUndoAdapter *adapter)
{
Q_ASSERT(doc);
Q_ASSERT(adapter);
m_doc = doc;
m_adapter = adapter;
m_stop = false;
m_max_row = 0;
m_img = 0;
}
KisPNGConverter::~KisPNGConverter()
{
}
class KisPNGStream {
public:
KisPNGStream(TQ_UINT8* buf, TQ_UINT32 depth ) : m_posinc(8),m_depth(depth), m_buf(buf) { *m_buf = 0;};
int nextValue()
{
if( m_posinc == 0)
{
m_posinc = 8;
m_buf++;
}
m_posinc -= m_depth;
return (( (*m_buf) >> (m_posinc) ) & ( ( 1 << m_depth ) - 1 ) );
}
void setNextValue(int v)
{
if( m_posinc == 0)
{
m_posinc = 8;
m_buf++;
*m_buf = 0;
}
m_posinc -= m_depth;
*m_buf = (v << m_posinc) | *m_buf;
}
private:
TQ_UINT32 m_posinc, m_depth;
TQ_UINT8* m_buf;
};
KisImageBuilder_Result KisPNGConverter::decode(const KURL& uri)
{
kdDebug(41008) << "Start decoding PNG File" << endl;
// open the file
kdDebug(41008) << TQString(TQFile::encodeName(uri.path())) << " " << uri.path() << " " << uri << endl;
FILE *fp = fopen(TQFile::encodeName(uri.path()), "rb");
if (!fp)
{
return (KisImageBuilder_RESULT_NOT_EXIST);
}
png_byte signature[8];
fread(signature, 1, 8, fp);
if (!png_check_sig(signature, 8))
{
return (KisImageBuilder_RESULT_BAD_FETCH);
}
// Initialize the internal structures
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
if (!KisImageBuilder_RESULT_FAILURE)
return (KisImageBuilder_RESULT_FAILURE);
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
return (KisImageBuilder_RESULT_FAILURE);
}
png_infop end_info = png_create_info_struct(png_ptr);
if (!end_info)
{
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
return (KisImageBuilder_RESULT_FAILURE);
}
// Catch errors
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
return (KisImageBuilder_RESULT_FAILURE);
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
// read all PNG info up to image data
png_read_info(png_ptr, info_ptr);
// Read information about the png
png_uint_32 width, height;
int color_nb_bits, color_type, interlace_type;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &color_nb_bits, &color_type, &interlace_type, NULL, NULL);
kdDebug(41008) << "it's an " << color_nb_bits << " depth image" << endl;
// swap byteorder on little endian machines.
#ifndef WORDS_BIGENDIAN
if (color_nb_bits > 8 )
png_set_swap(png_ptr);
#endif
// Determine the colorspace
TQString csName = getColorSpaceForColorType(color_type, color_nb_bits);
if(csName.isEmpty()) {
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
}
bool hasalpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA);
int number_of_passes = 1;
if (interlace_type == PNG_INTERLACE_ADAM7)
number_of_passes = png_set_interlace_handling(png_ptr);
// Read image profile
KisProfile* profile = 0;
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
png_charp profile_name;
#if PNG_LIBPNG_VER < 10500
png_charp profile_data;
#else
png_bytep profile_data;
#endif
int compression_type;
png_uint_32 proflen;
if (png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen))
{
TQByteArray profile_rawdata;
// XXX: Hardcoded for icc type -- is that correct for us?
if (TQString::compare(profile_name, "icc") == 0) {
profile_rawdata.resize(proflen);
memcpy(profile_rawdata.data(), profile_data, proflen);
profile = new KisProfile(profile_rawdata);
TQ_CHECK_PTR(profile);
if (profile) {
kdDebug(41008) << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo() << endl;
if(!profile->isSuitableForOutput())
{
kdDebug(41008) << "the profile is not suitable for output and therefore cannot be used in chalk, we need to convert the image to a standard profile" << endl; // TODO: in ko2 popup a selection menu to inform the user
}
}
}
}
}
// Retrieve a pointer to the colorspace
KisColorSpace* cs;
if (profile && profile->isSuitableForOutput())
{
kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
}
else
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
if(cs == 0)
{
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
}
// Create the cmsTransform if needed
cmsHTRANSFORM transform = 0;
if(profile && !profile->isSuitableForOutput())
{
transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(),
cs->getProfile()->profile() , cs->colorSpaceType(),
INTENT_PERCEPTUAL, 0);
}
// Read comments/texts...
png_text* text_ptr;
int num_comments;
png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
KoDocumentInfo * info = m_doc->documentInfo();
KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author"));
kdDebug(41008) << "There are " << num_comments << " comments in the text" << endl;
for(int i = 0; i < num_comments; i++)
{
kdDebug(41008) << "key is " << text_ptr[i].key << " containing " << text_ptr[i].text << endl;
if(TQString::compare(text_ptr[i].key, "title") == 0)
{
aboutPage->setTitle(text_ptr[i].text);
} else if(TQString::compare(text_ptr[i].key, "abstract") == 0)
{
aboutPage->setAbstract(text_ptr[i].text);
} else if(TQString::compare(text_ptr[i].key, "author") == 0)
{
authorPage->setFullName(text_ptr[i].text);
}
}
// Read image data
png_bytep row_pointer = 0;
try
{
png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
row_pointer = new png_byte[rowbytes];
}
catch(std::bad_alloc& e)
{
// new png_byte[] may raise such an exception if the image
// is invalid / to large.
kdDebug(41008) << "bad alloc: " << e.what() << endl;
// Free only the already allocated png_byte instances.
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return (KisImageBuilder_RESULT_FAILURE);
}
// Read the palette if the file is indexed
png_colorp palette ;
int num_palette;
if(color_type == PNG_COLOR_TYPE_PALETTE) {
png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
}
// png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL );
// png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); // By using this function libpng will take care of freeing memory
// png_read_image(png_ptr, row_pointers);
// Finish reading the file
// png_read_end(png_ptr, end_info);
// fclose(fp);
// Creating the KisImageSP
if( ! m_img) {
m_img = new KisImage(m_doc->undoAdapter(), width, height, cs, "built image");
m_img->blockSignals(true); // Don't send out signals while we're building the image
TQ_CHECK_PTR(m_img);
if(profile && !profile->isSuitableForOutput())
{
m_img -> addAnnotation( profile->annotation() );
}
}
KisPaintLayer* layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX);
for (int i = 0; i < number_of_passes; i++)
{
for (png_uint_32 y = 0; y < height; y++) {
KisHLineIterator it = layer -> paintDevice() -> createHLineIterator(0, y, width, true);
png_read_rows(png_ptr, &row_pointer, NULL, 1);
switch(color_type)
{
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_GRAY_ALPHA:
if(color_nb_bits == 16)
{
TQ_UINT16 *src = reinterpret_cast<TQ_UINT16 *>(row_pointer);
while (!it.isDone()) {
TQ_UINT16 *d = reinterpret_cast<TQ_UINT16 *>(it.rawData());
d[0] = *(src++);
if(transform) cmsDoTransform(transform, d, d, 1);
if(hasalpha) d[1] = *(src++);
else d[1] = TQ_UINT16_MAX;
++it;
}
} else {
TQ_UINT8 *src = row_pointer;
while (!it.isDone()) {
TQ_UINT8 *d = it.rawData();
d[0] = *(src++);
if(transform) cmsDoTransform(transform, d, d, 1);
if(hasalpha) d[1] = *(src++);
else d[1] = TQ_UINT8_MAX;
++it;
}
}
//FIXME:should be able to read 1 and 4 bits depth and scale them to 8 bits
break;
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
if(color_nb_bits == 16)
{
TQ_UINT16 *src = reinterpret_cast<TQ_UINT16 *>(row_pointer);
while (!it.isDone()) {
TQ_UINT16 *d = reinterpret_cast<TQ_UINT16 *>(it.rawData());
d[2] = *(src++);
d[1] = *(src++);
d[0] = *(src++);
if(transform) cmsDoTransform(transform, d, d, 1);
if(hasalpha) d[3] = *(src++);
else d[3] = TQ_UINT16_MAX;
++it;
}
} else {
TQ_UINT8 *src = row_pointer;
while (!it.isDone()) {
TQ_UINT8 *d = it.rawData();
d[2] = *(src++);
d[1] = *(src++);
d[0] = *(src++);
if(transform) cmsDoTransform(transform, d, d, 1);
if(hasalpha) d[3] = *(src++);
else d[3] = TQ_UINT8_MAX;
++it;
}
}
break;
case PNG_COLOR_TYPE_PALETTE:
{
KisPNGStream stream(row_pointer, color_nb_bits);
while (!it.isDone()) {
TQ_UINT8 *d = it.rawData();
png_color c = palette[ stream.nextValue() ];
d[2] = c.red;
d[1] = c.green;
d[0] = c.blue;
d[3] = TQ_UINT8_MAX;
++it;
}
}
break;
default:
return KisImageBuilder_RESULT_UNSUPPORTED;
}
}
}
m_img->addLayer(layer, m_img->rootLayer(), 0);
png_read_end(png_ptr, end_info);
fclose(fp);
// Freeing memory
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
delete [] row_pointer;
return KisImageBuilder_RESULT_OK;
}
KisImageBuilder_Result KisPNGConverter::buildImage(const KURL& uri)
{
kdDebug(41008) << TQString(TQFile::encodeName(uri.path())) << " " << uri.path() << " " << uri << endl;
if (uri.isEmpty())
return KisImageBuilder_RESULT_NO_URI;
if (!TDEIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) {
return KisImageBuilder_RESULT_NOT_EXIST;
}
// We're not set up to handle asynchronous loading at the moment.
KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
TQString tmpFile;
if (TDEIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
KURL uriTF;
uriTF.setPath( tmpFile );
result = decode(uriTF);
TDEIO::NetAccess::removeTempFile(tmpFile);
}
return result;
}
KisImageSP KisPNGConverter::image()
{
return m_img;
}
KisImageBuilder_Result KisPNGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, int compression, bool interlace, bool alpha)
{
kdDebug(41008) << "Start writing PNG File" << endl;
if (!layer)
return KisImageBuilder_RESULT_INVALID_ARG;
KisImageSP img = layer -> image();
if (!img)
return KisImageBuilder_RESULT_EMPTY;
if (uri.isEmpty())
return KisImageBuilder_RESULT_NO_URI;
if (!uri.isLocalFile())
return KisImageBuilder_RESULT_NOT_LOCAL;
// Open file for writing
FILE *fp = fopen(TQFile::encodeName(uri.path()), "wb");
if (!fp)
{
return (KisImageBuilder_RESULT_FAILURE);
}
int height = img->height();
int width = img->width();
// Initialize structures
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
if (!png_ptr)
{
TDEIO::del(uri);
return (KisImageBuilder_RESULT_FAILURE);
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
TDEIO::del(uri);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return (KisImageBuilder_RESULT_FAILURE);
}
// If an error occurs during writing, libpng will jump here
if (setjmp(png_jmpbuf(png_ptr)))
{
TDEIO::del(uri);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
return (KisImageBuilder_RESULT_FAILURE);
}
// Initialize the writing
png_init_io(png_ptr, fp);
// Setup the progress function
// FIXME png_set_write_status_fn(png_ptr, progress);
// setProgressTotalSteps(100/*height*/);
/* set the zlib compression level */
png_set_compression_level(png_ptr, compression);
/* set other zlib parameters */
png_set_compression_mem_level(png_ptr, 8);
png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
png_set_compression_window_bits(png_ptr, 15);
png_set_compression_method(png_ptr, 8);
png_set_compression_buffer_size(png_ptr, 8192);
int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
int color_type = getColorTypeforColorSpace(layer->paintDevice()->colorSpace(), alpha);
if(color_type == -1)
{
return KisImageBuilder_RESULT_UNSUPPORTED;
}
// Try to compute a table of color if the colorspace is RGB8f
png_colorp palette ;
int num_palette = 0;
if(!alpha && layer->paintDevice()->colorSpace()->id() == KisID("RGBA") )
{ // png doesn't handle indexed images and alpha, and only have indexed for RGB8
palette = new png_color[255];
KisRectIteratorPixel it = layer->paintDevice()->createRectIterator(0,0, img->width(), img->height(), false);
bool toomuchcolor = false;
while( !it.isDone() )
{
const TQ_UINT8* c = it.rawData();
bool findit = false;
for(int i = 0; i < num_palette; i++)
{
if(palette[i].red == c[2] &&
palette[i].green == c[1] &&
palette[i].blue == c[0] )
{
findit = true;
break;
}
}
if(!findit)
{
if( num_palette == 255)
{
toomuchcolor = true;
break;
}
palette[num_palette].red = c[2];
palette[num_palette].green = c[1];
palette[num_palette].blue = c[0];
num_palette++;
}
++it;
}
if(!toomuchcolor)
{
kdDebug(41008) << "Found a palette of " << num_palette << " colors" << endl;
color_type = PNG_COLOR_TYPE_PALETTE;
if( num_palette <= 2)
{
color_nb_bits = 1;
} else if( num_palette <= 4)
{
color_nb_bits = 2;
} else if( num_palette <= 16)
{
color_nb_bits = 4;
} else {
color_nb_bits = 8;
}
} else {
delete palette;
}
}
int interlacetype = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
png_set_IHDR(png_ptr, info_ptr,
width,
height,
color_nb_bits,
color_type, interlacetype,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
// set the palette
if( color_type == PNG_COLOR_TYPE_PALETTE)
{
png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
}
// Save annotation
vKisAnnotationSP_it it = annotationsStart;
while(it != annotationsEnd) {
if (!(*it) || (*it) -> type() == TQString()) {
kdDebug(41008) << "Warning: empty annotation" << endl;
++it;
continue;
}
kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute
// FIXME: it should be possible to save chalk_attributes in the "CHUNKs"
kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl;
} else { // Profile
char* name = new char[(*it)->type().length()+1];
strcpy(name, (*it)->type().ascii());
#if PNG_LIBPNG_VER < 10500
png_set_iCCP(png_ptr, info_ptr, name, PNG_COMPRESSION_TYPE_BASE, (png_charp)(*it)->annotation().data(), (*it) -> annotation() . size());
#else
png_set_iCCP(png_ptr, info_ptr, name, PNG_COMPRESSION_TYPE_BASE, (png_bytep)(*it)->annotation().data(), (*it) -> annotation() . size());
#endif
}
++it;
}
// read comments from the document information
png_text texts[3];
int nbtexts = 0;
KoDocumentInfo * info = m_doc->documentInfo();
KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
TQString title = aboutPage->title();
if(!title.isEmpty())
{
fillText(texts+nbtexts, "title", title);
nbtexts++;
}
TQString abstract = aboutPage->abstract();
if(!abstract.isEmpty())
{
fillText(texts+nbtexts, "abstract", abstract);
nbtexts++;
}
KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor *>(info->page( "author" ));
TQString author = authorPage->fullName();
if(!author.isEmpty())
{
fillText(texts+nbtexts, "author", author);
nbtexts++;
}
png_set_text(png_ptr, info_ptr, texts, nbtexts);
// Save the information to the file
png_write_info(png_ptr, info_ptr);
png_write_flush(png_ptr);
// swap byteorder on little endian machines.
#ifndef WORDS_BIGENDIAN
if (color_nb_bits > 8 )
png_set_swap(png_ptr);
#endif
// Write the PNG
// png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
// Fill the data structure
png_byte** row_pointers= new png_byte*[height];
for (int y = 0; y < height; y++) {
KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
row_pointers[y] = new png_byte[width*layer->paintDevice()->pixelSize()];
switch(color_type)
{
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_GRAY_ALPHA:
if(color_nb_bits == 16)
{
TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(row_pointers[y]);
while (!it.isDone()) {
const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
*(dst++) = d[0];
if(alpha) *(dst++) = d[1];
++it;
}
} else {
TQ_UINT8 *dst = row_pointers[y];
while (!it.isDone()) {
const TQ_UINT8 *d = it.rawData();
*(dst++) = d[0];
if(alpha) *(dst++) = d[1];
++it;
}
}
break;
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
if(color_nb_bits == 16)
{
TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(row_pointers[y]);
while (!it.isDone()) {
const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
*(dst++) = d[2];
*(dst++) = d[1];
*(dst++) = d[0];
if(alpha) *(dst++) = d[3];
++it;
}
} else {
TQ_UINT8 *dst = row_pointers[y];
while (!it.isDone()) {
const TQ_UINT8 *d = it.rawData();
*(dst++) = d[2];
*(dst++) = d[1];
*(dst++) = d[0];
if(alpha) *(dst++) = d[3];
++it;
}
}
break;
case PNG_COLOR_TYPE_PALETTE:
{
TQ_UINT8 *dst = row_pointers[y];
KisPNGStream writestream(dst, color_nb_bits);
while (!it.isDone()) {
const TQ_UINT8 *d = it.rawData();
int i;
for(i = 0; i < num_palette; i++)
{
if(palette[i].red == d[2] &&
palette[i].green == d[1] &&
palette[i].blue == d[0] )
{
break;
}
}
writestream.setNextValue(i);
++it;
}
}
break;
default:
kdDebug(41008) << "Unsupported color type for writting : " << color_type << endl;
TDEIO::del(uri);
return KisImageBuilder_RESULT_UNSUPPORTED;
}
}
png_write_image(png_ptr, row_pointers);
// Writting is over
png_write_end(png_ptr, info_ptr);
// Free memory
png_destroy_write_struct(&png_ptr, &info_ptr);
for (int y = 0; y < height; y++) {
delete[] row_pointers[y];
}
delete[] row_pointers;
if( color_type == PNG_COLOR_TYPE_PALETTE)
{
delete palette;
}
fclose(fp);
return KisImageBuilder_RESULT_OK;
}
void KisPNGConverter::cancel()
{
m_stop = true;
}
void KisPNGConverter::progress(png_structp png_ptr, png_uint_32 row_number, int pass)
{
if(png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) return;
// setProgress(row_number);
}
#include "kis_png_converter.moc"