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