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) ;
    }
}
Exemple #2
0
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 ;
}