~ubuntu-branches/ubuntu/lucid/thuban/lucid

« back to all changes in this revision

Viewing changes to libraries/thuban/bmpdataset.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Francesco Paolo Lovergine
  • Date: 2007-04-07 21:03:28 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070407210328-9a20n4dmbim3c3yc
Tags: 1.2.0-1
* New upstream release.
* Patchset updated.
* Policy bumped to 3.7.2 (no changes).
* Updated for current Python Policy by using python-support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************************************
2
 
 * $Id: bmpdataset.cpp,v 1.1 2003/08/19 21:32:24 jan Exp $
3
 
 *
4
 
 * Project:  Microsoft Windows Bitmap
5
 
 * Purpose:  Read/write MS Windows Device Independent Bitmap (DIB) files
6
 
 *           and OS/2 Presentation Manager bitmaps v. 1.x and v. 2.x
7
 
 * Author:   Andrey Kiselev, dron@remotesensing.org
8
 
 *
9
 
 ******************************************************************************
10
 
 * Copyright (c) 2002, Andrey Kiselev <dron@remotesensing.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
 
 * $Log: bmpdataset.cpp,v $
32
 
 * Revision 1.1  2003/08/19 21:32:24  jan
33
 
 * These files have been moved here from thuban/extensions/thuban/
34
 
 * See there in the Attic for the older history.
35
 
 *
36
 
 * Revision 1.2  2003/06/17 15:25:06  jonathan
37
 
 * (BMPDataset::Open): Call VSIFClose() not VSIFCloseL() to close the file.
38
 
 *         Fixes a crash under Windows.
39
 
 *
40
 
 * Revision 1.1  2003/05/20 15:25:45  jonathan
41
 
 * New, but copied from GDAL.  Provides a driver to output in .bmp format.
42
 
 *
43
 
 * Revision 1.19  2003/05/01 17:40:43  dron
44
 
 * Report colour interpretation GCI_PaletteIndex for 1-bit images.
45
 
 *
46
 
 * Revision 1.18  2003/03/27 15:51:06  dron
47
 
 * Improvements in update state handling in IReadBlock().
48
 
 *
49
 
 * Revision 1.17  2003/03/27 13:24:53  dron
50
 
 * Fixes for large file support.
51
 
 *
52
 
 * Revision 1.16  2003/02/15 14:23:09  dron
53
 
 * Fix in GetGeoTransform().
54
 
 *
55
 
 * Revision 1.15  2003/02/03 18:40:15  dron
56
 
 * Type of input data checked in Create() method now.
57
 
 *
58
 
 * Revision 1.14  2002/12/15 15:24:41  dron
59
 
 * Typos fixed.
60
 
 *
61
 
 * Revision 1.13  2002/12/15 15:13:33  dron
62
 
 * BMP structures extended.
63
 
 *
64
 
 * Revision 1.12  2002/12/13 14:15:50  dron
65
 
 * IWriteBlock() fixed, CreateCopy() removed, added RLE4 decoding and OS/2 BMP
66
 
 * support.
67
 
 *
68
 
 * Revision 1.11  2002/12/11 22:09:13  warmerda
69
 
 * Re-enable createcopy.
70
 
 *
71
 
 * Revision 1.10  2002/12/11 22:08:20  warmerda
72
 
 * fixed multiband support for writing ... open wit wb+ in create
73
 
 *
74
 
 * Revision 1.9  2002/12/11 16:13:04  dron
75
 
 * Support for 16-bit RGB images (untested).
76
 
 *
77
 
 * Revision 1.8  2002/12/10 22:12:59  dron
78
 
 * RLE8 decoding added.
79
 
 *
80
 
 * Revision 1.7  2002/12/09 19:31:44  dron
81
 
 * Switched to CPL_LSBWORD32 macro.
82
 
 *
83
 
 * Revision 1.6  2002/12/07 15:20:23  dron
84
 
 * SetColorTable() added. Create() really works now.
85
 
 *
86
 
 * Revision 1.5  2002/12/06 20:50:13  warmerda
87
 
 * fixed type warning
88
 
 *
89
 
 * Revision 1.4  2002/12/06 18:37:05  dron
90
 
 * Create() method added, 1- and 4-bpp images readed now.
91
 
 *
92
 
 * Revision 1.3  2002/12/05 19:25:35  dron
93
 
 * Preliminary CreateCopy() function.
94
 
 *
95
 
 * Revision 1.2  2002/12/04 18:37:49  dron
96
 
 * Support 32-bit, 24-bit True Color images and 8-bit pseudocolor ones.
97
 
 *
98
 
 * Revision 1.1  2002/12/03 19:04:18  dron
99
 
 * Initial version.
100
 
 *
101
 
 */
102
 
 
103
 
#include "gdal_priv.h"
104
 
#include "cpl_string.h"
105
 
#include "cpl_mfile.h"
106
 
 
107
 
CPL_CVSID("$Id: bmpdataset.cpp,v 1.1 2003/08/19 21:32:24 jan Exp $");
108
 
 
109
 
CPL_C_START
110
 
void    GDALRegister_THUBANBMP(void);
111
 
CPL_C_END
112
 
 
113
 
enum BMPType
114
 
{
115
 
    BMPT_WIN4,      // BMP used in Windows 3.0/NT 3.51/95
116
 
    BMPT_WIN5,      // BMP used in Windows NT 4.0/98/Me/2000/XP
117
 
    BMPT_OS21,      // BMP used in OS/2 PM 1.x
118
 
    BMPT_OS22       // BMP used in OS/2 PM 2.x
119
 
};
120
 
 
121
 
// Bitmap file consists of a BitmapFileHeader structure followed by
122
 
// a BitmapInfoHeader structure. An array of BMPColorEntry structures (also
123
 
// called a colour table) follows the bitmap information header structure. The
124
 
// colour table is followed by a second array of indexes into the colour table
125
 
// (the actual bitmap data). Data may be comressed, for 4-bpp and 8-bpp used
126
 
// RLE compression.
127
 
//
128
 
// +---------------------+
129
 
// | BitmapFileHeader    |
130
 
// +---------------------+
131
 
// | BitmapInfoHeader    |
132
 
// +---------------------+
133
 
// | BMPColorEntry array |
134
 
// +---------------------+
135
 
// | Colour-index array  |
136
 
// +---------------------+
137
 
//
138
 
// All numbers stored in Intel order with least significant byte first.
139
 
 
140
 
enum BMPComprMethod
141
 
{
142
 
    BMPC_RGB = 0L,              // Uncompressed
143
 
    BMPC_RLE8 = 1L,             // RLE for 8 bpp images
144
 
    BMPC_RLE4 = 2L,             // RLE for 4 bpp images
145
 
    BMPC_BITFIELDS = 3L,        // Bitmap is not compressed and the colour table
146
 
                                // consists of three DWORD color masks that specify
147
 
                                // the red, green, and blue components of each pixel.
148
 
                                // This is valid when used with 16- and 32-bpp bitmaps.
149
 
    BMPC_JPEG = 4L,             // Indicates that the image is a JPEG image.
150
 
    BMPC_PNG = 5L               // Indicates that the image is a PNG image.
151
 
};
152
 
 
153
 
enum BMPLCSType                 // Type of logical color space.
154
 
{
155
 
    BMPLT_CALIBRATED_RGB = 0,   // This value indicates that endpoints and gamma
156
 
                                // values are given in the appropriate fields.
157
 
    BMPLT_DEVICE_RGB = 1,
158
 
    BMPLT_DEVICE_CMYK = 2,
159
 
};
160
 
 
161
 
typedef struct
162
 
{
163
 
    GInt32      iCIEX;
164
 
    GInt32      iCIEY;
165
 
    GInt32      iCIEZ;
166
 
} BMPCIEXYZ;
167
 
 
168
 
typedef struct                  // This structure contains the x, y, and z
169
 
{                               // coordinates of the three colors that correspond
170
 
    BMPCIEXYZ   iCIERed;        // to the red, green, and blue endpoints for
171
 
    BMPCIEXYZ   iCIEGreen;      // a specified logical color space.
172
 
    BMPCIEXYZ   iCIEBlue;
173
 
} BMPCIEXYZTriple;
174
 
 
175
 
typedef struct
176
 
{
177
 
    GByte       bType[2];       // Signature "BM"
178
 
    GUInt32     iSize;          // Size in bytes of the bitmap file. Should always
179
 
                                // be ignored while reading because of error
180
 
                                // in Windows 3.0 SDK's description of this field
181
 
    GUInt16     iReserved1;     // Reserved, set as 0
182
 
    GUInt16     iReserved2;     // Reserved, set as 0
183
 
    GUInt32     iOffBits;       // Offset of the image from file start in bytes
184
 
} BitmapFileHeader;
185
 
const int       BFH_SIZE = 14;
186
 
 
187
 
typedef struct
188
 
{
189
 
    GUInt32     iSize;          // Size of BitmapInfoHeader structure in bytes.
190
 
                                // Should be used to determine start of the
191
 
                                // colour table
192
 
    GInt32      iWidth;         // Image width
193
 
    GInt32      iHeight;        // Image height. If positive, image has bottom left
194
 
                                // origin, if negative --- top left.
195
 
    GUInt16     iPlanes;        // Number of image planes (must be set to 1)
196
 
    GUInt16     iBitCount;      // Number of bits per pixel (1, 4, 8, 16, 24 or 32).
197
 
                                // If 0 then the number of bits per pixel is
198
 
                                // specified or is implied by the JPEG or PNG format.
199
 
    BMPComprMethod iCompression; // Compression method
200
 
    GUInt32     iSizeImage;     // Size of uncomressed image in bytes. May be 0
201
 
                                // for BMPC_RGB bitmaps. If iCompression is BI_JPEG
202
 
                                // or BI_PNG, iSizeImage indicates the size
203
 
                                // of the JPEG or PNG image buffer.
204
 
    GInt32      iXPelsPerMeter; // X resolution, pixels per meter (0 if not used)
205
 
    GInt32      iYPelsPerMeter; // Y resolution, pixels per meter (0 if not used)
206
 
    GUInt32     iClrUsed;       // Size of colour table. If 0, iBitCount should
207
 
                                // be used to calculate this value (1<<iBitCount)
208
 
    GUInt32     iClrImportant;  // Number of important colours. If 0, all
209
 
                                // colours are required
210
 
 
211
 
    // Fields above should be used for bitmaps, compatible with Windows NT 3.51
212
 
    // and earlier. Windows 98/Me, Windows 2000/XP introduces additional fields:
213
 
 
214
 
    GUInt32     iRedMask;       // Colour mask that specifies the red component
215
 
                                // of each pixel, valid only if iCompression
216
 
                                // is set to BI_BITFIELDS.
217
 
    GUInt32     iGreenMask;     // The same for green component
218
 
    GUInt32     iBlueMask;      // The same for blue component
219
 
    GUInt32     iAlphaMask;     // Colour mask that specifies the alpha
220
 
                                // component of each pixel.
221
 
    BMPLCSType  iCSType;        // Colour space of the DIB.
222
 
    BMPCIEXYZTriple sEndpoints; // This member is ignored unless the iCSType member
223
 
                                // specifies BMPLT_CALIBRATED_RGB.
224
 
    GUInt32     iGammaRed;      // Toned response curve for red. This member
225
 
                                // is ignored unless color values are calibrated
226
 
                                // RGB values and iCSType is set to
227
 
                                // BMPLT_CALIBRATED_RGB. Specified in 16^16 format.
228
 
    GUInt32     iGammaGreen;    // Toned response curve for green.
229
 
    GUInt32     iGammaBlue;     // Toned response curve for blue.
230
 
} BitmapInfoHeader;
231
 
const unsigned int  BIH_WIN4SIZE = 40; // For BMPT_WIN4
232
 
const unsigned int  BIH_WIN5SIZE = 57; // For BMPT_WIN5
233
 
const unsigned int  BIH_OS21SIZE = 12; // For BMPT_OS21
234
 
const unsigned int  BIH_OS22SIZE = 64; // For BMPT_OS22
235
 
 
236
 
// We will use plain byte array instead of this structure, but declaration
237
 
// provided for reference
238
 
typedef struct
239
 
{
240
 
    GByte       bBlue;
241
 
    GByte       bGreen;
242
 
    GByte       bRed;
243
 
    GByte       bReserved;      // Must be 0
244
 
} BMPColorEntry;
245
 
 
246
 
/************************************************************************/
247
 
/* ==================================================================== */
248
 
/*                              BMPDataset                              */
249
 
/* ==================================================================== */
250
 
/************************************************************************/
251
 
 
252
 
class BMPDataset : public GDALDataset
253
 
{
254
 
    friend class BMPRasterBand;
255
 
    friend class BMPComprRasterBand;
256
 
 
257
 
    BitmapFileHeader    sFileHeader;
258
 
    BitmapInfoHeader    sInfoHeader;
259
 
    int                 nColorTableSize, nColorElems;
260
 
    GByte               *pabyColorTable;
261
 
    GDALColorTable      *poColorTable;
262
 
    double              adfGeoTransform[6];
263
 
    int                 bGeoTransformValid;
264
 
    char                *pszProjection;
265
 
 
266
 
    const char          *pszFilename;
267
 
    MFILE               *fp;
268
 
 
269
 
  public:
270
 
                BMPDataset();
271
 
                ~BMPDataset();
272
 
 
273
 
    static GDALDataset  *Open( GDALOpenInfo * );
274
 
    static GDALDataset  *Create( const char * pszFilename,
275
 
                                int nXSize, int nYSize, int nBands,
276
 
                                GDALDataType eType, char ** papszParmList );
277
 
    virtual void        FlushCache( void );
278
 
 
279
 
    CPLErr              GetGeoTransform( double * padfTransform );
280
 
    virtual CPLErr      SetGeoTransform( double * );
281
 
    const char          *GetProjectionRef();
282
 
};
283
 
 
284
 
/************************************************************************/
285
 
/* ==================================================================== */
286
 
/*                            BMPRasterBand                             */
287
 
/* ==================================================================== */
288
 
/************************************************************************/
289
 
 
290
 
class BMPRasterBand : public GDALRasterBand
291
 
{
292
 
    friend class BMPDataset;
293
 
 
294
 
  protected:
295
 
 
296
 
    GUInt32    nScanSize;
297
 
    unsigned int    iBytesPerPixel;
298
 
    GByte           *pabyScan;
299
 
 
300
 
  public:
301
 
 
302
 
                BMPRasterBand( BMPDataset *, int );
303
 
                ~BMPRasterBand();
304
 
 
305
 
    virtual CPLErr          IReadBlock( int, int, void * );
306
 
    virtual CPLErr          IWriteBlock( int, int, void * );
307
 
    virtual GDALColorInterp GetColorInterpretation();
308
 
    virtual GDALColorTable  *GetColorTable();
309
 
    CPLErr                  SetColorTable( GDALColorTable * );
310
 
};
311
 
 
312
 
 
313
 
/************************************************************************/
314
 
/*                           BMPRasterBand()                            */
315
 
/************************************************************************/
316
 
 
317
 
BMPRasterBand::BMPRasterBand( BMPDataset *poDS, int nBand )
318
 
{
319
 
    this->poDS = poDS;
320
 
    this->nBand = nBand;
321
 
    eDataType = GDT_Byte;
322
 
    iBytesPerPixel = poDS->sInfoHeader.iBitCount / 8;
323
 
 
324
 
    // We will read one scanline per time. Scanlines in BMP aligned at 4-byte
325
 
    // boundary
326
 
    nBlockXSize = poDS->GetRasterXSize();
327
 
    nScanSize =
328
 
        ((poDS->GetRasterXSize() * poDS->sInfoHeader.iBitCount + 31) & ~31) / 8;
329
 
    nBlockYSize = 1;
330
 
 
331
 
    CPLDebug( "BMP", "Band %d: set nBlockXSize=%d, nBlockYSize=%d, nScanSize=%d",
332
 
              nBand, nBlockXSize, nBlockYSize, nScanSize );
333
 
 
334
 
    pabyScan = (GByte *) CPLMalloc( nScanSize * nBlockYSize );
335
 
}
336
 
 
337
 
/************************************************************************/
338
 
/*                           ~BMPRasterBand()                           */
339
 
/************************************************************************/
340
 
 
341
 
BMPRasterBand::~BMPRasterBand()
342
 
{
343
 
    CPLFree( pabyScan );
344
 
}
345
 
 
346
 
/************************************************************************/
347
 
/*                             IReadBlock()                             */
348
 
/************************************************************************/
349
 
 
350
 
CPLErr BMPRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
351
 
                                  void * pImage )
352
 
{
353
 
    BMPDataset  *poGDS = (BMPDataset *) poDS;
354
 
    GUInt32     iScanOffset;
355
 
    int         i, j;
356
 
    int         nBlockSize = nBlockXSize * nBlockYSize;
357
 
 
358
 
    if ( poGDS->sInfoHeader.iHeight > 0 )
359
 
        iScanOffset = poGDS->sFileHeader.iSize - (nBlockYOff + 1) * nScanSize;
360
 
    else
361
 
        iScanOffset = poGDS->sFileHeader.iOffBits + nBlockYOff * nScanSize;
362
 
 
363
 
    if ( MFILESeek( poGDS->fp, iScanOffset, SEEK_SET ) < 0 )
364
 
    {
365
 
        // XXX: We will not report error here, because file just may be
366
 
        // in update state and data for this block will be available later
367
 
        if( poGDS->eAccess == GA_Update )
368
 
        {
369
 
            memset( pImage, 0, nBlockSize );
370
 
            return CE_None;
371
 
        }
372
 
        else
373
 
        {
374
 
            CPLError( CE_Failure, CPLE_FileIO,
375
 
                      "Can't seek to offset %ld in input file to read data.",
376
 
                      iScanOffset );
377
 
            return CE_Failure;
378
 
        }
379
 
    }
380
 
    if ( MFILERead( pabyScan, 1, nScanSize, poGDS->fp ) < nScanSize )
381
 
    {
382
 
        // XXX
383
 
        if( poGDS->eAccess == GA_Update )
384
 
        {
385
 
            memset( pImage, 0, nBlockSize );
386
 
            return CE_None;
387
 
        }
388
 
        else
389
 
        {
390
 
            CPLError( CE_Failure, CPLE_FileIO,
391
 
                      "Can't read from offset %ld in input file.", iScanOffset );
392
 
            return CE_Failure;
393
 
        }
394
 
    }
395
 
 
396
 
    if ( poGDS->sInfoHeader.iBitCount == 8  ||
397
 
         poGDS->sInfoHeader.iBitCount == 24 ||
398
 
         poGDS->sInfoHeader.iBitCount == 32 )
399
 
    {
400
 
        for ( i = 0, j = 0; i < nBlockSize; i++ )
401
 
        {
402
 
            // Colour triplets in BMP file organized in reverse order:
403
 
            // blue, green, red
404
 
            ((GByte *) pImage)[i] = pabyScan[j + iBytesPerPixel - nBand];
405
 
            j += iBytesPerPixel;
406
 
        }
407
 
    }
408
 
    if ( poGDS->sInfoHeader.iBitCount == 16 )
409
 
    {
410
 
        for ( i = 0, j = 0; i < nBlockSize; i++ )
411
 
        {
412
 
            switch ( nBand )
413
 
            {
414
 
                case 1:
415
 
                ((GByte *) pImage)[i] = pabyScan[i + 1] & 0x1F;
416
 
                break;
417
 
                case 2:
418
 
                ((GByte *) pImage)[i] = ((pabyScan[i] & 0x03) << 3) |
419
 
                                        ((pabyScan[i + 1] & 0xE0) >> 5);
420
 
                break;
421
 
                case 3:
422
 
                ((GByte *) pImage)[i] = (pabyScan[i] & 0x7c) >> 2;
423
 
                break;
424
 
                default:
425
 
                break;
426
 
            }
427
 
        }
428
 
    }
429
 
    else if ( poGDS->sInfoHeader.iBitCount == 4 )
430
 
    {
431
 
        for ( i = 0, j = 0; i < nBlockSize; i++ )
432
 
        {
433
 
            // Most significant part of the byte represents leftmost pixel
434
 
            if ( i & 0x01 )
435
 
                ((GByte *) pImage)[i] = pabyScan[j++] & 0x0F;
436
 
            else
437
 
                ((GByte *) pImage)[i] = (pabyScan[j] & 0xF0) >> 4;
438
 
        }
439
 
    }
440
 
    else if ( poGDS->sInfoHeader.iBitCount == 1 )
441
 
    {
442
 
        for ( i = 0, j = 0; i < nBlockSize; i++ )
443
 
        {
444
 
            switch ( i & 0x7 )
445
 
            {
446
 
                case 0:
447
 
                ((GByte *) pImage)[i] = (pabyScan[j] & 0x80) >> 7;
448
 
                break;
449
 
                case 1:
450
 
                ((GByte *) pImage)[i] = (pabyScan[j] & 0x40) >> 6;
451
 
                break;
452
 
                case 2:
453
 
                ((GByte *) pImage)[i] = (pabyScan[j] & 0x20) >> 5;
454
 
                break;
455
 
                case 3:
456
 
                ((GByte *) pImage)[i] = (pabyScan[j] & 0x10) >> 4;
457
 
                break;
458
 
                case 4:
459
 
                ((GByte *) pImage)[i] = (pabyScan[j] & 0x08) >> 3;
460
 
                break;
461
 
                case 5:
462
 
                ((GByte *) pImage)[i] = (pabyScan[j] & 0x04) >> 2;
463
 
                break;
464
 
                case 6:
465
 
                ((GByte *) pImage)[i] = (pabyScan[j] & 0x02) >> 1;
466
 
                break;
467
 
                case 7:
468
 
                ((GByte *) pImage)[i] = pabyScan[j++] & 0x01;
469
 
                break;
470
 
                default:
471
 
                break;
472
 
            }
473
 
        }
474
 
    }
475
 
 
476
 
    return CE_None;
477
 
}
478
 
 
479
 
/************************************************************************/
480
 
/*                            IWriteBlock()                             */
481
 
/************************************************************************/
482
 
 
483
 
CPLErr BMPRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
484
 
                                   void * pImage )
485
 
{
486
 
    BMPDataset  *poGDS = (BMPDataset *)poDS;
487
 
    int         iInPixel, iOutPixel;
488
 
    GUInt32     iScanOffset;
489
 
 
490
 
    CPLAssert( poGDS != NULL
491
 
               && nBlockXOff >= 0
492
 
               && nBlockYOff >= 0
493
 
               && pImage != NULL );
494
 
 
495
 
    iScanOffset = poGDS->sFileHeader.iSize - (nBlockYOff + 1) * nScanSize;
496
 
    if ( MFILESeek( poGDS->fp, iScanOffset, SEEK_SET ) < 0 )
497
 
    {
498
 
        CPLError( CE_Failure, CPLE_FileIO,
499
 
                  "Can't seek to offset %ld in output file to write data",
500
 
                  iScanOffset );
501
 
        return CE_Failure;
502
 
    }
503
 
 
504
 
    if( poGDS->nBands != 1 )
505
 
    {
506
 
        memset( pabyScan, 0, nScanSize );
507
 
        MFILERead( pabyScan, 1, nScanSize, poGDS->fp );
508
 
        MFILESeek( poGDS->fp, iScanOffset, SEEK_SET );
509
 
    }
510
 
 
511
 
    for ( iInPixel = 0, iOutPixel = iBytesPerPixel - nBand;
512
 
          iInPixel < nBlockXSize; iInPixel++, iOutPixel += poGDS->nBands )
513
 
    {
514
 
        pabyScan[iOutPixel] = ((GByte *) pImage)[iInPixel];
515
 
    }
516
 
 
517
 
    if ( MFILEWrite( pabyScan, 1, nScanSize, poGDS->fp ) < nScanSize )
518
 
    {
519
 
        CPLError( CE_Failure, CPLE_FileIO,
520
 
                  "Can't write block with X offset %d and Y offset %d",
521
 
                  nBlockXOff, nBlockYOff );
522
 
        return CE_Failure;
523
 
    }
524
 
 
525
 
    return CE_None;
526
 
}
527
 
 
528
 
/************************************************************************/
529
 
/*                           GetColorTable()                            */
530
 
/************************************************************************/
531
 
 
532
 
GDALColorTable *BMPRasterBand::GetColorTable()
533
 
{
534
 
    BMPDataset   *poGDS = (BMPDataset *) poDS;
535
 
 
536
 
    return poGDS->poColorTable;
537
 
}
538
 
 
539
 
/************************************************************************/
540
 
/*                           SetColorTable()                            */
541
 
/************************************************************************/
542
 
 
543
 
CPLErr BMPRasterBand::SetColorTable( GDALColorTable *poColorTable )
544
 
{
545
 
    BMPDataset  *poGDS = (BMPDataset *) poDS;
546
 
 
547
 
    if ( poColorTable )
548
 
    {
549
 
        GDALColorEntry  oEntry;
550
 
        GUInt32         iULong;
551
 
        unsigned int    i;
552
 
 
553
 
        poGDS->sInfoHeader.iClrUsed = poColorTable->GetColorEntryCount();
554
 
        if ( poGDS->sInfoHeader.iClrUsed < 1 ||
555
 
             poGDS->sInfoHeader.iClrUsed > (1U << poGDS->sInfoHeader.iBitCount) )
556
 
            return CE_Failure;
557
 
 
558
 
        MFILESeek( poGDS->fp, BFH_SIZE + 32, SEEK_SET );
559
 
 
560
 
        iULong = CPL_LSBWORD32( poGDS->sInfoHeader.iClrUsed );
561
 
        MFILEWrite( &iULong, 4, 1, poGDS->fp );
562
 
        poGDS->pabyColorTable = (GByte *) CPLRealloc( poGDS->pabyColorTable,
563
 
                        poGDS->nColorElems * poGDS->sInfoHeader.iClrUsed );
564
 
        if ( !poGDS->pabyColorTable )
565
 
            return CE_Failure;
566
 
 
567
 
        for( i = 0; i < poGDS->sInfoHeader.iClrUsed; i++ )
568
 
        {
569
 
            poColorTable->GetColorEntryAsRGB( i, &oEntry );
570
 
            poGDS->pabyColorTable[i * poGDS->nColorElems + 3] = 0;
571
 
            poGDS->pabyColorTable[i * poGDS->nColorElems + 2] = oEntry.c1; // Red
572
 
            poGDS->pabyColorTable[i * poGDS->nColorElems + 1] = oEntry.c2; // Green
573
 
            poGDS->pabyColorTable[i * poGDS->nColorElems] = oEntry.c3;     // Blue
574
 
        }
575
 
 
576
 
        MFILESeek( poGDS->fp, BFH_SIZE + poGDS->sInfoHeader.iSize, SEEK_SET );
577
 
        if ( MFILEWrite( poGDS->pabyColorTable, 1,
578
 
                poGDS->nColorElems * poGDS->sInfoHeader.iClrUsed, poGDS->fp ) <
579
 
             poGDS->nColorElems * (GUInt32) poGDS->sInfoHeader.iClrUsed )
580
 
        {
581
 
            return CE_Failure;
582
 
        }
583
 
    }
584
 
    else
585
 
        return CE_Failure;
586
 
 
587
 
    return CE_None;
588
 
}
589
 
 
590
 
/************************************************************************/
591
 
/*                       GetColorInterpretation()                       */
592
 
/************************************************************************/
593
 
 
594
 
GDALColorInterp BMPRasterBand::GetColorInterpretation()
595
 
{
596
 
    BMPDataset      *poGDS = (BMPDataset *) poDS;
597
 
 
598
 
    if( poGDS->sInfoHeader.iBitCount == 24 ||
599
 
        poGDS->sInfoHeader.iBitCount == 32 ||
600
 
        poGDS->sInfoHeader.iBitCount == 16 )
601
 
    {
602
 
        if( nBand == 1 )
603
 
            return GCI_RedBand;
604
 
        else if( nBand == 2 )
605
 
            return GCI_GreenBand;
606
 
        else if( nBand == 3 )
607
 
            return GCI_BlueBand;
608
 
        else
609
 
            return GCI_Undefined;
610
 
    }
611
 
    else
612
 
    {
613
 
        return GCI_PaletteIndex;
614
 
    }
615
 
}
616
 
 
617
 
/************************************************************************/
618
 
/* ==================================================================== */
619
 
/*                       BMPComprRasterBand                             */
620
 
/* ==================================================================== */
621
 
/************************************************************************/
622
 
 
623
 
class BMPComprRasterBand : public BMPRasterBand
624
 
{
625
 
    friend class BMPDataset;
626
 
 
627
 
    GByte           *pabyComprBuf;
628
 
    GByte           *pabyUncomprBuf;
629
 
 
630
 
  public:
631
 
 
632
 
                BMPComprRasterBand( BMPDataset *, int );
633
 
                ~BMPComprRasterBand();
634
 
 
635
 
    virtual CPLErr          IReadBlock( int, int, void * );
636
 
//    virtual CPLErr        IWriteBlock( int, int, void * );
637
 
};
638
 
 
639
 
/************************************************************************/
640
 
/*                           BMPComprRasterBand()                       */
641
 
/************************************************************************/
642
 
 
643
 
BMPComprRasterBand::BMPComprRasterBand( BMPDataset *poDS, int nBand )
644
 
    : BMPRasterBand( poDS, nBand )
645
 
{
646
 
    unsigned int    i, j, k, iLength;
647
 
    GUInt32         iComprSize, iUncomprSize;
648
 
 
649
 
    iComprSize = poDS->sFileHeader.iSize - poDS->sFileHeader.iOffBits;
650
 
    iUncomprSize = poDS->GetRasterXSize() * poDS->GetRasterYSize();
651
 
    pabyComprBuf = (GByte *) CPLMalloc( iComprSize );
652
 
    pabyUncomprBuf = (GByte *) CPLMalloc( iUncomprSize );
653
 
 
654
 
    CPLDebug( "BMP", "RLE8 compression detected." );
655
 
    CPLDebug ( "BMP", "Size of compressed buffer %ld bytes,"
656
 
               " size of uncompressed buffer %ld bytes.",
657
 
               iComprSize, iUncomprSize );
658
 
 
659
 
    MFILESeek( poDS->fp, poDS->sFileHeader.iOffBits, SEEK_SET );
660
 
    MFILERead( pabyComprBuf, 1, iComprSize, poDS->fp );
661
 
    i = 0;
662
 
    j = 0;
663
 
    if ( poDS->sInfoHeader.iBitCount == 8 )         // RLE8
664
 
    {
665
 
        while( j < iUncomprSize && i < iComprSize )
666
 
        {
667
 
            if ( pabyComprBuf[i] )
668
 
            {
669
 
                iLength = pabyComprBuf[i++];
670
 
                while( iLength > 0 && j < iUncomprSize && i < iComprSize )
671
 
                {
672
 
                    pabyUncomprBuf[j++] = pabyComprBuf[i];
673
 
                    iLength--;
674
 
                }
675
 
                i++;
676
 
            }
677
 
            else
678
 
            {
679
 
                i++;
680
 
                if ( pabyComprBuf[i] == 0 )         // Next scanline
681
 
                {
682
 
                    i++;
683
 
                }
684
 
                else if ( pabyComprBuf[i] == 1 )    // End of image
685
 
                {
686
 
                    break;
687
 
                }
688
 
                else if ( pabyComprBuf[i] == 2 )    // Move to...
689
 
                {
690
 
                    i++;
691
 
                    if ( i < iComprSize - 1 )
692
 
                    {
693
 
                        j += pabyComprBuf[i++] +
694
 
                             pabyComprBuf[i++] * poDS->GetRasterXSize();
695
 
                    }
696
 
                    else
697
 
                        break;
698
 
                }
699
 
                else                                // Absolute mode
700
 
                {
701
 
                    iLength = pabyComprBuf[i++];
702
 
                    for ( k = 0; k < iLength && j < iUncomprSize && i < iComprSize; k++ )
703
 
                        pabyUncomprBuf[j++] = pabyComprBuf[i++];
704
 
                    if ( k & 0x01 )
705
 
                        i++;
706
 
                }
707
 
            }
708
 
        }
709
 
    }
710
 
    else                                            // RLE4
711
 
    {
712
 
        while( j < iUncomprSize && i < iComprSize )
713
 
        {
714
 
            if ( pabyComprBuf[i] )
715
 
            {
716
 
                iLength = pabyComprBuf[i++];
717
 
                while( iLength > 0 && j < iUncomprSize && i < iComprSize )
718
 
                {
719
 
                    if ( iLength & 0x01 )
720
 
                        pabyUncomprBuf[j++] = (pabyComprBuf[i] & 0xF0) >> 4;
721
 
                    else
722
 
                        pabyUncomprBuf[j++] = pabyComprBuf[i] & 0x0F;
723
 
                    iLength--;
724
 
                }
725
 
                i++;
726
 
            }
727
 
            else
728
 
            {
729
 
                i++;
730
 
                if ( pabyComprBuf[i] == 0 )         // Next scanline
731
 
                {
732
 
                    i++;
733
 
                }
734
 
                else if ( pabyComprBuf[i] == 1 )    // End of image
735
 
                {
736
 
                    break;
737
 
                }
738
 
                else if ( pabyComprBuf[i] == 2 )    // Move to...
739
 
                {
740
 
                    i++;
741
 
                    if ( i < iComprSize - 1 )
742
 
                    {
743
 
                        j += pabyComprBuf[i++] +
744
 
                             pabyComprBuf[i++] * poDS->GetRasterXSize();
745
 
                    }
746
 
                    else
747
 
                        break;
748
 
                }
749
 
                else                                // Absolute mode
750
 
                {
751
 
                    iLength = pabyComprBuf[i++];
752
 
                    for ( k = 0; k < iLength && j < iUncomprSize && i < iComprSize; k++ )
753
 
                    {
754
 
                        if ( k & 0x01 )
755
 
                            pabyUncomprBuf[j++] = pabyComprBuf[i++] & 0x0F;
756
 
                        else
757
 
                            pabyUncomprBuf[j++] = (pabyComprBuf[i] & 0xF0) >> 4;
758
 
                    }
759
 
                    if ( k & 0x01 )
760
 
                        i++;
761
 
                }
762
 
            }
763
 
        }
764
 
    }
765
 
}
766
 
 
767
 
/************************************************************************/
768
 
/*                           ~BMPComprRasterBand()                      */
769
 
/************************************************************************/
770
 
 
771
 
BMPComprRasterBand::~BMPComprRasterBand()
772
 
{
773
 
    if ( pabyComprBuf )
774
 
        CPLFree( pabyComprBuf );
775
 
    if ( pabyUncomprBuf )
776
 
        CPLFree( pabyUncomprBuf );
777
 
}
778
 
 
779
 
/************************************************************************/
780
 
/*                             IReadBlock()                             */
781
 
/************************************************************************/
782
 
 
783
 
CPLErr BMPComprRasterBand::
784
 
    IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage )
785
 
{
786
 
    memcpy( pImage, pabyUncomprBuf +
787
 
            (poDS->GetRasterYSize() - nBlockYOff - 1) * poDS->GetRasterXSize(),
788
 
            nBlockXSize );
789
 
 
790
 
    return CE_None;
791
 
}
792
 
 
793
 
/************************************************************************/
794
 
/*                           BMPDataset()                               */
795
 
/************************************************************************/
796
 
 
797
 
BMPDataset::BMPDataset()
798
 
{
799
 
    pszFilename = NULL;
800
 
    fp = NULL;
801
 
    nBands = 0;
802
 
    pszProjection = CPLStrdup( "" );
803
 
    bGeoTransformValid = FALSE;
804
 
    adfGeoTransform[0] = 0.0;
805
 
    adfGeoTransform[1] = 1.0;
806
 
    adfGeoTransform[2] = 0.0;
807
 
    adfGeoTransform[3] = 0.0;
808
 
    adfGeoTransform[4] = 0.0;
809
 
    adfGeoTransform[5] = 1.0;
810
 
    pabyColorTable = NULL;
811
 
    poColorTable = NULL;
812
 
    memset( &sFileHeader, 0, sizeof(sFileHeader) );
813
 
    memset( &sInfoHeader, 0, sizeof(sInfoHeader) );
814
 
}
815
 
 
816
 
/************************************************************************/
817
 
/*                            ~BMPDataset()                             */
818
 
/************************************************************************/
819
 
 
820
 
BMPDataset::~BMPDataset()
821
 
{
822
 
    FlushCache();
823
 
 
824
 
    if ( pszProjection )
825
 
        CPLFree( pszProjection );
826
 
    if ( pabyColorTable )
827
 
        CPLFree( pabyColorTable );
828
 
    if ( poColorTable != NULL )
829
 
        delete poColorTable;
830
 
    if( fp != NULL )
831
 
        MFILEClose( fp );
832
 
}
833
 
 
834
 
/************************************************************************/
835
 
/*                          GetGeoTransform()                           */
836
 
/************************************************************************/
837
 
 
838
 
CPLErr BMPDataset::GetGeoTransform( double * padfTransform )
839
 
{
840
 
    memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
841
 
 
842
 
    if( bGeoTransformValid )
843
 
        return CE_None;
844
 
    else
845
 
        return CE_Failure;
846
 
}
847
 
 
848
 
/************************************************************************/
849
 
/*                          SetGeoTransform()                           */
850
 
/************************************************************************/
851
 
 
852
 
CPLErr BMPDataset::SetGeoTransform( double * padfTransform )
853
 
{
854
 
    CPLErr              eErr = CE_None;
855
 
 
856
 
    memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
857
 
 
858
 
    if ( pszFilename && bGeoTransformValid )
859
 
        if ( GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform )
860
 
             == FALSE )
861
 
        {
862
 
            CPLError( CE_Failure, CPLE_FileIO, "Can't write world file." );
863
 
            eErr = CE_Failure;
864
 
        }
865
 
 
866
 
    return eErr;
867
 
}
868
 
 
869
 
/************************************************************************/
870
 
/*                          GetProjectionRef()                          */
871
 
/************************************************************************/
872
 
 
873
 
const char *BMPDataset::GetProjectionRef()
874
 
{
875
 
    if( pszProjection )
876
 
        return pszProjection;
877
 
    else
878
 
        return "";
879
 
}
880
 
 
881
 
/************************************************************************/
882
 
/*                             FlushCache()                             */
883
 
/************************************************************************/
884
 
 
885
 
void BMPDataset::FlushCache()
886
 
 
887
 
{
888
 
    GDALDataset::FlushCache();
889
 
}
890
 
 
891
 
/************************************************************************/
892
 
/*                                Open()                                */
893
 
/************************************************************************/
894
 
 
895
 
GDALDataset *BMPDataset::Open( GDALOpenInfo * poOpenInfo )
896
 
{
897
 
    if( poOpenInfo->fp == NULL )
898
 
        return NULL;
899
 
 
900
 
    if( !EQUALN((const char *) poOpenInfo->pabyHeader, "BM", 2) )
901
 
        return NULL;
902
 
 
903
 
    VSIFClose( poOpenInfo->fp );
904
 
    poOpenInfo->fp = NULL;
905
 
 
906
 
/* -------------------------------------------------------------------- */
907
 
/*      Create a corresponding GDALDataset.                             */
908
 
/* -------------------------------------------------------------------- */
909
 
    BMPDataset      *poDS;
910
 
    VSIStatBuf      sStat;
911
 
 
912
 
    poDS = new BMPDataset();
913
 
 
914
 
    if( poOpenInfo->eAccess == GA_ReadOnly )
915
 
        poDS->fp = MFILEOpen( poOpenInfo->pszFilename );
916
 
    else
917
 
        poDS->fp = MFILEOpen( poOpenInfo->pszFilename );
918
 
    if ( !poDS->fp )
919
 
        return NULL;
920
 
 
921
 
    CPLStat(poOpenInfo->pszFilename, &sStat);
922
 
 
923
 
/* -------------------------------------------------------------------- */
924
 
/*      Read the BitmapFileHeader. We need iOffBits value only          */
925
 
/* -------------------------------------------------------------------- */
926
 
    MFILESeek( poDS->fp, 10, SEEK_SET );
927
 
    MFILERead( &poDS->sFileHeader.iOffBits, 1, 4, poDS->fp );
928
 
#ifdef CPL_MSB
929
 
    CPL_SWAP32PTR( &poDS->sFileHeader.iOffBits );
930
 
#endif
931
 
    poDS->sFileHeader.iSize = sStat.st_size;
932
 
    CPLDebug( "BMP", "File size %d bytes.", poDS->sFileHeader.iSize );
933
 
    CPLDebug( "BMP", "Image offset 0x%x bytes from file start.",
934
 
              poDS->sFileHeader.iOffBits );
935
 
 
936
 
/* -------------------------------------------------------------------- */
937
 
/*      Read the BitmapInfoHeader.                                      */
938
 
/* -------------------------------------------------------------------- */
939
 
    BMPType         eBMPType;
940
 
 
941
 
    MFILESeek( poDS->fp, BFH_SIZE, SEEK_SET );
942
 
    MFILERead( &poDS->sInfoHeader.iSize, 1, 4, poDS->fp );
943
 
#ifdef CPL_MSB
944
 
    CPL_SWAP32PTR( &poDS->sInfoHeader.iSize );
945
 
#endif
946
 
 
947
 
    if ( poDS->sInfoHeader.iSize == BIH_WIN4SIZE )
948
 
        eBMPType = BMPT_WIN4;
949
 
    else if ( poDS->sInfoHeader.iSize == BIH_OS21SIZE )
950
 
        eBMPType = BMPT_OS21;
951
 
    else if ( poDS->sInfoHeader.iSize == BIH_OS22SIZE ||
952
 
              poDS->sInfoHeader.iSize == 16 )
953
 
        eBMPType = BMPT_OS22;
954
 
    else
955
 
        eBMPType = BMPT_WIN5;
956
 
 
957
 
    if ( eBMPType == BMPT_WIN4 || eBMPType == BMPT_WIN5 || eBMPType == BMPT_OS22 )
958
 
    {
959
 
        MFILERead( &poDS->sInfoHeader.iWidth, 1, 4, poDS->fp );
960
 
        MFILERead( &poDS->sInfoHeader.iHeight, 1, 4, poDS->fp );
961
 
        MFILERead( &poDS->sInfoHeader.iPlanes, 1, 2, poDS->fp );
962
 
        MFILERead( &poDS->sInfoHeader.iBitCount, 1, 2, poDS->fp );
963
 
        MFILERead( &poDS->sInfoHeader.iCompression, 1, 4, poDS->fp );
964
 
        MFILERead( &poDS->sInfoHeader.iSizeImage, 1, 4, poDS->fp );
965
 
        MFILERead( &poDS->sInfoHeader.iXPelsPerMeter, 1, 4, poDS->fp );
966
 
        MFILERead( &poDS->sInfoHeader.iYPelsPerMeter, 1, 4, poDS->fp );
967
 
        MFILERead( &poDS->sInfoHeader.iClrUsed, 1, 4, poDS->fp );
968
 
        MFILERead( &poDS->sInfoHeader.iClrImportant, 1, 4, poDS->fp );
969
 
#ifdef CPL_MSB
970
 
        CPL_SWAP32PTR( &poDS->sInfoHeader.iWidth );
971
 
        CPL_SWAP32PTR( &poDS->sInfoHeader.iHeight );
972
 
        CPL_SWAP16PTR( &poDS->sInfoHeader.iPlanes );
973
 
        CPL_SWAP16PTR( &poDS->sInfoHeader.iBitCount );
974
 
        CPL_SWAP32PTR( &poDS->sInfoHeader.iCompression );
975
 
        CPL_SWAP32PTR( &poDS->sInfoHeader.iSizeImage );
976
 
        CPL_SWAP32PTR( &poDS->sInfoHeader.iXPelsPerMeter );
977
 
        CPL_SWAP32PTR( &poDS->sInfoHeader.iYPelsPerMeter );
978
 
        CPL_SWAP32PTR( &poDS->sInfoHeader.iClrUsed );
979
 
        CPL_SWAP32PTR( &poDS->sInfoHeader.iClrImportant );
980
 
#endif
981
 
        poDS->nColorElems = 4;
982
 
    }
983
 
    if ( eBMPType == BMPT_OS22 )
984
 
    {
985
 
        poDS->nColorElems = 3; // FIXME: different info in different documents regarding this!
986
 
    }
987
 
    if ( eBMPType == BMPT_OS21 )
988
 
    {
989
 
        GInt16  iShort;
990
 
 
991
 
        MFILERead( &iShort, 1, 2, poDS->fp );
992
 
        poDS->sInfoHeader.iWidth = CPL_LSBWORD16( iShort );
993
 
        MFILERead( &iShort, 1, 2, poDS->fp );
994
 
        poDS->sInfoHeader.iHeight = CPL_LSBWORD16( iShort );
995
 
        MFILERead( &iShort, 1, 2, poDS->fp );
996
 
        poDS->sInfoHeader.iPlanes = CPL_LSBWORD16( iShort );
997
 
        MFILERead( &iShort, 1, 2, poDS->fp );
998
 
        poDS->sInfoHeader.iBitCount = CPL_LSBWORD16( iShort );
999
 
        poDS->nColorElems = 3;
1000
 
    }
1001
 
 
1002
 
    if ( poDS->sInfoHeader.iBitCount != 1  &&
1003
 
         poDS->sInfoHeader.iBitCount != 4  &&
1004
 
         poDS->sInfoHeader.iBitCount != 8  &&
1005
 
         poDS->sInfoHeader.iBitCount != 16 &&
1006
 
         poDS->sInfoHeader.iBitCount != 24 &&
1007
 
         poDS->sInfoHeader.iBitCount != 32 )
1008
 
    {
1009
 
        delete poDS;
1010
 
        return NULL;
1011
 
    }
1012
 
 
1013
 
    CPLDebug( "BMP", "Windows Device Independent Bitmap parameters:\n"
1014
 
              " info header size: %d bytes\n"
1015
 
              " width: %d\n height: %d\n planes: %d\n bpp: %d\n"
1016
 
              " compression: %d\n image size: %d bytes\n X resolution: %d\n"
1017
 
              " Y resolution: %d\n colours used: %d\n colours important: %d",
1018
 
              poDS->sInfoHeader.iSize,
1019
 
              poDS->sInfoHeader.iWidth, poDS->sInfoHeader.iHeight,
1020
 
              poDS->sInfoHeader.iPlanes, poDS->sInfoHeader.iBitCount,
1021
 
              poDS->sInfoHeader.iCompression, poDS->sInfoHeader.iSizeImage,
1022
 
              poDS->sInfoHeader.iXPelsPerMeter, poDS->sInfoHeader.iYPelsPerMeter,
1023
 
              poDS->sInfoHeader.iClrUsed, poDS->sInfoHeader.iClrImportant );
1024
 
 
1025
 
    poDS->nRasterXSize = poDS->sInfoHeader.iWidth;
1026
 
    poDS->nRasterYSize = (poDS->sInfoHeader.iHeight > 0)?
1027
 
        poDS->sInfoHeader.iHeight:-poDS->sInfoHeader.iHeight;
1028
 
    switch ( poDS->sInfoHeader.iBitCount )
1029
 
    {
1030
 
        case 1:
1031
 
        case 4:
1032
 
        case 8:
1033
 
        {
1034
 
            int     i;
1035
 
 
1036
 
            poDS->nBands = 1;
1037
 
            // Allocate memory for colour table and read it
1038
 
            if ( poDS->sInfoHeader.iClrUsed )
1039
 
                poDS->nColorTableSize = poDS->sInfoHeader.iClrUsed;
1040
 
            else
1041
 
                poDS->nColorTableSize = 1 << poDS->sInfoHeader.iBitCount;
1042
 
            poDS->pabyColorTable =
1043
 
                (GByte *)CPLMalloc( poDS->nColorElems * poDS->nColorTableSize );
1044
 
            MFILESeek( poDS->fp, BFH_SIZE + poDS->sInfoHeader.iSize, SEEK_SET );
1045
 
            MFILERead( poDS->pabyColorTable, poDS->nColorElems,
1046
 
                      poDS->nColorTableSize, poDS->fp );
1047
 
 
1048
 
            GDALColorEntry oEntry;
1049
 
            poDS->poColorTable = new GDALColorTable();
1050
 
            for( i = 0; i < poDS->nColorTableSize; i++ )
1051
 
            {
1052
 
                oEntry.c1 = poDS->pabyColorTable[i * poDS->nColorElems + 2]; // Red
1053
 
                oEntry.c2 = poDS->pabyColorTable[i * poDS->nColorElems + 1]; // Green
1054
 
                oEntry.c3 = poDS->pabyColorTable[i * poDS->nColorElems];     // Blue
1055
 
                oEntry.c4 = 255;
1056
 
 
1057
 
                poDS->poColorTable->SetColorEntry( i, &oEntry );
1058
 
            }
1059
 
        }
1060
 
        break;
1061
 
        case 16:
1062
 
        case 24:
1063
 
        case 32:
1064
 
        poDS->nBands = 3;
1065
 
        break;
1066
 
        default:
1067
 
        delete poDS;
1068
 
        return NULL;
1069
 
    }
1070
 
 
1071
 
/* -------------------------------------------------------------------- */
1072
 
/*      Create band information objects.                                */
1073
 
/* -------------------------------------------------------------------- */
1074
 
    int             iBand;
1075
 
 
1076
 
    if ( poDS->sInfoHeader.iCompression == BMPC_RGB )
1077
 
    {
1078
 
        for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1079
 
            poDS->SetBand( iBand, new BMPRasterBand( poDS, iBand ) );
1080
 
    }
1081
 
    else if ( poDS->sInfoHeader.iCompression == BMPC_RLE8 )
1082
 
    {
1083
 
        for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1084
 
            poDS->SetBand( iBand, new BMPComprRasterBand( poDS, iBand ) );
1085
 
    }
1086
 
    else
1087
 
    {
1088
 
        delete poDS;
1089
 
        return NULL;
1090
 
    }
1091
 
 
1092
 
/* -------------------------------------------------------------------- */
1093
 
/*      Check for world file.                                           */
1094
 
/* -------------------------------------------------------------------- */
1095
 
    poDS->bGeoTransformValid =
1096
 
        GDALReadWorldFile( poOpenInfo->pszFilename, ".wld",
1097
 
                           poDS->adfGeoTransform );
1098
 
 
1099
 
    return( poDS );
1100
 
}
1101
 
 
1102
 
/************************************************************************/
1103
 
/*                               Create()                               */
1104
 
/************************************************************************/
1105
 
 
1106
 
GDALDataset *BMPDataset::Create( const char * pszFilename,
1107
 
                                 int nXSize, int nYSize, int nBands,
1108
 
                                 GDALDataType eType, char **papszOptions )
1109
 
 
1110
 
{
1111
 
    if( eType != GDT_Byte )
1112
 
    {
1113
 
        CPLError( CE_Failure, CPLE_AppDefined,
1114
 
              "Attempt to create BMP dataset with an illegal\n"
1115
 
              "data type (%s), only Byte supported by the format.\n",
1116
 
              GDALGetDataTypeName(eType) );
1117
 
 
1118
 
        return NULL;
1119
 
    }
1120
 
 
1121
 
    if( nBands != 1 && nBands != 3 )
1122
 
    {
1123
 
        CPLError( CE_Failure, CPLE_NotSupported,
1124
 
                  "BMP driver doesn't support %d bands. Must be 1 or 3.\n",
1125
 
                  nBands );
1126
 
 
1127
 
        return NULL;
1128
 
    }
1129
 
 
1130
 
/* -------------------------------------------------------------------- */
1131
 
/*      Create the dataset.                                             */
1132
 
/* -------------------------------------------------------------------- */
1133
 
    BMPDataset      *poDS;
1134
 
 
1135
 
    poDS = new BMPDataset();
1136
 
 
1137
 
    poDS->fp = MFILEOpen( pszFilename );
1138
 
    if( poDS->fp == NULL )
1139
 
    {
1140
 
        CPLError( CE_Failure, CPLE_OpenFailed,
1141
 
                  "Unable to create file %s.\n",
1142
 
                  pszFilename );
1143
 
        return NULL;
1144
 
    }
1145
 
 
1146
 
    poDS->pszFilename = pszFilename;
1147
 
 
1148
 
/* -------------------------------------------------------------------- */
1149
 
/*      Fill the BitmapInfoHeader                                       */
1150
 
/* -------------------------------------------------------------------- */
1151
 
    GUInt32         nScanSize;
1152
 
 
1153
 
    poDS->sInfoHeader.iSize = 40;
1154
 
    poDS->sInfoHeader.iWidth = nXSize;
1155
 
    poDS->sInfoHeader.iHeight = nYSize;
1156
 
    poDS->sInfoHeader.iPlanes = 1;
1157
 
    poDS->sInfoHeader.iBitCount = ( nBands == 3 )?24:8;
1158
 
    poDS->sInfoHeader.iCompression = BMPC_RGB;
1159
 
    nScanSize = ((poDS->sInfoHeader.iWidth *
1160
 
                  poDS->sInfoHeader.iBitCount + 31) & ~31) / 8;
1161
 
    poDS->sInfoHeader.iSizeImage = nScanSize * poDS->sInfoHeader.iHeight;
1162
 
    poDS->sInfoHeader.iXPelsPerMeter = 0;
1163
 
    poDS->sInfoHeader.iYPelsPerMeter = 0;
1164
 
    poDS->nColorElems = 4;
1165
 
 
1166
 
/* -------------------------------------------------------------------- */
1167
 
/*      Do we need colour table?                                        */
1168
 
/* -------------------------------------------------------------------- */
1169
 
    unsigned int    i;
1170
 
 
1171
 
    if ( nBands == 1 )
1172
 
    {
1173
 
        poDS->sInfoHeader.iClrUsed = 1 << poDS->sInfoHeader.iBitCount;
1174
 
        poDS->pabyColorTable =
1175
 
            (GByte *) CPLMalloc( poDS->nColorElems * poDS->sInfoHeader.iClrUsed );
1176
 
        for ( i = 0; i < poDS->sInfoHeader.iClrUsed; i++ )
1177
 
        {
1178
 
            poDS->pabyColorTable[i * poDS->nColorElems] =
1179
 
                poDS->pabyColorTable[i * poDS->nColorElems + 1] =
1180
 
                poDS->pabyColorTable[i * poDS->nColorElems + 2] =
1181
 
                poDS->pabyColorTable[i * poDS->nColorElems + 3] = (GByte) i;
1182
 
        }
1183
 
    }
1184
 
    else
1185
 
    {
1186
 
        poDS->sInfoHeader.iClrUsed = 0;
1187
 
    }
1188
 
    poDS->sInfoHeader.iClrImportant = 0;
1189
 
 
1190
 
/* -------------------------------------------------------------------- */
1191
 
/*      Fill the BitmapFileHeader                                       */
1192
 
/* -------------------------------------------------------------------- */
1193
 
    poDS->sFileHeader.bType[0] = 'B';
1194
 
    poDS->sFileHeader.bType[1] = 'M';
1195
 
    poDS->sFileHeader.iSize = BFH_SIZE + poDS->sInfoHeader.iSize +
1196
 
                    poDS->sInfoHeader.iClrUsed * poDS->nColorElems +
1197
 
                    poDS->sInfoHeader.iSizeImage;
1198
 
    poDS->sFileHeader.iReserved1 = 0;
1199
 
    poDS->sFileHeader.iReserved2 = 0;
1200
 
    poDS->sFileHeader.iOffBits = BFH_SIZE + poDS->sInfoHeader.iSize +
1201
 
                    poDS->sInfoHeader.iClrUsed * poDS->nColorElems;
1202
 
 
1203
 
/* -------------------------------------------------------------------- */
1204
 
/*      Write all structures to the file                                */
1205
 
/* -------------------------------------------------------------------- */
1206
 
    MFILEWrite( &poDS->sFileHeader.bType, 1, 2, poDS->fp );
1207
 
 
1208
 
    GInt32      iLong;
1209
 
    GUInt32     iULong;
1210
 
    GUInt16     iUShort;
1211
 
 
1212
 
    iULong = CPL_LSBWORD32( poDS->sFileHeader.iSize );
1213
 
    MFILEWrite( &iULong, 4, 1, poDS->fp );
1214
 
    iUShort = CPL_LSBWORD16( poDS->sFileHeader.iReserved1 );
1215
 
    MFILEWrite( &iUShort, 2, 1, poDS->fp );
1216
 
    iUShort = CPL_LSBWORD16( poDS->sFileHeader.iReserved2 );
1217
 
    MFILEWrite( &iUShort, 2, 1, poDS->fp );
1218
 
    iULong = CPL_LSBWORD32( poDS->sFileHeader.iOffBits );
1219
 
    MFILEWrite( &iULong, 4, 1, poDS->fp );
1220
 
 
1221
 
    iULong = CPL_LSBWORD32( poDS->sInfoHeader.iSize );
1222
 
    MFILEWrite( &iULong, 4, 1, poDS->fp );
1223
 
    iLong = CPL_LSBWORD32( poDS->sInfoHeader.iWidth );
1224
 
    MFILEWrite( &iLong, 4, 1, poDS->fp );
1225
 
    iLong = CPL_LSBWORD32( poDS->sInfoHeader.iHeight );
1226
 
    MFILEWrite( &iLong, 4, 1, poDS->fp );
1227
 
    iUShort = CPL_LSBWORD16( poDS->sInfoHeader.iPlanes );
1228
 
    MFILEWrite( &iUShort, 2, 1, poDS->fp );
1229
 
    iUShort = CPL_LSBWORD16( poDS->sInfoHeader.iBitCount );
1230
 
    MFILEWrite( &iUShort, 2, 1, poDS->fp );
1231
 
    iULong = CPL_LSBWORD32( poDS->sInfoHeader.iCompression );
1232
 
    MFILEWrite( &iULong, 4, 1, poDS->fp );
1233
 
    iULong = CPL_LSBWORD32( poDS->sInfoHeader.iSizeImage );
1234
 
    MFILEWrite( &iULong, 4, 1, poDS->fp );
1235
 
    iLong = CPL_LSBWORD32( poDS->sInfoHeader.iXPelsPerMeter );
1236
 
    MFILEWrite( &iLong, 4, 1, poDS->fp );
1237
 
    iLong = CPL_LSBWORD32( poDS->sInfoHeader.iYPelsPerMeter );
1238
 
    MFILEWrite( &iLong, 4, 1, poDS->fp );
1239
 
    iULong = CPL_LSBWORD32( poDS->sInfoHeader.iClrUsed );
1240
 
    MFILEWrite( &iULong, 4, 1, poDS->fp );
1241
 
    iULong = CPL_LSBWORD32( poDS->sInfoHeader.iClrImportant );
1242
 
    MFILEWrite( &iULong, 4, 1, poDS->fp );
1243
 
 
1244
 
    if ( poDS->sInfoHeader.iClrUsed )
1245
 
        MFILEWrite( poDS->pabyColorTable, 1,
1246
 
                   poDS->nColorElems * poDS->sInfoHeader.iClrUsed, poDS->fp );
1247
 
 
1248
 
    poDS->nRasterXSize = nXSize;
1249
 
    poDS->nRasterYSize = nYSize;
1250
 
    poDS->eAccess = GA_Update;
1251
 
    poDS->nBands = nBands;
1252
 
 
1253
 
/* -------------------------------------------------------------------- */
1254
 
/*      Create band information objects.                                */
1255
 
/* -------------------------------------------------------------------- */
1256
 
    int         iBand;
1257
 
 
1258
 
    for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1259
 
    {
1260
 
        poDS->SetBand( iBand, new BMPRasterBand( poDS, iBand ) );
1261
 
    }
1262
 
 
1263
 
/* -------------------------------------------------------------------- */
1264
 
/*      Do we need a world file?                                        */
1265
 
/* -------------------------------------------------------------------- */
1266
 
    if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
1267
 
        poDS->bGeoTransformValid = TRUE;
1268
 
 
1269
 
    return (GDALDataset *) poDS;
1270
 
}
1271
 
 
1272
 
/************************************************************************/
1273
 
/*                        GDALRegister_BMP()                            */
1274
 
/************************************************************************/
1275
 
 
1276
 
void GDALRegister_THUBANBMP()
1277
 
 
1278
 
{
1279
 
    GDALDriver  *poDriver;
1280
 
 
1281
 
    if( GDALGetDriverByName( "THUBANBMP" ) == NULL )
1282
 
    {
1283
 
        poDriver = new GDALDriver();
1284
 
 
1285
 
        poDriver->SetDescription( "THUBANBMP" );
1286
 
        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1287
 
                                   "MS Windows Device Independent Bitmap for Thuban" );
1288
 
        //poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_bmp.html" );
1289
 
        poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" );
1290
 
        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1291
 
"<CreationOptionList>"
1292
 
"   <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
1293
 
"</CreationOptionList>" );
1294
 
 
1295
 
        poDriver->pfnOpen = BMPDataset::Open;
1296
 
        poDriver->pfnCreate = BMPDataset::Create;
1297
 
 
1298
 
        GetGDALDriverManager()->RegisterDriver( poDriver );
1299
 
    }
1300
 
}
1301