1 /* input-png.c: PNG loader for autotrace
2 
3    Copyright (C) 2000 MenTaLguY <mental@rydia.net>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License
7    as published by the Free Software Foundation; either version 2.1 of
8    the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18    USA. */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif /* Def: HAVE_CONFIG_H */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "types.h"
29 #include "bitmap.h"
30 #include "message.h"
31 #include "xstd.h"
32 #include <png.h>
33 #include "input-png.h"
34 
35 static volatile char rcsid[]="$Id: input-png.c,v 1.16 2002/10/05 19:38:25 masata-y Exp $";
36 static png_bytep * read_png(png_structp png_ptr, png_infop info_ptr, at_input_opts_type * opts);
37 
38 /* for pre-1.0.6 versions of libpng */
39 #ifndef png_jmpbuf
40 #	define png_jmpbuf(png_ptr) (png_ptr)->jmpbuf
41 #endif
42 
handle_warning(png_structp png,const at_string message)43 static void handle_warning(png_structp png, const at_string message) {
44         LOG1("PNG warning: %s", message);
45 	at_exception_warning((at_exception_type *)png_get_error_ptr(png),
46 			     message);
47 	/* at_exception_fatal((at_exception_type *)png_get_error_ptr(at_png),
48 	   "PNG warning"); */
49 }
50 
handle_error(png_structp png,const at_string message)51 static void handle_error(png_structp png, const at_string message) {
52 	LOG1("PNG error: %s", message);
53 	at_exception_fatal((at_exception_type *)png_get_error_ptr(png),
54 			   message);
55 	/* at_exception_fatal((at_exception_type *)png_get_error_ptr(at_png),
56 	   "PNG error"); */
57 
58 }
59 
finalize_structs(png_structp png,png_infop info,png_infop end_info)60 static void finalize_structs(png_structp png, png_infop info,
61                              png_infop end_info)
62 {
63 	png_destroy_read_struct(png ? &png : NULL,
64 	                        info ? &info : NULL,
65 	                        end_info ? &end_info : NULL);
66 }
67 
init_structs(png_structp * png,png_infop * info,png_infop * end_info,at_exception_type * exp)68 static int init_structs(png_structp *png, png_infop *info,
69                         png_infop *end_info, at_exception_type * exp)
70 {
71 	*png = NULL;
72 	*info = *end_info = NULL;
73 
74 	*png = png_create_read_struct(PNG_LIBPNG_VER_STRING, exp,
75 	                              (png_error_ptr)handle_error, (png_error_ptr)handle_warning);
76 
77 	if (*png) {
78 		*info = png_create_info_struct(*png);
79 		if (*info) {
80 			*end_info = png_create_info_struct(*png);
81 			if (*end_info) return 1;
82 		}
83 		finalize_structs(*png, *info, *end_info);
84 	}
85 	return 0;
86 }
87 
88 #define CHECK_ERROR() 	do { if (at_exception_got_fatal(exp))	\
89 	  {							\
90 	    result = 0;						\
91 	    goto cleanup;					\
92 	  } } while (0)
93 
load_image(at_bitmap_type * image,FILE * stream,at_input_opts_type * opts,at_exception_type * exp)94 static int load_image(at_bitmap_type *image, FILE *stream, at_input_opts_type * opts, at_exception_type * exp)
95 {
96 	png_structp png;
97 	png_infop info, end_info;
98 	png_bytep *rows;
99 	unsigned short width, height, row;
100 	int pixel_size;
101 	int result = 1;
102 
103 	if (!init_structs(&png, &info, &end_info, exp))
104 	  return 0;
105 
106 	png_init_io(png, stream);
107 	CHECK_ERROR();
108 
109 	png_read_png(png, info, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, 0);
110 	rows = png_get_rows(png, info);
111 
112 	width = (unsigned short)png_get_image_width(png, info);
113 	height = (unsigned short)png_get_image_height(png, info);
114 	if ( png_get_color_type(png, info) == PNG_COLOR_TYPE_GRAY ) {
115 		pixel_size = 1;
116 	} else {
117 		pixel_size = 3;
118 	}
119 
120 	*image = at_bitmap_init(NULL, width, height, pixel_size);
121 	for ( row = 0 ; row < height ; row++, rows++ ) {
122 		memcpy(AT_BITMAP_PIXEL(*image, row, 0), *rows,
123 		       width * pixel_size * sizeof(unsigned char));
124 	}
125  cleanup:
126 	finalize_structs(png, info, end_info);
127 	return result;
128 }
129 
input_png_reader(at_string filename,at_input_opts_type * opts,at_msg_func msg_func,at_address msg_data)130 at_bitmap_type input_png_reader(at_string filename, at_input_opts_type * opts,
131 				at_msg_func msg_func, at_address msg_data) {
132 	FILE *stream;
133 	at_bitmap_type image = at_bitmap_init(0, 0, 0, 1);
134 	at_exception_type exp = at_exception_new(msg_func, msg_data);
135 
136 	stream = fopen(filename, "rb");
137 	if (!stream)
138 	  {
139 	    LOG1("Can't open \"%s\"\n", filename);
140 	    at_exception_fatal(&exp, "Cannot open input png file");
141 	    return image;
142 	  }
143 
144 	load_image(&image, stream, opts, &exp);
145 	fclose(stream);
146 
147 	return image;
148 }
149