Esempio n. 1
0
static void
init_output(void)
{
  int bit_depth ;
  int color_type ;
  int invert_mono = 0 ;
  png_colorp pngpalette = NULL ;
  png_bytep ptrans = NULL ;
  
  outfile = openout(flatspec.output_filename);
  libpng = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                   png_voidp_NULL,
                                   my_error_callback,
                                   png_error_ptr_NULL);
  if( !libpng )
    FatalUnexpected(_("Couldn't initialize libpng library"));
  
  libpng2 = png_create_info_struct(libpng);
  if( !libpng2 )
    FatalUnexpected("Couldn't create PNG info structure");

  png_init_io(libpng,outfile);
  
  bit_depth = 8;
  switch( flatspec.out_color_mode ) {
  case COLOR_GRAY:
    if( flatspec.default_pixel == PERHAPS_ALPHA_CHANNEL ||
        flatspec.default_pixel == FORCE_ALPHA_CHANNEL )
      color_type = PNG_COLOR_TYPE_GRAY_ALPHA ;
    else
      color_type = PNG_COLOR_TYPE_GRAY ;
    break ;
  case COLOR_RGB:
    if( flatspec.default_pixel == PERHAPS_ALPHA_CHANNEL ||
        flatspec.default_pixel == FORCE_ALPHA_CHANNEL )
      color_type = PNG_COLOR_TYPE_RGB_ALPHA ;
    else
      color_type = PNG_COLOR_TYPE_RGB ;
    break ;
  case COLOR_INDEXED:
    if( paletteSize == 2 &&
        palette[0] == NEWALPHA(0,255) &&
        palette[1] == NEWALPHA(-1,255) ) {
      color_type = PNG_COLOR_TYPE_GRAY ;
      bit_depth = 1 ;
    } else if( paletteSize == 2 &&
               palette[0] == NEWALPHA(-1,255) &&
               palette[1] == NEWALPHA(0,255) ) {
      color_type = PNG_COLOR_TYPE_GRAY ;
      bit_depth = 1 ;
      invert_mono = 1 ;
    } else {
      unsigned i ;
      int need_trans = flatspec.default_pixel == FORCE_ALPHA_CHANNEL ;
      color_type = PNG_COLOR_TYPE_PALETTE ;
      pngpalette = xcfmalloc(paletteSize*sizeof(png_color)) ;
      ptrans = xcfmalloc(paletteSize);
      for(i = 0; i<paletteSize; i++ ) {
        pngpalette[i].red = 255 & (palette[i] >> RED_SHIFT);
        pngpalette[i].green = 255 & (palette[i] >> GREEN_SHIFT);
        pngpalette[i].blue = 255 & (palette[i] >> BLUE_SHIFT);
        if( (ptrans[i] = ALPHA(palette[i])) != 255 )
          need_trans = 1 ;
      }
      if( !need_trans ) {
        xcffree(ptrans);
        ptrans = NULL ;
      }
      if( paletteSize <= 2 )
        bit_depth = 1 ;
      else if( paletteSize <= 4 )
        bit_depth = 2 ;
      else if( paletteSize <= 16 )
        bit_depth = 4 ;
      else
        bit_depth = 8;
    }
    break ;
  default:
    FatalUnexpected("This can't happen (unknown out_color_mode)");
  }

  if( verboseFlag ) {
    fprintf(stderr,"Writing PNG: %s%s%s%s, %d bits",
            color_type & PNG_COLOR_MASK_COLOR ? _("color") : _("grayscale"),
            color_type & PNG_COLOR_MASK_PALETTE ? _("+palette") : "",
            color_type & PNG_COLOR_MASK_ALPHA ? _("+alpha") : "",
            ptrans || NULLALPHA(flatspec.default_pixel)
            ? _("+transparency") : "",
            bit_depth);
    if( pngpalette )
      fprintf(stderr,_(" (%d colors)"),paletteSize);
    fprintf(stderr,"\n");
  }
  
  png_set_IHDR(libpng,libpng2,flatspec.dim.width,flatspec.dim.height,
               bit_depth, color_type,
               PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_DEFAULT,
               PNG_FILTER_TYPE_DEFAULT);

  if( invert_mono )
    png_set_invert_mono(libpng);
  
  if( pngpalette )
    png_set_PLTE(libpng,libpng2,pngpalette,paletteSize);
  if( ptrans )
    png_set_tRNS(libpng,libpng2,ptrans,paletteSize,NULL);
  else if ( !pngpalette &&
            NULLALPHA(flatspec.default_pixel) ) {
    static png_color_16 trans ;
    trans.gray =
      trans.red = 255 & (flatspec.default_pixel >> RED_SHIFT) ;
    trans.green = 255 & (flatspec.default_pixel >> GREEN_SHIFT) ;
    trans.blue = 255 & (flatspec.default_pixel >> BLUE_SHIFT) ;
    png_set_tRNS(libpng,libpng2,NULL,0,&trans);
  }

  /* png_set_text here */

  png_write_info(libpng,libpng2);

  if( bit_depth < 8 )
    png_set_packing(libpng);

  switch( color_type ) {
  case PNG_COLOR_TYPE_RGB:
  case PNG_COLOR_TYPE_RGBA:
#if (BLUE_SHIFT < RED_SHIFT) == !defined(WORDS_BIGENDIAN)
    png_set_bgr(libpng);
#endif
    if( color_type == PNG_COLOR_TYPE_RGB )
#if (ALPHA_SHIFT < RED_SHIFT) == !defined(WORDS_BIGENDIAN)
      png_set_filler(libpng,0,PNG_FILLER_BEFORE);
    else
      png_set_swap_alpha(libpng);
#else
    png_set_filler(libpng,0,PNG_FILLER_AFTER);
#endif
    break ;
  case PNG_COLOR_TYPE_GRAY:
    png_set_filler(libpng,0,PNG_FILLER_AFTER);
    break ;
  case PNG_COLOR_TYPE_GRAY_ALPHA:
  case PNG_COLOR_TYPE_PALETTE:
    break ;
  default:
    FatalUnexpected("This can't happen (unexpected png color_type)");
  }
}
void
analyse_colormode(struct FlattenSpec *spec,rgba **allPixels,
                  guesser guess_callback)
{
    unsigned x,y ;
    int status ;
    /* 8 - looking for any transparency
     * 4 - looking for partially transparent pixels
     * 2 - looking for pixels other than black and white
     * 1 - looking for colored pixels
     */
    int known_absent = 0 ;
    int assume_present = 0 ;

    if( spec->out_color_mode == COLOR_BY_CONTENTS && guess_callback )
        spec->out_color_mode = guess_callback(spec,allPixels) ;

    if( spec->out_color_mode == COLOR_RGB     ) assume_present |= 3 ;
    if( spec->out_color_mode == COLOR_INDEXED ) assume_present |= 3 ;
    if( spec->out_color_mode == COLOR_GRAY    ) assume_present |= 2 ;
    switch( color_by_layers(spec) ) {
    case COLOR_GRAY:
        known_absent |= 1 ;
        break ;
    case COLOR_MONO:
        known_absent |= 3 ;
        break ;
    default:
        break ;
    }
    if( spec->partial_transparency_mode == DISSOLVE_PARTIAL_TRANSPARENCY ||
            spec->partial_transparency_mode == PARTIAL_TRANSPARENCY_IMPOSSIBLE )
        known_absent |= 4 ;
    if( ALPHA(spec->default_pixel) >= 128 )               known_absent |= 12 ;
    else if( spec->default_pixel == FORCE_ALPHA_CHANNEL ) assume_present |= 8 ;

    status = 15 - (known_absent | assume_present) ;

    for( y=0; status && y<spec->dim.height; y++ ) {
        rgba *row = allPixels[y] ;
        if( (status & 3) != 0 ) {
            /* We're still interested in color */
            for( x=0; status && x<spec->dim.width; x++ ) {
                if( NULLALPHA(row[x]) )
                    status &= ~8 ;
                else {
                    rgba full = row[x] | (255 << ALPHA_SHIFT) ;
                    if( !FULLALPHA(row[x]) ) status &= ~12 ;
                    if( full == NEWALPHA(0,255) || full == NEWALPHA(-1,255) )
                        /* Black or white */ ;
                    else if( degrayPixel(row[x]) != -1 )
                        status &= ~2 ; /* gray */
                    else
                        status &= ~3 ; /* color */
                }
            }
        } else {
            /* Not interested in color */
            for( x=0; status && x<spec->dim.width; x++ ) {
                if( NULLALPHA(row[x]) )
                    status &= ~8 ;
                else if( !FULLALPHA(row[x]) )
                    status &= ~12 ;
            }
        }
    }

    status |= known_absent ;

    switch( spec->out_color_mode ) {
    case COLOR_INDEXED: /* The caller takes responsibility */
    case COLOR_RGB: /* Everything is fine. */
        break ;
    case COLOR_GRAY:
        if( (status & 1) == 0 )
            FatalGeneric(103,
                         _("Grayscale output selected, but colored pixel(s) found"));
        break ;
    case COLOR_MONO:
        if( (status & 2) == 0 )
            FatalGeneric(103,_("Monochrome output selected, but not all pixels "
                               "are black or white"));
        break ;
    case COLOR_BY_FILENAME: /* Should not happen ... */
    case COLOR_BY_CONTENTS:
        if( (status & 1) == 0 )
            spec->out_color_mode = COLOR_RGB ;
        else if( (status & 2) == 0 )
            spec->out_color_mode = COLOR_GRAY ;
        else
            spec->out_color_mode = COLOR_MONO ;
        break ;
    }

    if( (status & 12) == 12 ) /* No transparency found */
        spec->default_pixel = NEWALPHA(colormap[0],255);
    else if( (status & 12) == 4 )
        spec->partial_transparency_mode = PARTIAL_TRANSPARENCY_IMPOSSIBLE ;
}