1 /*
2 * Copyright (c) 2007, Digital Signal Processing Laboratory, Universit� degli studi di Perugia (UPG), Italy
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26 /////////////////////////////////////////////////////////////////////////////
27 // Name: imagjpeg2000.cpp
28 // Purpose: wxImage JPEG 2000 family file format handler
29 // Author: Giuseppe Baruffa - based on imagjpeg.cpp, Vaclav Slavik
30 // RCS-ID: $Id: imagjpeg2000.cpp,v 0.00 2008/01/31 10:58:00 MW Exp $
31 // Copyright: (c) Giuseppe Baruffa
32 // Licence: wxWindows licence
33 /////////////////////////////////////////////////////////////////////////////
34
35 // For compilers that support precompilation, includes "wx.h".
36 #include "wx/wxprec.h"
37
38 #ifdef __BORLANDC__
39 #pragma hdrstop
40 #endif
41
42 #if wxUSE_IMAGE && wxUSE_LIBOPENJPEG
43
44 #include "imagjpeg2000.h"
45
46 #ifndef WX_PRECOMP
47 #include "wx/log.h"
48 #include "wx/app.h"
49 #include "wx/intl.h"
50 #include "wx/bitmap.h"
51 #include "wx/module.h"
52 #endif
53
54 #include "libopenjpeg/openjpeg.h"
55
56 #include "wx/filefn.h"
57 #include "wx/wfstream.h"
58
59 // ----------------------------------------------------------------------------
60 // types
61 // ----------------------------------------------------------------------------
62
63
64 //-----------------------------------------------------------------------------
65 // wxJPEG2000Handler
66 //-----------------------------------------------------------------------------
67
IMPLEMENT_DYNAMIC_CLASS(wxJPEG2000Handler,wxImageHandler)68 IMPLEMENT_DYNAMIC_CLASS(wxJPEG2000Handler,wxImageHandler)
69
70 #if wxUSE_STREAMS
71
72 //------------- JPEG 2000 Data Source Manager
73
74 #define J2K_CFMT 0
75 #define JP2_CFMT 1
76 #define JPT_CFMT 2
77 #define MJ2_CFMT 3
78 #define PXM_DFMT 0
79 #define PGX_DFMT 1
80 #define BMP_DFMT 2
81 #define YUV_DFMT 3
82
83 #define MAX_MESSAGE_LEN 200
84
85 /* check file type */
86 int
87 jpeg2000familytype(unsigned char *hdr, int hdr_len)
88 {
89 // check length
90 if (hdr_len < 24)
91 return -1;
92
93 // check format
94 if (hdr[0] == 0x00 &&
95 hdr[1] == 0x00 &&
96 hdr[2] == 0x00 &&
97 hdr[3] == 0x0C &&
98 hdr[4] == 0x6A &&
99 hdr[5] == 0x50 &&
100 hdr[6] == 0x20 &&
101 hdr[7] == 0x20 &&
102 hdr[20] == 0x6A &&
103 hdr[21] == 0x70 &&
104 hdr[22] == 0x32)
105 // JP2 file format
106 return JP2_CFMT;
107 else if (hdr[0] == 0x00 &&
108 hdr[1] == 0x00 &&
109 hdr[2] == 0x00 &&
110 hdr[3] == 0x0C &&
111 hdr[4] == 0x6A &&
112 hdr[5] == 0x50 &&
113 hdr[6] == 0x20 &&
114 hdr[7] == 0x20 &&
115 hdr[20] == 0x6D &&
116 hdr[21] == 0x6A &&
117 hdr[22] == 0x70 &&
118 hdr[23] == 0x32)
119 // MJ2 file format
120 return MJ2_CFMT;
121 else if (hdr[0] == 0xFF &&
122 hdr[1] == 0x4F)
123 // J2K file format
124 return J2K_CFMT;
125 else
126 // unknown format
127 return -1;
128
129 }
130
131 /* we have to use this to avoid GUI-noGUI threads crashing */
printevent(const char * msg)132 void printevent(const char *msg)
133 {
134 #ifndef __WXGTK__
135 wxMutexGuiEnter();
136 #endif /* __WXGTK__ */
137 wxLogMessage(wxT("%s"), msg);
138 #ifndef __WXGTK__
139 wxMutexGuiLeave();
140 #endif /* __WXGTK__ */
141 }
142
143 /* sample error callback expecting a FILE* client object */
jpeg2000_error_callback(const char * msg,void * client_data)144 void jpeg2000_error_callback(const char *msg, void *client_data) {
145 char mess[MAX_MESSAGE_LEN + 20];
146 int message_len = strlen(msg);
147
148 if (message_len > MAX_MESSAGE_LEN)
149 message_len = MAX_MESSAGE_LEN;
150
151 if (msg[message_len - 1] == '\n')
152 message_len--;
153
154 sprintf(mess, "[ERROR] %.*s", message_len, msg);
155 printevent(mess);
156 }
157
158 /* sample warning callback expecting a FILE* client object */
jpeg2000_warning_callback(const char * msg,void * client_data)159 void jpeg2000_warning_callback(const char *msg, void *client_data) {
160 char mess[MAX_MESSAGE_LEN + 20];
161 int message_len = strlen(msg);
162
163 if (message_len > MAX_MESSAGE_LEN)
164 message_len = MAX_MESSAGE_LEN;
165
166 if (msg[message_len - 1] == '\n')
167 message_len--;
168
169 sprintf(mess, "[WARNING] %.*s", message_len, msg);
170 printevent(mess);
171 }
172
173 /* sample debug callback expecting no client object */
jpeg2000_info_callback(const char * msg,void * client_data)174 void jpeg2000_info_callback(const char *msg, void *client_data) {
175 char mess[MAX_MESSAGE_LEN + 20];
176 int message_len = strlen(msg);
177
178 if (message_len > MAX_MESSAGE_LEN)
179 message_len = MAX_MESSAGE_LEN;
180
181 if (msg[message_len - 1] == '\n')
182 message_len--;
183
184 sprintf(mess, "[INFO] %.*s", message_len, msg);
185 printevent(mess);
186 }
187
188 /* macro functions */
189 /* From little endian to big endian, 2 and 4 bytes */
190 #define BYTE_SWAP2(X) ((X & 0x00FF) << 8) | ((X & 0xFF00) >> 8)
191 #define BYTE_SWAP4(X) ((X & 0x000000FF) << 24) | ((X & 0x0000FF00) << 8) | ((X & 0x00FF0000) >> 8) | ((X & 0xFF000000) >> 24)
192
193 #ifdef __WXGTK__
194 #define BYTE_SWAP8(X) ((X & 0x00000000000000FFULL) << 56) | ((X & 0x000000000000FF00ULL) << 40) | \
195 ((X & 0x0000000000FF0000ULL) << 24) | ((X & 0x00000000FF000000ULL) << 8) | \
196 ((X & 0x000000FF00000000ULL) >> 8) | ((X & 0x0000FF0000000000ULL) >> 24) | \
197 ((X & 0x00FF000000000000ULL) >> 40) | ((X & 0xFF00000000000000ULL) >> 56)
198 #else
199 #define BYTE_SWAP8(X) ((X & 0x00000000000000FF) << 56) | ((X & 0x000000000000FF00) << 40) | \
200 ((X & 0x0000000000FF0000) << 24) | ((X & 0x00000000FF000000) << 8) | \
201 ((X & 0x000000FF00000000) >> 8) | ((X & 0x0000FF0000000000) >> 24) | \
202 ((X & 0x00FF000000000000) >> 40) | ((X & 0xFF00000000000000) >> 56)
203 #endif
204
205 /* From codestream to int values */
206 #define STREAM_TO_UINT32(C, P) (((unsigned long int) (C)[(P) + 0] << 24) + \
207 ((unsigned long int) (C)[(P) + 1] << 16) + \
208 ((unsigned long int) (C)[(P) + 2] << 8) + \
209 ((unsigned long int) (C)[(P) + 3] << 0))
210
211 #define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \
212 ((unsigned long int) (C)[(P) + 1] << 0))
213
214 /* defines */
215 #define SHORT_DESCR_LEN 32
216 #define LONG_DESCR_LEN 256
217
218 /* enumeration for file formats */
219 #define JPEG2000FILENUM 4
220 typedef enum {
221
222 JP2_FILE,
223 J2K_FILE,
224 MJ2_FILE,
225 UNK_FILE
226
227 } jpeg2000filetype;
228
229 /* enumeration for the box types */
230 #define JPEG2000BOXNUM 23
231 typedef enum {
232
233 FILE_BOX,
234 JP_BOX,
235 FTYP_BOX,
236 JP2H_BOX,
237 IHDR_BOX,
238 COLR_BOX,
239 JP2C_BOX,
240 JP2I_BOX,
241 XML_BOX,
242 UUID_BOX,
243 UINF_BOX,
244 MOOV_BOX,
245 MVHD_BOX,
246 TRAK_BOX,
247 TKHD_BOX,
248 MDIA_BOX,
249 MINF_BOX,
250 STBL_BOX,
251 STSD_BOX,
252 MJP2_BOX,
253 MDAT_BOX,
254 ANY_BOX,
255 UNK_BOX
256
257 } jpeg2000boxtype;
258
259 /* jpeg2000 family box signatures */
260 #define FILE_SIGN ""
261 #define JP_SIGN "jP\040\040"
262 #define FTYP_SIGN "ftyp"
263 #define JP2H_SIGN "jp2h"
264 #define IHDR_SIGN "ihdr"
265 #define COLR_SIGN "colr"
266 #define JP2C_SIGN "jp2c"
267 #define JP2I_SIGN "jp2i"
268 #define XML_SIGN "xml\040"
269 #define UUID_SIGN "uuid"
270 #define UINF_SIGN "uinf"
271 #define MOOV_SIGN "moov"
272 #define MVHD_SIGN "mvhd"
273 #define TRAK_SIGN "trak"
274 #define TKHD_SIGN "tkhd"
275 #define MDIA_SIGN "mdia"
276 #define MINF_SIGN "minf"
277 #define VMHD_SIGN "vmhd"
278 #define STBL_SIGN "stbl"
279 #define STSD_SIGN "stsd"
280 #define MJP2_SIGN "mjp2"
281 #define MDAT_SIGN "mdat"
282 #define ANY_SIGN ""
283 #define UNK_SIGN ""
284
285 /* the box structure itself */
286 struct jpeg2000boxdef {
287
288 char value[5]; /* hexadecimal value/string*/
289 char name[SHORT_DESCR_LEN]; /* short description */
290 char descr[LONG_DESCR_LEN]; /* long description */
291 int sbox; /* is it a superbox? */
292 int req[JPEG2000FILENUM]; /* mandatory box */
293 jpeg2000boxtype ins; /* contained in box... */
294
295 };
296
297 /* the possible boxes */
298 struct jpeg2000boxdef jpeg2000box[] =
299 {
300 /* sign */ {FILE_SIGN,
301 /* short */ "placeholder for nothing",
302 /* long */ "Nothing to say",
303 /* sbox */ 0,
304 /* req */ {1, 1, 1},
305 /* ins */ FILE_BOX},
306
307 /* sign */ {JP_SIGN,
308 /* short */ "JPEG 2000 Signature box",
309 /* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files",
310 /* sbox */ 0,
311 /* req */ {1, 1, 1},
312 /* ins */ FILE_BOX},
313
314 /* sign */ {FTYP_SIGN,
315 /* short */ "File Type box",
316 /* long */ "This box specifies file type, version and compatibility information, including specifying if this file "
317 "is a conforming JP2 file or if it can be read by a conforming JP2 reader",
318 /* sbox */ 0,
319 /* req */ {1, 1, 1},
320 /* ins */ FILE_BOX},
321
322 /* sign */ {JP2H_SIGN,
323 /* short */ "JP2 Header box",
324 /* long */ "This box contains a series of boxes that contain header-type information about the file",
325 /* sbox */ 1,
326 /* req */ {1, 1, 1},
327 /* ins */ FILE_BOX},
328
329 /* sign */ {IHDR_SIGN,
330 /* short */ "Image Header box",
331 /* long */ "This box specifies the size of the image and other related fields",
332 /* sbox */ 0,
333 /* req */ {1, 1, 1},
334 /* ins */ JP2H_BOX},
335
336 /* sign */ {COLR_SIGN,
337 /* short */ "Colour Specification box",
338 /* long */ "This box specifies the colourspace of the image",
339 /* sbox */ 0,
340 /* req */ {1, 1, 1},
341 /* ins */ JP2H_BOX},
342
343 /* sign */ {JP2C_SIGN,
344 /* short */ "Contiguous Codestream box",
345 /* long */ "This box contains the codestream as defined by Annex A",
346 /* sbox */ 0,
347 /* req */ {1, 1, 1},
348 /* ins */ FILE_BOX},
349
350 /* sign */ {JP2I_SIGN,
351 /* short */ "Intellectual Property box",
352 /* long */ "This box contains intellectual property information about the image",
353 /* sbox */ 0,
354 /* req */ {0, 0, 0},
355 /* ins */ FILE_BOX},
356
357 /* sign */ {XML_SIGN,
358 /* short */ "XML box",
359 /* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file",
360 /* sbox */ 0,
361 /* req */ {0, 0, 0},
362 /* ins */ FILE_BOX},
363
364 /* sign */ {UUID_SIGN,
365 /* short */ "UUID box",
366 /* long */ "This box provides a tool by which vendors can add additional information to a file "
367 "without risking conflict with other vendors",
368 /* sbox */ 0,
369 /* req */ {0, 0, 0},
370 /* ins */ FILE_BOX},
371
372 /* sign */ {UINF_SIGN,
373 /* short */ "UUID Info box",
374 /* long */ "This box provides a tool by which a vendor may provide access to additional information associated with a UUID",
375 /* sbox */ 0,
376 /* req */ {0, 0, 0},
377 /* ins */ FILE_BOX},
378
379 /* sign */ {MOOV_SIGN,
380 /* short */ "Movie box",
381 /* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames",
382 /* sbox */ 1,
383 /* req */ {1, 1, 1},
384 /* ins */ FILE_BOX},
385
386 /* sign */ {MVHD_SIGN,
387 /* short */ "Movie Header box",
388 /* long */ "This box defines overall information which is media-independent, and relevant to the entire presentation "
389 "considered as a whole",
390 /* sbox */ 0,
391 /* req */ {1, 1, 1},
392 /* ins */ MOOV_BOX},
393
394 /* sign */ {TRAK_SIGN,
395 /* short */ "Track box",
396 /* long */ "This is a container box for a single track of a presentation. A presentation may consist of one or more tracks",
397 /* sbox */ 1,
398 /* req */ {1, 1, 1},
399 /* ins */ MOOV_BOX},
400
401 /* sign */ {TKHD_SIGN,
402 /* short */ "Track Header box",
403 /* long */ "This box specifies the characteristics of a single track. Exactly one Track Header Box is contained in a track",
404 /* sbox */ 0,
405 /* req */ {1, 1, 1},
406 /* ins */ TRAK_BOX},
407
408 /* sign */ {MDIA_SIGN,
409 /* short */ "Media box",
410 /* long */ "The media declaration container contains all the objects which declare information about the media data "
411 "within a track",
412 /* sbox */ 1,
413 /* req */ {1, 1, 1},
414 /* ins */ TRAK_BOX},
415
416 /* sign */ {MINF_SIGN,
417 /* short */ "Media Information box",
418 /* long */ "This box contains all the objects which declare characteristic information of the media in the track",
419 /* sbox */ 1,
420 /* req */ {1, 1, 1},
421 /* ins */ MDIA_BOX},
422
423 /* sign */ {STBL_SIGN,
424 /* short */ "Sample Table box",
425 /* long */ "The sample table contains all the time and data indexing of the media samples in a track",
426 /* sbox */ 1,
427 /* req */ {1, 1, 1},
428 /* ins */ MINF_BOX},
429
430 /* sign */ {STSD_SIGN,
431 /* short */ "Sample Description box",
432 /* long */ "The sample description table gives detailed information about the coding type used, and any initialization "
433 "information needed for that coding",
434 /* sbox */ 0,
435 /* req */ {1, 1, 1},
436 /* ins */ MINF_BOX},
437
438 /* sign */ {MJP2_SIGN,
439 /* short */ "MJP2 Sample Description box",
440 /* long */ "The MJP2 sample description table gives detailed information about the coding type used, and any initialization "
441 "information needed for that coding",
442 /* sbox */ 0,
443 /* req */ {1, 1, 1},
444 /* ins */ MINF_BOX},
445
446 /* sign */ {MDAT_SIGN,
447 /* short */ "Media Data box",
448 /* long */ "The meta-data for a presentation is stored in the single Movie Box which occurs at the top-level of a file",
449 /* sbox */ 1,
450 /* req */ {1, 1, 1},
451 /* ins */ FILE_BOX},
452
453 /* sign */ {ANY_SIGN,
454 /* short */ "Any box",
455 /* long */ "All the existing boxes",
456 /* sbox */ 0,
457 /* req */ {0, 0, 0},
458 /* ins */ FILE_BOX},
459
460 /* sign */ {UNK_SIGN,
461 /* short */ "Unknown Type box",
462 /* long */ "The signature is not recognised to be that of an existing box",
463 /* sbox */ 0,
464 /* req */ {0, 0, 0},
465 /* ins */ ANY_BOX}
466
467 };
468
469 /* declaration */
470 int
471 jpeg2000_box_handler_function(jpeg2000boxtype boxtype, wxInputStream& stream, unsigned long int filepoint,
472 unsigned long int filelimit, int level, char *scansign,
473 unsigned long int *scanpoint);
474
475 #ifdef __WXMSW__
476 typedef unsigned __int64 int8byte;
477 #endif // __WXMSW__
478
479 #ifdef __WXGTK__
480 typedef unsigned long long int8byte;
481 #endif // __WXGTK__
482
483 /* internal mini-search for a box signature */
484 int
jpeg2000_file_parse(wxInputStream & stream,unsigned long int filepoint,unsigned long int filelimit,int level,char * scansign,unsigned long int * scanpoint)485 jpeg2000_file_parse(wxInputStream& stream, unsigned long int filepoint, unsigned long int filelimit, int level,
486 char *scansign, unsigned long int *scanpoint)
487 {
488 unsigned long int LBox = 0x00000000;
489 char TBox[5] = "\0\0\0\0";
490 int8byte XLBox = 0x0000000000000000;
491 unsigned long int box_length = 0;
492 int last_box = 0, box_num = 0;
493 int box_type = ANY_BOX;
494 unsigned char fourbytes[4];
495 int box_number = 0;
496
497 /* cycle all over the file */
498 box_num = 0;
499 last_box = 0;
500 while (!last_box) {
501
502 /* do not exceed file limit */
503 if (filepoint >= filelimit)
504 return (0);
505
506 /* seek on file */
507 if (stream.SeekI(filepoint, wxFromStart) == wxInvalidOffset)
508 return (-1);
509
510 /* read the mandatory LBox, 4 bytes */
511 if (!stream.Read(fourbytes, 4)) {
512 wxLogError(wxT("Problem reading LBox from the file (file ended?)"));
513 return -1;
514 };
515 LBox = STREAM_TO_UINT32(fourbytes, 0);
516
517 /* read the mandatory TBox, 4 bytes */
518 if (!stream.Read(TBox, 4)) {
519 wxLogError(wxT("Problem reading TBox from the file (file ended?)"));
520 return -1;
521 };
522
523 /* look if scansign is got */
524 if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) {
525 /* hack/exploit */
526 // stop as soon as you find the level-th codebox
527 if (box_number == level) {
528 memcpy(scansign, " ", 4);
529 *scanpoint = filepoint;
530 return (0);
531 } else
532 box_number++;
533
534 };
535
536 /* determine the box type */
537 for (box_type = JP_BOX; box_type < UNK_BOX; box_type++)
538 if (memcmp(TBox, jpeg2000box[box_type].value, 4) == 0)
539 break;
540
541 /* read the optional XLBox, 8 bytes */
542 if (LBox == 1) {
543
544 if (!stream.Read(&XLBox, 8)) {
545 wxLogError(wxT("Problem reading XLBox from the file (file ended?)"));
546 return -1;
547 };
548 box_length = (unsigned long int) BYTE_SWAP8(XLBox);
549
550 } else if (LBox == 0x00000000) {
551
552 /* last box in file */
553 last_box = 1;
554 box_length = filelimit - filepoint;
555
556 } else
557
558 box_length = LBox;
559
560
561 /* go deep in the box */
562 jpeg2000_box_handler_function((jpeg2000boxtype) box_type,
563 stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8),
564 filepoint + box_length, level, scansign, scanpoint);
565
566 /* if it's a superbox go inside it */
567 if (jpeg2000box[box_type].sbox)
568 jpeg2000_file_parse(stream, (LBox == 1) ? (filepoint + 16) : (filepoint + 8), filepoint + box_length,
569 level, scansign, scanpoint);
570
571 /* increment box number and filepoint*/
572 box_num++;
573 filepoint += box_length;
574
575 };
576
577 /* all good */
578 return (0);
579 }
580
581 // search first contiguos codestream box in an mj2 file
582 unsigned long int
searchjpeg2000c(wxInputStream & stream,unsigned long int fsize,int number)583 searchjpeg2000c(wxInputStream& stream, unsigned long int fsize, int number)
584 {
585 char scansign[] = "jp2c";
586 unsigned long int scanpoint = 0L;
587
588 wxLogMessage(wxT("Searching jp2c box... "));
589
590 /* do the parsing */
591 if (jpeg2000_file_parse(stream, 0, fsize, number, scansign, &scanpoint) < 0)
592 wxLogMessage(wxT("Unrecoverable error during JPEG 2000 box parsing: stopping"));
593
594 if (strcmp(scansign, " "))
595 wxLogMessage(wxT("Box not found"));
596 else {
597
598 wxLogMessage(wxString::Format(wxT("Box found at byte %d"), scanpoint));
599
600 };
601
602 return (scanpoint);
603 }
604
605 // search the jp2h box in the file
606 unsigned long int
searchjpeg2000headerbox(wxInputStream & stream,unsigned long int fsize)607 searchjpeg2000headerbox(wxInputStream& stream, unsigned long int fsize)
608 {
609 char scansign[] = "jp2h";
610 unsigned long int scanpoint = 0L;
611
612 wxLogMessage(wxT("Searching jp2h box... "));
613
614 /* do the parsing */
615 if (jpeg2000_file_parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0)
616 wxLogMessage(wxT("Unrecoverable error during JPEG 2000 box parsing: stopping"));
617
618 if (strcmp(scansign, " "))
619 wxLogMessage(wxT("Box not found"));
620 else
621 wxLogMessage(wxString::Format(wxT("Box found at byte %d"), scanpoint));
622
623 return (scanpoint);
624 }
625
626 /* handling functions */
627 #define ITEM_PER_ROW 10
628
629 /* Box handler function */
630 int
jpeg2000_box_handler_function(jpeg2000boxtype boxtype,wxInputStream & stream,unsigned long int filepoint,unsigned long int filelimit,int level,char * scansign,unsigned long int * scanpoint)631 jpeg2000_box_handler_function(jpeg2000boxtype boxtype, wxInputStream& stream, unsigned long int filepoint,
632 unsigned long int filelimit, int level,
633 char *scansign, unsigned long int *scanpoint)
634 {
635 switch (boxtype) {
636
637 /* Sample Description box */
638 case (STSD_BOX):
639 jpeg2000_file_parse(stream, filepoint + 8, filelimit, level, scansign, scanpoint);
640 break;
641
642 /* MJP2 Sample Description box */
643 case (MJP2_BOX):
644 jpeg2000_file_parse(stream, filepoint + 78, filelimit, level, scansign, scanpoint);
645 break;
646
647 /* not yet implemented */
648 default:
649 break;
650
651 };
652
653 return (0);
654 }
655
656 // the jP and ftyp parts of the header
657 #define jpeg2000headSIZE 32
658 unsigned char jpeg2000head[jpeg2000headSIZE] = {
659 0x00, 0x00, 0x00, 0x0C, 'j', 'P', ' ', ' ',
660 0x0D, 0x0A, 0x87, 0x0A, 0x00, 0x00, 0x00, 0x14,
661 'f', 't', 'y', 'p', 'j', 'p', '2', ' ',
662 0x00, 0x00, 0x00, 0x00, 'j', 'p', '2', ' '
663 };
664
665 /////////////////////////////////////////////////
666 /////////////////////////////////////////////////
667
668 // load the jpeg2000 file format
LoadFile(wxImage * image,wxInputStream & stream,bool verbose,int index)669 bool wxJPEG2000Handler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int index)
670 {
671 opj_dparameters_t parameters; /* decompression parameters */
672 opj_event_mgr_t event_mgr; /* event manager */
673 opj_image_t *opjimage = NULL;
674 unsigned char *src = NULL;
675 unsigned char *ptr;
676 int file_length, jp2c_point, jp2h_point;
677 unsigned long int jp2hboxlen, jp2cboxlen;
678 opj_codestream_info_t cstr_info; /* Codestream information structure */
679 unsigned char hdr[24];
680 int jpfamform;
681
682 // destroy the image
683 image->Destroy();
684
685 /* read the beginning of the file to check the type */
686 if (!stream.Read(hdr, WXSIZEOF(hdr)))
687 return false;
688 if ((jpfamform = jpeg2000familytype(hdr, WXSIZEOF(hdr))) < 0)
689 return false;
690 stream.SeekI(0, wxFromStart);
691
692 /* handle to a decompressor */
693 opj_dinfo_t* dinfo = NULL;
694 opj_cio_t *cio = NULL;
695
696 /* configure the event callbacks */
697 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
698 event_mgr.error_handler = jpeg2000_error_callback;
699 event_mgr.warning_handler = jpeg2000_warning_callback;
700 event_mgr.info_handler = jpeg2000_info_callback;
701
702 /* set decoding parameters to default values */
703 opj_set_default_decoder_parameters(¶meters);
704
705 /* prepare parameters */
706 strncpy(parameters.infile, "", sizeof(parameters.infile) - 1);
707 strncpy(parameters.outfile, "", sizeof(parameters.outfile) - 1);
708 parameters.decod_format = jpfamform;
709 parameters.cod_format = BMP_DFMT;
710 if (m_reducefactor)
711 parameters.cp_reduce = m_reducefactor;
712 if (m_qualitylayers)
713 parameters.cp_layer = m_qualitylayers;
714 /*if (n_components)
715 parameters. = n_components;*/
716
717 /* JPWL only */
718 #ifdef USE_JPWL
719 parameters.jpwl_exp_comps = m_expcomps;
720 parameters.jpwl_max_tiles = m_maxtiles;
721 parameters.jpwl_correct = m_enablejpwl;
722 #endif /* USE_JPWL */
723
724 /* get a decoder handle */
725 if (jpfamform == JP2_CFMT || jpfamform == MJ2_CFMT)
726 dinfo = opj_create_decompress(CODEC_JP2);
727 else if (jpfamform == J2K_CFMT)
728 dinfo = opj_create_decompress(CODEC_J2K);
729 else
730 return false;
731
732 /* find length of the stream */
733 stream.SeekI(0, wxFromEnd);
734 file_length = (int) stream.TellI();
735
736 /* it's a movie */
737 if (jpfamform == MJ2_CFMT) {
738 /* search for the first codestream box and the movie header box */
739 jp2c_point = searchjpeg2000c(stream, file_length, m_framenum);
740 jp2h_point = searchjpeg2000headerbox(stream, file_length);
741
742 // read the jp2h box and store it
743 stream.SeekI(jp2h_point, wxFromStart);
744 stream.Read(&jp2hboxlen, sizeof(unsigned long int));
745 jp2hboxlen = BYTE_SWAP4(jp2hboxlen);
746
747 // read the jp2c box and store it
748 stream.SeekI(jp2c_point, wxFromStart);
749 stream.Read(&jp2cboxlen, sizeof(unsigned long int));
750 jp2cboxlen = BYTE_SWAP4(jp2cboxlen);
751
752 // malloc memory source
753 src = (unsigned char *) malloc(jpeg2000headSIZE + jp2hboxlen + jp2cboxlen);
754
755 // copy the jP and ftyp
756 memcpy(src, jpeg2000head, jpeg2000headSIZE);
757
758 // copy the jp2h
759 stream.SeekI(jp2h_point, wxFromStart);
760 stream.Read(&src[jpeg2000headSIZE], jp2hboxlen);
761
762 // copy the jp2c
763 stream.SeekI(jp2c_point, wxFromStart);
764 stream.Read(&src[jpeg2000headSIZE + jp2hboxlen], jp2cboxlen);
765 } else if (jpfamform == JP2_CFMT || jpfamform == J2K_CFMT) {
766 /* It's a plain image */
767 /* get data */
768 stream.SeekI(0, wxFromStart);
769 src = (unsigned char *) malloc(file_length);
770 stream.Read(src, file_length);
771 } else
772 return false;
773
774 /* catch events using our callbacks and give a local context */
775 opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
776
777 /* setup the decoder decoding parameters using user parameters */
778 opj_setup_decoder(dinfo, ¶meters);
779
780 /* open a byte stream */
781 if (jpfamform == MJ2_CFMT)
782 cio = opj_cio_open((opj_common_ptr)dinfo, src, jpeg2000headSIZE + jp2hboxlen + jp2cboxlen);
783 else if (jpfamform == JP2_CFMT || jpfamform == J2K_CFMT)
784 cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length);
785 else {
786 free(src);
787 return false;
788 }
789
790 /* decode the stream and fill the image structure */
791 opjimage = opj_decode_with_info(dinfo, cio, &cstr_info);
792 if (!opjimage) {
793 wxMutexGuiEnter();
794 wxLogError(wxT("JPEG 2000 failed to decode image!"));
795 wxMutexGuiLeave();
796 opj_destroy_decompress(dinfo);
797 opj_cio_close(cio);
798 free(src);
799 return false;
800 }
801
802 /* close the byte stream */
803 opj_cio_close(cio);
804
805 /*
806
807 - At this point, we have the structure "opjimage" that is filled with decompressed
808 data, as processed by the OpenJPEG decompression engine
809
810 - We need to fill the class "image" with the proper pixel sample values
811
812 */
813 {
814 int shiftbpp;
815 int c, tempcomps;
816
817 // check components number
818 if (m_components > opjimage->numcomps)
819 m_components = opjimage->numcomps;
820
821 // check image depth (only on the first one, for now)
822 if (m_components)
823 shiftbpp = opjimage->comps[m_components - 1].prec - 8;
824 else
825 shiftbpp = opjimage->comps[0].prec - 8;
826
827 // prepare image size
828 if (m_components)
829 image->Create(opjimage->comps[m_components - 1].w, opjimage->comps[m_components - 1].h, true);
830 else
831 image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true);
832
833 // access image raw data
834 image->SetMask(false);
835 ptr = image->GetData();
836
837 // workaround for components different from 1 or 3
838 if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) {
839 #ifndef __WXGTK__
840 wxMutexGuiEnter();
841 #endif /* __WXGTK__ */
842 wxLogMessage(wxT("JPEG2000: weird number of components"));
843 #ifndef __WXGTK__
844 wxMutexGuiLeave();
845 #endif /* __WXGTK__ */
846 tempcomps = 1;
847 } else
848 tempcomps = opjimage->numcomps;
849
850 // workaround for subsampled components
851 for (c = 1; c < tempcomps; c++) {
852 if ((opjimage->comps[c].w != opjimage->comps[c - 1].w) || (opjimage->comps[c].h != opjimage->comps[c - 1].h)) {
853 tempcomps = 1;
854 break;
855 }
856 }
857
858 // workaround for different precision components
859 for (c = 1; c < tempcomps; c++) {
860 if (opjimage->comps[c].bpp != opjimage->comps[c - 1].bpp) {
861 tempcomps = 1;
862 break;
863 }
864 }
865
866 // only one component selected
867 if (m_components)
868 tempcomps = 1;
869
870 // RGB color picture
871 if (tempcomps == 3) {
872 int row, col;
873 int *r = opjimage->comps[0].data;
874 int *g = opjimage->comps[1].data;
875 int *b = opjimage->comps[2].data;
876 if (shiftbpp > 0) {
877 for (row = 0; row < opjimage->comps[0].h; row++) {
878 for (col = 0; col < opjimage->comps[0].w; col++) {
879
880 *(ptr++) = (*(r++)) >> shiftbpp;
881 *(ptr++) = (*(g++)) >> shiftbpp;
882 *(ptr++) = (*(b++)) >> shiftbpp;
883
884 }
885 }
886
887 } else if (shiftbpp < 0) {
888 for (row = 0; row < opjimage->comps[0].h; row++) {
889 for (col = 0; col < opjimage->comps[0].w; col++) {
890
891 *(ptr++) = (*(r++)) << -shiftbpp;
892 *(ptr++) = (*(g++)) << -shiftbpp;
893 *(ptr++) = (*(b++)) << -shiftbpp;
894
895 }
896 }
897
898 } else {
899 for (row = 0; row < opjimage->comps[0].h; row++) {
900 for (col = 0; col < opjimage->comps[0].w; col++) {
901
902 *(ptr++) = *(r++);
903 *(ptr++) = *(g++);
904 *(ptr++) = *(b++);
905
906 }
907 }
908 }
909 }
910
911 // B/W picture
912 if (tempcomps == 1) {
913 int row, col;
914 int selcomp;
915
916 if (m_components)
917 selcomp = m_components - 1;
918 else
919 selcomp = 0;
920
921 int *y = opjimage->comps[selcomp].data;
922 if (shiftbpp > 0) {
923 for (row = 0; row < opjimage->comps[selcomp].h; row++) {
924 for (col = 0; col < opjimage->comps[selcomp].w; col++) {
925
926 *(ptr++) = (*(y)) >> shiftbpp;
927 *(ptr++) = (*(y)) >> shiftbpp;
928 *(ptr++) = (*(y++)) >> shiftbpp;
929
930 }
931 }
932 } else if (shiftbpp < 0) {
933 for (row = 0; row < opjimage->comps[selcomp].h; row++) {
934 for (col = 0; col < opjimage->comps[selcomp].w; col++) {
935
936 *(ptr++) = (*(y)) << -shiftbpp;
937 *(ptr++) = (*(y)) << -shiftbpp;
938 *(ptr++) = (*(y++)) << -shiftbpp;
939
940 }
941 }
942 } else {
943 for (row = 0; row < opjimage->comps[selcomp].h; row++) {
944 for (col = 0; col < opjimage->comps[selcomp].w; col++) {
945
946 *(ptr++) = *(y);
947 *(ptr++) = *(y);
948 *(ptr++) = *(y++);
949
950 }
951 }
952 }
953 }
954
955
956 }
957
958 wxMutexGuiEnter();
959 wxLogMessage(wxT("JPEG 2000 image loaded."));
960 wxMutexGuiLeave();
961
962 /* close openjpeg structs */
963 opj_destroy_decompress(dinfo);
964 opj_image_destroy(opjimage);
965 free(src);
966
967 if (!image->Ok())
968 return false;
969 else
970 return true;
971
972 }
973
974 #define CINEMA_24_CS 1302083 /* Codestream length for 24fps */
975 #define CINEMA_48_CS 651041 /* Codestream length for 48fps */
976 #define COMP_24_CS 1041666 /* Maximum size per color component for 2K & 4K @ 24fps */
977 #define COMP_48_CS 520833 /* Maximum size per color component for 2K @ 48fps */
978
979 // save the j2k codestream
SaveFile(wxImage * wimage,wxOutputStream & stream,bool verbose)980 bool wxJPEG2000Handler::SaveFile( wxImage *wimage, wxOutputStream& stream, bool verbose )
981 {
982 opj_cparameters_t parameters; /* compression parameters */
983 opj_event_mgr_t event_mgr; /* event manager */
984 opj_image_t *oimage = NULL;
985 opj_image_cmptparm_t *cmptparm;
986 opj_cio_t *cio = NULL;
987 opj_codestream_info_t cstr_info;
988 int codestream_length;
989 bool bSuccess;
990 int i;
991 char indexfilename[OPJ_PATH_LEN] = ""; /* index file name */
992
993 /*
994 configure the event callbacks (not required)
995 setting of each callback is optionnal
996 */
997 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
998 event_mgr.error_handler = jpeg2000_error_callback;
999 event_mgr.warning_handler = jpeg2000_warning_callback;
1000 event_mgr.info_handler = jpeg2000_info_callback;
1001
1002 /* set encoding parameters to default values */
1003 opj_set_default_encoder_parameters(¶meters);
1004
1005 /* load parameters */
1006 parameters.cp_cinema = OFF;
1007
1008 /* subsampling */
1009 if (sscanf(m_subsampling.ToAscii(), "%d,%d", &(parameters.subsampling_dx), &(parameters.subsampling_dy)) != 2) {
1010 wxLogError(wxT("Wrong sub-sampling encoder setting: dx,dy"));
1011 return false;
1012 }
1013
1014 /* compression rates */
1015 if ((m_rates != wxT("")) && (!m_enablequality)) {
1016 const char *s1 = m_rates.ToAscii();
1017 wxLogMessage(wxT("rates %s"), s1);
1018 while (sscanf(s1, "%f", &(parameters.tcp_rates[parameters.tcp_numlayers])) == 1) {
1019 parameters.tcp_numlayers++;
1020 while (*s1 && *s1 != ',') {
1021 s1++;
1022 }
1023 if (!*s1)
1024 break;
1025 s1++;
1026 }
1027 wxLogMessage(wxT("%d layers"), parameters.tcp_numlayers);
1028 parameters.cp_disto_alloc = 1;
1029 }
1030
1031 /* image quality, dB */
1032 if ((m_quality != wxT("")) && (m_enablequality)) {
1033 const char *s2 = m_quality.ToAscii();
1034 wxLogMessage(wxT("qualities %s"), s2);
1035 while (sscanf(s2, "%f", ¶meters.tcp_distoratio[parameters.tcp_numlayers]) == 1) {
1036 parameters.tcp_numlayers++;
1037 while (*s2 && *s2 != ',') {
1038 s2++;
1039 }
1040 if (!*s2)
1041 break;
1042 s2++;
1043 }
1044 wxLogMessage(wxT("%d layers"), parameters.tcp_numlayers);
1045 parameters.cp_fixed_quality = 1;
1046 }
1047
1048 /* image origin */
1049 if (sscanf(m_origin.ToAscii(), "%d,%d", ¶meters.image_offset_x0, ¶meters.image_offset_y0) != 2) {
1050 wxLogError(wxT("bad coordinate of the image origin: x0,y0"));
1051 return false;
1052 }
1053
1054 /* Create comment for codestream */
1055 if(m_enablecomm) {
1056 parameters.cp_comment = (char *) malloc(strlen(m_comment.ToAscii()) + 1);
1057 if(parameters.cp_comment) {
1058 strcpy(parameters.cp_comment, m_comment.ToAscii());
1059 }
1060 } else {
1061 parameters.cp_comment = NULL;
1062 }
1063
1064 /* indexing file */
1065 if (m_enableidx) {
1066 strncpy(indexfilename, m_index.ToAscii(), OPJ_PATH_LEN);
1067 wxLogMessage(wxT("index file is %s"), indexfilename);
1068 }
1069
1070 /* if no rate entered, lossless by default */
1071 if (parameters.tcp_numlayers == 0) {
1072 parameters.tcp_rates[0] = 0; /* MOD antonin : losslessbug */
1073 parameters.tcp_numlayers++;
1074 parameters.cp_disto_alloc = 1;
1075 }
1076
1077 /* irreversible transform */
1078 parameters.irreversible = (m_irreversible == true) ? 1 : 0;
1079
1080 /* resolutions */
1081 parameters.numresolution = m_resolutions;
1082
1083 /* codeblocks size */
1084 if (m_cbsize != wxT("")) {
1085 int cblockw_init = 0, cblockh_init = 0;
1086 sscanf(m_cbsize.ToAscii(), "%d,%d", &cblockw_init, &cblockh_init);
1087 if (cblockw_init * cblockh_init > 4096 || cblockw_init > 1024 || cblockw_init < 4 || cblockh_init > 1024 || cblockh_init < 4) {
1088 wxLogError(wxT("!! Size of code_block error !! Restrictions:\n width*height<=4096\n 4<=width,height<= 1024"));
1089 return false;
1090 }
1091 parameters.cblockw_init = cblockw_init;
1092 parameters.cblockh_init = cblockh_init;
1093 }
1094
1095 /* precincts size */
1096 if (m_prsize != wxT("")) {
1097 char sep;
1098 int res_spec = 0;
1099 char *s = (char *) m_prsize.c_str();
1100 do {
1101 sep = 0;
1102 sscanf(s, "[%d,%d]%c", ¶meters.prcw_init[res_spec], ¶meters.prch_init[res_spec], &sep);
1103 parameters.csty |= 0x01;
1104 res_spec++;
1105 s = strpbrk(s, "]") + 2;
1106 } while (sep == ',');
1107 parameters.res_spec = res_spec;
1108 }
1109
1110 /* tiles */
1111 if (m_tsize != wxT("")) {
1112 sscanf(m_tsize.ToAscii(), "%d,%d", ¶meters.cp_tdx, ¶meters.cp_tdy);
1113 parameters.tile_size_on = true;
1114 }
1115
1116 /* tile origin */
1117 if (sscanf(m_torigin.ToAscii(), "%d,%d", ¶meters.cp_tx0, ¶meters.cp_ty0) != 2) {
1118 wxLogError(wxT("tile offset setting error: X0,Y0"));
1119 return false;
1120 }
1121
1122 /* use SOP */
1123 if (m_enablesop)
1124 parameters.csty |= 0x02;
1125
1126 /* use EPH */
1127 if (m_enableeph)
1128 parameters.csty |= 0x04;
1129
1130 /* multiple component transform */
1131 if (m_multicomp)
1132 parameters.tcp_mct = 1;
1133 else
1134 parameters.tcp_mct = 0;
1135
1136 /* mode switch */
1137 parameters.mode = (m_enablebypass ? 1 : 0) + (m_enablereset ? 2 : 0)
1138 + (m_enablerestart ? 4 : 0) + (m_enablevsc ? 8 : 0)
1139 + (m_enableerterm ? 16 : 0) + (m_enablesegmark ? 32 : 0);
1140
1141 /* progression order */
1142 switch (m_progression) {
1143
1144 /* LRCP */
1145 case 0:
1146 parameters.prog_order = LRCP;
1147 break;
1148
1149 /* RLCP */
1150 case 1:
1151 parameters.prog_order = RLCP;
1152 break;
1153
1154 /* RPCL */
1155 case 2:
1156 parameters.prog_order = RPCL;
1157 break;
1158
1159 /* PCRL */
1160 case 3:
1161 parameters.prog_order = PCRL;
1162 break;
1163
1164 /* CPRL */
1165 case 4:
1166 parameters.prog_order = CPRL;
1167 break;
1168
1169 /* DCI2K24 */
1170 case 5:
1171 parameters.cp_cinema = CINEMA2K_24;
1172 parameters.cp_rsiz = CINEMA2K;
1173 break;
1174
1175 /* DCI2K48 */
1176 case 6:
1177 parameters.cp_cinema = CINEMA2K_48;
1178 parameters.cp_rsiz = CINEMA2K;
1179 break;
1180
1181 /* DCI4K */
1182 case 7:
1183 parameters.cp_cinema = CINEMA4K_24;
1184 parameters.cp_rsiz = CINEMA4K;
1185 break;
1186
1187 default:
1188 break;
1189 }
1190
1191 /* check cinema */
1192 if (parameters.cp_cinema) {
1193
1194 /* set up */
1195 parameters.tile_size_on = false;
1196 parameters.cp_tdx=1;
1197 parameters.cp_tdy=1;
1198
1199 /*Tile part*/
1200 parameters.tp_flag = 'C';
1201 parameters.tp_on = 1;
1202
1203 /*Tile and Image shall be at (0,0)*/
1204 parameters.cp_tx0 = 0;
1205 parameters.cp_ty0 = 0;
1206 parameters.image_offset_x0 = 0;
1207 parameters.image_offset_y0 = 0;
1208
1209 /*Codeblock size= 32*32*/
1210 parameters.cblockw_init = 32;
1211 parameters.cblockh_init = 32;
1212 parameters.csty |= 0x01;
1213
1214 /*The progression order shall be CPRL*/
1215 parameters.prog_order = CPRL;
1216
1217 /* No ROI */
1218 parameters.roi_compno = -1;
1219
1220 parameters.subsampling_dx = 1;
1221 parameters.subsampling_dy = 1;
1222
1223 /* 9-7 transform */
1224 parameters.irreversible = 1;
1225
1226 }
1227
1228 /* convert wx image into opj image */
1229 cmptparm = (opj_image_cmptparm_t*) malloc(3 * sizeof(opj_image_cmptparm_t));
1230
1231 /* initialize opj image components */
1232 memset(&cmptparm[0], 0, 3 * sizeof(opj_image_cmptparm_t));
1233 for(i = 0; i < 3; i++) {
1234 cmptparm[i].prec = 8;
1235 cmptparm[i].bpp = 8;
1236 cmptparm[i].sgnd = false;
1237 cmptparm[i].dx = parameters.subsampling_dx;
1238 cmptparm[i].dy = parameters.subsampling_dy;
1239 cmptparm[i].w = wimage->GetWidth();
1240 cmptparm[i].h = wimage->GetHeight();
1241 }
1242
1243 /* create the image */
1244 oimage = opj_image_create(3, &cmptparm[0], CLRSPC_SRGB);
1245 if(!oimage) {
1246 if (cmptparm)
1247 free(cmptparm);
1248 return false;
1249 }
1250
1251 /* set image offset and reference grid */
1252 oimage->x0 = parameters.image_offset_x0;
1253 oimage->y0 = parameters.image_offset_y0;
1254 oimage->x1 = parameters.image_offset_x0 + (wimage->GetWidth() - 1) * 1 + 1;
1255 oimage->y1 = parameters.image_offset_y0 + (wimage->GetHeight() - 1) * 1 + 1;
1256
1257 /* load image data */
1258 unsigned char *value = wimage->GetData();
1259 int area = wimage->GetWidth() * wimage->GetHeight();
1260 for (i = 0; i < area; i++) {
1261 oimage->comps[0].data[i] = *(value++);
1262 oimage->comps[1].data[i] = *(value++);
1263 oimage->comps[2].data[i] = *(value++);
1264 }
1265
1266 /* check cinema again */
1267 if (parameters.cp_cinema) {
1268 int i;
1269 float temp_rate;
1270 opj_poc_t *POC = NULL;
1271
1272 switch (parameters.cp_cinema) {
1273
1274 case CINEMA2K_24:
1275 case CINEMA2K_48:
1276 if (parameters.numresolution > 6) {
1277 parameters.numresolution = 6;
1278 }
1279 if (!((oimage->comps[0].w == 2048) | (oimage->comps[0].h == 1080))) {
1280 wxLogWarning(wxT("Image coordinates %d x %d is not 2K compliant. JPEG Digital Cinema Profile-3 "
1281 "(2K profile) compliance requires that at least one of coordinates match 2048 x 1080"),
1282 oimage->comps[0].w, oimage->comps[0].h);
1283 parameters.cp_rsiz = STD_RSIZ;
1284 }
1285 break;
1286
1287 case CINEMA4K_24:
1288 if (parameters.numresolution < 1) {
1289 parameters.numresolution = 1;
1290 } else if (parameters.numresolution > 7) {
1291 parameters.numresolution = 7;
1292 }
1293 if (!((oimage->comps[0].w == 4096) | (oimage->comps[0].h == 2160))) {
1294 wxLogWarning(wxT("Image coordinates %d x %d is not 4K compliant. JPEG Digital Cinema Profile-4"
1295 "(4K profile) compliance requires that at least one of coordinates match 4096 x 2160"),
1296 oimage->comps[0].w, oimage->comps[0].h);
1297 parameters.cp_rsiz = STD_RSIZ;
1298 }
1299 parameters.POC[0].tile = 1;
1300 parameters.POC[0].resno0 = 0;
1301 parameters.POC[0].compno0 = 0;
1302 parameters.POC[0].layno1 = 1;
1303 parameters.POC[0].resno1 = parameters.numresolution - 1;
1304 parameters.POC[0].compno1 = 3;
1305 parameters.POC[0].prg1 = CPRL;
1306 parameters.POC[1].tile = 1;
1307 parameters.POC[1].resno0 = parameters.numresolution - 1;
1308 parameters.POC[1].compno0 = 0;
1309 parameters.POC[1].layno1 = 1;
1310 parameters.POC[1].resno1 = parameters.numresolution;
1311 parameters.POC[1].compno1 = 3;
1312 parameters.POC[1].prg1 = CPRL;
1313 parameters.numpocs = 2;
1314 break;
1315 }
1316
1317 switch (parameters.cp_cinema) {
1318 case CINEMA2K_24:
1319 case CINEMA4K_24:
1320 for (i = 0 ; i < parameters.tcp_numlayers; i++) {
1321 temp_rate = 0;
1322 if (parameters.tcp_rates[i] == 0) {
1323 parameters.tcp_rates[0] = ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) /
1324 (CINEMA_24_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy);
1325 }else{
1326 temp_rate = ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) /
1327 (parameters.tcp_rates[i] * 8 * oimage->comps[0].dx * oimage->comps[0].dy);
1328 if (temp_rate > CINEMA_24_CS ) {
1329 parameters.tcp_rates[i]= ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) /
1330 (CINEMA_24_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy);
1331 } else {
1332 /* do nothing */
1333 }
1334 }
1335 }
1336 parameters.max_comp_size = COMP_24_CS;
1337 break;
1338
1339 case CINEMA2K_48:
1340 for (i = 0; i < parameters.tcp_numlayers; i++) {
1341 temp_rate = 0 ;
1342 if (parameters.tcp_rates[i] == 0) {
1343 parameters.tcp_rates[0] = ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) /
1344 (CINEMA_48_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy);
1345 }else{
1346 temp_rate =((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) /
1347 (parameters.tcp_rates[i] * 8 * oimage->comps[0].dx * oimage->comps[0].dy);
1348 if (temp_rate > CINEMA_48_CS ){
1349 parameters.tcp_rates[0]= ((float) (oimage->numcomps * oimage->comps[0].w * oimage->comps[0].h * oimage->comps[0].prec)) /
1350 (CINEMA_48_CS * 8 * oimage->comps[0].dx * oimage->comps[0].dy);
1351 }else{
1352 /* do nothing */
1353 }
1354 }
1355 }
1356 parameters.max_comp_size = COMP_48_CS;
1357 break;
1358 }
1359
1360 parameters.cp_disto_alloc = 1;
1361 }
1362
1363 /* get a J2K compressor handle */
1364 opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K);
1365
1366 /* catch events using our callbacks and give a local context */
1367 opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
1368
1369 /* setup the encoder parameters using the current image and user parameters */
1370 opj_setup_encoder(cinfo, ¶meters, oimage);
1371
1372 /* open a byte stream for writing */
1373 /* allocate memory for all tiles */
1374 cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
1375
1376 /* encode the image */
1377 bSuccess = opj_encode_with_info(cinfo, cio, oimage, &cstr_info);
1378 if (!bSuccess) {
1379
1380 opj_cio_close(cio);
1381 opj_destroy_compress(cinfo);
1382 opj_image_destroy(oimage);
1383 if (cmptparm)
1384 free(cmptparm);
1385 if(parameters.cp_comment)
1386 free(parameters.cp_comment);
1387 if(parameters.cp_matrice)
1388 free(parameters.cp_matrice);
1389
1390 #ifndef __WXGTK__
1391 wxMutexGuiEnter();
1392 #endif /* __WXGTK__ */
1393
1394 wxLogError(wxT("failed to encode image"));
1395
1396 #ifndef __WXGTK__
1397 wxMutexGuiLeave();
1398 #endif /* __WXGTK__ */
1399
1400 return false;
1401 }
1402 codestream_length = cio_tell(cio);
1403 wxLogMessage(wxT("Codestream: %d bytes"), codestream_length);
1404
1405 /* write the buffer to stream */
1406 stream.Write(cio->buffer, codestream_length);
1407
1408 /* close and free the byte stream */
1409 opj_cio_close(cio);
1410
1411 /* Write the index to disk */
1412 if (*indexfilename) {
1413 if (write_index_file(&cstr_info, indexfilename)) {
1414 wxLogError(wxT("Failed to output index file"));
1415 }
1416 }
1417
1418 /* free remaining compression structures */
1419 opj_destroy_compress(cinfo);
1420
1421 /* free image data */
1422 opj_image_destroy(oimage);
1423
1424 if (cmptparm)
1425 free(cmptparm);
1426 if(parameters.cp_comment)
1427 free(parameters.cp_comment);
1428 if(parameters.cp_matrice)
1429 free(parameters.cp_matrice);
1430
1431 #ifndef __WXGTK__
1432 wxMutexGuiEnter();
1433 #endif /* __WXGTK__ */
1434
1435 wxLogMessage(wxT("J2K: Image encoded!"));
1436
1437 #ifndef __WXGTK__
1438 wxMutexGuiLeave();
1439 #endif /* __WXGTK__ */
1440
1441 return true;
1442 }
1443
1444 #ifdef __VISUALC__
1445 #pragma warning(default:4611)
1446 #endif /* VC++ */
1447
1448 // recognize the JPEG 2000 family starting box or the 0xFF4F JPEG 2000 SOC marker
DoCanRead(wxInputStream & stream)1449 bool wxJPEG2000Handler::DoCanRead(wxInputStream& stream)
1450 {
1451 unsigned char hdr[24];
1452 int jpfamform;
1453
1454 if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
1455 return false;
1456
1457 jpfamform = jpeg2000familytype(hdr, WXSIZEOF(hdr));
1458
1459 return ((jpfamform == JP2_CFMT) || (jpfamform == MJ2_CFMT) || (jpfamform == J2K_CFMT));
1460 }
1461
1462 #endif // wxUSE_STREAMS
1463
1464 #endif // wxUSE_LIBOPENJPEG
1465