1 /******************************************************************************
2  * Project:  GDAL
3  * Author:   Raul Alonso Reyes <raul dot alonsoreyes at satcen dot europa dot eu>
4  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
5  * Purpose:  JPEG-2000 driver based on Lurawave library, driver developed by SatCen
6  *
7  ******************************************************************************
8  * Copyright (c) 2016, SatCen - European Union Satellite Centre
9  * Copyright (c) 2016, Even Rouault
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #include "jp2lurarasterband.h"
31 #include "jp2luradataset.h"
32 
33 /************************************************************************/
34 /*                        JP2LuraRasterBand()                           */
35 /************************************************************************/
36 
JP2LuraRasterBand(JP2LuraDataset * poDSIn,int nBandIn,GDALDataType eDataTypeIn,int nBits,int nBlockXSizeIn,int nBlockYSizeIn)37 JP2LuraRasterBand::JP2LuraRasterBand(JP2LuraDataset *poDSIn, int nBandIn,
38                                      GDALDataType eDataTypeIn,
39                                      int nBits,
40                                      int nBlockXSizeIn, int nBlockYSizeIn)
41 
42 {
43     eDataType = eDataTypeIn;
44     nBlockXSize = nBlockXSizeIn;
45     nBlockYSize = nBlockYSizeIn;
46     poDS = poDSIn;
47     nRasterXSize = poDSIn->nRasterXSize;
48     nRasterYSize = poDSIn->nRasterYSize;
49     nBand = nBandIn;
50 
51     if (nRasterXSize == nBlockXSize && nRasterYSize == nBlockYSize)
52     {
53     /* -------------------------------------------------------------------- */
54     /*      Use a 2048x128 "virtual" block size unless the file is small.   */
55     /* -------------------------------------------------------------------- */
56         if (nRasterXSize >= 2048)
57         {
58             nBlockXSize = 2048;
59         }
60         else
61         {
62             nBlockXSize = nRasterXSize;
63         }
64 
65         if (nRasterYSize >= 128)
66         {
67             nBlockYSize = 128;
68         }
69         else
70         {
71             nBlockYSize = nRasterYSize;
72         }
73     }
74 
75     if( (nBits % 8) != 0 )
76     {
77         GDALRasterBand::SetMetadataItem("NBITS",
78                         CPLString().Printf("%d",nBits),
79                         "IMAGE_STRUCTURE" );
80     }
81     GDALRasterBand::SetMetadataItem("COMPRESSION", "JPEG2000",
82                     "IMAGE_STRUCTURE" );
83 
84     bForceCachedIO = FALSE;
85 }
86 
87 /************************************************************************/
88 /*                      ~JP2OpenJPEGRasterBand()                        */
89 /************************************************************************/
90 
~JP2LuraRasterBand()91 JP2LuraRasterBand::~JP2LuraRasterBand()
92 {
93 }
94 
95 /************************************************************************/
96 /*                             IReadBlock()                             */
97 /************************************************************************/
98 
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)99 CPLErr JP2LuraRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
100                                      void * pImage)
101 {
102     JP2LuraDataset *poGDS = reinterpret_cast<JP2LuraDataset *>(poDS);
103 #ifdef DEBUG_VERBOSE
104     CPLDebug("JP2Lura", "IReadBlock(nBand=%d,nLevel=%d %d,%d)",
105              nBand, poGDS->iLevel, nBlockXOff, nBlockYOff);
106 #endif
107     int nXOff = nBlockXOff * nBlockXSize;
108     int nYOff = nBlockYOff * nBlockYSize;
109     int nXSize = nBlockXSize;
110     int nYSize = nBlockYSize;
111     if( nXOff + nXSize > nRasterXSize )
112         nXSize = nRasterXSize - nXOff;
113     if( nYOff + nYSize > nRasterYSize )
114         nYSize = nRasterYSize - nYOff;
115     GDALRasterIOExtraArg sExtraArgs;
116     INIT_RASTERIO_EXTRA_ARG(sExtraArgs);
117     const int nDTSizeBytes = GDALGetDataTypeSizeBytes(eDataType);
118     CPLErr eErr = IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
119                             pImage, nXSize, nYSize,
120                             eDataType,
121                             nDTSizeBytes,
122                             nDTSizeBytes * nXSize,
123                             &sExtraArgs);
124 
125     // Unpack previously packed buffer if needed
126     if( eErr == CE_None && nXSize < nBlockXSize )
127     {
128         GByte* pabyData = reinterpret_cast<GByte*>(pImage);
129         for( int j = nYSize - 1; j >= 0; --j )
130         {
131             memmove( pabyData + j * nBlockXSize * nDTSizeBytes,
132                      pabyData + j * nXSize * nDTSizeBytes,
133                      nXSize * nDTSizeBytes );
134         }
135     }
136 
137     // Caching other bands while we have the cached buffer valid
138     for( int iBand = 1;eErr == CE_None && iBand <= poGDS->nBands; iBand++ )
139     {
140         if( iBand == nBand )
141             continue;
142         JP2LuraRasterBand* poOtherBand =
143             reinterpret_cast<JP2LuraRasterBand*>(poGDS->GetRasterBand(iBand));
144         GDALRasterBlock* poBlock = poOtherBand->
145                                 TryGetLockedBlockRef(nBlockXOff,nBlockYOff);
146         if (poBlock != nullptr)
147         {
148             poBlock->DropLock();
149             continue;
150         }
151 
152         poBlock = poOtherBand->
153                             GetLockedBlockRef(nBlockXOff,nBlockYOff, TRUE);
154         if (poBlock == nullptr)
155         {
156             continue;
157         }
158 
159         GByte* pabyData = reinterpret_cast<GByte*>(poBlock->GetDataRef());
160         eErr = poOtherBand->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
161                         pabyData, nXSize, nYSize,
162                         eDataType,
163                         nDTSizeBytes,
164                         nDTSizeBytes * nXSize,
165                         &sExtraArgs);
166 
167         // Unpack previously packed buffer if needed
168         if( eErr == CE_None && nXSize < nBlockXSize )
169         {
170             for( int j = nYSize - 1; j >= 0; --j )
171             {
172                 memmove( pabyData + j * nBlockXSize * nDTSizeBytes,
173                         pabyData + j * nXSize * nDTSizeBytes,
174                         nXSize * nDTSizeBytes );
175             }
176         }
177 
178         poBlock->DropLock();
179     }
180 
181     return eErr;
182 }
183 
184 /************************************************************************/
185 /*                             IRasterIO()                              */
186 /************************************************************************/
187 
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpace,GSpacing nLineSpace,GDALRasterIOExtraArg * psExtraArg)188 CPLErr JP2LuraRasterBand::IRasterIO(GDALRWFlag eRWFlag,
189                                     int nXOff, int nYOff, int nXSize, int nYSize,
190                                     void * pData, int nBufXSize, int nBufYSize,
191                                     GDALDataType eBufType,
192                                     GSpacing nPixelSpace, GSpacing nLineSpace,
193                                     GDALRasterIOExtraArg* psExtraArg)
194 {
195     JP2LuraDataset *poGDS = reinterpret_cast<JP2LuraDataset *>(poDS);
196     const int nBufTypeSize = GDALGetDataTypeSizeBytes(eBufType);
197 
198     if (eRWFlag != GF_Read)
199         return CE_Failure;
200 
201 #ifdef DEBUG_VERBOSE
202     CPLDebug("JP2Lura", "RasterIO(nBand=%d,nLevel=%d %d,%d,%dx%d -> %dx%d)",
203              nBand, poGDS->iLevel, nXOff, nYOff, nXSize, nYSize,
204              nBufXSize, nBufYSize);
205 #endif
206     if( eBufType != eDataType ||
207         nPixelSpace != nBufTypeSize ||
208         nLineSpace != nPixelSpace * nBufXSize )
209     {
210         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
211                                         pData, nBufXSize, nBufYSize, eBufType,
212                                         nPixelSpace, nLineSpace, psExtraArg);
213     }
214 
215     // Use cached data
216     if( poGDS->sOutputData.nXOff == nXOff &&
217         poGDS->sOutputData.nYOff == nYOff &&
218         poGDS->sOutputData.nXSize == nXSize &&
219         poGDS->sOutputData.nYSize == nYSize &&
220         poGDS->sOutputData.nBufXSize == nBufXSize &&
221         poGDS->sOutputData.nBufYSize == nBufYSize &&
222         poGDS->sOutputData.eBufType == eBufType )
223     {
224         if (poGDS->sOutputData.pDatacache[nBand - 1] != nullptr)
225         {
226 #ifdef DEBUG_VERBOSE
227             CPLDebug("JP2Lura", "Using cached data");
228 #endif
229             memcpy(pData, poGDS->sOutputData.pDatacache[nBand - 1],
230                    static_cast<size_t>(nBufXSize)*nBufYSize*nBufTypeSize);
231             return CE_None;
232         }
233     }
234 
235     /* ==================================================================== */
236     /*      Do we have overviews that would be appropriate to satisfy       */
237     /*      this request?                                                   */
238     /* ==================================================================== */
239     if ((nBufXSize < nXSize || nBufYSize < nYSize)
240             && GetOverviewCount() > 0 && eRWFlag == GF_Read)
241     {
242         int         nOverview;
243         GDALRasterIOExtraArg sExtraArg;
244 
245         GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
246 
247         nOverview = GDALBandGetBestOverviewLevel2(
248                                         this, nXOff, nYOff, nXSize, nYSize,
249                                         nBufXSize, nBufYSize, &sExtraArg);
250         if (nOverview >= 0)
251         {
252             GDALRasterBand* poOverviewBand = GetOverview(nOverview);
253             if (poOverviewBand == nullptr)
254                     return CE_Failure;
255 
256             return poOverviewBand->RasterIO(
257                                 eRWFlag, nXOff, nYOff, nXSize, nYSize,
258                                 pData, nBufXSize, nBufYSize, eBufType,
259                                 nPixelSpace, nLineSpace, &sExtraArg);
260         }
261     }
262 
263     if( nBufXSize != nXSize || nBufYSize != nYSize )
264     {
265         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
266                                         pData, nBufXSize, nBufYSize, eBufType,
267                                         nPixelSpace, nLineSpace, psExtraArg);
268     }
269 
270     JP2_Error error = 0;
271     const short factor = 1 << poGDS->iLevel;
272 
273     JP2_Rect comp_region;
274     comp_region.ulLeft = nXOff;
275     comp_region.ulRight = nXOff + nXSize;
276     comp_region.ulTop = nYOff;
277     comp_region.ulBottom = nYOff + nYSize;
278 
279     error = JP2_Decompress_SetProp(poGDS->sOutputData.handle,
280                                    cJP2_Prop_Scale_Down, factor);
281     if( error )
282     {
283         CPLError(CE_Failure, CPLE_AppDefined,
284                  "Internal library error (%s).",
285                  JP2LuraDataset::GetErrorMessage(error));
286         return CE_Failure;
287     }
288 
289     poGDS->sOutputData.pimage = reinterpret_cast<unsigned char*>(pData);
290 
291     poGDS->sOutputData.nXOff = nXOff;
292     poGDS->sOutputData.nYOff = nYOff;
293     poGDS->sOutputData.nXSize = nXSize;
294     poGDS->sOutputData.nYSize = nYSize;
295     poGDS->sOutputData.nBufXSize = nBufXSize;
296     poGDS->sOutputData.nBufYSize = nBufYSize;
297     poGDS->sOutputData.eBufType = eBufType;
298 
299     poGDS->sOutputData.nBand = nBand;
300     poGDS->sOutputData.nBands = poGDS->nBands;
301     if( poGDS->sOutputData.pDatacache == nullptr )
302     {
303         poGDS->sOutputData.pDatacache = reinterpret_cast<unsigned char**>
304                             (CPLCalloc( poGDS->nBands, sizeof(unsigned char*)));
305     }
306 
307     for (int i = 0; i < poGDS->nBands; i++)
308     {
309         if (poGDS->sOutputData.pDatacache[i] != nullptr)
310         {
311             VSIFree(poGDS->sOutputData.pDatacache[i]);
312             poGDS->sOutputData.pDatacache[i] = nullptr;
313         }
314         if (i == nBand-1)
315             continue;
316         poGDS->sOutputData.pDatacache[i] =
317             reinterpret_cast<unsigned char*>(VSIMalloc(
318                         static_cast<size_t>(nBufXSize)*nBufYSize*nBufTypeSize));
319     }
320 
321     /*++++++++++++++++++++++++++++++++++++++++++++++*/
322     /* Set the callback function and parameter      */
323     /*++++++++++++++++++++++++++++++++++++++++++++++*/
324 
325     error = JP2_Decompress_SetProp(poGDS->sOutputData.handle,
326                 cJP2_Prop_Output_Parameter,
327                 reinterpret_cast<JP2_Property_Value>(&(poGDS->sOutputData)));
328     if( error )
329     {
330         CPLError(CE_Failure, CPLE_AppDefined,
331                  "Internal library error (%s).",
332                  JP2LuraDataset::GetErrorMessage(error));
333         return CE_Failure;
334     }
335 
336     error = JP2_Decompress_SetProp(poGDS->sOutputData.handle,
337                     cJP2_Prop_Output_Function,
338                     reinterpret_cast<JP2_Property_Value>(
339                                     GDALJP2Lura_Callback_Decompress_Write));
340     if( error )
341     {
342         CPLError(CE_Failure, CPLE_AppDefined,
343                  "Internal library error (%s).",
344                  JP2LuraDataset::GetErrorMessage(error));
345         return CE_Failure;
346     }
347 
348     error = JP2_Decompress_Region(poGDS->sOutputData.handle, comp_region);
349     if( error )
350     {
351         CPLError(CE_Failure, CPLE_AppDefined,
352                  "Internal library error during decompress region (%s).",
353                  JP2LuraDataset::GetErrorMessage(error));
354         return CE_Failure;
355     }
356 
357     return CE_None;
358 }
359 
360 /************************************************************************/
361 /*                         GetOverviewCount()                           */
362 /************************************************************************/
363 
GetOverviewCount()364 int JP2LuraRasterBand::GetOverviewCount()
365 {
366     JP2LuraDataset *poGDS = reinterpret_cast<JP2LuraDataset *>(poDS);
367     return poGDS->nOverviewCount;
368 }
369 
370 /************************************************************************/
371 /*                            GetOverview()                             */
372 /************************************************************************/
373 
GetOverview(int iOvrLevel)374 GDALRasterBand* JP2LuraRasterBand::GetOverview(int iOvrLevel)
375 {
376     JP2LuraDataset *poGDS = reinterpret_cast<JP2LuraDataset *>(poDS);
377     if (iOvrLevel < 0 || iOvrLevel >= poGDS->nOverviewCount)
378         return nullptr;
379 
380     return poGDS->papoOverviewDS[iOvrLevel]->GetRasterBand(nBand);
381 }
382 
383 /************************************************************************/
384 /*                       GetColorInterpretation()                       */
385 /************************************************************************/
386 
GetColorInterpretation()387 GDALColorInterp JP2LuraRasterBand::GetColorInterpretation()
388 {
389     JP2LuraDataset *poGDS = reinterpret_cast<JP2LuraDataset *>(poDS);
390 
391     if( poGDS->poCT )
392         return GCI_PaletteIndex;
393 
394     if( nBand == poGDS->nAlphaIndex + 1 )
395         return GCI_AlphaBand;
396 
397     if (poGDS->nBands <= 2 && poGDS->eColorspace == cJP2_Colorspace_Gray)
398         return GCI_GrayIndex;
399     else if (poGDS->eColorspace == cJP2_Colorspace_RGBa)
400     {
401         if( nBand == poGDS->nRedIndex + 1 )
402             return GCI_RedBand;
403         if( nBand == poGDS->nGreenIndex + 1 )
404             return GCI_GreenBand;
405         if( nBand == poGDS->nBlueIndex + 1 )
406             return GCI_BlueBand;
407     }
408 
409     return GCI_Undefined;
410 }
411 
412 /************************************************************************/
413 /*                          GetColorTable()                             */
414 /************************************************************************/
415 
GetColorTable()416 GDALColorTable* JP2LuraRasterBand::GetColorTable()
417 {
418     JP2LuraDataset *poGDS = reinterpret_cast<JP2LuraDataset *>(poDS);
419     return poGDS->poCT;
420 }
421