1997-11-25 06:05:25 +08:00
/*
* " $Id$ "
*
* Portable Network Graphics ( PNG ) plug - in for The GIMP - - an image
* manipulation program
*
1998-05-31 14:49:20 +08:00
* Copyright 1997 - 1998 Michael Sweet ( mike @ easysw . com ) and
1997-11-25 06:05:25 +08:00
* Daniel Skarda ( 0 rfelyus @ atrey . karlin . mff . cuni . cz ) .
2000-04-14 23:21:14 +08:00
* and 1999 - 2000 Nick Lamb ( njl195 @ zepler . org . uk )
1997-11-25 06:05:25 +08:00
*
* 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
1998-04-13 13:44:11 +08:00
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
1997-11-25 06:05:25 +08:00
*
* Contents :
*
* main ( ) - Main entry - just call gimp_main ( ) . . .
* query ( ) - Respond to a plug - in query . . .
* run ( ) - Run the plug - in . . .
* load_image ( ) - Load a PNG image into a new image window .
2000-04-02 10:46:59 +08:00
* respin_cmap ( ) - Re - order a Gimp colormap for PNG tRNS
1997-11-25 06:05:25 +08:00
* save_image ( ) - Save the specified image to a PNG file .
* save_compression_callback ( ) - Update the image compression level .
* save_interlace_update ( ) - Update the interlacing option .
* save_dialog ( ) - Pop up the save dialog .
*
* Revision History :
*
1999-06-29 14:15:15 +08:00
* see ChangeLog
1997-11-25 06:05:25 +08:00
*/
2000-01-08 23:23:28 +08:00
# include "config.h"
2003-06-13 22:37:00 +08:00
# include <errno.h>
1997-11-25 06:05:25 +08:00
# include <stdio.h>
# include <stdlib.h>
1999-11-09 13:16:55 +08:00
# include <time.h>
1997-11-25 06:05:25 +08:00
# include <gtk/gtk.h>
2000-01-08 23:23:28 +08:00
1997-11-25 06:05:25 +08:00
# include <libgimp/gimp.h>
1999-10-04 02:54:54 +08:00
# include <libgimp/gimpui.h>
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
# include <png.h> /* PNG library definitions */
2000-01-26 01:46:56 +08:00
1999-05-30 00:35:47 +08:00
# include "libgimp/stdplugins-intl.h"
1997-11-25 06:05:25 +08:00
2000-05-02 01:01:18 +08:00
1997-11-25 06:05:25 +08:00
/*
* Constants . . .
*/
2004-01-06 17:53:35 +08:00
# define PLUG_IN_VERSION "1.3.4 - 03 September 2002"
# define SCALE_WIDTH 125
1997-11-25 06:05:25 +08:00
2004-01-06 17:53:35 +08:00
# define DEFAULT_GAMMA 2.20
# define RESPONSE_LOAD_DEFAULTS 1
# define RESPONSE_SAVE_DEFAULTS 2
2004-01-06 20:58:31 +08:00
# define PNG_DEFAULTS_PARASITE "png-save-defaults"
1997-11-25 06:05:25 +08:00
/*
* Structures . . .
*/
typedef struct
{
2003-07-03 23:13:29 +08:00
gboolean interlaced ;
gboolean bkgd ;
gboolean gama ;
gboolean offs ;
gboolean phys ;
gboolean time ;
gboolean comment ;
2004-01-05 08:57:43 +08:00
gboolean save_transp_pixels ;
2004-01-06 17:53:35 +08:00
gint compression_level ;
2002-10-14 23:32:47 +08:00
}
PngSaveVals ;
1997-11-25 06:05:25 +08:00
2004-01-06 17:53:35 +08:00
typedef struct
{
gboolean run ;
GtkWidget * interlaced ;
GtkWidget * bkgd ;
GtkWidget * gama ;
GtkWidget * offs ;
GtkWidget * phys ;
GtkWidget * time ;
GtkWidget * comment ;
GtkWidget * save_transp_pixels ;
GtkObject * compression_level ;
}
PngSaveGui ;
1997-11-25 06:05:25 +08:00
/*
* Local functions . . .
*/
2002-10-14 23:32:47 +08:00
static void query ( void ) ;
2004-01-05 08:57:43 +08:00
static void run ( const gchar * name ,
gint nparams ,
const GimpParam * param ,
gint * nreturn_vals ,
GimpParam * * return_vals ) ;
2003-07-02 20:03:08 +08:00
2003-11-19 00:46:56 +08:00
static gint32 load_image ( const gchar * filename ,
gboolean interactive ) ;
2003-07-02 20:03:08 +08:00
static gint save_image ( const gchar * filename ,
gint32 image_ID ,
gint32 drawable_ID ,
gint32 orig_image_ID ) ;
2002-10-14 23:32:47 +08:00
2003-07-03 23:13:29 +08:00
static void respin_cmap ( png_structp pp ,
png_infop info ,
guchar * remap ,
gint32 image_ID ,
GimpDrawable * drawable ) ;
2002-10-14 23:32:47 +08:00
2004-01-05 08:57:43 +08:00
static gint save_dialog ( gint32 image_ID ,
gboolean alpha ) ;
2002-10-14 23:32:47 +08:00
2004-01-06 17:53:35 +08:00
static void save_dialog_response ( GtkWidget * widget ,
gint response_id ,
gpointer data ) ;
2003-07-03 23:13:29 +08:00
static int find_unused_ia_colour ( guchar * pixels ,
gint numpixels ,
gint * colors ) ;
1997-11-25 06:05:25 +08:00
2004-01-06 17:53:35 +08:00
static gboolean load_defaults ( void ) ;
static void save_defaults ( void ) ;
static void load_gui_defaults ( PngSaveGui * pg ) ;
1997-11-25 06:05:25 +08:00
/*
* Globals . . .
*/
2003-07-03 23:13:29 +08:00
GimpPlugInInfo PLUG_IN_INFO =
{
NULL ,
NULL ,
query ,
2004-01-05 08:57:43 +08:00
run
1997-11-25 06:05:25 +08:00
} ;
2003-07-03 23:13:29 +08:00
PngSaveVals pngvals =
{
FALSE ,
TRUE ,
FALSE ,
1999-11-09 13:16:55 +08:00
FALSE ,
2003-07-03 23:13:29 +08:00
TRUE ,
TRUE ,
2004-01-05 08:57:43 +08:00
TRUE ,
2004-01-06 17:53:35 +08:00
TRUE ,
9
1997-11-25 06:05:25 +08:00
} ;
/*
* ' main ( ) ' - Main entry - just call gimp_main ( ) . . .
*/
2002-10-14 23:32:47 +08:00
MAIN ( )
2003-02-22 22:20:53 +08:00
2002-09-11 00:46:41 +08:00
1997-11-25 06:05:25 +08:00
/*
* ' query ( ) ' - Respond to a plug - in query . . .
*/
static void
1999-10-04 02:54:54 +08:00
query ( void )
1997-11-25 06:05:25 +08:00
{
2002-10-14 23:32:47 +08:00
static GimpParamDef load_args [ ] = {
{ GIMP_PDB_INT32 , " run_mode " , " Interactive, non-interactive " } ,
{ GIMP_PDB_STRING , " filename " , " The name of the file to load " } ,
{ GIMP_PDB_STRING , " raw_filename " , " The name of the file to load " }
1997-11-25 06:05:25 +08:00
} ;
2002-10-14 23:32:47 +08:00
static GimpParamDef load_return_vals [ ] = {
{ GIMP_PDB_IMAGE , " image " , " Output image " }
1997-11-25 06:05:25 +08:00
} ;
2000-01-26 01:46:56 +08:00
2004-01-06 17:53:35 +08:00
# define COMMON_SAVE_ARGS \
{ GIMP_PDB_INT32 , " run_mode " , " Interactive, non-interactive " } , \
{ GIMP_PDB_IMAGE , " image " , " Input image " } , \
{ GIMP_PDB_DRAWABLE , " drawable " , " Drawable to save " } , \
{ GIMP_PDB_STRING , " filename " , \
" The name of the file to save the image in " } , \
{ GIMP_PDB_STRING , " raw_filename " , \
" The name of the file to save the image in " }
# define OLD_CONFIG_ARGS \
{ GIMP_PDB_INT32 , " interlace " , " Use Adam7 interlacing? " } , \
{ GIMP_PDB_INT32 , " compression " , " Deflate Compression factor (0--9) " } , \
{ GIMP_PDB_INT32 , " bkgd " , " Write bKGD chunk? " } , \
{ GIMP_PDB_INT32 , " gama " , " Write gAMA chunk? " } , \
{ GIMP_PDB_INT32 , " offs " , " Write oFFs chunk? " } , \
{ GIMP_PDB_INT32 , " phys " , " Write pHYs chunk? " } , \
2003-10-09 02:18:10 +08:00
{ GIMP_PDB_INT32 , " time " , " Write tIME chunk? " }
2004-01-06 17:53:35 +08:00
# define FULL_CONFIG_ARGS \
OLD_CONFIG_ARGS , \
{ GIMP_PDB_INT32 , " comment " , " Write comment? " } , \
{ GIMP_PDB_INT32 , " svtrans " , " Preserve color of transparent pixels? " }
static GimpParamDef save_args [ ] = {
COMMON_SAVE_ARGS ,
OLD_CONFIG_ARGS
1997-11-25 06:05:25 +08:00
} ;
2004-01-05 08:57:43 +08:00
static GimpParamDef save_args2 [ ] = {
2004-01-06 17:53:35 +08:00
COMMON_SAVE_ARGS ,
FULL_CONFIG_ARGS
} ;
static GimpParamDef save_args_defaults [ ] = {
COMMON_SAVE_ARGS
} ;
static GimpParamDef save_get_defaults_return_vals [ ] = {
FULL_CONFIG_ARGS
} ;
static GimpParamDef save_args_set_defaults [ ] = {
FULL_CONFIG_ARGS
2004-01-05 08:57:43 +08:00
} ;
1999-10-04 02:54:54 +08:00
gimp_install_procedure ( " file_png_load " ,
2002-10-14 23:32:47 +08:00
" Loads files in PNG file format " ,
" This plug-in loads Portable Network Graphics (PNG) files. " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz> " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz>, Nick Lamb <njl195@zepler.org.uk> " ,
PLUG_IN_VERSION ,
2004-05-14 08:01:11 +08:00
N_ ( " PNG image " ) ,
2002-10-14 23:32:47 +08:00
NULL ,
GIMP_PLUGIN ,
G_N_ELEMENTS ( load_args ) ,
2001-12-06 10:28:58 +08:00
G_N_ELEMENTS ( load_return_vals ) ,
2002-10-14 23:32:47 +08:00
load_args , load_return_vals ) ;
2004-05-14 08:01:11 +08:00
gimp_plugin_menu_register ( " file_png_load " , " <Load> " ) ;
gimp_register_file_handler_mime ( " file_png_load " , " image/png " ) ;
gimp_register_magic_load_handler ( " file_png_load " ,
" png " , " " , " 0,string, \211 PNG \r \n \032 \n " ) ;
2002-10-14 23:32:47 +08:00
gimp_install_procedure ( " file_png_save " ,
" Saves files in PNG file format " ,
" This plug-in saves Portable Network Graphics (PNG) files. " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz> " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz>, Nick Lamb <njl195@zepler.org.uk> " ,
PLUG_IN_VERSION ,
2004-05-14 08:01:11 +08:00
N_ ( " PNG image " ) ,
2002-10-14 23:32:47 +08:00
" RGB*,GRAY*,INDEXED* " ,
GIMP_PLUGIN ,
2004-01-06 17:53:35 +08:00
G_N_ELEMENTS ( save_args ) , 0 ,
save_args , NULL ) ;
2000-01-14 20:41:00 +08:00
2004-05-14 08:01:11 +08:00
gimp_register_file_handler_mime ( " file_png_save " , " image/png " ) ;
2004-01-05 08:57:43 +08:00
gimp_install_procedure ( " file_png_save2 " ,
" Saves files in PNG file format " ,
" This plug-in saves Portable Network Graphics (PNG) files. "
2004-01-06 17:53:35 +08:00
" This procedure adds 2 extra parameters to file_png_save that allows to control whether image comments are saved and whether transparent pixels are saved or nullified. " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz> " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz>, Nick Lamb <njl195@zepler.org.uk> " ,
PLUG_IN_VERSION ,
2004-05-14 08:01:11 +08:00
N_ ( " PNG image " ) ,
2004-01-06 17:53:35 +08:00
" RGB*,GRAY*,INDEXED* " ,
GIMP_PLUGIN ,
G_N_ELEMENTS ( save_args2 ) , 0 ,
save_args2 , NULL ) ;
2004-05-14 08:01:11 +08:00
gimp_register_file_handler_mime ( " file_png_save2 " , " image/png " ) ;
2004-01-06 17:53:35 +08:00
gimp_install_procedure ( " file_png_save_defaults " ,
" Saves files in PNG file format " ,
2004-01-06 20:58:31 +08:00
" This plug-in saves Portable Network Graphics (PNG) files, using the default settings stored as a parasite. " ,
2004-01-05 08:57:43 +08:00
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz> " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz>, Nick Lamb <njl195@zepler.org.uk> " ,
PLUG_IN_VERSION ,
2004-05-14 08:01:11 +08:00
N_ ( " PNG image " ) ,
2004-01-05 08:57:43 +08:00
" RGB*,GRAY*,INDEXED* " ,
GIMP_PLUGIN ,
2004-01-06 17:53:35 +08:00
G_N_ELEMENTS ( save_args_defaults ) , 0 ,
save_args_defaults , NULL ) ;
2004-05-14 08:01:11 +08:00
gimp_plugin_menu_register ( " file_png_save_defaults " , " <Save> " ) ;
gimp_register_file_handler_mime ( " file_png_save_defaults " , " image/png " ) ;
2004-01-09 03:34:07 +08:00
gimp_register_save_handler ( " file_png_save_defaults " , " png " , " " ) ;
2004-01-06 17:53:35 +08:00
gimp_install_procedure ( " file_png_get_defaults " ,
" Get the current set of defaults used by the PNG file save plug-in " ,
2004-01-06 20:58:31 +08:00
" This procedure returns the current set of defaults stored as a parasite for the PNG save plug-in. "
2004-01-06 17:53:35 +08:00
" These defaults are used to seed the UI, by the file_png_save_defaults procedure, and by gimp_file_save when it detects to use PNG. " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz> " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz>, Nick Lamb <njl195@zepler.org.uk> " ,
PLUG_IN_VERSION ,
NULL ,
NULL ,
GIMP_PLUGIN ,
0 , G_N_ELEMENTS ( save_get_defaults_return_vals ) ,
NULL , save_get_defaults_return_vals ) ;
gimp_install_procedure ( " file_png_set_defaults " ,
" Set the current set of defaults used by the PNG file save plug-in " ,
2004-01-06 20:58:31 +08:00
" This procedure set the current set of defaults stored as a parasite for the PNG save plug-in. "
2004-01-06 17:53:35 +08:00
" These defaults are used to seed the UI, by the file_png_save_defaults procedure, and by gimp_file_save when it detects to use PNG. " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz> " ,
" Michael Sweet <mike@easysw.com>, Daniel Skarda <0rfelyus@atrey.karlin.mff.cuni.cz>, Nick Lamb <njl195@zepler.org.uk> " ,
PLUG_IN_VERSION ,
NULL ,
NULL ,
GIMP_PLUGIN ,
G_N_ELEMENTS ( save_args_set_defaults ) , 0 ,
save_args_set_defaults , NULL ) ;
1997-11-25 06:05:25 +08:00
}
/*
* ' run ( ) ' - Run the plug - in . . .
*/
static void
2003-07-02 20:03:08 +08:00
run ( const gchar * name ,
gint nparams ,
const GimpParam * param ,
gint * nreturn_vals ,
GimpParam * * return_vals )
1997-11-25 06:05:25 +08:00
{
2004-01-06 17:53:35 +08:00
static GimpParam values [ 10 ] ;
2003-11-06 23:27:05 +08:00
GimpRunMode run_mode ;
GimpPDBStatusType status = GIMP_PDB_SUCCESS ;
gint32 image_ID ;
gint32 drawable_ID ;
gint32 orig_image_ID ;
GimpExportReturn export = GIMP_EXPORT_CANCEL ;
1997-11-25 06:05:25 +08:00
2003-03-26 00:38:19 +08:00
INIT_I18N ( ) ;
2000-01-26 01:46:56 +08:00
* nreturn_vals = 1 ;
2002-10-14 23:32:47 +08:00
* return_vals = values ;
2001-12-31 08:21:10 +08:00
2002-10-14 23:32:47 +08:00
values [ 0 ] . type = GIMP_PDB_STATUS ;
2000-08-22 09:26:57 +08:00
values [ 0 ] . data . d_status = GIMP_PDB_EXECUTION_ERROR ;
1997-11-25 06:05:25 +08:00
1999-10-04 02:54:54 +08:00
if ( strcmp ( name , " file_png_load " ) = = 0 )
2000-01-14 20:41:00 +08:00
{
2003-11-19 00:46:56 +08:00
run_mode = param [ 0 ] . data . d_int32 ;
image_ID = load_image ( param [ 1 ] . data . d_string ,
run_mode = = GIMP_RUN_INTERACTIVE ) ;
1997-11-25 06:05:25 +08:00
2000-01-14 20:41:00 +08:00
if ( image_ID ! = - 1 )
2002-10-14 23:32:47 +08:00
{
* nreturn_vals = 2 ;
values [ 1 ] . type = GIMP_PDB_IMAGE ;
values [ 1 ] . data . d_image = image_ID ;
}
2000-01-14 20:41:00 +08:00
else
2002-10-14 23:32:47 +08:00
{
status = GIMP_PDB_EXECUTION_ERROR ;
}
1997-11-25 06:05:25 +08:00
}
2004-01-05 08:57:43 +08:00
else if ( strcmp ( name , " file_png_save " ) = = 0 | |
2004-01-06 17:53:35 +08:00
strcmp ( name , " file_png_save2 " ) = = 0 | |
strcmp ( name , " file_png_save_defaults " ) = = 0 )
1997-11-25 06:05:25 +08:00
{
2004-01-05 08:57:43 +08:00
gboolean alpha ;
run_mode = param [ 0 ] . data . d_int32 ;
image_ID = orig_image_ID = param [ 1 ] . data . d_int32 ;
2000-01-14 20:41:00 +08:00
drawable_ID = param [ 2 ] . data . d_int32 ;
2002-10-14 23:32:47 +08:00
2004-01-06 17:53:35 +08:00
load_defaults ( ) ;
2002-10-14 23:32:47 +08:00
/* eventually export the image */
2000-01-14 20:41:00 +08:00
switch ( run_mode )
2002-10-14 23:32:47 +08:00
{
case GIMP_RUN_INTERACTIVE :
case GIMP_RUN_WITH_LAST_VALS :
gimp_ui_init ( " png " , FALSE ) ;
export = gimp_export_image ( & image_ID , & drawable_ID , " PNG " ,
( GIMP_EXPORT_CAN_HANDLE_RGB |
GIMP_EXPORT_CAN_HANDLE_GRAY |
GIMP_EXPORT_CAN_HANDLE_INDEXED |
GIMP_EXPORT_CAN_HANDLE_ALPHA ) ) ;
if ( export = = GIMP_EXPORT_CANCEL )
{
* nreturn_vals = 1 ;
values [ 0 ] . data . d_status = GIMP_PDB_CANCEL ;
return ;
}
break ;
default :
break ;
}
2000-01-14 20:41:00 +08:00
switch ( run_mode )
2002-10-14 23:32:47 +08:00
{
case GIMP_RUN_INTERACTIVE :
/*
* Possibly retrieve data . . .
*/
1999-10-04 02:54:54 +08:00
gimp_get_data ( " file_png_save " , & pngvals ) ;
1997-11-25 06:05:25 +08:00
2004-01-05 08:57:43 +08:00
alpha = gimp_drawable_has_alpha ( drawable_ID ) ;
2002-11-07 04:37:19 +08:00
/*
* If the image has no transparency , then there is usually
* no need to save a bKGD chunk . For more information , see :
* http : //bugzilla.gnome.org/show_bug.cgi?id=92395
*/
2004-01-05 08:57:43 +08:00
if ( ! alpha )
2002-11-07 04:37:19 +08:00
pngvals . bkgd = FALSE ;
2002-10-14 23:32:47 +08:00
/*
* Then acquire information with a dialog . . .
*/
2004-01-05 08:57:43 +08:00
if ( ! save_dialog ( orig_image_ID , alpha ) )
2000-08-22 09:26:57 +08:00
status = GIMP_PDB_CANCEL ;
1997-11-25 06:05:25 +08:00
break ;
2002-10-14 23:32:47 +08:00
case GIMP_RUN_NONINTERACTIVE :
/*
* Make sure all the arguments are there !
*/
2004-01-06 17:53:35 +08:00
if ( nparams ! = 5 )
2002-10-14 23:32:47 +08:00
{
2004-01-06 17:53:35 +08:00
if ( nparams ! = 12 & & nparams ! = 14 )
{
status = GIMP_PDB_CALLING_ERROR ;
}
2004-01-05 08:57:43 +08:00
else
2004-01-06 17:53:35 +08:00
{
pngvals . interlaced = param [ 5 ] . data . d_int32 ;
pngvals . compression_level = param [ 6 ] . data . d_int32 ;
pngvals . bkgd = param [ 7 ] . data . d_int32 ;
pngvals . gama = param [ 8 ] . data . d_int32 ;
pngvals . offs = param [ 9 ] . data . d_int32 ;
pngvals . phys = param [ 10 ] . data . d_int32 ;
pngvals . time = param [ 11 ] . data . d_int32 ;
if ( nparams = = 14 )
{
pngvals . comment = param [ 12 ] . data . d_int32 ;
pngvals . save_transp_pixels = param [ 13 ] . data . d_int32 ;
}
else
{
pngvals . comment = TRUE ;
pngvals . save_transp_pixels = TRUE ;
}
2002-10-14 23:32:47 +08:00
2004-01-06 17:53:35 +08:00
if ( pngvals . compression_level < 0 | |
pngvals . compression_level > 9 )
status = GIMP_PDB_CALLING_ERROR ;
}
}
1997-11-25 06:05:25 +08:00
break ;
2002-10-14 23:32:47 +08:00
case GIMP_RUN_WITH_LAST_VALS :
/*
* Possibly retrieve data . . .
*/
1999-10-04 02:54:54 +08:00
gimp_get_data ( " file_png_save " , & pngvals ) ;
1997-11-25 06:05:25 +08:00
break ;
2002-10-14 23:32:47 +08:00
default :
1997-11-25 06:05:25 +08:00
break ;
2004-01-06 17:53:35 +08:00
}
2000-01-14 20:41:00 +08:00
2000-08-22 09:26:57 +08:00
if ( status = = GIMP_PDB_SUCCESS )
2002-10-14 23:32:47 +08:00
{
if ( save_image ( param [ 3 ] . data . d_string ,
image_ID , drawable_ID , orig_image_ID ) )
{
gimp_set_data ( " file_png_save " , & pngvals , sizeof ( pngvals ) ) ;
}
else
{
status = GIMP_PDB_EXECUTION_ERROR ;
}
}
1999-10-20 09:45:41 +08:00
2000-08-24 22:17:34 +08:00
if ( export = = GIMP_EXPORT_EXPORT )
2002-10-14 23:32:47 +08:00
gimp_image_delete ( image_ID ) ;
2000-01-14 20:41:00 +08:00
}
2004-01-06 17:53:35 +08:00
else if ( strcmp ( name , " file_png_get_defaults " ) = = 0 )
{
load_defaults ( ) ;
* nreturn_vals = 9 ;
# define SET_VALUE(index, field) G_STMT_START { \
values [ ( index ) ] . type = GIMP_PDB_INT32 ; \
values [ ( index ) ] . data . d_int32 = pngvals . field ; \
} G_STMT_END
SET_VALUE ( 1 , interlaced ) ;
SET_VALUE ( 2 , compression_level ) ;
SET_VALUE ( 3 , bkgd ) ;
SET_VALUE ( 4 , gama ) ;
SET_VALUE ( 5 , offs ) ;
SET_VALUE ( 6 , phys ) ;
SET_VALUE ( 7 , time ) ;
SET_VALUE ( 8 , comment ) ;
SET_VALUE ( 9 , save_transp_pixels ) ;
# undef SET_VALUE
}
else if ( strcmp ( name , " file_png_set_defaults " ) = = 0 )
{
if ( nparams = = 10 )
{
pngvals . interlaced = param [ 1 ] . data . d_int32 ;
pngvals . compression_level = param [ 2 ] . data . d_int32 ;
pngvals . bkgd = param [ 3 ] . data . d_int32 ;
pngvals . gama = param [ 4 ] . data . d_int32 ;
pngvals . offs = param [ 5 ] . data . d_int32 ;
pngvals . phys = param [ 6 ] . data . d_int32 ;
pngvals . time = param [ 7 ] . data . d_int32 ;
pngvals . comment = param [ 8 ] . data . d_int32 ;
pngvals . save_transp_pixels = param [ 9 ] . data . d_int32 ;
save_defaults ( ) ;
}
else
status = GIMP_PDB_CALLING_ERROR ;
}
1997-11-25 06:05:25 +08:00
else
2000-01-26 01:46:56 +08:00
{
2000-08-22 09:26:57 +08:00
status = GIMP_PDB_EXECUTION_ERROR ;
2000-01-26 01:46:56 +08:00
}
values [ 0 ] . data . d_status = status ;
1997-11-25 06:05:25 +08:00
}
2003-11-03 00:52:26 +08:00
/* Try to find a colour in the palette which isn't actually
* used in the image , so that we can use it as the transparency
2003-07-03 23:13:29 +08:00
* index . Taken from gif . c */
static gint
find_unused_ia_colour ( guchar * pixels ,
gint numpixels ,
gint * colors )
{
gint i ;
gboolean ix_used [ 256 ] ;
gboolean trans_used = FALSE ;
for ( i = 0 ; i < * colors ; i + + )
{
ix_used [ i ] = FALSE ;
}
for ( i = 0 ; i < numpixels ; i + + )
{
2003-11-03 00:52:26 +08:00
/* If alpha is over a threshold, the colour index in the
2003-07-03 23:13:29 +08:00
* palette is taken . Otherwise , this pixel is transparent . */
if ( pixels [ i * 2 + 1 ] > 127 )
ix_used [ pixels [ i * 2 ] ] = TRUE ;
else
trans_used = TRUE ;
}
/* If there is no transparency, ignore alpha. */
if ( trans_used = = FALSE )
return - 1 ;
for ( i = 0 ; i < * colors ; i + + )
{
if ( ix_used [ i ] = = FALSE )
{
return i ;
}
}
/* Couldn't find an unused colour index within the number of
bits per pixel we wanted . Will have to increment the number
of colours in the image and assign a transparent pixel there . */
if ( ( * colors ) < 256 )
{
( * colors ) + + ;
return ( ( * colors ) - 1 ) ;
}
return ( - 1 ) ;
}
1997-11-25 06:05:25 +08:00
/*
* ' load_image ( ) ' - Load a PNG image into a new image window .
*/
static gint32
2003-11-19 00:46:56 +08:00
load_image ( const gchar * filename ,
gboolean interactive )
1997-11-25 06:05:25 +08:00
{
2002-10-14 23:32:47 +08:00
int i , /* Looping var */
trns , /* Transparency present */
bpp , /* Bytes per pixel */
image_type , /* Type of image */
layer_type , /* Type of drawable/layer */
empty , /* Number of fully transparent indices */
num_passes , /* Number of interlace passes in file */
pass , /* Current pass in file */
tile_height , /* Height of tile in GIMP */
begin , /* Beginning tile row */
end , /* Ending tile row */
num ; /* Number of rows to load */
FILE * fp ; /* File pointer */
volatile gint32 image ; /* Image -- preserved against setjmp() */
gint32 layer ; /* Layer */
GimpDrawable * drawable ; /* Drawable for layer */
GimpPixelRgn pixel_rgn ; /* Pixel region for layer */
png_structp pp ; /* PNG read pointer */
png_infop info ; /* PNG info pointers */
guchar * * pixels , /* Pixel rows */
* pixel ; /* Pixel data */
gchar * progress ; /* Title for progress display... */
guchar alpha [ 256 ] , /* Index -> Alpha */
* alpha_ptr ; /* Temporary pointer */
2003-07-03 08:30:33 +08:00
png_textp text ;
gint num_texts ;
2002-10-14 23:32:47 +08:00
/*
* PNG 0.89 and newer have a sane , forwards compatible constructor .
* Some SGI IRIX users will not have a new enough version though
*/
1997-11-25 06:05:25 +08:00
# if PNG_LIBPNG_VER > 88
2002-10-14 23:32:47 +08:00
pp = png_create_read_struct ( PNG_LIBPNG_VER_STRING , NULL , NULL , NULL ) ;
info = png_create_info_struct ( pp ) ;
1997-11-25 06:05:25 +08:00
# else
2002-10-14 23:32:47 +08:00
pp = ( png_structp ) calloc ( sizeof ( png_struct ) , 1 ) ;
png_read_init ( pp ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
info = ( png_infop ) calloc ( sizeof ( png_info ) , 1 ) ;
1997-11-25 06:05:25 +08:00
# endif /* PNG_LIBPNG_VER > 88 */
1999-10-04 02:54:54 +08:00
if ( setjmp ( pp - > jmpbuf ) )
2002-10-14 23:32:47 +08:00
{
2004-01-19 11:06:04 +08:00
g_message ( _ ( " Error while reading '%s'. File corrupted? " ) ,
gimp_filename_to_utf8 ( filename ) ) ;
2002-10-14 23:32:47 +08:00
return image ;
}
1999-09-13 08:57:52 +08:00
2000-04-25 11:57:03 +08:00
/* initialise image here, thus avoiding compiler warnings */
2000-04-21 09:38:36 +08:00
2002-10-14 23:32:47 +08:00
image = - 1 ;
2000-04-21 09:38:36 +08:00
2002-10-14 23:32:47 +08:00
/*
* Open the file and initialize the PNG read " engine " . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
fp = fopen ( filename , " rb " ) ;
1999-09-13 08:57:52 +08:00
2002-10-14 23:32:47 +08:00
if ( fp = = NULL )
1999-10-04 02:54:54 +08:00
{
2003-11-15 21:53:33 +08:00
g_message ( _ ( " Could not open '%s' for reading: %s " ) ,
2004-01-19 11:06:04 +08:00
gimp_filename_to_utf8 ( filename ) , g_strerror ( errno ) ) ;
1999-10-04 02:54:54 +08:00
gimp_quit ( ) ;
2002-10-14 23:32:47 +08:00
}
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
png_init_io ( pp , fp ) ;
1997-11-25 06:05:25 +08:00
2004-01-19 11:06:04 +08:00
progress = g_strdup_printf ( _ ( " Opening '%s'... " ) ,
gimp_filename_to_utf8 ( filename ) ) ;
2002-10-14 23:32:47 +08:00
gimp_progress_init ( progress ) ;
1999-12-30 02:07:43 +08:00
g_free ( progress ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Get the image dimensions and create the image . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
png_read_info ( pp , info ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Latest attempt , this should be my best yet : )
*/
1998-11-09 10:05:24 +08:00
2002-10-14 23:32:47 +08:00
if ( info - > bit_depth = = 16 )
{
png_set_strip_16 ( pp ) ;
}
2000-05-09 09:46:13 +08:00
2002-10-14 23:32:47 +08:00
if ( info - > color_type = = PNG_COLOR_TYPE_GRAY & & info - > bit_depth < 8 )
{
png_set_expand ( pp ) ;
}
2000-04-25 11:57:03 +08:00
2002-10-14 23:32:47 +08:00
if ( info - > color_type = = PNG_COLOR_TYPE_PALETTE & & info - > bit_depth < 8 )
{
png_set_packing ( pp ) ;
}
2000-04-25 11:57:03 +08:00
2002-10-14 23:32:47 +08:00
/*
* Expand G + tRNS to GA , RGB + tRNS to RGBA
*/
2000-05-09 09:46:13 +08:00
if ( info - > color_type ! = PNG_COLOR_TYPE_PALETTE & &
2002-10-14 23:32:47 +08:00
( info - > valid & PNG_INFO_tRNS ) )
{
png_set_expand ( pp ) ;
}
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Turn on interlace handling . . . libpng returns just 1 ( ie single pass )
* if the image is not interlaced
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
num_passes = png_set_interlace_handling ( pp ) ;
1999-09-13 08:57:52 +08:00
2002-10-14 23:32:47 +08:00
/*
* Special handling for INDEXED + tRNS ( transparency palette )
*/
1999-10-03 06:48:44 +08:00
2000-04-25 11:57:03 +08:00
# if PNG_LIBPNG_VER > 99
2002-10-14 23:32:47 +08:00
if ( png_get_valid ( pp , info , PNG_INFO_tRNS ) & &
1999-10-03 06:48:44 +08:00
info - > color_type = = PNG_COLOR_TYPE_PALETTE )
2002-10-14 23:32:47 +08:00
{
png_get_tRNS ( pp , info , & alpha_ptr , & num , NULL ) ;
/* Copy the existing alpha values from the tRNS chunk */
for ( i = 0 ; i < num ; + + i )
alpha [ i ] = alpha_ptr [ i ] ;
/* And set any others to fully opaque (255) */
for ( i = num ; i < 256 ; + + i )
alpha [ i ] = 255 ;
trns = 1 ;
}
else
{
trns = 0 ;
}
2000-04-25 11:57:03 +08:00
# else
2002-10-14 23:32:47 +08:00
trns = 0 ;
2000-04-25 11:57:03 +08:00
# endif /* PNG_LIBPNG_VER > 99 */
1999-10-03 06:48:44 +08:00
2002-10-14 23:32:47 +08:00
/*
* Update the info structures after the transformations take effect
*/
png_read_update_info ( pp , info ) ;
1999-09-13 08:57:52 +08:00
1997-11-25 06:05:25 +08:00
switch ( info - > color_type )
2002-10-14 23:32:47 +08:00
{
2003-11-19 00:46:56 +08:00
case PNG_COLOR_TYPE_RGB : /* RGB */
2002-10-14 23:32:47 +08:00
bpp = 3 ;
image_type = GIMP_RGB ;
layer_type = GIMP_RGB_IMAGE ;
break ;
case PNG_COLOR_TYPE_RGB_ALPHA : /* RGBA */
bpp = 4 ;
image_type = GIMP_RGB ;
layer_type = GIMP_RGBA_IMAGE ;
break ;
2003-11-19 00:46:56 +08:00
case PNG_COLOR_TYPE_GRAY : /* Grayscale */
2002-10-14 23:32:47 +08:00
bpp = 1 ;
image_type = GIMP_GRAY ;
layer_type = GIMP_GRAY_IMAGE ;
break ;
case PNG_COLOR_TYPE_GRAY_ALPHA : /* Grayscale + alpha */
bpp = 2 ;
image_type = GIMP_GRAY ;
layer_type = GIMP_GRAYA_IMAGE ;
break ;
case PNG_COLOR_TYPE_PALETTE : /* Indexed */
bpp = 1 ;
image_type = GIMP_INDEXED ;
layer_type = GIMP_INDEXED_IMAGE ;
break ;
default : /* Aie! Unknown type */
2004-01-19 11:06:04 +08:00
g_message ( _ ( " Unknown color model in PNG file '%s'. " ) ,
gimp_filename_to_utf8 ( filename ) ) ;
2002-10-14 23:32:47 +08:00
return - 1 ;
} ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
image = gimp_image_new ( info - > width , info - > height , image_type ) ;
1997-11-25 06:05:25 +08:00
if ( image = = - 1 )
2002-10-14 23:32:47 +08:00
{
2004-01-19 11:06:04 +08:00
g_message ( " Could not create new image for '%s' " ,
gimp_filename_to_utf8 ( filename ) ) ;
2002-10-14 23:32:47 +08:00
gimp_quit ( ) ;
} ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Create the " background " layer to hold the image . . .
*/
2000-06-30 10:51:35 +08:00
2002-10-14 23:32:47 +08:00
layer = gimp_layer_new ( image , _ ( " Background " ) , info - > width , info - > height ,
layer_type , 100 , GIMP_NORMAL_MODE ) ;
gimp_image_add_layer ( image , layer , 0 ) ;
2000-06-30 10:51:35 +08:00
1999-04-19 08:17:49 +08:00
/*
* Find out everything we can about the image resolution
2000-04-25 11:57:03 +08:00
* This is only practical with the new 1.0 APIs , I ' m afraid
* due to a bug in libpng - 1.0 .6 , see png - implement for details
1999-04-19 08:17:49 +08:00
*/
2000-04-25 11:57:03 +08:00
# if PNG_LIBPNG_VER > 99
2002-10-14 23:32:47 +08:00
if ( png_get_valid ( pp , info , PNG_INFO_gAMA ) )
{
2003-11-03 00:52:26 +08:00
GimpParasite * parasite ;
gchar buf [ G_ASCII_DTOSTR_BUF_SIZE ] ;
gdouble gamma ;
png_get_gAMA ( pp , info , & gamma ) ;
g_ascii_dtostr ( buf , sizeof ( buf ) , gamma ) ;
parasite = gimp_parasite_new ( " gamma " ,
GIMP_PARASITE_PERSISTENT ,
strlen ( buf ) + 1 , buf ) ;
gimp_image_parasite_attach ( image , parasite ) ;
gimp_parasite_free ( parasite ) ;
2002-10-14 23:32:47 +08:00
}
2003-11-19 00:46:56 +08:00
2002-10-14 23:32:47 +08:00
if ( png_get_valid ( pp , info , PNG_INFO_oFFs ) )
{
2003-11-19 00:46:56 +08:00
gint offset_x = png_get_x_offset_pixels ( pp , info ) ;
gint offset_y = png_get_y_offset_pixels ( pp , info ) ;
gimp_layer_set_offsets ( layer , offset_x , offset_y ) ;
if ( ( abs ( offset_x ) > info - > width ) | | ( abs ( offset_y ) > info - > height ) )
{
if ( interactive )
g_message ( _ ( " The PNG file specifies an offset that caused "
" the layer to be positioned outside the image. " ) ) ;
}
2002-10-14 23:32:47 +08:00
}
2003-11-19 00:46:56 +08:00
2002-10-14 23:32:47 +08:00
if ( png_get_valid ( pp , info , PNG_INFO_pHYs ) )
{
2003-10-01 07:19:48 +08:00
png_uint_32 xres ;
png_uint_32 yres ;
gint unit_type ;
if ( png_get_pHYs ( pp , info , & xres , & yres , & unit_type ) )
{
switch ( unit_type )
{
case PNG_RESOLUTION_UNKNOWN :
{
gdouble image_xres , image_yres ;
gimp_image_get_resolution ( image , & image_xres , & image_yres ) ;
if ( xres > yres )
image_xres = image_yres * ( gdouble ) xres / ( gdouble ) yres ;
else
image_yres = image_xres * ( gdouble ) yres / ( gdouble ) xres ;
gimp_image_set_resolution ( image , image_xres , image_yres ) ;
}
break ;
case PNG_RESOLUTION_METER :
gimp_image_set_resolution ( image ,
2003-10-10 22:26:34 +08:00
( gdouble ) xres * 0.0254 ,
( gdouble ) yres * 0.0254 ) ;
2003-10-01 07:19:48 +08:00
break ;
default :
break ;
}
}
2002-10-14 23:32:47 +08:00
}
2000-04-25 11:57:03 +08:00
# endif /* PNG_LIBPNG_VER > 99 */
1999-04-19 08:17:49 +08:00
2002-10-14 23:32:47 +08:00
gimp_image_set_filename ( image , filename ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Load the colormap as necessary . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
empty = 0 ; /* by default assume no full transparent palette entries */
2000-04-14 23:21:14 +08:00
2002-10-14 23:32:47 +08:00
if ( info - > color_type & PNG_COLOR_MASK_PALETTE )
{
2000-04-02 10:46:59 +08:00
2000-04-26 05:57:46 +08:00
# if PNG_LIBPNG_VER > 99
2002-10-14 23:32:47 +08:00
if ( png_get_valid ( pp , info , PNG_INFO_tRNS ) )
{
2004-05-07 04:18:53 +08:00
for ( empty = 0 ; empty < 256 & & alpha [ empty ] = = 0 ; + + empty )
/* Calculates number of fully transparent "empty" entries */ ;
/* keep at least one entry */
empty = MIN ( empty , info - > num_palette - 1 ) ;
2002-10-14 23:32:47 +08:00
gimp_image_set_cmap ( image , ( guchar * ) ( info - > palette + empty ) ,
info - > num_palette - empty ) ;
}
else
{
gimp_image_set_cmap ( image , ( guchar * ) info - > palette ,
info - > num_palette ) ;
}
2000-04-26 05:57:46 +08:00
# else
2002-10-14 23:32:47 +08:00
gimp_image_set_cmap ( image , ( guchar * ) info - > palette ,
info - > num_palette ) ;
2000-04-26 05:57:46 +08:00
# endif /* PNG_LIBPNG_VER > 99 */
2002-10-14 23:32:47 +08:00
}
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Get the drawable and set the pixel region for our load . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
drawable = gimp_drawable_get ( layer ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
gimp_pixel_rgn_init ( & pixel_rgn , drawable , 0 , 0 , drawable - > width ,
drawable - > height , TRUE , FALSE ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Temporary buffer . . .
*/
1997-11-25 06:05:25 +08:00
tile_height = gimp_tile_height ( ) ;
2002-10-14 23:32:47 +08:00
pixel = g_new ( guchar , tile_height * info - > width * bpp ) ;
pixels = g_new ( guchar * , tile_height ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
for ( i = 0 ; i < tile_height ; i + + )
1997-11-25 06:05:25 +08:00
pixels [ i ] = pixel + info - > width * info - > channels * i ;
2002-10-14 23:32:47 +08:00
for ( pass = 0 ; pass < num_passes ; pass + + )
1997-11-25 06:05:25 +08:00
{
2002-10-14 23:32:47 +08:00
/*
* This works if you are only reading one row at a time . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
for ( begin = 0 , end = tile_height ;
begin < info - > height ; begin + = tile_height , end + = tile_height )
{
if ( end > info - > height )
end = info - > height ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
num = end - begin ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
if ( pass ! = 0 ) /* to handle interlaced PiNGs */
gimp_pixel_rgn_get_rect ( & pixel_rgn , pixel , 0 , begin ,
drawable - > width , num ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
png_read_rows ( pp , pixels , NULL , num ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
gimp_pixel_rgn_set_rect ( & pixel_rgn , pixel , 0 , begin ,
drawable - > width , num ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
gimp_progress_update ( ( ( double ) pass +
( double ) end / ( double ) info - > height ) /
( double ) num_passes ) ;
} ;
} ;
1997-11-25 06:05:25 +08:00
2003-07-03 08:30:33 +08:00
png_read_end ( pp , info ) ;
if ( png_get_text ( pp , info , & text , & num_texts ) )
{
gchar * comment = NULL ;
for ( i = 0 ; i < num_texts & & ! comment ; i + + )
{
if ( text - > key = = NULL | | strcmp ( text - > key , " Comment " ) )
continue ;
if ( text - > text_length > 0 ) /* tEXt */
{
2003-11-03 00:52:26 +08:00
comment = g_convert ( text - > text , - 1 ,
" UTF-8 " , " ISO-8859-1 " ,
2003-07-03 08:30:33 +08:00
NULL , NULL , NULL ) ;
}
2003-07-03 08:37:41 +08:00
else if ( g_utf8_validate ( text - > text , - 1 , NULL ) )
2003-07-03 08:30:33 +08:00
{ /* iTXt */
comment = g_strdup ( text - > text ) ;
}
}
if ( comment & & * comment )
{
GimpParasite * parasite ;
parasite = gimp_parasite_new ( " gimp-comment " ,
GIMP_PARASITE_PERSISTENT ,
strlen ( comment ) + 1 , comment ) ;
gimp_image_parasite_attach ( image , parasite ) ;
gimp_parasite_free ( parasite ) ;
}
g_free ( comment ) ;
}
2002-10-14 23:32:47 +08:00
/*
* Done with the file . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
png_read_destroy ( pp , info , NULL ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
g_free ( pixel ) ;
g_free ( pixels ) ;
free ( pp ) ;
free ( info ) ;
1999-10-03 06:48:44 +08:00
2002-10-14 23:32:47 +08:00
fclose ( fp ) ;
1999-10-03 06:48:44 +08:00
2002-10-14 23:32:47 +08:00
if ( trns )
1999-10-03 06:48:44 +08:00
{
2002-10-14 23:32:47 +08:00
gimp_layer_add_alpha ( layer ) ;
drawable = gimp_drawable_get ( layer ) ;
gimp_pixel_rgn_init ( & pixel_rgn , drawable , 0 , 0 , drawable - > width ,
drawable - > height , TRUE , FALSE ) ;
pixel = g_new ( guchar , tile_height * drawable - > width * 2 ) ; /* bpp == 1 */
for ( begin = 0 , end = tile_height ;
begin < drawable - > height ; begin + = tile_height , end + = tile_height )
{
if ( end > drawable - > height )
end = drawable - > height ;
num = end - begin ;
1999-10-03 06:48:44 +08:00
2002-10-14 23:32:47 +08:00
gimp_pixel_rgn_get_rect ( & pixel_rgn , pixel , 0 , begin ,
drawable - > width , num ) ;
1999-10-03 06:48:44 +08:00
2002-10-14 23:32:47 +08:00
for ( i = 0 ; i < tile_height * drawable - > width ; + + i )
{
pixel [ i * 2 + 1 ] = alpha [ pixel [ i * 2 ] ] ;
pixel [ i * 2 ] - = empty ;
}
1999-10-03 06:48:44 +08:00
2002-10-14 23:32:47 +08:00
gimp_pixel_rgn_set_rect ( & pixel_rgn , pixel , 0 , begin ,
drawable - > width , num ) ;
}
g_free ( pixel ) ;
1999-10-03 06:48:44 +08:00
}
2002-10-14 23:32:47 +08:00
/*
* Update the display . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
gimp_drawable_flush ( drawable ) ;
gimp_drawable_detach ( drawable ) ;
1997-11-25 06:05:25 +08:00
return ( image ) ;
}
/*
1999-10-04 02:54:54 +08:00
* ' save_image ( ) ' - Save the specified image to a PNG file .
1997-11-25 06:05:25 +08:00
*/
static gint
2003-07-02 20:03:08 +08:00
save_image ( const gchar * filename ,
gint32 image_ID ,
gint32 drawable_ID ,
gint32 orig_image_ID )
1997-11-25 06:05:25 +08:00
{
2002-10-14 23:32:47 +08:00
int i , k , /* Looping vars */
bpp = 0 , /* Bytes per pixel */
type , /* Type of drawable/layer */
num_passes , /* Number of interlace passes in file */
pass , /* Current pass in file */
tile_height , /* Height of tile in GIMP */
begin , /* Beginning tile row */
end , /* Ending tile row */
num ; /* Number of rows to load */
FILE * fp ; /* File pointer */
GimpDrawable * drawable ; /* Drawable for layer */
GimpPixelRgn pixel_rgn ; /* Pixel region for layer */
png_structp pp ; /* PNG read pointer */
png_infop info ; /* PNG info pointer */
gint num_colors ; /* Number of colors in colormap */
gint offx , offy ; /* Drawable offsets from origin */
guchar * * pixels , /* Pixel rows */
* fixed , /* Fixed-up pixel data */
* pixel ; /* Pixel data */
gchar * progress ; /* Title for progress display... */
gdouble xres , yres ; /* GIMP resolution (dpi) */
png_color_16 background ; /* Background color */
png_time mod_time ; /* Modification time (ie NOW) */
guchar red , green , blue ; /* Used for palette background */
time_t cutime ; /* Time since epoch */
struct tm * gmt ; /* GMT broken down */
guchar remap [ 256 ] ; /* Re-mapping for the palette */
2003-11-03 00:52:26 +08:00
2003-07-03 23:13:29 +08:00
png_textp text = NULL ;
2003-07-03 08:30:33 +08:00
2003-07-03 23:13:29 +08:00
if ( pngvals . comment )
2003-07-03 08:30:33 +08:00
{
2003-07-03 23:13:29 +08:00
GimpParasite * parasite ;
2003-07-03 08:30:33 +08:00
2003-07-03 23:13:29 +08:00
parasite = gimp_image_parasite_find ( orig_image_ID , " gimp-comment " ) ;
2003-11-03 00:52:26 +08:00
if ( parasite )
2003-07-03 23:13:29 +08:00
{
gchar * comment = g_strndup ( gimp_parasite_data ( parasite ) ,
gimp_parasite_data_size ( parasite ) ) ;
2003-07-03 08:30:33 +08:00
2003-07-03 23:13:29 +08:00
gimp_parasite_free ( parasite ) ;
text = g_new0 ( png_text , 1 ) ;
text - > key = " Comment " ;
2003-07-03 08:30:33 +08:00
# ifdef PNG_iTXt_SUPPORTED
2003-07-03 23:13:29 +08:00
text - > compression = PNG_ITXT_COMPRESSION_NONE ;
text - > text = comment ;
text - > itxt_length = strlen ( comment ) ;
2003-07-03 08:30:33 +08:00
# else
2003-07-03 23:13:29 +08:00
text - > compression = PNG_TEXT_COMPRESSION_NONE ;
2003-11-03 00:52:26 +08:00
text - > text = g_convert ( comment , - 1 ,
" ISO-8859-1 " , " UTF-8 " ,
NULL , & text - > text_length ,
2003-07-03 23:13:29 +08:00
NULL ) ;
2003-07-03 08:30:33 +08:00
# endif
2003-07-03 23:13:29 +08:00
if ( ! text - > text )
{
g_free ( text ) ;
text = NULL ;
}
}
2003-07-03 08:30:33 +08:00
}
2002-10-14 23:32:47 +08:00
/*
* PNG 0.89 and newer have a sane , forwards compatible constructor .
* Some SGI IRIX users will not have a new enough version though
*/
1997-11-25 06:05:25 +08:00
# if PNG_LIBPNG_VER > 88
2002-10-14 23:32:47 +08:00
pp = png_create_write_struct ( PNG_LIBPNG_VER_STRING , NULL , NULL , NULL ) ;
info = png_create_info_struct ( pp ) ;
1997-11-25 06:05:25 +08:00
# else
2002-10-14 23:32:47 +08:00
pp = ( png_structp ) calloc ( sizeof ( png_struct ) , 1 ) ;
png_write_init ( pp ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
info = ( png_infop ) calloc ( sizeof ( png_info ) , 1 ) ;
1997-11-25 06:05:25 +08:00
# endif /* PNG_LIBPNG_VER > 88 */
2000-04-25 11:57:03 +08:00
if ( setjmp ( pp - > jmpbuf ) )
2002-10-14 23:32:47 +08:00
{
2004-01-19 11:06:04 +08:00
g_message ( _ ( " Error while saving '%s'. Could not save image. " ) ,
gimp_filename_to_utf8 ( filename ) ) ;
2002-10-14 23:32:47 +08:00
return 0 ;
}
2000-04-25 11:57:03 +08:00
2003-07-03 08:30:33 +08:00
if ( text )
png_set_text ( pp , info , text , 1 ) ;
2002-10-14 23:32:47 +08:00
/*
* Open the file and initialize the PNG write " engine " . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
fp = fopen ( filename , " wb " ) ;
if ( fp = = NULL )
{
2003-11-15 21:53:33 +08:00
g_message ( _ ( " Could not open '%s' for writing: %s " ) ,
2004-01-19 11:06:04 +08:00
gimp_filename_to_utf8 ( filename ) , g_strerror ( errno ) ) ;
2002-10-14 23:32:47 +08:00
return 0 ;
}
2003-11-03 00:52:26 +08:00
2002-10-14 23:32:47 +08:00
png_init_io ( pp , fp ) ;
1997-11-25 06:05:25 +08:00
2004-01-19 11:06:04 +08:00
progress = g_strdup_printf ( _ ( " Saving '%s'... " ) ,
gimp_filename_to_utf8 ( filename ) ) ;
2002-10-14 23:32:47 +08:00
gimp_progress_init ( progress ) ;
1999-12-30 02:07:43 +08:00
g_free ( progress ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Get the drawable for the current image . . .
*/
1997-11-25 06:05:25 +08:00
1999-10-04 02:54:54 +08:00
drawable = gimp_drawable_get ( drawable_ID ) ;
2002-10-14 23:32:47 +08:00
type = gimp_drawable_type ( drawable_ID ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Set the image dimensions , bit depth , interlacing and compression
*/
1997-11-25 06:05:25 +08:00
1999-10-04 02:54:54 +08:00
png_set_compression_level ( pp , pngvals . compression_level ) ;
1997-11-25 06:05:25 +08:00
2003-07-03 23:13:29 +08:00
info - > width = drawable - > width ;
info - > height = drawable - > height ;
info - > bit_depth = 8 ;
1997-11-25 06:05:25 +08:00
info - > interlace_type = pngvals . interlaced ;
2000-04-02 10:46:59 +08:00
2003-11-03 00:52:26 +08:00
/*
2002-10-14 23:32:47 +08:00
* Initialise remap [ ]
*/
for ( i = 0 ; i < 256 ; i + + )
2003-07-03 23:13:29 +08:00
remap [ i ] = i ;
2002-10-14 22:52:53 +08:00
2002-10-14 23:32:47 +08:00
/*
2003-11-03 00:52:26 +08:00
* Set color type and remember bytes per pixel count
2002-10-14 23:32:47 +08:00
*/
2000-04-25 11:57:03 +08:00
1997-11-25 06:05:25 +08:00
switch ( type )
2002-10-14 23:32:47 +08:00
{
case GIMP_RGB_IMAGE :
info - > color_type = PNG_COLOR_TYPE_RGB ;
bpp = 3 ;
break ;
case GIMP_RGBA_IMAGE :
info - > color_type = PNG_COLOR_TYPE_RGB_ALPHA ;
bpp = 4 ;
break ;
case GIMP_GRAY_IMAGE :
info - > color_type = PNG_COLOR_TYPE_GRAY ;
bpp = 1 ;
break ;
case GIMP_GRAYA_IMAGE :
info - > color_type = PNG_COLOR_TYPE_GRAY_ALPHA ;
bpp = 2 ;
break ;
case GIMP_INDEXED_IMAGE :
bpp = 1 ;
info - > color_type = PNG_COLOR_TYPE_PALETTE ;
info - > valid | = PNG_INFO_PLTE ;
info - > palette =
( png_colorp ) gimp_image_get_cmap ( image_ID , & num_colors ) ;
info - > num_palette = num_colors ;
break ;
case GIMP_INDEXEDA_IMAGE :
bpp = 2 ;
info - > color_type = PNG_COLOR_TYPE_PALETTE ;
2003-07-03 23:13:29 +08:00
/* fix up transparency */
respin_cmap ( pp , info , remap , image_ID , drawable ) ;
2002-10-14 23:32:47 +08:00
break ;
1999-07-11 21:26:37 +08:00
default :
2003-11-15 21:53:33 +08:00
g_message ( " Image type can't be saved as PNG " ) ;
2002-10-14 23:32:47 +08:00
return 0 ;
} ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Fix bit depths for ( possibly ) smaller colormap images
*/
if ( info - > valid & PNG_INFO_PLTE )
{
if ( info - > num_palette < = 2 )
info - > bit_depth = 1 ;
else if ( info - > num_palette < = 4 )
info - > bit_depth = 2 ;
else if ( info - > num_palette < = 16 )
info - > bit_depth = 4 ;
/* otherwise the default is fine */
}
2000-04-02 10:46:59 +08:00
2000-04-26 05:57:46 +08:00
/* All this stuff is optional extras, if the user is aiming for smallest
possible file size she can turn them all off */
# if PNG_LIBPNG_VER > 99
2002-10-14 23:32:47 +08:00
if ( pngvals . bkgd )
2001-01-15 08:06:43 +08:00
{
GimpRGB color ;
2001-01-25 09:20:05 +08:00
gimp_palette_get_background ( & color ) ;
2001-01-15 08:06:43 +08:00
gimp_rgb_get_uchar ( & color , & red , & green , & blue ) ;
2002-10-14 23:32:47 +08:00
2001-01-15 08:06:43 +08:00
background . index = 0 ;
2002-10-14 23:32:47 +08:00
background . red = red ;
2001-01-15 08:06:43 +08:00
background . green = green ;
2002-10-14 23:32:47 +08:00
background . blue = blue ;
background . gray = gimp_rgb_intensity_uchar ( & color ) ;
png_set_bKGD ( pp , info , & background ) ;
}
2004-01-05 08:57:43 +08:00
else
{
2004-01-06 17:53:35 +08:00
/* used to save_transp_pixels */
2004-01-05 08:57:43 +08:00
red = green = blue = 0 ;
}
2002-10-14 23:32:47 +08:00
if ( pngvals . gama )
{
2003-11-03 00:52:26 +08:00
GimpParasite * parasite ;
2003-11-17 02:01:56 +08:00
gdouble gamma = 1.0 / DEFAULT_GAMMA ;
2003-11-03 00:52:26 +08:00
parasite = gimp_image_parasite_find ( orig_image_ID , " gamma " ) ;
if ( parasite )
{
gamma = g_ascii_strtod ( parasite - > data , NULL ) ;
gimp_parasite_free ( parasite ) ;
}
png_set_gAMA ( pp , info , gamma ) ;
2002-10-14 23:32:47 +08:00
}
if ( pngvals . offs )
{
gimp_drawable_offsets ( drawable_ID , & offx , & offy ) ;
if ( offx ! = 0 | | offy ! = 0 )
{
png_set_oFFs ( pp , info , offx , offy , PNG_OFFSET_PIXEL ) ;
}
2001-01-15 08:06:43 +08:00
}
2000-04-26 05:57:46 +08:00
2002-10-14 23:32:47 +08:00
if ( pngvals . phys )
{
gimp_image_get_resolution ( orig_image_ID , & xres , & yres ) ;
2003-10-13 02:26:47 +08:00
png_set_pHYs ( pp , info , RINT ( xres / 0.0254 ) , RINT ( yres / 0.0254 ) ,
2002-10-14 23:32:47 +08:00
PNG_RESOLUTION_METER ) ;
}
2000-04-26 05:57:46 +08:00
2002-10-14 23:32:47 +08:00
if ( pngvals . time )
{
cutime = time ( NULL ) ; /* time right NOW */
gmt = gmtime ( & cutime ) ;
mod_time . year = gmt - > tm_year + 1900 ;
mod_time . month = gmt - > tm_mon + 1 ;
mod_time . day = gmt - > tm_mday ;
mod_time . hour = gmt - > tm_hour ;
mod_time . minute = gmt - > tm_min ;
mod_time . second = gmt - > tm_sec ;
png_set_tIME ( pp , info , & mod_time ) ;
2000-04-26 05:57:46 +08:00
}
2000-06-30 10:51:35 +08:00
2000-04-26 05:57:46 +08:00
# endif /* PNG_LIBPNG_VER > 99 */
2000-04-02 10:46:59 +08:00
1999-10-04 02:54:54 +08:00
png_write_info ( pp , info ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Turn on interlace handling . . .
*/
1997-11-25 06:05:25 +08:00
if ( pngvals . interlaced )
2002-10-14 23:32:47 +08:00
num_passes = png_set_interlace_handling ( pp ) ;
1997-11-25 06:05:25 +08:00
else
2000-04-13 12:48:56 +08:00
num_passes = 1 ;
2002-10-14 23:32:47 +08:00
/*
* Convert unpacked pixels to packed if necessary
*/
2000-04-13 12:48:56 +08:00
if ( info - > color_type = = PNG_COLOR_TYPE_PALETTE & & info - > bit_depth < 8 )
2002-10-14 23:32:47 +08:00
png_set_packing ( pp ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Allocate memory for " tile_height " rows and save the image . . .
*/
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
tile_height = gimp_tile_height ( ) ;
pixel = g_new ( guchar , tile_height * drawable - > width * bpp ) ;
pixels = g_new ( guchar * , tile_height ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
for ( i = 0 ; i < tile_height ; i + + )
pixels [ i ] = pixel + drawable - > width * bpp * i ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
gimp_pixel_rgn_init ( & pixel_rgn , drawable , 0 , 0 , drawable - > width ,
drawable - > height , FALSE , FALSE ) ;
2000-04-26 05:57:46 +08:00
2002-10-14 23:32:47 +08:00
for ( pass = 0 ; pass < num_passes ; pass + + )
{
2000-04-26 05:57:46 +08:00
/* This works if you are only writing one row at a time... */
2002-10-14 23:32:47 +08:00
for ( begin = 0 , end = tile_height ;
begin < drawable - > height ; begin + = tile_height , end + = tile_height )
{
if ( end > drawable - > height )
end = drawable - > height ;
num = end - begin ;
gimp_pixel_rgn_get_rect ( & pixel_rgn , pixel , 0 , begin ,
drawable - > width , num ) ;
2004-01-05 08:57:43 +08:00
/*if we are with a RGBA image and have to pre-multiply the alpha channel */
2004-01-06 17:53:35 +08:00
if ( bpp = = 4 & & ! pngvals . save_transp_pixels )
2004-01-05 08:57:43 +08:00
{
for ( i = 0 ; i < num ; + + i )
{
fixed = pixels [ i ] ;
for ( k = 0 ; k < drawable - > width ; + + k )
{
int aux ;
aux = k < < 2 ;
if ( ! fixed [ aux + 3 ] )
{
fixed [ aux ] = red ;
fixed [ aux + 1 ] = green ;
fixed [ aux + 2 ] = blue ;
}
}
}
}
2002-11-06 19:31:35 +08:00
2003-11-03 00:52:26 +08:00
/* If we're dealing with a paletted image with
2002-11-06 19:31:35 +08:00
* transparency set , write out the remapped palette */
2002-10-14 23:32:47 +08:00
if ( info - > valid & PNG_INFO_tRNS )
{
for ( i = 0 ; i < num ; + + i )
{
fixed = pixels [ i ] ;
for ( k = 0 ; k < drawable - > width ; + + k )
{
2003-11-03 00:52:26 +08:00
fixed [ k ] = ( fixed [ k * 2 + 1 ] > 127 ) ?
remap [ fixed [ k * 2 ] ] :
2003-04-12 23:00:20 +08:00
0 ;
2002-10-14 23:32:47 +08:00
}
}
}
2003-11-03 00:52:26 +08:00
/* Otherwise if we have a paletted image and transparency
2002-11-06 19:31:35 +08:00
* couldn ' t be set , we ignore the alpha channel */
2002-10-14 23:32:47 +08:00
else if ( info - > valid & PNG_INFO_PLTE & & bpp = = 2 )
{
for ( i = 0 ; i < num ; + + i )
{
fixed = pixels [ i ] ;
for ( k = 0 ; k < drawable - > width ; + + k )
{
fixed [ k ] = fixed [ k * 2 ] ;
}
}
}
png_write_rows ( pp , pixels , num ) ;
gimp_progress_update ( ( ( double ) pass + ( double ) end /
( double ) info - > height ) /
( double ) num_passes ) ;
} ;
} ;
1997-11-25 06:05:25 +08:00
1999-10-04 02:54:54 +08:00
png_write_end ( pp , info ) ;
png_write_destroy ( pp ) ;
1997-11-25 06:05:25 +08:00
1999-10-04 02:54:54 +08:00
g_free ( pixel ) ;
g_free ( pixels ) ;
1997-11-25 06:05:25 +08:00
2002-10-14 23:32:47 +08:00
/*
* Done with the file . . .
*/
1997-11-25 06:05:25 +08:00
2003-07-03 08:30:33 +08:00
if ( text )
{
g_free ( text - > text ) ;
g_free ( text ) ;
}
1999-10-04 02:54:54 +08:00
free ( pp ) ;
free ( info ) ;
1997-11-25 06:05:25 +08:00
1999-10-04 02:54:54 +08:00
fclose ( fp ) ;
1997-11-25 06:05:25 +08:00
return ( 1 ) ;
}
2002-10-14 23:32:47 +08:00
static void
respin_cmap ( png_structp pp ,
png_infop info ,
guchar * remap ,
gint32 image_ID ,
GimpDrawable * drawable )
2002-09-11 00:46:41 +08:00
{
2000-09-15 08:50:12 +08:00
static const guchar trans [ ] = { 0 } ;
2002-10-14 23:32:47 +08:00
gint colors ;
2000-04-02 10:46:59 +08:00
guchar * before ;
2002-09-11 00:46:41 +08:00
gint transparent ;
gint cols , rows ;
GimpPixelRgn pixel_rgn ;
guchar * pixels ;
2000-04-02 10:46:59 +08:00
2002-10-14 23:32:47 +08:00
before = gimp_image_get_cmap ( image_ID , & colors ) ;
2000-04-26 05:57:46 +08:00
2002-09-11 00:46:41 +08:00
cols = drawable - > width ;
rows = drawable - > height ;
gimp_pixel_rgn_init ( & pixel_rgn , drawable , 0 , 0 ,
2002-10-14 23:32:47 +08:00
drawable - > width , drawable - > height , FALSE , FALSE ) ;
pixels = ( guchar * ) g_malloc ( drawable - > width * drawable - > height * 2 ) ;
2002-09-11 00:46:41 +08:00
gimp_pixel_rgn_get_rect ( & pixel_rgn , pixels , 0 , 0 ,
drawable - > width , drawable - > height ) ;
/* Try to find an entry which isn't actually used in the
image , for a transparency index . */
2002-10-14 23:32:47 +08:00
transparent = find_unused_ia_colour ( pixels ,
drawable - > width * drawable - > height ,
& colors ) ;
2002-09-11 00:46:41 +08:00
2000-04-26 05:57:46 +08:00
# if PNG_LIBPNG_VER > 99
2003-11-03 00:52:26 +08:00
if ( transparent ! = - 1 ) /* we have a winner for a transparent
* index - do like gif2png and swap
2002-10-14 23:32:47 +08:00
* index 0 and index transparent */
2002-09-11 00:46:41 +08:00
{
2002-10-14 22:52:53 +08:00
png_color palette [ 256 ] ;
gint i ;
2002-10-14 23:32:47 +08:00
png_set_tRNS ( pp , info , ( png_bytep ) trans , 1 , NULL ) ;
2001-01-15 08:06:43 +08:00
2003-11-03 00:52:26 +08:00
/* Transform all pixels with a value = transparent to
* 0 and vice versa to compensate for re - ordering in palette
2002-10-14 22:52:53 +08:00
* due to png_set_tRNS ( ) */
remap [ 0 ] = transparent ;
remap [ transparent ] = 0 ;
2002-10-14 23:32:47 +08:00
2003-11-03 00:52:26 +08:00
/* Copy from index 0 to index transparent - 1 to index 1 to
* transparent of after , then from transparent + 1 to colors - 1
2002-09-11 00:46:41 +08:00
* unchanged , and finally from index transparent to index 0. */
2000-04-02 10:46:59 +08:00
2002-10-14 23:32:47 +08:00
for ( i = 0 ; i < colors ; i + + )
2002-09-11 00:46:41 +08:00
{
2002-10-14 22:52:53 +08:00
palette [ i ] . red = before [ 3 * remap [ i ] ] ;
palette [ i ] . green = before [ 3 * remap [ i ] + 1 ] ;
palette [ i ] . blue = before [ 3 * remap [ i ] + 2 ] ;
2002-09-11 00:46:41 +08:00
}
2002-10-14 23:32:47 +08:00
png_set_PLTE ( pp , info , palette , colors ) ;
}
else
2002-09-11 00:46:41 +08:00
{
2003-11-03 00:52:26 +08:00
/* Inform the user that we couldn't losslessly save the
2002-09-11 00:46:41 +08:00
* transparency & just use the full palette */
2003-11-15 21:53:33 +08:00
g_message ( _ ( " Couldn't losslessly save transparency, "
2003-06-13 22:37:00 +08:00
" saving opacity instead. " ) ) ;
2002-09-11 00:46:41 +08:00
png_set_PLTE ( pp , info , ( png_colorp ) before , colors ) ;
}
2000-04-26 05:57:46 +08:00
# else
2002-10-14 23:32:47 +08:00
info - > valid | = PNG_INFO_PLTE ;
info - > palette = ( png_colorp ) before ;
info - > num_palette = colors ;
2000-04-26 05:57:46 +08:00
# endif /* PNG_LIBPNG_VER > 99 */
2002-10-14 23:32:47 +08:00
2002-10-14 22:52:53 +08:00
g_free ( pixels ) ;
2000-04-02 10:46:59 +08:00
}
1997-11-25 06:05:25 +08:00
static gint
2004-01-05 08:57:43 +08:00
save_dialog ( gint32 image_ID ,
gboolean alpha )
1997-11-25 06:05:25 +08:00
{
2004-01-06 17:53:35 +08:00
PngSaveGui pg ;
2003-07-03 23:13:29 +08:00
GtkWidget * dlg ;
GtkWidget * frame ;
GtkWidget * table ;
GtkWidget * toggle ;
GtkObject * scale ;
GimpParasite * parasite ;
1997-11-25 06:05:25 +08:00
2000-01-08 23:23:28 +08:00
dlg = gimp_dialog_new ( _ ( " Save as PNG " ) , " png " ,
2003-11-06 23:27:05 +08:00
NULL , 0 ,
2004-01-21 01:10:16 +08:00
gimp_standard_help_func , " file-png-save-defaults " ,
1999-11-24 04:29:20 +08:00
2004-01-06 17:53:35 +08:00
_ ( " _Load Defaults " ) , RESPONSE_LOAD_DEFAULTS ,
_ ( " _Save Defaults " ) , RESPONSE_SAVE_DEFAULTS ,
GTK_STOCK_CANCEL , GTK_RESPONSE_CANCEL ,
GTK_STOCK_OK , GTK_RESPONSE_OK ,
2003-11-06 23:27:05 +08:00
NULL ) ;
1997-11-25 06:05:25 +08:00
2004-01-06 17:53:35 +08:00
g_signal_connect ( dlg , " response " ,
G_CALLBACK ( save_dialog_response ) ,
& pg ) ;
g_signal_connect ( dlg , " destroy " ,
G_CALLBACK ( gtk_main_quit ) ,
NULL ) ;
2003-07-03 23:13:29 +08:00
frame = gtk_frame_new ( _ ( " Settings " ) ) ;
2000-08-28 08:42:32 +08:00
gtk_container_set_border_width ( GTK_CONTAINER ( frame ) , 6 ) ;
2000-01-08 23:23:28 +08:00
gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG ( dlg ) - > vbox ) , frame , TRUE , TRUE , 0 ) ;
2000-01-14 20:41:00 +08:00
gtk_widget_show ( frame ) ;
1997-11-25 06:05:25 +08:00
2004-01-05 08:57:43 +08:00
table = gtk_table_new ( 9 , 3 , FALSE ) ;
2000-01-08 23:23:28 +08:00
gtk_table_set_col_spacings ( GTK_TABLE ( table ) , 4 ) ;
gtk_table_set_row_spacings ( GTK_TABLE ( table ) , 2 ) ;
2003-07-03 23:13:29 +08:00
gtk_container_set_border_width ( GTK_CONTAINER ( table ) , 6 ) ;
2000-01-14 20:41:00 +08:00
gtk_container_add ( GTK_CONTAINER ( frame ) , table ) ;
gtk_widget_show ( table ) ;
2004-01-06 17:53:35 +08:00
pg . interlaced = toggle =
gtk_check_button_new_with_mnemonic ( _ ( " _Interlacing (Adam7) " ) ) ;
2003-07-03 23:13:29 +08:00
gtk_table_attach ( GTK_TABLE ( table ) , toggle , 0 , 3 , 0 , 1 , GTK_FILL , 0 , 0 , 0 ) ;
2002-10-14 23:32:47 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) ,
pngvals . interlaced ) ;
2000-01-14 20:41:00 +08:00
gtk_widget_show ( toggle ) ;
2003-07-03 08:30:33 +08:00
2003-01-07 14:16:02 +08:00
g_signal_connect ( toggle , " toggled " ,
2001-12-31 08:21:10 +08:00
G_CALLBACK ( gimp_toggle_button_update ) ,
& pngvals . interlaced ) ;
2000-01-14 20:41:00 +08:00
2004-01-06 17:53:35 +08:00
pg . bkgd = toggle =
gtk_check_button_new_with_mnemonic ( _ ( " Save _Background Color " ) ) ;
2003-07-03 23:13:29 +08:00
gtk_table_attach ( GTK_TABLE ( table ) , toggle , 0 , 3 , 1 , 2 , GTK_FILL , 0 , 0 , 0 ) ;
2000-06-30 10:51:35 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) , pngvals . bkgd ) ;
gtk_widget_show ( toggle ) ;
2003-01-07 14:16:02 +08:00
g_signal_connect ( toggle , " toggled " ,
2002-10-14 23:32:47 +08:00
G_CALLBACK ( gimp_toggle_button_update ) , & pngvals . bkgd ) ;
2001-12-31 08:21:10 +08:00
2004-01-06 17:53:35 +08:00
pg . gama = toggle = gtk_check_button_new_with_mnemonic ( _ ( " Save _Gamma " ) ) ;
2003-07-03 23:13:29 +08:00
gtk_table_attach ( GTK_TABLE ( table ) , toggle , 0 , 3 , 2 , 3 , GTK_FILL , 0 , 0 , 0 ) ;
2000-06-30 10:51:35 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) , pngvals . gama ) ;
gtk_widget_show ( toggle ) ;
2003-01-07 14:16:02 +08:00
g_signal_connect ( toggle , " toggled " ,
2002-10-14 23:32:47 +08:00
G_CALLBACK ( gimp_toggle_button_update ) , & pngvals . gama ) ;
2001-12-31 08:21:10 +08:00
2004-01-06 17:53:35 +08:00
pg . offs = toggle =
gtk_check_button_new_with_mnemonic ( _ ( " Save Layer O_ffset " ) ) ;
2003-07-03 23:13:29 +08:00
gtk_table_attach ( GTK_TABLE ( table ) , toggle , 0 , 3 , 3 , 4 , GTK_FILL , 0 , 0 , 0 ) ;
2000-06-30 10:51:35 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) , pngvals . offs ) ;
gtk_widget_show ( toggle ) ;
2003-01-07 14:16:02 +08:00
g_signal_connect ( toggle , " toggled " ,
2004-01-06 17:53:35 +08:00
G_CALLBACK ( gimp_toggle_button_update ) ,
& pngvals . offs ) ;
2001-12-31 08:21:10 +08:00
2004-01-06 17:53:35 +08:00
pg . phys = toggle = gtk_check_button_new_with_mnemonic ( _ ( " Save _Resolution " ) ) ;
2003-07-03 23:13:29 +08:00
gtk_table_attach ( GTK_TABLE ( table ) , toggle , 0 , 3 , 4 , 5 , GTK_FILL , 0 , 0 , 0 ) ;
2000-06-30 10:51:35 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) , pngvals . phys ) ;
gtk_widget_show ( toggle ) ;
2003-01-07 14:16:02 +08:00
g_signal_connect ( toggle , " toggled " ,
2002-10-14 23:32:47 +08:00
G_CALLBACK ( gimp_toggle_button_update ) , & pngvals . phys ) ;
2001-12-31 08:21:10 +08:00
2004-01-06 17:53:35 +08:00
pg . time = toggle =
gtk_check_button_new_with_mnemonic ( _ ( " Save Creation _Time " ) ) ;
2003-07-03 23:13:29 +08:00
gtk_table_attach ( GTK_TABLE ( table ) , toggle , 0 , 3 , 5 , 6 , GTK_FILL , 0 , 0 , 0 ) ;
2000-06-30 10:51:35 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) , pngvals . time ) ;
2000-01-14 20:41:00 +08:00
gtk_widget_show ( toggle ) ;
1999-11-09 13:16:55 +08:00
2003-01-07 14:16:02 +08:00
g_signal_connect ( toggle , " toggled " ,
2002-10-14 23:32:47 +08:00
G_CALLBACK ( gimp_toggle_button_update ) , & pngvals . time ) ;
2001-12-31 08:21:10 +08:00
2004-01-06 17:53:35 +08:00
pg . comment = toggle = gtk_check_button_new_with_mnemonic ( _ ( " Save Comme_nt " ) ) ;
2003-07-03 23:13:29 +08:00
gtk_table_attach ( GTK_TABLE ( table ) , toggle , 0 , 3 , 6 , 7 , GTK_FILL , 0 , 0 , 0 ) ;
2004-01-06 17:53:35 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) , pngvals . comment ) ;
2003-07-03 23:13:29 +08:00
gtk_widget_show ( toggle ) ;
parasite = gimp_image_parasite_find ( image_ID , " gimp-comment " ) ;
2003-09-24 05:51:08 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) ,
pngvals . comment & & parasite ! = NULL ) ;
2003-07-03 23:13:29 +08:00
gtk_widget_set_sensitive ( toggle , parasite ! = NULL ) ;
gimp_parasite_free ( parasite ) ;
2003-09-24 05:51:08 +08:00
2004-01-06 17:53:35 +08:00
g_signal_connect ( toggle , " toggled " ,
G_CALLBACK ( gimp_toggle_button_update ) , & pngvals . comment ) ;
pg . save_transp_pixels = toggle =
gtk_check_button_new_with_mnemonic ( _ ( " Save Color _Values From Transparent Pixels " ) ) ;
gtk_table_attach ( GTK_TABLE ( table ) , toggle , 0 , 3 , 7 , 8 , GTK_FILL , 0 , 0 , 0 ) ;
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) ,
alpha & & pngvals . save_transp_pixels ) ;
gtk_widget_set_sensitive ( toggle , alpha ) ;
gtk_widget_show ( toggle ) ;
2003-07-03 23:13:29 +08:00
g_signal_connect ( toggle , " toggled " ,
G_CALLBACK ( gimp_toggle_button_update ) ,
2004-01-06 17:53:35 +08:00
& pngvals . save_transp_pixels ) ;
2003-07-03 23:13:29 +08:00
2004-01-06 17:53:35 +08:00
pg . compression_level = scale =
gimp_scale_entry_new ( GTK_TABLE ( table ) , 0 , 8 ,
_ ( " Co_mpression Level: " ) ,
SCALE_WIDTH , 0 ,
pngvals . compression_level ,
0.0 , 9.0 , 1.0 , 1.0 , 0 , TRUE , 0.0 , 0.0 ,
_ ( " Choose a high compression level "
" for small file size " ) , NULL ) ;
2003-07-03 23:13:29 +08:00
g_signal_connect ( scale , " value_changed " ,
2001-12-31 08:21:10 +08:00
G_CALLBACK ( gimp_int_adjustment_update ) ,
& pngvals . compression_level ) ;
2000-01-14 20:41:00 +08:00
gtk_widget_show ( dlg ) ;
2004-01-06 17:53:35 +08:00
pg . run = FALSE ;
gtk_main ( ) ;
return pg . run ;
}
static void
save_dialog_response ( GtkWidget * widget ,
gint response_id ,
gpointer data )
{
PngSaveGui * pg = data ;
switch ( response_id )
{
case RESPONSE_LOAD_DEFAULTS :
load_gui_defaults ( pg ) ;
break ;
case RESPONSE_SAVE_DEFAULTS :
save_defaults ( ) ;
break ;
case GTK_RESPONSE_OK :
pg - > run = TRUE ;
default :
gtk_widget_destroy ( widget ) ;
break ;
}
}
static gboolean
load_defaults ( void )
{
2004-01-06 20:58:31 +08:00
GimpParasite * parasite ;
gchar * def_str ;
PngSaveVals tmpvals ;
gint num_fields ;
2004-01-06 17:53:35 +08:00
2004-01-06 20:58:31 +08:00
parasite = gimp_parasite_find ( PNG_DEFAULTS_PARASITE ) ;
2004-01-06 17:53:35 +08:00
2004-01-06 20:58:31 +08:00
if ( ! parasite )
2004-01-06 17:53:35 +08:00
return FALSE ;
2004-01-06 20:58:31 +08:00
def_str = g_strndup ( gimp_parasite_data ( parasite ) ,
gimp_parasite_data_size ( parasite ) ) ;
gimp_parasite_free ( parasite ) ;
2004-01-06 17:53:35 +08:00
num_fields = sscanf ( def_str , " %d %d %d %d %d %d %d %d %d " ,
& tmpvals . interlaced ,
& tmpvals . bkgd ,
& tmpvals . gama ,
& tmpvals . offs ,
& tmpvals . phys ,
& tmpvals . time ,
& tmpvals . comment ,
& tmpvals . save_transp_pixels ,
& tmpvals . compression_level ) ;
2004-01-06 20:58:31 +08:00
2004-01-06 17:53:35 +08:00
g_free ( def_str ) ;
if ( num_fields = = 9 )
{
memcpy ( & pngvals , & tmpvals , sizeof ( tmpvals ) ) ;
return TRUE ;
}
else
2004-01-06 20:58:31 +08:00
{
return FALSE ;
}
2004-01-06 17:53:35 +08:00
}
static void
save_defaults ( void )
{
2004-01-06 20:58:31 +08:00
GimpParasite * parasite ;
gchar * def_str ;
2004-01-06 17:53:35 +08:00
def_str = g_strdup_printf ( " %d %d %d %d %d %d %d %d %d " ,
pngvals . interlaced ,
pngvals . bkgd ,
pngvals . gama ,
pngvals . offs ,
pngvals . phys ,
pngvals . time ,
pngvals . comment ,
pngvals . save_transp_pixels ,
pngvals . compression_level ) ;
2004-01-06 20:58:31 +08:00
parasite = gimp_parasite_new ( PNG_DEFAULTS_PARASITE ,
GIMP_PARASITE_PERSISTENT ,
strlen ( def_str ) , def_str ) ;
gimp_parasite_attach ( parasite ) ;
gimp_parasite_free ( parasite ) ;
2004-01-06 17:53:35 +08:00
g_free ( def_str ) ;
}
static void
load_gui_defaults ( PngSaveGui * pg )
{
if ( ! load_defaults ( ) )
{
g_message ( _ ( " Could not load PNG defaults " ) ) ;
return ;
}
# define SET_ACTIVE(field) \
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( pg - > field ) , pngvals . field )
SET_ACTIVE ( interlaced ) ;
SET_ACTIVE ( bkgd ) ;
SET_ACTIVE ( gama ) ;
SET_ACTIVE ( offs ) ;
SET_ACTIVE ( phys ) ;
SET_ACTIVE ( time ) ;
SET_ACTIVE ( comment ) ;
SET_ACTIVE ( save_transp_pixels ) ;
2003-11-06 23:27:05 +08:00
2004-01-06 17:53:35 +08:00
# undef SET_ACTIVE
2000-01-14 20:41:00 +08:00
2004-01-06 17:53:35 +08:00
gtk_adjustment_set_value ( GTK_ADJUSTMENT ( pg - > compression_level ) ,
pngvals . compression_level ) ;
1997-11-25 06:05:25 +08:00
}