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