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