void complete_flatspec(struct FlattenSpec *spec, guesser guess_callback) { unsigned i ; int anyPartial ; /* Find the layers to convert. */ if( spec->numLayers == 0 ) { spec->layers = XCF.layers ; spec->numLayers = XCF.numLayers ; } else { for( i=0; i<spec->numLayers; i++ ) { GimpLayerModeEffects mode ; int opacity, hasMask ; unsigned j ; for( j=0; ; j++ ) { if( j == XCF.numLayers ) FatalGeneric(22,_("The image has no layer called '%s'"), spec->layers[i].name); if( strcmp(spec->layers[i].name,XCF.layers[j].name) == 0 ) break ; } mode = spec->layers[i].mode == (GimpLayerModeEffects)-1 ? XCF.layers[j].mode : spec->layers[i].mode ; opacity = spec->layers[i].opacity == 9999 ? XCF.layers[j].opacity : spec->layers[i].opacity ; hasMask = spec->layers[i].hasMask == -1 ? XCF.layers[j].hasMask : spec->layers[i].hasMask ; if( hasMask && !XCF.layers[j].hasMask && XCF.layers[j].mask.hierarchy == 0 ) FatalGeneric(22,_("Layer '%s' has no layer mask to enable"), spec->layers[i].name); spec->layers[i] = XCF.layers[j] ; spec->layers[i].mode = mode ; spec->layers[i].opacity = opacity ; spec->layers[i].hasMask = hasMask ; spec->layers[i].isVisible = 1 ; } } /* Force the mode of the lowest visible layer to be Normal or Dissolve. * That may not be logical, but the Gimp does it */ for( i=0; i < spec->numLayers; i++ ) { if( spec->layers[i].isVisible ) { if( spec->layers[i].mode != GIMP_DISSOLVE_MODE ) spec->layers[i].mode = GIMP_NORMAL_MODE ; break ; } } /* Mimic the Gimp's behavior on indexed layers */ if( XCF.type == GIMP_INDEXED && spec->gimpish_indexed ) { for( i=0; i<spec->numLayers; i++ ) if( spec->layers[i].mode != GIMP_DISSOLVE_MODE ) spec->layers[i].mode = GIMP_NORMAL_NOPARTIAL_MODE ; } else spec->gimpish_indexed = 0 ; /* compute dimensions of the window */ if( spec->window_mode == AUTOCROP ) { int first = 1 ; for( i=0; i<spec->numLayers; i++ ) if( spec->layers[i].isVisible ) { computeDimensions(&spec->layers[i].dim) ; if( first ) { spec->dim = spec->layers[i].dim ; first = 0 ; } else { if( spec->dim.c.l < spec->layers[i].dim.c.l ) spec->dim.c.l = spec->layers[i].dim.c.l ; if( spec->dim.c.r > spec->layers[i].dim.c.r ) spec->dim.c.r = spec->layers[i].dim.c.r ; if( spec->dim.c.t < spec->layers[i].dim.c.t ) spec->dim.c.t = spec->layers[i].dim.c.t ; if( spec->dim.c.b > spec->layers[i].dim.c.b ) spec->dim.c.b = spec->layers[i].dim.c.b ; } } if( first ) { spec->window_mode = USE_CANVAS ; } else { spec->dim.width = spec->dim.c.r - spec->dim.c.l ; spec->dim.height = spec->dim.c.b - spec->dim.c.t ; } } if( spec->window_mode != AUTOCROP ) { if( (spec->window_mode & MANUAL_OFFSET) == 0 ) spec->dim.c.t = spec->dim.c.l = 0 ; if( (spec->window_mode & MANUAL_CROP) == 0 ) { spec->dim.height = XCF.height ; spec->dim.width = XCF.width ; } } computeDimensions(&spec->dim); /* We can't handle negative coordinates properly, so abort rather than * crash chaotically. See CVE-2009-217; Debian bug #533361. */ if( spec->dim.c.t < 0 || spec->dim.c.l < 0 ) { FatalUnsupportedXCF("This version cannot extract pixels above or to the " "left of the canvas"); } /* Turn off layers that we don't hit at all */ for( i=0; i<spec->numLayers; i++ ) if( spec->layers[i].isVisible && disjointRects(spec->dim.c,spec->layers[i].dim.c) ) spec->layers[i].isVisible = 0 ; /* See if there is a completely covering layer somewhere in the stack */ /* Also check if partial transparency is possible */ anyPartial = 0 ; for( i=spec->numLayers; i-- ; ) { if( !spec->layers[i].isVisible ) continue ; if( typeHasTransparency(spec->layers[i].type) ) { if( spec->layers[i].mode == GIMP_NORMAL_MODE ) anyPartial = 1; } else if( isSubrect(spec->dim.c,spec->layers[i].dim.c) && (spec->layers[i].mode == GIMP_NORMAL_MODE || spec->layers[i].mode == GIMP_NORMAL_NOPARTIAL_MODE || spec->layers[i].mode == GIMP_DISSOLVE_MODE) ) { /* This layer fills out the entire image. * Turn off anly lower layers, and note that we cannot have * transparency at all. */ while(i) spec->layers[--i].isVisible = 0 ; if( spec->default_pixel != FORCE_ALPHA_CHANNEL ) spec->default_pixel = NEWALPHA(colormap[0],255); anyPartial = 0 ; break ; } } if( spec->partial_transparency_mode == ALLOW_PARTIAL_TRANSPARENCY && (!anyPartial || ALPHA(spec->default_pixel) >= 128) ) spec->partial_transparency_mode = PARTIAL_TRANSPARENCY_IMPOSSIBLE ; /* Initialize layers and print overview if we're verbose */ for( i=spec->numLayers; i--; ) if( spec->layers[i].isVisible ) { initLayer(&spec->layers[i]) ; if( verboseFlag ) { fprintf(stderr,"%dx%d%+d%+d %s %s", spec->layers[i].dim.width, spec->layers[i].dim.height, spec->layers[i].dim.c.l - spec->dim.c.l, spec->layers[i].dim.c.t - spec->dim.c.t, _(showGimpImageType(spec->layers[i].type)), _(showGimpLayerModeEffects(spec->layers[i].mode))); if( spec->layers[i].opacity < 255 ) fprintf(stderr,"/%02d%%",spec->layers[i].opacity * 100 / 255); if( XCF.layers[i].hasMask ) fprintf(stderr,_("/mask")); fprintf(stderr," %s\n",spec->layers[i].name); } } /* Resolve color mode unless we wait until we have the entire image */ if( spec->out_color_mode == COLOR_BY_CONTENTS && !spec->process_in_memory ) { if( guess_callback ) spec->out_color_mode = guess_callback(spec,NULL); if( spec->out_color_mode == COLOR_BY_CONTENTS ) spec->out_color_mode = color_by_layers(spec) ; } }
int main(int argc,char **argv) { int i ; int option ; const char *unzipper = NULL ; const char *infile = NULL ; const char *pathSeparator = "|"; setlocale(LC_ALL,""); progname = argv[0] ; nls_init(); if( argc <= 1 ) gpl_blurb() ; 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 ) { FatalGeneric (20,_("Only one XCF file per command line, please")); } else { infile = optarg ; break ; } case '?': usage(stderr); default: FatalUnexpected("Getopt(_long) unexpectedly returned '%c'",option); } if( infile == NULL ) { usage(stderr); } read_or_mmap_xcf(infile,unzipper); getBasicXcfInfo() ; printf(_("Version %d, %dx%d %s, %d layers, compressed %s\n"), XCF.version,XCF.width,XCF.height, _(showGimpImageBaseType(XCF.type)), XCF.numLayers, _(showXcfCompressionType(XCF.compression))); for( i = XCF.numLayers ; i-- ; ) { printf("%c %dx%d%+d%+d %s %s", XCF.layers[i].isVisible ? '+' : '-', XCF.layers[i].dim.width, XCF.layers[i].dim.height, XCF.layers[i].dim.c.l, XCF.layers[i].dim.c.t, _(showGimpImageType(XCF.layers[i].type)), _(showGimpLayerModeEffects(XCF.layers[i].mode))); if( XCF.layers[i].opacity < 255 ) printf("/%02d%%",XCF.layers[i].opacity * 100 / 255); if( XCF.layers[i].hasMask ) printf(_("/mask")); if( XCF.layers[i].isGroup ) printf(_("/group")); printf( " " ); if ( XCF.version > 2 ) { printLayerPath( i, pathSeparator ); printf( "%s", pathSeparator ); } printf("%s\n",XCF.layers[i].name); } return 0 ; }