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