1 : /******************************************************************************
2 : * $Id: sgidataset.cpp 21680 2011-02-11 21:12:07Z warmerdam $
3 : *
4 : * Project: SGI Image Driver
5 : * Purpose: Implement SGI Image Support based on Paul Bourke's SGI Image code.
6 : * http://astronomy.swin.edu.au/~pbourke/dataformats/sgirgb/
7 : * ftp://ftp.sgi.com/graphics/SGIIMAGESPEC
8 : * Authors: Mike Mazzella (GDAL driver)
9 : * Paul Bourke (original SGI format code)
10 : * Frank Warmerdam (write support)
11 : *
12 : ******************************************************************************
13 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
14 : *
15 : * Permission is hereby granted, free of charge, to any person obtaining a
16 : * copy of this software and associated documentation files (the "Software"),
17 : * to deal in the Software without restriction, including without limitation
18 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 : * and/or sell copies of the Software, and to permit persons to whom the
20 : * Software is furnished to do so, subject to the following conditions:
21 : *
22 : * The above copyright notice and this permission notice shall be included
23 : * in all copies or substantial portions of the Software.
24 : *
25 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 : * DEALINGS IN THE SOFTWARE.
32 : ****************************************************************************/
33 :
34 : #include "gdal_pam.h"
35 : #include "cpl_port.h"
36 : #include "cpl_string.h"
37 :
38 : CPL_CVSID("$Id: sgidataset.cpp 21680 2011-02-11 21:12:07Z warmerdam $");
39 :
40 : CPL_C_START
41 : void GDALRegister_SGI(void);
42 : CPL_C_END
43 :
44 : struct ImageRec
45 3316 : {
46 : GUInt16 imagic;
47 : GByte type;
48 : GByte bpc;
49 : GUInt16 dim;
50 : GUInt16 xsize;
51 : GUInt16 ysize;
52 : GUInt16 zsize;
53 : GUInt32 min;
54 : GUInt32 max;
55 : char wasteBytes[4];
56 : char name[80];
57 : GUInt32 colorMap;
58 :
59 : VSILFILE* file;
60 : std::string fileName;
61 : unsigned char* tmp;
62 : GUInt32 rleEnd;
63 : int rleTableDirty;
64 : GUInt32* rowStart;
65 : GInt32* rowSize;
66 :
67 3316 : ImageRec()
68 : : imagic(0),
69 : type(0),
70 : bpc(1),
71 : dim(0),
72 : xsize(0),
73 : ysize(0),
74 : zsize(0),
75 : min(0),
76 : max(0),
77 : colorMap(0),
78 : file(NULL),
79 : fileName(""),
80 : tmp(NULL),
81 : rleEnd(0),
82 : rleTableDirty(FALSE),
83 : rowStart(NULL),
84 3316 : rowSize(NULL)
85 : {
86 3316 : memset(wasteBytes, 0, 4);
87 3316 : memset(name, 0, 80);
88 3316 : }
89 :
90 3316 : void Swap()
91 : {
92 : #ifdef CPL_LSB
93 3316 : CPL_SWAP16PTR(&imagic);
94 3316 : CPL_SWAP16PTR(&dim);
95 3316 : CPL_SWAP16PTR(&xsize);
96 3316 : CPL_SWAP16PTR(&ysize);
97 3316 : CPL_SWAP16PTR(&zsize);
98 3316 : CPL_SWAP32PTR(&min);
99 3316 : CPL_SWAP32PTR(&max);
100 : #endif
101 3316 : }
102 : };
103 :
104 : /************************************************************************/
105 : /* ConvertLong() */
106 : /************************************************************************/
107 116 : static void ConvertLong(GUInt32* array, GInt32 length)
108 : {
109 : #ifdef CPL_LSB
110 : GUInt32* ptr;
111 116 : ptr = (GUInt32*)array;
112 14632 : while(length--)
113 14400 : CPL_SWAP32PTR(ptr++);
114 : #endif
115 116 : }
116 :
117 : /************************************************************************/
118 : /* ImageGetRow() */
119 : /************************************************************************/
120 180 : static CPLErr ImageGetRow(ImageRec* image, unsigned char* buf, int y, int z)
121 : {
122 : unsigned char *iPtr, *oPtr, pixel;
123 : int count;
124 :
125 180 : y = image->ysize - 1 - y;
126 :
127 180 : if(int(image->type) == 1)
128 : {
129 : // reads row
130 180 : VSIFSeekL(image->file, (long)image->rowStart[y+z*image->ysize], SEEK_SET);
131 180 : if(VSIFReadL(image->tmp, 1, (GUInt32)image->rowSize[y+z*image->ysize], image->file) != (GUInt32)image->rowSize[y+z*image->ysize])
132 : {
133 0 : CPLError(CE_Failure, CPLE_OpenFailed, "file read error: row (%d) of (%s)\n", y, image->fileName.empty() ? "none" : image->fileName.c_str());
134 0 : return CE_Failure;
135 : }
136 :
137 : // expands row
138 180 : iPtr = image->tmp;
139 180 : oPtr = buf;
140 180 : int xsizeCount = 0;
141 396 : for(;;)
142 : {
143 576 : pixel = *iPtr++;
144 576 : count = (int)(pixel & 0x7F);
145 576 : if(!count)
146 : {
147 180 : if(xsizeCount != image->xsize)
148 : {
149 0 : CPLError(CE_Failure, CPLE_OpenFailed, "file read error: row (%d) of (%s)\n", y, image->fileName.empty() ? "none" : image->fileName.c_str());
150 0 : return CE_Failure;
151 : }
152 : else
153 : {
154 180 : return CE_None;
155 : }
156 : }
157 :
158 396 : if( xsizeCount + count > image->xsize )
159 : {
160 0 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong repetition number that would overflow data at line %d", y);
161 0 : return CE_Failure;
162 : }
163 :
164 396 : if(pixel & 0x80)
165 : {
166 220 : memcpy(oPtr, iPtr, count);
167 220 : iPtr += count;
168 : }
169 : else
170 : {
171 176 : pixel = *iPtr++;
172 176 : memset(oPtr, pixel, count);
173 : }
174 396 : oPtr += count;
175 396 : xsizeCount += count;
176 : }
177 : }
178 : else
179 : {
180 0 : VSIFSeekL(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize), SEEK_SET);
181 0 : if(VSIFReadL(buf, 1, image->xsize, image->file) != image->xsize)
182 : {
183 0 : CPLError(CE_Failure, CPLE_OpenFailed, "file read error: row (%d) of (%s)\n", y, image->fileName.empty() ? "none" : image->fileName.c_str());
184 0 : return CE_Failure;
185 : }
186 : }
187 :
188 0 : return CE_None;
189 : }
190 :
191 : /************************************************************************/
192 : /* ==================================================================== */
193 : /* SGIDataset */
194 : /* ==================================================================== */
195 : /************************************************************************/
196 :
197 : class SGIRasterBand;
198 :
199 : class SGIDataset : public GDALPamDataset
200 : {
201 : friend class SGIRasterBand;
202 :
203 : VSILFILE* fpImage;
204 :
205 : int bGeoTransformValid;
206 : double adfGeoTransform[6];
207 :
208 : ImageRec image;
209 :
210 : public:
211 : SGIDataset();
212 : ~SGIDataset();
213 :
214 : virtual CPLErr GetGeoTransform(double*);
215 : static GDALDataset* Open(GDALOpenInfo*);
216 : static GDALDataset *Create( const char * pszFilename,
217 : int nXSize, int nYSize, int nBands,
218 : GDALDataType eType, char **papszOptions );
219 : };
220 :
221 : /************************************************************************/
222 : /* ==================================================================== */
223 : /* SGIRasterBand */
224 : /* ==================================================================== */
225 : /************************************************************************/
226 :
227 : class SGIRasterBand : public GDALPamRasterBand
228 104 : {
229 : friend class SGIDataset;
230 :
231 : public:
232 : SGIRasterBand(SGIDataset*, int);
233 :
234 : virtual CPLErr IReadBlock(int, int, void*);
235 : virtual CPLErr IWriteBlock(int, int, void*);
236 : virtual GDALColorInterp GetColorInterpretation();
237 : };
238 :
239 :
240 : /************************************************************************/
241 : /* SGIRasterBand() */
242 : /************************************************************************/
243 :
244 104 : SGIRasterBand::SGIRasterBand(SGIDataset* poDS, int nBand)
245 :
246 : {
247 104 : this->poDS = poDS;
248 104 : this->nBand = nBand;
249 104 : if(poDS == NULL)
250 : {
251 0 : eDataType = GDT_Byte;
252 : }
253 : else
254 : {
255 104 : if(int(poDS->image.bpc) == 1)
256 104 : eDataType = GDT_Byte;
257 : else
258 0 : eDataType = GDT_Int16;
259 : }
260 104 : nBlockXSize = poDS->nRasterXSize;;
261 104 : nBlockYSize = 1;
262 104 : }
263 :
264 : /************************************************************************/
265 : /* IReadBlock() */
266 : /************************************************************************/
267 :
268 180 : CPLErr SGIRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
269 : void* pImage)
270 :
271 : {
272 180 : SGIDataset* poGDS = (SGIDataset*) poDS;
273 :
274 180 : CPLAssert(nBlockXOff == 0);
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Load the desired data into the working buffer. */
278 : /* -------------------------------------------------------------------- */
279 180 : return ImageGetRow(&(poGDS->image), (unsigned char*)pImage, nBlockYOff, nBand-1);
280 : }
281 :
282 : /************************************************************************/
283 : /* IWritelock() */
284 : /************************************************************************/
285 :
286 440 : CPLErr SGIRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
287 : void* pImage)
288 :
289 : {
290 440 : SGIDataset* poGDS = (SGIDataset*) poDS;
291 440 : ImageRec *image = &(poGDS->image);
292 :
293 440 : CPLAssert(nBlockXOff == 0);
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Handle the fairly trivial non-RLE case. */
297 : /* -------------------------------------------------------------------- */
298 440 : if( image->type == 0 )
299 : {
300 : VSIFSeekL(image->file,
301 : 512 + (nBlockYOff*image->xsize)
302 : + ((nBand-1)*image->xsize*image->ysize ),
303 0 : SEEK_SET);
304 0 : if(VSIFWriteL(pImage, 1, image->xsize, image->file) != image->xsize)
305 : {
306 : CPLError(CE_Failure, CPLE_OpenFailed,
307 0 : "file write error: row (%d)\n", nBlockYOff );
308 0 : return CE_Failure;
309 : }
310 0 : return CE_None;
311 : }
312 :
313 : /* -------------------------------------------------------------------- */
314 : /* Handle RLE case. */
315 : /* -------------------------------------------------------------------- */
316 440 : const GByte *pabyRawBuf = (const GByte *) pImage;
317 440 : GByte *pabyRLEBuf = (GByte *) CPLMalloc(image->xsize * 2 + 6);
318 440 : int iX = 0, nRLEBytes = 0;
319 :
320 1496 : while( iX < image->xsize )
321 : {
322 616 : int nRepeatCount = 1;
323 :
324 13308 : while( iX + nRepeatCount < image->xsize
325 : && nRepeatCount < 127
326 8260 : && pabyRawBuf[iX + nRepeatCount] == pabyRawBuf[iX] )
327 3816 : nRepeatCount++;
328 :
329 1484 : if( nRepeatCount > 2
330 : || iX + nRepeatCount == image->xsize
331 : || (iX + nRepeatCount < image->xsize - 2
332 176 : && pabyRawBuf[iX + nRepeatCount + 1]
333 176 : == pabyRawBuf[iX + nRepeatCount + 2]
334 32 : && pabyRawBuf[iX + nRepeatCount + 1]
335 32 : == pabyRawBuf[iX + nRepeatCount + 3]) )
336 : { // encode a constant run.
337 452 : pabyRLEBuf[nRLEBytes++] = (GByte) nRepeatCount;
338 452 : pabyRLEBuf[nRLEBytes++] = pabyRawBuf[iX];
339 452 : iX += nRepeatCount;
340 : }
341 : else
342 : { // copy over mixed data.
343 164 : nRepeatCount = 1;
344 :
345 4544 : for( nRepeatCount = 1;
346 : iX + nRepeatCount < image->xsize && nRepeatCount < 127;
347 : nRepeatCount++ )
348 : {
349 4406 : if( iX + nRepeatCount + 3 >= image->xsize )
350 408 : continue;
351 :
352 : // quit if the next 3 pixels match
353 8360 : if( pabyRawBuf[iX + nRepeatCount]
354 3998 : == pabyRawBuf[iX + nRepeatCount+1]
355 182 : && pabyRawBuf[iX + nRepeatCount]
356 182 : == pabyRawBuf[iX + nRepeatCount+2] )
357 26 : break;
358 : }
359 :
360 164 : pabyRLEBuf[nRLEBytes++] = (GByte) (0x80 | nRepeatCount);
361 : memcpy( pabyRLEBuf + nRLEBytes,
362 : pabyRawBuf + iX,
363 164 : nRepeatCount );
364 :
365 164 : nRLEBytes += nRepeatCount;
366 164 : iX += nRepeatCount;
367 : }
368 : }
369 :
370 : // EOL marker.
371 440 : pabyRLEBuf[nRLEBytes++] = 0;
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* Write RLE Buffer at end of file. */
375 : /* -------------------------------------------------------------------- */
376 440 : int row = (image->ysize - nBlockYOff - 1) + (nBand-1) * image->ysize;
377 :
378 440 : VSIFSeekL(image->file, 0, SEEK_END );
379 :
380 440 : image->rowStart[row] = (GUInt32) VSIFTellL( image->file );
381 440 : image->rowSize[row] = nRLEBytes;
382 440 : image->rleTableDirty = TRUE;
383 :
384 440 : if( (int) VSIFWriteL(pabyRLEBuf, 1, nRLEBytes, image->file) != nRLEBytes )
385 : {
386 0 : CPLFree( pabyRLEBuf );
387 : CPLError(CE_Failure, CPLE_OpenFailed,
388 0 : "file write error: row (%d)\n", nBlockYOff );
389 0 : return CE_Failure;
390 : }
391 :
392 440 : CPLFree( pabyRLEBuf );
393 :
394 440 : return CE_None;
395 : }
396 :
397 : /************************************************************************/
398 : /* GetColorInterpretation() */
399 : /************************************************************************/
400 :
401 20 : GDALColorInterp SGIRasterBand::GetColorInterpretation()
402 :
403 : {
404 20 : SGIDataset* poGDS = (SGIDataset*)poDS;
405 :
406 20 : if(poGDS->nBands == 1)
407 2 : return GCI_GrayIndex;
408 18 : else if(poGDS->nBands == 2)
409 : {
410 2 : if(nBand == 1)
411 2 : return GCI_GrayIndex;
412 : else
413 0 : return GCI_AlphaBand;
414 : }
415 16 : else if(poGDS->nBands == 3)
416 : {
417 6 : if(nBand == 1)
418 2 : return GCI_RedBand;
419 4 : else if(nBand == 2)
420 2 : return GCI_GreenBand;
421 : else
422 2 : return GCI_BlueBand;
423 : }
424 10 : else if(poGDS->nBands == 4)
425 : {
426 8 : if(nBand == 1)
427 2 : return GCI_RedBand;
428 6 : else if(nBand == 2)
429 2 : return GCI_GreenBand;
430 4 : else if(nBand == 3)
431 2 : return GCI_BlueBand;
432 : else
433 2 : return GCI_AlphaBand;
434 : }
435 2 : return GCI_Undefined;
436 : }
437 :
438 : /************************************************************************/
439 : /* ==================================================================== */
440 : /* SGIDataset */
441 : /* ==================================================================== */
442 : /************************************************************************/
443 :
444 :
445 : /************************************************************************/
446 : /* SGIDataset() */
447 : /************************************************************************/
448 :
449 48 : SGIDataset::SGIDataset()
450 : : fpImage(NULL),
451 48 : bGeoTransformValid(FALSE)
452 : {
453 48 : adfGeoTransform[0] = 0.0;
454 48 : adfGeoTransform[1] = 1.0;
455 48 : adfGeoTransform[2] = 0.0;
456 48 : adfGeoTransform[3] = 0.0;
457 48 : adfGeoTransform[4] = 0.0;
458 48 : adfGeoTransform[5] = 1.0;
459 48 : }
460 :
461 : /************************************************************************/
462 : /* ~SGIDataset() */
463 : /************************************************************************/
464 :
465 48 : SGIDataset::~SGIDataset()
466 :
467 : {
468 48 : FlushCache();
469 :
470 : // Do we need to write out rle table?
471 48 : if( image.rleTableDirty )
472 : {
473 14 : CPLDebug( "SGI", "Flushing RLE offset table." );
474 14 : ConvertLong( image.rowStart, image.ysize * image.zsize );
475 14 : ConvertLong( (GUInt32 *) image.rowSize, image.ysize * image.zsize );
476 :
477 14 : VSIFSeekL( fpImage, 512, SEEK_SET );
478 14 : VSIFWriteL( image.rowStart, 4, image.ysize * image.zsize, fpImage );
479 14 : VSIFWriteL( image.rowSize, 4, image.ysize * image.zsize, fpImage );
480 14 : image.rleTableDirty = FALSE;
481 : }
482 :
483 48 : if(fpImage != NULL)
484 48 : VSIFCloseL(fpImage);
485 :
486 48 : CPLFree(image.tmp);
487 48 : CPLFree(image.rowSize);
488 48 : CPLFree(image.rowStart);
489 48 : }
490 :
491 : /************************************************************************/
492 : /* GetGeoTransform() */
493 : /************************************************************************/
494 :
495 10 : CPLErr SGIDataset::GetGeoTransform(double * padfTransform)
496 :
497 : {
498 10 : if(bGeoTransformValid)
499 : {
500 0 : memcpy(padfTransform, adfGeoTransform, sizeof(double)*6);
501 :
502 0 : return CE_None;
503 : }
504 : else
505 10 : return GDALPamDataset::GetGeoTransform(padfTransform);
506 : }
507 :
508 : /************************************************************************/
509 : /* Open() */
510 : /************************************************************************/
511 :
512 25572 : GDALDataset* SGIDataset::Open(GDALOpenInfo* poOpenInfo)
513 :
514 : {
515 : /* -------------------------------------------------------------------- */
516 : /* First we check to see if the file has the expected header */
517 : /* bytes. */
518 : /* -------------------------------------------------------------------- */
519 25572 : if(poOpenInfo->nHeaderBytes < 12)
520 22304 : return NULL;
521 :
522 3268 : ImageRec tmpImage;
523 3268 : memcpy(&tmpImage, poOpenInfo->pabyHeader, 12);
524 3268 : tmpImage.Swap();
525 :
526 3268 : if(tmpImage.imagic != 474)
527 3220 : return NULL;
528 :
529 48 : if (tmpImage.type != 0 && tmpImage.type != 1)
530 0 : return NULL;
531 :
532 48 : if (tmpImage.bpc != 1 && tmpImage.bpc != 2)
533 0 : return NULL;
534 :
535 48 : if (tmpImage.dim != 1 && tmpImage.dim != 2 && tmpImage.dim != 3)
536 0 : return NULL;
537 :
538 48 : if(tmpImage.bpc != 1)
539 : {
540 : CPLError(CE_Failure, CPLE_NotSupported,
541 0 : "The SGI driver only supports 1 byte channel values.\n");
542 0 : return NULL;
543 : }
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* Create a corresponding GDALDataset. */
547 : /* -------------------------------------------------------------------- */
548 : SGIDataset* poDS;
549 :
550 48 : poDS = new SGIDataset();
551 48 : poDS->eAccess = poOpenInfo->eAccess;
552 :
553 : /* -------------------------------------------------------------------- */
554 : /* Open the file using the large file api. */
555 : /* -------------------------------------------------------------------- */
556 48 : if( poDS->eAccess == GA_ReadOnly )
557 22 : poDS->fpImage = VSIFOpenL(poOpenInfo->pszFilename, "rb");
558 : else
559 26 : poDS->fpImage = VSIFOpenL(poOpenInfo->pszFilename, "rb+");
560 48 : if(poDS->fpImage == NULL)
561 : {
562 : CPLError(CE_Failure, CPLE_OpenFailed,
563 : "VSIFOpenL(%s) failed unexpectedly in sgidataset.cpp\n%s",
564 : poOpenInfo->pszFilename,
565 0 : VSIStrerror( errno ) );
566 0 : delete poDS;
567 0 : return NULL;
568 : }
569 :
570 : /* -------------------------------------------------------------------- */
571 : /* Read pre-image data after ensuring the file is rewound. */
572 : /* -------------------------------------------------------------------- */
573 48 : VSIFSeekL(poDS->fpImage, 0, SEEK_SET);
574 48 : if(VSIFReadL((void*)(&(poDS->image)), 1, 12, poDS->fpImage) != 12)
575 : {
576 0 : CPLError(CE_Failure, CPLE_OpenFailed, "file read error while reading header in sgidataset.cpp");
577 0 : delete poDS;
578 0 : return NULL;
579 : }
580 48 : poDS->image.Swap();
581 48 : poDS->image.file = poDS->fpImage;
582 48 : poDS->image.fileName = poOpenInfo->pszFilename;
583 :
584 : /* -------------------------------------------------------------------- */
585 : /* Capture some information from the file that is of interest. */
586 : /* -------------------------------------------------------------------- */
587 48 : poDS->nRasterXSize = poDS->image.xsize;
588 48 : poDS->nRasterYSize = poDS->image.ysize;
589 48 : if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
590 : {
591 : CPLError(CE_Failure, CPLE_OpenFailed,
592 0 : "Invalid image dimensions : %d x %d", poDS->nRasterXSize, poDS->nRasterYSize);
593 0 : delete poDS;
594 0 : return NULL;
595 : }
596 48 : poDS->nBands = MAX(1,poDS->image.zsize);
597 48 : if (poDS->nBands > 256)
598 : {
599 : CPLError(CE_Failure, CPLE_OpenFailed,
600 0 : "Too many bands : %d", poDS->nBands);
601 0 : delete poDS;
602 0 : return NULL;
603 : }
604 :
605 48 : int numItems = (int(poDS->image.bpc) == 1) ? 256 : 65536;
606 48 : poDS->image.tmp = (unsigned char*)VSICalloc(poDS->image.xsize,numItems);
607 48 : if (poDS->image.tmp == NULL)
608 : {
609 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
610 0 : delete poDS;
611 0 : return NULL;
612 : }
613 :
614 : /* -------------------------------------------------------------------- */
615 : /* Read RLE Pointer tables. */
616 : /* -------------------------------------------------------------------- */
617 48 : if(int(poDS->image.type) == 1) // RLE compressed
618 : {
619 48 : int x = poDS->image.ysize * poDS->nBands * sizeof(GUInt32);
620 48 : poDS->image.rowStart = (GUInt32*)VSIMalloc2(poDS->image.ysize, poDS->nBands * sizeof(GUInt32));
621 48 : poDS->image.rowSize = (GInt32*)VSIMalloc2(poDS->image.ysize, poDS->nBands * sizeof(GUInt32));
622 48 : if (poDS->image.rowStart == NULL || poDS->image.rowSize == NULL)
623 : {
624 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
625 0 : delete poDS;
626 0 : return NULL;
627 : }
628 48 : memset(poDS->image.rowStart, 0, x);
629 48 : memset(poDS->image.rowSize, 0, x);
630 48 : poDS->image.rleEnd = 512 + (2 * x);
631 48 : VSIFSeekL(poDS->fpImage, 512, SEEK_SET);
632 48 : if((int) VSIFReadL(poDS->image.rowStart, 1, x, poDS->image.file) != x)
633 : {
634 4 : delete poDS;
635 : CPLError(CE_Failure, CPLE_OpenFailed,
636 4 : "file read error while reading start positions in sgidataset.cpp");
637 4 : return NULL;
638 : }
639 44 : if((int) VSIFReadL(poDS->image.rowSize, 1, x, poDS->image.file) != x)
640 : {
641 0 : delete poDS;
642 : CPLError(CE_Failure, CPLE_OpenFailed,
643 0 : "file read error while reading row lengths in sgidataset.cpp");
644 0 : return NULL;
645 : }
646 44 : ConvertLong(poDS->image.rowStart, x/(int)sizeof(GUInt32));
647 44 : ConvertLong((GUInt32*)poDS->image.rowSize, x/(int)sizeof(GInt32));
648 : }
649 : else // uncompressed.
650 : {
651 0 : poDS->image.rowStart = NULL;
652 0 : poDS->image.rowSize = NULL;
653 : }
654 :
655 : /* -------------------------------------------------------------------- */
656 : /* Create band information objects. */
657 : /* -------------------------------------------------------------------- */
658 148 : for(int iBand = 0; iBand < poDS->nBands; iBand++)
659 104 : poDS->SetBand(iBand+1, new SGIRasterBand(poDS, iBand+1));
660 :
661 : /* -------------------------------------------------------------------- */
662 : /* Check for world file. */
663 : /* -------------------------------------------------------------------- */
664 : poDS->bGeoTransformValid =
665 : GDALReadWorldFile(poOpenInfo->pszFilename, ".wld",
666 44 : poDS->adfGeoTransform);
667 :
668 : /* -------------------------------------------------------------------- */
669 : /* Initialize any PAM information. */
670 : /* -------------------------------------------------------------------- */
671 44 : poDS->SetDescription(poOpenInfo->pszFilename);
672 44 : poDS->TryLoadXML();
673 :
674 : /* -------------------------------------------------------------------- */
675 : /* Check for overviews. */
676 : /* -------------------------------------------------------------------- */
677 44 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
678 :
679 44 : return poDS;
680 : }
681 :
682 : /************************************************************************/
683 : /* Create() */
684 : /************************************************************************/
685 :
686 90 : GDALDataset *SGIDataset::Create( const char * pszFilename,
687 : int nXSize, int nYSize, int nBands,
688 : GDALDataType eType, char **papszOptions )
689 :
690 : {
691 90 : if( eType != GDT_Byte )
692 : {
693 : CPLError( CE_Failure, CPLE_AppDefined,
694 : "Attempt to create SGI dataset with an illegal\n"
695 : "data type (%s), only Byte supported by the format.\n",
696 60 : GDALGetDataTypeName(eType) );
697 :
698 60 : return NULL;
699 : }
700 :
701 : /* -------------------------------------------------------------------- */
702 : /* Open the file for output. */
703 : /* -------------------------------------------------------------------- */
704 30 : VSILFILE *fp = VSIFOpenL( pszFilename, "w" );
705 30 : if( fp == NULL )
706 : {
707 : CPLError( CE_Failure, CPLE_OpenFailed,
708 : "Failed to create file '%s': %s",
709 4 : pszFilename, VSIStrerror( errno ) );
710 4 : return NULL;
711 : }
712 :
713 : /* -------------------------------------------------------------------- */
714 : /* Prepare and write 512 byte header. */
715 : /* -------------------------------------------------------------------- */
716 : GByte abyHeader[512];
717 : GInt16 nShortValue;
718 : GInt32 nIntValue;
719 :
720 26 : memset( abyHeader, 0, 512 );
721 :
722 26 : abyHeader[0] = 1;
723 26 : abyHeader[1] = 218;
724 26 : abyHeader[2] = 1; // RLE
725 26 : abyHeader[3] = 1; // 8bit
726 :
727 26 : if( nBands == 1 )
728 8 : nShortValue = CPL_MSBWORD16(2);
729 : else
730 18 : nShortValue = CPL_MSBWORD16(3);
731 26 : memcpy( abyHeader + 4, &nShortValue, 2 );
732 :
733 26 : nShortValue = CPL_MSBWORD16(nXSize);
734 26 : memcpy( abyHeader + 6, &nShortValue, 2 );
735 :
736 26 : nShortValue = CPL_MSBWORD16(nYSize);
737 26 : memcpy( abyHeader + 8, &nShortValue, 2 );
738 :
739 26 : nShortValue = CPL_MSBWORD16(nBands);
740 26 : memcpy( abyHeader + 10, &nShortValue, 2 );
741 :
742 26 : nIntValue = CPL_MSBWORD32(0);
743 26 : memcpy( abyHeader + 12, &nIntValue, 4 );
744 :
745 26 : nIntValue = CPL_MSBWORD32(255);
746 26 : memcpy( abyHeader + 16, &nIntValue, 4 );
747 :
748 26 : VSIFWriteL( abyHeader, 1, 512, fp );
749 :
750 : /* -------------------------------------------------------------------- */
751 : /* Create our RLE compressed zero-ed dummy line. */
752 : /* -------------------------------------------------------------------- */
753 : GByte *pabyRLELine;
754 26 : GInt32 nRLEBytes = 0;
755 26 : int nPixelsRemaining = nXSize;
756 :
757 26 : pabyRLELine = (GByte *) CPLMalloc((nXSize/127) * 2 + 4);
758 :
759 78 : while( nPixelsRemaining > 0 )
760 : {
761 26 : pabyRLELine[nRLEBytes] = (GByte) MIN(127,nPixelsRemaining);
762 26 : pabyRLELine[nRLEBytes+1] = 0;
763 26 : nPixelsRemaining -= pabyRLELine[nRLEBytes];
764 :
765 26 : nRLEBytes += 2;
766 : }
767 :
768 : /* -------------------------------------------------------------------- */
769 : /* Prepare and write RLE offset/size tables with everything */
770 : /* zeroed indicating dummy lines. */
771 : /* -------------------------------------------------------------------- */
772 : int i;
773 26 : int nTableLen = nYSize * nBands;
774 26 : GInt32 nDummyRLEOffset = 512 + 4 * nTableLen * 2;
775 :
776 26 : CPL_MSBPTR32( &nRLEBytes );
777 26 : CPL_MSBPTR32( &nDummyRLEOffset );
778 :
779 3466 : for( i = 0; i < nTableLen; i++ )
780 3440 : VSIFWriteL( &nDummyRLEOffset, 1, 4, fp );
781 :
782 3466 : for( i = 0; i < nTableLen; i++ )
783 3440 : VSIFWriteL( &nRLEBytes, 1, 4, fp );
784 :
785 : /* -------------------------------------------------------------------- */
786 : /* write the dummy RLE blank line. */
787 : /* -------------------------------------------------------------------- */
788 26 : CPL_MSBPTR32( &nRLEBytes );
789 26 : if( (GInt32) VSIFWriteL( pabyRLELine, 1, nRLEBytes, fp ) != nRLEBytes )
790 : {
791 : CPLError( CE_Failure, CPLE_FileIO,
792 : "Failure writing SGI file '%s'.\n%s",
793 : pszFilename,
794 0 : VSIStrerror( errno ) );
795 0 : return NULL;
796 : }
797 :
798 26 : VSIFCloseL( fp );
799 26 : CPLFree( pabyRLELine );
800 :
801 26 : return (GDALDataset*) GDALOpen( pszFilename, GA_Update );
802 : }
803 :
804 : /************************************************************************/
805 : /* GDALRegister_SGI() */
806 : /************************************************************************/
807 :
808 1135 : void GDALRegister_SGI()
809 :
810 : {
811 : GDALDriver* poDriver;
812 :
813 1135 : if(GDALGetDriverByName("SGI") == NULL)
814 : {
815 1093 : poDriver = new GDALDriver();
816 :
817 1093 : poDriver->SetDescription("SGI");
818 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
819 1093 : "SGI Image File Format 1.0");
820 1093 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rgb");
821 1093 : poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/rgb");
822 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
823 1093 : "frmt_various.html#SGI" );
824 1093 : poDriver->pfnOpen = SGIDataset::Open;
825 1093 : poDriver->pfnCreate = SGIDataset::Create;
826 1093 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" );
827 1093 : GetGDALDriverManager()->RegisterDriver(poDriver);
828 : }
829 1135 : }
830 :
|