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.
7 * Copyright (c) 2007, Digital Signal Processing Laboratory, Universit� degli studi di Perugia (UPG), Italy
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
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 /////////////////////////////////////////////////////////////////////////////
40 // For compilers that support precompilation, includes "wx.h".
41 #include "wx/wxprec.h"
47 #if wxUSE_IMAGE && wxUSE_LIBOPENJPEG
49 #include "imagjpeg2000.h"
55 #include "wx/bitmap.h"
56 #include "wx/module.h"
59 #include "openjp2/openjpeg.h"
61 #include "wx/filefn.h"
62 #include "wx/wfstream.h"
64 // ----------------------------------------------------------------------------
66 // ----------------------------------------------------------------------------
69 //-----------------------------------------------------------------------------
71 //-----------------------------------------------------------------------------
73 IMPLEMENT_DYNAMIC_CLASS(wxJPEG2000Handler, wxImageHandler)
77 //------------- JPEG 2000 Data Source Manager
88 #define MAX_MESSAGE_LEN 200
92 jpeg2000familytype(unsigned char *hdr, int hdr_len)
100 if (hdr[0] == 0x00 &&
114 } else if (hdr[0] == 0x00 &&
129 } else if (hdr[0] == 0xFF &&
142 /* we have to use this to avoid GUI-noGUI threads crashing */
143 void printevent(const char *msg)
147 #endif /* __WXGTK__ */
148 wxLogMessage(wxT("%s"), msg);
151 #endif /* __WXGTK__ */
154 /* sample error callback expecting a FILE* client object */
155 void jpeg2000_error_callback(const char *msg, void *client_data)
157 char mess[MAX_MESSAGE_LEN + 20];
158 int message_len = strlen(msg);
160 if (message_len > MAX_MESSAGE_LEN) {
161 message_len = MAX_MESSAGE_LEN;
164 if (msg[message_len - 1] == '\n') {
168 sprintf(mess, "[ERROR] %.*s", message_len, msg);
172 /* sample warning callback expecting a FILE* client object */
173 void jpeg2000_warning_callback(const char *msg, void *client_data)
175 char mess[MAX_MESSAGE_LEN + 20];
176 int message_len = strlen(msg);
178 if (message_len > MAX_MESSAGE_LEN) {
179 message_len = MAX_MESSAGE_LEN;
182 if (msg[message_len - 1] == '\n') {
186 sprintf(mess, "[WARNING] %.*s", message_len, msg);
190 /* sample debug callback expecting no client object */
191 void jpeg2000_info_callback(const char *msg, void *client_data)
193 char mess[MAX_MESSAGE_LEN + 20];
194 int message_len = strlen(msg);
196 if (message_len > MAX_MESSAGE_LEN) {
197 message_len = MAX_MESSAGE_LEN;
200 if (msg[message_len - 1] == '\n') {
204 sprintf(mess, "[INFO] %.*s", message_len, msg);
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)
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)
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)
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))
231 #define STREAM_TO_UINT16(C, P) (((unsigned long int) (C)[(P) + 0] << 8) + \
232 ((unsigned long int) (C)[(P) + 1] << 0))
235 #define SHORT_DESCR_LEN 32
236 #define LONG_DESCR_LEN 256
238 /* enumeration for file formats */
239 #define JPEG2000FILENUM 4
249 /* enumeration for the box types */
250 #define JPEG2000BOXNUM 23
279 /* jpeg2000 family box signatures */
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"
305 /* the box structure itself */
306 struct jpeg2000boxdef {
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... */
317 /* the possible boxes */
318 struct jpeg2000boxdef jpeg2000box[] = {
321 /* short */ "placeholder for nothing",
322 /* long */ "Nothing to say",
330 /* short */ "JPEG 2000 Signature box",
331 /* long */ "This box uniquely identifies the file as being part of the JPEG 2000 family of files",
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",
349 /* short */ "JP2 Header box",
350 /* long */ "This box contains a series of boxes that contain header-type information about the file",
358 /* short */ "Image Header box",
359 /* long */ "This box specifies the size of the image and other related fields",
367 /* short */ "Colour Specification box",
368 /* long */ "This box specifies the colourspace of the image",
376 /* short */ "Contiguous Codestream box",
377 /* long */ "This box contains the codestream as defined by Annex A",
385 /* short */ "Intellectual Property box",
386 /* long */ "This box contains intellectual property information about the image",
394 /* short */ "XML box",
395 /* long */ "This box provides a tool by which vendors can add XML formatted information to a JP2 file",
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",
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",
422 /* short */ "Movie box",
423 /* long */ "This box contains the media data. In video tracks, this box would contain JPEG2000 video frames",
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",
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",
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",
459 /* short */ "Media box",
460 /* long */ "The media declaration container contains all the objects which declare information about the media data "
469 /* short */ "Media Information box",
470 /* long */ "This box contains all the objects which declare characteristic information of the media in the track",
478 /* short */ "Sample Table box",
479 /* long */ "The sample table contains all the time and data indexing of the media samples in a track",
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",
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",
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",
516 /* short */ "Any box",
517 /* long */ "All the existing boxes",
525 /* short */ "Unknown Type box",
526 /* long */ "The signature is not recognised to be that of an existing box",
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);
542 typedef unsigned __int64 int8byte;
546 typedef unsigned long long int8byte;
549 /* internal mini-search for a box signature */
551 jpeg2000_file_parse(wxInputStream& stream, unsigned long int filepoint,
552 unsigned long int filelimit, int level,
553 char *scansign, unsigned long int *scanpoint)
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];
564 /* cycle all over the file */
569 /* do not exceed file limit */
570 if (filepoint >= filelimit) {
575 if (stream.SeekI(filepoint, wxFromStart) == wxInvalidOffset) {
579 /* read the mandatory LBox, 4 bytes */
580 if (!stream.Read(fourbytes, 4)) {
581 wxLogError(wxT("Problem reading LBox from the file (file ended?)"));
584 LBox = STREAM_TO_UINT32(fourbytes, 0);
586 /* read the mandatory TBox, 4 bytes */
587 if (!stream.Read(TBox, 4)) {
588 wxLogError(wxT("Problem reading TBox from the file (file ended?)"));
592 /* look if scansign is got */
593 if ((scansign != NULL) && (memcmp(TBox, scansign, 4) == 0)) {
595 // stop as soon as you find the level-th codebox
596 if (box_number == level) {
597 memcpy(scansign, " ", 4);
598 *scanpoint = filepoint;
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) {
612 /* read the optional XLBox, 8 bytes */
615 if (!stream.Read(&XLBox, 8)) {
616 wxLogError(wxT("Problem reading XLBox from the file (file ended?)"));
619 box_length = (unsigned long int) BYTE_SWAP8(XLBox);
621 } else if (LBox == 0x00000000) {
623 /* last box in file */
625 box_length = filelimit - filepoint;
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);
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);
645 /* increment box number and filepoint*/
647 filepoint += box_length;
655 // search first contiguos codestream box in an mj2 file
657 searchjpeg2000c(wxInputStream& stream, unsigned long int fsize, int number)
659 char scansign[] = "jp2c";
660 unsigned long int scanpoint = 0L;
662 wxLogMessage(wxT("Searching jp2c box... "));
665 if (jpeg2000_file_parse(stream, 0, fsize, number, scansign, &scanpoint) < 0) {
667 wxT("Unrecoverable error during JPEG 2000 box parsing: stopping"));
670 if (strcmp(scansign, " ")) {
671 wxLogMessage(wxT("Box not found"));
674 wxLogMessage(wxString::Format(wxT("Box found at byte %d"), scanpoint));
681 // search the jp2h box in the file
683 searchjpeg2000headerbox(wxInputStream& stream, unsigned long int fsize)
685 char scansign[] = "jp2h";
686 unsigned long int scanpoint = 0L;
688 wxLogMessage(wxT("Searching jp2h box... "));
691 if (jpeg2000_file_parse(stream, 0, fsize, 0, scansign, &scanpoint) < 0) {
693 wxT("Unrecoverable error during JPEG 2000 box parsing: stopping"));
696 if (strcmp(scansign, " ")) {
697 wxLogMessage(wxT("Box not found"));
699 wxLogMessage(wxString::Format(wxT("Box found at byte %d"), scanpoint));
705 /* handling functions */
706 #define ITEM_PER_ROW 10
708 /* Box handler function */
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)
717 /* Sample Description box */
719 jpeg2000_file_parse(stream, filepoint + 8, filelimit, level, scansign,
723 /* MJP2 Sample Description box */
725 jpeg2000_file_parse(stream, filepoint + 78, filelimit, level, scansign,
729 /* not yet implemented */
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', ' '
747 /////////////////////////////////////////////////
748 /////////////////////////////////////////////////
750 // load the jpeg2000 file format
751 bool wxJPEG2000Handler::LoadFile(wxImage *image, wxInputStream& stream,
752 bool verbose, int index)
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;
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];
768 /* read the beginning of the file to check the type */
769 if (!stream.Read(hdr, WXSIZEOF(hdr))) {
772 if ((jpfamform = jpeg2000familytype(hdr, WXSIZEOF(hdr))) < 0) {
775 stream.SeekI(0, wxFromStart);
777 /* handle to a decompressor */
778 opj_dinfo_t* dinfo = NULL;
779 opj_cio_t *cio = NULL;
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;
787 /* set decoding parameters to default values */
788 opj_set_default_decoder_parameters(¶meters);
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;
798 if (m_qualitylayers) {
799 parameters.cp_layer = m_qualitylayers;
802 parameters. = n_components;*/
806 parameters.jpwl_exp_comps = m_expcomps;
807 parameters.jpwl_max_tiles = m_maxtiles;
808 parameters.jpwl_correct = m_enablejpwl;
809 #endif /* USE_JPWL */
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);
820 /* find length of the stream */
821 stream.SeekI(0, wxFromEnd);
822 file_length = (int) stream.TellI();
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);
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);
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);
840 // malloc memory source
841 src = (unsigned char *) malloc(jpeg2000headSIZE + jp2hboxlen + jp2cboxlen);
843 // copy the jP and ftyp
844 memcpy(src, jpeg2000head, jpeg2000headSIZE);
847 stream.SeekI(jp2h_point, wxFromStart);
848 stream.Read(&src[jpeg2000headSIZE], jp2hboxlen);
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 */
856 stream.SeekI(0, wxFromStart);
857 src = (unsigned char *) malloc(file_length);
858 stream.Read(src, file_length);
863 /* catch events using our callbacks and give a local context */
864 opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
866 /* setup the decoder decoding parameters using user parameters */
867 opj_setup_decoder(dinfo, ¶meters);
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);
880 /* decode the stream and fill the image structure */
881 opjimage = opj_decode_with_info(dinfo, cio, &cstr_info);
884 wxLogError(wxT("JPEG 2000 failed to decode image!"));
886 opj_destroy_decompress(dinfo);
892 /* close the byte stream */
897 - At this point, we have the structure "opjimage" that is filled with decompressed
898 data, as processed by the OpenJPEG decompression engine
900 - We need to fill the class "image" with the proper pixel sample values
907 // check components number
908 if (m_components > opjimage->numcomps) {
909 m_components = opjimage->numcomps;
912 // check image depth (only on the first one, for now)
914 shiftbpp = opjimage->comps[m_components - 1].prec - 8;
916 shiftbpp = opjimage->comps[0].prec - 8;
919 // prepare image size
921 image->Create(opjimage->comps[m_components - 1].w,
922 opjimage->comps[m_components - 1].h, true);
924 image->Create(opjimage->comps[0].w, opjimage->comps[0].h, true);
927 // access image raw data
928 image->SetMask(false);
929 ptr = image->GetData();
931 // workaround for components different from 1 or 3
932 if ((opjimage->numcomps != 1) && (opjimage->numcomps != 3)) {
935 #endif /* __WXGTK__ */
936 wxLogMessage(wxT("JPEG2000: weird number of components"));
939 #endif /* __WXGTK__ */
942 tempcomps = opjimage->numcomps;
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)) {
954 // workaround for different precision components
955 for (c = 1; c < tempcomps; c++) {
956 if (opjimage->comps[c].bpp != opjimage->comps[c - 1].bpp) {
962 // only one component selected
968 if (tempcomps == 3) {
970 int *r = opjimage->comps[0].data;
971 int *g = opjimage->comps[1].data;
972 int *b = opjimage->comps[2].data;
974 for (row = 0; row < opjimage->comps[0].h; row++) {
975 for (col = 0; col < opjimage->comps[0].w; col++) {
977 *(ptr++) = (*(r++)) >> shiftbpp;
978 *(ptr++) = (*(g++)) >> shiftbpp;
979 *(ptr++) = (*(b++)) >> shiftbpp;
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++) {
988 *(ptr++) = (*(r++)) << -shiftbpp;
989 *(ptr++) = (*(g++)) << -shiftbpp;
990 *(ptr++) = (*(b++)) << -shiftbpp;
996 for (row = 0; row < opjimage->comps[0].h; row++) {
997 for (col = 0; col < opjimage->comps[0].w; col++) {
1009 if (tempcomps == 1) {
1014 selcomp = m_components - 1;
1019 int *y = opjimage->comps[selcomp].data;
1021 for (row = 0; row < opjimage->comps[selcomp].h; row++) {
1022 for (col = 0; col < opjimage->comps[selcomp].w; col++) {
1024 *(ptr++) = (*(y)) >> shiftbpp;
1025 *(ptr++) = (*(y)) >> shiftbpp;
1026 *(ptr++) = (*(y++)) >> shiftbpp;
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++) {
1034 *(ptr++) = (*(y)) << -shiftbpp;
1035 *(ptr++) = (*(y)) << -shiftbpp;
1036 *(ptr++) = (*(y++)) << -shiftbpp;
1041 for (row = 0; row < opjimage->comps[selcomp].h; row++) {
1042 for (col = 0; col < opjimage->comps[selcomp].w; col++) {
1057 wxLogMessage(wxT("JPEG 2000 image loaded."));
1060 /* close openjpeg structs */
1061 opj_destroy_decompress(dinfo);
1062 opj_image_destroy(opjimage);
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 */
1078 // save the j2k codestream
1079 bool wxJPEG2000Handler::SaveFile(wxImage *wimage, wxOutputStream& stream,
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;
1091 char indexfilename[OPJ_PATH_LEN] = ""; /* index file name */
1094 configure the event callbacks (not required)
1095 setting of each callback is optional
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;
1102 /* set encoding parameters to default values */
1103 opj_set_default_encoder_parameters(¶meters);
1105 /* load parameters */
1106 parameters.cp_cinema = OFF;
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"));
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])) ==
1121 parameters.tcp_numlayers++;
1122 while (*s1 && *s1 != ',') {
1130 wxLogMessage(wxT("%d layers"), parameters.tcp_numlayers);
1131 parameters.cp_disto_alloc = 1;
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", ¶meters.tcp_distoratio[parameters.tcp_numlayers]) ==
1140 parameters.tcp_numlayers++;
1141 while (*s2 && *s2 != ',') {
1149 wxLogMessage(wxT("%d layers"), parameters.tcp_numlayers);
1150 parameters.cp_fixed_quality = 1;
1154 if (sscanf(m_origin.ToAscii(), "%d,%d", ¶meters.image_offset_x0,
1155 ¶meters.image_offset_y0) != 2) {
1156 wxLogError(wxT("bad coordinate of the image origin: x0,y0"));
1160 /* Create comment for codestream */
1162 parameters.cp_comment = (char *) malloc(strlen(m_comment.ToAscii()) + 1);
1163 if (parameters.cp_comment) {
1164 strcpy(parameters.cp_comment, m_comment.ToAscii());
1167 parameters.cp_comment = NULL;
1172 strncpy(indexfilename, m_index.ToAscii(), OPJ_PATH_LEN);
1173 wxLogMessage(wxT("index file is %s"), indexfilename);
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;
1183 /* irreversible transform */
1184 parameters.irreversible = (m_irreversible == true) ? 1 : 0;
1187 parameters.numresolution = m_resolutions;
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) {
1196 wxT("!! Size of code_block error !! Restrictions:\n width*height<=4096\n 4<=width,height<= 1024"));
1199 parameters.cblockw_init = cblockw_init;
1200 parameters.cblockh_init = cblockh_init;
1203 /* precincts size */
1204 if (m_prsize != wxT("")) {
1207 char *s = (char *) m_prsize.c_str();
1210 sscanf(s, "[%d,%d]%c", ¶meters.prcw_init[res_spec],
1211 ¶meters.prch_init[res_spec], &sep);
1212 parameters.csty |= 0x01;
1214 s = strpbrk(s, "]") + 2;
1215 } while (sep == ',');
1216 parameters.res_spec = res_spec;
1220 if (m_tsize != wxT("")) {
1221 sscanf(m_tsize.ToAscii(), "%d,%d", ¶meters.cp_tdx, ¶meters.cp_tdy);
1222 parameters.tile_size_on = true;
1226 if (sscanf(m_torigin.ToAscii(), "%d,%d", ¶meters.cp_tx0,
1227 ¶meters.cp_ty0) != 2) {
1228 wxLogError(wxT("tile offset setting error: X0,Y0"));
1234 parameters.csty |= 0x02;
1239 parameters.csty |= 0x04;
1242 /* multiple component transform */
1244 parameters.tcp_mct = 1;
1246 parameters.tcp_mct = 0;
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);
1254 /* progression order */
1255 switch (m_progression) {
1259 parameters.prog_order = LRCP;
1264 parameters.prog_order = RLCP;
1269 parameters.prog_order = RPCL;
1274 parameters.prog_order = PCRL;
1279 parameters.prog_order = CPRL;
1284 parameters.cp_cinema = CINEMA2K_24;
1285 parameters.cp_rsiz = CINEMA2K;
1290 parameters.cp_cinema = CINEMA2K_48;
1291 parameters.cp_rsiz = CINEMA2K;
1296 parameters.cp_cinema = CINEMA4K_24;
1297 parameters.cp_rsiz = CINEMA4K;
1305 if (parameters.cp_cinema) {
1308 parameters.tile_size_on = false;
1309 parameters.cp_tdx = 1;
1310 parameters.cp_tdy = 1;
1313 parameters.tp_flag = 'C';
1314 parameters.tp_on = 1;
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;
1322 /*Codeblock size= 32*32*/
1323 parameters.cblockw_init = 32;
1324 parameters.cblockh_init = 32;
1325 parameters.csty |= 0x01;
1327 /*The progression order shall be CPRL*/
1328 parameters.prog_order = CPRL;
1331 parameters.roi_compno = -1;
1333 parameters.subsampling_dx = 1;
1334 parameters.subsampling_dy = 1;
1337 parameters.irreversible = 1;
1341 /* convert wx image into opj image */
1342 cmptparm = (opj_image_cmptparm_t*) malloc(3 * sizeof(opj_image_cmptparm_t));
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();
1356 /* create the image */
1357 oimage = opj_image_create(3, &cmptparm[0], CLRSPC_SRGB);
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;
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++);
1380 /* check cinema again */
1381 if (parameters.cp_cinema) {
1384 opj_poc_t *POC = NULL;
1386 switch (parameters.cp_cinema) {
1390 if (parameters.numresolution > 6) {
1391 parameters.numresolution = 6;
1393 if (!((oimage->comps[0].w == 2048) | (oimage->comps[0].h == 1080))) {
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;
1403 if (parameters.numresolution < 1) {
1404 parameters.numresolution = 1;
1405 } else if (parameters.numresolution > 7) {
1406 parameters.numresolution = 7;
1408 if (!((oimage->comps[0].w == 4096) | (oimage->comps[0].h == 2160))) {
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;
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;
1433 switch (parameters.cp_cinema) {
1436 for (i = 0 ; i < parameters.tcp_numlayers; i++) {
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);
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);
1455 parameters.max_comp_size = COMP_24_CS;
1459 for (i = 0; i < parameters.tcp_numlayers; i++) {
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);
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);
1478 parameters.max_comp_size = COMP_48_CS;
1482 parameters.cp_disto_alloc = 1;
1485 /* get a J2K compressor handle */
1486 opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K);
1488 /* catch events using our callbacks and give a local context */
1489 opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
1491 /* setup the encoder parameters using the current image and user parameters */
1492 opj_setup_encoder(cinfo, ¶meters, oimage);
1494 /* open a byte stream for writing */
1495 /* allocate memory for all tiles */
1496 cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0);
1498 /* encode the image */
1499 bSuccess = opj_encode_with_info(cinfo, cio, oimage, &cstr_info);
1503 opj_destroy_compress(cinfo);
1504 opj_image_destroy(oimage);
1508 if (parameters.cp_comment) {
1509 free(parameters.cp_comment);
1511 if (parameters.cp_matrice) {
1512 free(parameters.cp_matrice);
1517 #endif /* __WXGTK__ */
1519 wxLogError(wxT("failed to encode image"));
1523 #endif /* __WXGTK__ */
1527 codestream_length = cio_tell(cio);
1528 wxLogMessage(wxT("Codestream: %d bytes"), codestream_length);
1530 /* write the buffer to stream */
1531 stream.Write(cio->buffer, codestream_length);
1533 /* close and free the byte stream */
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"));
1543 /* free remaining compression structures */
1544 opj_destroy_compress(cinfo);
1546 /* free image data */
1547 opj_image_destroy(oimage);
1552 if (parameters.cp_comment) {
1553 free(parameters.cp_comment);
1555 if (parameters.cp_matrice) {
1556 free(parameters.cp_matrice);
1561 #endif /* __WXGTK__ */
1563 wxLogMessage(wxT("J2K: Image encoded!"));
1567 #endif /* __WXGTK__ */
1573 #pragma warning(default:4611)
1576 // recognize the JPEG 2000 family starting box or the 0xFF4F JPEG 2000 SOC marker
1577 bool wxJPEG2000Handler::DoCanRead(wxInputStream& stream)
1579 unsigned char hdr[24];
1582 if (!stream.Read(hdr, WXSIZEOF(hdr))) {
1586 jpfamform = jpeg2000familytype(hdr, WXSIZEOF(hdr));
1588 return ((jpfamform == JP2_CFMT) || (jpfamform == MJ2_CFMT) ||
1589 (jpfamform == J2K_CFMT));
1592 #endif // wxUSE_STREAMS
1594 #endif // wxUSE_LIBOPENJPEG