1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #ifdef _NO_LIBPNG
31 
32 static void *a_file_must_define_something=(void *) &a_file_must_define_something;
33 		/* ANSI says so */
34 
35 #else
36 
37 # include <png.h>
38 
39 # define int32 _int32
40 # define uint32 _uint32
41 # define int16 _int16
42 # define uint16 _uint16
43 # define int8 _int8
44 # define uint8 _uint8
45 
46 # include "basics.h"
47 # include "gimage.h"
48 
49 struct mem_buffer {
50     char *buffer;
51     size_t size;
52     size_t read;
53 };
54 
user_error_fn(png_structp png_ptr,png_const_charp error_msg)55 static void user_error_fn(png_structp png_ptr, png_const_charp error_msg) {
56     fprintf(stderr,"%s\n", error_msg);
57 #if (PNG_LIBPNG_VER < 10500)
58     longjmp(png_ptr->jmpbuf,1);
59 #else
60     png_longjmp (png_ptr, 1);
61 #endif
62 }
63 
user_warning_fn(png_structp UNUSED (png_ptr),png_const_charp warning_msg)64 static void user_warning_fn(png_structp UNUSED(png_ptr), png_const_charp warning_msg) {
65     fprintf(stderr,"%s\n", warning_msg);
66 }
67 
mem_read_fn(png_structp png_ptr,png_bytep data,png_size_t sz)68 static void mem_read_fn(png_structp png_ptr, png_bytep data, png_size_t sz) {
69     struct mem_buffer* buf = (struct mem_buffer*)png_get_io_ptr(png_ptr);
70 
71     if (buf->read + sz > buf->size) {
72         png_error(png_ptr, "memory buffer is too small");
73         return;
74     }
75 
76     memcpy(data, buf->buffer+buf->read, sz);
77     buf->read += sz;
78 }
79 
GImageReadPngFull(void * io,int in_memory)80 static GImage *GImageReadPngFull(void *io, int in_memory) {
81     GImage *ret=NULL;
82     struct _GImage *base;
83     png_structp png_ptr;
84     png_infop info_ptr;
85     png_bytep *row_pointers=NULL;
86     png_bytep trans_alpha;
87     int num_trans;
88     png_color_16p trans_color;
89     unsigned i;
90     int test;
91 
92    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
93       (void *)NULL, user_error_fn, user_warning_fn);
94 
95    if (!png_ptr)
96 return( NULL );
97 
98     info_ptr = png_create_info_struct(png_ptr);
99     if (!info_ptr) {
100       png_destroy_read_struct(&png_ptr,  (png_infopp)NULL, (png_infopp)NULL);
101 return( NULL );
102     }
103 
104 #if (PNG_LIBPNG_VER < 10500)
105     test = setjmp(png_ptr->jmpbuf);
106 #else
107     test = setjmp(*png_set_longjmp_fn(png_ptr, longjmp, sizeof (jmp_buf)));
108 #endif
109     if (test) {
110       /* Free all of the memory associated with the png_ptr and info_ptr */
111       png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
112       if ( ret!=NULL ) {
113 	  GImageDestroy(ret);
114 	  free(row_pointers);
115       }
116       /* If we get here, we had a problem reading the file */
117 return( NULL );
118     }
119 
120     if (in_memory) {
121         png_set_read_fn(png_ptr, io, mem_read_fn);
122     } else {
123         png_init_io(png_ptr, (FILE*)io);
124     }
125     png_read_info(png_ptr, info_ptr);
126     png_set_strip_16(png_ptr);
127     if ( (png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_GRAY || png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_PALETTE ) &&
128 	    png_get_bit_depth(png_ptr,info_ptr) == 1 )
129 	/* Leave bitmaps packed */;
130     else
131 	png_set_packing(png_ptr);
132     if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_GRAY_ALPHA )
133 	png_set_strip_alpha(png_ptr);
134     if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB)
135 	png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
136 
137     if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr,info_ptr) == 1 ) {
138 	ret = GImageCreate(it_mono,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
139     } else if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_GRAY || png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_GRAY_ALPHA ) {
140 	GClut *clut;
141 	ret = GImageCreate(it_index,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
142 	clut = ret->u.image->clut;
143 	clut->is_grey = true;
144 	clut->clut_len = 256;
145 	for ( i=0; i<256; ++i )
146 	    clut->clut[i] = COLOR_CREATE(i,i,i);
147     } else if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB_ALPHA ) {
148 	ret = GImageCreate(it_rgba,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
149     } else if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB || png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB_ALPHA )
150 	ret = GImageCreate(it_true,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
151     else {
152 	png_colorp palette;
153 	int num_palette;
154 	GClut *clut;
155 	ret = GImageCreate(png_get_bit_depth(png_ptr,info_ptr) != 1? it_index : it_mono,
156 		png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
157 	clut = ret->u.image->clut;
158 	if ( clut==NULL )
159 	    clut = ret->u.image->clut = (GClut *) calloc(1,sizeof(GClut));
160 	clut->is_grey = true;
161 	png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette);
162 	clut->clut_len = num_palette;
163 	for ( i=0; i<(unsigned)num_palette; ++i )
164 	    clut->clut[i] = COLOR_CREATE(palette[i].red,
165 			palette[i].green,
166 			palette[i].blue);
167     }
168     png_get_tRNS(png_ptr,info_ptr,&trans_alpha,&num_trans,&trans_color);
169     base = ret->u.image;
170     if ( (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) && num_trans>0 ) {
171 	if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB || png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB_ALPHA )
172 	    base->trans = COLOR_CREATE(
173 		    (trans_color->red>>8),
174 		    (trans_color->green>>8),
175 		    (trans_color->blue>>8));
176         else if ( base->image_type == it_mono )
177 	    base->trans = trans_alpha ? trans_alpha[0] : 0;
178 	else
179 	    base->clut->trans_index = base->trans = trans_alpha ? trans_alpha[0] : 0;
180     }
181 
182     row_pointers = (png_byte **) malloc(png_get_image_height(png_ptr,info_ptr)*sizeof(png_bytep));
183     for ( i=0; i<png_get_image_height(png_ptr,info_ptr); ++i )
184 	row_pointers[i] = (png_bytep) (base->data + i*base->bytes_per_line);
185 
186     /* Ignore progressive loads for now */
187     /* libpng wants me to do it with callbacks, but that doesn't sit well */
188     /*  with my wish to be in control... */
189     png_read_image(png_ptr,row_pointers);
190     png_read_end(png_ptr, NULL);
191 
192     if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB || png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB_ALPHA ) {
193 	/* PNG orders its bytes as AABBGGRR instead of 00RRGGBB */
194 	uint32 *ipt, *iend;
195 	for ( ipt = (uint32 *) (base->data), iend=ipt+base->width*base->height; ipt<iend; ++ipt ) {
196 	    uint32 r, g, b, a = *ipt&0xff000000;
197 	    r = (*ipt    )&0xff;
198 	    g = (*ipt>>8 )&0xff;
199 	    b = (*ipt>>16)&0xff;
200 	    *ipt = COLOR_CREATE( r,g,b ) | a;
201 	}
202     }
203 
204     png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
205     free(row_pointers);
206     /* Note png b&w images come out as indexed */
207 return( ret );
208 }
209 
GImageReadPngBuf(char * buf,size_t sz)210 GImage *GImageReadPngBuf(char* buf, size_t sz) {
211     struct mem_buffer membuf = {buf, sz, 0};
212     return GImageReadPngFull(&membuf, true);
213 }
214 
GImageRead_Png(FILE * fp)215 GImage *GImageRead_Png(FILE *fp) {
216     return GImageReadPngFull(fp, false);
217 }
218 
GImageReadPng(char * filename)219 GImage *GImageReadPng(char *filename) {
220     GImage *ret=NULL;
221     FILE *fp;
222 
223     fp = fopen(filename, "rb");
224     if (!fp)
225 return( NULL );
226 
227     ret = GImageRead_Png(fp);
228     fclose(fp);
229 return( ret );
230 }
231 #endif
232