/* * libbmeps - Bitmap to EPS conversion library * Copyright (C) 2000 - Dirk Krause * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * In this package the copy of the GNU Library General Public License * is placed in file COPYING. */ #include #include #include #include $(trace-include) #if HAVE_ZLIB #if HAVE_LIBPNG #include static char default_name[] = { "noname.png" }; /* static int a2t(int x, int alpha, int trans, int aldual, int altrig) { int back = 0; $? "+ a2t x=%d alpha=%d trans=%d dual=%d tr=%d", x, alpha, trans, aldual, altrig if(alpha) { if(!trans) { back = 255 - x; } if(aldual) { if(altrig) { if(back > 0) { back = 255; } } else { if(back < 255) { back = 0; } } } } $? "- a2t %d", back return back; } */ static int new_bit_depth(int alt, int newbits, int altbits) { int back = 0; unsigned long a, b, nb, ab; $? "+ new_bit_depth x=%d newbits=%d altbits=%d", alt, newbits, altbits a = alt; nb = newbits; ab = altbits; b = (((2UL ^ nb)-1UL)*(a)) / ((2UL ^ ab) - 1UL); back = b; $? "- new_bit_depth %d", back return back; } static int ntsc(int red, int green, int blue) { int back = 0; unsigned long r, g, b, bck; $? "+ ntsc %d %d %d", red, green, blue r = red; g = green; b = blue; bck = ((54UL * r) + (183UL * g) + (19UL * b)) / 256UL; back = bck; $? "- ntsc %d", back return back; } static int mix_colors(int fg, int bg, int alpha, int tr) { int back = 0; unsigned long f, b, a, bck; $? "+ mix_colors fg=%d bg=%d a=%d tr=%d", fg, bg, alpha, tr if(tr) { a = (255UL - alpha) ; } else { a = alpha; } f = fg; b = bg; bck = ((a * f) + ((255UL - a) * b)) / 255UL; back = bck; $? "- mix_colors %d", back return back; } static int png_run(FILE *out, FILE *in, char *name, unsigned long *w, unsigned long *h, int cmd) { int back = 0; png_structp pp; png_infop pi; unsigned long wi; /* width */ unsigned long he; /* height */ unsigned long i, j, x, y; int bd; /* bit depth */ int ct, cu; /* color type */ int it; /* interlace type */ int zt; /* compression type */ int ft; /* filter type */ int ch; /* channels */ int alpha; int trans; int altrig; int rowbytes; int mix; /* mix foreground and background */ int specbg; /* specified background from command line */ int bg_red, bg_green, bg_blue; png_bytep row, *rows, *rowp; png_color_16 bg; png_color_16p bgp; if(in) { alpha = bmeps_get_alpha(); trans = bmeps_get_trans(); altrig = bmeps_get_altrig(); mix = bmeps_get_mix(); specbg = bmeps_get_specbg(); bg_red = bmeps_get_bg_red(); bg_green = bmeps_get_bg_green(); bg_blue = bmeps_get_bg_blue(); rewind(in); pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(pp) { $? ". pp created" pi = png_create_info_struct(pp); if(pi) { $? ". pi created" png_init_io(pp, in); $? ". image initialized" png_read_info(pp, pi); $? ". info was read" png_get_IHDR(pp, pi, &wi, &he, &bd, &ct, &it, &zt, &ft); $? ". width = %lu", wi $? ". height = %lu", he $? ". bitdepth = %d", bd $? ". colortype = %d", ct $? ". interlace = %d", it $? ". compressiontype = %d", zt $? ". filtertype = %d", ft cu = ct; ch = png_get_channels(pp, pi); $? ". channels = %d", ch switch(cmd) { case 0: { if(out) { bmeps_header( out, (name ? name : default_name), wi, he ); if(bmeps_get_draft()) { back = 1; bmeps_draft(out, wi, he); } else { int need_expansion; int need_strip; int need_pack; need_expansion = 0; need_strip = 0; need_pack = 0; if((ct == PNG_COLOR_TYPE_PALETTE) && (bd <= 8)) { need_expansion = 1; } if((ct == PNG_COLOR_TYPE_GRAY) && (bd < 8)) { need_expansion = 1; } if(png_get_valid(pp, pi, PNG_INFO_tRNS)) { need_expansion = 1; } if(bd > 8) { need_strip = 1; } else { if(bd < 8) { need_pack = 1; } } if(need_expansion) { png_set_expand(pp); } if(need_strip) { png_set_strip_16(pp); } if(need_pack) { png_set_packing(pp); } bgp = &bg; bg.red = bg_red; bg.green = bg_green; bg.blue = bg_blue; bg.gray = ntsc(bg.red, bg.green, bg.blue); bg.index = 0; $? ". have alpha support" if(!(alpha)) { $? ". alpha support not in use" if(png_get_bKGD(pp, pi, &bgp)) { png_set_background(pp,bgp,PNG_BACKGROUND_GAMMA_FILE,1,1.0); } else { png_set_background(pp,&bg,PNG_BACKGROUND_GAMMA_SCREEN,0,1.0); } } else { $? ". alpha support in use" if(png_get_bKGD(pp, pi, &bgp) && (!specbg)) { $? ". background chunk contained" if(ct & PNG_COLOR_MASK_PALETTE) { png_colorp ptr; int num; $? ". paletted PNG" if(png_get_PLTE(pp, pi, &ptr, &num)) { $? ". palette was read" if(bgp->index < num) { $? ". backround index in range" if(bd != 8) { $? ". bitdepth needs correction" bg.red = new_bit_depth(ptr[bgp->index].red, 8, bd); bg.green = new_bit_depth( ptr[bgp->index].green, 8, bd ); bg.blue = new_bit_depth( ptr[bgp->index].blue, 8, bd ); bg.gray = ntsc( bg.red, bg.green, bg.blue ); } else { $? ". bitdepth ok" bg.red = ptr[bgp->index].red; bg.green = ptr[bgp->index].green; bg.blue = ptr[bgp->index].blue; bg.gray = ntsc(bg.red, bg.green, bg.blue); } } else { $? "! background index out of range" bg.red = bg_red; bg.green = bg_green; bg.blue = bg_blue; bg.gray = ntsc(bg.red, bg.green, bg.blue); bg.index = 0; } } else { $? "! failed to read palette" bg.red = bg_red; bg.green = bg_green; bg.blue = bg_blue; bg.gray = ntsc(bg.red, bg.green, bg.blue); bg.index = 0; } } else { $? ". not paletted" if(bd != 8) { $? ". bitdepth ok" bg.red = new_bit_depth( bgp->red, 8, bd); bg.blue = new_bit_depth( bgp->blue, 8, bd); bg.green = new_bit_depth( bgp->green, 8, bd); bg.gray = new_bit_depth( bgp->gray, 8, bd); } else { $? ". need to correct bitdepth" bg.red = bgp->red; bg.blue = bgp->blue; bg.green = bgp->green; bg.gray = bgp->gray; } bg.index = 0; } } else { $? ". no background chunk contained or chunk unused" bg.red = bg_red; bg.green = bg_green; bg.blue = bg_blue; bg.gray = ntsc(bg.red, bg.green, bg.blue); bg.index = 0; } } /* place gamma correction here */ /* place interlace handling here */ png_read_update_info(pp, pi); ch = png_get_channels(pp, pi); ct = png_get_color_type(pp, pi); $? ". colortype now %d", ct $? ". channels now %d", ch rowbytes = png_get_rowbytes(pp, pi); rows = (png_bytep *)malloc(he*sizeof(png_bytep)); if(rows) { back = 1; rowp = rows; for(y = 0; y < he; y++) { *rowp = NULL; row = (png_bytep)malloc(rowbytes*sizeof(png_byte)); if(row) { *rowp = row; } else { back = 0; } rowp++; } if(back) { png_read_image(pp, rows); if((ct & PNG_COLOR_MASK_ALPHA) && alpha) { $? ". alpha channel detected" bmeps_set_trans(1); } else { $? ". no alpha channel in picture" } bmeps_begin_image( out, wi, he ); rowp = rows; for(y = 0; y < he; y++) { row = *(rowp++); for(x = 0; x < wi; x++) { if((ct & PNG_COLOR_MASK_ALPHA) && alpha) { $? ". alpha %lu %lu", x, y bmeps_add_trans( 255-row[(x+1UL)*((unsigned long)ch)-1UL] ); } if(ct & PNG_COLOR_MASK_COLOR) { $? ". rgb %lu %lu", x, y if((ct & PNG_COLOR_MASK_ALPHA) && alpha && mix) { /* 4 lines for debugging only */ static int firstrun = 1; if(firstrun) { $? ". MIXING COLORS WITH BACKGROUND" } firstrun = 0; bmeps_add_rgb( mix_colors( row[x*((unsigned long)ch)], bg.red, row[(x+1UL)*((unsigned long)ch)-1UL], trans ), mix_colors( row[x*((unsigned long)ch)+1UL], bg.green, row[(x+1UL)*((unsigned long)ch)-1UL], trans ), mix_colors( row[x*((unsigned long)ch)+2UL], bg.blue, row[(x+1UL)*((unsigned long)ch)-1UL], trans ) ); } else { /* 4 lines for debugging only */ static int firstrun = 1; if(firstrun) { $? ". NOT MIXING COLORS WITH BACKGROUND" } firstrun = 0; bmeps_add_rgb( row[x*((unsigned long)ch)], row[x*((unsigned long)ch)+1UL], row[x*((unsigned long)ch)+2UL] ); } } else { if((ct & PNG_COLOR_MASK_ALPHA) && alpha && mix) { /* 4 lines for debugging only */ static int firstrun = 1; if(firstrun) { $? ". MIXING GRAY WITH BACKGROUND" } firstrun = 0; bmeps_add_gray( mix_colors( row[x*((unsigned long)ch)], bg.gray, row[(x+1UL)*((unsigned long)ch)-1UL], trans ) ); } else { /* 4 lines for debugging only */ static int firstrun = 1; if(firstrun) { $? ". MIXING GRAY WITH BACKGROUND" } firstrun = 0; $? ". gray %lu %lu", x, y bmeps_add_gray( row[x*((unsigned long)ch)] ); } } } } bmeps_end_image(out); $? ". image finished" } /* done with rows */ rowp = rows; for(y = 0; y < he; y++) { row = *rowp; if(row) { free(row); } *(rowp++) = NULL; } free(rows); } else { $? "! memory allocation failed for rows" } } bmeps_footer(out); } } break; case 1: { if(out) { back = 1; bmeps_bb(out, wi, he); } } break; case 2: { if(w && h) { back = 1; *w = wi; *h = he; } } break; } /* done with it */ png_destroy_info_struct(pp, &pi); } else { $? "! failed to create pi" } png_destroy_read_struct(&pp, NULL, NULL); } else { $? "! failed to create pp" } } return back; } #else /* HAVE_LIBPNG */ static int png_run(FILE *out, FILE *in, char *name, unsigned long *w, unsigned long *h, int cmd) { return 0; } #endif /* HAVE_LIBPNG */ #else /* HAVE_ZLIB */ static int png_run(FILE *out, FILE *in, char *name, unsigned long *w, unsigned long *h, int cmd) { return 0; } #endif /* HAVE_ZLIB */ int bmeps_png(FILE *out, FILE *in, char *name) { int back; if(out && in) { bmeps_configure(); back = png_run(out, in, name, NULL, NULL, 0); } return back; } int bmeps_png_bb(FILE *out, FILE *in, char *name) { int back; if(out && in) { bmeps_configure(); back = png_run(out, in, name, NULL, NULL, 1); } return back; } int bmeps_png_wh(FILE *in, unsigned long *w, unsigned long *h) { int back = 0; if(w && h && in) { bmeps_configure(); back = png_run(NULL, in, NULL, w, h, 2); } return back; } #ifndef LINT static char sccs_id[] = { "@(#)09/26/00\t1.12\tpngeps.ctr\t(krause) PNG to EPS conversion module" }; #endif