/** ** png2ctx.c ---- loads a context from a PNG file ** ** Copyright (C) 2001 Mariano Alvarez Fernandez ** [e-mail: malfer@teleline.es] ** ** This file is part of the GRX graphics library. ** ** The GRX graphics library is free software; you can redistribute it ** and/or modify it under some conditions; see the "copying.grx" file ** for details. ** ** 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. ** ** 170320 M.Alvarez, Fix a warning in newer versions of libPNG **/ #include #include #include #include #include "mgrx.h" /* ** GrPngSupport - Returns true */ int GrPngSupport( void ) { return 1; } #ifndef png_jmpbuf # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) #endif static int readpng( FILE *f, GrContext *grc, int use_alpha ); static int querypng( FILE *f, int *w, int *h ); /* ** GrLoadContextFromPng - Load a context from a PNG file ** ** If context dimensions are lesser than png dimensions, ** the routine loads as much as it can ** ** If color mode is not in RGB mode, the routine allocates as ** much colors as it can ** ** Arguments: ** grc: Context to be loaded (NULL -> use current context) ** pngfn: Name of pnm file ** use_alpha: if true, use alpha channel if available ** ** Returns 0 on success ** -1 on error */ int GrLoadContextFromPng( GrContext *grc, char *pngfn, int use_alpha ) { GrContext grcaux; FILE *f; int r; f = fopen( pngfn,"rb" ); if( f == NULL ) return -1; GrSaveContext( &grcaux ); if( grc != NULL ) GrSetContext( grc ); r = readpng( f,grc,use_alpha ); GrSetContext( &grcaux ); fclose( f ); return r; } /* ** GrQueryPnm - Query width and height data from a PNG file ** ** Arguments: ** pngfn: Name of png file ** width: return pnm width ** height: return pnm height ** ** Returns 0 on success ** -1 on error */ int GrQueryPng( char *pngfn, int *width, int *height ) { FILE *f; int r; f = fopen( pngfn,"rb" ); if( f == NULL ) return -1; r = querypng( f,width,height ); fclose( f ); return r; } /**/ static int readpng( FILE *f, GrContext *grc, int use_alpha ) { png_struct *png_ptr = NULL; png_info *info_ptr = NULL; png_byte buf[8]; png_byte *png_pixels = NULL; png_byte **row_pointers = NULL; png_byte *pix_ptr = NULL; png_uint_32 row_bytes; png_uint_32 width; png_uint_32 height; int bit_depth; int color_type; int alpha_present; int i, x, y, r, g, b; int alpha = 0, ro, go, bo; int maxwidth, maxheight; GrColor *pColors = NULL; /* is it a PNG file? */ if( fread( buf,1,8,f ) != 8 ) return -1; if( ! png_check_sig( buf,8 ) ) return -1; png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); if( !png_ptr ){ return -1; } info_ptr = png_create_info_struct( png_ptr ); if( !info_ptr ){ png_destroy_read_struct( &png_ptr,NULL,NULL ); return -1; } if( setjmp( png_jmpbuf(png_ptr) ) ){ png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); return -1; } png_init_io( png_ptr,f ); png_set_sig_bytes( png_ptr,8 ); png_read_info( png_ptr,info_ptr ); png_get_IHDR( png_ptr,info_ptr,&width,&height,&bit_depth, &color_type,NULL,NULL,NULL); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ if( bit_depth == 16 ) png_set_strip_16( png_ptr ); /* expand paletted colors into true RGB triplets */ if( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_expand( png_ptr ); /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 ) png_set_expand( png_ptr ); /* expand paletted or RGB images with transparency to full alpha channels so the data will be available as RGBA quartets. */ if( png_get_valid( png_ptr,info_ptr,PNG_INFO_tRNS ) ) png_set_expand( png_ptr ); /* transform grayscale images into rgb */ if( color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png_ptr ); /* we don't do gamma correction by now */ /* nedeed t ofix a warning in newer versions of libPNG */ png_set_interlace_handling( png_ptr ); png_read_update_info( png_ptr,info_ptr ); png_get_IHDR( png_ptr,info_ptr,&width,&height,&bit_depth, &color_type,NULL,NULL,NULL); if( color_type == PNG_COLOR_TYPE_RGB ) alpha_present = 0; else if( color_type == PNG_COLOR_TYPE_RGB_ALPHA ) alpha_present = 1; else{ png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); return -1; } row_bytes = png_get_rowbytes( png_ptr,info_ptr ); png_pixels = (png_byte *) malloc( row_bytes * height * sizeof(png_byte) ); if( png_pixels == NULL ){ png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); return -1; } row_pointers = (png_byte **) malloc( height * sizeof(png_bytep) ); if( row_pointers == NULL ){ png_destroy_read_struct( &png_ptr,&info_ptr,NULL ); free( png_pixels ); png_pixels = NULL; return -1; } for( i=0; i GrSizeX()) ? GrSizeX() : width; maxheight = (height > GrSizeY()) ? GrSizeY() : height; pColors = malloc( maxwidth * sizeof(GrColor) ); if( pColors == NULL ){ free( row_pointers ); row_pointers = NULL; free( png_pixels ); png_pixels = NULL; return -1; } for( y=0; y