1 /******************************************************************************
2 * $Id: fitdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
3 *
4 * Project: FIT Driver
5 * Purpose: Implement FIT Support - not using the SGI iflFIT library.
6 * Author: Philip Nemec, nemec@keyholecorp.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2001, Keyhole, Inc.
10 * Copyright (c) 2007-2011, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "fit.h"
32 #include "gstEndian.h"
33 #include "gdal_pam.h"
34 #include "cpl_string.h"
35
36 CPL_CVSID("$Id: fitdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
37
38 CPL_C_START
39
40 void GDALRegister_FIT(void);
41 CPL_C_END
42
43 #define FIT_WRITE
44
45 #define FIT_PAGE_SIZE 128
46
47 using namespace gstEndian;
48
49 /************************************************************************/
50 /* ==================================================================== */
51 /* FITDataset */
52 /* ==================================================================== */
53 /************************************************************************/
54
55 class FITRasterBand;
56
57 class FITDataset : public GDALPamDataset
58 {
59 friend class FITRasterBand;
60
61 VSILFILE *fp;
62 FITinfo *info;
63 double adfGeoTransform[6];
64
65 public:
66 FITDataset();
67 ~FITDataset();
68 static GDALDataset *Open( GDALOpenInfo * );
69 // virtual CPLErr GetGeoTransform( double * );
70 };
71
72 #ifdef FIT_WRITE
73 static GDALDataset *FITCreateCopy(const char * pszFilename,
74 GDALDataset *poSrcDS,
75 int bStrict, char ** papszOptions,
76 GDALProgressFunc pfnProgress,
77 void * pProgressData );
78 #endif // FIT_WRITE
79
80 /************************************************************************/
81 /* ==================================================================== */
82 /* FITRasterBand */
83 /* ==================================================================== */
84 /************************************************************************/
85
86 class FITRasterBand : public GDALPamRasterBand
87 {
88 friend class FITDataset;
89
90 unsigned long recordSize; // number of bytes of a single page/block/record
91 unsigned long numXBlocks; // number of pages in the X direction
92 unsigned long numYBlocks; // number of pages in the Y direction
93 unsigned long bytesPerComponent;
94 unsigned long bytesPerPixel;
95 char *tmpImage;
96
97 public:
98
99 FITRasterBand( FITDataset *, int );
100 ~FITRasterBand();
101
102 // should override RasterIO eventually.
103
104 virtual CPLErr IReadBlock( int, int, void * );
105 // virtual CPLErr WriteBlock( int, int, void * );
106 virtual double GetMinimum( int *pbSuccess );
107 virtual double GetMaximum( int *pbSuccess );
108 virtual GDALColorInterp GetColorInterpretation();
109 };
110
111
112 /************************************************************************/
113 /* FITRasterBand() */
114 /************************************************************************/
115
FITRasterBand(FITDataset * poDS,int nBand)116 FITRasterBand::FITRasterBand( FITDataset *poDS, int nBand ) : tmpImage( NULL )
117
118 {
119 this->poDS = poDS;
120 this->nBand = nBand;
121
122 /* -------------------------------------------------------------------- */
123 /* Get the GDAL data type. */
124 /* -------------------------------------------------------------------- */
125 eDataType = fitDataType(poDS->info->dtype);
126
127 /* -------------------------------------------------------------------- */
128 /* Get the page sizes. */
129 /* -------------------------------------------------------------------- */
130 nBlockXSize = poDS->info->xPageSize;
131 nBlockYSize = poDS->info->yPageSize;
132
133 /* -------------------------------------------------------------------- */
134 /* Caculate the values for record offset calculations. */
135 /* -------------------------------------------------------------------- */
136 bytesPerComponent = (GDALGetDataTypeSize(eDataType) / 8);
137 bytesPerPixel = poDS->nBands * bytesPerComponent;
138 recordSize = bytesPerPixel * nBlockXSize * nBlockYSize;
139 numXBlocks =
140 (unsigned long) ceil((double) poDS->info->xSize / nBlockXSize);
141 numYBlocks =
142 (unsigned long) ceil((double) poDS->info->ySize / nBlockYSize);
143
144 tmpImage = (char *) malloc(recordSize);
145 if (! tmpImage)
146 CPLError(CE_Fatal, CPLE_NotSupported,
147 "FITRasterBand couldn't allocate %lu bytes", recordSize);
148
149 /* -------------------------------------------------------------------- */
150 /* Set the access flag. For now we set it the same as the */
151 /* whole dataset, but eventually this should take account of */
152 /* locked channels, or read-only secondary data files. */
153 /* -------------------------------------------------------------------- */
154 /* ... */
155 }
156
157
~FITRasterBand()158 FITRasterBand::~FITRasterBand()
159 {
160 if ( tmpImage )
161 free ( tmpImage );
162 }
163
164
165 /************************************************************************/
166 /* IReadBlock() */
167 /************************************************************************/
168
169 #define COPY_XFIRST(t) { \
170 t *dstp = (t *) pImage; \
171 t *srcp = (t *) tmpImage; \
172 srcp += nBand-1; \
173 long i = 0; \
174 for(long y=ystart; y != ystop; y+= yinc) \
175 for(long x=xstart; x != xstop; x+= xinc, i++) { \
176 dstp[i] = srcp[(y * nBlockXSize + x) * \
177 poFIT_DS->nBands]; \
178 } \
179 }
180
181
182 #define COPY_YFIRST(t) { \
183 t *dstp = (t *) pImage; \
184 t *srcp = (t *) tmpImage; \
185 srcp += nBand-1; \
186 long i = 0; \
187 for(long x=xstart; x != xstop; x+= xinc, i++) \
188 for(long y=ystart; y != ystop; y+= yinc) { \
189 dstp[i] = srcp[(x * nBlockYSize + y) * \
190 poFIT_DS->nBands]; \
191 } \
192 }
193
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)194 CPLErr FITRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
195 void * pImage )
196
197 {
198 FITDataset *poFIT_DS = (FITDataset *) poDS;
199
200 uint64 tilenum = 0;
201
202 switch (poFIT_DS->info->space) {
203 case 1:
204 // iflUpperLeftOrigin - from upper left corner
205 // scan right then down
206 tilenum = nBlockYOff * numXBlocks + nBlockXOff;
207 break;
208 case 2:
209 // iflUpperRightOrigin - from upper right corner
210 // scan left then down
211 tilenum = numYBlocks * numXBlocks + (numXBlocks-1-nBlockXOff);
212 break;
213 case 3:
214 // iflLowerRightOrigin - from lower right corner
215 // scan left then up
216 tilenum = (numYBlocks-1-nBlockYOff) * numXBlocks +
217 (numXBlocks-1-nBlockXOff);
218 break;
219 case 4:
220 // iflLowerLeftOrigin - from lower left corner
221 // scan right then up
222 tilenum = (numYBlocks-1-nBlockYOff) * numXBlocks + nBlockXOff;
223 break;
224 case 5:
225 // iflLeftUpperOrigin -* from upper left corner
226 // scan down then right
227 tilenum = nBlockXOff * numYBlocks + nBlockYOff;
228 break;
229 case 6:
230 // iflRightUpperOrigin - from upper right corner
231 // scan down then left
232 tilenum = (numXBlocks-1-nBlockXOff) * numYBlocks + nBlockYOff;
233 break;
234 case 7:
235 // iflRightLowerOrigin - from lower right corner
236 // scan up then left
237 tilenum = nBlockXOff * numYBlocks + (numYBlocks-1-nBlockYOff);
238 break;
239 case 8:
240 // iflLeftLowerOrigin -* from lower left corner
241 // scan up then right
242 tilenum = (numXBlocks-1-nBlockXOff) * numYBlocks +
243 (numYBlocks-1-nBlockYOff);
244 break;
245 default:
246 CPLError(CE_Failure, CPLE_NotSupported,
247 "FIT - unrecognized image space %i",
248 poFIT_DS->info->space);
249 tilenum = 0;
250 } // switch
251
252 uint64 offset = poFIT_DS->info->dataOffset + recordSize * tilenum;
253 // CPLDebug("FIT", "%i RasterBand::IReadBlock %i %i (out of %i %i) -- %i",
254 // poFIT_DS->info->space,
255 // nBlockXOff, nBlockYOff, numXBlocks, numYBlocks, tilenum);
256
257 if ( VSIFSeekL( poFIT_DS->fp, offset, SEEK_SET ) == -1 ) {
258 CPLError(CE_Failure, CPLE_NotSupported,
259 "FIT - 64bit file seek failure, handle=%p", poFIT_DS->fp );
260 return CE_Failure;
261 }
262
263 // XXX - should handle status
264 // fast path is single component (ll?) - no copy needed
265 char *p;
266 int fastpath = FALSE;
267
268 if ((poFIT_DS->nBands == 1) && (poFIT_DS->info->space == 1)) // upper left
269 fastpath = TRUE;
270
271 if (! fastpath) {
272 VSIFReadL( tmpImage, recordSize, 1, poFIT_DS->fp );
273 // offset to correct component to swap
274 p = (char *) tmpImage + nBand-1;
275 }
276 else {
277 VSIFReadL( pImage, recordSize, 1, poFIT_DS->fp );
278 p = (char *) pImage;
279 }
280
281
282 #ifdef swapping
283 unsigned long i = 0;
284
285 switch(bytesPerComponent) {
286 case 1:
287 // do nothing
288 break;
289 case 2:
290 for(i=0; i < recordSize; i+= bytesPerPixel)
291 gst_swap16(p + i);
292 break;
293 case 4:
294 for(i=0; i < recordSize; i+= bytesPerPixel)
295 gst_swap32(p + i);
296 break;
297 case 8:
298 for(i=0; i < recordSize; i+= bytesPerPixel)
299 gst_swap64(p + i);
300 break;
301 default:
302 CPLError(CE_Failure, CPLE_NotSupported,
303 "FITRasterBand::IReadBlock unsupported bytesPerPixel %lu",
304 bytesPerComponent);
305 } // switch
306 #else
307 (void) p; // avoid warnings.
308 #endif // swapping
309
310 if (! fastpath) {
311 long xinc, yinc, xstart, ystart, xstop, ystop;
312 if (poFIT_DS->info->space <= 4) {
313 // scan left/right first
314
315 switch (poFIT_DS->info->space) {
316 case 1:
317 // iflUpperLeftOrigin - from upper left corner
318 // scan right then down
319 xinc = 1;
320 yinc = 1;
321 break;
322 case 2:
323 // iflUpperRightOrigin - from upper right corner
324 // scan left then down
325 xinc = -1;
326 yinc = 1;
327 break;
328 case 3:
329 // iflLowerRightOrigin - from lower right corner
330 // scan left then up
331 xinc = -1;
332 yinc = -1;
333 break;
334 case 4:
335 // iflLowerLeftOrigin - from lower left corner
336 // scan right then up
337 xinc = 1;
338 yinc = -1;
339 break;
340 default:
341 CPLError(CE_Failure, CPLE_NotSupported,
342 "FIT - unrecognized image space %i",
343 poFIT_DS->info->space);
344 xinc = 1;
345 yinc = 1;
346 } // switch
347
348
349 if (xinc == 1) {
350 xstart = 0;
351 xstop = nBlockXSize;
352 }
353 else {
354 xstart = nBlockXSize-1;
355 xstop = -1;
356 }
357 if (yinc == 1) {
358 ystart = 0;
359 ystop = nBlockYSize;
360 }
361 else {
362 int localBlockYSize = nBlockYSize;
363 long maxy_full =
364 (long) floor(poFIT_DS->info->ySize / (double) nBlockYSize);
365 if (nBlockYOff >= maxy_full)
366 localBlockYSize = poFIT_DS->info->ySize % nBlockYSize;
367 ystart = localBlockYSize-1;
368 ystop = -1;
369 }
370
371 switch(bytesPerComponent) {
372 case 1:
373 COPY_XFIRST(char);
374 break;
375 case 2:
376 COPY_XFIRST(uint16);
377 break;
378 case 4:
379 COPY_XFIRST(uint32);
380 break;
381 case 8:
382 COPY_XFIRST(uint64);
383 break;
384 default:
385 CPLError(CE_Failure, CPLE_NotSupported,
386 "FITRasterBand::IReadBlock unsupported "
387 "bytesPerComponent %lu", bytesPerComponent);
388 } // switch
389
390 } // scan left/right first
391 else {
392 // scan up/down first
393
394 switch (poFIT_DS->info->space) {
395 case 5:
396 // iflLeftUpperOrigin -* from upper left corner
397 // scan down then right
398 xinc = 1;
399 yinc = 1;
400 break;
401 case 6:
402 // iflRightUpperOrigin - from upper right corner
403 // scan down then left
404 xinc = -1;
405 yinc = 1;
406 break;
407 case 7:
408 // iflRightLowerOrigin - from lower right corner
409 // scan up then left
410 xinc = -1;
411 yinc = -1;
412 break;
413 case 8:
414 // iflLeftLowerOrigin -* from lower left corner
415 // scan up then right
416 xinc = 1;
417 yinc = -1;
418 break;
419 default:
420 CPLError(CE_Failure, CPLE_NotSupported,
421 "FIT - unrecognized image space %i",
422 poFIT_DS->info->space);
423 xinc = 1;
424 yinc = 1;
425 } // switch
426
427 if (xinc == 1) {
428 xstart = 0;
429 xstop = nBlockXSize;
430 }
431 else {
432 int localBlockXSize = nBlockXSize;
433 long maxx_full =
434 (long) floor(poFIT_DS->info->xSize / (double) nBlockXSize);
435 if (nBlockXOff >= maxx_full)
436 localBlockXSize = poFIT_DS->info->xSize % nBlockXSize;
437 xstart = localBlockXSize-1;
438 xstop = -1;
439 }
440 if (yinc == 1) {
441 ystart = 0;
442 ystop = nBlockYSize;
443 }
444 else {
445 ystart = nBlockYSize-1;
446 ystop = -1;
447 }
448
449 switch(bytesPerComponent) {
450 case 1:
451 COPY_YFIRST(char);
452 break;
453 case 2:
454 COPY_YFIRST(uint16);
455 break;
456 case 4:
457 COPY_YFIRST(uint32);
458 break;
459 case 8:
460 COPY_YFIRST(uint64);
461 break;
462 default:
463 CPLError(CE_Failure, CPLE_NotSupported,
464 "FITRasterBand::IReadBlock unsupported "
465 "bytesPerComponent %lu", bytesPerComponent);
466 } // switch
467
468 } // scan up/down first
469
470 } // ! fastpath
471 return CE_None;
472 }
473
474 #if 0
475 /************************************************************************/
476 /* ReadBlock() */
477 /************************************************************************/
478
479 CPLErr FITRasterBand::ReadBlock( int nBlockXOff, int nBlockYOff,
480 void * pImage )
481
482 {
483 FITDataset *poFIT_DS = (FITDataset *) poDS;
484
485
486
487 return CE_None;
488 }
489
490 /************************************************************************/
491 /* WriteBlock() */
492 /************************************************************************/
493
494 CPLErr FITRasterBand::WriteBlock( int nBlockXOff, int nBlockYOff,
495 void * pImage )
496
497 {
498 FITDataset *poFIT_DS = (FITDataset *) poDS;
499
500
501
502 return CE_None;
503 }
504 #endif
505
506 /************************************************************************/
507 /* GetMinimum() */
508 /************************************************************************/
509
GetMinimum(int * pbSuccess)510 double FITRasterBand::GetMinimum( int *pbSuccess )
511 {
512 FITDataset *poFIT_DS = (FITDataset *) poDS;
513
514 if ((! poFIT_DS) || (! poFIT_DS->info))
515 return GDALRasterBand::GetMinimum( pbSuccess );
516
517 if (pbSuccess)
518 *pbSuccess = TRUE;
519
520 if (poFIT_DS->info->version &&
521 EQUALN((const char *) &(poFIT_DS->info->version), "02", 2)) {
522 return poFIT_DS->info->minValue;
523 }
524 else {
525 return GDALRasterBand::GetMinimum( pbSuccess );
526 }
527 }
528
529 /************************************************************************/
530 /* GetMaximum() */
531 /************************************************************************/
532
GetMaximum(int * pbSuccess)533 double FITRasterBand::GetMaximum( int *pbSuccess )
534 {
535 FITDataset *poFIT_DS = (FITDataset *) poDS;
536
537 if ((! poFIT_DS) || (! poFIT_DS->info))
538 return GDALRasterBand::GetMaximum( pbSuccess );
539
540 if (pbSuccess)
541 *pbSuccess = TRUE;
542
543 if (EQUALN((const char *) &poFIT_DS->info->version, "02", 2)) {
544 return poFIT_DS->info->maxValue;
545 }
546 else {
547 return GDALRasterBand::GetMaximum( pbSuccess );
548 }
549 }
550
551 /************************************************************************/
552 /* GetColorInterpretation() */
553 /************************************************************************/
554
GetColorInterpretation()555 GDALColorInterp FITRasterBand::GetColorInterpretation()
556 {
557 FITDataset *poFIT_DS = (FITDataset *) poDS;
558
559 if ((! poFIT_DS) || (! poFIT_DS->info))
560 return GCI_Undefined;
561
562 switch(poFIT_DS->info->cm) {
563 case 1: // iflNegative - inverted luminance (min value is white)
564 CPLError( CE_Warning, CPLE_NotSupported,
565 "FIT - color model Negative not supported - ignoring model");
566 return GCI_Undefined;
567
568 case 2: // iflLuminance - luminance
569 if (poFIT_DS->nBands != 1) {
570 CPLError( CE_Failure, CPLE_NotSupported,
571 "FIT - color model Luminance mismatch with %i bands",
572 poFIT_DS->nBands);
573 return GCI_Undefined;
574 }
575 switch (nBand) {
576 case 1:
577 return GCI_GrayIndex;
578 default:
579 CPLError( CE_Failure, CPLE_NotSupported,
580 "FIT - color model Luminance unknown band %i", nBand);
581 return GCI_Undefined;
582 } // switch nBand
583
584 case 3: // iflRGB - full color (Red, Green, Blue triplets)
585 if (poFIT_DS->nBands != 3) {
586 CPLError( CE_Failure, CPLE_NotSupported,
587 "FIT - color model RGB mismatch with %i bands",
588 poFIT_DS->nBands);
589 return GCI_Undefined;
590 }
591 switch (nBand) {
592 case 1:
593 return GCI_RedBand;
594 case 2:
595 return GCI_GreenBand;
596 case 3:
597 return GCI_BlueBand;
598 default:
599 CPLError( CE_Failure, CPLE_NotSupported,
600 "FIT - color model RGB unknown band %i", nBand);
601 return GCI_Undefined;
602 } // switch nBand
603
604 case 4: // iflRGBPalette - color mapped values
605 CPLError( CE_Warning, CPLE_NotSupported,
606 "FIT - color model RGBPalette not supported - "
607 "ignoring model");
608 return GCI_Undefined;
609
610 case 5: // iflRGBA - full color with transparency (alpha channel)
611 if (poFIT_DS->nBands != 4) {
612 CPLError( CE_Failure, CPLE_NotSupported,
613 "FIT - color model RGBA mismatch with %i bands",
614 poFIT_DS->nBands);
615 return GCI_Undefined;
616 }
617 switch (nBand) {
618 case 1:
619 return GCI_RedBand;
620 case 2:
621 return GCI_GreenBand;
622 case 3:
623 return GCI_BlueBand;
624 case 4:
625 return GCI_AlphaBand;
626 default:
627 CPLError( CE_Failure, CPLE_NotSupported,
628 "FIT - color model RGBA unknown band %i", nBand);
629 return GCI_Undefined;
630 } // switch nBand
631
632 case 6: // iflHSV - Hue, Saturation, Value
633 if (poFIT_DS->nBands != 3) {
634 CPLError( CE_Failure, CPLE_NotSupported,
635 "FIT - color model HSV mismatch with %i bands",
636 poFIT_DS->nBands);
637 return GCI_Undefined;
638 }
639 switch (nBand) {
640 case 1:
641 return GCI_HueBand;
642 case 2:
643 return GCI_SaturationBand;
644 case 3:
645 return GCI_LightnessBand;
646 default:
647 CPLError( CE_Failure, CPLE_NotSupported,
648 "FIT - color model HSV unknown band %i", nBand);
649 return GCI_Undefined;
650 } // switch nBand
651
652 case 7: // iflCMY - Cyan, Magenta, Yellow
653 if (poFIT_DS->nBands != 3) {
654 CPLError( CE_Failure, CPLE_NotSupported,
655 "FIT - color model CMY mismatch with %i bands",
656 poFIT_DS->nBands);
657 return GCI_Undefined;
658 }
659 switch (nBand) {
660 case 1:
661 return GCI_CyanBand;
662 case 2:
663 return GCI_MagentaBand;
664 case 3:
665 return GCI_YellowBand;
666 default:
667 CPLError( CE_Failure, CPLE_NotSupported,
668 "FIT - color model CMY unknown band %i", nBand);
669 return GCI_Undefined;
670 } // switch nBand
671
672 case 8: // iflCMYK - Cyan, Magenta, Yellow, Black
673 if (poFIT_DS->nBands != 4) {
674 CPLError( CE_Failure, CPLE_NotSupported,
675 "FIT - color model CMYK mismatch with %i bands",
676 poFIT_DS->nBands);
677 return GCI_Undefined;
678 }
679 switch (nBand) {
680 case 1:
681 return GCI_CyanBand;
682 case 2:
683 return GCI_MagentaBand;
684 case 3:
685 return GCI_YellowBand;
686 case 4:
687 return GCI_BlackBand;
688 default:
689 CPLError( CE_Failure, CPLE_NotSupported,
690 "FIT - color model CMYK unknown band %i", nBand);
691 return GCI_Undefined;
692 } // switch nBand
693
694 case 9: // iflBGR - full color (ordered Blue, Green, Red)
695 if (poFIT_DS->nBands != 3) {
696 CPLError( CE_Failure, CPLE_NotSupported,
697 "FIT - color model BGR mismatch with %i bands",
698 poFIT_DS->nBands);
699 return GCI_Undefined;
700 }
701 switch (nBand) {
702 case 1:
703 return GCI_BlueBand;
704 case 2:
705 return GCI_GreenBand;
706 case 3:
707 return GCI_RedBand;
708 default:
709 CPLError( CE_Failure, CPLE_NotSupported,
710 "FIT - color model BGR unknown band %i", nBand);
711 return GCI_Undefined;
712 } // switch nBand
713
714 case 10: // iflABGR - Alpha, Blue, Green, Red (SGI frame buffers)
715 if (poFIT_DS->nBands != 4) {
716 CPLError( CE_Failure, CPLE_NotSupported,
717 "FIT - color model ABGR mismatch with %i bands",
718 poFIT_DS->nBands);
719 return GCI_Undefined;
720 }
721 switch (nBand) {
722 case 1:
723 return GCI_AlphaBand;
724 case 2:
725 return GCI_BlueBand;
726 case 3:
727 return GCI_GreenBand;
728 case 4:
729 return GCI_RedBand;
730 default:
731 CPLError( CE_Failure, CPLE_NotSupported,
732 "FIT - color model ABGR unknown band %i", nBand);
733 return GCI_Undefined;
734 } // switch nBand
735
736 case 11: // iflMultiSpectral - multi-spectral data, arbitrary number of
737 // chans
738 return GCI_Undefined;
739
740 case 12: // iflYCC PhotoCD color model (Luminance, Chrominance)
741 CPLError( CE_Warning, CPLE_NotSupported,
742 "FIT - color model YCC not supported - ignoring model");
743 return GCI_Undefined;
744
745 case 13: // iflLuminanceAlpha - Luminance plus alpha
746 if (poFIT_DS->nBands != 2) {
747 CPLError( CE_Failure, CPLE_NotSupported,
748 "FIT - color model LuminanceAlpha mismatch with "
749 "%i bands",
750 poFIT_DS->nBands);
751 return GCI_Undefined;
752 }
753 switch (nBand) {
754 case 1:
755 return GCI_GrayIndex;
756 case 2:
757 return GCI_AlphaBand;
758 default:
759 CPLError( CE_Failure, CPLE_NotSupported,
760 "FIT - color model LuminanceAlpha unknown band %i",
761 nBand);
762 return GCI_Undefined;
763 } // switch nBand
764
765 default:
766 CPLError( CE_Warning, CPLE_NotSupported,
767 "FIT - unrecognized color model %i - ignoring model",
768 poFIT_DS->info->cm);
769 return GCI_Undefined;
770 } // switch
771 }
772
773 /************************************************************************/
774 /* FITDataset() */
775 /************************************************************************/
776
FITDataset()777 FITDataset::FITDataset() : fp( NULL ), info( NULL )
778 {
779
780 adfGeoTransform[0] = 0.0; // x origin (top left corner)
781 adfGeoTransform[1] = 1.0; // x pixel size
782 adfGeoTransform[2] = 0.0;
783
784 adfGeoTransform[3] = 0.0; // y origin (top left corner)
785 adfGeoTransform[4] = 0.0;
786 adfGeoTransform[5] = 1.0; // y pixel size
787 }
788
789 /************************************************************************/
790 /* ~FITDataset() */
791 /************************************************************************/
792
~FITDataset()793 FITDataset::~FITDataset()
794 {
795 FlushCache();
796 if (info)
797 delete(info);
798 if(fp)
799 VSIFCloseL(fp);
800 }
801
802 // simple guard object to delete memory
803 // when the guard goes out of scope
804 template< class T >
805 class DeleteGuard
806 {
807 public:
DeleteGuard(T * p)808 DeleteGuard( T *p ) : _ptr( p ) { }
~DeleteGuard()809 ~DeleteGuard()
810 {
811 delete _ptr;
812 }
813
take()814 T *take()
815 {
816 T *tmp = _ptr;
817 _ptr = 0;
818 return tmp;
819 }
820
821 private:
822 T *_ptr;
823 // prevent default copy constructor and assignment operator
824 DeleteGuard( const DeleteGuard & );
825 DeleteGuard &operator=( const DeleteGuard & );
826 };
827
828 // simple guard object to free memory
829 // when the guard goes out of scope
830 template< class T >
831 class FreeGuard
832 {
833 public:
FreeGuard(T * p)834 FreeGuard( T *p ) : _ptr( p ) { }
~FreeGuard()835 ~FreeGuard()
836 {
837 if ( _ptr )
838 free( _ptr );
839 }
840
take()841 T *take()
842 {
843 T *tmp = _ptr;
844 _ptr = 0;
845 return tmp;
846 }
847
848 private:
849 T *_ptr;
850 // prevent default copy constructor and assignment operator
851 FreeGuard( const FreeGuard & );
852 FreeGuard &operator=( const FreeGuard & );
853 };
854
855 /************************************************************************/
856 /* Open() */
857 /************************************************************************/
858
Open(GDALOpenInfo * poOpenInfo)859 GDALDataset *FITDataset::Open( GDALOpenInfo * poOpenInfo )
860 {
861 /* -------------------------------------------------------------------- */
862 /* First we check to see if the file has the expected header */
863 /* bytes. */
864 /* -------------------------------------------------------------------- */
865
866 if( poOpenInfo->nHeaderBytes < 5 )
867 return NULL;
868
869
870 if( !EQUALN((const char *) poOpenInfo->pabyHeader, "IT01", 4) &&
871 !EQUALN((const char *) poOpenInfo->pabyHeader, "IT02", 4) )
872 return NULL;
873
874 if( poOpenInfo->eAccess == GA_Update )
875 {
876 CPLError( CE_Failure, CPLE_NotSupported,
877 "The FIT driver does not support update access to existing"
878 " files.\n" );
879 return NULL;
880 }
881
882 /* -------------------------------------------------------------------- */
883 /* Create a corresponding GDALDataset. */
884 /* -------------------------------------------------------------------- */
885 FITDataset *poDS;
886
887 poDS = new FITDataset();
888 DeleteGuard<FITDataset> guard( poDS );
889
890 // re-open file for large file (64bit) access
891 if ( poOpenInfo->eAccess == GA_ReadOnly )
892 poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
893 else
894 poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
895
896 if ( !poDS->fp ) {
897 CPLError( CE_Failure, CPLE_OpenFailed,
898 "Failed to re-open %s with FIT driver.\n",
899 poOpenInfo->pszFilename );
900 return NULL;
901 }
902 poDS->eAccess = poOpenInfo->eAccess;
903
904
905 poDS->info = new FITinfo;
906 FITinfo *info = poDS->info;
907
908 /* -------------------------------------------------------------------- */
909 /* Read other header values. */
910 /* -------------------------------------------------------------------- */
911 FIThead02 *head = (FIThead02 *) poOpenInfo->pabyHeader;
912
913 // extract the image attributes from the file header
914 if (EQUALN((const char *) &head->version, "02", 2)) {
915 // incomplete header
916 if( poOpenInfo->nHeaderBytes < (signed) sizeof(FIThead02) )
917 return NULL;
918
919 CPLDebug("FIT", "Loading file with header version 02");
920
921 gst_swapb(head->minValue);
922 info->minValue = head->minValue;
923 gst_swapb(head->maxValue);
924 info->maxValue = head->maxValue;
925 gst_swapb(head->dataOffset);
926 info->dataOffset = head->dataOffset;
927
928 info->userOffset = sizeof(FIThead02);
929 }
930 else if (EQUALN((const char *) &head->version, "01", 2)) {
931 // incomplete header
932 if( poOpenInfo->nHeaderBytes < (signed) sizeof(FIThead01) )
933 return NULL;
934
935 CPLDebug("FIT", "Loading file with header version 01");
936
937 // map old style header into new header structure
938 FIThead01* head01 = (FIThead01*)head;
939 gst_swapb(head->dataOffset);
940 info->dataOffset = head01->dataOffset;
941
942 info->userOffset = sizeof(FIThead01);
943 }
944 else {
945 // unrecognized header version
946 CPLError( CE_Failure, CPLE_NotSupported,
947 "FIT - unsupported header version %.2s\n",
948 (const char*) &head->version);
949 return NULL;
950 }
951
952 CPLDebug("FIT", "userOffset %i, dataOffset %i",
953 info->userOffset, info->dataOffset);
954
955 info->magic = head->magic;
956 info->version = head->version;
957
958 gst_swapb(head->xSize);
959 info->xSize = head->xSize;
960 gst_swapb(head->ySize);
961 info->ySize = head->ySize;
962 gst_swapb(head->zSize);
963 info->zSize = head->zSize;
964 gst_swapb(head->cSize);
965 info->cSize = head->cSize;
966 gst_swapb(head->dtype);
967 info->dtype = head->dtype;
968 gst_swapb(head->order);
969 info->order = head->order;
970 gst_swapb(head->space);
971 info->space = head->space;
972 gst_swapb(head->cm);
973 info->cm = head->cm;
974 gst_swapb(head->xPageSize);
975 info->xPageSize = head->xPageSize;
976 gst_swapb(head->yPageSize);
977 info->yPageSize = head->yPageSize;
978 gst_swapb(head->zPageSize);
979 info->zPageSize = head->zPageSize;
980 gst_swapb(head->cPageSize);
981 info->cPageSize = head->cPageSize;
982
983 CPLDebug("FIT", "size %i %i %i %i, pageSize %i %i %i %i",
984 info->xSize, info->ySize, info->zSize, info->cSize,
985 info->xPageSize, info->yPageSize, info->zPageSize,
986 info->cPageSize);
987
988 CPLDebug("FIT", "dtype %i order %i space %i cm %i",
989 info->dtype, info->order, info->space, info->cm);
990
991 /**************************/
992
993 poDS->nRasterXSize = head->xSize;
994 poDS->nRasterYSize = head->ySize;
995 poDS->nBands = head->cSize;
996
997 /* -------------------------------------------------------------------- */
998 /* Check if 64 bit seek is needed. */
999 /* -------------------------------------------------------------------- */
1000 uint64 bytesPerComponent =
1001 (GDALGetDataTypeSize(fitDataType(poDS->info->dtype)) / 8);
1002 uint64 bytesPerPixel = head->cSize * bytesPerComponent;
1003 uint64 recordSize = bytesPerPixel * head->xPageSize *
1004 head->yPageSize;
1005 uint64 numXBlocks =
1006 (uint64) ceil((double) head->xSize / head->xPageSize);
1007 uint64 numYBlocks =
1008 (uint64) ceil((double) head->ySize / head->yPageSize);
1009
1010 uint64 maxseek = recordSize * numXBlocks * numYBlocks;
1011
1012 // CPLDebug("FIT", "(sizeof %i) max seek %llx ==> %llx\n", sizeof(uint64),
1013 // maxseek, maxseek >> 31);
1014 if (maxseek >> 31) // signed long
1015 #ifdef VSI_LARGE_API_SUPPORTED
1016 CPLDebug("FIT", "Using 64 bit version of fseek");
1017 #else
1018 CPLError(CE_Fatal, CPLE_NotSupported,
1019 "FIT - need 64 bit version of fseek");
1020 #endif
1021
1022 /* -------------------------------------------------------------------- */
1023 /* Verify all "unused" header values. */
1024 /* -------------------------------------------------------------------- */
1025
1026 if( info->zSize != 1 )
1027 {
1028 CPLError( CE_Failure, CPLE_NotSupported,
1029 "FIT driver - unsupported zSize %i\n", info->zSize);
1030 return NULL;
1031 }
1032
1033 if( info->order != 1 ) // interleaved - RGBRGB
1034 {
1035 CPLError( CE_Failure, CPLE_NotSupported,
1036 "FIT driver - unsupported order %i\n", info->order);
1037 return NULL;
1038 }
1039
1040 if( info->zPageSize != 1 )
1041 {
1042 CPLError( CE_Failure, CPLE_NotSupported,
1043 "FIT driver - unsupported zPageSize %i\n", info->zPageSize);
1044 return NULL;
1045 }
1046
1047 if( info->cPageSize != info->cSize )
1048 {
1049 CPLError( CE_Failure, CPLE_NotSupported,
1050 "FIT driver - unsupported cPageSize %i (!= %i)\n",
1051 info->cPageSize, info->cSize);
1052 return NULL;
1053 }
1054
1055 /* -------------------------------------------------------------------- */
1056 /* Create band information objects. */
1057 /* -------------------------------------------------------------------- */
1058 for( int i = 0; i < poDS->nBands; i++ )
1059 {
1060 poDS->SetBand( i+1, new FITRasterBand( poDS, i+1 ) ) ;
1061 }
1062
1063 /* -------------------------------------------------------------------- */
1064 /* Initialize any PAM information. */
1065 /* -------------------------------------------------------------------- */
1066 poDS->SetDescription( poOpenInfo->pszFilename );
1067 poDS->TryLoadXML();
1068
1069 /* -------------------------------------------------------------------- */
1070 /* Check for external overviews. */
1071 /* -------------------------------------------------------------------- */
1072 poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
1073
1074 return guard.take();
1075 }
1076
1077 /************************************************************************/
1078 /* FITCreateCopy() */
1079 /************************************************************************/
1080
1081 #ifdef FIT_WRITE
FITCreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)1082 static GDALDataset *FITCreateCopy(const char * pszFilename,
1083 GDALDataset *poSrcDS,
1084 int bStrict, char ** papszOptions,
1085 GDALProgressFunc pfnProgress,
1086 void * pProgressData )
1087 {
1088 CPLDebug("FIT", "CreateCopy %s - %i", pszFilename, bStrict);
1089
1090 int nBands = poSrcDS->GetRasterCount();
1091 if (nBands == 0)
1092 {
1093 CPLError( CE_Failure, CPLE_NotSupported,
1094 "FIT driver does not support source dataset with zero band.\n");
1095 return NULL;
1096 }
1097
1098 /* -------------------------------------------------------------------- */
1099 /* Create the dataset. */
1100 /* -------------------------------------------------------------------- */
1101 VSILFILE *fpImage;
1102
1103 if( !pfnProgress( 0.0, NULL, pProgressData ) )
1104 {
1105 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
1106 return NULL;
1107 }
1108
1109 fpImage = VSIFOpenL( pszFilename, "wb" );
1110 if( fpImage == NULL )
1111 {
1112 CPLError( CE_Failure, CPLE_OpenFailed,
1113 "FIT - unable to create file %s.\n",
1114 pszFilename );
1115 return NULL;
1116 }
1117
1118 /* -------------------------------------------------------------------- */
1119 /* Generate header. */
1120 /* -------------------------------------------------------------------- */
1121 // XXX - should FIT_PAGE_SIZE be based on file page size ??
1122 int size = MAX(sizeof(FIThead02), FIT_PAGE_SIZE);
1123 FIThead02 *head = (FIThead02 *) malloc(size);
1124 FreeGuard<FIThead02> guardHead( head );
1125
1126 // clean header so padding (past real header) is all zeros
1127 memset( head, 0, size );
1128
1129 strncpy((char *) &head->magic, "IT", 2);
1130 strncpy((char *) &head->version, "02", 2);
1131
1132 head->xSize = poSrcDS->GetRasterXSize();
1133 gst_swapb(head->xSize);
1134 head->ySize = poSrcDS->GetRasterYSize();
1135 gst_swapb(head->ySize);
1136 head->zSize = 1;
1137 gst_swapb(head->zSize);
1138
1139 head->cSize = nBands;
1140 gst_swapb(head->cSize);
1141
1142 GDALRasterBand *firstBand = poSrcDS->GetRasterBand(1);
1143 if (! firstBand) {
1144 VSIFCloseL(fpImage);
1145 return NULL;
1146 }
1147
1148 head->dtype = fitGetDataType(firstBand->GetRasterDataType());
1149 if (! head->dtype) {
1150 VSIFCloseL(fpImage);
1151 return NULL;
1152 }
1153 gst_swapb(head->dtype);
1154 head->order = 1; // interleaved - RGBRGB
1155 gst_swapb(head->order);
1156 head->space = 1; // upper left
1157 gst_swapb(head->space);
1158
1159 // XXX - need to check all bands
1160 head->cm = fitGetColorModel(firstBand->GetColorInterpretation(), nBands);
1161 gst_swapb(head->cm);
1162
1163 int blockX, blockY;
1164 firstBand->GetBlockSize(&blockX, &blockY);
1165 CPLDebug("FIT write", "inherited block size %ix%i", blockX, blockY);
1166
1167 if( CSLFetchNameValue(papszOptions,"PAGESIZE") != NULL )
1168 {
1169 const char *str = CSLFetchNameValue(papszOptions,"PAGESIZE");
1170 int newBlockX, newBlockY;
1171 sscanf(str, "%i,%i", &newBlockX, &newBlockY);
1172 if (newBlockX && newBlockY) {
1173 blockX = newBlockX;
1174 blockY = newBlockY;
1175 }
1176 else {
1177 CPLError(CE_Failure, CPLE_OpenFailed,
1178 "FIT - Unable to parse option PAGESIZE values [%s]", str);
1179 }
1180 }
1181
1182 // XXX - need to do lots of checking of block size
1183 // * provide ability to override block size with options
1184 // * handle non-square block size (like scanline)
1185 // - probably default from non-tiled image - have default block size
1186 // * handle block size bigger than image size
1187 // * undesirable block size (non power of 2, others?)
1188 // * mismatched block sizes for different bands
1189 // * image that isn't even pages (ie. partially empty pages at edge)
1190 CPLDebug("FIT write", "using block size %ix%i", blockX, blockY);
1191
1192 head->xPageSize = blockX;
1193 gst_swapb(head->xPageSize);
1194 head->yPageSize = blockY;
1195 gst_swapb(head->yPageSize);
1196 head->zPageSize = 1;
1197 gst_swapb(head->zPageSize);
1198 head->cPageSize = nBands;
1199 gst_swapb(head->cPageSize);
1200
1201 // XXX - need to check all bands
1202 head->minValue = firstBand->GetMinimum();
1203 gst_swapb(head->minValue);
1204 // XXX - need to check all bands
1205 head->maxValue = firstBand->GetMaximum();
1206 gst_swapb(head->maxValue);
1207 head->dataOffset = size;
1208 gst_swapb(head->dataOffset);
1209
1210 VSIFWriteL(head, size, 1, fpImage);
1211
1212 /* -------------------------------------------------------------------- */
1213 /* Loop over image, copying image data. */
1214 /* -------------------------------------------------------------------- */
1215 unsigned long bytesPerComponent =
1216 (GDALGetDataTypeSize(firstBand->GetRasterDataType()) / 8);
1217 unsigned long bytesPerPixel = nBands * bytesPerComponent;
1218
1219 unsigned long pageBytes = blockX * blockY * bytesPerPixel;
1220 char *output = (char *) malloc(pageBytes);
1221 if (! output)
1222 CPLError(CE_Fatal, CPLE_NotSupported,
1223 "FITRasterBand couldn't allocate %lu bytes", pageBytes);
1224 FreeGuard<char> guardOutput( output );
1225
1226 long maxx = (long) ceil(poSrcDS->GetRasterXSize() / (double) blockX);
1227 long maxy = (long) ceil(poSrcDS->GetRasterYSize() / (double) blockY);
1228 long maxx_full = (long) floor(poSrcDS->GetRasterXSize() / (double) blockX);
1229 long maxy_full = (long) floor(poSrcDS->GetRasterYSize() / (double) blockY);
1230
1231 CPLDebug("FIT", "about to write %ld x %ld blocks", maxx, maxy);
1232
1233 for(long y=0; y < maxy; y++)
1234 for(long x=0; x < maxx; x++) {
1235 long readX = blockX;
1236 long readY = blockY;
1237 int do_clean = FALSE;
1238
1239 // handle cases where image size isn't an exact multiple
1240 // of page size
1241 if (x >= maxx_full) {
1242 readX = poSrcDS->GetRasterXSize() % blockX;
1243 do_clean = TRUE;
1244 }
1245 if (y >= maxy_full) {
1246 readY = poSrcDS->GetRasterYSize() % blockY;
1247 do_clean = TRUE;
1248 }
1249
1250 // clean out image if only doing partial reads
1251 if (do_clean)
1252 memset( output, 0, pageBytes );
1253
1254 for( int iBand = 0; iBand < nBands; iBand++ ) {
1255 GDALRasterBand * poBand = poSrcDS->GetRasterBand( iBand+1 );
1256 CPLErr eErr =
1257 poBand->RasterIO( GF_Read, // eRWFlag
1258 x * blockX, // nXOff
1259 y * blockY, // nYOff
1260 readX, // nXSize
1261 readY, // nYSize
1262 output + iBand * bytesPerComponent,
1263 // pData
1264 blockX, // nBufXSize
1265 blockY, // nBufYSize
1266 firstBand->GetRasterDataType(),
1267 // eBufType
1268 bytesPerPixel, // nPixelSpace
1269 bytesPerPixel * blockX, NULL); // nLineSpace
1270 if (eErr != CE_None)
1271 CPLError(CE_Failure, CPLE_FileIO,
1272 "FIT write - CreateCopy got read error %i", eErr);
1273 } // for iBand
1274
1275 #ifdef swapping
1276 char *p = output;
1277 unsigned long i;
1278 switch(bytesPerComponent) {
1279 case 1:
1280 // do nothing
1281 break;
1282 case 2:
1283 for(i=0; i < pageBytes; i+= bytesPerComponent)
1284 gst_swap16(p + i);
1285 break;
1286 case 4:
1287 for(i=0; i < pageBytes; i+= bytesPerComponent)
1288 gst_swap32(p + i);
1289 break;
1290 case 8:
1291 for(i=0; i < pageBytes; i+= bytesPerComponent)
1292 gst_swap64(p + i);
1293 break;
1294 default:
1295 CPLError(CE_Failure, CPLE_NotSupported,
1296 "FIT write - unsupported bytesPerPixel %lu",
1297 bytesPerComponent);
1298 } // switch
1299 #endif // swapping
1300
1301 VSIFWriteL(output, pageBytes, 1, fpImage);
1302
1303 double perc = ((double) (y * maxx + x)) / (maxx * maxy);
1304 // printf("progress %f\n", perc);
1305 if( !pfnProgress( perc, NULL, pProgressData ) )
1306 {
1307 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
1308 //free(output);
1309 VSIFCloseL( fpImage );
1310 VSIUnlink( pszFilename );
1311 return NULL;
1312 }
1313 } // for x
1314
1315 //free(output);
1316
1317 VSIFCloseL( fpImage );
1318
1319 pfnProgress( 1.0, NULL, pProgressData );
1320
1321 /* -------------------------------------------------------------------- */
1322 /* Re-open dataset, and copy any auxiliary pam information. */
1323 /* -------------------------------------------------------------------- */
1324 GDALPamDataset *poDS = (GDALPamDataset *)
1325 GDALOpen( pszFilename, GA_ReadOnly );
1326
1327 if( poDS )
1328 poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
1329
1330 return poDS;
1331 }
1332 #endif // FIT_WRITE
1333
1334 /************************************************************************/
1335 /* GetGeoTransform() */
1336 /************************************************************************/
1337
1338 // CPLErr FITDataset::GetGeoTransform( double * padfTransform )
1339 // {
1340 // CPLDebug("FIT", "FITDataset::GetGeoTransform");
1341 // memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1342 // return( CE_None );
1343 // }
1344
1345 /************************************************************************/
1346 /* GDALRegister_FIT() */
1347 /************************************************************************/
1348
GDALRegister_FIT()1349 void GDALRegister_FIT()
1350
1351 {
1352 GDALDriver *poDriver;
1353
1354 if( GDALGetDriverByName( "FIT" ) == NULL )
1355 {
1356 poDriver = new GDALDriver();
1357
1358 poDriver->SetDescription( "FIT" );
1359 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
1360 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1361 "FIT Image" );
1362 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1363 "frmt_various.html#" );
1364 poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "" );
1365 poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1366
1367 poDriver->pfnOpen = FITDataset::Open;
1368 #ifdef FIT_WRITE
1369 poDriver->pfnCreateCopy = FITCreateCopy;
1370 poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1371 "Byte UInt16 Int16 UInt32 Int32 Float32 Float64" );
1372 #endif // FIT_WRITE
1373
1374 GetGDALDriverManager()->RegisterDriver( poDriver );
1375 }
1376 }
1377