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