|
|
|
/* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#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 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);
|
|
|
|
|
|
|
|
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( ALPHA(flatspec.default_pixel) < 128 ) {
|
|
|
|
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"));
|
|
|
|
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 && ALPHA(flatspec.default_pixel) >= 128 )
|
|
|
|
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] ;
|
|
|
|
nls_init();
|
|
|
|
|
|
|
|
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 '?':
|
|
|
|
exit(1);
|
|
|
|
case '@':
|
|
|
|
/* Non-documented option for build-time test */
|
|
|
|
suppress_byline = 1 ;
|
|
|
|
break ;
|
|
|
|
case '#':
|
|
|
|
/* Non-documented option for xcfview */
|
|
|
|
flatspec.default_pixel = CHECKERED_BACKGROUND ;
|
|
|
|
break ;
|
|
|
|
default:
|
|
|
|
FatalUnexpected("Getopt(_long) unexpectedly returned '%c'",option);
|
|
|
|
}
|
|
|
|
if( infile == NULL ) {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ;
|
|
|
|
}
|