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