Include jpeg2000 loader
[geeqie.git] / src / image_load_j2k.c
1 /*
2  * Copyright (C) 20019 - The Geeqie Team
3  *
4  * Author: Colin Clark
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "main.h"
22
23 #include "image-load.h"
24 #include "image_load_j2k.h"
25
26 #include "misc.h"
27
28 #include <sys/sysinfo.h>
29 #ifdef HAVE_J2K
30 #include "openjpeg.h"
31
32 typedef struct _ImageLoaderJ2K ImageLoaderJ2K;
33 struct _ImageLoaderJ2K {
34         ImageLoaderBackendCbAreaUpdated area_updated_cb;
35         ImageLoaderBackendCbSize size_cb;
36         ImageLoaderBackendCbAreaPrepared area_prepared_cb;
37         gpointer data;
38         GdkPixbuf *pixbuf;
39         guint requested_width;
40         guint requested_height;
41         gboolean abort;
42 };
43
44 static void free_buffer(guchar *pixels, gpointer data)
45 {
46         g_free (pixels);
47 }
48
49 typedef struct opj_buffer_info {
50     OPJ_BYTE* buf;
51     OPJ_BYTE* cur;
52     OPJ_SIZE_T len;
53 } opj_buffer_info_t;
54
55 static OPJ_SIZE_T opj_read_from_buffer (void* pdst, OPJ_SIZE_T len, opj_buffer_info_t* psrc)
56 {
57     OPJ_SIZE_T n = psrc->buf + psrc->len - psrc->cur;
58
59     if (n) {
60         if (n > len)
61             n = len;
62
63         memcpy (pdst, psrc->cur, n);
64         psrc->cur += n;
65     }
66     else
67         n = (OPJ_SIZE_T)-1;
68
69     return n;
70 }
71
72 static OPJ_SIZE_T opj_write_to_buffer (void* p_buffer, OPJ_SIZE_T p_nb_bytes,
73                      opj_buffer_info_t* p_source_buffer)
74 {
75     void* pbuf = p_source_buffer->buf;
76     void* pcur = p_source_buffer->cur;
77
78     OPJ_SIZE_T len = p_source_buffer->len;
79
80     if (0 == len)
81         len = 1;
82
83     OPJ_SIZE_T dist = pcur - pbuf, n = len - dist;
84     g_assert (dist <= len);
85
86     while (n < p_nb_bytes) {
87         len *= 2;
88         n = len - dist;
89     }
90
91     if (len != p_source_buffer->len) {
92         pbuf = malloc (len);
93
94         if (0 == pbuf)
95             return (OPJ_SIZE_T)-1;
96
97         if (p_source_buffer->buf) {
98             memcpy (pbuf, p_source_buffer->buf, dist);
99             free (p_source_buffer->buf);
100         }
101
102         p_source_buffer->buf = pbuf;
103         p_source_buffer->cur = pbuf + dist;
104         p_source_buffer->len = len;
105     }
106
107     memcpy (p_source_buffer->cur, p_buffer, p_nb_bytes);
108     p_source_buffer->cur += p_nb_bytes;
109
110     return p_nb_bytes;
111 }
112
113 static OPJ_SIZE_T opj_skip_from_buffer (OPJ_SIZE_T len, opj_buffer_info_t* psrc)
114 {
115     OPJ_SIZE_T n = psrc->buf + psrc->len - psrc->cur;
116
117     if (n) {
118         if (n > len)
119             n = len;
120
121         psrc->cur += len;
122     }
123     else
124         n = (OPJ_SIZE_T)-1;
125
126     return n;
127 }
128
129 static OPJ_BOOL opj_seek_from_buffer (OPJ_OFF_T len, opj_buffer_info_t* psrc)
130 {
131     OPJ_SIZE_T n = psrc->len;
132
133     if (n > len)
134         n = len;
135
136     psrc->cur = psrc->buf + n;
137
138     return OPJ_TRUE;
139 }
140
141 opj_stream_t* OPJ_CALLCONV opj_stream_create_buffer_stream (opj_buffer_info_t* psrc, OPJ_BOOL input)
142 {
143     if (!psrc)
144         return 0;
145
146     opj_stream_t* ps = opj_stream_default_create (input);
147
148     if (0 == ps)
149         return 0;
150
151     opj_stream_set_user_data        (ps, psrc, 0);
152     opj_stream_set_user_data_length (ps, psrc->len);
153
154     if (input)
155         opj_stream_set_read_function (
156             ps, (opj_stream_read_fn)opj_read_from_buffer);
157     else
158         opj_stream_set_write_function(
159             ps,(opj_stream_write_fn) opj_write_to_buffer);
160
161     opj_stream_set_skip_function (
162         ps, (opj_stream_skip_fn)opj_skip_from_buffer);
163
164     opj_stream_set_seek_function (
165         ps, (opj_stream_seek_fn)opj_seek_from_buffer);
166
167     return ps;
168 }
169
170 static gboolean image_loader_j2k_load(gpointer loader, const guchar *buf, gsize count, GError **error)
171 {
172         ImageLoaderJ2K *ld = (ImageLoaderJ2K *) loader;
173         ImageLoader *il = ld->data;
174         opj_stream_t *stream;
175         opj_codec_t *codec;
176         opj_dparameters_t parameters;
177         opj_image_t *image;
178         gint width;
179         gint height;
180         gint num_components;
181         gint i, j, k;
182         guchar *pixels;
183         gint  bytes_per_pixel;
184         opj_buffer_info_t *decode_buffer;
185     guchar *buf_copy;
186
187         stream = NULL;
188         codec = NULL;
189         image = NULL;
190
191         buf_copy = (guchar *) g_malloc(count);
192         memcpy(buf_copy, buf, count);
193
194         decode_buffer = g_new0(opj_buffer_info_t, 1);
195         decode_buffer->buf = buf_copy;
196         decode_buffer->len = count;
197         decode_buffer->cur = buf_copy;
198
199         stream = opj_stream_create_buffer_stream(decode_buffer, OPJ_TRUE);
200
201         if (!stream)
202                 {
203                 log_printf(_("Could not open file for reading"));
204                 return FALSE;
205                 }
206
207         if (memcmp(buf_copy + 20, "jp2", 3) == 0)
208                 {
209                 codec = opj_create_decompress(OPJ_CODEC_JP2);
210                 }
211         else
212                 {
213                 log_printf(_("Unknown jpeg2000 decoder type"));
214                 return FALSE;
215                 }
216
217         opj_set_default_decoder_parameters(&parameters);
218         if (opj_setup_decoder (codec, &parameters) != OPJ_TRUE)
219                 {
220                 log_printf(_("Couldn't set parameters on decoder for file."));
221                 return FALSE;
222                 }
223
224         opj_codec_set_threads(codec, get_cpu_cores());
225
226         if (opj_read_header(stream, codec, &image) != OPJ_TRUE)
227                 {
228                 log_printf(_("Couldn't read JP2 header from file"));
229                 return FALSE;
230                 }
231
232         if (opj_decode(codec, stream, image) != OPJ_TRUE)
233                 {
234                 log_printf(_("Couldn't decode JP2 image in file"));
235                 return FALSE;
236                 }
237
238         if (opj_end_decompress(codec, stream) != OPJ_TRUE)
239                 {
240                 log_printf(_("Couldn't decompress JP2 image in file"));
241                 return FALSE;
242                 }
243
244         num_components = image->numcomps;
245         if (num_components != 3)
246                 {
247                 log_printf(_("JP2 image not rgb"));
248                 return FALSE;
249                 }
250
251         width = image->comps[0].w;
252         height = image->comps[0].h;
253
254         bytes_per_pixel = 3;
255
256         pixels = g_new0(guchar, width * bytes_per_pixel * height);
257         for (i = 0; i < height; i++)
258                 {
259                 for (j = 0; j < num_components; j++)
260                         {
261                         for (k = 0; k < width; k++)
262                                 {
263                                 pixels[(k * bytes_per_pixel + j) + (i * width * bytes_per_pixel)] =   image->comps[j].data[i * width + k];
264                                 }
265                         }
266                 }
267
268         ld->pixbuf = gdk_pixbuf_new_from_data(pixels, GDK_COLORSPACE_RGB, FALSE , 8, width, height, width * bytes_per_pixel, free_buffer, NULL);
269
270         ld->area_updated_cb(loader, 0, 0, width, height, ld->data);
271
272         g_free(decode_buffer);
273         g_free(buf_copy);
274         if (image)
275                 opj_image_destroy (image);
276         if (codec)
277                 opj_destroy_codec (codec);
278         if (stream)
279                 opj_stream_destroy (stream);
280
281         return TRUE;
282 }
283
284 static gpointer image_loader_j2k_new(ImageLoaderBackendCbAreaUpdated area_updated_cb, ImageLoaderBackendCbSize size_cb, ImageLoaderBackendCbAreaPrepared area_prepared_cb, gpointer data)
285 {
286         ImageLoaderJ2K *loader = g_new0(ImageLoaderJ2K, 1);
287         loader->area_updated_cb = area_updated_cb;
288         loader->size_cb = size_cb;
289         loader->area_prepared_cb = area_prepared_cb;
290         loader->data = data;
291         return (gpointer) loader;
292 }
293
294 static void image_loader_j2k_set_size(gpointer loader, int width, int height)
295 {
296         ImageLoaderJ2K *ld = (ImageLoaderJ2K *) loader;
297         ld->requested_width = width;
298         ld->requested_height = height;
299 }
300
301 static GdkPixbuf* image_loader_j2k_get_pixbuf(gpointer loader)
302 {
303         ImageLoaderJ2K *ld = (ImageLoaderJ2K *) loader;
304         return ld->pixbuf;
305 }
306
307 static gchar* image_loader_j2k_get_format_name(gpointer loader)
308 {
309         return g_strdup("j2k");
310 }
311
312 static gchar** image_loader_j2k_get_format_mime_types(gpointer loader)
313 {
314         static gchar *mime[] = {"image/jp2", NULL};
315         return g_strdupv(mime);
316 }
317
318 static gboolean image_loader_j2k_close(gpointer loader, GError **error)
319 {
320         return TRUE;
321 }
322
323 static void image_loader_j2k_abort(gpointer loader)
324 {
325         ImageLoaderJ2K *ld = (ImageLoaderJ2K *) loader;
326         ld->abort = TRUE;
327 }
328
329 static void image_loader_j2k_free(gpointer loader)
330 {
331         ImageLoaderJ2K *ld = (ImageLoaderJ2K *) loader;
332         if (ld->pixbuf) g_object_unref(ld->pixbuf);
333         g_free(ld);
334 }
335
336 void image_loader_backend_set_j2k(ImageLoaderBackend *funcs)
337 {
338         funcs->loader_new = image_loader_j2k_new;
339         funcs->set_size = image_loader_j2k_set_size;
340         funcs->load = image_loader_j2k_load;
341         funcs->write = NULL;
342         funcs->get_pixbuf = image_loader_j2k_get_pixbuf;
343         funcs->close = image_loader_j2k_close;
344         funcs->abort = image_loader_j2k_abort;
345         funcs->free = image_loader_j2k_free;
346         funcs->get_format_name = image_loader_j2k_get_format_name;
347         funcs->get_format_mime_types = image_loader_j2k_get_format_mime_types;
348 }
349
350 #endif
351 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */