workarounds for rendering differently sized components
[openjpeg.git] / OPJViewer / source / imagj2k.cpp
1 /*\r
2  * Copyright (c) 2007, Digital Signal Processing Laboratory, Universit� degli studi di Perugia (UPG), Italy\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without\r
6  * modification, are permitted provided that the following conditions\r
7  * are met:\r
8  * 1. Redistributions of source code must retain the above copyright\r
9  *    notice, this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright\r
11  *    notice, this list of conditions and the following disclaimer in the\r
12  *    documentation and/or other materials provided with the distribution.\r
13  *\r
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'\r
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\r
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
24  * POSSIBILITY OF SUCH DAMAGE.\r
25  */\r
26 /////////////////////////////////////////////////////////////////////////////\r
27 // Name:        imagj2k.cpp\r
28 // Purpose:     wxImage JPEG 2000 codestream handler\r
29 // Author:      Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik\r
30 // RCS-ID:      $Id: imagj2k.cpp,v 0.00 2007/02/08 23:59:00 MW Exp $\r
31 // Copyright:   (c) Giuseppe Baruffa\r
32 // Licence:     wxWindows licence\r
33 /////////////////////////////////////////////////////////////////////////////\r
34 \r
35 // For compilers that support precompilation, includes "wx.h".\r
36 #include "wx/wxprec.h"\r
37 \r
38 #ifdef __BORLANDC__\r
39     #pragma hdrstop\r
40 #endif\r
41 \r
42 #if wxUSE_IMAGE && wxUSE_LIBOPENJPEG\r
43 \r
44 #include "imagj2k.h"\r
45 \r
46 #ifndef WX_PRECOMP\r
47     #include "wx/log.h"\r
48     #include "wx/app.h"\r
49     #include "wx/intl.h"\r
50     #include "wx/bitmap.h"\r
51     #include "wx/module.h"\r
52 #endif\r
53 \r
54 #include "wx/filefn.h"\r
55 #include "wx/wfstream.h"\r
56 \r
57 // ----------------------------------------------------------------------------\r
58 // types\r
59 // ----------------------------------------------------------------------------\r
60 \r
61 \r
62 //-----------------------------------------------------------------------------\r
63 // wxJ2KHandler\r
64 //-----------------------------------------------------------------------------\r
65 \r
66 IMPLEMENT_DYNAMIC_CLASS(wxJ2KHandler,wxImageHandler)\r
67 \r
68 #if wxUSE_STREAMS\r
69 \r
70 //------------- JPEG 2000 Data Source Manager\r
71 \r
72 #define J2K_CFMT 0\r
73 #define JP2_CFMT 1\r
74 #define JPT_CFMT 2\r
75 #define MJ2_CFMT 3\r
76 #define PXM_DFMT 0\r
77 #define PGX_DFMT 1\r
78 #define BMP_DFMT 2\r
79 #define YUV_DFMT 3\r
80 \r
81 #define MAX_MESSAGE_LEN 200\r
82 \r
83 /* sample error callback expecting a FILE* client object */\r
84 void j2k_error_callback(const char *msg, void *client_data) {\r
85         int message_len = strlen(msg) - 1;\r
86         if (msg[message_len] != '\n')\r
87                 message_len = MAX_MESSAGE_LEN;\r
88     wxMutexGuiEnter();\r
89         wxLogMessage(wxT("[ERROR] %.*s"), message_len, msg);\r
90     wxMutexGuiLeave();\r
91 }\r
92 /* sample warning callback expecting a FILE* client object */\r
93 void j2k_warning_callback(const char *msg, void *client_data) {\r
94         int message_len = strlen(msg) - 1;\r
95         if (msg[message_len] != '\n')\r
96                 message_len = MAX_MESSAGE_LEN;\r
97     wxMutexGuiEnter();\r
98         wxLogMessage(wxT("[WARNING] %.*s"), message_len, msg);\r
99     wxMutexGuiLeave();\r
100 }\r
101 /* sample debug callback expecting no client object */\r
102 void j2k_info_callback(const char *msg, void *client_data) {\r
103         int message_len = strlen(msg) - 1;\r
104         if (msg[message_len] != '\n')\r
105                 message_len = MAX_MESSAGE_LEN;\r
106     wxMutexGuiEnter();\r
107         wxLogMessage(wxT("[INFO] %.*s"), message_len, msg);\r
108     wxMutexGuiLeave();\r
109 }\r
110 \r
111 // load the j2k codestream\r
112 bool wxJ2KHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index)\r
113 {\r
114         opj_dparameters_t parameters;   /* decompression parameters */\r
115         opj_event_mgr_t event_mgr;              /* event manager */\r
116         opj_image_t *opjimage = NULL;\r
117         unsigned char *src = NULL;\r
118     unsigned char *ptr;\r
119         int file_length;\r
120         int shiftbpp;\r
121         int c, tempcomps;\r
122 \r
123         // destroy the image\r
124     image->Destroy();\r
125 \r
126         /* handle to a decompressor */\r
127         opj_dinfo_t* dinfo = NULL;      \r
128         opj_cio_t *cio = NULL;\r
129 \r
130 \r
131         /* configure the event callbacks (not required) */\r
132         memset(&event_mgr, 0, sizeof(opj_event_mgr_t));\r
133         event_mgr.error_handler = j2k_error_callback;\r
134         event_mgr.warning_handler = j2k_warning_callback;\r
135         event_mgr.info_handler = j2k_info_callback;\r
136 \r
137         /* set decoding parameters to default values */\r
138         opj_set_default_decoder_parameters(&parameters);\r
139 \r
140         /* prepare parameters */\r
141         strncpy(parameters.infile, "", sizeof(parameters.infile)-1);\r
142         strncpy(parameters.outfile, "", sizeof(parameters.outfile)-1);\r
143         parameters.decod_format = J2K_CFMT;\r
144         parameters.cod_format = BMP_DFMT;\r
145         if (m_reducefactor)\r
146                 parameters.cp_reduce = m_reducefactor;\r
147         if (m_qualitylayers)\r
148                 parameters.cp_layer = m_qualitylayers;\r
149         /*if (n_components)\r
150                 parameters. = n_components;*/\r
151 \r
152         /* JPWL only */\r
153 #ifdef USE_JPWL\r
154         parameters.jpwl_exp_comps = m_expcomps;\r
155         parameters.jpwl_max_tiles = m_maxtiles;\r
156         parameters.jpwl_correct = m_enablejpwl;\r
157 #endif /* USE_JPWL */\r
158 \r
159         /* get a decoder handle */\r
160         dinfo = opj_create_decompress(CODEC_J2K);\r
161 \r
162         /* find length of the stream */\r
163         stream.SeekI(0, wxFromEnd);\r
164         file_length = (int) stream.TellI();\r
165 \r
166         /* get data */\r
167         stream.SeekI(0, wxFromStart);\r
168     src = (unsigned char *) malloc(file_length);\r
169         stream.Read(src, file_length);\r
170 \r
171         /* catch events using our callbacks and give a local context */\r
172         opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);\r
173 \r
174         /* setup the decoder decoding parameters using user parameters */\r
175         opj_setup_decoder(dinfo, &parameters);\r
176 \r
177         /* open a byte stream */\r
178         cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);\r
179 \r
180         /* decode the stream and fill the image structure */\r
181         opjimage = opj_decode(dinfo, cio);\r
182         if (!opjimage) {\r
183                 wxMutexGuiEnter();\r
184                 wxLogError(wxT("J2K: failed to decode image!"));\r
185                 wxMutexGuiLeave();\r
186                 opj_destroy_decompress(dinfo);\r
187                 opj_cio_close(cio);\r
188                 opj_image_destroy(opjimage);\r
189                 free(src);\r
190                 return false;\r
191         }\r
192 \r
193         /* close the byte stream */\r
194         opj_cio_close(cio);\r
195 \r
196         // check image components\r
197 \r
198         // check image depth (only on the first one, for now)\r
199         shiftbpp = opjimage->comps[0].prec - 8;\r
200 \r
201         // prepare image size\r
202     image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true );\r
203 \r
204         // access image raw data\r
205     image->SetMask( false );\r
206     ptr = image->GetData();\r
207 \r
208         // workaround for components different from 1 or 3\r
209         if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) {\r
210                 wxMutexGuiEnter();\r
211                 wxLogMessage(wxT("J2K: weird number of components"));\r
212                 tempcomps = 1;\r
213                 wxMutexGuiLeave();\r
214         } else\r
215                 tempcomps = opjimage->numcomps;\r
216 \r
217         // workaround for subsampled components\r
218         for (c = 1; c < tempcomps; c++) {\r
219                 if ((opjimage->comps[c].w != opjimage->comps[c - 1].w) || (opjimage->comps[c].h != opjimage->comps[c - 1].h)) {\r
220                         tempcomps = 1;\r
221                         break;\r
222                 }\r
223         }\r
224 \r
225         // workaround for different precision components\r
226         for (c = 1; c < tempcomps; c++) {\r
227                 if (opjimage->comps[c].bpp != opjimage->comps[c - 1].bpp) {\r
228                         tempcomps = 1;\r
229                         break;\r
230                 }\r
231         }\r
232 \r
233 \r
234         // RGB color picture\r
235         if (tempcomps == 3) {\r
236                 int row, col;\r
237                 int *r = opjimage->comps[0].data;\r
238                 int *g = opjimage->comps[1].data;\r
239                 int *b = opjimage->comps[2].data;\r
240                 if (shiftbpp > 0) {\r
241                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
242                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
243                                         \r
244                                         *(ptr++) = (*(r++)) >> shiftbpp;\r
245                                         *(ptr++) = (*(g++)) >> shiftbpp;\r
246                                         *(ptr++) = (*(b++)) >> shiftbpp;\r
247 \r
248                                 }\r
249                         }\r
250 \r
251                 } else if (shiftbpp < 0) {\r
252                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
253                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
254                                         \r
255                                         *(ptr++) = (*(r++)) << -shiftbpp;\r
256                                         *(ptr++) = (*(g++)) << -shiftbpp;\r
257                                         *(ptr++) = (*(b++)) << -shiftbpp;\r
258 \r
259                                 }\r
260                         }\r
261                         \r
262                 } else {\r
263                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
264                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
265 \r
266                                         *(ptr++) = *(r++);\r
267                                         *(ptr++) = *(g++);\r
268                                         *(ptr++) = *(b++);\r
269                                 \r
270                                 }\r
271                         }\r
272                 }\r
273         }\r
274 \r
275         // B/W picture\r
276         if (tempcomps == 1) {\r
277                 int row, col;\r
278                 int *y = opjimage->comps[0].data;\r
279                 if (shiftbpp > 0) {\r
280                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
281                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
282                                         \r
283                                         *(ptr++) = (*(y)) >> shiftbpp;\r
284                                         *(ptr++) = (*(y)) >> shiftbpp;\r
285                                         *(ptr++) = (*(y++)) >> shiftbpp;\r
286 \r
287                                 }\r
288                         }\r
289                 } else if (shiftbpp < 0) {\r
290                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
291                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
292                                         \r
293                                         *(ptr++) = (*(y)) << -shiftbpp;\r
294                                         *(ptr++) = (*(y)) << -shiftbpp;\r
295                                         *(ptr++) = (*(y++)) << -shiftbpp;\r
296 \r
297                                 }\r
298                         }\r
299                 } else {\r
300                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
301                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
302                                         \r
303                                         *(ptr++) = *(y);\r
304                                         *(ptr++) = *(y);\r
305                                         *(ptr++) = *(y++);\r
306 \r
307                                 }\r
308                         }\r
309                 }\r
310         }\r
311 \r
312     wxMutexGuiEnter();\r
313     wxLogMessage(wxT("J2K: image loaded."));\r
314     wxMutexGuiLeave();\r
315 \r
316         /* close openjpeg structs */\r
317         opj_destroy_decompress(dinfo);\r
318         opj_image_destroy(opjimage);\r
319         free(src);\r
320 \r
321         if (!image->Ok())\r
322                 return false;\r
323         else\r
324                 return true;\r
325 \r
326 }\r
327 \r
328 // save the j2k codestream\r
329 bool wxJ2KHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )\r
330 {\r
331     wxLogError(wxT("J2K: Couldn't save image -> not implemented."));\r
332     return false;\r
333 }\r
334 \r
335 #ifdef __VISUALC__\r
336     #pragma warning(default:4611)\r
337 #endif /* VC++ */\r
338 \r
339 // recognize the 0xFF4F JPEG 2000 SOC marker\r
340 bool wxJ2KHandler::DoCanRead( wxInputStream& stream )\r
341 {\r
342     unsigned char hdr[2];\r
343 \r
344     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )\r
345         return false;\r
346 \r
347     return hdr[0] == 0xFF && hdr[1] == 0x4F;\r
348 }\r
349 \r
350 #endif   // wxUSE_STREAMS\r
351 \r
352 #endif   // wxUSE_LIBOPENJPEG\r