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