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