LTP GCOV extension - code coverage report
Current view: directory - frmts/openjpeg - openjpegdataset.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 557
Code covered: 70.0 % Executed lines: 390

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

Generated by: LTP GCOV extension version 1.5