You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libksquirrel/kernel/kls_xcf/xcf2pnm/xcf2pnm.c

274 lines
7.5 KiB

/* 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 ;
}