1 #include "image.h" |
1 #include "image.h" |
2 #include "cache.h" |
2 #include "cache.h" |
|
3 #include "error.h" |
3 #include "shared/util.h" |
4 #include "shared/util.h" |
4 |
5 |
5 #include <stdlib.h> |
6 #include <stdlib.h> |
6 #include <errno.h> |
7 #include <errno.h> |
7 |
8 |
8 #include <png.h> |
9 #include <png.h> |
9 |
10 |
10 static int pt_image_new (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *path) |
11 static int pt_image_new (struct pt_image **image_ptr, struct pt_ctx *ctx, const char *path) |
11 { |
12 { |
12 struct pt_image *img; |
13 struct pt_image *image; |
|
14 int err = 0; |
13 |
15 |
14 // alloc |
16 // alloc |
15 if ((img = calloc(1, sizeof(*img))) == NULL) |
17 if ((image = calloc(1, sizeof(*image))) == NULL) |
16 return -1; |
18 JUMP_SET_ERROR(err, PT_ERR_MEM); |
17 |
19 |
18 if ((img->path = strdup(path)) == NULL) |
20 if ((image->path = strdup(path)) == NULL) |
19 goto error; |
21 JUMP_SET_ERROR(err, PT_ERR_MEM); |
20 |
22 |
21 // init |
23 // init |
22 img->ctx = ctx; |
24 image->ctx = ctx; |
23 |
25 |
24 // ok |
26 // ok |
25 *img_ptr = img; |
27 *image_ptr = image; |
26 |
28 |
27 return 0; |
29 return 0; |
28 |
30 |
29 error: |
31 error: |
30 pt_image_destroy(img); |
32 pt_image_destroy(image); |
31 |
33 |
32 return -1; |
34 return err; |
33 } |
35 } |
34 |
36 |
35 /** |
37 /** |
36 * Open the image's FILE |
38 * Open the image's FILE |
37 */ |
39 */ |
38 static int pt_image_open_file (struct pt_image *img, FILE **file_ptr) |
40 static int pt_image_open_file (struct pt_image *image, FILE **file_ptr) |
39 { |
41 { |
40 FILE *fp; |
42 FILE *fp; |
41 |
43 |
42 // open |
44 // open |
43 if ((fp = fopen(img->path, "rb")) < 0) |
45 if ((fp = fopen(image->path, "rb")) == NULL) |
44 return -1; |
46 RETURN_ERROR(PT_ERR_IMG_FOPEN); |
45 |
47 |
46 // ok |
48 // ok |
47 *file_ptr = fp; |
49 *file_ptr = fp; |
48 |
50 |
49 return 0; |
51 return 0; |
50 } |
52 } |
51 |
53 |
52 /** |
54 /** |
53 * Open the PNG image, setting up the I/O and returning the png_structp and png_infop |
55 * Open the PNG image, setting up the I/O and returning the png_structp and png_infop |
54 */ |
56 */ |
55 static int pt_image_open_png (struct pt_image *img, png_structp *png_ptr, png_infop *info_ptr) |
57 static int pt_image_open_png (struct pt_image *image, png_structp *png_ptr, png_infop *info_ptr) |
56 { |
58 { |
57 FILE *fp = NULL; |
59 FILE *fp = NULL; |
58 png_structp png = NULL; |
60 png_structp png = NULL; |
59 png_infop info = NULL; |
61 png_infop info = NULL; |
|
62 int err; |
60 |
63 |
61 // open I/O |
64 // open I/O |
62 if (pt_image_open_file(img, &fp)) |
65 if ((err = pt_image_open_file(image, &fp))) |
63 goto error; |
66 JUMP_ERROR(err); |
64 |
67 |
65 // create the struct |
68 // create the struct |
66 if ((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) |
69 if ((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) |
67 goto error; |
70 JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE); |
68 |
71 |
69 // create the info |
72 // create the info |
70 if ((info = png_create_info_struct(png)) == NULL) |
73 if ((info = png_create_info_struct(png)) == NULL) |
71 goto error; |
74 JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE); |
72 |
75 |
73 // setup error trap for the I/O |
76 // setup error trap for the I/O |
74 if (setjmp(png_jmpbuf(png))) |
77 if (setjmp(png_jmpbuf(png))) |
75 goto error; |
78 JUMP_SET_ERROR(err, PT_ERR_PNG); |
76 |
79 |
77 // setup I/O to FILE |
80 // setup I/O to FILE |
78 png_init_io(png, fp); |
81 png_init_io(png, fp); |
79 |
82 |
80 // ok |
83 // ok |
81 // XXX: what to do with fp? |
84 // XXX: what to do with fp? Should fclose() when done? |
82 *png_ptr = png; |
85 *png_ptr = png; |
83 *info_ptr = info; |
86 *info_ptr = info; |
84 |
87 |
85 return 0; |
88 return 0; |
86 |
89 |
113 */ |
116 */ |
114 static int pt_image_update_cache (struct pt_image *image) |
117 static int pt_image_update_cache (struct pt_image *image) |
115 { |
118 { |
116 png_structp png; |
119 png_structp png; |
117 png_infop info; |
120 png_infop info; |
|
121 int err = 0; |
118 |
122 |
119 // pre-check enabled |
123 // pre-check enabled |
120 if (!(image->cache->mode & PT_OPEN_UPDATE)) { |
124 if (!(image->cache->mode & PT_OPEN_UPDATE)) |
121 errno = EPERM; |
125 RETURN_ERROR_ERRNO(PT_ERR_OPEN_MODE, EACCES); |
122 return -1; |
|
123 } |
|
124 |
126 |
125 // open .png |
127 // open .png |
126 if (pt_image_open_png(image, &png, &info)) |
128 if ((err = pt_image_open_png(image, &png, &info))) |
127 return -1; |
129 return err; |
128 |
130 |
129 // setup error trap |
131 // setup error trap |
130 if (setjmp(png_jmpbuf(png))) |
132 if (setjmp(png_jmpbuf(png))) |
131 goto error; |
133 JUMP_SET_ERROR(err, PT_ERR_PNG); |
132 |
134 |
133 // read meta-info |
135 // read meta-info |
134 png_read_info(png, info); |
136 png_read_info(png, info); |
135 |
137 |
136 // update our meta-info |
138 // update our meta-info |
137 if (pt_image_update_info(image, png, info)) |
139 if ((err = pt_image_update_info(image, png, info))) |
138 goto error; |
140 JUMP_ERROR(err); |
139 |
141 |
140 // pass to cache object |
142 // pass to cache object |
141 if (pt_cache_update_png(image->cache, png, info)) |
143 if ((err = pt_cache_update_png(image->cache, png, info))) |
142 goto error; |
144 JUMP_ERROR(err); |
143 |
145 |
144 // finish off, ignore trailing data |
146 // finish off, ignore trailing data |
145 png_read_end(png, NULL); |
147 png_read_end(png, NULL); |
146 |
148 |
|
149 error: |
147 // clean up |
150 // clean up |
|
151 // XXX: we need to close the fopen'd .png |
148 png_destroy_read_struct(&png, &info, NULL); |
152 png_destroy_read_struct(&png, &info, NULL); |
149 |
153 |
150 return 0; |
154 return err; |
151 |
|
152 error: |
|
153 // clean up |
|
154 png_destroy_read_struct(&png, &info, NULL); |
|
155 |
|
156 return -1; |
|
157 } |
155 } |
158 |
156 |
159 /** |
157 /** |
160 * Build a filesystem path representing the appropriate path for this image's cache entry, and store it in the given |
158 * Build a filesystem path representing the appropriate path for this image's cache entry, and store it in the given |
161 * buffer. |
159 * buffer. |
162 */ |
160 */ |
163 static int pt_image_cache_path (struct pt_image *image, char *buf, size_t len) |
161 static int pt_image_cache_path (struct pt_image *image, char *buf, size_t len) |
164 { |
162 { |
165 return path_with_fext(image->path, buf, len, ".cache"); |
163 if (path_with_fext(image->path, buf, len, ".cache")) |
|
164 RETURN_ERROR(PT_ERR_PATH); |
|
165 |
|
166 return 0; |
166 } |
167 } |
167 |
168 |
168 int pt_image_open (struct pt_image **image_ptr, struct pt_ctx *ctx, const char *path, int cache_mode) |
169 int pt_image_open (struct pt_image **image_ptr, struct pt_ctx *ctx, const char *path, int cache_mode) |
169 { |
170 { |
170 struct pt_image *image; |
171 struct pt_image *image; |
171 char cache_path[1024]; |
172 char cache_path[1024]; |
|
173 int err; |
172 |
174 |
173 // XXX: verify that the path exists and looks like a PNG file |
175 // XXX: verify that the path exists and looks like a PNG file |
174 |
176 |
175 // alloc |
177 // alloc |
176 if (pt_image_new(&image, ctx, path)) |
178 if ((err = pt_image_new(&image, ctx, path))) |
177 return -1; |
179 return err; |
178 |
180 |
179 // compute cache file path |
181 // compute cache file path |
180 if (pt_image_cache_path(image, cache_path, sizeof(cache_path))) |
182 if ((err = pt_image_cache_path(image, cache_path, sizeof(cache_path)))) |
181 goto error; |
183 JUMP_ERROR(err); |
182 |
184 |
183 // create the cache object for this image (doesn't yet open it) |
185 // create the cache object for this image (doesn't yet open it) |
184 if (pt_cache_new(&image->cache, cache_path, cache_mode)) |
186 if ((err = pt_cache_new(&image->cache, cache_path, cache_mode))) |
185 goto error; |
187 JUMP_ERROR(err); |
186 |
188 |
187 // ok, ready for access |
189 // ok, ready for access |
188 *image_ptr = image; |
190 *image_ptr = image; |
189 |
191 |
190 return 0; |
192 return 0; |
191 |
193 |
192 error: |
194 error: |
193 pt_image_destroy(image); |
195 pt_image_destroy(image); |
194 |
196 |
195 return -1; |
197 return err; |
196 } |
198 } |
197 |
199 |
198 int pt_image_info (struct pt_image *image, const struct pt_image_info **info_ptr) |
200 int pt_image_info (struct pt_image *image, const struct pt_image_info **info_ptr) |
199 { |
201 { |
|
202 int err; |
|
203 |
200 // update info |
204 // update info |
201 if (pt_cache_info(image->cache, &image->info)) |
205 if ((err = pt_cache_info(image->cache, &image->info))) |
202 return -1; |
206 return err; |
203 |
207 |
204 // return pointer |
208 // return pointer |
205 *info_ptr = &image->info; |
209 *info_ptr = &image->info; |
206 |
210 |
207 return 0; |
211 return 0; |
219 |
223 |
220 int pt_image_tile (struct pt_image *image, const struct pt_tile_info *tile_info, FILE *out) |
224 int pt_image_tile (struct pt_image *image, const struct pt_tile_info *tile_info, FILE *out) |
221 { |
225 { |
222 png_structp png = NULL; |
226 png_structp png = NULL; |
223 png_infop info = NULL; |
227 png_infop info = NULL; |
|
228 int err = 0; |
224 |
229 |
225 // open PNG writer |
230 // open PNG writer |
226 if ((png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) |
231 if ((png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) |
227 goto error; |
232 JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE); |
228 |
233 |
229 if ((info = png_create_info_struct(png)) == NULL) |
234 if ((info = png_create_info_struct(png)) == NULL) |
230 goto error; |
235 JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE); |
231 |
236 |
232 // libpng error trap |
237 // libpng error trap |
233 if (setjmp(png_jmpbuf(png))) |
238 if (setjmp(png_jmpbuf(png))) |
234 goto error; |
239 JUMP_SET_ERROR(err, PT_ERR_PNG); |
235 |
240 |
236 // setup IO |
241 // setup IO |
237 png_init_io(png, out); |
242 png_init_io(png, out); |
238 |
243 |
239 // render tile |
244 // render tile |
240 if (pt_cache_tile_png(image->cache, png, info, tile_info)) |
245 if ((err = pt_cache_tile_png(image->cache, png, info, tile_info))) |
241 goto error; |
246 JUMP_ERROR(err); |
242 |
247 |
243 // done |
248 // done |
244 png_write_end(png, info); |
249 png_write_end(png, info); |
245 |
250 |
|
251 error: |
246 // cleanup |
252 // cleanup |
247 png_destroy_write_struct(&png, &info); |
253 png_destroy_write_struct(&png, &info); |
248 |
254 |
249 return 0; |
255 return err; |
250 |
|
251 error: |
|
252 // cleanup |
|
253 png_destroy_write_struct(&png, &info); |
|
254 |
|
255 return -1; |
|
256 } |
256 } |
257 |
257 |
258 void pt_image_destroy (struct pt_image *image) |
258 void pt_image_destroy (struct pt_image *image) |
259 { |
259 { |
260 free(image->path); |
260 free(image->path); |