]> mj.ucw.cz Git - libucw.git/blob - images/io-main.c
Merge with git+ssh://git.ucw.cz/projects/sherlock/GIT/sherlock.git
[libucw.git] / images / io-main.c
1 /*
2  *      Image Library -- Image compression/decompression interface
3  *
4  *      (c) 2006 Pavel Charvat <pchar@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #undef LOCAL_DEBUG
11
12 #include "lib/lib.h"
13 #include "lib/mempool.h"
14 #include "images/images.h"
15 #include "images/error.h"
16 #include "images/io-main.h"
17
18 #include <string.h>
19
20 int
21 image_io_init(struct image_context *ctx, struct image_io *io)
22 {
23   DBG("image_io_init()");
24   bzero(io, sizeof(*io));
25   io->context = ctx;
26 #ifdef CONFIG_IMAGES_LIBJPEG
27   if (!libjpeg_init(io))
28     goto libjpeg_failed;
29 #endif
30 #ifdef CONFIG_IMAGES_LIBPNG
31   if (!libpng_init(io))
32     goto libpng_failed;
33 #endif
34 #ifdef CONFIG_IMAGES_LIBUNGIF
35   if (!libungif_init(io))
36     goto libungif_failed;
37 #endif
38 #ifdef CONFIG_IMAGES_LIBMAGICK
39   if (!libmagick_init(io))
40     goto libmagick_failed;
41 #endif
42   io->internal_pool = mp_new(1024);
43   return 1;
44 #ifdef CONFIG_IMAGES_LIBMAGICK
45   libmagick_cleanup(io);
46 libmagick_failed:
47 #endif
48 #ifdef CONFIG_IMAGES_LIBUNGIF
49   libungif_cleanup(io);
50 libungif_failed:
51 #endif
52 #ifdef CONFIG_IMAGES_LIBPNG
53   libpng_cleanup(io);
54 libpng_failed:  
55 #endif
56 #ifdef CONFIG_IMAGES_LIBJPEG
57   libjpeg_cleanup(io);
58 libjpeg_failed:
59 #endif
60   return 0;
61 }
62
63 static inline void
64 image_io_read_cancel(struct image_io *io)
65 {
66   if (io->read_cancel)
67     {
68       io->read_cancel(io);
69       io->read_cancel = NULL;
70     }
71 }
72
73 static inline void
74 image_io_image_destroy(struct image_io *io)
75 {
76   if (io->image && (io->flags & IMAGE_IO_NEED_DESTROY))
77     {
78       image_destroy(io->image);
79       io->flags &= ~IMAGE_IO_NEED_DESTROY;
80       io->image = NULL;
81     }
82 }
83
84 void
85 image_io_cleanup(struct image_io *io)
86 {
87   DBG("image_io_cleanup()");
88   image_io_read_cancel(io);
89   image_io_image_destroy(io);
90 #ifdef CONFIG_IMAGES_LIBMAGICK
91   libmagick_cleanup(io);
92 #endif
93 #ifdef CONFIG_IMAGES_LIBUNGIF
94   libungif_cleanup(io);
95 #endif
96 #ifdef CONFIG_IMAGES_LIBPNG
97   libpng_cleanup(io);
98 #endif
99 #ifdef CONFIG_IMAGES_LIBJPEG
100   libjpeg_cleanup(io);
101 #endif
102   mp_delete(io->internal_pool);
103 }
104
105 void
106 image_io_reset(struct image_io *io)
107 {
108   DBG("image_io_reset()");
109   image_io_read_cancel(io);
110   image_io_image_destroy(io);
111   struct mempool *pool = io->internal_pool;
112   struct image_context *ctx = io->context;
113   mp_flush(pool);
114   bzero(io, sizeof(*io));
115   io->internal_pool = pool;
116   io->context = ctx;
117 }
118
119 int
120 image_io_read_header(struct image_io *io)
121 {
122   DBG("image_io_read_header()");
123   image_io_read_cancel(io);
124   image_io_image_destroy(io);
125   switch (io->format) {
126     case IMAGE_FORMAT_JPEG:
127 #if defined(CONFIG_IMAGES_LIBJPEG)
128       return libjpeg_read_header(io);
129 #elif defined(CONFIG_IMAGES_LIBMAGICK)
130       return libmagick_read_header(io);
131 #endif
132       break;
133
134     case IMAGE_FORMAT_PNG:
135 #if defined(CONFIG_IMAGES_LIBPNG)
136       return libpng_read_header(io);
137 #elif defined(CONFIG_IMAGES_LIBMAGICK)
138       return libmagick_read_header(io);
139 #endif
140       break;
141
142     case IMAGE_FORMAT_GIF:
143 #if defined(CONFIG_IMAGES_LIBUNGIF) || defined(CONFIG_IMAGES_LIBGIF)
144       return libungif_read_header(io);
145 #elif defined(CONFIG_IMAGES_LIBMAGICK)
146       return libmagick_read_header(io);
147 #endif
148       break;
149
150     case IMAGE_FORMAT_UNDEFINED:
151 #if defined (CONFIG_IMAGES_LIBMAGICK)
152       return libmagick_read_header(io);
153 #endif
154       break;
155
156     default:
157       ASSERT(0);
158   }
159   IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_FILE_FORMAT, "Image format not supported.");
160   return 0;
161 }
162
163 struct image *
164 image_io_read_data(struct image_io *io, int ref)
165 {
166   DBG("image_io_read_data()");
167   ASSERT(io->read_cancel);
168   io->read_cancel = NULL;
169   int result;
170   switch (io->format) {
171     case IMAGE_FORMAT_JPEG:
172 #if defined(CONFIG_IMAGES_LIBJPEG)
173       result = libjpeg_read_data(io);
174 #elif defined(CONFIG_IMAGES_LIBMAGICK)
175       result = libmagick_read_data(io);
176 #else
177       ASSERT(0);
178 #endif
179       break;
180
181     case IMAGE_FORMAT_PNG:
182 #if defined(CONFIG_IMAGES_LIBPNG)
183       result = libpng_read_data(io);
184 #elif defined(CONFIG_IMAGES_LIBMAGICK)
185       result = libmagick_read_data(io);
186 #else
187       ASSERT(0);
188 #endif
189       break;
190
191     case IMAGE_FORMAT_GIF:
192 #if defined(CONFIG_IMAGES_LIBUNGIF) || defined(CONFIG_IMAGES_LIBGIF)
193       result = libungif_read_data(io);
194 #elif defined(CONFIG_IMAGES_LIBMAGICK)
195       result = libmagick_read_data(io);
196 #else
197       ASSERT(0);
198 #endif
199       break;
200
201     case IMAGE_FORMAT_UNDEFINED:
202 #if defined(CONFIG_IMAGES_LIBMAGICK)
203       result = libmagick_read_data(io);
204 #else
205       ASSERT(0);
206 #endif
207       break;
208
209     default:
210       ASSERT(0);
211   }
212   if (result)
213     {
214       if (!ref)
215         io->flags |= IMAGE_IO_NEED_DESTROY;
216       else
217         io->flags &= ~IMAGE_IO_NEED_DESTROY;
218       return io->image;
219     }
220   else
221     return NULL;
222 }
223
224 struct image *
225 image_io_read(struct image_io *io, int ref)
226 {
227   if (!image_io_read_header(io))
228     return NULL;
229   return image_io_read_data(io, ref);
230 }
231
232 int
233 image_io_write(struct image_io *io)
234 {
235   DBG("image_io_write()");
236   image_io_read_cancel(io);
237   switch (io->format) {
238     case IMAGE_FORMAT_JPEG:
239 #if defined(CONFIG_IMAGES_LIBJPEG)
240       return libjpeg_write(io);
241 #elif defined(CONFIG_IMAGES_LIBMAGICK)
242       return libmagick_write(io);
243 #endif
244       break;
245
246     case IMAGE_FORMAT_PNG:
247 #if defined(CONFIG_IMAGES_LIBPNG)
248       return libpng_write(io);
249 #elif defined(CONFIG_IMAGES_LIBMAGICK)
250       return libmagick_write(io);
251 #endif
252       break;
253
254     case IMAGE_FORMAT_GIF:
255 #if defined(CONFIG_IMAGES_LIBMAGICK)
256       return libmagick_write(io);
257 #endif
258       break;
259
260     default:
261       break;
262   }
263   IMAGE_ERROR(io->context, IMAGE_ERROR_INVALID_FILE_FORMAT, "Output format not supported.");
264   return 0;
265 }
266
267 byte *
268 image_format_to_extension(enum image_format format)
269 {
270   switch (format)
271     {
272       case IMAGE_FORMAT_JPEG:
273         return "jpg";
274       case IMAGE_FORMAT_PNG:
275         return "png";
276       case IMAGE_FORMAT_GIF:
277         return "gif";
278       default:
279         return NULL;
280     }
281 }
282
283 enum image_format
284 image_extension_to_format(byte *extension)
285 {
286   if (!strcasecmp(extension, "jpg"))
287     return IMAGE_FORMAT_JPEG;
288   if (!strcasecmp(extension, "jpeg"))
289     return IMAGE_FORMAT_JPEG;
290   if (!strcasecmp(extension, "png"))
291     return IMAGE_FORMAT_PNG;
292   if (!strcasecmp(extension, "gif"))
293     return IMAGE_FORMAT_GIF;
294   return IMAGE_FORMAT_UNDEFINED;
295 }
296
297 enum image_format
298 image_file_name_to_format(byte *file_name)
299 {
300   byte *extension = strrchr(file_name, '.');
301   return extension ? image_extension_to_format(extension + 1) : IMAGE_FORMAT_UNDEFINED;
302 }
303
304 struct image *
305 image_io_read_data_prepare(struct image_io_read_data_internals *rdi, struct image_io *io, uns cols, uns rows, uns flags)
306 {
307   DBG("image_io_read_data_prepare()");
308   if (rdi->need_transformations = io->cols != cols || io->rows != rows ||
309       ((io->flags ^ flags) & IMAGE_NEW_FLAGS))
310     return rdi->image = image_new(io->context, cols, rows, flags & IMAGE_IO_IMAGE_FLAGS, NULL);
311   else
312     return rdi->image = image_new(io->context, io->cols, io->rows, io->flags & IMAGE_IO_IMAGE_FLAGS, io->pool);
313 }
314
315 int
316 image_io_read_data_finish(struct image_io_read_data_internals *rdi, struct image_io *io)
317 {
318   DBG("image_io_read_data_finish()");
319   if (rdi->need_transformations)
320     {
321       /* Scale the image */
322       if (io->cols != rdi->image->cols || io->rows != rdi->image->rows)
323         {
324           DBG("Scaling image");
325           uns flags = rdi->image->flags;
326           if (!(rdi->need_transformations = ((io->flags ^ rdi->image->flags) & (IMAGE_NEW_FLAGS & ~IMAGE_PIXELS_ALIGNED))))
327             flags = io->flags;
328           struct image *img = image_new(io->context, io->cols, io->rows, flags, rdi->need_transformations ? NULL : io->pool);
329           if (unlikely(!img))
330             {
331               image_destroy(rdi->image);
332               return 0;
333             }
334           if (unlikely(!image_scale(io->context, img, rdi->image)))
335             {
336               image_destroy(rdi->image);
337               image_destroy(img);
338               return 0;
339             }
340           image_destroy(rdi->image);
341           rdi->image = img;
342         }
343
344       /* Merge with background */
345       if ((io->flags ^ rdi->image->flags) & IMAGE_ALPHA)
346         {
347           DBG("Applying background");
348           uns flags = rdi->image->flags & ~IMAGE_ALPHA;
349           if (!(rdi->need_transformations = (flags ^ io->flags) & (IMAGE_NEW_FLAGS & ~IMAGE_PIXELS_ALIGNED)))
350             flags = io->flags;
351           struct image *img = image_new(io->context, io->cols, io->rows, flags, rdi->need_transformations ? NULL : io->pool);
352           if (unlikely(!img))
353             {
354               image_destroy(rdi->image);
355               return 0;
356             }
357           if (unlikely(!image_apply_background(io->context, img, rdi->image, &io->background_color)))
358             {
359               image_destroy(rdi->image);
360               image_destroy(img);
361               return 0;
362             }
363           image_destroy(rdi->image);
364           rdi->image = img;
365         }
366
367       // FIXME: support for various color spaces
368
369       ASSERT(!rdi->need_transformations);
370     }
371
372   /* Success */
373   io->image = rdi->image;
374   return 1;
375 }
376
377 void
378 image_io_read_data_break(struct image_io_read_data_internals *rdi, struct image_io *io UNUSED)
379 {
380   DBG("image_io_read_data_break()");
381   if (rdi->image)
382     image_destroy(rdi->image);
383 }