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