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(&parameters);
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, &parameters);
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(&parameters);
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", &parameters.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", &parameters.image_offset_x0, &parameters.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", &parameters.prcw_init[res_spec], &parameters.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", &parameters.cp_tdx, &parameters.cp_tdy);
1113                 parameters.tile_size_on = true;
1114         }
1115 
1116         /* tile origin */
1117         if (sscanf(m_torigin.ToAscii(), "%d,%d", &parameters.cp_tx0, &parameters.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, &parameters, 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