1 : /******************************************************************************
2 : * $Id: openjpegdataset.cpp 23033 2011-09-03 18:46:11Z rouault $
3 : *
4 : * Project: JPEG2000 driver based on OpenJPEG library
5 : * Purpose: JPEG2000 driver based on OpenJPEG library
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault, <even dot rouault at mines dash paris dot org>
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 : /* Necessary for opj_setup_decoder() */
31 : #define USE_OPJ_DEPRECATED
32 :
33 : /* A bit of explanation for this ugly "#define bool int"... */
34 : /* openjpeg.h contains itself a "#define bool int" when it is included from a C file */
35 : /* The openjpeg library is written in C, so every reference to bool within the library */
36 : /* assumes that bool is a int. So we have also to reinforce this when including the library */
37 : /* and when calling openjpeg API from the driver, we have to replace bool by int also */
38 : #define bool int
39 : #define GDAL_OPENJPEG_BOOL int
40 : #include <openjpeg.h>
41 : #undef bool /* undef now, so that later includes are happy */
42 :
43 : #include "gdal_pam.h"
44 : #include "cpl_string.h"
45 : #include "gdaljp2metadata.h"
46 :
47 : CPL_CVSID("$Id: openjpegdataset.cpp 23033 2011-09-03 18:46:11Z rouault $");
48 :
49 : /************************************************************************/
50 : /* JP2OpenJPEGDataset_ErrorCallback() */
51 : /************************************************************************/
52 :
53 6 : static void JP2OpenJPEGDataset_ErrorCallback(const char *pszMsg, void *unused)
54 : {
55 6 : CPLError(CE_Failure, CPLE_AppDefined, "%s", pszMsg);
56 6 : }
57 :
58 : /************************************************************************/
59 : /* JP2OpenJPEGDataset_WarningCallback() */
60 : /************************************************************************/
61 :
62 0 : static void JP2OpenJPEGDataset_WarningCallback(const char *pszMsg, void *unused)
63 : {
64 0 : CPLError(CE_Warning, CPLE_AppDefined, "%s", pszMsg);
65 0 : }
66 :
67 : /************************************************************************/
68 : /* JP2OpenJPEGDataset_InfoCallback() */
69 : /************************************************************************/
70 :
71 23 : static void JP2OpenJPEGDataset_InfoCallback(const char *pszMsg, void *unused)
72 : {
73 23 : CPLDebug("OPENJPEG", "info: %s", pszMsg);
74 23 : }
75 :
76 : /************************************************************************/
77 : /* JP2OpenJPEGDataset_Read() */
78 : /************************************************************************/
79 :
80 1456 : static OPJ_UINT32 JP2OpenJPEGDataset_Read(void* pBuffer, OPJ_UINT32 nBytes,
81 : void *pUserData)
82 : {
83 1456 : int nRet = VSIFReadL(pBuffer, 1, nBytes, (VSILFILE*)pUserData);
84 : #ifdef DEBUG
85 1456 : CPLDebug("OPENJPEG", "JP2OpenJPEGDataset_Read(%d) = %d", nBytes, nRet);
86 : #endif
87 1456 : if (nRet == 0)
88 21 : nRet = -1;
89 1456 : return nRet;
90 : }
91 :
92 : /************************************************************************/
93 : /* JP2OpenJPEGDataset_Write() */
94 : /************************************************************************/
95 :
96 2 : static OPJ_UINT32 JP2OpenJPEGDataset_Write(void* pBuffer, OPJ_UINT32 nBytes,
97 : void *pUserData)
98 : {
99 2 : int nRet = VSIFWriteL(pBuffer, 1, nBytes, (VSILFILE*)pUserData);
100 : #ifdef DEBUG
101 2 : CPLDebug("OPENJPEG", "JP2OpenJPEGDataset_Write(%d) = %d", nBytes, nRet);
102 : #endif
103 2 : return nRet;
104 : }
105 :
106 : /************************************************************************/
107 : /* JP2OpenJPEGDataset_Seek() */
108 : /************************************************************************/
109 :
110 0 : static GDAL_OPENJPEG_BOOL JP2OpenJPEGDataset_Seek(OPJ_SIZE_T nBytes, void * pUserData)
111 : {
112 : #ifdef DEBUG
113 0 : CPLDebug("OPENJPEG", "JP2OpenJPEGDataset_Seek(%d)", nBytes);
114 : #endif
115 0 : return VSIFSeekL((VSILFILE*)pUserData, nBytes, SEEK_SET) == 0;
116 : }
117 :
118 : /************************************************************************/
119 : /* JP2OpenJPEGDataset_Skip() */
120 : /************************************************************************/
121 :
122 1218 : static OPJ_SIZE_T JP2OpenJPEGDataset_Skip(OPJ_SIZE_T nBytes, void * pUserData)
123 : {
124 1218 : vsi_l_offset nOffset = VSIFTellL((VSILFILE*)pUserData);
125 1218 : nOffset += nBytes;
126 : #ifdef DEBUG
127 : CPLDebug("OPENJPEG", "JP2OpenJPEGDataset_Skip(%d -> " CPL_FRMT_GUIB ")",
128 1218 : nBytes, (GUIntBig)nOffset);
129 : #endif
130 1218 : VSIFSeekL((VSILFILE*)pUserData, nOffset, SEEK_SET);
131 1218 : return nBytes;
132 : }
133 :
134 : /************************************************************************/
135 : /* ==================================================================== */
136 : /* JP2OpenJPEGDataset */
137 : /* ==================================================================== */
138 : /************************************************************************/
139 :
140 : class JP2OpenJPEGDataset : public GDALPamDataset
141 : {
142 : friend class JP2OpenJPEGRasterBand;
143 :
144 : VSILFILE *fp; /* Large FILE API */
145 :
146 : char *pszProjection;
147 : int bGeoTransformValid;
148 : double adfGeoTransform[6];
149 : int nGCPCount;
150 : GDAL_GCP *pasGCPList;
151 :
152 : OPJ_CODEC_FORMAT eCodecFormat;
153 : OPJ_COLOR_SPACE eColorSpace;
154 :
155 : int bLoadingOtherBands;
156 : int bIs420;
157 : OPJ_BYTE * pFullBuffer;
158 :
159 : public:
160 : JP2OpenJPEGDataset();
161 : ~JP2OpenJPEGDataset();
162 :
163 : static int Identify( GDALOpenInfo * poOpenInfo );
164 : static GDALDataset *Open( GDALOpenInfo * );
165 : static GDALDataset *CreateCopy( const char * pszFilename,
166 : GDALDataset *poSrcDS,
167 : int bStrict, char ** papszOptions,
168 : GDALProgressFunc pfnProgress,
169 : void * pProgressData );
170 : CPLErr GetGeoTransform( double* );
171 : virtual const char *GetProjectionRef(void);
172 : virtual int GetGCPCount();
173 : virtual const char *GetGCPProjection();
174 : virtual const GDAL_GCP *GetGCPs();
175 : };
176 :
177 : /************************************************************************/
178 : /* ==================================================================== */
179 : /* JP2OpenJPEGRasterBand */
180 : /* ==================================================================== */
181 : /************************************************************************/
182 :
183 : class JP2OpenJPEGRasterBand : public GDALPamRasterBand
184 : {
185 : friend class JP2OpenJPEGDataset;
186 :
187 : public:
188 :
189 : JP2OpenJPEGRasterBand( JP2OpenJPEGDataset * poDS, int nBand,
190 : GDALDataType eDataType,
191 : int nBlockXSize, int nBlockYSize);
192 : ~JP2OpenJPEGRasterBand();
193 :
194 : virtual CPLErr IReadBlock( int, int, void * );
195 : virtual GDALColorInterp GetColorInterpretation();
196 : };
197 :
198 :
199 : /************************************************************************/
200 : /* JP2OpenJPEGRasterBand() */
201 : /************************************************************************/
202 :
203 38 : JP2OpenJPEGRasterBand::JP2OpenJPEGRasterBand( JP2OpenJPEGDataset *poDS, int nBand,
204 : GDALDataType eDataType,
205 38 : int nBlockXSize, int nBlockYSize)
206 :
207 : {
208 38 : this->poDS = poDS;
209 38 : this->nBand = nBand;
210 38 : this->eDataType = eDataType;
211 38 : this->nBlockXSize = nBlockXSize;
212 38 : this->nBlockYSize = nBlockYSize;
213 38 : }
214 :
215 : /************************************************************************/
216 : /* ~JP2OpenJPEGRasterBand() */
217 : /************************************************************************/
218 :
219 38 : JP2OpenJPEGRasterBand::~JP2OpenJPEGRasterBand()
220 : {
221 38 : }
222 :
223 : /************************************************************************/
224 : /* CopySrcToDst() */
225 : /************************************************************************/
226 :
227 921600 : static CPL_INLINE GByte CLAMP_0_255(int val)
228 : {
229 921600 : if (val < 0)
230 1383 : return 0;
231 920217 : else if (val > 255)
232 1778 : return 255;
233 : else
234 918439 : return (GByte)val;
235 : }
236 :
237 179 : static void CopySrcToDst(int nWidthToRead, int nHeightToRead,
238 : GByte* pTempBuffer,
239 : int nBlockXSize, int nBlockYSize, int nDataTypeSize,
240 : void* pImage, int nBand, int bIs420)
241 : {
242 : int i, j;
243 179 : if (bIs420)
244 : {
245 3 : GByte* pSrc = (GByte*)pTempBuffer;
246 3 : GByte* pDst = (GByte*)pImage;
247 1923 : for(j=0;j<nHeightToRead;j++)
248 : {
249 923520 : for(i=0;i<nWidthToRead;i++)
250 : {
251 921600 : int Y = pSrc[j * nWidthToRead + i];
252 921600 : int Cb = pSrc[nHeightToRead * nWidthToRead + ((j/2) * (nWidthToRead/2) + i/2) ];
253 921600 : int Cr = pSrc[5 * nHeightToRead * nWidthToRead / 4 + ((j/2) * (nWidthToRead/2) + i/2) ];
254 921600 : if (nBand == 1)
255 307200 : pDst[j * nBlockXSize + i] = CLAMP_0_255((int)(Y + 1.402 * (Cr - 128)));
256 614400 : else if (nBand == 2)
257 307200 : pDst[j * nBlockXSize + i] = CLAMP_0_255((int)(Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128)));
258 : else
259 307200 : pDst[j * nBlockXSize + i] = CLAMP_0_255((int)(Y + 1.772 * (Cb - 128)));
260 : }
261 : }
262 : }
263 : else
264 : {
265 66992 : for(j=0;j<nHeightToRead;j++)
266 : {
267 : memcpy(((GByte*)pImage) + j*nBlockXSize * nDataTypeSize,
268 : pTempBuffer + (j*nWidthToRead + (nBand-1) * nHeightToRead * nWidthToRead) * nDataTypeSize,
269 66816 : nWidthToRead * nDataTypeSize);
270 : }
271 : }
272 179 : }
273 :
274 : /************************************************************************/
275 : /* IReadBlock() */
276 : /************************************************************************/
277 :
278 69 : CPLErr JP2OpenJPEGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
279 : void * pImage )
280 : {
281 69 : JP2OpenJPEGDataset *poGDS = (JP2OpenJPEGDataset *) poDS;
282 69 : opj_codec_t* pCodec = NULL;
283 69 : int nDataTypeSize = (GDALGetDataTypeSize(eDataType) / 8);
284 :
285 : CPLDebug("OPENJPEG", "xoff=%d yoff=%d band=%d",
286 69 : nBlockXOff, nBlockYOff, nBand);
287 :
288 69 : int nWidthToRead = MIN(nBlockXSize, poGDS->nRasterXSize - nBlockXOff * nBlockXSize);
289 69 : int nHeightToRead = MIN(nBlockYSize, poGDS->nRasterYSize - nBlockYOff * nBlockYSize);
290 :
291 69 : if (poGDS->pFullBuffer)
292 : {
293 : CopySrcToDst(nWidthToRead, nHeightToRead, poGDS->pFullBuffer,
294 : nBlockXSize, nBlockYSize, nDataTypeSize, pImage,
295 0 : nBand, poGDS->bIs420);
296 0 : return CE_None;
297 : }
298 :
299 69 : if (nWidthToRead != nBlockXSize || nHeightToRead != nBlockYSize)
300 : {
301 18 : memset(pImage, 0, nBlockXSize * nBlockYSize * nDataTypeSize);
302 : }
303 :
304 : /* FIXME ? Well, this is pretty inefficient as for each block we recreate */
305 : /* a new decoding session. But currently there's no way to call opj_set_decode_area() */
306 : /* twice on the same codec instance... */
307 :
308 69 : pCodec = opj_create_decompress(poGDS->eCodecFormat);
309 :
310 69 : opj_set_info_handler(pCodec, JP2OpenJPEGDataset_InfoCallback,NULL);
311 69 : opj_set_warning_handler(pCodec, JP2OpenJPEGDataset_WarningCallback,NULL);
312 69 : opj_set_error_handler(pCodec, JP2OpenJPEGDataset_ErrorCallback,NULL);
313 :
314 : opj_dparameters_t parameters;
315 69 : opj_set_default_decoder_parameters(¶meters);
316 :
317 69 : if (! opj_setup_decoder(pCodec,¶meters))
318 : {
319 0 : CPLError(CE_Failure, CPLE_AppDefined, "opj_setup_decoder() failed");
320 0 : opj_destroy_codec(pCodec);
321 0 : return CE_Failure;
322 : }
323 :
324 : /* Reseek to file beginning */
325 69 : VSIFSeekL(poGDS->fp, 0, SEEK_SET);
326 :
327 : opj_stream_t * pStream;
328 69 : pStream = opj_stream_create(1024, TRUE); // Default 1MB is way too big for some datasets
329 69 : opj_stream_set_read_function(pStream, JP2OpenJPEGDataset_Read);
330 69 : opj_stream_set_seek_function(pStream, JP2OpenJPEGDataset_Seek);
331 69 : opj_stream_set_skip_function(pStream, JP2OpenJPEGDataset_Skip);
332 69 : opj_stream_set_user_data(pStream, poGDS->fp);
333 :
334 69 : opj_image_t * psImage = NULL;
335 : OPJ_INT32 nX0,nY0;
336 : OPJ_UINT32 nTileW,nTileH,nTilesX,nTilesY;
337 69 : if(!opj_read_header(pCodec, &psImage, &nX0, &nY0, &nTileW, &nTileH,
338 : &nTilesX, &nTilesY, pStream))
339 : {
340 0 : CPLError(CE_Failure, CPLE_AppDefined, "opj_read_header() failed");
341 0 : opj_destroy_codec(pCodec);
342 0 : opj_stream_destroy(pStream);
343 0 : return CE_Failure;
344 : }
345 :
346 69 : if (!opj_set_decode_area(pCodec,
347 : nBlockXOff * nBlockXSize,
348 : nBlockYOff * nBlockYSize,
349 : nBlockXOff * nBlockXSize + nWidthToRead,
350 : nBlockYOff * nBlockYSize + nHeightToRead))
351 : {
352 0 : CPLError(CE_Failure, CPLE_AppDefined, "opj_set_decode_area() failed");
353 0 : opj_destroy_codec(pCodec);
354 0 : opj_stream_destroy(pStream);
355 0 : opj_image_destroy(psImage);
356 0 : return CE_Failure;
357 : }
358 :
359 : GDAL_OPENJPEG_BOOL bDataToUncompress;
360 : OPJ_UINT32 nTileIndex,nCompCount;
361 : OPJ_INT32 nTileX0,nTileY0,nTileX1,nTileY1;
362 : OPJ_UINT32 nRequiredSize;
363 :
364 : int nAllocatedSize;
365 69 : if (poGDS->bIs420)
366 1 : nAllocatedSize = 3 * nWidthToRead * nHeightToRead * nDataTypeSize / 2;
367 : else
368 68 : nAllocatedSize = poGDS->nBands * nWidthToRead * nHeightToRead * nDataTypeSize;
369 69 : OPJ_BYTE *pTempBuffer = (OPJ_BYTE *)VSIMalloc(nAllocatedSize);
370 69 : if (pTempBuffer == NULL)
371 : {
372 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate temp buffer");
373 0 : opj_destroy_codec(pCodec);
374 0 : opj_stream_destroy(pStream);
375 0 : opj_image_destroy(psImage);
376 0 : return CE_Failure;
377 : }
378 :
379 138 : do
380 : {
381 138 : if (!opj_read_tile_header(pCodec, &nTileIndex, &nRequiredSize,
382 : &nTileX0, &nTileY0, &nTileX1, &nTileY1,
383 : &nCompCount, &bDataToUncompress, pStream))
384 : {
385 0 : CPLError(CE_Failure, CPLE_AppDefined, "opj_read_tile_header() failed");
386 0 : CPLFree(pTempBuffer);
387 0 : opj_destroy_codec(pCodec);
388 0 : opj_stream_destroy(pStream);
389 0 : opj_image_destroy(psImage);
390 0 : return CE_Failure;
391 : }
392 :
393 : /* A few sanity checks */
394 138 : if (nTileX0 != nBlockXOff * nBlockXSize ||
395 : nTileY0 != nBlockYOff * nBlockYSize ||
396 : nTileX1 != nBlockXOff * nBlockXSize + nWidthToRead ||
397 : nTileY1 != nBlockYOff * nBlockYSize + nHeightToRead ||
398 : (int)nRequiredSize != nAllocatedSize ||
399 : (int)nCompCount != poGDS->nBands)
400 : {
401 : CPLDebug("OPENJPEG",
402 : "bDataToUncompress=%d nTileIndex=%d nRequiredSize=%d nCompCount=%d",
403 0 : bDataToUncompress, nTileIndex, nRequiredSize, nCompCount);
404 : CPLDebug("OPENJPEG",
405 : "nTileX0=%d nTileY0=%d nTileX1=%d nTileY1=%d",
406 0 : nTileX0, nTileY0, nTileX1, nTileY1);
407 : CPLError(CE_Failure, CPLE_AppDefined,
408 0 : "opj_read_tile_header() returned unexpected parameters");
409 0 : CPLFree(pTempBuffer);
410 0 : opj_destroy_codec(pCodec);
411 0 : opj_stream_destroy(pStream);
412 0 : opj_image_destroy(psImage);
413 0 : return CE_Failure;
414 : }
415 :
416 138 : if (bDataToUncompress)
417 : {
418 69 : if (!opj_decode_tile_data(pCodec,nTileIndex,pTempBuffer,
419 : nRequiredSize,pStream))
420 : {
421 0 : CPLError(CE_Failure, CPLE_AppDefined, "opj_decode_tile_data() failed");
422 0 : CPLFree(pTempBuffer);
423 0 : opj_destroy_codec(pCodec);
424 0 : opj_stream_destroy(pStream);
425 0 : opj_image_destroy(psImage);
426 0 : return CE_Failure;
427 : }
428 : }
429 : } while(bDataToUncompress);
430 :
431 : CopySrcToDst(nWidthToRead, nHeightToRead, pTempBuffer,
432 : nBlockXSize, nBlockYSize, nDataTypeSize, pImage,
433 69 : nBand, poGDS->bIs420);
434 :
435 : /* Let's cache other bands */
436 69 : if( poGDS->nBands != 1 && !poGDS->bLoadingOtherBands &&
437 : poGDS->nBands * nWidthToRead * nHeightToRead * nDataTypeSize <= GDALGetCacheMax64())
438 : {
439 : int iOtherBand;
440 :
441 55 : poGDS->bLoadingOtherBands = TRUE;
442 :
443 220 : for( iOtherBand = 1; iOtherBand <= poGDS->nBands; iOtherBand++ )
444 : {
445 165 : if( iOtherBand == nBand )
446 55 : continue;
447 :
448 : GDALRasterBlock *poBlock;
449 :
450 : poBlock = poGDS->GetRasterBand(iOtherBand)->
451 110 : GetLockedBlockRef(nBlockXOff,nBlockYOff, TRUE);
452 110 : if (poBlock == NULL)
453 : {
454 0 : break;
455 : }
456 :
457 110 : void* pData = poBlock->GetDataRef();
458 110 : if (pData)
459 : {
460 : CopySrcToDst(nWidthToRead, nHeightToRead, pTempBuffer,
461 : nBlockXSize, nBlockYSize, nDataTypeSize, pData,
462 110 : iOtherBand, poGDS->bIs420);
463 : }
464 :
465 110 : poBlock->DropLock();
466 : }
467 :
468 55 : poGDS->bLoadingOtherBands = FALSE;
469 : }
470 :
471 69 : if (nBlockXSize == nRasterXSize && nBlockYSize == nRasterYSize &&
472 : poGDS->nBands * nWidthToRead * nHeightToRead * nDataTypeSize > GDALGetCacheMax64())
473 : {
474 0 : poGDS->pFullBuffer = pTempBuffer;
475 : }
476 : else
477 : {
478 69 : CPLFree(pTempBuffer);
479 : }
480 :
481 69 : opj_end_decompress(pCodec,pStream);
482 69 : opj_stream_destroy(pStream);
483 69 : opj_destroy_codec(pCodec);
484 69 : opj_image_destroy(psImage);
485 :
486 69 : return CE_None;
487 : }
488 :
489 : /************************************************************************/
490 : /* GetColorInterpretation() */
491 : /************************************************************************/
492 :
493 3 : GDALColorInterp JP2OpenJPEGRasterBand::GetColorInterpretation()
494 : {
495 3 : JP2OpenJPEGDataset *poGDS = (JP2OpenJPEGDataset *) poDS;
496 :
497 3 : if (poGDS->eColorSpace == CLRSPC_GRAY)
498 0 : return GCI_GrayIndex;
499 3 : else if (poGDS->nBands == 3 || poGDS->nBands == 4)
500 : {
501 0 : switch(nBand)
502 : {
503 : case 1:
504 0 : return GCI_RedBand;
505 : case 2:
506 0 : return GCI_GreenBand;
507 : case 3:
508 0 : return GCI_BlueBand;
509 : case 4:
510 0 : return GCI_AlphaBand;
511 : default:
512 0 : return GCI_Undefined;
513 : }
514 : }
515 :
516 3 : return GCI_Undefined;
517 : }
518 :
519 : /************************************************************************/
520 : /* ==================================================================== */
521 : /* JP2OpenJPEGDataset */
522 : /* ==================================================================== */
523 : /************************************************************************/
524 :
525 : /************************************************************************/
526 : /* JP2OpenJPEGDataset() */
527 : /************************************************************************/
528 :
529 24 : JP2OpenJPEGDataset::JP2OpenJPEGDataset()
530 : {
531 24 : fp = NULL;
532 24 : nBands = 0;
533 24 : pszProjection = CPLStrdup("");
534 24 : nGCPCount = 0;
535 24 : pasGCPList = NULL;
536 24 : bGeoTransformValid = FALSE;
537 24 : adfGeoTransform[0] = 0.0;
538 24 : adfGeoTransform[1] = 1.0;
539 24 : adfGeoTransform[2] = 0.0;
540 24 : adfGeoTransform[3] = 0.0;
541 24 : adfGeoTransform[4] = 0.0;
542 24 : adfGeoTransform[5] = 1.0;
543 24 : bLoadingOtherBands = FALSE;
544 24 : eCodecFormat = CODEC_UNKNOWN;
545 24 : eColorSpace = CLRSPC_UNKNOWN;
546 24 : bIs420 = FALSE;
547 24 : pFullBuffer = NULL;
548 24 : }
549 :
550 : /************************************************************************/
551 : /* ~JP2OpenJPEGDataset() */
552 : /************************************************************************/
553 :
554 24 : JP2OpenJPEGDataset::~JP2OpenJPEGDataset()
555 :
556 : {
557 24 : FlushCache();
558 :
559 24 : if ( pszProjection )
560 24 : CPLFree( pszProjection );
561 24 : if( nGCPCount > 0 )
562 : {
563 2 : GDALDeinitGCPs( nGCPCount, pasGCPList );
564 2 : CPLFree( pasGCPList );
565 : }
566 24 : if( fp != NULL )
567 24 : VSIFCloseL( fp );
568 24 : VSIFree(pFullBuffer);
569 24 : }
570 :
571 : /************************************************************************/
572 : /* GetProjectionRef() */
573 : /************************************************************************/
574 :
575 9 : const char *JP2OpenJPEGDataset::GetProjectionRef()
576 :
577 : {
578 9 : if ( pszProjection && pszProjection[0] != 0 )
579 5 : return( pszProjection );
580 : else
581 4 : return GDALPamDataset::GetProjectionRef();
582 : }
583 :
584 : /************************************************************************/
585 : /* GetGeoTransform() */
586 : /************************************************************************/
587 :
588 7 : CPLErr JP2OpenJPEGDataset::GetGeoTransform( double * padfTransform )
589 : {
590 7 : if( bGeoTransformValid )
591 : {
592 5 : memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
593 5 : return CE_None;
594 : }
595 : else
596 2 : return GDALPamDataset::GetGeoTransform(padfTransform);
597 : }
598 :
599 : /************************************************************************/
600 : /* GetGCPCount() */
601 : /************************************************************************/
602 :
603 3 : int JP2OpenJPEGDataset::GetGCPCount()
604 :
605 : {
606 3 : if( nGCPCount > 0 )
607 1 : return nGCPCount;
608 : else
609 2 : return GDALPamDataset::GetGCPCount();
610 : }
611 :
612 : /************************************************************************/
613 : /* GetGCPProjection() */
614 : /************************************************************************/
615 :
616 1 : const char *JP2OpenJPEGDataset::GetGCPProjection()
617 :
618 : {
619 1 : if( nGCPCount > 0 )
620 1 : return pszProjection;
621 : else
622 0 : return GDALPamDataset::GetGCPProjection();
623 : }
624 :
625 : /************************************************************************/
626 : /* GetGCP() */
627 : /************************************************************************/
628 :
629 1 : const GDAL_GCP *JP2OpenJPEGDataset::GetGCPs()
630 :
631 : {
632 1 : if( nGCPCount > 0 )
633 1 : return pasGCPList;
634 : else
635 0 : return GDALPamDataset::GetGCPs();
636 : }
637 :
638 : /************************************************************************/
639 : /* Identify() */
640 : /************************************************************************/
641 :
642 11003 : int JP2OpenJPEGDataset::Identify( GDALOpenInfo * poOpenInfo )
643 :
644 : {
645 : static const unsigned char jpc_header[] = {0xff,0x4f};
646 : static const unsigned char jp2_box_jp[] = {0x6a,0x50,0x20,0x20}; /* 'jP ' */
647 :
648 11003 : if( poOpenInfo->nHeaderBytes >= 16
649 : && (memcmp( poOpenInfo->pabyHeader, jpc_header,
650 : sizeof(jpc_header) ) == 0
651 : || memcmp( poOpenInfo->pabyHeader + 4, jp2_box_jp,
652 : sizeof(jp2_box_jp) ) == 0
653 : ) )
654 25 : return TRUE;
655 :
656 : else
657 10978 : return FALSE;
658 : }
659 : /************************************************************************/
660 : /* Open() */
661 : /************************************************************************/
662 :
663 1783 : GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
664 :
665 : {
666 1783 : if (!Identify(poOpenInfo))
667 1758 : return NULL;
668 :
669 25 : VSILFILE* fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
670 25 : if (!fp)
671 0 : return NULL;
672 :
673 : OPJ_CODEC_FORMAT eCodecFormat;
674 :
675 : /* Detect which codec to use : J2K or JP2 ? */
676 : static const unsigned char jpc_header[] = {0xff,0x4f};
677 25 : if (memcmp( poOpenInfo->pabyHeader, jpc_header,
678 : sizeof(jpc_header) ) == 0)
679 13 : eCodecFormat = CODEC_J2K;
680 : else
681 12 : eCodecFormat = CODEC_JP2;
682 :
683 25 : opj_codec_t* pCodec = opj_create_decompress(eCodecFormat);
684 :
685 25 : opj_set_info_handler(pCodec, JP2OpenJPEGDataset_InfoCallback,NULL);
686 25 : opj_set_warning_handler(pCodec, JP2OpenJPEGDataset_WarningCallback,NULL);
687 25 : opj_set_error_handler(pCodec, JP2OpenJPEGDataset_ErrorCallback,NULL);
688 :
689 : opj_dparameters_t parameters;
690 25 : opj_set_default_decoder_parameters(¶meters);
691 :
692 25 : if (! opj_setup_decoder(pCodec,¶meters))
693 : {
694 0 : VSIFCloseL(fp);
695 0 : return NULL;
696 : }
697 :
698 : opj_stream_t * pStream;
699 25 : pStream = opj_stream_create(1024, TRUE); // Default 1MB is way too big for some datasets
700 25 : opj_stream_set_read_function(pStream, JP2OpenJPEGDataset_Read);
701 25 : opj_stream_set_seek_function(pStream, JP2OpenJPEGDataset_Seek);
702 25 : opj_stream_set_skip_function(pStream, JP2OpenJPEGDataset_Skip);
703 25 : opj_stream_set_user_data(pStream, fp);
704 :
705 25 : opj_image_t * psImage = NULL;
706 : OPJ_INT32 nX0,nY0;
707 : OPJ_UINT32 nTileW,nTileH,nTilesX,nTilesY;
708 25 : if(!opj_read_header(pCodec, &psImage, &nX0, &nY0, &nTileW, &nTileH,
709 : &nTilesX, &nTilesY, pStream))
710 : {
711 0 : CPLError(CE_Failure, CPLE_AppDefined, "opj_read_header() failed");
712 0 : opj_destroy_codec(pCodec);
713 0 : opj_stream_destroy(pStream);
714 0 : opj_image_destroy(psImage);
715 0 : VSIFCloseL(fp);
716 0 : return NULL;
717 : }
718 :
719 25 : if (psImage == NULL)
720 : {
721 0 : opj_destroy_codec(pCodec);
722 0 : opj_stream_destroy(pStream);
723 0 : opj_image_destroy(psImage);
724 0 : VSIFCloseL(fp);
725 0 : return NULL;
726 : }
727 :
728 : #ifdef DEBUG
729 : int i;
730 25 : CPLDebug("OPENJPEG", "nX0 = %d", nX0);
731 25 : CPLDebug("OPENJPEG", "nY0 = %d", nY0);
732 25 : CPLDebug("OPENJPEG", "nTileW = %d", nTileW);
733 25 : CPLDebug("OPENJPEG", "nTileH = %d", nTileH);
734 25 : CPLDebug("OPENJPEG", "psImage->x0 = %d", psImage->x0);
735 25 : CPLDebug("OPENJPEG", "psImage->y0 = %d", psImage->y0);
736 25 : CPLDebug("OPENJPEG", "psImage->x1 = %d", psImage->x1);
737 25 : CPLDebug("OPENJPEG", "psImage->y1 = %d", psImage->y1);
738 25 : CPLDebug("OPENJPEG", "psImage->numcomps = %d", psImage->numcomps);
739 25 : CPLDebug("OPENJPEG", "psImage->color_space = %d", psImage->color_space);
740 67 : for(i=0;i<(int)psImage->numcomps;i++)
741 : {
742 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].dx = %d", i, psImage->comps[i].dx);
743 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].dy = %d", i, psImage->comps[i].dy);
744 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].x0 = %d", i, psImage->comps[i].x0);
745 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].y0 = %d", i, psImage->comps[i].y0);
746 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].w = %d", i, psImage->comps[i].w);
747 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].h = %d", i, psImage->comps[i].h);
748 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].factor = %d", i, psImage->comps[i].factor);
749 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].prec = %d", i, psImage->comps[i].prec);
750 42 : CPLDebug("OPENJPEG", "psImage->comps[%d].sgnd = %d", i, psImage->comps[i].sgnd);
751 : }
752 : #endif
753 :
754 75 : if (psImage->x1 - psImage->x0 <= 0 ||
755 : psImage->y1 - psImage->y0 <= 0 ||
756 : psImage->numcomps == 0 ||
757 25 : (int)psImage->comps[0].w != psImage->x1 - psImage->x0 ||
758 25 : (int)psImage->comps[0].h != psImage->y1 - psImage->y0)
759 : {
760 0 : opj_destroy_codec(pCodec);
761 0 : opj_stream_destroy(pStream);
762 0 : opj_image_destroy(psImage);
763 0 : VSIFCloseL(fp);
764 0 : return NULL;
765 : }
766 :
767 25 : GDALDataType eDataType = GDT_Byte;
768 25 : if (psImage->comps[0].prec > 16)
769 : {
770 0 : if (psImage->comps[0].sgnd)
771 0 : eDataType = GDT_Int32;
772 : else
773 0 : eDataType = GDT_UInt32;
774 : }
775 25 : else if (psImage->comps[0].prec > 8)
776 : {
777 8 : if (psImage->comps[0].sgnd)
778 5 : eDataType = GDT_Int16;
779 : else
780 3 : eDataType = GDT_UInt16;
781 : }
782 :
783 : int bIs420 = (psImage->color_space != CLRSPC_SRGB &&
784 : eDataType == GDT_Byte &&
785 : psImage->numcomps == 3 &&
786 14 : psImage->comps[1].w == psImage->comps[0].w / 2 &&
787 2 : psImage->comps[1].h == psImage->comps[0].h / 2 &&
788 2 : psImage->comps[2].w == psImage->comps[0].w / 2 &&
789 43 : psImage->comps[2].h == psImage->comps[0].h / 2);
790 :
791 25 : if (bIs420)
792 : {
793 1 : CPLDebug("OPENJPEG", "420 format");
794 : }
795 : else
796 : {
797 : int iBand;
798 38 : for(iBand = 2; iBand <= (int)psImage->numcomps; iBand ++)
799 : {
800 75 : if (psImage->comps[iBand-1].w != psImage->comps[0].w ||
801 30 : psImage->comps[iBand-1].h != psImage->comps[0].h ||
802 30 : psImage->comps[iBand-1].prec != psImage->comps[0].prec)
803 : {
804 1 : opj_destroy_codec(pCodec);
805 1 : opj_stream_destroy(pStream);
806 1 : opj_image_destroy(psImage);
807 1 : VSIFCloseL(fp);
808 1 : return NULL;
809 : }
810 : }
811 : }
812 :
813 :
814 : /* -------------------------------------------------------------------- */
815 : /* Create a corresponding GDALDataset. */
816 : /* -------------------------------------------------------------------- */
817 : JP2OpenJPEGDataset *poDS;
818 : int iBand;
819 :
820 24 : poDS = new JP2OpenJPEGDataset();
821 24 : poDS->eCodecFormat = eCodecFormat;
822 24 : poDS->eColorSpace = psImage->color_space;
823 24 : poDS->nRasterXSize = psImage->x1 - psImage->x0;
824 24 : poDS->nRasterYSize = psImage->y1 - psImage->y0;
825 24 : poDS->nBands = psImage->numcomps;
826 24 : poDS->fp = fp;
827 24 : poDS->bIs420 = bIs420;
828 :
829 24 : opj_end_decompress(pCodec,pStream);
830 24 : opj_stream_destroy(pStream);
831 24 : opj_destroy_codec(pCodec);
832 24 : opj_image_destroy(psImage);
833 :
834 : /* -------------------------------------------------------------------- */
835 : /* Create band information objects. */
836 : /* -------------------------------------------------------------------- */
837 124 : for( iBand = 1; iBand <= poDS->nBands; iBand++ )
838 : {
839 : poDS->SetBand( iBand, new JP2OpenJPEGRasterBand( poDS, iBand, eDataType,
840 38 : nTileW, nTileH) );
841 : }
842 :
843 : /* -------------------------------------------------------------------- */
844 : /* More metadata. */
845 : /* -------------------------------------------------------------------- */
846 24 : if( poDS->nBands > 1 )
847 : {
848 7 : poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
849 : }
850 :
851 : /* -------------------------------------------------------------------- */
852 : /* Check for georeferencing information. */
853 : /* -------------------------------------------------------------------- */
854 24 : GDALJP2Metadata oJP2Geo;
855 :
856 24 : if( oJP2Geo.ReadAndParse( poOpenInfo->pszFilename ) )
857 : {
858 10 : if ( poDS->pszProjection )
859 10 : CPLFree( poDS->pszProjection );
860 10 : poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
861 10 : poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
862 : memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
863 10 : sizeof(double) * 6 );
864 10 : poDS->nGCPCount = oJP2Geo.nGCPCount;
865 : poDS->pasGCPList =
866 10 : GDALDuplicateGCPs( oJP2Geo.nGCPCount, oJP2Geo.pasGCPList );
867 : }
868 :
869 24 : if (oJP2Geo.pszXMPMetadata)
870 : {
871 : char *apszMDList[2];
872 1 : apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
873 1 : apszMDList[1] = NULL;
874 1 : poDS->SetMetadata(apszMDList, "xml:XMP");
875 : }
876 : /* -------------------------------------------------------------------- */
877 : /* Initialize any PAM information. */
878 : /* -------------------------------------------------------------------- */
879 24 : poDS->SetDescription( poOpenInfo->pszFilename );
880 24 : poDS->TryLoadXML();
881 :
882 : /* -------------------------------------------------------------------- */
883 : /* Check for overviews. */
884 : /* -------------------------------------------------------------------- */
885 24 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
886 :
887 24 : return( poDS );
888 : }
889 :
890 : /************************************************************************/
891 : /* CreateCopy() */
892 : /************************************************************************/
893 :
894 20 : GDALDataset * JP2OpenJPEGDataset::CreateCopy( const char * pszFilename,
895 : GDALDataset *poSrcDS,
896 : int bStrict, char ** papszOptions,
897 : GDALProgressFunc pfnProgress,
898 : void * pProgressData )
899 :
900 : {
901 20 : int nBands = poSrcDS->GetRasterCount();
902 20 : int nXSize = poSrcDS->GetRasterXSize();
903 20 : int nYSize = poSrcDS->GetRasterYSize();
904 :
905 20 : if( nBands != 1 && nBands != 3 )
906 : {
907 : CPLError( CE_Failure, CPLE_NotSupported,
908 4 : "Unable to export files with %d bands.", nBands );
909 4 : return NULL;
910 : }
911 :
912 16 : if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
913 : {
914 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
915 : "JP2OpenJPEG driver ignores color table. "
916 : "The source raster band will be considered as grey level.\n"
917 0 : "Consider using color table expansion (-expand option in gdal_translate)\n");
918 0 : if (bStrict)
919 0 : return NULL;
920 : }
921 :
922 16 : GDALDataType eDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
923 16 : int nDataTypeSize = (GDALGetDataTypeSize(eDataType) / 8);
924 16 : if (eDataType != GDT_Byte && eDataType != GDT_Int16 && eDataType != GDT_UInt16
925 : && eDataType != GDT_Int32 && eDataType != GDT_UInt32)
926 : {
927 : CPLError( CE_Failure, CPLE_NotSupported,
928 6 : "JP2OpenJPEG driver only supports creating Byte, GDT_Int16, GDT_UInt16, GDT_Int32, GDT_UInt32");
929 6 : return NULL;
930 : }
931 :
932 : /* -------------------------------------------------------------------- */
933 : /* Analyze creation options. */
934 : /* -------------------------------------------------------------------- */
935 10 : OPJ_CODEC_FORMAT eCodecFormat = CODEC_J2K;
936 10 : const char* pszCodec = CSLFetchNameValueDef(papszOptions, "CODEC", NULL);
937 10 : if (pszCodec)
938 : {
939 0 : if (EQUAL(pszCodec, "JP2"))
940 0 : eCodecFormat = CODEC_JP2;
941 0 : else if (EQUAL(pszCodec, "J2K"))
942 0 : eCodecFormat = CODEC_J2K;
943 : else
944 : {
945 : CPLError(CE_Warning, CPLE_NotSupported,
946 : "Unsupported value for CODEC : %s. Defaulting to J2K",
947 0 : pszCodec);
948 : }
949 : }
950 : else
951 : {
952 10 : if (strlen(pszFilename) > 4 &&
953 : EQUAL(pszFilename + strlen(pszFilename) - 4, ".JP2"))
954 : {
955 0 : eCodecFormat = CODEC_JP2;
956 : }
957 : }
958 :
959 : int nBlockXSize =
960 10 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "1024"));
961 : int nBlockYSize =
962 10 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "1024"));
963 10 : if (nBlockXSize < 32 || nBlockYSize < 32)
964 : {
965 0 : CPLError(CE_Failure, CPLE_NotSupported, "Invalid block size");
966 0 : return NULL;
967 : }
968 :
969 10 : if (nXSize < nBlockXSize)
970 8 : nBlockXSize = nXSize;
971 10 : if (nYSize < nBlockYSize)
972 8 : nBlockYSize = nYSize;
973 :
974 10 : OPJ_PROG_ORDER eProgOrder = LRCP;
975 : const char* pszPROGORDER =
976 10 : CSLFetchNameValueDef(papszOptions, "PROGRESSION", "LRCP");
977 10 : if (EQUAL(pszPROGORDER, "LRCP"))
978 10 : eProgOrder = LRCP;
979 0 : else if (EQUAL(pszPROGORDER, "RLCP"))
980 0 : eProgOrder = RLCP;
981 0 : else if (EQUAL(pszPROGORDER, "RPCL"))
982 0 : eProgOrder = RPCL;
983 0 : else if (EQUAL(pszPROGORDER, "PCRL"))
984 0 : eProgOrder = PCRL;
985 0 : else if (EQUAL(pszPROGORDER, "CPRL"))
986 0 : eProgOrder = CPRL;
987 : else
988 : {
989 : CPLError(CE_Warning, CPLE_NotSupported,
990 : "Unsupported value for PROGRESSION : %s. Defaulting to LRCP",
991 0 : pszPROGORDER);
992 : }
993 :
994 : int bIsIrreversible =
995 10 : ! (CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "REVERSIBLE", "NO")));
996 :
997 10 : double dfRate = 100. / 25;
998 10 : const char* pszQuality = CSLFetchNameValueDef(papszOptions, "QUALITY", NULL);
999 10 : if (pszQuality)
1000 : {
1001 2 : double dfQuality = atof(pszQuality);
1002 4 : if (dfQuality > 0 && dfQuality <= 100)
1003 : {
1004 2 : dfRate = 100 / dfQuality;
1005 : }
1006 : else
1007 : {
1008 : CPLError(CE_Warning, CPLE_NotSupported,
1009 : "Unsupported value for QUALITY : %s. Defaulting to 25",
1010 0 : pszQuality);
1011 : }
1012 : }
1013 :
1014 10 : int nNumResolutions = 6;
1015 10 : const char* pszResolutions = CSLFetchNameValueDef(papszOptions, "RESOLUTIONS", NULL);
1016 10 : if (pszResolutions)
1017 : {
1018 1 : nNumResolutions = atoi(pszResolutions);
1019 1 : if (nNumResolutions < 1 || nNumResolutions > 7)
1020 : {
1021 0 : nNumResolutions = 6;
1022 : CPLError(CE_Warning, CPLE_NotSupported,
1023 : "Unsupported value for RESOLUTIONS : %s. Defaulting to 6",
1024 0 : pszResolutions);
1025 : }
1026 : }
1027 :
1028 10 : int bSOP = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SOP", "FALSE"));
1029 10 : int bEPH = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "EPH", "FALSE"));
1030 :
1031 : int bResample = nBands == 3 && eDataType == GDT_Byte &&
1032 10 : CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "YCBCR420", "FALSE"));
1033 10 : if (bResample && !((nXSize % 2) == 0 && (nYSize % 2) == 0 && (nBlockXSize % 2) == 0 && (nBlockYSize % 2) == 0))
1034 : {
1035 : CPLError(CE_Warning, CPLE_NotSupported,
1036 0 : "YCBCR420 unsupported when image size and/or tile size are not multiple of 2");
1037 0 : bResample = FALSE;
1038 : }
1039 :
1040 : /* -------------------------------------------------------------------- */
1041 : /* Setup encoder */
1042 : /* -------------------------------------------------------------------- */
1043 :
1044 : opj_cparameters_t parameters;
1045 10 : opj_set_default_encoder_parameters(¶meters);
1046 10 : if (bSOP)
1047 0 : parameters.csty |= 0x02;
1048 10 : if (bEPH)
1049 0 : parameters.csty |= 0x04;
1050 10 : parameters.cp_disto_alloc = 1;
1051 10 : parameters.tcp_numlayers = 1;
1052 10 : parameters.tcp_rates[0] = (float) dfRate;
1053 10 : parameters.cp_tx0 = 0;
1054 10 : parameters.cp_ty0 = 0;
1055 10 : parameters.tile_size_on = TRUE;
1056 10 : parameters.cp_tdx = nBlockXSize;
1057 10 : parameters.cp_tdy = nBlockYSize;
1058 10 : parameters.irreversible = bIsIrreversible;
1059 10 : parameters.numresolution = nNumResolutions;
1060 10 : parameters.prog_order = eProgOrder;
1061 :
1062 : opj_image_cmptparm_t* pasBandParams =
1063 10 : (opj_image_cmptparm_t*)CPLMalloc(nBands * sizeof(opj_image_cmptparm_t));
1064 : int iBand;
1065 22 : for(iBand=0;iBand<nBands;iBand++)
1066 : {
1067 12 : pasBandParams[iBand].x0 = 0;
1068 12 : pasBandParams[iBand].y0 = 0;
1069 12 : if (bResample && iBand > 0)
1070 : {
1071 0 : pasBandParams[iBand].dx = 2;
1072 0 : pasBandParams[iBand].dy = 2;
1073 0 : pasBandParams[iBand].w = nXSize / 2;
1074 0 : pasBandParams[iBand].h = nYSize / 2;
1075 : }
1076 : else
1077 : {
1078 12 : pasBandParams[iBand].dx = 1;
1079 12 : pasBandParams[iBand].dy = 1;
1080 12 : pasBandParams[iBand].w = nXSize;
1081 12 : pasBandParams[iBand].h = nYSize;
1082 : }
1083 12 : pasBandParams[iBand].sgnd = (eDataType == GDT_Int16 || eDataType == GDT_Int32);
1084 12 : pasBandParams[iBand].prec = 8 * nDataTypeSize;
1085 : }
1086 :
1087 10 : opj_codec_t* pCodec = opj_create_compress(eCodecFormat);
1088 10 : if (pCodec == NULL)
1089 : {
1090 : CPLError(CE_Failure, CPLE_AppDefined,
1091 0 : "opj_create_compress() failed");
1092 0 : CPLFree(pasBandParams);
1093 0 : return NULL;
1094 : }
1095 :
1096 10 : opj_set_info_handler(pCodec, JP2OpenJPEGDataset_InfoCallback,NULL);
1097 10 : opj_set_warning_handler(pCodec, JP2OpenJPEGDataset_WarningCallback,NULL);
1098 10 : opj_set_error_handler(pCodec, JP2OpenJPEGDataset_ErrorCallback,NULL);
1099 :
1100 10 : OPJ_COLOR_SPACE eColorSpace = (bResample) ? CLRSPC_SYCC : (nBands == 3) ? CLRSPC_SRGB : CLRSPC_GRAY;
1101 : opj_image_t* psImage = opj_image_tile_create(nBands,pasBandParams,
1102 10 : eColorSpace);
1103 10 : CPLFree(pasBandParams);
1104 10 : pasBandParams = NULL;
1105 10 : if (psImage == NULL)
1106 : {
1107 : CPLError(CE_Failure, CPLE_AppDefined,
1108 0 : "opj_image_tile_create() failed");
1109 0 : opj_destroy_codec(pCodec);
1110 0 : return NULL;
1111 : }
1112 :
1113 10 : psImage->x0 = 0;
1114 10 : psImage->y0 = 0;
1115 10 : psImage->x1 = nXSize;
1116 10 : psImage->y1 = nYSize;
1117 10 : psImage->color_space = eColorSpace;
1118 10 : psImage->numcomps = nBands;
1119 :
1120 10 : if (!opj_setup_encoder(pCodec,¶meters,psImage))
1121 : {
1122 : CPLError(CE_Failure, CPLE_AppDefined,
1123 0 : "opj_setup_encoder() failed");
1124 0 : opj_image_destroy(psImage);
1125 0 : opj_destroy_codec(pCodec);
1126 0 : return NULL;
1127 : }
1128 :
1129 : /* -------------------------------------------------------------------- */
1130 : /* Create the dataset. */
1131 : /* -------------------------------------------------------------------- */
1132 :
1133 10 : const char* pszAccess = EQUALN(pszFilename, "/vsisubfile/", 12) ? "r+b" : "w+b";
1134 10 : VSILFILE* fp = VSIFOpenL(pszFilename, pszAccess);
1135 10 : if (fp == NULL)
1136 : {
1137 2 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot create file");
1138 2 : opj_image_destroy(psImage);
1139 2 : opj_destroy_codec(pCodec);
1140 2 : return NULL;
1141 : }
1142 :
1143 : opj_stream_t * pStream;
1144 8 : pStream = opj_stream_create(1024*1024, FALSE);
1145 8 : opj_stream_set_write_function(pStream, JP2OpenJPEGDataset_Write);
1146 8 : opj_stream_set_seek_function(pStream, JP2OpenJPEGDataset_Seek);
1147 8 : opj_stream_set_skip_function(pStream, JP2OpenJPEGDataset_Skip);
1148 8 : opj_stream_set_user_data(pStream, fp);
1149 :
1150 8 : if (!opj_start_compress(pCodec,psImage,pStream))
1151 : {
1152 : CPLError(CE_Failure, CPLE_AppDefined,
1153 6 : "opj_start_compress() failed");
1154 6 : opj_stream_destroy(pStream);
1155 6 : opj_image_destroy(psImage);
1156 6 : opj_destroy_codec(pCodec);
1157 6 : VSIFCloseL(fp);
1158 6 : return NULL;
1159 : }
1160 :
1161 2 : int nTilesX = (nXSize + nBlockXSize - 1) / nBlockXSize;
1162 2 : int nTilesY = (nYSize + nBlockYSize - 1) / nBlockYSize;
1163 :
1164 : GByte* pTempBuffer =(GByte*)VSIMalloc(nBlockXSize * nBlockYSize *
1165 2 : nBands * nDataTypeSize);
1166 2 : if (pTempBuffer == NULL)
1167 : {
1168 0 : opj_stream_destroy(pStream);
1169 0 : opj_image_destroy(psImage);
1170 0 : opj_destroy_codec(pCodec);
1171 0 : VSIFCloseL(fp);
1172 0 : return NULL;
1173 : }
1174 :
1175 2 : GByte* pYUV420Buffer = NULL;
1176 2 : if (bResample)
1177 : {
1178 0 : pYUV420Buffer =(GByte*)VSIMalloc(3 * nBlockXSize * nBlockYSize / 2);
1179 0 : if (pYUV420Buffer == NULL)
1180 : {
1181 0 : opj_stream_destroy(pStream);
1182 0 : opj_image_destroy(psImage);
1183 0 : opj_destroy_codec(pCodec);
1184 0 : CPLFree(pTempBuffer);
1185 0 : VSIFCloseL(fp);
1186 0 : return NULL;
1187 : }
1188 : }
1189 :
1190 : /* -------------------------------------------------------------------- */
1191 : /* Iterate over the tiles */
1192 : /* -------------------------------------------------------------------- */
1193 2 : pfnProgress( 0.0, NULL, pProgressData );
1194 :
1195 2 : CPLErr eErr = CE_None;
1196 : int nBlockXOff, nBlockYOff;
1197 2 : int iTile = 0;
1198 4 : for(nBlockYOff=0;eErr == CE_None && nBlockYOff<nTilesY;nBlockYOff++)
1199 : {
1200 4 : for(nBlockXOff=0;eErr == CE_None && nBlockXOff<nTilesX;nBlockXOff++)
1201 : {
1202 2 : int nWidthToRead = MIN(nBlockXSize, nXSize - nBlockXOff * nBlockXSize);
1203 2 : int nHeightToRead = MIN(nBlockYSize, nYSize - nBlockYOff * nBlockYSize);
1204 : eErr = poSrcDS->RasterIO(GF_Read,
1205 : nBlockXOff * nBlockXSize,
1206 : nBlockYOff * nBlockYSize,
1207 : nWidthToRead, nHeightToRead,
1208 : pTempBuffer, nWidthToRead, nHeightToRead,
1209 : eDataType,
1210 : nBands, NULL,
1211 2 : 0,0,0);
1212 2 : if (eErr == CE_None)
1213 : {
1214 2 : if (bResample)
1215 : {
1216 : int j, i;
1217 0 : for(j=0;j<nHeightToRead;j++)
1218 : {
1219 0 : for(i=0;i<nWidthToRead;i++)
1220 : {
1221 0 : int R = pTempBuffer[j*nWidthToRead+i];
1222 0 : int G = pTempBuffer[nHeightToRead*nWidthToRead + j*nWidthToRead+i];
1223 0 : int B = pTempBuffer[2*nHeightToRead*nWidthToRead + j*nWidthToRead+i];
1224 0 : int Y = (int) (0.299 * R + 0.587 * G + 0.114 * B);
1225 0 : int Cb = CLAMP_0_255((int) (-0.1687 * R - 0.3313 * G + 0.5 * B + 128));
1226 0 : int Cr = CLAMP_0_255((int) (0.5 * R - 0.4187 * G - 0.0813 * B + 128));
1227 0 : pYUV420Buffer[j*nWidthToRead+i] = (GByte) Y;
1228 0 : pYUV420Buffer[nHeightToRead * nWidthToRead + ((j/2) * ((nWidthToRead)/2) + i/2) ] = (GByte) Cb;
1229 0 : pYUV420Buffer[5 * nHeightToRead * nWidthToRead / 4 + ((j/2) * ((nWidthToRead)/2) + i/2) ] = (GByte) Cr;
1230 : }
1231 : }
1232 :
1233 0 : if (!opj_write_tile(pCodec,
1234 : iTile,
1235 : pYUV420Buffer,
1236 : 3 * nWidthToRead * nHeightToRead / 2,
1237 : pStream))
1238 : {
1239 : CPLError(CE_Failure, CPLE_AppDefined,
1240 0 : "opj_write_tile() failed");
1241 0 : eErr = CE_Failure;
1242 : }
1243 : }
1244 : else
1245 : {
1246 2 : if (!opj_write_tile(pCodec,
1247 : iTile,
1248 : pTempBuffer,
1249 : nWidthToRead * nHeightToRead * nBands * nDataTypeSize,
1250 : pStream))
1251 : {
1252 : CPLError(CE_Failure, CPLE_AppDefined,
1253 0 : "opj_write_tile() failed");
1254 0 : eErr = CE_Failure;
1255 : }
1256 : }
1257 : }
1258 :
1259 2 : if( !pfnProgress( (iTile + 1) * 1.0 / (nTilesX * nTilesY), NULL, pProgressData ) )
1260 0 : eErr = CE_Failure;
1261 :
1262 2 : iTile ++;
1263 : }
1264 : }
1265 :
1266 2 : VSIFree(pTempBuffer);
1267 2 : VSIFree(pYUV420Buffer);
1268 :
1269 2 : if (eErr != CE_None)
1270 : {
1271 0 : opj_stream_destroy(pStream);
1272 0 : opj_image_destroy(psImage);
1273 0 : opj_destroy_codec(pCodec);
1274 0 : VSIFCloseL(fp);
1275 0 : return NULL;
1276 : }
1277 :
1278 2 : if (!opj_end_compress(pCodec,pStream))
1279 : {
1280 : CPLError(CE_Failure, CPLE_AppDefined,
1281 0 : "opj_end_compress() failed");
1282 0 : opj_stream_destroy(pStream);
1283 0 : opj_image_destroy(psImage);
1284 0 : opj_destroy_codec(pCodec);
1285 0 : VSIFCloseL(fp);
1286 0 : return NULL;
1287 : }
1288 :
1289 2 : opj_stream_destroy(pStream);
1290 2 : opj_image_destroy(psImage);
1291 2 : opj_destroy_codec(pCodec);
1292 2 : VSIFCloseL(fp);
1293 :
1294 : /* -------------------------------------------------------------------- */
1295 : /* Re-open dataset, and copy any auxilary pam information. */
1296 : /* -------------------------------------------------------------------- */
1297 2 : GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
1298 2 : JP2OpenJPEGDataset *poDS = (JP2OpenJPEGDataset*) JP2OpenJPEGDataset::Open(&oOpenInfo);
1299 :
1300 2 : if( poDS )
1301 2 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
1302 :
1303 2 : return poDS;
1304 : }
1305 :
1306 : /************************************************************************/
1307 : /* GDALRegister_JP2OpenJPEG() */
1308 : /************************************************************************/
1309 :
1310 558 : void GDALRegister_JP2OpenJPEG()
1311 :
1312 : {
1313 : GDALDriver *poDriver;
1314 :
1315 558 : if (! GDAL_CHECK_VERSION("JP2OpenJPEG driver"))
1316 0 : return;
1317 :
1318 558 : if( GDALGetDriverByName( "JP2OpenJPEG" ) == NULL )
1319 : {
1320 537 : poDriver = new GDALDriver();
1321 :
1322 537 : poDriver->SetDescription( "JP2OpenJPEG" );
1323 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1324 537 : "JPEG-2000 driver based on OpenJPEG library" );
1325 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1326 537 : "frmt_jp2openjpeg.html" );
1327 537 : poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/jp2" );
1328 537 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
1329 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1330 537 : "Byte Int16 UInt16 Int32 UInt32" );
1331 :
1332 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1333 : "<CreationOptionList>"
1334 : " <Option name='CODEC' type='string-select' default='according to file extension. If unknown, default to J2K'>"
1335 : " <Value>JP2</Value>"
1336 : " <Value>J2K</Value>"
1337 : " </Option>"
1338 : " <Option name='QUALITY' type='float' description='Quality. 0-100' default='25'/>"
1339 : " <Option name='REVERSIBLE' type='boolean' description='True if the compression is reversible' default='false'/>"
1340 : " <Option name='RESOLUTIONS' type='int' description='Number of resolutions. 1-7' default='6'/>"
1341 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width' default='1024'/>"
1342 : " <Option name='BLOCKYSIZE' type='int' description='Tile Height' default='1024'/>"
1343 : " <Option name='PROGRESSION' type='string-select' default='LRCP'>"
1344 : " <Value>LRCP</Value>"
1345 : " <Value>RLCP</Value>"
1346 : " <Value>RPCL</Value>"
1347 : " <Value>PCRL</Value>"
1348 : " <Value>CPRL</Value>"
1349 : " </Option>"
1350 : " <Option name='SOP' type='boolean' description='True to insert SOP markers' default='false'/>"
1351 : " <Option name='EPH' type='boolean' description='True to insert EPH markers' default='false'/>"
1352 : " <Option name='YCBCR420' type='boolean' description='if RGB must be resampled to YCbCr 4:2:0' default='false'/>"
1353 537 : "</CreationOptionList>" );
1354 :
1355 537 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1356 :
1357 537 : poDriver->pfnIdentify = JP2OpenJPEGDataset::Identify;
1358 537 : poDriver->pfnOpen = JP2OpenJPEGDataset::Open;
1359 537 : poDriver->pfnCreateCopy = JP2OpenJPEGDataset::CreateCopy;
1360 :
1361 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
1362 : }
1363 : }
1364 :
|