Added the OPJViewer Module (/OPJViewer), developed by Giuseppe Baruffa of the Univers...
[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 \r
55 #include "libopenjpeg/openjpeg.h"\r
56 \r
57 \r
58 #include "wx/filefn.h"\r
59 #include "wx/wfstream.h"\r
60 \r
61 // ----------------------------------------------------------------------------\r
62 // types\r
63 // ----------------------------------------------------------------------------\r
64 \r
65 \r
66 //-----------------------------------------------------------------------------\r
67 // wxJ2KHandler\r
68 //-----------------------------------------------------------------------------\r
69 \r
70 IMPLEMENT_DYNAMIC_CLASS(wxJ2KHandler,wxImageHandler)\r
71 \r
72 #if wxUSE_STREAMS\r
73 \r
74 //------------- JPEG 2000 Data Source Manager\r
75 \r
76 #define J2K_CFMT 0\r
77 #define JP2_CFMT 1\r
78 #define JPT_CFMT 2\r
79 #define MJ2_CFMT 3\r
80 #define PXM_DFMT 0\r
81 #define PGX_DFMT 1\r
82 #define BMP_DFMT 2\r
83 #define YUV_DFMT 3\r
84 \r
85 #define MAX_MESSAGE_LEN 200\r
86 \r
87 /* sample error callback expecting a FILE* client object */\r
88 void j2k_error_callback(const char *msg, void *client_data) {\r
89         char m_msg[MAX_MESSAGE_LEN];\r
90         int message_len = strlen(msg) - 1;\r
91         if (msg[message_len] != '\n')\r
92                 message_len = MAX_MESSAGE_LEN;\r
93         sprintf(m_msg, "[ERROR] %.*s", message_len, msg);\r
94     wxMutexGuiEnter();\r
95         wxLogMessage(m_msg);\r
96     wxMutexGuiLeave();\r
97 }\r
98 /* sample warning callback expecting a FILE* client object */\r
99 void j2k_warning_callback(const char *msg, void *client_data) {\r
100         char m_msg[MAX_MESSAGE_LEN];\r
101         int message_len = strlen(msg) - 1;\r
102         if (msg[message_len] != '\n')\r
103                 message_len = MAX_MESSAGE_LEN;\r
104         sprintf(m_msg, "[WARNING] %.*s", message_len, msg);\r
105     wxMutexGuiEnter();\r
106         wxLogMessage(m_msg);\r
107     wxMutexGuiLeave();\r
108 }\r
109 /* sample debug callback expecting no client object */\r
110 void j2k_info_callback(const char *msg, void *client_data) {\r
111         char m_msg[MAX_MESSAGE_LEN];\r
112         int message_len = strlen(msg) - 1;\r
113         if (msg[message_len] != '\n')\r
114                 message_len = MAX_MESSAGE_LEN;\r
115         sprintf(m_msg, "[INFO] %.*s", message_len, msg);\r
116     wxMutexGuiEnter();\r
117         wxLogMessage(m_msg);\r
118     wxMutexGuiLeave();\r
119 }\r
120 \r
121 // load the j2k codestream\r
122 bool wxJ2KHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index)\r
123 {\r
124         opj_dparameters_t parameters;   /* decompression parameters */\r
125         opj_event_mgr_t event_mgr;              /* event manager */\r
126         opj_image_t *opjimage = NULL;\r
127         FILE *fsrc = NULL;\r
128         unsigned char *src = NULL;\r
129     unsigned char *ptr;\r
130         int file_length;\r
131         int shiftbpp;\r
132 \r
133         // destroy the image\r
134     image->Destroy();\r
135 \r
136         /* handle to a decompressor */\r
137         opj_dinfo_t* dinfo = NULL;      \r
138         opj_cio_t *cio = NULL;\r
139 \r
140         /* configure the event callbacks (not required) */\r
141         memset(&event_mgr, 0, sizeof(opj_event_mgr_t));\r
142         event_mgr.error_handler = j2k_error_callback;\r
143         event_mgr.warning_handler = j2k_warning_callback;\r
144         event_mgr.info_handler = j2k_info_callback;\r
145 \r
146         /* set decoding parameters to default values */\r
147         opj_set_default_decoder_parameters(&parameters);\r
148 \r
149         /* prepare parameters */\r
150         parameters.decod_format = J2K_CFMT;\r
151         parameters.cod_format = BMP_DFMT;\r
152 \r
153         /* JPWL only */\r
154 #ifdef USE_JPWL\r
155         parameters.jpwl_exp_comps = 3;\r
156         parameters.jpwl_max_tiles = 100;\r
157         parameters.jpwl_correct = true;\r
158 #endif /* USE_JPWL */\r
159 \r
160         /* get a decoder handle */\r
161         dinfo = opj_create_decompress(CODEC_J2K);\r
162 \r
163         /* find length of the stream */\r
164         stream.SeekI(0, wxFromEnd);\r
165         file_length = (int) stream.TellI();\r
166 \r
167         /* get data */\r
168         stream.SeekI(0, wxFromStart);\r
169     src = (unsigned char *) malloc(file_length);\r
170         stream.Read(src, file_length);\r
171 \r
172         /* catch events using our callbacks and give a local context */\r
173         opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);\r
174 \r
175         /* setup the decoder decoding parameters using user parameters */\r
176         opj_setup_decoder(dinfo, &parameters);\r
177 \r
178         /* open a byte stream */\r
179         cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);\r
180 \r
181         /* decode the stream and fill the image structure */\r
182         opjimage = opj_decode(dinfo, cio);\r
183         if (!opjimage) {\r
184                 wxMutexGuiEnter();\r
185                 wxLogError("J2K: failed to decode image!");\r
186                 wxMutexGuiLeave();\r
187                 opj_destroy_decompress(dinfo);\r
188                 opj_cio_close(cio);\r
189                 opj_image_destroy(opjimage);\r
190                 free(src);\r
191                 return false;\r
192         }\r
193 \r
194         // check image components\r
195         if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) {\r
196                 wxMutexGuiEnter();\r
197                 wxLogError("J2K: weird number of components");\r
198                 wxMutexGuiLeave();\r
199                 opj_destroy_decompress(dinfo);\r
200                 opj_cio_close(cio);\r
201                 free(src);\r
202                 return false;\r
203         }\r
204 \r
205         // check image depth (only on the first one, for now)\r
206         shiftbpp = opjimage->comps[0].prec - 8;\r
207 \r
208         // prepare image size\r
209     image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true );\r
210 \r
211         // access image raw data\r
212     image->SetMask( false );\r
213     ptr = image->GetData();\r
214 \r
215         // RGB color picture\r
216         if (opjimage->numcomps == 3) {\r
217                 int row, col;\r
218                 int *r = opjimage->comps[0].data;\r
219                 int *g = opjimage->comps[1].data;\r
220                 int *b = opjimage->comps[2].data;\r
221                 if (shiftbpp > 0) {\r
222                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
223                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
224                                         \r
225                                         *(ptr++) = (*(r++)) >> shiftbpp;\r
226                                         *(ptr++) = (*(g++)) >> shiftbpp;\r
227                                         *(ptr++) = (*(b++)) >> shiftbpp;\r
228 \r
229                                 }\r
230                         }\r
231                 } else {\r
232                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
233                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
234                                         \r
235                                         *(ptr++) = *(r++);\r
236                                         *(ptr++) = *(g++);\r
237                                         *(ptr++) = *(b++);\r
238 \r
239                                 }\r
240                         }\r
241                 }\r
242         }\r
243 \r
244         // B/W picture\r
245         if (opjimage->numcomps == 1) {\r
246                 int row, col;\r
247                 int *y = opjimage->comps[0].data;\r
248                 if (shiftbpp > 0) {\r
249                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
250                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
251                                         \r
252                                         *(ptr++) = (*(y)) >> shiftbpp;\r
253                                         *(ptr++) = (*(y)) >> shiftbpp;\r
254                                         *(ptr++) = (*(y++)) >> shiftbpp;\r
255 \r
256                                 }\r
257                         }\r
258                 } else {\r
259                         for (row = 0; row < opjimage->comps[0].h; row++) {\r
260                                 for (col = 0; col < opjimage->comps[0].w; col++) {\r
261                                         \r
262                                         *(ptr++) = *(y);\r
263                                         *(ptr++) = *(y);\r
264                                         *(ptr++) = *(y++);\r
265 \r
266                                 }\r
267                         }\r
268                 }\r
269         }\r
270 \r
271     wxMutexGuiEnter();\r
272     wxLogMessage(wxT("J2K: image loaded."));\r
273     wxMutexGuiLeave();\r
274 \r
275         /* close openjpeg structs */\r
276         opj_destroy_decompress(dinfo);\r
277         opj_cio_close(cio);\r
278         opj_image_destroy(opjimage);\r
279         free(src);\r
280 \r
281         if (!image->Ok())\r
282                 return false;\r
283         else\r
284                 return true;\r
285 \r
286 }\r
287 \r
288 // save the j2k codestream\r
289 bool wxJ2KHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )\r
290 {\r
291     wxLogError(wxT("J2K: Couldn't save image -> not implemented."));\r
292     return false;\r
293 }\r
294 \r
295 #ifdef __VISUALC__\r
296     #pragma warning(default:4611)\r
297 #endif /* VC++ */\r
298 \r
299 // recognize the 0xFF4F JPEG 2000 SOC marker\r
300 bool wxJ2KHandler::DoCanRead( wxInputStream& stream )\r
301 {\r
302     unsigned char hdr[2];\r
303 \r
304     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )\r
305         return false;\r
306 \r
307     return hdr[0] == 0xFF && hdr[1] == 0x4F;\r
308 }\r
309 \r
310 #endif   // wxUSE_STREAMS\r
311 \r
312 #endif   // wxUSE_LIBOPENJPEG\r