2 * Copyright (c) 2007, Digital Signal Processing Laboratory, Universit� degli studi di Perugia (UPG), Italy
\r
3 * All rights reserved.
\r
5 * Redistribution and use in source and binary forms, with or without
\r
6 * modification, are permitted provided that the following conditions
\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
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
26 /////////////////////////////////////////////////////////////////////////////
\r
27 // Name: imagmj2.cpp
\r
28 // Purpose: wxImage Motion JPEG 2000 file format handler
\r
29 // Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik
\r
30 // RCS-ID: $Id: imagmj2.cpp,v 0.00 2007/02/18 23:59:00 MW Exp $
\r
31 // Copyright: (c) Giuseppe Baruffa
\r
32 // Licence: wxWindows licence
\r
33 /////////////////////////////////////////////////////////////////////////////
\r
35 // For compilers that support precompilation, includes "wx.h".
\r
36 #include "wx/wxprec.h"
\r
42 #if wxUSE_IMAGE && wxUSE_LIBOPENJPEG
\r
44 #include "imagmj2.h"
\r
49 #include "wx/intl.h"
\r
50 #include "wx/bitmap.h"
\r
51 #include "wx/module.h"
\r
55 #include "libopenjpeg/openjpeg.h"
\r
58 #include "wx/filefn.h"
\r
59 #include "wx/wfstream.h"
\r
61 // ----------------------------------------------------------------------------
\r
63 // ----------------------------------------------------------------------------
\r
66 //-----------------------------------------------------------------------------
\r
68 //-----------------------------------------------------------------------------
\r
70 IMPLEMENT_DYNAMIC_CLASS(wxMJ2Handler,wxImageHandler)
\r
74 //------------- JPEG 2000 Data Source Manager
\r
85 #define MAX_MESSAGE_LEN 200
\r
87 /* sample error callback expecting a FILE* client object */
\r
88 void mj2_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
95 wxLogMessage(m_msg);
\r
98 /* sample warning callback expecting a FILE* client object */
\r
99 void mj2_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
106 wxLogMessage(m_msg);
\r
109 /* sample debug callback expecting no client object */
\r
110 void mj2_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
117 wxLogMessage(m_msg);
\r
121 /* macro functions */
\r
122 /* From little endian to big endian, 2 and 4 bytes */
\r
123 #define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8)
\r
124 #define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24)
\r
125 #define BYTE_SWAP8(X) ((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \
\r
126 ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \
\r
127 ((X & 0x000000FF00000000) >> 8) | ((X & 0x0000FF0000000000) >> 24) | \
\r
128 ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56)
\r
130 /* From codestream to int values */
\r
131 #define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \
\r
132 ((unsigned long int) (C)[(P) + 1] << 16) + \
\r
133 ((unsigned long int) (C)[(P) + 2] << 8) + \
\r
134 ((unsigned long int) (C)[(P) + 3] << 0))
\r
136 #define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \
\r
137 ((unsigned long int) (C)[(P) + 1] << 0))
\r
140 #define SHORT_DESCR_LEN 32
\r
141 #define LONG_DESCR_LEN 256
\r
143 /* enumeration for file formats */
\r
144 #define J2FILENUM 4
\r
154 /* enumeration for the box types */
\r
155 #define J2BOXNUM 23
\r
184 /* jp2 family box signatures */
\r
185 #define FILE_SIGN ""
\r
186 #define JP_SIGN "jP\040\040"
\r
187 #define FTYP_SIGN "ftyp"
\r
188 #define JP2H_SIGN "jp2h"
\r
189 #define IHDR_SIGN "ihdr"
\r
190 #define COLR_SIGN "colr"
\r
191 #define JP2C_SIGN "jp2c"
\r
192 #define JP2I_SIGN "jp2i"
\r
193 #define XML_SIGN "xml\040"
\r
194 #define UUID_SIGN "uuid"
\r
195 #define UINF_SIGN "uinf"
\r
196 #define MOOV_SIGN "moov"
\r
197 #define MVHD_SIGN "mvhd"
\r
198 #define TRAK_SIGN "trak"
\r
199 #define TKHD_SIGN "tkhd"
\r
200 #define MDIA_SIGN "mdia"
\r
201 #define MINF_SIGN "minf"
\r
202 #define STBL_SIGN "stbl"
\r
203 #define STSD_SIGN "stsd"
\r
204 #define MJP2_SIGN "mjp2"
\r
205 #define MDAT_SIGN "mdat"
\r
206 #define ANY_SIGN ""
\r
207 #define UNK_SIGN ""
\r
209 /* the box structure itself */
\r
212 char value[5]; /* hexadecimal value/string*/
\r
213 char name[SHORT_DESCR_LEN]; /* short description */
\r
214 char descr[LONG_DESCR_LEN]; /* long description */
\r
215 int sbox; /* is it a superbox? */
\r
216 int req[J2FILENUM]; /* mandatory box */
\r
217 my_j2boxtype ins; /* contained in box... */
\r
221 /* the possible boxes */
\r
222 struct my_boxdef j2box[] =
\r
224 /* sign */ {FILE_SIGN,
\r
225 /* short */ "placeholder for nothing",
\r
226 /* long */ "Nothing to say",
\r
228 /* req */ {1, 1, 1},
\r
229 /* ins */ FILE_BOX},
\r
231 /* sign */ {JP_SIGN,
\r
232 /* short */ "JPEG 2000 Signature box",
\r
233 /* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files",
\r
235 /* req */ {1, 1, 1},
\r
236 /* ins */ FILE_BOX},
\r
238 /* sign */ {FTYP_SIGN,
\r
239 /* short */ "File Type box",
\r
240 /* long */ "This box specifies file type, version and compatibility information, including specifying if this file "
\r
241 "is a conforming JP2 file or if it can be read by a conforming JP2 reader",
\r
243 /* req */ {1, 1, 1},
\r
244 /* ins */ FILE_BOX},
\r
246 /* sign */ {JP2H_SIGN,
\r
247 /* short */ "JP2 Header box",
\r
248 /* long */ "This box contains a series of boxes that contain header-type information about the file",
\r
250 /* req */ {1, 1, 1},
\r
251 /* ins */ FILE_BOX},
\r
253 /* sign */ {IHDR_SIGN,
\r
254 /* short */ "Image Header box",
\r
255 /* long */ "This box specifies the size of the image and other related fields",
\r
257 /* req */ {1, 1, 1},
\r
258 /* ins */ JP2H_BOX},
\r
260 /* sign */ {COLR_SIGN,
\r
261 /* short */ "Colour Specification box",
\r
262 /* long */ "This box specifies the colourspace of the image",
\r
264 /* req */ {1, 1, 1},
\r
265 /* ins */ JP2H_BOX},
\r
267 /* sign */ {JP2C_SIGN,
\r
268 /* short */ "Contiguous Codestream box",
\r
269 /* long */ "This box contains the codestream as defined by Annex A",
\r
271 /* req */ {1, 1, 1},
\r
272 /* ins */ FILE_BOX},
\r
274 /* sign */ {JP2I_SIGN,
\r
275 /* short */ "Intellectual Property box",
\r
276 /* long */ "This box contains intellectual property information about the image",
\r
278 /* req */ {0, 0, 0},
\r
279 /* ins */ FILE_BOX},
\r
281 /* sign */ {XML_SIGN,
\r
282 /* short */ "XML box",
\r
283 /* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file",
\r
285 /* req */ {0, 0, 0},
\r
286 /* ins */ FILE_BOX},
\r
288 /* sign */ {UUID_SIGN,
\r
289 /* short */ "UUID box",
\r
290 /* long */ "This box provides a tool by which vendors can add additional information to a file "
\r
291 "without risking conflict with other vendors",
\r
293 /* req */ {0, 0, 0},
\r
294 /* ins */ FILE_BOX},
\r
296 /* sign */ {UINF_SIGN,
\r
297 /* short */ "UUID Info box",
\r
298 /* long */ "This box provides a tool by which a vendor may provide access to additional information associated with a UUID",
\r
300 /* req */ {0, 0, 0},
\r
301 /* ins */ FILE_BOX},
\r
303 /* sign */ {MOOV_SIGN,
\r
304 /* short */ "Movie box",
\r
305 /* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames",
\r
307 /* req */ {1, 1, 1},
\r
308 /* ins */ FILE_BOX},
\r
310 /* sign */ {MVHD_SIGN,
\r
311 /* short */ "Movie Header box",
\r
312 /* long */ "This box defines overall information which is media-independent, and relevant to the entire presentation "
\r
313 "considered as a whole",
\r
315 /* req */ {1, 1, 1},
\r
316 /* ins */ MOOV_BOX},
\r
318 /* sign */ {TRAK_SIGN,
\r
319 /* short */ "Track box",
\r
320 /* long */ "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks",
\r
322 /* req */ {1, 1, 1},
\r
323 /* ins */ MOOV_BOX},
\r
325 /* sign */ {TKHD_SIGN,
\r
326 /* short */ "Track Header box",
\r
327 /* long */ "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track",
\r
329 /* req */ {1, 1, 1},
\r
330 /* ins */ TRAK_BOX},
\r
332 /* sign */ {MDIA_SIGN,
\r
333 /* short */ "Media box",
\r
334 /* long */ "The media declaration container contains all the objects which declare information about the media data "
\r
337 /* req */ {1, 1, 1},
\r
338 /* ins */ TRAK_BOX},
\r
340 /* sign */ {MINF_SIGN,
\r
341 /* short */ "Media Information box",
\r
342 /* long */ "This box contains all the objects which declare characteristic information of the media in the track",
\r
344 /* req */ {1, 1, 1},
\r
345 /* ins */ MDIA_BOX},
\r
347 /* sign */ {STBL_SIGN,
\r
348 /* short */ "Sample Table box",
\r
349 /* long */ "The sample table contains all the time and data indexing of the media samples in a track",
\r
351 /* req */ {1, 1, 1},
\r
352 /* ins */ MINF_BOX},
\r
354 /* sign */ {STSD_SIGN,
\r
355 /* short */ "Sample Description box",
\r
356 /* long */ "The sample description table gives detailed information about the coding type used, and any initialization "
\r
357 "information needed for that coding",
\r
359 /* req */ {1, 1, 1},
\r
360 /* ins */ MINF_BOX},
\r
362 /* sign */ {MJP2_SIGN,
\r
363 /* short */ "MJP2 Sample Description box",
\r
364 /* long */ "The MJP2 sample description table gives detailed information about the coding type used, and any initialization "
\r
365 "information needed for that coding",
\r
367 /* req */ {1, 1, 1},
\r
368 /* ins */ MINF_BOX},
\r
370 /* sign */ {MDAT_SIGN,
\r
371 /* short */ "Media Data box",
\r
372 /* long */ "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file",
\r
374 /* req */ {1, 1, 1},
\r
375 /* ins */ FILE_BOX},
\r
377 /* sign */ {ANY_SIGN,
\r
378 /* short */ "Any box",
\r
379 /* long */ "All the existing boxes",
\r
381 /* req */ {0, 0, 0},
\r
382 /* ins */ FILE_BOX},
\r
384 /* sign */ {UNK_SIGN,
\r
385 /* short */ "Unknown Type box",
\r
386 /* long */ "The signature is not recognised to be that of an existing box",
\r
388 /* req */ {0, 0, 0},
\r
395 my_box_handler_function(my_j2boxtype boxtype, wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level,
\r
396 char *scansign, unsigned long int *scanpoint);
\r
398 /* internal mini-search for a box signature */
\r
400 my_jpeg2000parse(wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level,
\r
401 char *scansign, unsigned long int *scanpoint)
\r
403 unsigned long int LBox = 0x00000000;
\r
405 char TBox[5] = "\0\0\0\0";
\r
407 __int64 XLBox = 0x0000000000000000;
\r
409 unsigned long int box_length = 0;
\r
410 int last_box = 0, box_num = 0;
\r
411 int box_type = ANY_BOX;
\r
412 unsigned char onebyte[1], twobytes[2], fourbytes[4];
\r
413 int box_number = 0;
\r
415 /* cycle all over the file */
\r
418 while (!last_box) {
\r
420 /* do not exceed file limit */
\r
421 if (filepoint >= filelimit)
\r
425 if (stream.SeekI(filepoint, wxFromStart) == wxInvalidOffset)
\r
428 /* read the mandatory LBox, 4 bytes */
\r
429 if (!stream.Read(fourbytes, 4)) {
\r
430 (wxT("Problem reading LBox from the file (file ended?)"));
\r
433 LBox = STREAM_TO_UINT32(fourbytes, 0);
\r
435 /* read the mandatory TBox, 4 bytes */
\r
436 if (!stream.Read(TBox, 4)) {
\r
437 wxLogError(wxT("Problem reading TBox from the file (file ended?)"));
\r
441 /* look if scansign is got */
\r
442 if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) {
\r
444 // stop as soon as you find the level-th codebox
\r
445 if (box_number == level) {
\r
446 memcpy(scansign, " ", 4);
\r
447 *scanpoint = filepoint;
\r
455 /* determine the box type */
\r
456 for (box_type = JP_BOX; box_type < UNK_BOX; box_type++)
\r
457 if (memcmp(TBox, j2box[box_type].value, 4) == 0)
\r
460 /* read the optional XLBox, 8 bytes */
\r
463 if (!stream.Read(&XLBox, 8)) {
\r
464 wxLogError(wxT("Problem reading XLBox from the file (file ended?)"));
\r
467 box_length = (unsigned long int) BYTE_SWAP8(XLBox);
\r
469 } else if (LBox == 0x00000000) {
\r
471 /* last box in file */
\r
473 box_length = filelimit - filepoint;
\r
480 /* go deep in the box */
\r
481 my_box_handler_function((my_j2boxtype) box_type, stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length, level,
\r
482 scansign, scanpoint);
\r
484 /* if it's a superbox go inside it */
\r
485 if (j2box[box_type].sbox)
\r
486 my_jpeg2000parse(stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length,
\r
487 level, scansign, scanpoint);
\r
489 /* increment box number and filepoint*/
\r
491 filepoint += box_length;
\r
499 // search first contiguos codestream box in an mj2 file
\r
501 searchfirstjp2c(wxInputStream& stream, unsigned long int fsize)
\r
503 char scansign[] = "jp2c";
\r
504 unsigned long int scanpoint = 0L;
\r
506 wxLogMessage("MJ2: searching jp2c box... ");
\r
508 /* do the parsing */
\r
509 if (my_jpeg2000parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0)
\r
510 wxLogMessage("MJ2: Unrecoverable error during file parsing: stopping");
\r
512 if (strcmp(scansign, " "))
\r
513 wxLogMessage("MJ2: not found");
\r
516 wxLogMessage(wxString::Format("MJ2: found at byte %d", scanpoint));
\r
521 return (scanpoint);
\r
524 // search the jp2h box in the file
\r
526 searchjpegheaderbox(wxInputStream& stream, unsigned long int fsize)
\r
528 char scansign[] = "jp2h";
\r
529 unsigned long int scanpoint = 0L;
\r
531 wxLogMessage("MJ2: searching jp2h box... ");
\r
533 /* do the parsing */
\r
534 if (my_jpeg2000parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0)
\r
535 wxLogMessage("Unrecoverable error during file parsing: stopping");
\r
537 if (strcmp(scansign, " "))
\r
538 wxLogMessage("MJ2: not found");
\r
540 wxLogMessage(wxString::Format("MJ2: found at byte %d", scanpoint));
\r
542 return (scanpoint);
\r
545 /* handling functions */
\r
546 #define ITEM_PER_ROW 10
\r
548 /* Box handler function */
\r
550 my_box_handler_function(my_j2boxtype boxtype, wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level,
\r
551 char *scansign, unsigned long int *scanpoint)
\r
555 /* Sample Description box */
\r
557 my_jpeg2000parse(stream, filepoint + 8, filelimit, level, scansign, scanpoint);
\r
560 /* MJP2 Sample Description box */
\r
562 my_jpeg2000parse(stream, filepoint + 78, filelimit, level, scansign, scanpoint);
\r
565 /* not yet implemented */
\r
574 // the jP and ftyp parts of the header
\r
575 #define my_jPheadSIZE 32
\r
576 unsigned char my_jPhead[my_jPheadSIZE] = {
\r
577 0x00, 0x00, 0x00, 0x0C, 'j', 'P', ' ', ' ',
\r
578 0x0D, 0x0A, 0x87, 0x0A, 0x00, 0x00, 0x00, 0x14,
\r
579 'f', 't', 'y', 'p', 'j', 'p', '2', ' ',
\r
580 0x00, 0x00, 0x00, 0x00, 'j', 'p', '2', ' '
\r
583 /////////////////////////////////////////////////
\r
584 /////////////////////////////////////////////////
\r
586 // load the mj2 file format
\r
587 bool wxMJ2Handler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index)
\r
589 opj_dparameters_t parameters; /* decompression parameters */
\r
590 opj_event_mgr_t event_mgr; /* event manager */
\r
591 opj_image_t *opjimage = NULL;
\r
592 unsigned char *src = NULL;
\r
593 unsigned char *ptr;
\r
594 int file_length, jp2c_point, jp2h_point;
\r
595 unsigned long int jp2hboxlen, jp2cboxlen;
\r
597 // destroy the image
\r
600 /* handle to a decompressor */
\r
601 opj_dinfo_t* dinfo = NULL;
\r
602 opj_cio_t *cio = NULL;
\r
604 /* configure the event callbacks (not required) */
\r
605 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
\r
606 event_mgr.error_handler = mj2_error_callback;
\r
607 event_mgr.warning_handler = mj2_warning_callback;
\r
608 event_mgr.info_handler = mj2_info_callback;
\r
610 /* set decoding parameters to default values */
\r
611 opj_set_default_decoder_parameters(¶meters);
\r
613 /* prepare parameters */
\r
614 strncpy(parameters.infile, "", sizeof(parameters.infile)-1);
\r
615 strncpy(parameters.outfile, "", sizeof(parameters.outfile)-1);
\r
616 parameters.decod_format = JP2_CFMT;
\r
617 parameters.cod_format = BMP_DFMT;
\r
619 /* get a decoder handle */
\r
620 dinfo = opj_create_decompress(CODEC_JP2);
\r
622 /* find length of the stream */
\r
623 stream.SeekI(0, wxFromEnd);
\r
624 file_length = (int) stream.TellI();
\r
626 /* search for the first codestream box and the movie header box */
\r
627 jp2c_point = searchfirstjp2c(stream, file_length);
\r
628 jp2h_point = searchjpegheaderbox(stream, file_length);
\r
630 // read the jp2h box and store it
\r
631 stream.SeekI(jp2h_point, wxFromStart);
\r
632 stream.Read(&jp2hboxlen, sizeof(unsigned long int));
\r
633 jp2hboxlen = BYTE_SWAP4(jp2hboxlen);
\r
635 // read the jp2c box and store it
\r
636 stream.SeekI(jp2c_point, wxFromStart);
\r
637 stream.Read(&jp2cboxlen, sizeof(unsigned long int));
\r
638 jp2cboxlen = BYTE_SWAP4(jp2cboxlen);
\r
640 // malloc memory source
\r
641 src = (unsigned char *) malloc(my_jPheadSIZE + jp2hboxlen + jp2cboxlen);
\r
643 // copy the jP and ftyp
\r
644 memcpy(src, my_jPhead, my_jPheadSIZE);
\r
647 stream.SeekI(jp2h_point, wxFromStart);
\r
648 stream.Read(&src[my_jPheadSIZE], jp2hboxlen);
\r
651 stream.SeekI(jp2c_point, wxFromStart);
\r
652 stream.Read(&src[my_jPheadSIZE + jp2hboxlen], jp2cboxlen);
\r
654 /* catch events using our callbacks and give a local context */
\r
655 opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
\r
657 /* setup the decoder decoding parameters using user parameters */
\r
658 opj_setup_decoder(dinfo, ¶meters);
\r
660 /* open a byte stream */
\r
661 cio = opj_cio_open((opj_common_ptr)dinfo, src, my_jPheadSIZE + jp2hboxlen + jp2cboxlen);
\r
663 /* decode the stream and fill the image structure */
\r
664 opjimage = opj_decode(dinfo, cio);
\r
667 wxLogError("MJ2: failed to decode image!");
\r
669 opj_destroy_decompress(dinfo);
\r
670 opj_cio_close(cio);
\r
675 /* close the byte stream */
\r
676 opj_cio_close(cio);
\r
678 // check image size
\r
679 if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) {
\r
681 wxLogError("MJ2: weird number of components");
\r
683 opj_destroy_decompress(dinfo);
\r
688 // prepare image size
\r
689 image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true );
\r
691 // access image raw data
\r
692 image->SetMask( false );
\r
693 ptr = image->GetData();
\r
695 // RGB color picture
\r
696 // does not handle comps. subsampling,
\r
697 // so simply render the first component
\r
698 if (opjimage->numcomps == 3) {
\r
700 int *r = opjimage->comps[0].data;
\r
702 int *g = opjimage->comps[1].data;
\r
703 int *b = opjimage->comps[2].data;
\r
705 for (row = 0; row < opjimage->comps[0].h; row++) {
\r
706 for (col = 0; col < opjimage->comps[0].w; col++) {
\r
722 if (opjimage->numcomps == 1) {
\r
724 int *y = opjimage->comps[0].data;
\r
725 for (row = 0; row < opjimage->comps[0].h; row++) {
\r
726 for (col = 0; col < opjimage->comps[0].w; col++) {
\r
737 wxLogMessage(wxT("MJ2: image loaded."));
\r
740 /* close openjpeg structs */
\r
741 opj_destroy_decompress(dinfo);
\r
742 opj_image_destroy(opjimage);
\r
752 // save the mj2 file format
\r
753 bool wxMJ2Handler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
\r
755 wxLogError(wxT("MJ2: Couldn't save movie -> not implemented."));
\r
760 #pragma warning(default:4611)
\r
763 // recognize the Motion JPEG 2000 starting box
\r
764 bool wxMJ2Handler::DoCanRead( wxInputStream& stream )
\r
766 unsigned char hdr[24];
\r
768 if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
\r
771 return (hdr[0] == 0x00 &&
\r
785 #endif // wxUSE_STREAMS
\r
787 #endif // wxUSE_LIBOPENJPEG
\r