1 : /******************************************************************************
2 : * $Id: epsilondataset.cpp 22363 2011-05-12 18:26:19Z rouault $
3 : *
4 : * Project: GDAL Epsilon driver
5 : * Purpose: Implement GDAL Epsilon support using Epsilon library
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2009, 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 : #include "epsilon.h"
31 : #include "gdal_pam.h"
32 :
33 : CPL_CVSID("$Id: epsilondataset.cpp 22363 2011-05-12 18:26:19Z rouault $");
34 :
35 : #define RASTERLITE_WAVELET_HEADER "StartWaveletsImage$$"
36 : #define RASTERLITE_WAVELET_FOOTER "$$EndWaveletsImage"
37 :
38 : #define BLOCK_DATA_MAX_SIZE MAX(EPS_MAX_GRAYSCALE_BUF, EPS_MAX_TRUECOLOR_BUF)
39 :
40 : class EpsilonRasterBand;
41 :
42 : typedef struct
43 : {
44 : int x;
45 : int y;
46 : int w;
47 : int h;
48 : vsi_l_offset offset;
49 : } BlockDesc;
50 :
51 : #ifdef I_WANT_COMPATIBILITY_WITH_EPSILON_0_8_1
52 : #define GET_FIELD(hdr, field) \
53 : (hdr.block_type == EPS_GRAYSCALE_BLOCK) ? hdr.gs.field : hdr.tc.field
54 : #else
55 : #define GET_FIELD(hdr, field) \
56 : (hdr.block_type == EPS_GRAYSCALE_BLOCK) ? hdr.hdr_data.gs.field : hdr.hdr_data.tc.field
57 : #endif
58 :
59 : /************************************************************************/
60 : /* ==================================================================== */
61 : /* EpsilonDataset */
62 : /* ==================================================================== */
63 : /************************************************************************/
64 :
65 : class EpsilonDataset : public GDALPamDataset
66 : {
67 : friend class EpsilonRasterBand;
68 :
69 : VSILFILE* fp;
70 : vsi_l_offset nFileOff;
71 :
72 : GByte* pabyFileBuf;
73 : int nFileBufMaxSize;
74 : int nFileBufCurSize;
75 : int nFileBufOffset;
76 : int bEOF;
77 : int bError;
78 :
79 : GByte* pabyBlockData;
80 : int nBlockDataSize;
81 : vsi_l_offset nStartBlockFileOff;
82 :
83 : int bRegularTiling;
84 :
85 : int nBlocks;
86 : BlockDesc* pasBlocks;
87 :
88 : int nBufferedBlock;
89 : GByte* pabyRGBData;
90 :
91 : void Seek(vsi_l_offset nPos);
92 : int GetNextByte();
93 : int GetNextBlockData();
94 : int ScanBlocks(int *pnBands);
95 :
96 : public:
97 : EpsilonDataset();
98 : virtual ~EpsilonDataset();
99 :
100 : static GDALDataset *Open( GDALOpenInfo * );
101 : static int Identify( GDALOpenInfo * );
102 : };
103 :
104 : /************************************************************************/
105 : /* ==================================================================== */
106 : /* EpsilonRasterBand */
107 : /* ==================================================================== */
108 : /************************************************************************/
109 :
110 : class EpsilonRasterBand : public GDALPamRasterBand
111 20 : {
112 : public:
113 : EpsilonRasterBand(EpsilonDataset* poDS, int nBand);
114 :
115 : virtual CPLErr IReadBlock( int, int, void * );
116 : virtual GDALColorInterp GetColorInterpretation();
117 : };
118 :
119 : /************************************************************************/
120 : /* EpsilonDataset() */
121 : /************************************************************************/
122 :
123 10 : EpsilonDataset::EpsilonDataset()
124 : {
125 10 : fp = NULL;
126 10 : nFileOff = 0;
127 :
128 10 : pabyFileBuf = NULL;
129 10 : nFileBufMaxSize = 0;
130 10 : nFileBufCurSize = 0;
131 10 : nFileBufOffset = 0;
132 10 : bEOF = FALSE;
133 10 : bError = FALSE;
134 :
135 10 : pabyBlockData = NULL;
136 10 : nBlockDataSize = 0;
137 10 : nStartBlockFileOff = 0;
138 :
139 10 : bRegularTiling = FALSE;
140 :
141 10 : nBlocks = 0;
142 10 : pasBlocks = NULL;
143 :
144 10 : nBufferedBlock = -1;
145 10 : pabyRGBData = NULL;
146 10 : }
147 :
148 : /************************************************************************/
149 : /* ~EpsilonDataset() */
150 : /************************************************************************/
151 :
152 10 : EpsilonDataset::~EpsilonDataset()
153 : {
154 10 : if (fp)
155 10 : VSIFCloseL(fp);
156 10 : VSIFree(pabyFileBuf);
157 10 : VSIFree(pasBlocks);
158 10 : CPLFree(pabyRGBData);
159 10 : }
160 :
161 : /************************************************************************/
162 : /* EpsilonRasterBand() */
163 : /************************************************************************/
164 :
165 20 : EpsilonRasterBand::EpsilonRasterBand(EpsilonDataset* poDS, int nBand)
166 : {
167 20 : this->poDS = poDS;
168 20 : this->nBand = nBand;
169 20 : this->eDataType = GDT_Byte;
170 20 : this->nBlockXSize = poDS->pasBlocks[0].w;
171 20 : this->nBlockYSize = poDS->pasBlocks[0].h;
172 20 : }
173 :
174 : /************************************************************************/
175 : /* GetColorInterpretation() */
176 : /************************************************************************/
177 :
178 0 : GDALColorInterp EpsilonRasterBand::GetColorInterpretation()
179 : {
180 0 : EpsilonDataset* poGDS = (EpsilonDataset*) poDS;
181 0 : if (poGDS->nBands == 1)
182 : {
183 0 : return GCI_GrayIndex;
184 : }
185 : else
186 : {
187 0 : if (nBand == 1)
188 0 : return GCI_RedBand;
189 0 : else if (nBand == 2)
190 0 : return GCI_GreenBand;
191 : else
192 0 : return GCI_BlueBand;
193 : }
194 : }
195 :
196 : /************************************************************************/
197 : /* IReadBlock() */
198 : /************************************************************************/
199 :
200 4 : CPLErr EpsilonRasterBand::IReadBlock( int nBlockXOff,
201 : int nBlockYOff, void * pImage)
202 : {
203 4 : EpsilonDataset* poGDS = (EpsilonDataset*) poDS;
204 :
205 : //CPLDebug("EPSILON", "IReadBlock(nBand=%d,nBlockXOff=%d,nBlockYOff=%d)",
206 : // nBand, nBlockXOff, nBlockYOff);
207 :
208 4 : int nBlocksPerRow = (poGDS->nRasterXSize + nBlockXSize - 1) / nBlockXSize;
209 4 : int nBlock = nBlockXOff + nBlockYOff * nBlocksPerRow;
210 :
211 4 : BlockDesc* psDesc = &poGDS->pasBlocks[nBlock];
212 : #ifdef DEBUG
213 4 : int nBlocksPerColumn = (poGDS->nRasterYSize + nBlockYSize - 1) / nBlockYSize;
214 4 : CPLAssert(psDesc->x == nBlockXOff * nBlockXSize);
215 4 : CPLAssert(psDesc->y == nBlockYOff * nBlockYSize);
216 : CPLAssert(psDesc->w == (nBlockXOff < nBlocksPerRow - 1) ?
217 4 : nBlockXSize : poGDS->nRasterXSize - psDesc->x);
218 : CPLAssert(psDesc->h == (nBlockYOff < nBlocksPerColumn - 1) ?
219 4 : nBlockYSize : poGDS->nRasterYSize - psDesc->y);
220 : #endif
221 :
222 4 : poGDS->Seek(psDesc->offset);
223 :
224 4 : if (!poGDS->GetNextBlockData())
225 : {
226 0 : memset(pImage, 0, nBlockXSize * nBlockYSize);
227 0 : return CE_Failure;
228 : }
229 :
230 : eps_block_header hdr;
231 4 : if (eps_read_block_header (poGDS->pabyBlockData,
232 : poGDS->nBlockDataSize, &hdr) != EPS_OK)
233 : {
234 0 : CPLError(CE_Warning, CPLE_AppDefined, "cannot read block header");
235 0 : memset(pImage, 0, nBlockXSize * nBlockYSize);
236 0 : return CE_Failure;
237 : }
238 :
239 4 : if (hdr.chk_flag == EPS_BAD_CRC ||
240 : hdr.crc_flag == EPS_BAD_CRC)
241 : {
242 0 : CPLError(CE_Warning, CPLE_AppDefined, "bad CRC");
243 0 : memset(pImage, 0, nBlockXSize * nBlockYSize);
244 0 : return CE_Failure;
245 : }
246 :
247 4 : int w = GET_FIELD(hdr, w);
248 4 : int h = GET_FIELD(hdr, h);
249 : int i;
250 :
251 4 : if (poGDS->nBands == 1)
252 : {
253 : unsigned char ** pTempData =
254 2 : (unsigned char **) CPLMalloc(h * sizeof(unsigned char*));
255 42 : for(i=0;i<h;i++)
256 40 : pTempData[i] = ((GByte*)pImage) + i * nBlockXSize;
257 :
258 2 : if (w != nBlockXSize || h != nBlockYSize)
259 0 : memset(pImage, 0, nBlockXSize * nBlockYSize);
260 :
261 2 : if (eps_decode_grayscale_block (pTempData,
262 : poGDS->pabyBlockData, &hdr) != EPS_OK)
263 : {
264 0 : CPLFree(pTempData);
265 0 : memset(pImage, 0, nBlockXSize * nBlockYSize);
266 0 : return CE_Failure;
267 : }
268 2 : CPLFree(pTempData);
269 : }
270 : else
271 : {
272 2 : if (poGDS->pabyRGBData == NULL)
273 : {
274 : poGDS->pabyRGBData =
275 2 : (GByte*) VSIMalloc3(nBlockXSize, nBlockYSize, 3);
276 2 : if (poGDS->pabyRGBData == NULL)
277 : {
278 0 : memset(pImage, 0, nBlockXSize * nBlockYSize);
279 0 : return CE_Failure;
280 : }
281 : }
282 :
283 2 : if (poGDS->nBufferedBlock == nBlock)
284 : {
285 : memcpy(pImage,
286 : poGDS->pabyRGBData + (nBand - 1) * nBlockXSize * nBlockYSize,
287 0 : nBlockXSize * nBlockYSize);
288 0 : return CE_None;
289 : }
290 :
291 : unsigned char ** pTempData[3];
292 : int iBand;
293 8 : for(iBand=0;iBand<3;iBand++)
294 : {
295 6 : pTempData[iBand] =
296 6 : (unsigned char **) CPLMalloc(h * sizeof(unsigned char*));
297 306 : for(i=0;i<h;i++)
298 300 : pTempData[iBand][i] = poGDS->pabyRGBData +
299 300 : iBand * nBlockXSize * nBlockYSize + i * nBlockXSize;
300 : }
301 :
302 2 : if (w != nBlockXSize || h != nBlockYSize)
303 0 : memset(poGDS->pabyRGBData, 0, 3 * nBlockXSize * nBlockYSize);
304 :
305 2 : if (eps_decode_truecolor_block (pTempData[0], pTempData[1], pTempData[2],
306 : poGDS->pabyBlockData, &hdr) != EPS_OK)
307 : {
308 0 : for(iBand=0;iBand<poGDS->nBands;iBand++)
309 0 : CPLFree(pTempData[iBand]);
310 0 : memset(pImage, 0, nBlockXSize * nBlockYSize);
311 0 : return CE_Failure;
312 : }
313 :
314 8 : for(iBand=0;iBand<poGDS->nBands;iBand++)
315 6 : CPLFree(pTempData[iBand]);
316 :
317 2 : poGDS->nBufferedBlock = nBlock;
318 : memcpy(pImage,
319 : poGDS->pabyRGBData + (nBand - 1) * nBlockXSize * nBlockYSize,
320 2 : nBlockXSize * nBlockYSize);
321 :
322 2 : if (nBand == 1)
323 : {
324 : int iOtherBand;
325 6 : for(iOtherBand=2;iOtherBand<=poGDS->nBands;iOtherBand++)
326 : {
327 : GDALRasterBlock *poBlock;
328 :
329 : poBlock = poGDS->GetRasterBand(iOtherBand)->
330 4 : GetLockedBlockRef(nBlockXOff,nBlockYOff, TRUE);
331 4 : if (poBlock == NULL)
332 0 : break;
333 :
334 4 : GByte* pabySrcBlock = (GByte *) poBlock->GetDataRef();
335 4 : if( pabySrcBlock == NULL )
336 : {
337 0 : poBlock->DropLock();
338 0 : break;
339 : }
340 :
341 : memcpy(pabySrcBlock,
342 : poGDS->pabyRGBData + (iOtherBand - 1) * nBlockXSize * nBlockYSize,
343 4 : nBlockXSize * nBlockYSize);
344 :
345 4 : poBlock->DropLock();
346 : }
347 : }
348 : }
349 :
350 4 : return CE_None;
351 : }
352 :
353 : /************************************************************************/
354 : /* Seek() */
355 : /************************************************************************/
356 :
357 34 : void EpsilonDataset::Seek(vsi_l_offset nPos)
358 : {
359 34 : bEOF = FALSE;
360 34 : VSIFSeekL(fp, nPos, SEEK_SET);
361 34 : nFileBufOffset = 0;
362 34 : nFileBufCurSize = 0;
363 34 : nFileOff = nPos;
364 34 : }
365 :
366 : /************************************************************************/
367 : /* GetNextByte() */
368 : /************************************************************************/
369 :
370 : #define BUFFER_CHUNK 16384
371 :
372 4333 : int EpsilonDataset::GetNextByte()
373 : {
374 4333 : if (nFileBufOffset < nFileBufCurSize)
375 : {
376 4299 : nFileOff ++;
377 4299 : return pabyFileBuf[nFileBufOffset ++];
378 : }
379 :
380 34 : if (bError || bEOF)
381 0 : return -1;
382 :
383 34 : if (nFileBufCurSize + BUFFER_CHUNK > nFileBufMaxSize)
384 : {
385 : GByte* pabyFileBufNew =
386 10 : (GByte*)VSIRealloc(pabyFileBuf, nFileBufCurSize + BUFFER_CHUNK);
387 10 : if (pabyFileBufNew == NULL)
388 : {
389 0 : bError = TRUE;
390 0 : return -1;
391 : }
392 10 : pabyFileBuf = pabyFileBufNew;
393 10 : nFileBufMaxSize = nFileBufCurSize + BUFFER_CHUNK;
394 : }
395 : int nBytesRead =
396 34 : (int)VSIFReadL(pabyFileBuf + nFileBufCurSize, 1, BUFFER_CHUNK, fp);
397 34 : nFileBufCurSize += nBytesRead;
398 34 : if (nBytesRead < BUFFER_CHUNK)
399 34 : bEOF = TRUE;
400 34 : if (nBytesRead == 0)
401 0 : return -1;
402 :
403 34 : nFileOff ++;
404 34 : return pabyFileBuf[nFileBufOffset ++];
405 : }
406 :
407 : /************************************************************************/
408 : /* GetNextBlockData() */
409 : /************************************************************************/
410 :
411 : #define MAX_SIZE_BEFORE_BLOCK_MARKER 100
412 :
413 34 : int EpsilonDataset::GetNextBlockData()
414 : {
415 34 : int nStartBlockBufOffset = 0;
416 34 : pabyBlockData = NULL;
417 34 : nBlockDataSize = 0;
418 :
419 88 : while (nFileBufOffset < MAX_SIZE_BEFORE_BLOCK_MARKER)
420 : {
421 54 : int chNextByte = GetNextByte();
422 54 : if (chNextByte < 0)
423 0 : return FALSE;
424 :
425 54 : if (chNextByte != EPS_MARKER)
426 : {
427 34 : nStartBlockFileOff = nFileOff - 1;
428 34 : nStartBlockBufOffset = nFileBufOffset - 1;
429 34 : nBlockDataSize = 1;
430 34 : break;
431 : }
432 : }
433 34 : if (nFileBufOffset == MAX_SIZE_BEFORE_BLOCK_MARKER)
434 0 : return FALSE;
435 :
436 4313 : while (nFileBufOffset < BLOCK_DATA_MAX_SIZE)
437 : {
438 4279 : int chNextByte = GetNextByte();
439 4279 : if (chNextByte < 0)
440 0 : break;
441 :
442 4279 : if (chNextByte == EPS_MARKER)
443 : {
444 34 : pabyBlockData = pabyFileBuf + nStartBlockBufOffset;
445 34 : return TRUE;
446 : }
447 :
448 4245 : nBlockDataSize ++;
449 : }
450 :
451 0 : pabyBlockData = pabyFileBuf + nStartBlockBufOffset;
452 0 : return TRUE;
453 : }
454 :
455 : /************************************************************************/
456 : /* ScanBlocks() */
457 : /************************************************************************/
458 :
459 10 : int EpsilonDataset::ScanBlocks(int* pnBands)
460 : {
461 10 : int bRet = FALSE;
462 :
463 10 : int nExpectedX = 0;
464 10 : int nExpectedY = 0;
465 :
466 10 : int nTileW = -1;
467 10 : int nTileH = -1;
468 :
469 10 : *pnBands = 0;
470 :
471 10 : bRegularTiling = TRUE;
472 :
473 : eps_block_header hdr;
474 20 : while(TRUE)
475 : {
476 30 : Seek(nStartBlockFileOff + nBlockDataSize);
477 :
478 30 : if (!GetNextBlockData())
479 : {
480 0 : break;
481 : }
482 :
483 : /* Ignore rasterlite wavelet header */
484 30 : int nRasterliteWaveletHeaderLen = strlen(RASTERLITE_WAVELET_HEADER);
485 30 : if (nBlockDataSize >= nRasterliteWaveletHeaderLen &&
486 : memcmp(pabyBlockData, RASTERLITE_WAVELET_HEADER,
487 : nRasterliteWaveletHeaderLen) == 0)
488 : {
489 10 : continue;
490 : }
491 :
492 : /* Stop at rasterlite wavelet footer */
493 20 : int nRasterlineWaveletFooterLen = strlen(RASTERLITE_WAVELET_FOOTER);
494 20 : if (nBlockDataSize >= nRasterlineWaveletFooterLen &&
495 : memcmp(pabyBlockData, RASTERLITE_WAVELET_FOOTER,
496 : nRasterlineWaveletFooterLen) == 0)
497 : {
498 10 : break;
499 : }
500 :
501 10 : if (eps_read_block_header (pabyBlockData,
502 : nBlockDataSize, &hdr) != EPS_OK)
503 : {
504 0 : CPLError(CE_Warning, CPLE_AppDefined, "cannot read block header");
505 0 : continue;
506 : }
507 :
508 10 : if (hdr.chk_flag == EPS_BAD_CRC ||
509 : hdr.crc_flag == EPS_BAD_CRC)
510 : {
511 0 : CPLError(CE_Warning, CPLE_AppDefined, "bad CRC");
512 0 : continue;
513 : }
514 :
515 10 : int W = GET_FIELD(hdr, W);
516 10 : int H = GET_FIELD(hdr, H);
517 10 : int x = GET_FIELD(hdr, x);
518 10 : int y = GET_FIELD(hdr, y);
519 10 : int w = GET_FIELD(hdr, w);
520 10 : int h = GET_FIELD(hdr, h);
521 :
522 : //CPLDebug("EPSILON", "W=%d,H=%d,x=%d,y=%d,w=%d,h=%d,offset=" CPL_FRMT_GUIB,
523 : // W, H, x, y, w, h, nStartBlockFileOff);
524 :
525 10 : int nNewBands = (hdr.block_type == EPS_GRAYSCALE_BLOCK) ? 1 : 3;
526 10 : if (nRasterXSize == 0)
527 : {
528 10 : if (W <= 0 || H <= 0)
529 : {
530 0 : break;
531 : }
532 :
533 10 : bRet = TRUE;
534 10 : nRasterXSize = W;
535 10 : nRasterYSize = H;
536 10 : *pnBands = nNewBands;
537 : }
538 :
539 10 : if (nRasterXSize != W || nRasterYSize != H || *pnBands != nNewBands ||
540 : x < 0 || y < 0 || x + w > W || y + h > H)
541 : {
542 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad block characteristics");
543 0 : bRet = FALSE;
544 0 : break;
545 : }
546 :
547 10 : nBlocks++;
548 10 : pasBlocks = (BlockDesc*)VSIRealloc(pasBlocks, sizeof(BlockDesc) * nBlocks);
549 10 : pasBlocks[nBlocks-1].x = x;
550 10 : pasBlocks[nBlocks-1].y = y;
551 10 : pasBlocks[nBlocks-1].w = w;
552 10 : pasBlocks[nBlocks-1].h = h;
553 10 : pasBlocks[nBlocks-1].offset = nStartBlockFileOff;
554 :
555 10 : if (bRegularTiling)
556 : {
557 10 : if (nTileW < 0)
558 : {
559 10 : nTileW = w;
560 10 : nTileH = h;
561 : }
562 :
563 10 : if (w > nTileW || h > nTileH)
564 0 : bRegularTiling = FALSE;
565 :
566 10 : if (x != nExpectedX)
567 0 : bRegularTiling = FALSE;
568 :
569 10 : if (y != nExpectedY || nTileH != h)
570 : {
571 0 : if (y + h != H)
572 0 : bRegularTiling = FALSE;
573 : }
574 :
575 10 : if (nTileW != w)
576 : {
577 0 : if (x + w != W)
578 0 : bRegularTiling = FALSE;
579 : else
580 : {
581 0 : nExpectedX = 0;
582 0 : nExpectedY += nTileW;
583 : }
584 : }
585 : else
586 10 : nExpectedX += nTileW;
587 :
588 : //if (!bRegularTiling)
589 : // CPLDebug("EPSILON", "not regular tiling!");
590 : }
591 : }
592 :
593 10 : return bRet;
594 : }
595 :
596 : /************************************************************************/
597 : /* Identify() */
598 : /************************************************************************/
599 :
600 11746 : int EpsilonDataset::Identify(GDALOpenInfo* poOpenInfo)
601 : {
602 11746 : int nRasterliteWaveletHeaderLen = strlen(RASTERLITE_WAVELET_HEADER);
603 11746 : if (poOpenInfo->nHeaderBytes > nRasterliteWaveletHeaderLen + 1 &&
604 : EQUALN((const char*)poOpenInfo->pabyHeader,
605 : RASTERLITE_WAVELET_HEADER, nRasterliteWaveletHeaderLen))
606 : {
607 10 : return TRUE;
608 : }
609 :
610 11736 : if (poOpenInfo->nHeaderBytes > EPS_MIN_GRAYSCALE_BUF &&
611 : (EQUALN((const char*)poOpenInfo->pabyHeader, "type=gs", 7) ||
612 : EQUALN((const char*)poOpenInfo->pabyHeader, "type=tc", 7)))
613 : {
614 0 : return TRUE;
615 : }
616 :
617 11736 : return FALSE;
618 : }
619 :
620 : /************************************************************************/
621 : /* Open() */
622 : /************************************************************************/
623 :
624 1656 : GDALDataset* EpsilonDataset::Open(GDALOpenInfo* poOpenInfo)
625 : {
626 1656 : if (!Identify(poOpenInfo))
627 1646 : return NULL;
628 :
629 10 : if( poOpenInfo->eAccess == GA_Update )
630 : {
631 : CPLError( CE_Failure, CPLE_NotSupported,
632 : "The EPSILON driver does not support update access to existing"
633 0 : " files.\n" );
634 0 : return NULL;
635 : }
636 :
637 10 : VSILFILE* fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
638 10 : if (fp == NULL)
639 0 : return NULL;
640 :
641 10 : EpsilonDataset* poDS = new EpsilonDataset();
642 10 : poDS->fp = fp;
643 :
644 10 : poDS->nRasterXSize = 0;
645 10 : poDS->nRasterYSize = 0;
646 :
647 10 : int nBandsToAdd = 0;
648 10 : if (!poDS->ScanBlocks(&nBandsToAdd))
649 : {
650 0 : delete poDS;
651 0 : return NULL;
652 : }
653 :
654 10 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
655 : !GDALCheckBandCount(nBandsToAdd, FALSE))
656 : {
657 0 : delete poDS;
658 0 : return NULL;
659 : }
660 10 : if (!poDS->bRegularTiling)
661 : {
662 : CPLError( CE_Failure, CPLE_NotSupported,
663 : "The EPSILON driver does not support reading "
664 0 : "not regularly blocked files.\n" );
665 0 : delete poDS;
666 0 : return NULL;
667 : }
668 :
669 : int i;
670 60 : for(i=1;i<=nBandsToAdd;i++)
671 20 : poDS->SetBand(i, new EpsilonRasterBand(poDS, i));
672 :
673 10 : if (nBandsToAdd > 1)
674 5 : poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
675 :
676 10 : return poDS;
677 : }
678 :
679 :
680 : /************************************************************************/
681 : /* EpsilonDatasetCreateCopy () */
682 : /************************************************************************/
683 :
684 : GDALDataset *
685 20 : EpsilonDatasetCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
686 : int bStrict, char ** papszOptions,
687 : GDALProgressFunc pfnProgress, void * pProgressData )
688 : {
689 20 : int nBands = poSrcDS->GetRasterCount();
690 36 : if ((nBands != 1 && nBands != 3) ||
691 16 : (nBands > 0 && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL))
692 : {
693 : CPLError(CE_Failure, CPLE_NotSupported,
694 : "The EPSILON driver only supports 1 band (grayscale) "
695 4 : "or 3 band (RGB) data");
696 4 : return NULL;
697 : }
698 :
699 : /* -------------------------------------------------------------------- */
700 : /* Fetch and check creation options */
701 : /* -------------------------------------------------------------------- */
702 :
703 : int nBlockXSize =
704 16 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "256"));
705 : int nBlockYSize =
706 16 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "256"));
707 16 : if ((nBlockXSize != 32 && nBlockXSize != 64 && nBlockXSize != 128 &&
708 : nBlockXSize != 256 && nBlockXSize != 512 && nBlockXSize != 1024) ||
709 : (nBlockYSize != 32 && nBlockYSize != 64 && nBlockYSize != 128 &&
710 : nBlockYSize != 256 && nBlockYSize != 512 && nBlockYSize != 1024))
711 : {
712 : CPLError(CE_Failure, CPLE_NotSupported,
713 0 : "Block size must be a power of 2 between 32 et 1024");
714 0 : return NULL;
715 : }
716 :
717 : const char* pszFilter =
718 16 : CSLFetchNameValueDef(papszOptions, "FILTER", "daub97lift");
719 16 : char** papszFBID = eps_get_fb_info(EPS_FB_ID);
720 16 : char** papszFBIDIter = papszFBID;
721 16 : int bFound = FALSE;
722 16 : int nIndexFB = 0;
723 464 : while(papszFBIDIter && *papszFBIDIter && !bFound)
724 : {
725 432 : if (strcmp(*papszFBIDIter, pszFilter) == 0)
726 16 : bFound = TRUE;
727 : else
728 416 : nIndexFB ++;
729 432 : papszFBIDIter ++;
730 : }
731 16 : eps_free_fb_info(papszFBID);
732 16 : if (!bFound)
733 : {
734 : CPLError(CE_Failure, CPLE_NotSupported, "FILTER='%s' not supported",
735 0 : pszFilter);
736 0 : return NULL;
737 : }
738 :
739 16 : int eMode = EPS_MODE_OTLPF;
740 16 : const char* pszMode = CSLFetchNameValueDef(papszOptions, "MODE", "OTLPF");
741 16 : if (EQUAL(pszMode, "NORMAL"))
742 0 : eMode = EPS_MODE_NORMAL;
743 16 : else if (EQUAL(pszMode, "OTLPF"))
744 16 : eMode = EPS_MODE_OTLPF;
745 : else
746 : {
747 : CPLError(CE_Failure, CPLE_NotSupported, "MODE='%s' not supported",
748 0 : pszMode);
749 0 : return NULL;
750 : }
751 :
752 16 : char** papszFBType = eps_get_fb_info(EPS_FB_TYPE);
753 16 : int bIsBiOrthogonal = EQUAL(papszFBType[nIndexFB], "biorthogonal");
754 16 : eps_free_fb_info(papszFBType);
755 :
756 16 : if (eMode == EPS_MODE_OTLPF && !bIsBiOrthogonal)
757 : {
758 : CPLError(CE_Failure, CPLE_NotSupported,
759 : "MODE=OTLPF can only be used with biorthogonal filters. "
760 0 : "Use MODE=NORMAL instead");
761 0 : return NULL;
762 : }
763 :
764 : int bRasterliteOutput =
765 : CSLTestBoolean(CSLFetchNameValueDef(papszOptions,
766 16 : "RASTERLITE_OUTPUT", "NO"));
767 :
768 16 : int nYRatio = EPS_Y_RT;
769 16 : int nCbRatio = EPS_Cb_RT;
770 16 : int nCrRatio = EPS_Cr_RT;
771 :
772 : int eResample;
773 16 : if (CSLTestBoolean(CSLFetchNameValueDef(papszOptions,
774 : "RGB_RESAMPLE", "YES")))
775 16 : eResample = EPS_RESAMPLE_420;
776 : else
777 0 : eResample = EPS_RESAMPLE_444;
778 :
779 16 : const char* pszTarget = CSLFetchNameValueDef(papszOptions, "TARGET", "96");
780 16 : double dfReductionFactor = 1 - atof(pszTarget) / 100;
781 16 : if (dfReductionFactor > 1)
782 0 : dfReductionFactor = 1;
783 16 : else if (dfReductionFactor < 0)
784 0 : dfReductionFactor = 0;
785 :
786 : /* -------------------------------------------------------------------- */
787 : /* Open file */
788 : /* -------------------------------------------------------------------- */
789 :
790 16 : VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
791 16 : if (fp == NULL)
792 2 : return NULL;
793 :
794 : /* -------------------------------------------------------------------- */
795 : /* Compute number of blocks, block size, etc... */
796 : /* -------------------------------------------------------------------- */
797 :
798 14 : int nXSize = poSrcDS->GetRasterXSize();
799 14 : int nYSize = poSrcDS->GetRasterYSize();
800 14 : if (eMode == EPS_MODE_OTLPF)
801 : {
802 14 : nBlockXSize ++;
803 14 : nBlockYSize ++;
804 : }
805 14 : int nXBlocks = (nXSize + nBlockXSize - 1) / nBlockXSize;
806 14 : int nYBlocks = (nYSize + nBlockYSize - 1) / nBlockYSize;
807 14 : int nBlocks = nXBlocks * nYBlocks;
808 14 : int nUncompressedFileSize = nXSize * nYSize * nBands;
809 14 : int nUncompressedBlockSize = nUncompressedFileSize / nBlocks;
810 14 : int nTargetBlockSize = (int) (dfReductionFactor * nUncompressedBlockSize);
811 14 : if (nBands == 1)
812 12 : nTargetBlockSize = MAX (nTargetBlockSize, EPS_MIN_GRAYSCALE_BUF + 1);
813 : else
814 2 : nTargetBlockSize = MAX (nTargetBlockSize, EPS_MIN_TRUECOLOR_BUF + 1);
815 :
816 : /* -------------------------------------------------------------------- */
817 : /* Allocate work buffers */
818 : /* -------------------------------------------------------------------- */
819 :
820 14 : GByte* pabyBuffer = (GByte*)VSIMalloc3(nBlockXSize, nBlockYSize, nBands);
821 14 : if (pabyBuffer == NULL)
822 : {
823 0 : VSIFCloseL(fp);
824 0 : return NULL;
825 : }
826 :
827 14 : GByte* pabyOutBuf = (GByte*)VSIMalloc(nTargetBlockSize);
828 14 : if (pabyOutBuf == NULL)
829 : {
830 0 : VSIFree(pabyBuffer);
831 0 : VSIFCloseL(fp);
832 0 : return NULL;
833 : }
834 :
835 : GByte** apapbyRawBuffer[3];
836 : int i, j;
837 32 : for(i=0;i<nBands;i++)
838 : {
839 18 : apapbyRawBuffer[i] = (GByte**) VSIMalloc(sizeof(GByte*) * nBlockYSize);
840 4644 : for(j=0;j<nBlockYSize;j++)
841 : {
842 4626 : apapbyRawBuffer[i][j] =
843 4626 : pabyBuffer + (i * nBlockXSize + j) * nBlockYSize;
844 : }
845 : }
846 :
847 14 : if (bRasterliteOutput)
848 : {
849 2 : const char* pszHeader = RASTERLITE_WAVELET_HEADER;
850 2 : VSIFWriteL(pszHeader, 1, strlen(pszHeader) + 1, fp);
851 : }
852 :
853 : /* -------------------------------------------------------------------- */
854 : /* Iterate over blocks */
855 : /* -------------------------------------------------------------------- */
856 :
857 : int nBlockXOff, nBlockYOff;
858 14 : CPLErr eErr = CE_None;
859 28 : for(nBlockYOff = 0;
860 : eErr == CE_None && nBlockYOff < nYBlocks; nBlockYOff ++)
861 : {
862 28 : for(nBlockXOff = 0;
863 : eErr == CE_None && nBlockXOff < nXBlocks; nBlockXOff ++)
864 : {
865 14 : int bMustMemset = FALSE;
866 14 : int nReqXSize = nBlockXSize, nReqYSize = nBlockYSize;
867 14 : if ((nBlockXOff+1) * nBlockXSize > nXSize)
868 : {
869 14 : bMustMemset = TRUE;
870 14 : nReqXSize = nXSize - nBlockXOff * nBlockXSize;
871 : }
872 14 : if ((nBlockYOff+1) * nBlockYSize > nYSize)
873 : {
874 14 : bMustMemset = TRUE;
875 14 : nReqYSize = nYSize - nBlockYOff * nBlockYSize;
876 : }
877 14 : if (bMustMemset)
878 14 : memset(pabyBuffer, 0, nBands * nBlockXSize * nBlockYSize);
879 :
880 : eErr = poSrcDS->RasterIO(GF_Read,
881 : nBlockXOff * nBlockXSize,
882 : nBlockYOff * nBlockYSize,
883 : nReqXSize, nReqYSize,
884 : pabyBuffer,
885 : nReqXSize, nReqYSize,
886 : GDT_Byte, nBands, NULL,
887 : 1,
888 : nBlockXSize,
889 14 : nBlockXSize * nBlockYSize);
890 :
891 14 : int nOutBufSize = nTargetBlockSize;
892 26 : if (eErr == CE_None && nBands == 1)
893 : {
894 12 : if (EPS_OK != eps_encode_grayscale_block(apapbyRawBuffer[0],
895 : nXSize, nYSize,
896 : nReqXSize, nReqYSize,
897 : nBlockXOff * nBlockXSize,
898 : nBlockYOff * nBlockYSize,
899 : pabyOutBuf, &nOutBufSize,
900 : (char*) pszFilter, eMode))
901 : {
902 : CPLError(CE_Failure, CPLE_AppDefined,
903 : "Error occured when encoding block (%d, %d)",
904 0 : nBlockXOff, nBlockYOff);
905 0 : eErr = CE_Failure;
906 : }
907 : }
908 2 : else if (eErr == CE_None)
909 : {
910 2 : if (EPS_OK != eps_encode_truecolor_block(
911 : apapbyRawBuffer[0],
912 : apapbyRawBuffer[1],
913 : apapbyRawBuffer[2],
914 : nXSize, nYSize,
915 : nReqXSize, nReqYSize,
916 : nBlockXOff * nBlockXSize,
917 : nBlockYOff * nBlockYSize,
918 : eResample,
919 : pabyOutBuf, &nOutBufSize,
920 : nYRatio, nCbRatio, nCrRatio,
921 : (char*) pszFilter, eMode))
922 : {
923 : CPLError(CE_Failure, CPLE_AppDefined,
924 : "Error occured when encoding block (%d, %d)",
925 0 : nBlockXOff, nBlockYOff);
926 0 : eErr = CE_Failure;
927 : }
928 : }
929 :
930 14 : if (eErr == CE_None)
931 : {
932 14 : if ((int)VSIFWriteL(pabyOutBuf, 1, nOutBufSize, fp) !=
933 : nOutBufSize)
934 0 : eErr = CE_Failure;
935 :
936 14 : char chEPSMarker = EPS_MARKER;
937 14 : VSIFWriteL(&chEPSMarker, 1, 1, fp);
938 :
939 14 : if (pfnProgress && !pfnProgress(
940 : 1.0 * (nBlockYOff * nXBlocks + nBlockXOff + 1) / nBlocks,
941 : NULL, pProgressData))
942 : {
943 0 : eErr = CE_Failure;
944 : }
945 : }
946 : }
947 : }
948 :
949 14 : if (bRasterliteOutput)
950 : {
951 2 : const char* pszFooter = RASTERLITE_WAVELET_FOOTER;
952 2 : VSIFWriteL(pszFooter, 1, strlen(pszFooter) + 1, fp);
953 : }
954 :
955 : /* -------------------------------------------------------------------- */
956 : /* Cleanup work buffers */
957 : /* -------------------------------------------------------------------- */
958 :
959 32 : for(i=0;i<nBands;i++)
960 : {
961 18 : VSIFree(apapbyRawBuffer[i]);
962 : }
963 :
964 14 : VSIFree(pabyOutBuf);
965 14 : VSIFree(pabyBuffer);
966 :
967 14 : VSIFCloseL(fp);
968 :
969 14 : if (eErr != CE_None)
970 0 : return NULL;
971 :
972 : /* -------------------------------------------------------------------- */
973 : /* Reopen the dataset, unless asked for not (Rasterlite optim) */
974 : /* -------------------------------------------------------------------- */
975 14 : return (GDALDataset*) GDALOpen(pszFilename, GA_ReadOnly);
976 : }
977 :
978 : /************************************************************************/
979 : /* GDALRegister_EPSILON() */
980 : /************************************************************************/
981 :
982 582 : void GDALRegister_EPSILON()
983 :
984 : {
985 : GDALDriver *poDriver;
986 :
987 582 : if (! GDAL_CHECK_VERSION("EPSILON driver"))
988 0 : return;
989 :
990 582 : if( GDALGetDriverByName( "EPSILON" ) == NULL )
991 : {
992 561 : poDriver = new GDALDriver();
993 :
994 561 : poDriver->SetDescription( "EPSILON" );
995 :
996 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
997 561 : "Epsilon wavelets" );
998 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
999 561 : "frmt_epsilon.html" );
1000 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1001 561 : "Byte" );
1002 :
1003 561 : CPLString osMethods;
1004 1122 : char** papszFBID = eps_get_fb_info(EPS_FB_ID);
1005 561 : char** papszFBIDIter = papszFBID;
1006 19074 : while(papszFBIDIter && *papszFBIDIter)
1007 : {
1008 17952 : osMethods += " <Value>";
1009 17952 : osMethods += *papszFBIDIter;
1010 17952 : osMethods += "</Value>\n";
1011 17952 : papszFBIDIter ++;
1012 : }
1013 561 : eps_free_fb_info(papszFBID);
1014 :
1015 561 : CPLString osOptionList;
1016 : osOptionList.Printf(
1017 : "<CreationOptionList>"
1018 : " <Option name='TARGET' type='int' description='target size reduction as a percentage of the original (0-100)' default='75'/>"
1019 : " <Option name='FILTER' type='string-select' description='Filter ID' default='daub97lift'>"
1020 : "%s"
1021 : " </Option>"
1022 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width. Between 32 and 1024' default='256'/>"
1023 : " <Option name='BLOCKYSIZE' type='int' description='Tile Height. Between 32 and 1024' default='256'/>"
1024 : " <Option name='MODE' type='string-select' default='OTLPF'>"
1025 : " <Value>NORMAL</Value>"
1026 : " <Value>OTLPF</Value>"
1027 : " </Option>"
1028 : " <Option name='RGB_RESAMPLE' type='boolean' description='if RGB must be resampled to 4:2:0' default='YES'/>"
1029 : " <Option name='RASTERLITE_OUTPUT' type='boolean' description='if Rasterlite header and footers must be inserted' default='FALSE'/>"
1030 561 : "</CreationOptionList>", osMethods.c_str() );
1031 :
1032 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1033 561 : osOptionList.c_str() );
1034 :
1035 561 : poDriver->pfnOpen = EpsilonDataset::Open;
1036 561 : poDriver->pfnIdentify = EpsilonDataset::Identify;
1037 561 : poDriver->pfnCreateCopy = EpsilonDatasetCreateCopy;
1038 :
1039 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1040 :
1041 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
1042 : }
1043 : }
|