bmp-load.c 30.3 KB
Newer Older
1
/* bmpread.c    reads any bitmap I could get for testing */
Elliot Lee's avatar
Elliot Lee committed
2 3
/* Alexander.Schulz@stud.uni-karlsruhe.de                */

4
/*
5
 * GIMP - The GNU Image Manipulation Program
6 7
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 3 of the License, or
11 12 13 14 15 16 17 18
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 21 22
 * ----------------------------------------------------------------------------
 */

23
#include "config.h"
24

25
#include <errno.h>
Elliot Lee's avatar
Elliot Lee committed
26
#include <string.h>
27

28 29
#include <glib/gstdio.h>

30
#include <libgimp/gimp.h>
31 32

#include "bmp.h"
33
#include "bmp-load.h"
34

35
#include "libgimp/stdplugins-intl.h"
Elliot Lee's avatar
Elliot Lee committed
36

37

38
#if !defined(WIN32) || defined(__MINGW32__)
39 40 41 42 43
#define BI_RGB            0
#define BI_RLE8           1
#define BI_RLE4           2
#define BI_BITFIELDS      3
#define BI_ALPHABITFIELDS 4
44 45
#endif

46

47 48 49 50 51 52 53 54 55 56 57 58
static gint32 ReadImage (FILE                 *fd,
                         const gchar          *filename,
                         gint                  width,
                         gint                  height,
                         guchar                cmap[256][3],
                         gint                  ncols,
                         gint                  bpp,
                         gint                  compression,
                         gint                  rowbytes,
                         gboolean              gray,
                         const BitmapChannel  *masks,
                         GError              **error);
59 60


61
static void
62 63
setMasksDefault (gushort        biBitCnt,
                 BitmapChannel *masks)
64 65 66 67
{
  switch (biBitCnt)
    {
    case 32:
68 69 70 71 72 73 74 75 76 77 78 79
      masks[0].mask      = 0x00ff0000;
      masks[0].shiftin   = 16;
      masks[0].max_value = (gfloat)255.0;
      masks[1].mask      = 0x0000ff00;
      masks[1].shiftin   = 8;
      masks[1].max_value = (gfloat)255.0;
      masks[2].mask      = 0x000000ff;
      masks[2].shiftin   = 0;
      masks[2].max_value = (gfloat)255.0;
      masks[3].mask      = 0x00000000;
      masks[3].shiftin   = 0;
      masks[3].max_value = (gfloat)0.0;
80
      break;
81

82
    case 24:
83 84 85 86 87 88 89 90 91 92 93 94
      masks[0].mask      = 0xff0000;
      masks[0].shiftin   = 16;
      masks[0].max_value = (gfloat)255.0;
      masks[1].mask      = 0x00ff00;
      masks[1].shiftin   = 8;
      masks[1].max_value = (gfloat)255.0;
      masks[2].mask      = 0x0000ff;
      masks[2].shiftin   = 0;
      masks[2].max_value = (gfloat)255.0;
      masks[3].mask      = 0x0;
      masks[3].shiftin   = 0;
      masks[3].max_value = (gfloat)0.0;
95
      break;
96

97
    case 16:
98 99 100 101 102 103 104 105 106 107 108 109
      masks[0].mask      = 0x7c00;
      masks[0].shiftin   = 10;
      masks[0].max_value = (gfloat)31.0;
      masks[1].mask      = 0x03e0;
      masks[1].shiftin   = 5;
      masks[1].max_value = (gfloat)31.0;
      masks[2].mask      = 0x001f;
      masks[2].shiftin   = 0;
      masks[2].max_value = (gfloat)31.0;
      masks[3].mask      = 0x0;
      masks[3].shiftin   = 0;
      masks[3].max_value = (gfloat)0.0;
110
      break;
111

112 113 114 115 116
    default:
      break;
    }
}

117
static gint32
118
ToL (const guchar *buffer)
119
{
120
  return (buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24);
121 122
}

123
static gint16
124
ToS (const guchar *buffer)
125
{
126
  return (buffer[0] | buffer[1] << 8);
127 128 129
}

static gboolean
130
ReadColorMap (FILE     *fd,
131 132 133
              guchar    buffer[256][3],
              gint      number,
              gint      size,
134
              gboolean *gray)
135
{
136
  gint i;
137

138
  *gray = (number > 2);
139

140 141
  for (i = 0; i < number ; i++)
    {
142 143
      guchar rgb[4];

144
      if (! ReadOK (fd, rgb, size))
145 146 147 148
        {
          g_message (_("Bad colormap"));
          return FALSE;
        }
149

150 151 152 153 154
      /* Bitmap save the colors in another order! But change only once! */

      buffer[i][0] = rgb[2];
      buffer[i][1] = rgb[1];
      buffer[i][2] = rgb[0];
155 156

      *gray = ((*gray) && (rgb[0] == rgb[1]) && (rgb[1] == rgb[2]));
157
    }
158

159 160 161
  return TRUE;
}

162
static gboolean
163 164 165
ReadChannelMasks (guint32       *tmp,
                  BitmapChannel *masks,
                  guint          channels)
166
{
167
  gint i;
168

169 170
  for (i = 0; i < channels; i++)
    {
171 172 173
      guint32 mask;
      gint    nbits, offset, bit;

174
      mask = tmp[i];
175 176 177
      masks[i].mask = mask;
      nbits = 0;
      offset = -1;
178

179 180 181 182 183 184 185 186
      for (bit = 0; bit < 32; bit++)
        {
          if (mask & 1)
            {
              nbits++;
              if (offset == -1)
                offset = bit;
            }
187

188 189
          mask = mask >> 1;
        }
190 191 192

      masks[i].shiftin   = offset;
      masks[i].max_value = (gfloat) ((1 << nbits) - 1);
193

194
#ifdef DEBUG
195 196
      g_print ("Channel %d mask %08x in %d max_val %d\n",
               i, masks[i].mask, masks[i].shiftin, (gint)masks[i].max_value);
197 198
#endif
    }
199

200 201 202
  return TRUE;
}

203
gint32
204 205
load_image (const gchar  *filename,
            GError      **error)
Elliot Lee's avatar
Elliot Lee committed
206
{
207 208 209 210 211 212 213 214 215 216
  FILE           *fd;
  BitmapFileHead  bitmap_file_head;
  BitmapHead      bitmap_head;
  guchar          buffer[124];
  gint            ColormapSize, rowbytes, Maps;
  gboolean        gray = FALSE;
  guchar          ColorMap[256][3];
  gint32          image_ID = -1;
  gchar           magick[2];
  BitmapChannel   masks[4];
Elliot Lee's avatar
Elliot Lee committed
217

218
  gimp_progress_init_printf (_("Opening '%s'"),
219
                             gimp_filename_to_utf8 (filename));
220

221
  fd = g_fopen (filename, "rb");
222

Elliot Lee's avatar
Elliot Lee committed
223 224
  if (!fd)
    {
225 226 227
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                   _("Could not open '%s' for reading: %s"),
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
228
      goto out;
Elliot Lee's avatar
Elliot Lee committed
229 230
    }

231
  /* It is a File. Now is it a Bitmap? Read the shortest possible header */
232

233 234 235 236 237 238 239
  if (! ReadOK (fd, magick, 2) ||
      ! (! strncmp (magick, "BA", 2) ||
         ! strncmp (magick, "BM", 2) ||
         ! strncmp (magick, "IC", 2) ||
         ! strncmp (magick, "PT", 2) ||
         ! strncmp (magick, "CI", 2) ||
         ! strncmp (magick, "CP", 2)))
240
    {
241 242 243
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
244
      goto out;
245
    }
246

247
  while (! strncmp (magick, "BA", 2))
248
    {
249
      if (! ReadOK (fd, buffer, 12))
250
        {
251 252 253
          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                       _("'%s' is not a valid BMP file"),
                       gimp_filename_to_utf8 (filename));
254
          goto out;
255
        }
256 257

      if (! ReadOK (fd, magick, 2))
258
        {
259 260 261
          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                       _("'%s' is not a valid BMP file"),
                       gimp_filename_to_utf8 (filename));
262
          goto out;
263 264 265
        }
    }

266
  if (! ReadOK (fd, buffer, 12))
Elliot Lee's avatar
Elliot Lee committed
267
    {
268 269 270
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
271
      goto out;
Elliot Lee's avatar
Elliot Lee committed
272
    }
Manish Singh's avatar
Manish Singh committed
273

274
  /* bring them to the right byteorder. Not too nice, but it should work */
Manish Singh's avatar
Manish Singh committed
275

276 277 278 279
  bitmap_file_head.bfSize = ToL (&buffer[0x00]);
  bitmap_file_head.zzHotX = ToS (&buffer[0x04]);
  bitmap_file_head.zzHotY = ToS (&buffer[0x06]);
  bitmap_file_head.bfOffs = ToL (&buffer[0x08]);
280

281
  if (! ReadOK (fd, buffer, 4))
282
    {
283 284 285
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
286
      goto out;
287
    }
288

289
  bitmap_file_head.biSize = ToL (&buffer[0x00]);
290 291 292

  /* What kind of bitmap is it? */

293
  if (bitmap_file_head.biSize == 12) /* OS/2 1.x ? */
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
294
    {
295
      if (! ReadOK (fd, buffer, 8))
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
296
        {
297 298 299
          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                       _("Error reading BMP file header from '%s'"),
                       gimp_filename_to_utf8 (filename));
300
          goto out;
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
301
        }
302

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
      bitmap_head.biWidth   = ToS (&buffer[0x00]);       /* 12 */
      bitmap_head.biHeight  = ToS (&buffer[0x02]);       /* 14 */
      bitmap_head.biPlanes  = ToS (&buffer[0x04]);       /* 16 */
      bitmap_head.biBitCnt  = ToS (&buffer[0x06]);       /* 18 */
      bitmap_head.biCompr   = 0;
      bitmap_head.biSizeIm  = 0;
      bitmap_head.biXPels   = bitmap_head.biYPels = 0;
      bitmap_head.biClrUsed = 0;
      bitmap_head.biClrImp  = 0;
      bitmap_head.masks[0]  = 0;
      bitmap_head.masks[1]  = 0;
      bitmap_head.masks[2]  = 0;
      bitmap_head.masks[3]  = 0;

      memset (masks, 0, sizeof (masks));
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
318 319
      Maps = 3;
    }
320
  else if (bitmap_file_head.biSize == 40) /* Windows 3.x */
Elliot Lee's avatar
Elliot Lee committed
321
    {
322
      if (! ReadOK (fd, buffer, 36))
Elliot Lee's avatar
Elliot Lee committed
323
        {
324 325 326
          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                       _("Error reading BMP file header from '%s'"),
                       gimp_filename_to_utf8 (filename));
327
          goto out;
Elliot Lee's avatar
Elliot Lee committed
328
        }
329

330 331 332 333 334 335 336 337 338 339 340 341 342 343
      bitmap_head.biWidth   = ToL (&buffer[0x00]);      /* 12 */
      bitmap_head.biHeight  = ToL (&buffer[0x04]);      /* 16 */
      bitmap_head.biPlanes  = ToS (&buffer[0x08]);      /* 1A */
      bitmap_head.biBitCnt  = ToS (&buffer[0x0A]);      /* 1C */
      bitmap_head.biCompr   = ToL (&buffer[0x0C]);      /* 1E */
      bitmap_head.biSizeIm  = ToL (&buffer[0x10]);      /* 22 */
      bitmap_head.biXPels   = ToL (&buffer[0x14]);      /* 26 */
      bitmap_head.biYPels   = ToL (&buffer[0x18]);      /* 2A */
      bitmap_head.biClrUsed = ToL (&buffer[0x1C]);      /* 2E */
      bitmap_head.biClrImp  = ToL (&buffer[0x20]);      /* 32 */
      bitmap_head.masks[0]  = 0;
      bitmap_head.masks[1]  = 0;
      bitmap_head.masks[2]  = 0;
      bitmap_head.masks[3]  = 0;
344

345
      Maps = 4;
346
      memset (masks, 0, sizeof (masks));
347

348
      if (bitmap_head.biCompr == BI_BITFIELDS)
349
        {
350 351 352 353
#ifdef DEBUG
          g_print ("Got BI_BITFIELDS compression\n");
#endif

354
          if (! ReadOK (fd, buffer, 3 * sizeof (guint32)))
355 356 357 358
            {
              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                           _("Error reading BMP file header from '%s'"),
                           gimp_filename_to_utf8 (filename));
359
              goto out;
360 361
            }

362 363 364
          bitmap_head.masks[0] = ToL (&buffer[0x00]);
          bitmap_head.masks[1] = ToL (&buffer[0x04]);
          bitmap_head.masks[2] = ToL (&buffer[0x08]);
365 366

          ReadChannelMasks (&bitmap_head.masks[0], masks, 3);
367
        }
368
      else if (bitmap_head.biCompr == BI_RGB)
369
        {
370 371 372 373
#ifdef DEBUG
          g_print ("Got BI_RGB compression\n");
#endif

374
          setMasksDefault (bitmap_head.biBitCnt, masks);
375
        }
376 377
      else if ((bitmap_head.biCompr != BI_RLE4) &&
               (bitmap_head.biCompr != BI_RLE8))
378 379 380
        {
          /* BI_ALPHABITFIELDS, etc. */
          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
381
                       _("Unsupported compression (%u) in BMP file from '%s'"),
382
                       bitmap_head.biCompr,
383 384
                       gimp_filename_to_utf8 (filename));
        }
385 386 387 388

#ifdef DEBUG
      g_print ("Got BI_RLE4 or BI_RLE8 compression\n");
#endif
Elliot Lee's avatar
Elliot Lee committed
389
    }
390 391
  else if (bitmap_file_head.biSize >= 56 &&
           bitmap_file_head.biSize <= 64)
Elliot Lee's avatar
Elliot Lee committed
392
    {
393 394 395
      /* enhanced Windows format with bit masks */

      if (! ReadOK (fd, buffer, bitmap_file_head.biSize - 4))
Elliot Lee's avatar
Elliot Lee committed
396
        {
397 398 399
          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                       _("Error reading BMP file header from '%s'"),
                       gimp_filename_to_utf8 (filename));
400
          goto out;
Elliot Lee's avatar
Elliot Lee committed
401
        }
402

403 404 405 406 407 408 409 410 411 412 413 414 415 416
      bitmap_head.biWidth   = ToL (&buffer[0x00]);       /* 12 */
      bitmap_head.biHeight  = ToL (&buffer[0x04]);       /* 16 */
      bitmap_head.biPlanes  = ToS (&buffer[0x08]);       /* 1A */
      bitmap_head.biBitCnt  = ToS (&buffer[0x0A]);       /* 1C */
      bitmap_head.biCompr   = ToL (&buffer[0x0C]);       /* 1E */
      bitmap_head.biSizeIm  = ToL (&buffer[0x10]);       /* 22 */
      bitmap_head.biXPels   = ToL (&buffer[0x14]);       /* 26 */
      bitmap_head.biYPels   = ToL (&buffer[0x18]);       /* 2A */
      bitmap_head.biClrUsed = ToL (&buffer[0x1C]);       /* 2E */
      bitmap_head.biClrImp  = ToL (&buffer[0x20]);       /* 32 */
      bitmap_head.masks[0]  = ToL (&buffer[0x24]);       /* 36 */
      bitmap_head.masks[1]  = ToL (&buffer[0x28]);       /* 3A */
      bitmap_head.masks[2]  = ToL (&buffer[0x2C]);       /* 3E */
      bitmap_head.masks[3]  = ToL (&buffer[0x30]);       /* 42 */
417 418

      Maps = 4;
419
      ReadChannelMasks (&bitmap_head.masks[0], masks, 4);
Elliot Lee's avatar
Elliot Lee committed
420
    }
421 422
  else if (bitmap_file_head.biSize == 108 ||
           bitmap_file_head.biSize == 124)
423
    {
424
      /* BMP Version 4 or 5 */
425

426 427
      if (! ReadOK (fd, buffer, bitmap_file_head.biSize - 4))
        {
428 429 430
          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                       _("Error reading BMP file header from '%s'"),
                       gimp_filename_to_utf8 (filename));
431
          goto out;
432
        }
433

434 435 436 437 438 439 440 441 442 443 444 445 446 447
      bitmap_head.biWidth   = ToL (&buffer[0x00]);
      bitmap_head.biHeight  = ToL (&buffer[0x04]);
      bitmap_head.biPlanes  = ToS (&buffer[0x08]);
      bitmap_head.biBitCnt  = ToS (&buffer[0x0A]);
      bitmap_head.biCompr   = ToL (&buffer[0x0C]);
      bitmap_head.biSizeIm  = ToL (&buffer[0x10]);
      bitmap_head.biXPels   = ToL (&buffer[0x14]);
      bitmap_head.biYPels   = ToL (&buffer[0x18]);
      bitmap_head.biClrUsed = ToL (&buffer[0x1C]);
      bitmap_head.biClrImp  = ToL (&buffer[0x20]);
      bitmap_head.masks[0]  = ToL (&buffer[0x24]);
      bitmap_head.masks[1]  = ToL (&buffer[0x28]);
      bitmap_head.masks[2]  = ToL (&buffer[0x2C]);
      bitmap_head.masks[3]  = ToL (&buffer[0x30]);
448

449
      Maps = 4;
450

451
      if (bitmap_head.biCompr == BI_BITFIELDS)
452
        {
453 454 455 456
#ifdef DEBUG
          g_print ("Got BI_BITFIELDS compression\n");
#endif

457
          ReadChannelMasks (&bitmap_head.masks[0], masks, 4);
458
        }
459
      else if (bitmap_head.biCompr == BI_RGB)
460
        {
461 462 463 464
#ifdef DEBUG
          g_print ("Got BI_RGB compression\n");
#endif

465
          setMasksDefault (bitmap_head.biBitCnt, masks);
466
        }
467
    }
468 469 470 471 472
  else
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("Error reading BMP file header from '%s'"),
                   gimp_filename_to_utf8 (filename));
473
      goto out;
474
    }
Elliot Lee's avatar
Elliot Lee committed
475

476
  /* Valid bit depth is 1, 4, 8, 16, 24, 32 */
477
  /* 16 is awful, we should probably shoot whoever invented it */
478

479
  switch (bitmap_head.biBitCnt)
480 481 482 483 484 485 486 487 488 489 490 491 492
    {
    case 1:
    case 2:
    case 4:
    case 8:
    case 16:
    case 24:
    case 32:
      break;
    default:
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
493
      goto out;
494 495
    }

Elliot Lee's avatar
Elliot Lee committed
496
  /* There should be some colors used! */
497

498
  ColormapSize =
499
    (bitmap_file_head.bfOffs - bitmap_file_head.biSize - 14) / Maps;
500

501 502 503 504 505
  if ((bitmap_head.biClrUsed == 0) &&
      (bitmap_head.biBitCnt  <= 8))
    {
      ColormapSize = bitmap_head.biClrUsed = 1 << bitmap_head.biBitCnt;
    }
506

507 508
  if (ColormapSize > 256)
    ColormapSize = 256;
509 510 511

  /* Sanity checks */

512 513
  if (bitmap_head.biHeight == 0 ||
      bitmap_head.biWidth  == 0)
514 515 516 517
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
518
      goto out;
519
    }
520

521 522
  /* biHeight may be negative, but G_MININT32 is dangerous because:
     G_MININT32 == -(G_MININT32) */
523 524
  if (bitmap_head.biWidth  <  0 ||
      bitmap_head.biHeight == G_MININT32)
525
    {
526 527 528
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
529
      goto out;
530 531
    }

532
  if (bitmap_head.biPlanes != 1)
533 534 535 536
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
537
      goto out;
538
    }
539

540 541
  if (bitmap_head.biClrUsed >  256 &&
      bitmap_head.biBitCnt  <= 8)
542 543 544 545
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
546
      goto out;
547
    }
548

549
  /* protect against integer overflows caused by malicious BMPs */
550
  /* use divisions in comparisons to avoid type overflows */
551

552 553
  if (((guint64) bitmap_head.biWidth) > G_MAXINT32 / bitmap_head.biBitCnt ||
      ((guint64) bitmap_head.biWidth) > (G_MAXINT32 / ABS (bitmap_head.biHeight)) / 4)
554 555 556 557
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("'%s' is not a valid BMP file"),
                   gimp_filename_to_utf8 (filename));
558
      goto out;
559 560
    }

561 562
  /* Windows and OS/2 declare filler so that rows are a multiple of
   * word length (32 bits == 4 bytes)
563 564
   */

565
  rowbytes = ((bitmap_head.biWidth * bitmap_head.biBitCnt - 1) / 32) * 4 + 4;
566

Elliot Lee's avatar
Elliot Lee committed
567
#ifdef DEBUG
568 569
  printf ("\nSize: %lu, Colors: %lu, Bits: %hu, Width: %ld, Height: %ld, "
          "Comp: %lu, Zeile: %d\n",
570 571 572 573 574 575
          bitmap_file_head.bfSize,
          bitmap_head.biClrUsed,
          bitmap_head.biBitCnt,
          bitmap_head.biWidth,
          bitmap_head.biHeight,
          bitmap_head.biCompr,
576
          rowbytes);
Elliot Lee's avatar
Elliot Lee committed
577
#endif
578

579
  if (bitmap_head.biBitCnt <= 8)
580
    {
581 582 583
#ifdef DEBUG
      printf ("Colormap read\n");
#endif
584
      /* Get the Colormap */
585
      if (! ReadColorMap (fd, ColorMap, ColormapSize, Maps, &gray))
586
        goto out;
587
    }
588

589
  fseek (fd, bitmap_file_head.bfOffs, SEEK_SET);
590

Elliot Lee's avatar
Elliot Lee committed
591
  /* Get the Image and return the ID or -1 on error*/
592
  image_ID = ReadImage (fd,
593 594 595
                        filename,
                        bitmap_head.biWidth,
                        ABS (bitmap_head.biHeight),
596
                        ColorMap,
597 598 599
                        bitmap_head.biClrUsed,
                        bitmap_head.biBitCnt,
                        bitmap_head.biCompr,
600
                        rowbytes,
601
                        gray,
602 603
                        masks,
                        error);
604

605
  if (image_ID < 0)
606
    goto out;
607

608 609
  if (bitmap_head.biXPels > 0 &&
      bitmap_head.biYPels > 0)
610 611 612 613
    {
      /* Fixed up from scott@asofyet's changes last year, njl195 */
      gdouble xresolution;
      gdouble yresolution;
Elliot Lee's avatar
Elliot Lee committed
614

615 616 617 618 619
      /* I don't agree with scott's feeling that Gimp should be trying
       * to "fix" metric resolution translations, in the long term
       * Gimp should be SI (metric) anyway, but we haven't told the
       * Americans that yet
       */
620

621 622
      xresolution = bitmap_head.biXPels * 0.0254;
      yresolution = bitmap_head.biYPels * 0.0254;
623

624 625
      gimp_image_set_resolution (image_ID, xresolution, yresolution);
    }
Elliot Lee's avatar
Elliot Lee committed
626

627
  if (bitmap_head.biHeight < 0)
628 629
    gimp_image_flip (image_ID, GIMP_ORIENTATION_VERTICAL);

630 631 632 633
out:
  if (fd)
    fclose (fd);

634
  return image_ID;
Elliot Lee's avatar
Elliot Lee committed
635 636
}

637
static gint32
638 639 640 641 642 643 644 645 646 647 648 649
ReadImage (FILE                 *fd,
           const gchar          *filename,
           gint                  width,
           gint                  height,
           guchar                cmap[256][3],
           gint                  ncols,
           gint                  bpp,
           gint                  compression,
           gint                  rowbytes,
           gboolean              gray,
           const BitmapChannel  *masks,
           GError              **error)
Elliot Lee's avatar
Elliot Lee committed
650
{
651 652 653 654 655
  guchar             v, n;
  gint               xpos = 0;
  gint               ypos = 0;
  gint32             image;
  gint32             layer;
656 657
  GeglBuffer        *buffer;
  guchar            *dest, *temp, *row_buf;
658 659 660
  guchar             gimp_cmap[768];
  gushort            rgb;
  glong              rowstride, channels;
661 662
  gint               i, i_max, j, cur_progress, max_progress;
  gint               total_bytes_read;
663 664
  GimpImageBaseType  base_type;
  GimpImageType      image_type;
665
  guint32            px32;
666

667 668 669 670 671 672
  if (! (compression == BI_RGB ||
      (bpp == 8 && compression == BI_RLE8) ||
      (bpp == 4 && compression == BI_RLE4) ||
      (bpp == 16 && compression == BI_BITFIELDS) ||
      (bpp == 32 && compression == BI_BITFIELDS)))
    {
673 674 675
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   "%s",
                   _("Unrecognized or invalid BMP compression format."));
676 677 678
      return -1;
    }

679
  /* Make a new image in GIMP */
680

681
  switch (bpp)
682
    {
683 684 685 686
    case 32:
    case 24:
    case 16:
      base_type = GIMP_RGB;
687
      if (masks[3].mask != 0)
688 689 690 691
        {
          image_type = GIMP_RGBA_IMAGE;
          channels = 4;
        }
692
      else
693 694 695 696
        {
          image_type = GIMP_RGB_IMAGE;
          channels = 3;
        }
697 698 699 700 701
      break;

    case 8:
    case 4:
    case 1:
702
      if (gray)
703 704
        {
          base_type = GIMP_GRAY;
705
          image_type = GIMP_GRAY_IMAGE;
706 707 708 709 710 711 712
        }
      else
        {
          base_type = GIMP_INDEXED;
          image_type = GIMP_INDEXED_IMAGE;
        }

713
      channels = 1;
714 715 716
      break;

    default:
717
      g_message (_("Unsupported or invalid bitdepth."));
718
      return -1;
Elliot Lee's avatar
Elliot Lee committed
719
    }
720

721 722 723 724 725
  if ((width < 0) || (width > GIMP_MAX_IMAGE_SIZE))
    {
      g_message (_("Unsupported or invalid image width: %d"), width);
      return -1;
    }
726

727 728 729 730 731
  if ((height < 0) || (height > GIMP_MAX_IMAGE_SIZE))
    {
      g_message (_("Unsupported or invalid image height: %d"), height);
      return -1;
    }
732

733 734 735
  image = gimp_image_new (width, height, base_type);
  layer = gimp_layer_new (image, _("Background"),
                          width, height,
736 737
                          image_type, 100,
                          gimp_image_get_default_new_layer_mode (image));
738

739
  gimp_image_set_filename (image, filename);
740

741
  gimp_image_insert_layer (image, layer, -1, 0);
742

743 744 745
  /* use g_malloc0 to initialize the dest buffer so that unspecified
     pixels in RLE bitmaps show up as the zeroth element in the palette.
  */
746 747 748
  dest      = g_malloc0 (width * height * channels);
  row_buf   = g_malloc (rowbytes);
  rowstride = width * channels;
749

750
  ypos = height - 1;  /* Bitmaps begin in the lower left corner */
Elliot Lee's avatar
Elliot Lee committed
751 752
  cur_progress = 0;
  max_progress = height;
753

754
  switch (bpp)
755
    {
756 757
    case 32:
      {
758
        while (ReadOK (fd, row_buf, rowbytes))
759 760
          {
            temp = dest + (ypos * rowstride);
761

762 763
            for (xpos= 0; xpos < width; ++xpos)
              {
764
                px32 = ToL(&row_buf[xpos*4]);
765 766 767
                *(temp++) = ((px32 & masks[0].mask) >> masks[0].shiftin) * 255.0 / masks[0].max_value + 0.5;
                *(temp++) = ((px32 & masks[1].mask) >> masks[1].shiftin) * 255.0 / masks[1].max_value + 0.5;
                *(temp++) = ((px32 & masks[2].mask) >> masks[2].shiftin) * 255.0 / masks[2].max_value + 0.5;
768
                if (channels > 3)
769
                  *(temp++) = ((px32 & masks[3].mask) >> masks[3].shiftin) * 255.0 / masks[3].max_value + 0.5;
770
              }
771

772 773
            if (ypos == 0)
              break;
774

775
            --ypos; /* next line */
776

777 778 779 780 781 782 783
            cur_progress++;
            if ((cur_progress % 5) == 0)
              gimp_progress_update ((gdouble) cur_progress /
                                    (gdouble) max_progress);
          }
      }
      break;
784

785 786
    case 24:
      {
787
        while (ReadOK (fd, row_buf, rowbytes))
788 789
          {
            temp = dest + (ypos * rowstride);
790

791 792
            for (xpos= 0; xpos < width; ++xpos)
              {
793 794 795
                *(temp++) = row_buf[xpos * 3 + 2];
                *(temp++) = row_buf[xpos * 3 + 1];
                *(temp++) = row_buf[xpos * 3];
796
              }
797

798 799
            if (ypos == 0)
              break;
800

801
            --ypos; /* next line */
802

803 804 805 806 807 808 809
            cur_progress++;
            if ((cur_progress % 5) == 0)
              gimp_progress_update ((gdouble) cur_progress /
                                    (gdouble) max_progress);
          }
      }
      break;
810

811 812
    case 16:
      {
813
        while (ReadOK (fd, row_buf, rowbytes))
814 815
          {
            temp = dest + (ypos * rowstride);
816

817 818
            for (xpos= 0; xpos < width; ++xpos)
              {
819
                rgb= ToS(&row_buf[xpos * 2]);
820 821 822
                *(temp++) = ((rgb & masks[0].mask) >> masks[0].shiftin) * 255.0 / masks[0].max_value + 0.5;
                *(temp++) = ((rgb & masks[1].mask) >> masks[1].shiftin) * 255.0 / masks[1].max_value + 0.5;
                *(temp++) = ((rgb & masks[2].mask) >> masks[2].shiftin) * 255.0 / masks[2].max_value + 0.5;
823
                if (channels > 3)
824
                  *(temp++) = ((rgb & masks[3].mask) >> masks[3].shiftin) * 255.0 / masks[3].max_value + 0.5;
825
              }
826

827 828
            if (ypos == 0)
              break;
829

830
            --ypos; /* next line */
831

832 833 834 835 836 837 838 839 840 841 842 843 844
            cur_progress++;
            if ((cur_progress % 5) == 0)
              gimp_progress_update ((gdouble) cur_progress /
                                    (gdouble) max_progress);
          }
      }
      break;

    case 8:
    case 4:
    case 1:
      {
        if (compression == 0)
845
          /* no compression */
846 847 848 849 850 851 852
          {
            while (ReadOK (fd, &v, 1))
              {
                for (i = 1; (i <= (8 / bpp)) && (xpos < width); i++, xpos++)
                  {
                    temp = dest + (ypos * rowstride) + (xpos * channels);
                    *temp=( v & ( ((1<<bpp)-1) << (8-(i*bpp)) ) ) >> (8-(i*bpp));
853
                    if (gray)
854 855
                      *temp = cmap[*temp][0];
                  }
856

857 858
                if (xpos == width)
                  {
859
                    fread (row_buf, rowbytes - 1 - (width * bpp - 1) / 8, 1, fd);
860

861 862
                    if (ypos == 0)
                      break;
863

864 865 866 867 868 869 870 871
                    ypos--;
                    xpos = 0;

                    cur_progress++;
                    if ((cur_progress % 5) == 0)
                      gimp_progress_update ((gdouble) cur_progress /
                                            (gdouble) max_progress);
                  }
872

873 874 875 876 877 878 879
                if (ypos < 0)
                  break;
              }
            break;
          }
        else
          {
880
            /* compressed image (either RLE8 or RLE4) */
881 882
            while (ypos >= 0 && xpos <= width)
              {
883
                if (! ReadOK (fd, row_buf, 2))
884 885 886 887 888
                  {
                    g_message (_("The bitmap ends unexpectedly."));
                    break;
                  }

889
                if (row_buf[0] != 0)
890 891
                  /* Count + Color - record */
                  {
892
                    /* encoded mode run -
893 894 895
                     *   row_buf[0] == run_length
                     *   row_buf[1] == pixel data
                     */
896
                    for (j = 0;
897
                         ((guchar) j < row_buf[0]) && (xpos < width);)
898
                      {
Manish Singh's avatar
Manish Singh committed
899
#ifdef DEBUG2
900
                        printf("%u %u | ",xpos,width);
Manish Singh's avatar
Manish Singh committed
901
#endif
902 903 904
                        for (i = 1;
                             ((i <= (8 / bpp)) &&
                              (xpos < width) &&
905
                              ((guchar) j < row_buf[0]));
906 907 908
                             i++, xpos++, j++)
                          {
                            temp = dest + (ypos * rowstride) + (xpos * channels);
909
                            *temp = (row_buf[1] &
910
                                     (((1<<bpp)-1) << (8 - (i * bpp)))) >> (8 - (i * bpp));
911
                            if (gray)
912 913 914 915
                              *temp = cmap[*temp][0];
                          }
                      }
                  }
916

917
                if ((row_buf[0] == 0) && (row_buf[1] > 2))
918 919
                  /* uncompressed record */
                  {
920
                    n = row_buf[1];
921
                    total_bytes_read = 0;
922

923 924
                    for (j = 0; j < n; j += (8 / bpp))
                      {
925
                        /* read the next byte in the record */
926
                        if (! ReadOK (fd, &v, 1))
927 928 929 930
                          {
                            g_message (_("The bitmap ends unexpectedly."));
                            break;
                          }
931

932 933 934 935 936 937 938 939 940
                        total_bytes_read++;

                        /* read all pixels from that byte */
                        i_max = 8 / bpp;
                        if (n - j < i_max)
                          {
                            i_max = n - j;
                          }

941 942 943 944 945
                        i = 1;
                        while ((i <= i_max) && (xpos < width))
                          {
                            temp =
                              dest + (ypos * rowstride) + (xpos * channels);
946
                            *temp = (v >> (8-(i*bpp))) & ((1<<bpp)-1);
947
                            if (gray)
948 949 950 951 952
                              *temp = cmap[*temp][0];
                            i++;
                            xpos++;
                          }
                      }
953

954 955
                    /* absolute mode runs are padded to 16-bit alignment */
                    if (total_bytes_read % 2)
956
                      fread (&v, 1, 1, fd);
957
                  }
958

959
                if ((row_buf[0] == 0) && (row_buf[1] == 0))
960 961 962 963 964 965 966 967 968 969
                  /* Line end */
                  {
                    ypos--;
                    xpos = 0;

                    cur_progress++;
                    if ((cur_progress % 5) == 0)
                      gimp_progress_update ((gdouble) cur_progress /
                                            (gdouble)  max_progress);
                  }
970

971
                if ((row_buf[0] == 0) && (row_buf[1] == 1))
972 973 974 975
                  /* Bitmap end */
                  {
                    break;
                  }
976

977
                if ((row_buf[0] == 0) && (row_buf[1] == 2))
978 979
                  /* Deltarecord */
                  {
980
                    if (! ReadOK (fd, row_buf, 2))
981 982 983 984
                      {
                        g_message (_("The bitmap ends unexpectedly."));
                        break;
                      }
985

986 987
                    xpos += row_buf[0];
                    ypos -= row_buf[1];
988 989 990 991
                  }
              }
            break;
          }
992 993 994 995 996 997
      }
      break;

    default:
      g_assert_not_reached ();
      break;
Manish Singh's avatar
Manish Singh committed
998
    }
999

1000
  if (bpp <= 8)
1001 1002
    for (i = 0, j = 0; i < ncols; i++)
      {
1003 1004 1005
        gimp_cmap[j++] = cmap[i][0];
        gimp_cmap[j++] = cmap[i][1];
        gimp_cmap[j++] = cmap[i][2];
1006 1007
      }

1008
  buffer = gimp_drawable_get_buffer (layer);
1009

1010 1011 1012 1013 1014 1015
  gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
                   NULL, dest, GEGL_AUTO_ROWSTRIDE);

  g_object_unref (buffer);

  g_free (dest);
1016

1017
  if ((! gray) && (bpp <= 8))
1018
    gimp_image_set_colormap (image, gimp_cmap, ncols);
1019

1020
  gimp_progress_update (1.0);
1021

1022
  return image;
Elliot Lee's avatar
Elliot Lee committed
1023
}