2 * Copyright (C) 20019 - The Geeqie Team
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.
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.
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.
25 #include "image-load-j2k.h"
30 #include <gdk-pixbuf/gdk-pixbuf.h>
31 #include <glib-object.h>
36 #include "image-load.h"
43 struct ImageLoaderJ2K : public ImageLoaderBackend
46 ~ImageLoaderJ2K() override;
48 void init(AreaUpdatedCb area_updated_cb, SizePreparedCb size_prepared_cb, AreaPreparedCb area_prepared_cb, gpointer data) override;
49 gboolean write(const guchar *buf, gsize &chunk_size, gsize count, GError **error) override;
50 GdkPixbuf *get_pixbuf() override;
51 gchar *get_format_name() override;
52 gchar **get_format_mime_types() override;
55 AreaUpdatedCb area_updated_cb;
61 void free_buffer(guchar *pixels, gpointer)
66 struct opj_buffer_info_t {
72 OPJ_SIZE_T opj_read_from_buffer (void* pdst, OPJ_SIZE_T len, opj_buffer_info_t* psrc)
74 OPJ_SIZE_T n = psrc->buf + psrc->len - psrc->cur;
81 memcpy (pdst, psrc->cur, n);
85 n = static_cast<OPJ_SIZE_T>(-1);
90 OPJ_SIZE_T opj_write_to_buffer (void* p_buffer, OPJ_SIZE_T p_nb_bytes,
91 opj_buffer_info_t* p_source_buffer)
93 void* pbuf = p_source_buffer->buf;
94 void* pcur = p_source_buffer->cur;
96 OPJ_SIZE_T len = p_source_buffer->len;
101 OPJ_SIZE_T dist = static_cast<guchar *>(pcur) - static_cast<guchar *>(pbuf);
102 OPJ_SIZE_T n = len - dist;
103 g_assert (dist <= len);
105 while (n < p_nb_bytes)
111 if (len != p_source_buffer->len)
116 return static_cast<OPJ_SIZE_T>(-1);
118 if (p_source_buffer->buf)
120 memcpy (pbuf, p_source_buffer->buf, dist);
121 free (p_source_buffer->buf);
124 p_source_buffer->buf = static_cast<OPJ_BYTE *>(pbuf);
125 p_source_buffer->cur = static_cast<guchar *>(pbuf) + dist;
126 p_source_buffer->len = len;
129 memcpy (p_source_buffer->cur, p_buffer, p_nb_bytes);
130 p_source_buffer->cur += p_nb_bytes;
135 OPJ_SIZE_T opj_skip_from_buffer (OPJ_SIZE_T len, opj_buffer_info_t* psrc)
137 OPJ_SIZE_T n = psrc->buf + psrc->len - psrc->cur;
147 n = static_cast<OPJ_SIZE_T>(-1);
152 OPJ_BOOL opj_seek_from_buffer (OPJ_OFF_T len, opj_buffer_info_t* psrc)
154 OPJ_SIZE_T n = psrc->len;
156 if (n > static_cast<gulong>(len))
159 psrc->cur = psrc->buf + n;
164 opj_stream_t* OPJ_CALLCONV opj_stream_create_buffer_stream (opj_buffer_info_t* psrc, OPJ_BOOL input)
169 opj_stream_t* ps = opj_stream_default_create (input);
174 opj_stream_set_user_data (ps, psrc, nullptr);
175 opj_stream_set_user_data_length (ps, psrc->len);
178 opj_stream_set_read_function (
179 ps, reinterpret_cast<opj_stream_read_fn>(opj_read_from_buffer));
181 opj_stream_set_write_function(
182 ps,reinterpret_cast<opj_stream_write_fn>(opj_write_to_buffer));
184 opj_stream_set_skip_function (
185 ps, reinterpret_cast<opj_stream_skip_fn>(opj_skip_from_buffer));
187 opj_stream_set_seek_function (
188 ps, reinterpret_cast<opj_stream_seek_fn>(opj_seek_from_buffer));
193 gboolean ImageLoaderJ2K::write(const guchar *buf, gsize &chunk_size, gsize count, GError **)
195 opj_stream_t *stream;
197 opj_dparameters_t parameters;
206 gint bytes_per_pixel;
207 opj_buffer_info_t *decode_buffer;
214 buf_copy = static_cast<guchar *>(g_malloc(count));
215 memcpy(buf_copy, buf, count);
217 decode_buffer = g_new0(opj_buffer_info_t, 1);
218 decode_buffer->buf = buf_copy;
219 decode_buffer->len = count;
220 decode_buffer->cur = buf_copy;
222 stream = opj_stream_create_buffer_stream(decode_buffer, OPJ_TRUE);
226 log_printf(_("Could not open file for reading"));
230 if (memcmp(buf_copy + 20, "jp2", 3) == 0)
232 codec = opj_create_decompress(OPJ_CODEC_JP2);
236 log_printf(_("Unknown jpeg2000 decoder type"));
240 opj_set_default_decoder_parameters(¶meters);
241 if (opj_setup_decoder (codec, ¶meters) != OPJ_TRUE)
243 log_printf(_("Couldn't set parameters on decoder for file."));
247 opj_codec_set_threads(codec, get_cpu_cores());
249 if (opj_read_header(stream, codec, &image) != OPJ_TRUE)
251 log_printf(_("Couldn't read JP2 header from file"));
255 if (opj_decode(codec, stream, image) != OPJ_TRUE)
257 log_printf(_("Couldn't decode JP2 image in file"));
261 if (opj_end_decompress(codec, stream) != OPJ_TRUE)
263 log_printf(_("Couldn't decompress JP2 image in file"));
267 num_components = image->numcomps;
268 if (num_components != 3)
270 log_printf(_("JP2 image not rgb"));
274 width = image->comps[0].w;
275 height = image->comps[0].h;
279 pixels = g_new0(guchar, width * bytes_per_pixel * height);
280 for (i = 0; i < height; i++)
282 for (j = 0; j < num_components; j++)
284 for (k = 0; k < width; k++)
286 pixels[(k * bytes_per_pixel + j) + (i * width * bytes_per_pixel)] = image->comps[j].data[i * width + k];
291 pixbuf = gdk_pixbuf_new_from_data(pixels, GDK_COLORSPACE_RGB, FALSE , 8, width, height, width * bytes_per_pixel, free_buffer, nullptr);
293 area_updated_cb(nullptr, 0, 0, width, height, data);
295 g_free(decode_buffer);
298 opj_image_destroy (image);
300 opj_destroy_codec (codec);
302 opj_stream_destroy (stream);
308 void ImageLoaderJ2K::init(AreaUpdatedCb area_updated_cb, SizePreparedCb, AreaPreparedCb, gpointer data)
310 this->area_updated_cb = area_updated_cb;
314 GdkPixbuf *ImageLoaderJ2K::get_pixbuf()
319 gchar *ImageLoaderJ2K::get_format_name()
321 return g_strdup("j2k");
324 gchar **ImageLoaderJ2K::get_format_mime_types()
326 static const gchar *mime[] = {"image/jp2", nullptr};
327 return g_strdupv(const_cast<gchar **>(mime));
330 ImageLoaderJ2K::~ImageLoaderJ2K()
332 if (pixbuf) g_object_unref(pixbuf);
337 std::unique_ptr<ImageLoaderBackend> get_image_loader_backend_j2k()
339 return std::make_unique<ImageLoaderJ2K>();
343 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */