1 /******************************************************************************
2 * $Id: jpeg2000dataset.cpp 29171 2015-05-07 19:49:07Z rouault $
3 *
4 * Project: JPEG-2000
5 * Purpose: Partial implementation of the ISO/IEC 15444-1 standard
6 * Author: Andrey Kiselev, dron@ak4719.spb.edu
7 *
8 ******************************************************************************
9 * Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
10 * Copyright (c) 2007-2013, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "gdaljp2abstractdataset.h"
32 #include "gdaljp2metadata.h"
33 #include "cpl_string.h"
34
35 #include <jasper/jasper.h>
36 #include "jpeg2000_vsil_io.h"
37
38 CPL_CVSID("$Id: jpeg2000dataset.cpp 29171 2015-05-07 19:49:07Z rouault $");
39
40 CPL_C_START
41 void GDALRegister_JPEG2000(void);
42 CPL_C_END
43
44 // XXX: Part of code below extracted from the JasPer internal headers and
45 // must be in sync with JasPer version (this one works with JasPer 1.900.1)
46 #define JP2_FTYP_MAXCOMPATCODES 32
47 #define JP2_BOX_IHDR 0x69686472 /* Image Header */
48 #define JP2_BOX_BPCC 0x62706363 /* Bits Per Component */
49 #define JP2_BOX_PCLR 0x70636c72 /* Palette */
50 #define JP2_BOX_UUID 0x75756964 /* UUID */
51 extern "C" {
52 typedef struct {
53 uint_fast32_t magic;
54 } jp2_jp_t;
55 typedef struct {
56 uint_fast32_t majver;
57 uint_fast32_t minver;
58 uint_fast32_t numcompatcodes;
59 uint_fast32_t compatcodes[JP2_FTYP_MAXCOMPATCODES];
60 } jp2_ftyp_t;
61 typedef struct {
62 uint_fast32_t width;
63 uint_fast32_t height;
64 uint_fast16_t numcmpts;
65 uint_fast8_t bpc;
66 uint_fast8_t comptype;
67 uint_fast8_t csunk;
68 uint_fast8_t ipr;
69 } jp2_ihdr_t;
70 typedef struct {
71 uint_fast16_t numcmpts;
72 uint_fast8_t *bpcs;
73 } jp2_bpcc_t;
74 typedef struct {
75 uint_fast8_t method;
76 uint_fast8_t pri;
77 uint_fast8_t approx;
78 uint_fast32_t csid;
79 uint_fast8_t *iccp;
80 int iccplen;
81 } jp2_colr_t;
82 typedef struct {
83 uint_fast16_t numlutents;
84 uint_fast8_t numchans;
85 int_fast32_t *lutdata;
86 uint_fast8_t *bpc;
87 } jp2_pclr_t;
88 typedef struct {
89 uint_fast16_t channo;
90 uint_fast16_t type;
91 uint_fast16_t assoc;
92 } jp2_cdefchan_t;
93 typedef struct {
94 uint_fast16_t numchans;
95 jp2_cdefchan_t *ents;
96 } jp2_cdef_t;
97 typedef struct {
98 uint_fast16_t cmptno;
99 uint_fast8_t map;
100 uint_fast8_t pcol;
101 } jp2_cmapent_t;
102
103 typedef struct {
104 uint_fast16_t numchans;
105 jp2_cmapent_t *ents;
106 } jp2_cmap_t;
107
108 #ifdef HAVE_JASPER_UUID
109 typedef struct {
110 uint_fast32_t datalen;
111 uint_fast8_t uuid[16];
112 uint_fast8_t *data;
113 } jp2_uuid_t;
114 #endif
115
116 struct jp2_boxops_s;
117 typedef struct {
118
119 struct jp2_boxops_s *ops;
120 struct jp2_boxinfo_s *info;
121
122 uint_fast32_t type;
123
124 /* The length of the box including the (variable-length) header. */
125 uint_fast32_t len;
126
127 /* The length of the box data. */
128 uint_fast32_t datalen;
129
130 union {
131 jp2_jp_t jp;
132 jp2_ftyp_t ftyp;
133 jp2_ihdr_t ihdr;
134 jp2_bpcc_t bpcc;
135 jp2_colr_t colr;
136 jp2_pclr_t pclr;
137 jp2_cdef_t cdef;
138 jp2_cmap_t cmap;
139 #ifdef HAVE_JASPER_UUID
140 jp2_uuid_t uuid;
141 #endif
142 } data;
143
144 } jp2_box_t;
145
146 typedef struct jp2_boxops_s {
147 void (*init)(jp2_box_t *box);
148 void (*destroy)(jp2_box_t *box);
149 int (*getdata)(jp2_box_t *box, jas_stream_t *in);
150 int (*putdata)(jp2_box_t *box, jas_stream_t *out);
151 void (*dumpdata)(jp2_box_t *box, FILE *out);
152 } jp2_boxops_t;
153
154 extern jp2_box_t *jp2_box_create(int type);
155 extern void jp2_box_destroy(jp2_box_t *box);
156 extern jp2_box_t *jp2_box_get(jas_stream_t *in);
157 extern int jp2_box_put(jp2_box_t *box, jas_stream_t *out);
158 #ifdef HAVE_JASPER_UUID
159 int jp2_encode_uuid(jas_image_t *image, jas_stream_t *out,
160 char *optstr, jp2_box_t *uuid);
161 #endif
162 }
163 // XXX: End of JasPer header.
164
165 /************************************************************************/
166 /* ==================================================================== */
167 /* JPEG2000Dataset */
168 /* ==================================================================== */
169 /************************************************************************/
170
171 class JPEG2000Dataset : public GDALJP2AbstractDataset
172 {
173 friend class JPEG2000RasterBand;
174
175 jas_stream_t *psStream;
176 jas_image_t *psImage;
177 int iFormat;
178 int bPromoteTo8Bit;
179
180 int bAlreadyDecoded;
181 int DecodeImage();
182
183 public:
184 JPEG2000Dataset();
185 ~JPEG2000Dataset();
186
187 static int Identify( GDALOpenInfo * );
188 static GDALDataset *Open( GDALOpenInfo * );
189 };
190
191 /************************************************************************/
192 /* ==================================================================== */
193 /* JPEG2000RasterBand */
194 /* ==================================================================== */
195 /************************************************************************/
196
197 class JPEG2000RasterBand : public GDALPamRasterBand
198 {
199 friend class JPEG2000Dataset;
200
201 // NOTE: poDS may be altered for NITF/JPEG2000 files!
202 JPEG2000Dataset *poGDS;
203
204 jas_matrix_t *psMatrix;
205
206 int iDepth;
207 int bSignedness;
208
209 public:
210
211 JPEG2000RasterBand( JPEG2000Dataset *, int, int, int );
212 ~JPEG2000RasterBand();
213
214 virtual CPLErr IReadBlock( int, int, void * );
215 virtual GDALColorInterp GetColorInterpretation();
216 };
217
218
219 /************************************************************************/
220 /* JPEG2000RasterBand() */
221 /************************************************************************/
222
JPEG2000RasterBand(JPEG2000Dataset * poDS,int nBand,int iDepth,int bSignedness)223 JPEG2000RasterBand::JPEG2000RasterBand( JPEG2000Dataset *poDS, int nBand,
224 int iDepth, int bSignedness )
225
226 {
227 this->poDS = poDS;
228 poGDS = poDS;
229 this->nBand = nBand;
230 this->iDepth = iDepth;
231 this->bSignedness = bSignedness;
232
233 // XXX: JasPer can't handle data with depth > 32 bits
234 // Maximum possible depth for JPEG2000 is 38!
235 switch ( bSignedness )
236 {
237 case 1: // Signed component
238 if (iDepth <= 8)
239 this->eDataType = GDT_Byte; // FIXME: should be signed,
240 // but we haven't signed byte
241 // data type in GDAL
242 else if (iDepth <= 16)
243 this->eDataType = GDT_Int16;
244 else if (iDepth <= 32)
245 this->eDataType = GDT_Int32;
246 break;
247 case 0: // Unsigned component
248 default:
249 if (iDepth <= 8)
250 this->eDataType = GDT_Byte;
251 else if (iDepth <= 16)
252 this->eDataType = GDT_UInt16;
253 else if (iDepth <= 32)
254 this->eDataType = GDT_UInt32;
255 break;
256 }
257 // FIXME: Figure out optimal block size!
258 // Should the block size be fixed or determined dynamically?
259 nBlockXSize = MIN(256, poDS->nRasterXSize);
260 nBlockYSize = MIN(256, poDS->nRasterYSize);
261 psMatrix = jas_matrix_create(nBlockYSize, nBlockXSize);
262
263 if( iDepth % 8 != 0 && !poDS->bPromoteTo8Bit )
264 {
265 SetMetadataItem( "NBITS",
266 CPLString().Printf("%d",iDepth),
267 "IMAGE_STRUCTURE" );
268 }
269 SetMetadataItem( "COMPRESSION", "JP2000", "IMAGE_STRUCTURE" );
270 }
271
272 /************************************************************************/
273 /* ~JPEG2000RasterBand() */
274 /************************************************************************/
275
~JPEG2000RasterBand()276 JPEG2000RasterBand::~JPEG2000RasterBand()
277 {
278 if ( psMatrix )
279 jas_matrix_destroy( psMatrix );
280 }
281
282 /************************************************************************/
283 /* IReadBlock() */
284 /************************************************************************/
285
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)286 CPLErr JPEG2000RasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
287 void * pImage )
288 {
289 int i, j;
290
291 // Decode image from the stream, if not yet
292 if ( !poGDS->DecodeImage() )
293 {
294 return CE_Failure;
295 }
296
297 // Now we can calculate the pixel offset of the top left by multiplying
298 // block offset with the block size.
299
300 /* In case the dimensions of the image are not multiple of the block dimensions */
301 /* take care of not requesting more pixels than available for the blocks at the */
302 /* right or bottom of the image */
303 int nWidthToRead = MIN(nBlockXSize, poGDS->nRasterXSize - nBlockXOff * nBlockXSize);
304 int nHeightToRead = MIN(nBlockYSize, poGDS->nRasterYSize - nBlockYOff * nBlockYSize);
305
306 jas_image_readcmpt( poGDS->psImage, nBand - 1,
307 nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
308 nWidthToRead, nHeightToRead, psMatrix );
309
310 int nWordSize = GDALGetDataTypeSize(eDataType) / 8;
311 int nLineSize = nBlockXSize * nWordSize;
312 GByte* ptr = (GByte*)pImage;
313
314 /* Pad incomplete blocks at the right or bottom of the image */
315 if (nWidthToRead != nBlockXSize || nHeightToRead != nBlockYSize)
316 memset(pImage, 0, nLineSize * nBlockYSize);
317
318 for( i = 0; i < nHeightToRead; i++, ptr += nLineSize )
319 {
320 for( j = 0; j < nWidthToRead; j++ )
321 {
322 // XXX: We need casting because matrix element always
323 // has 32 bit depth in JasPer
324 // FIXME: what about float values?
325 switch( eDataType )
326 {
327 case GDT_Int16:
328 {
329 ((GInt16*)ptr)[j] = (GInt16)jas_matrix_get(psMatrix, i, j);
330 }
331 break;
332 case GDT_Int32:
333 {
334 ((GInt32*)ptr)[j] = (GInt32)jas_matrix_get(psMatrix, i, j);
335 }
336 break;
337 case GDT_UInt16:
338 {
339 ((GUInt16*)ptr)[j] = (GUInt16)jas_matrix_get(psMatrix, i, j);
340 }
341 break;
342 case GDT_UInt32:
343 {
344 ((GUInt32*)ptr)[j] = (GUInt32)jas_matrix_get(psMatrix, i, j);
345 }
346 break;
347 case GDT_Byte:
348 default:
349 {
350 ((GByte*)ptr)[j] = (GByte)jas_matrix_get(psMatrix, i, j);
351 }
352 break;
353 }
354 }
355 }
356
357 if( poGDS->bPromoteTo8Bit && nBand == 4 )
358 {
359 ptr = (GByte*)pImage;
360 for( i = 0; i < nHeightToRead; i++, ptr += nLineSize )
361 {
362 for( j = 0; j < nWidthToRead; j++ )
363 {
364 ((GByte*)ptr)[j] *= 255;
365 }
366 }
367 }
368
369 return CE_None;
370 }
371
372 /************************************************************************/
373 /* GetColorInterpretation() */
374 /************************************************************************/
375
GetColorInterpretation()376 GDALColorInterp JPEG2000RasterBand::GetColorInterpretation()
377 {
378 // Decode image from the stream, if not yet
379 if ( !poGDS->DecodeImage() )
380 {
381 return GCI_Undefined;
382 }
383
384 if ( jas_clrspc_fam( jas_image_clrspc( poGDS->psImage ) ) ==
385 JAS_CLRSPC_FAM_GRAY )
386 return GCI_GrayIndex;
387 else if ( jas_clrspc_fam( jas_image_clrspc( poGDS->psImage ) ) ==
388 JAS_CLRSPC_FAM_RGB )
389 {
390 switch ( jas_image_cmpttype( poGDS->psImage, nBand - 1 ) )
391 {
392 case JAS_IMAGE_CT_RGB_R:
393 return GCI_RedBand;
394 case JAS_IMAGE_CT_RGB_G:
395 return GCI_GreenBand;
396 case JAS_IMAGE_CT_RGB_B:
397 return GCI_BlueBand;
398 case JAS_IMAGE_CT_OPACITY:
399 return GCI_AlphaBand;
400 default:
401 return GCI_Undefined;
402 }
403 }
404 else
405 return GCI_Undefined;
406 }
407
408 /************************************************************************/
409 /* ==================================================================== */
410 /* JPEG2000Dataset */
411 /* ==================================================================== */
412 /************************************************************************/
413
414 /************************************************************************/
415 /* JPEG2000Dataset() */
416 /************************************************************************/
417
JPEG2000Dataset()418 JPEG2000Dataset::JPEG2000Dataset()
419 {
420 psStream = NULL;
421 psImage = NULL;
422 nBands = 0;
423 bAlreadyDecoded = FALSE;
424 bPromoteTo8Bit = FALSE;
425
426 poDriver = (GDALDriver *)GDALGetDriverByName("JPEG2000");
427 }
428
429 /************************************************************************/
430 /* ~JPEG2000Dataset() */
431 /************************************************************************/
432
~JPEG2000Dataset()433 JPEG2000Dataset::~JPEG2000Dataset()
434
435 {
436 FlushCache();
437
438 if ( psStream )
439 jas_stream_close( psStream );
440 if ( psImage )
441 jas_image_destroy( psImage );
442 }
443
444 /************************************************************************/
445 /* DecodeImage() */
446 /************************************************************************/
DecodeImage()447 int JPEG2000Dataset::DecodeImage()
448 {
449 if (bAlreadyDecoded)
450 return psImage != NULL;
451
452 bAlreadyDecoded = TRUE;
453 if ( !( psImage = jas_image_decode(psStream, iFormat, 0) ) )
454 {
455 CPLDebug( "JPEG2000", "Unable to decode image. Format: %s, %d",
456 jas_image_fmttostr( iFormat ), iFormat );
457 return FALSE;
458 }
459
460 /* Case of a JP2 image : check that the properties given by */
461 /* the JP2 boxes match the ones of the code stream */
462 if (nBands != 0)
463 {
464 if (nBands != jas_image_numcmpts( psImage ))
465 {
466 CPLError(CE_Failure, CPLE_AppDefined,
467 "The number of components indicated in the IHDR box (%d) mismatch "
468 "the value specified in the code stream (%d)",
469 nBands, jas_image_numcmpts( psImage ));
470 jas_image_destroy( psImage );
471 psImage = NULL;
472 return FALSE;
473 }
474
475 if (nRasterXSize != jas_image_cmptwidth( psImage, 0 ) ||
476 nRasterYSize != jas_image_cmptheight( psImage, 0 ) )
477 {
478 CPLError(CE_Failure, CPLE_AppDefined,
479 "The dimensions indicated in the IHDR box (%d x %d) mismatch "
480 "the value specified in the code stream (%d x %d)",
481 nRasterXSize, nRasterYSize,
482 (int)jas_image_cmptwidth( psImage, 0 ),
483 (int)jas_image_cmptheight( psImage, 0 ));
484 jas_image_destroy( psImage );
485 psImage = NULL;
486 return FALSE;
487 }
488
489 int iBand;
490 for ( iBand = 0; iBand < nBands; iBand++ )
491 {
492 JPEG2000RasterBand* poBand = (JPEG2000RasterBand*) GetRasterBand(iBand+1);
493 if (poBand->iDepth != jas_image_cmptprec( psImage, iBand ) ||
494 poBand->bSignedness != jas_image_cmptsgnd( psImage, iBand ))
495 {
496 CPLError(CE_Failure, CPLE_AppDefined,
497 "The bit depth of band %d indicated in the IHDR box (%d) mismatch "
498 "the value specified in the code stream (%d)",
499 iBand + 1, poBand->iDepth, jas_image_cmptprec( psImage, iBand ));
500 jas_image_destroy( psImage );
501 psImage = NULL;
502 return FALSE;
503 }
504 }
505 }
506
507 /* Ask for YCbCr -> RGB translation */
508 if ( jas_clrspc_fam( jas_image_clrspc( psImage ) ) ==
509 JAS_CLRSPC_FAM_YCBCR )
510 {
511 jas_image_t *psRGBImage;
512 jas_cmprof_t *psRGBProf;
513 CPLDebug( "JPEG2000", "forcing conversion to sRGB");
514 if (!(psRGBProf = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB))) {
515 CPLDebug( "JPEG2000", "cannot create sRGB profile");
516 return TRUE;
517 }
518 if (!(psRGBImage = jas_image_chclrspc(psImage, psRGBProf, JAS_CMXFORM_INTENT_PER))) {
519 CPLDebug( "JPEG2000", "cannot convert to sRGB");
520 jas_cmprof_destroy(psRGBProf);
521 return TRUE;
522 }
523 jas_image_destroy(psImage);
524 jas_cmprof_destroy(psRGBProf);
525 psImage = psRGBImage;
526 }
527
528 return TRUE;
529 }
530
JPEG2000Init()531 static void JPEG2000Init()
532 {
533 static int bHasInit = FALSE;
534 if (!bHasInit)
535 {
536 bHasInit = TRUE;
537 jas_init();
538 }
539 }
540
541 /************************************************************************/
542 /* Identify() */
543 /************************************************************************/
544
Identify(GDALOpenInfo * poOpenInfo)545 int JPEG2000Dataset::Identify( GDALOpenInfo * poOpenInfo )
546
547 {
548 static const unsigned char jpc_header[] = {0xff,0x4f};
549 static const unsigned char jp2_box_jp[] = {0x6a,0x50,0x20,0x20}; /* 'jP ' */
550
551 if( poOpenInfo->nHeaderBytes >= 16
552 && (memcmp( poOpenInfo->pabyHeader, jpc_header,
553 sizeof(jpc_header) ) == 0
554 || memcmp( poOpenInfo->pabyHeader + 4, jp2_box_jp,
555 sizeof(jp2_box_jp) ) == 0
556 /* PGX file*/
557 || (memcmp( poOpenInfo->pabyHeader, "PG", 2) == 0 &&
558 (poOpenInfo->pabyHeader[2] == ' ' || poOpenInfo->pabyHeader[2] == '\t') &&
559 (memcmp( poOpenInfo->pabyHeader + 3, "ML", 2) == 0 ||
560 memcmp( poOpenInfo->pabyHeader + 3, "LM", 2) == 0))) )
561 return TRUE;
562
563 else
564 return FALSE;
565 }
566
567 /************************************************************************/
568 /* Open() */
569 /************************************************************************/
570
Open(GDALOpenInfo * poOpenInfo)571 GDALDataset *JPEG2000Dataset::Open( GDALOpenInfo * poOpenInfo )
572
573 {
574 int iFormat;
575 char *pszFormatName = NULL;
576 jas_stream_t *sS;
577
578 if (!Identify(poOpenInfo))
579 return NULL;
580
581 JPEG2000Init();
582 if( !(sS = JPEG2000_VSIL_fopen( poOpenInfo->pszFilename, "rb" )) )
583 {
584 return NULL;
585 }
586
587 iFormat = jas_image_getfmt( sS );
588 if ( !(pszFormatName = jas_image_fmttostr( iFormat )) )
589 {
590 jas_stream_close( sS );
591 return NULL;
592 }
593 if ( strlen( pszFormatName ) < 3 ||
594 (!EQUALN( pszFormatName, "jp2", 3 ) &&
595 !EQUALN( pszFormatName, "jpc", 3 ) &&
596 !EQUALN( pszFormatName, "pgx", 3 )) )
597 {
598 CPLDebug( "JPEG2000", "JasPer reports file is format type `%s'.",
599 pszFormatName );
600 jas_stream_close( sS );
601 return NULL;
602 }
603
604 /* -------------------------------------------------------------------- */
605 /* Confirm the requested access is supported. */
606 /* -------------------------------------------------------------------- */
607 if( poOpenInfo->eAccess == GA_Update )
608 {
609 jas_stream_close(sS);
610 CPLError( CE_Failure, CPLE_NotSupported,
611 "The JPEG2000 driver does not support update access to existing"
612 " datasets.\n" );
613 return NULL;
614 }
615 /* -------------------------------------------------------------------- */
616 /* Create a corresponding GDALDataset. */
617 /* -------------------------------------------------------------------- */
618 JPEG2000Dataset *poDS;
619 int *paiDepth = NULL, *pabSignedness = NULL;
620 int iBand;
621
622 poDS = new JPEG2000Dataset();
623
624 poDS->psStream = sS;
625 poDS->iFormat = iFormat;
626
627 if ( EQUALN( pszFormatName, "jp2", 3 ) )
628 {
629 // XXX: Hack to read JP2 boxes from input file. JasPer hasn't public
630 // API call for such things, so we will use internal JasPer functions.
631 jp2_box_t *box;
632 box = 0;
633 while ( ( box = jp2_box_get(poDS->psStream) ) )
634 {
635 switch (box->type)
636 {
637 case JP2_BOX_IHDR:
638 poDS->nBands = box->data.ihdr.numcmpts;
639 poDS->nRasterXSize = box->data.ihdr.width;
640 poDS->nRasterYSize = box->data.ihdr.height;
641 CPLDebug( "JPEG2000",
642 "IHDR box found. Dump: "
643 "width=%d, height=%d, numcmpts=%d, bpp=%d",
644 (int)box->data.ihdr.width, (int)box->data.ihdr.height,
645 (int)box->data.ihdr.numcmpts, (box->data.ihdr.bpc & 0x7F) + 1 );
646 /* ISO/IEC 15444-1:2004 I.5.3.1 specifies that 255 means that all */
647 /* components have not the same bit depth and/or sign and that a */
648 /* BPCC box must then follow to specify them for each component */
649 if ( box->data.ihdr.bpc != 255 )
650 {
651 paiDepth = (int *)CPLMalloc(poDS->nBands * sizeof(int));
652 pabSignedness = (int *)CPLMalloc(poDS->nBands * sizeof(int));
653 for ( iBand = 0; iBand < poDS->nBands; iBand++ )
654 {
655 paiDepth[iBand] = (box->data.ihdr.bpc & 0x7F) + 1;
656 pabSignedness[iBand] = box->data.ihdr.bpc >> 7;
657 CPLDebug( "JPEG2000",
658 "Component %d: bpp=%d, signedness=%d",
659 iBand, paiDepth[iBand], pabSignedness[iBand] );
660 }
661 }
662 break;
663
664 case JP2_BOX_BPCC:
665 CPLDebug( "JPEG2000", "BPCC box found. Dump:" );
666 if ( !paiDepth && !pabSignedness )
667 {
668 paiDepth = (int *)
669 CPLMalloc( box->data.bpcc.numcmpts * sizeof(int) );
670 pabSignedness = (int *)
671 CPLMalloc( box->data.bpcc.numcmpts * sizeof(int) );
672 for( iBand = 0; iBand < (int)box->data.bpcc.numcmpts; iBand++ )
673 {
674 paiDepth[iBand] = (box->data.bpcc.bpcs[iBand] & 0x7F) + 1;
675 pabSignedness[iBand] = box->data.bpcc.bpcs[iBand] >> 7;
676 CPLDebug( "JPEG2000",
677 "Component %d: bpp=%d, signedness=%d",
678 iBand, paiDepth[iBand], pabSignedness[iBand] );
679 }
680 }
681 break;
682
683 case JP2_BOX_PCLR:
684 CPLDebug( "JPEG2000",
685 "PCLR box found. Dump: number of LUT entries=%d, "
686 "number of resulting channels=%d",
687 (int)box->data.pclr.numlutents, box->data.pclr.numchans );
688 poDS->nBands = box->data.pclr.numchans;
689 if ( paiDepth )
690 CPLFree( paiDepth );
691 if ( pabSignedness )
692 CPLFree( pabSignedness );
693 paiDepth = (int *)
694 CPLMalloc( box->data.pclr.numchans * sizeof(int) );
695 pabSignedness = (int *)
696 CPLMalloc( box->data.pclr.numchans * sizeof(int) );
697 for( iBand = 0; iBand < (int)box->data.pclr.numchans; iBand++ )
698 {
699 paiDepth[iBand] = (box->data.pclr.bpc[iBand] & 0x7F) + 1;
700 pabSignedness[iBand] = box->data.pclr.bpc[iBand] >> 7;
701 CPLDebug( "JPEG2000",
702 "Component %d: bpp=%d, signedness=%d",
703 iBand, paiDepth[iBand], pabSignedness[iBand] );
704 }
705 break;
706 }
707 jp2_box_destroy( box );
708 box = 0;
709 }
710 if( !paiDepth || !pabSignedness )
711 {
712 delete poDS;
713 CPLDebug( "JPEG2000", "Unable to read JP2 header boxes.\n" );
714 return NULL;
715 }
716 if ( jas_stream_rewind( poDS->psStream ) < 0 )
717 {
718 delete poDS;
719 CPLDebug( "JPEG2000", "Unable to rewind input stream.\n" );
720 return NULL;
721 }
722 }
723 else
724 {
725 if ( !poDS->DecodeImage() )
726 {
727 delete poDS;
728 return NULL;
729 }
730
731 poDS->nBands = jas_image_numcmpts( poDS->psImage );
732 poDS->nRasterXSize = jas_image_cmptwidth( poDS->psImage, 0 );
733 poDS->nRasterYSize = jas_image_cmptheight( poDS->psImage, 0 );
734 paiDepth = (int *)CPLMalloc( poDS->nBands * sizeof(int) );
735 pabSignedness = (int *)CPLMalloc( poDS->nBands * sizeof(int) );
736 for ( iBand = 0; iBand < poDS->nBands; iBand++ )
737 {
738 paiDepth[iBand] = jas_image_cmptprec( poDS->psImage, iBand );
739 pabSignedness[iBand] = jas_image_cmptsgnd( poDS->psImage, iBand );
740 }
741 }
742
743 if ( !GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
744 !GDALCheckBandCount(poDS->nBands, 0) )
745 {
746 CPLFree( paiDepth );
747 CPLFree( pabSignedness );
748 delete poDS;
749 return NULL;
750 }
751
752 /* -------------------------------------------------------------------- */
753 /* Should we promote alpha channel to 8 bits ? */
754 /* -------------------------------------------------------------------- */
755 poDS->bPromoteTo8Bit = (poDS->nBands == 4 &&
756 paiDepth[0] == 8 &&
757 paiDepth[1] == 8 &&
758 paiDepth[2] == 8 &&
759 paiDepth[3] == 1 &&
760 CSLFetchBoolean(poOpenInfo->papszOpenOptions, "1BIT_ALPHA_PROMOTION", TRUE));
761 if( poDS->bPromoteTo8Bit )
762 CPLDebug( "JPEG2000", "Fourth (alpha) band is promoted from 1 bit to 8 bit");
763
764 /* -------------------------------------------------------------------- */
765
766 /* Create band information objects. */
767 /* -------------------------------------------------------------------- */
768
769
770 for( iBand = 1; iBand <= poDS->nBands; iBand++ )
771 {
772 poDS->SetBand( iBand, new JPEG2000RasterBand( poDS, iBand,
773 paiDepth[iBand - 1], pabSignedness[iBand - 1] ) );
774
775 }
776
777 if ( paiDepth )
778 CPLFree( paiDepth );
779 if ( pabSignedness )
780 CPLFree( pabSignedness );
781
782 poDS->LoadJP2Metadata(poOpenInfo);
783
784 /* -------------------------------------------------------------------- */
785 /* Initialize any PAM information. */
786 /* -------------------------------------------------------------------- */
787 poDS->SetDescription( poOpenInfo->pszFilename );
788 poDS->TryLoadXML();
789
790 /* -------------------------------------------------------------------- */
791 /* Check for overviews. */
792 /* -------------------------------------------------------------------- */
793 poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
794
795 /* -------------------------------------------------------------------- */
796 /* Vector layers */
797 /* -------------------------------------------------------------------- */
798 if( poOpenInfo->nOpenFlags & GDAL_OF_VECTOR )
799 {
800 poDS->LoadVectorLayers(
801 CSLFetchBoolean(poOpenInfo->papszOpenOptions, "OPEN_REMOTE_GML", FALSE));
802
803 // If file opened in vector-only mode and there's no vector,
804 // return
805 if( (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
806 poDS->GetLayerCount() == 0 )
807 {
808 delete poDS;
809 return NULL;
810 }
811 }
812
813 return( poDS );
814 }
815
816 /************************************************************************/
817 /* JPEG2000CreateCopy() */
818 /************************************************************************/
819
820 static GDALDataset *
JPEG2000CreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)821 JPEG2000CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
822 int bStrict, char ** papszOptions,
823 GDALProgressFunc pfnProgress, void * pProgressData )
824
825 {
826 int nBands = poSrcDS->GetRasterCount();
827 int nXSize = poSrcDS->GetRasterXSize();
828 int nYSize = poSrcDS->GetRasterYSize();
829 int iBand;
830 GDALRasterBand *poBand;
831
832 if( nBands == 0 )
833 {
834 CPLError( CE_Failure, CPLE_NotSupported,
835 "Unable to export files with zero bands." );
836 return NULL;
837 }
838
839 if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
840 {
841 CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
842 "JPEG2000 driver ignores color table. "
843 "The source raster band will be considered as grey level.\n"
844 "Consider using color table expansion (-expand option in gdal_translate)\n");
845 if (bStrict)
846 return NULL;
847 }
848
849 for ( iBand = 0; iBand < nBands; iBand++ )
850 {
851 poBand = poSrcDS->GetRasterBand( iBand + 1);
852
853 switch ( poBand->GetRasterDataType() )
854 {
855 case GDT_Byte:
856 case GDT_Int16:
857 case GDT_UInt16:
858 break;
859
860 default:
861 if( !CSLTestBoolean(CPLGetConfigOption("JPEG2000_FORCE_CREATION", "NO")) )
862 {
863 CPLError(CE_Failure, CPLE_AppDefined,
864 "A band of the source dataset is of type %s, which might cause crashes in libjasper. "
865 "Set JPEG2000_FORCE_CREATION configuration option to YES to attempt the creation of the file.",
866 GDALGetDataTypeName(poBand->GetRasterDataType()));
867 return NULL;
868 }
869 break;
870 }
871 }
872
873 if( !pfnProgress( 0.0, NULL, pProgressData ) )
874 return NULL;
875
876 /* -------------------------------------------------------------------- */
877 /* Create the dataset. */
878 /* -------------------------------------------------------------------- */
879 jas_stream_t *psStream;
880 jas_image_t *psImage;
881
882 JPEG2000Init();
883 const char* pszAccess = EQUALN(pszFilename, "/vsisubfile/", 12) ? "r+b" : "w+b";
884 if( !(psStream = JPEG2000_VSIL_fopen( pszFilename, pszAccess) ) )
885 {
886 CPLError( CE_Failure, CPLE_FileIO, "Unable to create file %s.\n",
887 pszFilename );
888 return NULL;
889 }
890
891 if ( !(psImage = jas_image_create0()) )
892 {
893 CPLError( CE_Failure, CPLE_OutOfMemory, "Unable to create image %s.\n",
894 pszFilename );
895 return NULL;
896 }
897
898 /* -------------------------------------------------------------------- */
899 /* Loop over image, copying image data. */
900 /* -------------------------------------------------------------------- */
901 GUInt32 *paiScanline;
902 int iLine, iPixel;
903 CPLErr eErr = CE_None;
904 jas_matrix_t *psMatrix;
905 jas_image_cmptparm_t *sComps; // Array of pointers to image components
906
907 sComps = (jas_image_cmptparm_t*)
908 CPLMalloc( nBands * sizeof(jas_image_cmptparm_t) );
909
910 if ( !(psMatrix = jas_matrix_create( 1, nXSize )) )
911 {
912 CPLError( CE_Failure, CPLE_OutOfMemory,
913 "Unable to create matrix with size %dx%d.\n", 1, nYSize );
914 CPLFree( sComps );
915 jas_image_destroy( psImage );
916 return NULL;
917 }
918 paiScanline = (GUInt32 *) CPLMalloc( nXSize *
919 GDALGetDataTypeSize(GDT_UInt32) / 8 );
920
921 for ( iBand = 0; iBand < nBands; iBand++ )
922 {
923 poBand = poSrcDS->GetRasterBand( iBand + 1);
924
925 sComps[iBand].tlx = sComps[iBand].tly = 0;
926 sComps[iBand].hstep = sComps[iBand].vstep = 1;
927 sComps[iBand].width = nXSize;
928 sComps[iBand].height = nYSize;
929 sComps[iBand].prec = GDALGetDataTypeSize( poBand->GetRasterDataType() );
930 switch ( poBand->GetRasterDataType() )
931 {
932 case GDT_Int16:
933 case GDT_Int32:
934 case GDT_Float32:
935 case GDT_Float64:
936 sComps[iBand].sgnd = 1;
937 break;
938 case GDT_Byte:
939 case GDT_UInt16:
940 case GDT_UInt32:
941 default:
942 sComps[iBand].sgnd = 0;
943 break;
944 }
945 jas_image_addcmpt(psImage, iBand, sComps);
946
947 for( iLine = 0; eErr == CE_None && iLine < nYSize; iLine++ )
948 {
949 eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
950 paiScanline, nXSize, 1, GDT_UInt32,
951 sizeof(GUInt32), sizeof(GUInt32) * nXSize, NULL );
952 for ( iPixel = 0; iPixel < nXSize; iPixel++ )
953 jas_matrix_setv( psMatrix, iPixel, paiScanline[iPixel] );
954
955 if( (jas_image_writecmpt(psImage, iBand, 0, iLine,
956 nXSize, 1, psMatrix)) < 0 )
957 {
958 CPLError( CE_Failure, CPLE_AppDefined,
959 "Unable to write scanline %d of the component %d.\n",
960 iLine, iBand );
961 jas_matrix_destroy( psMatrix );
962 CPLFree( paiScanline );
963 CPLFree( sComps );
964 jas_image_destroy( psImage );
965 return NULL;
966 }
967
968 if( eErr == CE_None &&
969 !pfnProgress( ((iLine + 1) + iBand * nYSize) /
970 ((double) nYSize * nBands),
971 NULL, pProgressData) )
972 {
973 eErr = CE_Failure;
974 CPLError( CE_Failure, CPLE_UserInterrupt,
975 "User terminated CreateCopy()" );
976 }
977 }
978 }
979
980 /* -------------------------------------------------------------------- */
981 /* Read compression parameters and encode the image. */
982 /* -------------------------------------------------------------------- */
983 int i, j;
984 const int OPTSMAX = 4096;
985 const char *pszFormatName;
986 char pszOptionBuf[OPTSMAX + 1];
987
988 const char *apszComprOptions[]=
989 {
990 "imgareatlx",
991 "imgareatly",
992 "tilegrdtlx",
993 "tilegrdtly",
994 "tilewidth",
995 "tileheight",
996 "prcwidth",
997 "prcheight",
998 "cblkwidth",
999 "cblkheight",
1000 "mode",
1001 "rate",
1002 "ilyrrates",
1003 "prg",
1004 "numrlvls",
1005 "sop",
1006 "eph",
1007 "lazy",
1008 "termall",
1009 "segsym",
1010 "vcausal",
1011 "pterm",
1012 "resetprob",
1013 "numgbits",
1014 NULL
1015 };
1016
1017 pszFormatName = CSLFetchNameValue( papszOptions, "FORMAT" );
1018 if ( !pszFormatName ||
1019 (!EQUALN( pszFormatName, "jp2", 3 ) &&
1020 !EQUALN( pszFormatName, "jpc", 3 ) ) )
1021 pszFormatName = "jp2";
1022
1023 pszOptionBuf[0] = '\0';
1024 if ( papszOptions )
1025 {
1026 CPLDebug( "JPEG2000", "User supplied parameters:" );
1027 for ( i = 0; papszOptions[i] != NULL; i++ )
1028 {
1029 CPLDebug( "JPEG2000", "%s\n", papszOptions[i] );
1030 for ( j = 0; apszComprOptions[j] != NULL; j++ )
1031 if( EQUALN( apszComprOptions[j], papszOptions[i],
1032 strlen(apszComprOptions[j]) ) )
1033 {
1034 int m, n;
1035
1036 n = strlen( pszOptionBuf );
1037 m = n + strlen( papszOptions[i] ) + 1;
1038 if ( m > OPTSMAX )
1039 break;
1040 if ( n > 0 )
1041 {
1042 strcat( pszOptionBuf, "\n" );
1043 }
1044 strcat( pszOptionBuf, papszOptions[i] );
1045 }
1046 }
1047 }
1048 CPLDebug( "JPEG2000", "Parameters, delivered to the JasPer library:" );
1049 CPLDebug( "JPEG2000", "%s", pszOptionBuf );
1050
1051 if ( nBands == 1 ) // Grayscale
1052 {
1053 jas_image_setclrspc( psImage, JAS_CLRSPC_SGRAY );
1054 jas_image_setcmpttype( psImage, 0, JAS_IMAGE_CT_GRAY_Y );
1055 }
1056 else if ( nBands == 3 || nBands == 4 ) // Assume as RGB(A)
1057 {
1058 jas_image_setclrspc( psImage, JAS_CLRSPC_SRGB );
1059 for ( iBand = 0; iBand < nBands; iBand++ )
1060 {
1061 poBand = poSrcDS->GetRasterBand( iBand + 1);
1062 switch ( poBand->GetColorInterpretation() )
1063 {
1064 case GCI_RedBand:
1065 jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_RGB_R );
1066 break;
1067 case GCI_GreenBand:
1068 jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_RGB_G );
1069 break;
1070 case GCI_BlueBand:
1071 jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_RGB_B );
1072 break;
1073 case GCI_AlphaBand:
1074 jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_OPACITY );
1075 break;
1076 default:
1077 jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_UNKNOWN );
1078 break;
1079 }
1080 }
1081 }
1082 else // Unknown
1083 {
1084 /* JAS_CLRSPC_UNKNOWN causes crashes in Jasper jp2_enc.c at line 231 */
1085 /* iccprof = jas_iccprof_createfromcmprof(jas_image_cmprof(image)); */
1086 /* but if we explictely set the cmprof, it does not work better */
1087 /* since it would abort at line 281 later ... */
1088 /* So the best option is to switch to gray colorspace */
1089 /* And we need to switch at the band level too, otherwise Kakadu or */
1090 /* JP2MrSID don't like it */
1091 //jas_image_setclrspc( psImage, JAS_CLRSPC_UNKNOWN );
1092 jas_image_setclrspc( psImage, JAS_CLRSPC_SGRAY );
1093 for ( iBand = 0; iBand < nBands; iBand++ )
1094 //jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_UNKNOWN );
1095 jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_GRAY_Y );
1096 }
1097
1098 /* -------------------------------------------------------------------- */
1099 /* Set the GeoTIFF box if georeferencing is available, and this */
1100 /* is a JP2 file. */
1101 /* -------------------------------------------------------------------- */
1102 if ( EQUALN( pszFormatName, "jp2", 3 ) )
1103 {
1104 #ifdef HAVE_JASPER_UUID
1105 double adfGeoTransform[6];
1106 if( CSLFetchBoolean( papszOptions, "GeoJP2", TRUE ) &&
1107 ((poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None
1108 && (adfGeoTransform[0] != 0.0
1109 || adfGeoTransform[1] != 1.0
1110 || adfGeoTransform[2] != 0.0
1111 || adfGeoTransform[3] != 0.0
1112 || adfGeoTransform[4] != 0.0
1113 || ABS(adfGeoTransform[5]) != 1.0))
1114 || poSrcDS->GetGCPCount() > 0
1115 || poSrcDS->GetMetadata("RPC") != NULL ) )
1116 {
1117 GDALJP2Metadata oJP2Geo;
1118
1119 if( poSrcDS->GetGCPCount() > 0 )
1120 {
1121 oJP2Geo.SetProjection( poSrcDS->GetGCPProjection() );
1122 oJP2Geo.SetGCPs( poSrcDS->GetGCPCount(), poSrcDS->GetGCPs() );
1123 }
1124 else
1125 {
1126 oJP2Geo.SetProjection( poSrcDS->GetProjectionRef() );
1127 oJP2Geo.SetGeoTransform( adfGeoTransform );
1128 }
1129
1130 oJP2Geo.SetRPCMD( poSrcDS->GetMetadata("RPC") );
1131
1132 const char* pszAreaOrPoint = poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT);
1133 oJP2Geo.bPixelIsPoint = pszAreaOrPoint != NULL && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT);
1134
1135 GDALJP2Box *poBox = oJP2Geo.CreateJP2GeoTIFF();
1136 jp2_box_t *box = jp2_box_create( JP2_BOX_UUID );
1137 memcpy( box->data.uuid.uuid, poBox->GetUUID(), 16 );
1138 box->data.uuid.datalen = poBox->GetDataLength() - 16;
1139 box->data.uuid.data =
1140 (uint_fast8_t *)jas_malloc( poBox->GetDataLength() - 16 );
1141 memcpy( box->data.uuid.data, poBox->GetWritableData() + 16,
1142 poBox->GetDataLength() - 16 );
1143 delete poBox;
1144 poBox = NULL;
1145
1146 if ( jp2_encode_uuid( psImage, psStream, pszOptionBuf, box) < 0 )
1147 {
1148 CPLError( CE_Failure, CPLE_FileIO,
1149 "Unable to encode image %s.", pszFilename );
1150 jp2_box_destroy( box );
1151 jas_matrix_destroy( psMatrix );
1152 CPLFree( paiScanline );
1153 CPLFree( sComps );
1154 jas_image_destroy( psImage );
1155 return NULL;
1156 }
1157 jp2_box_destroy( box );
1158 }
1159 else
1160 {
1161 #endif
1162 if ( jp2_encode( psImage, psStream, pszOptionBuf) < 0 )
1163 {
1164 CPLError( CE_Failure, CPLE_FileIO,
1165 "Unable to encode image %s.", pszFilename );
1166 jas_matrix_destroy( psMatrix );
1167 CPLFree( paiScanline );
1168 CPLFree( sComps );
1169 jas_image_destroy( psImage );
1170 return NULL;
1171 }
1172 #ifdef HAVE_JASPER_UUID
1173 }
1174 #endif
1175 }
1176 else // Write JPC code stream
1177 {
1178 if ( jpc_encode(psImage, psStream, pszOptionBuf) < 0 )
1179 {
1180 CPLError( CE_Failure, CPLE_FileIO,
1181 "Unable to encode image %s.\n", pszFilename );
1182 jas_matrix_destroy( psMatrix );
1183 CPLFree( paiScanline );
1184 CPLFree( sComps );
1185 jas_image_destroy( psImage );
1186 return NULL;
1187 }
1188 }
1189
1190 jas_stream_flush( psStream );
1191
1192 jas_matrix_destroy( psMatrix );
1193 CPLFree( paiScanline );
1194 CPLFree( sComps );
1195 jas_image_destroy( psImage );
1196 if ( jas_stream_close( psStream ) )
1197 {
1198 CPLError( CE_Failure, CPLE_FileIO, "Unable to close file %s.\n",
1199 pszFilename );
1200 return NULL;
1201 }
1202
1203 /* -------------------------------------------------------------------- */
1204 /* Add GMLJP2 box at end of file. */
1205 /* -------------------------------------------------------------------- */
1206 if ( EQUALN( pszFormatName, "jp2", 3 ) )
1207 {
1208 double adfGeoTransform[6];
1209 if( CSLFetchBoolean( papszOptions, "GMLJP2", TRUE ) &&
1210 poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None &&
1211 poSrcDS->GetProjectionRef() != NULL &&
1212 poSrcDS->GetProjectionRef()[0] != '\0' )
1213 {
1214 VSILFILE* fp = VSIFOpenL(pszFilename, "rb+");
1215 if( fp )
1216 {
1217 // Look for jp2c box and patch its LBox to be the real box size
1218 // instead of zero
1219 int bOK = FALSE;
1220 GUInt32 nLBox;
1221 GUInt32 nTBox;
1222
1223 while(TRUE)
1224 {
1225 if( VSIFReadL(&nLBox, 4, 1, fp) != 1 ||
1226 VSIFReadL(&nTBox, 4, 1, fp) != 1 )
1227 break;
1228 nLBox = CPL_MSBWORD32( nLBox );
1229 if( memcmp(&nTBox, "jp2c", 4) == 0 )
1230 {
1231 if( nLBox >= 8 )
1232 {
1233 bOK = TRUE;
1234 break;
1235 }
1236 if( nLBox == 0 )
1237 {
1238 vsi_l_offset nPos = VSIFTellL(fp);
1239 VSIFSeekL(fp, 0, SEEK_END);
1240 vsi_l_offset nEnd = VSIFTellL(fp);
1241 VSIFSeekL(fp, nPos - 8, SEEK_SET);
1242 nLBox = (GUInt32)(8 + nEnd - nPos);
1243 if( nLBox == (vsi_l_offset)8 + nEnd - nPos )
1244 {
1245 nLBox = CPL_MSBWORD32( nLBox );
1246 VSIFWriteL(&nLBox, 1, 4, fp);
1247 bOK = TRUE;
1248 }
1249 }
1250 break;
1251 }
1252 if( nLBox < 8 )
1253 break;
1254 VSIFSeekL(fp, nLBox - 8, SEEK_CUR);
1255 }
1256
1257 // Can write GMLJP2 box
1258 if( bOK )
1259 {
1260 GDALJP2Metadata oJP2MD;
1261 oJP2MD.SetProjection( poSrcDS->GetProjectionRef() );
1262 oJP2MD.SetGeoTransform( adfGeoTransform );
1263 GDALJP2Box *poBox;
1264 const char* pszGMLJP2V2Def = CSLFetchNameValue( papszOptions, "GMLJP2V2_DEF" );
1265 if( pszGMLJP2V2Def != NULL )
1266 poBox = oJP2MD.CreateGMLJP2V2(nXSize,nYSize,pszGMLJP2V2Def,poSrcDS);
1267 else
1268 poBox = oJP2MD.CreateGMLJP2(nXSize,nYSize);
1269
1270 nLBox = (int) poBox->GetDataLength() + 8;
1271 nLBox = CPL_MSBWORD32( nLBox );
1272 memcpy(&nTBox, poBox->GetType(), 4);
1273
1274 VSIFSeekL(fp, 0, SEEK_END);
1275 VSIFWriteL( &nLBox, 4, 1, fp );
1276 VSIFWriteL( &nTBox, 4, 1, fp );
1277 VSIFWriteL(poBox->GetWritableData(), 1, (int) poBox->GetDataLength(), fp);
1278 VSIFCloseL(fp);
1279
1280 delete poBox;
1281 }
1282 }
1283 }
1284 }
1285
1286 /* -------------------------------------------------------------------- */
1287 /* Do we need a world file? */
1288 /* -------------------------------------------------------------------- */
1289 if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
1290 {
1291 double adfGeoTransform[6];
1292
1293 poSrcDS->GetGeoTransform( adfGeoTransform );
1294 GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform );
1295 }
1296
1297 /* -------------------------------------------------------------------- */
1298 /* Re-open dataset, and copy any auxiliary pam information. */
1299 /* -------------------------------------------------------------------- */
1300 GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
1301 GDALPamDataset *poDS = (GDALPamDataset*) JPEG2000Dataset::Open(&oOpenInfo);
1302
1303 if( poDS )
1304 {
1305 poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT & (~GCIF_METADATA) );
1306
1307 /* Only write relevant metadata to PAM, and if needed */
1308 char** papszSrcMD = CSLDuplicate(poSrcDS->GetMetadata());
1309 papszSrcMD = CSLSetNameValue(papszSrcMD, GDALMD_AREA_OR_POINT, NULL);
1310 papszSrcMD = CSLSetNameValue(papszSrcMD, "Corder", NULL);
1311 for(char** papszSrcMDIter = papszSrcMD;
1312 papszSrcMDIter && *papszSrcMDIter; )
1313 {
1314 /* Remove entries like KEY= (without value) */
1315 if( (*papszSrcMDIter)[0] &&
1316 (*papszSrcMDIter)[strlen((*papszSrcMDIter))-1] == '=' )
1317 {
1318 CPLFree(*papszSrcMDIter);
1319 memmove(papszSrcMDIter, papszSrcMDIter + 1,
1320 sizeof(char*) * (CSLCount(papszSrcMDIter + 1) + 1));
1321 }
1322 else
1323 ++papszSrcMDIter;
1324 }
1325 char** papszMD = CSLDuplicate(poDS->GetMetadata());
1326 papszMD = CSLSetNameValue(papszMD, GDALMD_AREA_OR_POINT, NULL);
1327 if( papszSrcMD && papszSrcMD[0] != NULL &&
1328 CSLCount(papszSrcMD) != CSLCount(papszMD) )
1329 {
1330 poDS->SetMetadata(papszSrcMD);
1331 }
1332 CSLDestroy(papszSrcMD);
1333 CSLDestroy(papszMD);
1334 }
1335
1336 return poDS;
1337 }
1338
1339 /************************************************************************/
1340 /* GDALRegister_JPEG2000() */
1341 /************************************************************************/
1342
GDALRegister_JPEG2000()1343 void GDALRegister_JPEG2000()
1344
1345 {
1346 GDALDriver *poDriver;
1347
1348 if (! GDAL_CHECK_VERSION("JPEG2000 driver"))
1349 return;
1350
1351 if( GDALGetDriverByName( "JPEG2000" ) == NULL )
1352 {
1353 poDriver = new GDALDriver();
1354
1355 poDriver->SetDescription( "JPEG2000" );
1356 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
1357 poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
1358 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1359 "JPEG-2000 part 1 (ISO/IEC 15444-1), based on Jasper library" );
1360 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1361 "frmt_jpeg2000.html" );
1362 poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1363 "Byte Int16 UInt16 Int32 UInt32" );
1364 poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/jp2" );
1365 poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
1366
1367 poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1368
1369 poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
1370 "<OpenOptionList>"
1371 " <Option name='1BIT_ALPHA_PROMOTION' type='boolean' description='Whether a 1-bit alpha channel should be promoted to 8-bit' default='YES'/>"
1372 " <Option name='OPEN_REMOTE_GML' type='boolean' description='Whether to load remote vector layers referenced by a link in a GMLJP2 v2 box' default='NO'/>"
1373 "</OpenOptionList>" );
1374
1375 poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1376 "<CreationOptionList>"
1377 " <Option name='FORMAT' type='string-select' default='according to file extension. If unknown, default to J2K'>"
1378 " <Value>JP2</Value>"
1379 " <Value>JPC</Value>"
1380 " </Option>"
1381 " <Option name='GeoJP2' type='boolean' description='Whether to emit a GeoJP2 box' default='YES'/>"
1382 " <Option name='GMLJP2' type='boolean' description='Whether to emit a GMLJP2 v1 box' default='YES'/>"
1383 " <Option name='GMLJP2V2_DEF' type='string' description='Definition file to describe how a GMLJP2 v2 box should be generated. If set to YES, a minimal instance will be created'/>"
1384 " <Option name='WORLDFILE' type='boolean' description='Whether to write a worldfile .wld' default='NO'/>"
1385 " <Option name='imgareatlx' type='string' />"
1386 " <Option name='imgareatly' type='string' />"
1387 " <Option name='tilegrdtlx' type='string' />"
1388 " <Option name='tilegrdtly' type='string' />"
1389 " <Option name='tilewidth' type='string' />"
1390 " <Option name='tileheight' type='string' />"
1391 " <Option name='prcwidth' type='string' />"
1392 " <Option name='prcheight' type='string' />"
1393 " <Option name='cblkwidth' type='string' />"
1394 " <Option name='cblkheight' type='string' />"
1395 " <Option name='mode' type='string' />"
1396 " <Option name='rate' type='string' />"
1397 " <Option name='ilyrrates' type='string' />"
1398 " <Option name='prg' type='string' />"
1399 " <Option name='numrlvls' type='string' />"
1400 " <Option name='sop' type='string' />"
1401 " <Option name='eph' type='string' />"
1402 " <Option name='lazy' type='string' />"
1403 " <Option name='termall' type='string' />"
1404 " <Option name='segsym' type='string' />"
1405 " <Option name='vcausal' type='string' />"
1406 " <Option name='pterm' type='string' />"
1407 " <Option name='resetprob' type='string' />"
1408 " <Option name='numgbits' type='string' />"
1409 "</CreationOptionList>" );
1410
1411 poDriver->pfnIdentify = JPEG2000Dataset::Identify;
1412 poDriver->pfnOpen = JPEG2000Dataset::Open;
1413 poDriver->pfnCreateCopy = JPEG2000CreateCopy;
1414
1415 GetGDALDriverManager()->RegisterDriver( poDriver );
1416 }
1417 }
1418
1419