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