summaryrefslogtreecommitdiffstats
path: root/xcf2pnm.c
diff options
context:
space:
mode:
Diffstat (limited to 'xcf2pnm.c')
-rw-r--r--xcf2pnm.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/xcf2pnm.c b/xcf2pnm.c
new file mode 100644
index 0000000..f13c306
--- /dev/null
+++ b/xcf2pnm.c
@@ -0,0 +1,271 @@
+/* Convert xcf files to ppm
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "xcftools.h"
+#include "flatten.h"
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <ctype.h>
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
+#ifndef HAVE_GETOPT_LONG
+#define getopt_long(argc,argv,optstring,l1,l2) getopt(argc,argv,optstring)
+#endif
+
+#include "xcf2pnm.oi"
+
+static void
+usage(FILE *where)
+{
+ fprintf(where,_("Usage: %s [options] filename.xcf[.gz] [layers]\n"),
+ progname) ;
+ fprintf(where,_("Options:\n"));
+ opt_usage(where);
+ if( where == stderr ) {
+ exit(1);
+ }
+}
+
+static int suppress_byline ;
+static struct FlattenSpec flatspec ;
+static FILE *outfile = NULL ;
+static FILE *transfile = NULL ;
+
+static void
+start_writing(FILE **f,int version)
+{
+ const char *format[] = {"(format zero)",
+ "PBM-ascii",
+ "PGM-ascii",
+ "PPM-ascii",
+ "PBM",
+ "PGM",
+ "PPM" };
+
+ if( verboseFlag )
+ fprintf(stderr,f == &outfile ? _("Writing converted image as %s\n")
+ : _("Writing transparency map as %s\n"),
+ format[version]);
+
+ *f = openout( f == &outfile ? flatspec.output_filename
+ : flatspec.transmap_filename );
+ fprintf(*f,"P%d",version);
+ if( suppress_byline )
+ ;
+ else if( f == &outfile )
+ fprintf(*f,_(" # Converted by xcf2pnm %s"),PACKAGE_VERSION);
+ else
+ fprintf(*f,_(" # Transparency map by xcf2pnm %s"),PACKAGE_VERSION);
+ fprintf(*f,"\n%d %d\n%s",
+ flatspec.dim.width,
+ flatspec.dim.height,
+ version == 4 ? "" : "255\n");
+}
+
+int
+put_pbm_row(FILE *file,unsigned num,rgba *pixels,rgba mask) {
+ unsigned out ;
+ unsigned i ;
+ int bitsleft = 8 ;
+ out = 0 ;
+ for( i=0; i<num; i++ ) {
+ out <<= 1 ;
+ if( (pixels[i] & mask) == 0 )
+ out++ ; /* 1 is black */
+ else if( (pixels[i] & mask) == mask )
+ ; /* 0 is white */
+ else
+ return 0 ;
+ if( --bitsleft == 0 ) {
+ putc( out, file );
+ out = 0 ;
+ bitsleft = 8 ;
+ }
+ }
+ if( bitsleft < 8 )
+ putc( out << bitsleft, file );
+ return 1 ;
+}
+
+static void
+callback_common(unsigned num,rgba *pixels)
+{
+ if( flatspec.transmap_filename ) {
+ if( flatspec.partial_transparency_mode == ALLOW_PARTIAL_TRANSPARENCY ) {
+ unsigned i ;
+ if( transfile == NULL ) start_writing(&transfile,5);
+ for( i=0; i < num; i++ )
+ putc( ALPHA(pixels[i]), transfile );
+ } else {
+ if( transfile == NULL ) {
+ start_writing(&transfile,4);
+ }
+ /* Partial transparency should have been caught in the flattener,
+ * so just extract a single byte.
+ */
+ put_pbm_row(transfile,num,pixels,(rgba)1 << ALPHA_SHIFT);
+ }
+ } else if( !FULLALPHA(flatspec.default_pixel) ) {
+ unsigned i ;
+ for( i=0; i < num; i++ )
+ if( !FULLALPHA(pixels[i]) )
+ FatalGeneric(100,_("Transparency found, but -a option not given"));
+ }
+ xcffree(pixels) ;
+}
+
+static void
+ppm_callback(unsigned num,rgba *pixels)
+{
+ unsigned i ;
+ if( outfile == NULL ) start_writing(&outfile,6);
+ for( i=0; i < num; i++ ) {
+ putc( (pixels[i] >> RED_SHIFT) & 0xFF , outfile );
+ putc( (pixels[i] >> GREEN_SHIFT) & 0xFF , outfile );
+ putc( (pixels[i] >> BLUE_SHIFT) & 0xFF , outfile );
+ }
+ callback_common(num,pixels);
+}
+
+static void
+pgm_callback(unsigned num,rgba *pixels)
+{
+ unsigned i ;
+ if( outfile == NULL ) start_writing(&outfile,5);
+ for( i=0; i < num; i++ ) {
+ int gray = degrayPixel(pixels[i]) ;
+ if( gray == -1 )
+ FatalGeneric(103,
+ _("Grayscale output selected, but colored pixel(s) found %d=%x"),i,pixels[i] /*XXX*/);
+ putc( gray, outfile );
+ }
+ callback_common(num,pixels);
+}
+
+static void
+pbm_callback(unsigned num,rgba *pixels)
+{
+ if( outfile == NULL ) start_writing(&outfile,4);
+ if( !put_pbm_row(outfile,num,pixels,
+ ((rgba)255 << RED_SHIFT) +
+ ((rgba)255 << GREEN_SHIFT) +
+ ((rgba)255 << BLUE_SHIFT)) )
+ FatalGeneric(103,_("Monochrome output selected, but not all pixels "
+ "are black or white"));
+ callback_common(num,pixels);
+}
+
+static enum out_color_mode
+guess_color_mode(const char *string)
+{
+ if( strlen(string) >= 3 ) {
+ string += strlen(string)-3 ;
+ if( strcmp(string,"ppm")==0 ) return COLOR_RGB ;
+ if( strcmp(string,"pgm")==0 ) return COLOR_GRAY ;
+ if( strcmp(string,"pbm")==0 ) return COLOR_MONO ;
+ }
+ return COLOR_BY_FILENAME ;
+}
+
+static lineCallback
+selectCallback(void)
+{
+ if( flatspec.transmap_filename && FULLALPHA(flatspec.default_pixel) )
+ FatalGeneric(101,_("The -a option was given, "
+ "but the image has no transparency"));
+
+ switch( flatspec.out_color_mode ) {
+ default:
+ case COLOR_RGB: return &ppm_callback ;
+ case COLOR_GRAY: return &pgm_callback ;
+ case COLOR_MONO: return &pbm_callback ;
+ }
+}
+
+int
+main(int argc,char **argv)
+{
+ int option ;
+ const char *unzipper = NULL ;
+ const char *infile = NULL ;
+
+ setlocale(LC_ALL,"");
+ progname = argv[0] ;
+
+ if( argc <= 1 ) gpl_blurb() ;
+
+ init_flatspec(&flatspec) ;
+ flatspec.out_color_mode = COLOR_BY_FILENAME ;
+ while( (option=getopt_long(argc,argv,"-@"OPTSTRING,longopts,NULL)) >= 0 )
+ switch(option) {
+ #define OPTION(char,long,desc,man) case char:
+ #include "options.i"
+ case 1:
+ if( infile )
+ add_layer_request(&flatspec,optarg);
+ else
+ infile = optarg ;
+ break ;
+ case '?':
+ usage(stderr);
+ case '@':
+ /* Non-documented option for build-time test */
+ suppress_byline = 1 ;
+ break ;
+ default:
+ FatalUnexpected("Getopt(_long) unexpectedly returned '%c'",option);
+ }
+ if( infile == NULL ) {
+ usage(stderr);
+ }
+
+ if( flatspec.out_color_mode == COLOR_BY_FILENAME &&
+ strlen(flatspec.output_filename) > 4 &&
+ flatspec.output_filename[strlen(flatspec.output_filename)-4] == '.' )
+ flatspec.out_color_mode = guess_color_mode(flatspec.output_filename);
+
+ /* If the output filename was not enough cue, see if we're running
+ * through a symlink/hardlink that gives the required output format
+ */
+ if( flatspec.out_color_mode == COLOR_BY_FILENAME &&
+ strlen(progname) > 3 )
+ flatspec.out_color_mode = guess_color_mode(progname);
+
+ if( flatspec.out_color_mode == COLOR_BY_FILENAME )
+ flatspec.out_color_mode = COLOR_BY_CONTENTS ;
+
+ read_or_mmap_xcf(infile,unzipper);
+ getBasicXcfInfo() ;
+ initColormap();
+
+ complete_flatspec(&flatspec,NULL);
+ if( flatspec.process_in_memory ) {
+ rgba **allPixels = flattenAll(&flatspec);
+ analyse_colormode(&flatspec,allPixels,NULL);
+ shipoutWithCallback(&flatspec,allPixels,selectCallback());
+ } else {
+ flattenIncrementally(&flatspec,selectCallback());
+ }
+ closeout(outfile,flatspec.output_filename) ;
+ closeout(transfile,flatspec.transmap_filename) ;
+ return 0 ;
+}