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

4
/*
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * ----------------------------------------------------------------------------
 */

24
#include "config.h"
25

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

29
30
#include <glib/gstdio.h>

31
#include <libgimp/gimp.h>
32
33
34

#include "bmp.h"

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

37

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

45
46
47
48
49
50
51
52
static gint32 ReadImage (FILE     *fd,
                         gint      width,
                         gint      height,
                         guchar    cmap[256][3],
                         gint      ncols,
                         gint      bpp,
                         gint      compression,
                         gint      rowbytes,
53
54
                         gboolean  grey,
                         const Bitmap_Channel *masks);
55

56

57
static gint32
58
ToL (const guchar *puffer)
59
{
60
  return (puffer[0] | puffer[1] << 8 | puffer[2] << 16 | puffer[3] << 24);
61
62
}

63
static gint16
64
ToS (const guchar *puffer)
65
{
66
  return (puffer[0] | puffer[1] << 8);
67
68
69
}

static gboolean
70
71
72
73
74
ReadColorMap (FILE     *fd,
	      guchar    buffer[256][3],
	      gint      number,
	      gint      size,
	      gboolean *grey)
75
{
76
  gint   i;
77
  guchar rgb[4];
78

79
80
  *grey = (number > 2);

81
82
83
84
  for (i = 0; i < number ; i++)
    {
      if (!ReadOK (fd, rgb, size))
	{
85
	  g_message (_("Bad colormap"));
86
87
	  return FALSE;
	}
88

89
90
91
92
93
94
95
96
97
98
      /* 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];
      *grey = ((*grey) && (rgb[0]==rgb[1]) && (rgb[1]==rgb[2]));
    }
  return TRUE;
}

99
100
101
102
103
104
static gboolean
ReadChannelMasks (FILE *fd, Bitmap_Channel *masks, guint channels)
{
  guint32 tmp[3];
  guint32 mask;
  gint   i, nbits, offset, bit;
105

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  if (!ReadOK (fd, tmp, 3 * sizeof (guint32)))
    return FALSE;

  for (i = 0; i < channels; i++)
    {
      mask = ToL ((guchar*) &tmp[i]);
      masks[i].mask = mask;
      nbits = 0;
      offset = -1;
      for (bit = 0; bit < 32; bit++)
        {
          if (mask & 1)
            {
              nbits++;
              if (offset == -1)
                offset = bit;
            }
          mask = mask >> 1;
        }
      masks[i].shiftin = offset;
      masks[i].shiftout = 8 - nbits;
#ifdef DEBUG
128
129
      g_print ("Channel %d mask %08x in %d out %d\n",
               i, masks[i].mask, masks[i].shiftin, masks[i].shiftout);
130
131
132
133
134
#endif
    }
  return TRUE;
}

135
gint32
136
ReadBMP (const gchar *name)
Elliot Lee's avatar
Elliot Lee committed
137
{
138
139
140
141
142
143
144
  FILE     *fd;
  guchar    buffer[64];
  gint      ColormapSize, rowbytes, Maps;
  gboolean  Grey;
  guchar    ColorMap[256][3];
  gint32    image_ID;
  guchar    magick[2];
145
  Bitmap_Channel *masks;
Elliot Lee's avatar
Elliot Lee committed
146
147

  filename = name;
148
  fd = g_fopen (filename, "rb");
149

Elliot Lee's avatar
Elliot Lee committed
150
151
  if (!fd)
    {
152
      g_message (_("Could not open '%s' for reading: %s"),
153
                 gimp_filename_to_utf8 (filename), g_strerror (errno));
Elliot Lee's avatar
Elliot Lee committed
154
155
156
      return -1;
    }

Sven Neumann's avatar
Sven Neumann committed
157
158
159
  gimp_progress_init (NULL);
  gimp_progress_set_text (_("Opening '%s'..."),
                          gimp_filename_to_utf8 (name));
160

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

163
164
165
166
  if (!ReadOK (fd, magick, 2) || !(!strncmp (magick, "BA", 2) ||
     !strncmp (magick, "BM", 2) || !strncmp (magick, "IC", 2) ||
     !strncmp (magick, "PI", 2) || !strncmp (magick, "CI", 2) ||
     !strncmp (magick, "CP", 2)))
167
    {
168
169
      g_message (_("'%s' is not a valid BMP file"),
                 gimp_filename_to_utf8 (filename));
170
171
      return -1;
    }
172

173
  while (!strncmp (magick, "BA", 2))
174
    {
175
      if (!ReadOK (fd, buffer, 12))
176
	{
177
          g_message (_("'%s' is not a valid BMP file"),
178
                      gimp_filename_to_utf8 (filename));
179
180
          return -1;
        }
181
      if (!ReadOK (fd, magick, 2))
182
	{
183
          g_message (_("'%s' is not a valid BMP file"),
184
                      gimp_filename_to_utf8 (filename));
185
186
187
188
          return -1;
        }
    }

189
  if (!ReadOK (fd, buffer, 12))
Elliot Lee's avatar
Elliot Lee committed
190
    {
191
      g_message (_("'%s' is not a valid BMP file"),
192
                  gimp_filename_to_utf8 (filename));
Elliot Lee's avatar
Elliot Lee committed
193
194
      return -1;
    }
Manish Singh's avatar
Manish Singh committed
195

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

198
199
200
201
  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]);
202

203
  if (!ReadOK (fd, buffer, 4))
204
    {
205
206
      g_message (_("'%s' is not a valid BMP file"),
                  gimp_filename_to_utf8 (filename));
207
208
      return -1;
    }
209

210
  Bitmap_File_Head.biSize    = ToL (&buffer[0x00]);
211
212
213

  /* What kind of bitmap is it? */

214
  if (Bitmap_File_Head.biSize == 12) /* OS/2 1.x ? */
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
215
    {
216
      if (!ReadOK (fd, buffer, 8))
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
217
        {
218
219
          g_message (_("Error reading BMP file header from '%s'"),
                      gimp_filename_to_utf8 (filename));
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
220
221
          return -1;
        }
222

223
224
225
226
227
228
229
      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;
230
      Bitmap_Head.biClrUsed = 0;
Asbjørn Pettersen's avatar
Asbjørn Pettersen committed
231
232
      Maps = 3;
    }
233
  else if (Bitmap_File_Head.biSize == 40) /* Windows 3.x */
Elliot Lee's avatar
Elliot Lee committed
234
    {
235
      if (!ReadOK (fd, buffer, Bitmap_File_Head.biSize - 4))
Elliot Lee's avatar
Elliot Lee committed
236
        {
237
238
          g_message (_("Error reading BMP file header from '%s'"),
                      gimp_filename_to_utf8 (filename));
Elliot Lee's avatar
Elliot Lee committed
239
240
          return -1;
        }
241
242
243
244
245
246
247
248
249
250
      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 */
251
252
    					                /* 36 */
      Maps = 4;
Elliot Lee's avatar
Elliot Lee committed
253
    }
254
  else if (Bitmap_File_Head.biSize <= 64) /* Probably OS/2 2.x */
Elliot Lee's avatar
Elliot Lee committed
255
    {
256
      if (!ReadOK (fd, buffer, Bitmap_File_Head.biSize - 4))
Elliot Lee's avatar
Elliot Lee committed
257
        {
258
259
          g_message (_("Error reading BMP file header from '%s'"),
                      gimp_filename_to_utf8 (filename));
Elliot Lee's avatar
Elliot Lee committed
260
261
          return -1;
        }
262
263
264
265
266
267
268
269
270
271
272
273
      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 */
                                                        /* 36 */
      Maps = 3;
Elliot Lee's avatar
Elliot Lee committed
274
    }
275
  else
276
    {
277
278
      g_message (_("Error reading BMP file header from '%s'"),
                  gimp_filename_to_utf8 (filename));
279
280
      return -1;
    }
Elliot Lee's avatar
Elliot Lee committed
281

282
  /* Valid bitpdepthis 1, 4, 8, 16, 24, 32 */
283
  /* 16 is awful, we should probably shoot whoever invented it */
284

Elliot Lee's avatar
Elliot Lee committed
285
  /* There should be some colors used! */
286

287
288
  ColormapSize = (Bitmap_File_Head.bfOffs - Bitmap_File_Head.biSize - 14) / Maps;

289
  if ((Bitmap_Head.biClrUsed == 0) && (Bitmap_Head.biBitCnt <= 8))
290
    ColormapSize = Bitmap_Head.biClrUsed = 1 << Bitmap_Head.biBitCnt;
291

292
293
  if (ColormapSize > 256)
    ColormapSize = 256;
294
295
296
297

  /* Sanity checks */

  if (Bitmap_Head.biHeight == 0 || Bitmap_Head.biWidth == 0) {
298
299
      g_message (_("Error reading BMP file header from '%s'"),
                  gimp_filename_to_utf8 (filename));
300
301
302
      return -1;
  }

303
304
305
306
307
308
309
  if (Bitmap_Head.biWidth < 0)
    {
      g_message (_("'%s' is not a valid BMP file"),
                  gimp_filename_to_utf8 (filename));
      return -1;
    }

310
  if (Bitmap_Head.biPlanes != 1) {
311
312
      g_message (_("Error reading BMP file header from '%s'"),
                  gimp_filename_to_utf8 (filename));
313
314
315
      return -1;
  }

316
  if (Bitmap_Head.biClrUsed > 256) {
317
318
      g_message (_("Error reading BMP file header from '%s'"),
                  gimp_filename_to_utf8 (filename));
319
320
321
322
323
      return -1;
  }

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

326
  rowbytes= ((Bitmap_Head.biWidth * Bitmap_Head.biBitCnt - 1) / 32) * 4 + 4;
327

Elliot Lee's avatar
Elliot Lee committed
328
#ifdef DEBUG
329
330
331
332
333
334
335
336
337
  printf ("\nSize: %u, Colors: %u, Bits: %u, Width: %u, Height: %u, "
          "Comp: %u, Zeile: %u\n",
          Bitmap_File_Head.bfSize,
          Bitmap_Head.biClrUsed,
          Bitmap_Head.biBitCnt,
          Bitmap_Head.biWidth,
          Bitmap_Head.biHeight,
          Bitmap_Head.biCompr,
          rowbytes);
Elliot Lee's avatar
Elliot Lee committed
338
#endif
339

340
  if (Bitmap_Head.biCompr == BI_BITFIELDS &&
341
      Bitmap_Head.biBitCnt == 16)
342
    {
343
344
345
      masks = g_new (Bitmap_Channel, 3);
      if (! ReadChannelMasks (fd, masks, 3))
        {
346
          g_message (_("'%s' is not a valid BMP file"),
347
                      gimp_filename_to_utf8 (filename));
348
349
          return -1;
        }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
    }
  else if (Bitmap_Head.biBitCnt == 16)
    {
      /* Default is 5.5.5 if no masks are given */
      masks = g_new (Bitmap_Channel, 3);
      masks[0].mask     = 0x7c00;
      masks[0].shiftin  = 10;
      masks[0].shiftout = 3;
      masks[1].mask     = 0x03e0;
      masks[1].shiftin  = 5;
      masks[1].shiftout = 3;
      masks[2].mask     = 0x001f;
      masks[2].shiftin  = 0;
      masks[2].shiftout = 3;
364
365
366
367
368
    }
  else
    {
      /* Get the Colormap */
      if (!ReadColorMap (fd, ColorMap, ColormapSize, Maps, &Grey))
369
370
        return -1;
      masks = NULL;
371
    }
372

Elliot Lee's avatar
Elliot Lee committed
373
#ifdef DEBUG
374
  printf ("Colormap read\n");
Elliot Lee's avatar
Elliot Lee committed
375
376
#endif

377
  fseek (fd, Bitmap_File_Head.bfOffs, SEEK_SET);
378

Elliot Lee's avatar
Elliot Lee committed
379
  /* Get the Image and return the ID or -1 on error*/
380
381
  image_ID = ReadImage (fd,
			Bitmap_Head.biWidth,
382
			ABS (Bitmap_Head.biHeight),
383
384
385
386
387
			ColorMap,
			Bitmap_Head.biClrUsed,
			Bitmap_Head.biBitCnt,
			Bitmap_Head.biCompr,
			rowbytes,
388
389
			Grey,
			masks);
390

391
  if (Bitmap_Head.biXPels > 0 && Bitmap_Head.biYPels > 0)
392
393
394
395
    {
      /* Fixed up from scott@asofyet's changes last year, njl195 */
      gdouble xresolution;
      gdouble yresolution;
Elliot Lee's avatar
Elliot Lee committed
396

397
398
399
400
      /* 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  */
401

402
403
      xresolution = Bitmap_Head.biXPels * 0.0254;
      yresolution = Bitmap_Head.biYPels * 0.0254;
404

405
406
      gimp_image_set_resolution (image_ID, xresolution, yresolution);
    }
Elliot Lee's avatar
Elliot Lee committed
407

408
409
410
  if (Bitmap_Head.biHeight < 0)
    gimp_image_flip (image_ID, GIMP_ORIENTATION_VERTICAL);

411
  return image_ID;
Elliot Lee's avatar
Elliot Lee committed
412
413
}

414
415
416
417
418
419
420
421
422
static gint32
ReadImage (FILE     *fd,
	   gint      width,
	   gint      height,
	   guchar    cmap[256][3],
	   gint      ncols,
	   gint      bpp,
	   gint      compression,
	   gint      rowbytes,
423
424
	   gboolean  grey,
	   const Bitmap_Channel *masks)
Elliot Lee's avatar
Elliot Lee committed
425
{
426
427
428
429
430
431
432
433
434
435
436
  guchar             v, n;
  GimpPixelRgn       pixel_rgn;
  gint               xpos = 0;
  gint               ypos = 0;
  gint32             image;
  gint32             layer;
  GimpDrawable      *drawable;
  guchar            *dest, *temp, *buffer;
  guchar             gimp_cmap[768];
  gushort            rgb;
  glong              rowstride, channels;
437
438
  gint               i, i_max, j, cur_progress, max_progress;
  gint               total_bytes_read;
439
440
  GimpImageBaseType  base_type;
  GimpImageType      image_type;
441

442
443
444
445
446
447
448
449
450
451
  if (! (compression == BI_RGB ||
      (bpp == 8 && compression == BI_RLE8) ||
      (bpp == 4 && compression == BI_RLE4) ||
      (bpp == 16 && compression == BI_BITFIELDS) ||
      (bpp == 32 && compression == BI_BITFIELDS)))
    {
      g_message (_("Unrecognized or invalid BMP compression format."));
      return -1;
    }

Elliot Lee's avatar
Elliot Lee committed
452
  /* Make a new image in the gimp */
453

454
  switch (bpp)
455
    {
456
457
458
459
460
461
    case 32:
    case 24:
    case 16:
      base_type = GIMP_RGB;
      image_type = GIMP_RGB_IMAGE;

462
      channels = 3;
463
464
465
466
467
468
469
470
      break;

    case 8:
    case 4:
    case 1:
      if (grey)
        {
          base_type = GIMP_GRAY;
471
          image_type = GIMP_GRAY_IMAGE;
472
473
474
475
476
477
478
        }
      else
        {
          base_type = GIMP_INDEXED;
          image_type = GIMP_INDEXED_IMAGE;
        }

479
      channels = 1;
480
481
482
      break;

    default:
483
      g_message (_("Unsupported or invalid bitdepth."));
484
      return -1;
Elliot Lee's avatar
Elliot Lee committed
485
    }
486

487
488
489
490
491
  image = gimp_image_new (width, height, base_type);
  layer = gimp_layer_new (image, _("Background"),
                          width, height,
                          image_type, 100, GIMP_NORMAL_MODE);

492
  gimp_image_set_filename (image, filename);
493

494
495
  gimp_image_add_layer (image, layer, 0);
  drawable = gimp_drawable_get (layer);
496

497
498
499
500
  /* use g_malloc0 to initialize the dest buffer so that unspecified
     pixels in RLE bitmaps show up as the zeroth element in the palette.
  */
  dest      = g_malloc0 (drawable->width * drawable->height * channels);
501
  buffer    = g_malloc (rowbytes);
Elliot Lee's avatar
Elliot Lee committed
502
  rowstride = drawable->width * channels;
503

504
  ypos = height - 1;  /* Bitmaps begin in the lower left corner */
Elliot Lee's avatar
Elliot Lee committed
505
506
  cur_progress = 0;
  max_progress = height;
507

508
  switch (bpp)
509
    {
510
511
512
513
514
515
516
517
518
519
520
    case 32:
      {
        while (ReadOK (fd, buffer, rowbytes))
          {
            temp = dest + (ypos * rowstride);
            for (xpos= 0; xpos < width; ++xpos)
              {
                *(temp++)= buffer[xpos * 4 + 2];
                *(temp++)= buffer[xpos * 4 + 1];
                *(temp++)= buffer[xpos * 4];
              }
521
522
            if (ypos == 0)
              break;
523
524
525
526
527
528
529
530
            --ypos; /* next line */
            cur_progress++;
            if ((cur_progress % 5) == 0)
              gimp_progress_update ((gdouble) cur_progress /
                                    (gdouble) max_progress);
          }
      }
      break;
531

532
533
534
535
536
537
538
539
540
541
542
    case 24:
      {
        while (ReadOK (fd, buffer, rowbytes))
          {
            temp = dest + (ypos * rowstride);
            for (xpos= 0; xpos < width; ++xpos)
              {
                *(temp++)= buffer[xpos * 3 + 2];
                *(temp++)= buffer[xpos * 3 + 1];
                *(temp++)= buffer[xpos * 3];
              }
543
544
            if (ypos == 0)
              break;
545
546
547
548
549
550
551
552
            --ypos; /* next line */
            cur_progress++;
            if ((cur_progress % 5) == 0)
              gimp_progress_update ((gdouble) cur_progress /
                                    (gdouble) max_progress);
          }
      }
      break;
553

554
555
556
557
558
559
560
561
    case 16:
      {
        while (ReadOK (fd, buffer, rowbytes))
          {
            temp = dest + (ypos * rowstride);
            for (xpos= 0; xpos < width; ++xpos)
              {
                rgb= ToS(&buffer[xpos * 2]);
562
563
564
                *(temp++) = ((rgb & masks[0].mask) >> masks[0].shiftin) << masks[0].shiftout;
                *(temp++) = ((rgb & masks[1].mask) >> masks[1].shiftin) << masks[1].shiftout;
                *(temp++) = ((rgb & masks[2].mask) >> masks[2].shiftin) << masks[2].shiftout;
565
              }
566
567
            if (ypos == 0)
              break;
568
569
570
571
572
573
574
575
576
577
578
579
580
581
            --ypos; /* next line */
            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)
582
          /* no compression */
Manish Singh's avatar
Manish Singh committed
583
	  {
584
585
	    while (ReadOK (fd, &v, 1))
	      {
586
		for (i = 1; (i <= (8 / bpp)) && (xpos < width); i++, xpos++)
587
588
589
590
591
592
		  {
		    temp = dest + (ypos * rowstride) + (xpos * channels);
		    *temp=( v & ( ((1<<bpp)-1) << (8-(i*bpp)) ) ) >> (8-(i*bpp));
		    if (grey)
		      *temp = cmap[*temp][0];
		  }
593
		if (xpos == width)
594
		  {
595
		    ReadOK (fd, buffer, rowbytes - 1 - (width * bpp - 1) / 8);
596
597
            if (ypos == 0)
              break;
598
599
600
601
		    ypos--;
		    xpos = 0;

		    cur_progress++;
602
		    if ((cur_progress % 5) == 0)
603
604
605
606
607
608
609
		      gimp_progress_update ((gdouble) cur_progress /
					    (gdouble) max_progress);
		  }
		if (ypos < 0)
		  break;
	      }
	    break;
Manish Singh's avatar
Manish Singh committed
610
	  }
611
	else
Manish Singh's avatar
Manish Singh committed
612
	  {
613
            /* compressed image (either RLE8 or RLE4) */
614
	    while (ypos >= 0 && xpos <= width)
Manish Singh's avatar
Manish Singh committed
615
	      {
616
		ReadOK (fd, buffer, 2);
617
		if ((guchar) buffer[0] != 0)
618
		  /* Count + Color - record */
Manish Singh's avatar
Manish Singh committed
619
		  {
620
621
622
623
                    /* encoded mode run -
                         buffer[0] == run_length
                         buffer[1] == pixel data
                    */
624
		    for (j = 0; ((guchar) j < (guchar) buffer[0]) && (xpos < width);)
625
		      {
Manish Singh's avatar
Manish Singh committed
626
#ifdef DEBUG2
627
			printf("%u %u | ",xpos,width);
Manish Singh's avatar
Manish Singh committed
628
#endif
629
630
			for (i = 1;
			     ((i <= (8 / bpp)) &&
631
			      (xpos < width) &&
632
			      ((guchar) j < (unsigned char) buffer[0]));
633
634
635
			     i++, xpos++, j++)
			  {
			    temp = dest + (ypos * rowstride) + (xpos * channels);
636
			    *temp = (buffer[1] & (((1<<bpp)-1) << (8 - (i * bpp)))) >> (8 - (i * bpp));
637
638
639
			    if (grey)
			      *temp = cmap[*temp][0];
			  }
Manish Singh's avatar
Manish Singh committed
640
641
		      }
		  }
642
		if (((guchar) buffer[0] == 0) && ((guchar) buffer[1] > 2))
643
		  /* uncompressed record */
Manish Singh's avatar
Manish Singh committed
644
		  {
645
		    n = buffer[1];
646
                    total_bytes_read = 0;
647
		    for (j = 0; j < n; j += (8 / bpp))
Manish Singh's avatar
Manish Singh committed
648
		      {
649
650
651
652
653
654
655
656
657
658
659
                        /* read the next byte in the record */
                        ReadOK (fd, &v, 1);
                        total_bytes_read++;

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

660
			i = 1;
661
			while ((i <= i_max) && (xpos < width))
662
663
			  {
			    temp = dest + (ypos * rowstride) + (xpos * channels);
664
                            *temp = (v >> (8-(i*bpp))) & ((1<<bpp)-1);
665
666
667
668
669
			    if (grey)
			      *temp = cmap[*temp][0];
			    i++;
			    xpos++;
			  }
Manish Singh's avatar
Manish Singh committed
670
		      }
671

672
673
674
                    /* absolute mode runs are padded to 16-bit alignment */
                    if (total_bytes_read % 2)
                      ReadOK (fd, &v, 1);
675
		  }
676
		if (((guchar) buffer[0] == 0) && ((guchar) buffer[1]==0))
Stanislav Brabec's avatar
Stanislav Brabec committed
677
		  /* Line end */
678
679
680
681
682
		  {
		    ypos--;
		    xpos = 0;

		    cur_progress++;
683
		    if ((cur_progress % 5) == 0)
684
685
686
		      gimp_progress_update ((gdouble) cur_progress /
					    (gdouble)  max_progress);
		  }
687
		if (((guchar) buffer[0]==0) && ((guchar) buffer[1]==1))
Stanislav Brabec's avatar
Stanislav Brabec committed
688
		  /* Bitmap end */
689
690
691
		  {
		    break;
		  }
692
		if (((guchar) buffer[0]==0) && ((guchar) buffer[1]==2))
693
694
		  /* Deltarecord */
		  {
695
		    ReadOK (fd, buffer, 2);
696
697
		    xpos += (guchar) buffer[0];
		    ypos -= (guchar) buffer[1];
Manish Singh's avatar
Manish Singh committed
698
699
		  }
	      }
700
	    break;
Manish Singh's avatar
Manish Singh committed
701
	  }
702
703
704
705
706
707
      }
      break;

    default:
      g_assert_not_reached ();
      break;
Manish Singh's avatar
Manish Singh committed
708
    }
709

710
  fclose (fd);
711
  if (bpp <= 8)
712
713
    for (i = 0, j = 0; i < ncols; i++)
      {
714
715
716
        gimp_cmap[j++] = cmap[i][0];
        gimp_cmap[j++] = cmap[i][1];
        gimp_cmap[j++] = cmap[i][2];
717
718
      }

719
  gimp_progress_update (1);
720
721

  gimp_pixel_rgn_init (&pixel_rgn, drawable,
722
                       0, 0, drawable->width, drawable->height, TRUE, FALSE);
723
  gimp_pixel_rgn_set_rect (&pixel_rgn, dest,
724
                           0, 0, drawable->width, drawable->height);
725

726
  if ((!grey) && (bpp<= 8))
727
    gimp_image_set_colormap (image, gimp_cmap, ncols);
728

729
730
731
  gimp_drawable_flush (drawable);
  gimp_drawable_detach (drawable);
  g_free (dest);
732

733
  return image;
Elliot Lee's avatar
Elliot Lee committed
734
}