/*
* 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"