Line data Source code
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 "inc/basics.h"
47 : # include "gimage.h"
48 :
49 : static void *libpng=(void *) 1;
50 :
51 0 : static int loadpng(void) { return true; }
52 :
53 0 : static void user_error_fn(png_structp png_ptr, png_const_charp error_msg) {
54 0 : fprintf(stderr,"%s\n", error_msg);
55 : #if (PNG_LIBPNG_VER < 10500)
56 0 : longjmp(png_ptr->jmpbuf,1);
57 : #else
58 : png_longjmp (png_ptr, 1);
59 : #endif
60 : }
61 :
62 0 : static void user_warning_fn(png_structp UNUSED(png_ptr), png_const_charp warning_msg) {
63 0 : fprintf(stderr,"%s\n", warning_msg);
64 0 : }
65 :
66 1 : GImage *GImageRead_Png(FILE *fp) {
67 1 : GImage *ret=NULL;
68 : struct _GImage *base;
69 : png_structp png_ptr;
70 : png_infop info_ptr;
71 1 : png_bytep *row_pointers=NULL;
72 : png_bytep trans_alpha;
73 : int num_trans;
74 : png_color_16p trans_color;
75 : unsigned i;
76 : int test;
77 :
78 1 : if ( libpng==NULL )
79 0 : if ( !loadpng())
80 0 : return( NULL );
81 :
82 1 : png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
83 : (void *)NULL, user_error_fn, user_warning_fn);
84 :
85 1 : if (!png_ptr)
86 0 : return( NULL );
87 :
88 1 : info_ptr = png_create_info_struct(png_ptr);
89 1 : if (!info_ptr) {
90 0 : png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
91 0 : return( NULL );
92 : }
93 :
94 : #if (PNG_LIBPNG_VER < 10500)
95 1 : test = setjmp(png_ptr->jmpbuf);
96 : #else
97 : test = setjmp(*png_set_longjmp_fn(png_ptr, longjmp, sizeof (jmp_buf)));
98 : #endif
99 1 : if (test) {
100 : /* Free all of the memory associated with the png_ptr and info_ptr */
101 0 : png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
102 0 : if ( ret!=NULL ) {
103 0 : GImageDestroy(ret);
104 0 : free(row_pointers);
105 : }
106 : /* If we get here, we had a problem reading the file */
107 0 : return( NULL );
108 : }
109 :
110 1 : png_init_io(png_ptr, fp);
111 1 : png_read_info(png_ptr, info_ptr);
112 1 : png_set_strip_16(png_ptr);
113 2 : 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 ) &&
114 1 : png_get_bit_depth(png_ptr,info_ptr) == 1 )
115 : /* Leave bitmaps packed */;
116 : else
117 1 : png_set_packing(png_ptr);
118 1 : if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_GRAY_ALPHA )
119 0 : png_set_strip_alpha(png_ptr);
120 1 : if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB)
121 0 : png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
122 :
123 1 : if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr,info_ptr) == 1 ) {
124 0 : ret = GImageCreate(it_mono,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
125 1 : } 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 ) {
126 : GClut *clut;
127 0 : ret = GImageCreate(it_index,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
128 0 : clut = ret->u.image->clut;
129 0 : clut->is_grey = true;
130 0 : clut->clut_len = 256;
131 0 : for ( i=0; i<256; ++i )
132 0 : clut->clut[i] = COLOR_CREATE(i,i,i);
133 1 : } else if ( png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_RGB_ALPHA ) {
134 0 : ret = GImageCreate(it_rgba,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
135 1 : } 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 )
136 0 : ret = GImageCreate(it_true,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
137 : else {
138 : png_colorp palette;
139 : int num_palette;
140 : GClut *clut;
141 2 : ret = GImageCreate(png_get_bit_depth(png_ptr,info_ptr) != 1? it_index : it_mono,
142 2 : png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr));
143 1 : clut = ret->u.image->clut;
144 1 : if ( clut==NULL )
145 0 : clut = ret->u.image->clut = (GClut *) calloc(1,sizeof(GClut));
146 1 : clut->is_grey = true;
147 1 : png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette);
148 1 : clut->clut_len = num_palette;
149 33 : for ( i=0; i<(unsigned)num_palette; ++i )
150 32 : clut->clut[i] = COLOR_CREATE(palette[i].red,
151 : palette[i].green,
152 : palette[i].blue);
153 : }
154 1 : png_get_tRNS(png_ptr,info_ptr,&trans_alpha,&num_trans,&trans_color);
155 1 : base = ret->u.image;
156 1 : if ( (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) && num_trans>0 ) {
157 0 : 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 )
158 0 : base->trans = COLOR_CREATE(
159 : (trans_color->red>>8),
160 : (trans_color->green>>8),
161 : (trans_color->blue>>8));
162 0 : else if ( base->image_type == it_mono )
163 0 : base->trans = trans_alpha ? trans_alpha[0] : 0;
164 : else
165 0 : base->clut->trans_index = base->trans = trans_alpha ? trans_alpha[0] : 0;
166 : }
167 :
168 1 : row_pointers = (png_byte **) malloc(png_get_image_height(png_ptr,info_ptr)*sizeof(png_bytep));
169 33 : for ( i=0; i<png_get_image_height(png_ptr,info_ptr); ++i )
170 32 : row_pointers[i] = (png_bytep) (base->data + i*base->bytes_per_line);
171 :
172 : /* Ignore progressive loads for now */
173 : /* libpng wants me to do it with callbacks, but that doesn't sit well */
174 : /* with my wish to be in control... */
175 1 : png_read_image(png_ptr,row_pointers);
176 1 : png_read_end(png_ptr, NULL);
177 :
178 1 : 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 ) {
179 : /* PNG orders its bytes as AABBGGRR instead of 00RRGGBB */
180 : uint32 *ipt, *iend;
181 0 : for ( ipt = (uint32 *) (base->data), iend=ipt+base->width*base->height; ipt<iend; ++ipt ) {
182 0 : uint32 r, g, b, a = *ipt&0xff000000;
183 0 : r = (*ipt )&0xff;
184 0 : g = (*ipt>>8 )&0xff;
185 0 : b = (*ipt>>16)&0xff;
186 0 : *ipt = COLOR_CREATE( r,g,b ) | a;
187 : }
188 : }
189 :
190 1 : png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
191 1 : free(row_pointers);
192 : /* Note png b&w images come out as indexed */
193 1 : return( ret );
194 : }
195 :
196 0 : GImage *GImageReadPng(char *filename) {
197 0 : GImage *ret=NULL;
198 : FILE *fp;
199 :
200 0 : fp = fopen(filename, "rb");
201 0 : if (!fp)
202 0 : return( NULL );
203 :
204 0 : ret = GImageRead_Png(fp);
205 0 : fclose(fp);
206 0 : return( ret );
207 : }
208 : #endif
|