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