Commit 743b449a authored by Arjan van de Ven's avatar Arjan van de Ven Committed by Arjan van de Ven

Major cleanup, added support for 32 bpp and 4 bpp (uncompressed) images,

1999-12-04  Arjan van de Ven <arjan@fenrus.demon.nl>

	* gdk-pixbuf/io-bmp.c: Major cleanup, added support for
	32 bpp and 4 bpp (uncompressed) images, fixed 1bpp.

	* gdk-pixbuf/io-ras.c: Minor cleanup, ran through lclint

	* gdk-pixbuf/io-ico.c: Minor cleanup, fixed 1bpp icons,
 	ran through lclint.

	* gdk-pixbuf/gdk-pixbuf-io.c: Added detection of .CUR files
	(Windows Cursor files). These are identical to .ICO files,
	except for the signature and 2 extra fields for the hotspot.
parent a7a48b82
......@@ -145,7 +145,7 @@ pixbuf_check_ico (guchar *buffer, int size)
return FALSE;
if (buffer [0] != 0x0 ||
buffer [1] != 0x0 ||
buffer [2] != 0x1 ||
((buffer [2] != 0x1)&&(buffer[2]!=0x2)) ||
buffer [3] != 0x0 ||
buffer [5] != 0x0 )
return FALSE;
......
......@@ -26,33 +26,27 @@
/*
Known bugs:
* Compressed files don't work yet
* bi-tonal files aren't tested
* 4bpp compressed files don't work
* bi-tonal files aren't tested with palettes
*/
#include <config.h>
#include <stdio.h>
#include <unistd.h>
#include "gdk-pixbuf.h"
#include "gdk-pixbuf-io.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk-pixbuf/gdk-pixbuf-io.h>
struct headerpair {
guint width;
guint height;
guint depth;
guint Negative; /* Negative = 1 -> top down BMP,
Negative = 0 -> bottom up BMP */
};
/*
These structures are actually dummies. These are according to
the "Windows API reference guide volume II" as written by Borland,
but GCC fiddles with the alignment of the internal members.
the "Windows API reference guide volume II" as written by
Borland International, but GCC fiddles with the alignment of
the internal members, so these aren't actually usable.
*/
......@@ -77,57 +71,56 @@ struct BitmapInfoHeader {
guint biClrImportant;
};
/*
DumpBIH printf's the values in a BitmapInfoHeader to the screen, for
debugging purposes.
*/
#if DUMPBIH
static void DumpBIH(unsigned char *BIH)
{ /* For debugging */
{
printf("biSize = %i \n",
(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
(int) (BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) +
(BIH[0]));
printf("biWidth = %i \n",
(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
(int) (BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) +
(BIH[4]));
printf("biHeight = %i \n",
(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
(int) (BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
(BIH[8]));
printf("biPlanes = %i \n", (BIH[13] << 8) + (BIH[12]));
printf("biBitCount = %i \n", (BIH[15] << 8) + (BIH[14]));
printf("biPlanes = %i \n", (int) (BIH[13] << 8) + (BIH[12]));
printf("biBitCount = %i \n", (int) (BIH[15] << 8) + (BIH[14]));
printf("biCompress = %i \n",
(BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
(int) (BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
(BIH[16]));
printf("biSizeImage = %i \n",
(BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
(int) (BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
(BIH[20]));
printf("biXPels = %i \n",
(BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
(int) (BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
(BIH[24]));
printf("biYPels = %i \n",
(BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
(int) (BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
(BIH[28]));
printf("biClrUsed = %i \n",
(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
(int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
(BIH[32]));
printf("biClrImprtnt= %i \n",
(BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
(int) (BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
(BIH[36]));
}
#endif
/* struct headerpair contains the decoded width/height/depth info for
the current bitmap */
/*
This does a byte-order swap. Does glib have something like
be32_to_cpu() ??
*/
static unsigned int le32_to_cpu(guint i)
{
unsigned int i2;
return i2;
}
/*
Destroy notification function for the libart pixbuf
*/
static void free_buffer(gpointer user_data, gpointer data)
{
free(data);
}
struct headerpair {
guint width;
guint height;
guint depth;
guint Negative; /* Negative = 1 -> top down BMP,
Negative = 0 -> bottom up BMP */
};
/* Data needed for the "state" during decompression */
struct bmp_compression_state {
......@@ -161,8 +154,10 @@ struct bmp_progressive_state {
gint Lines; /* # of finished lines */
gint Type; /*
32 = RGB + alpha
24 = RGB
8 = 8 bit colormapped
4 = 4 bpp colormapped
8 = 8 bpp colormapped
1 = 1 bit bitonal
*/
gint Compressed;
......@@ -183,13 +178,13 @@ gboolean image_load_increment(gpointer data, guchar * buf, guint size);
/* Shared library entry point */
/* Shared library entry point --> This should be removed when
generic_image_load enters gdk-pixbuf-io. */
GdkPixbuf *image_load(FILE * f)
{
guchar *membuf;
size_t length;
struct bmp_progressive_state *State;
int fd;
GdkPixbuf *pb;
......@@ -202,7 +197,7 @@ GdkPixbuf *image_load(FILE * f)
while (feof(f) == 0) {
length = fread(membuf, 1, 4096, f);
if (length > 0)
image_load_increment(State, membuf, length);
(void) image_load_increment(State, membuf, length);
}
g_free(membuf);
......@@ -212,31 +207,38 @@ GdkPixbuf *image_load(FILE * f)
pb = State->pixbuf;
image_stop_load(State);
return State->pixbuf;
return pb;
}
static void DecodeHeader(unsigned char *BFH, unsigned char *BIH,
struct bmp_progressive_state *State)
{
/* DumpBIH(BIH);*/
#if DUMPBIH
DumpBIH(BIH);
#endif
State->Header.width =
(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
(int) (BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) +
(BIH[4]);
State->Header.height =
(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8]);
State->Header.depth = (BIH[15] << 8) + (BIH[14]);;
(int) (BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
(BIH[8]);
State->Header.depth = (int) (BIH[15] << 8) + (BIH[14]);;
State->Type = State->Header.depth; /* This may be less trivial someday */
State->HeaderSize =
((BFH[13] << 24) + (BFH[12] << 16) + (BFH[11] << 8) +
(BFH[10]));
if (State->HeaderSize >= 14 + 40 + 768 + 512)
State->HeaderSize = 14 + 40 + 768 + 512 - 1;
(int) ((BFH[13] << 24) + (BFH[12] << 16) + (BFH[11] << 8) +
(BFH[10]));
if (State->HeaderSize >= 14 + 40 + 1024)
State->HeaderBuf =
g_realloc(State->HeaderBuf, State->HeaderSize);
if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
|| (BIH[19] != 0)) {
State->Compressed = 1;
}
/* Negative heights indicates bottom-down pixelorder */
if (State->Header.height < 0) {
State->Header.height = -State->Header.height;
State->Header.Negative = 1;
......@@ -246,10 +248,14 @@ static void DecodeHeader(unsigned char *BFH, unsigned char *BIH,
State->Header.Negative = 0;
}
if (State->Type == 32)
State->LineWidth = State->Header.width * 4;
if (State->Type == 24)
State->LineWidth = State->Header.width * 3;
if (State->Type == 8)
State->LineWidth = State->Header.width * 1;
if (State->Type == 4)
State->LineWidth = (State->Header.width + 1) / 2;
if (State->Type == 1) {
State->LineWidth = State->Header.width / 8;
if ((State->Header.width & 7) != 0)
......@@ -268,10 +274,16 @@ static void DecodeHeader(unsigned char *BFH, unsigned char *BIH,
if (State->pixbuf == NULL) {
State->pixbuf =
gdk_pixbuf_new(ART_PIX_RGB, FALSE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
if (State->Type == 32)
State->pixbuf =
gdk_pixbuf_new(ART_PIX_RGB, TRUE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
else
State->pixbuf =
gdk_pixbuf_new(ART_PIX_RGB, FALSE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
......@@ -300,8 +312,10 @@ image_begin_load(ModulePreparedNotifyFunc prepared_func,
context->user_data = user_data;
context->HeaderSize = 54;
context->HeaderBuf = g_malloc(14 + 40 + 768 + 512);
/* 768 for the colormap */
context->HeaderBuf = g_malloc(14 + 40 + 1024);
/* 14 for the BitmapFileHeader, 40 for the BitmapImageHeader and
1024 for the colormap */
context->HeaderDone = 0;
context->LineWidth = 0;
......@@ -337,8 +351,10 @@ void image_stop_load(gpointer data)
if (context->LineBuf != NULL)
g_free(context->LineBuf);
context->LineBuf = NULL;
if (context->HeaderBuf != NULL)
g_free(context->HeaderBuf);
context->LineBuf = NULL;
if (context->pixbuf)
gdk_pixbuf_unref(context->pixbuf);
......@@ -347,6 +363,34 @@ void image_stop_load(gpointer data)
}
/*
The OneLineXX functions are called when 1 line worth of data is present.
OneLine24 is the 24 bpp-version.
*/
static void OneLine32(struct bmp_progressive_state *context)
{
gint X;
guchar *Pixels;
X = 0;
if (context->Header.Negative == 0)
Pixels = context->pixbuf->art_pixbuf->pixels +
gdk_pixbuf_get_rowstride(context->pixbuf) *
(context->Header.height - context->Lines - 1);
else
Pixels = context->pixbuf->art_pixbuf->pixels +
gdk_pixbuf_get_rowstride(context->pixbuf) *
context->Lines;
while (X < context->Header.width) {
Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
X++;
}
}
static void OneLine24(struct bmp_progressive_state *context)
{
gint X;
......@@ -385,7 +429,6 @@ static void OneLine8(struct bmp_progressive_state *context)
gdk_pixbuf_get_rowstride(context->pixbuf) *
context->Lines;
while (X < context->Header.width) {
/* The joys of having a BGR byteorder */
Pixels[X * 3 + 0] =
context->HeaderBuf[4 * context->LineBuf[X] + 56];
Pixels[X * 3 + 1] =
......@@ -396,6 +439,47 @@ static void OneLine8(struct bmp_progressive_state *context)
}
}
static void OneLine4(struct bmp_progressive_state *context)
{
gint X;
guchar *Pixels;
X = 0;
if (context->Header.Negative == 0)
Pixels = context->pixbuf->art_pixbuf->pixels +
gdk_pixbuf_get_rowstride(context->pixbuf) *
(context->Header.height - context->Lines - 1);
else
Pixels = context->pixbuf->art_pixbuf->pixels +
gdk_pixbuf_get_rowstride(context->pixbuf) *
context->Lines;
while (X < context->Header.width) {
guchar Pix;
Pix = context->LineBuf[X / 2];
Pixels[X * 3 + 0] =
context->HeaderBuf[4 * (Pix >> 4) + 56];
Pixels[X * 3 + 1] =
context->HeaderBuf[4 * (Pix >> 4) + 55];
Pixels[X * 3 + 2] =
context->HeaderBuf[4 * (Pix >> 4) + 54];
X++;
if (X < context->Header.width) {
/* Handle the other 4 bit pixel only when there is one */
Pixels[X * 3 + 0] =
context->HeaderBuf[4 * (Pix & 15) + 56];
Pixels[X * 3 + 1] =
context->HeaderBuf[4 * (Pix & 15) + 55];
Pixels[X * 3 + 2] =
context->HeaderBuf[4 * (Pix & 15) + 54];
X++;
}
}
}
static void OneLine1(struct bmp_progressive_state *context)
{
gint X;
......@@ -411,14 +495,13 @@ static void OneLine1(struct bmp_progressive_state *context)
gdk_pixbuf_get_rowstride(context->pixbuf) *
context->Lines;
while (X < context->Header.width) {
int Bit;
gint Bit;
Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
Bit = Bit & 1;
/* The joys of having a BGR byteorder */
Pixels[X * 3 + 0] = context->HeaderBuf[Bit + 32];
Pixels[X * 3 + 1] = context->HeaderBuf[Bit + 2 + 32];
Pixels[X * 3 + 2] = context->HeaderBuf[Bit + 4 + 32];
Pixels[X * 3 + 0] = Bit*255;
Pixels[X * 3 + 1] = Bit*255;
Pixels[X * 3 + 2] = Bit*255;
X++;
}
}
......@@ -430,10 +513,14 @@ static void OneLine(struct bmp_progressive_state *context)
if (context->Lines >= context->Header.height)
return;
if (context->Type == 32)
OneLine32(context);
if (context->Type == 24)
OneLine24(context);
if (context->Type == 8)
OneLine8(context);
if (context->Type == 4)
OneLine4(context);
if (context->Type == 1)
OneLine1(context);
......@@ -450,6 +537,113 @@ static void OneLine(struct bmp_progressive_state *context)
}
}
/* DoCompressedByte handles 1 byte of incomming compressed data */
void DoCompressedByte(struct bmp_progressive_state *context, guchar ** buf,
gint * size)
{
gint BytesToCopy;
switch (context->compr.phase) {
case 0: /* Neutral state */
if (buf[0] != 0) { /* run count */
context->compr.phase = 1;
context->compr.RunCount = (*buf)[0];
} else { /* Escape */
context->compr.phase = 2;
}
(*buf)++;
(*size)--;
break;
case 1: /* Run count received.... */
while (context->compr.RunCount > 0) {
BytesToCopy =
context->LineWidth - context->LineDone;
if (BytesToCopy > context->compr.RunCount)
BytesToCopy = context->compr.RunCount;
if (BytesToCopy > 0) {
memset(context->LineBuf +
context->LineDone,
(*buf)[0], BytesToCopy);
context->compr.RunCount -= BytesToCopy;
context->LineDone += BytesToCopy;
}
if ((context->LineDone >= context->LineWidth)
&& (context->LineWidth > 0)) {
OneLine(context);
}
}
context->compr.phase = 0;
(*buf)++;
(*size)--;
break;
case 2: /* Escape received */
if ((*buf)[0] == 0) { /* End of line */
context->compr.phase = 0;
if (context->LineDone > 0)
OneLine(context);
} else if ((*buf)[0] == 1) { /* End of image */
OneLine(context);
context->compr.phase = 6;
(*size) = 0;
break;
} else if ((*buf)[0] == 2) { /* Cursor displacement */
context->compr.phase = 4;
} else {
context->compr.phase = 3;
context->compr.RunCount = (*buf)[0];
}
(*buf)++;
(*size)--;
break;
case 3:
while ((context->compr.RunCount > 0)
&& (size > 0)) {
BytesToCopy =
context->LineWidth - context->LineDone;
if (BytesToCopy > context->compr.RunCount)
BytesToCopy = context->compr.RunCount;
if (BytesToCopy > *size)
BytesToCopy = *size;
if (BytesToCopy > 0) {
memcpy(context->LineBuf +
context->LineDone,
*buf, BytesToCopy);
context->compr.RunCount -= BytesToCopy;
(*buf) += BytesToCopy;
(*size) -= BytesToCopy;
context->LineDone += BytesToCopy;
}
if ((context->LineDone >= context->LineWidth)
&& (context->LineWidth > 0))
OneLine(context);
}
if (context->compr.RunCount <= 0)
context->compr.phase = 0;
break;
case 4:
context->compr.phase = 5;
context->compr.XDelta = (*buf)[0];
(*buf)++;
(*size)--;
break;
case 5:
context->compr.phase = 0;
context->compr.YDelta = (*buf)[0];
g_assert(0); /* No implementatio of this yet */
/* If this happens, please email me (arjan@fenrus.demon.nl)
the image concerned. */
(*buf)++;
(*size)--;
break;
case 6:
(*size) = 0;
}
}
/*
* context - from image_begin_load
* buf - new image data
......@@ -473,7 +667,7 @@ gboolean image_load_increment(gpointer data, guchar * buf, guint size)
if (BytesToCopy > size)
BytesToCopy = size;
memcpy(context->HeaderBuf + context->HeaderDone,
memmove(context->HeaderBuf + context->HeaderDone,
buf, BytesToCopy);
size -= BytesToCopy;
......@@ -481,132 +675,18 @@ gboolean image_load_increment(gpointer data, guchar * buf, guint size)
context->HeaderDone += BytesToCopy;
} else if (context->Compressed) {
/* Compression is done 1 at a time for now */
switch (context->compr.phase) {
case 0:
if (buf[0] != 0) { /* run count */
context->compr.phase = 1;
context->compr.RunCount = buf[0];
} else { /* Escape */
context->compr.phase = 2;
}
buf++;
size--;
break;
case 1: /* Run count received.... */
while (context->compr.RunCount > 0) {
BytesToCopy =
context->LineWidth -
context->LineDone;
if (BytesToCopy >
context->compr.
RunCount) BytesToCopy =
context->compr.
RunCount;
if (BytesToCopy > 0) {
memset(context->LineBuf +
context->LineDone,
buf[0],
BytesToCopy);
context->compr.RunCount -=
BytesToCopy;
context->LineDone +=
BytesToCopy;
}
if (
(context->LineDone >=
context->LineWidth)
&& (context->LineWidth > 0)) {
OneLine(context);
}
}
context->compr.phase = 0;
buf++;
size--;
break;
case 2: /* Escape received */
if (buf[0] == 0) { /* End of line */
context->compr.phase = 0;
if (context->LineDone > 0)
OneLine(context);
} else if (buf[0] == 1) { /* End of image */
OneLine(context);
context->compr.phase = 6;
size = 0;
break;
} else if (buf[0] == 2) { /* Cursor displacement */
context->compr.phase = 4;
} else {
context->compr.phase = 3;
context->compr.RunCount = buf[0];
}
buf++;
size--;
break;
case 3:
while ((context->compr.RunCount > 0)
&& (size > 0)) {
BytesToCopy =
context->LineWidth -
context->LineDone;
if (BytesToCopy >
context->compr.
RunCount) BytesToCopy =
context->compr.
RunCount;
if (BytesToCopy > size)
BytesToCopy = size;
if (BytesToCopy > 0) {
memcpy(context->LineBuf +
context->LineDone,
buf, BytesToCopy);
context->compr.RunCount -=
BytesToCopy;
buf += BytesToCopy;
size -= BytesToCopy;
context->LineDone +=
BytesToCopy;
}
if (
(context->LineDone >=
context->LineWidth)
&& (context->LineWidth > 0))
OneLine(context);
}
if (context->compr.RunCount <= 0)
context->compr.phase = 0;
break;
case 4:
context->compr.phase = 5;
context->compr.XDelta = buf[0];
buf++;
size--;
break;
case 5:
context->compr.phase = 0;
context->compr.YDelta = buf[0];
g_assert(0); /* No implementatio of this yet */
buf++;
size--;
break;
case 6:
size = 0;
}
/* Compression is done 1 byte at a time for now */
DoCompressedByte(context, &buf, &size);
} else {
/* Pixeldata only */
/* Uncompressed pixeldata */
BytesToCopy =
context->LineWidth - context->LineDone;
if (BytesToCopy > size)
BytesToCopy = size;
if (BytesToCopy > 0) {
memcpy(context->LineBuf +
memmove(context->LineBuf +
context->LineDone, buf,
BytesToCopy);
......
/* GdkPixbuf library - Windows Bitmap image loader
/* GdkPixbuf library - Windows Icon/Cursor image loader
*
* Copyright (C) 1999 The Free Software Foundation
*
......@@ -23,6 +23,7 @@
* Boston, MA 02111-1307, USA.
*/
#undef DUMPBIH
/*
Icons are just like BMP's, except for the header.
......@@ -40,19 +41,13 @@ Known bugs:
struct headerpair {
guint width;
guint height;
guint depth;
guint Negative; /* Negative = 1 -> top down BMP,
Negative = 0 -> bottom up BMP */
};
/*
These structures are actually dummies. These are according to
the "Windows API reference guide volume II" as written by Borland,
but GCC fiddles with the alignment of the internal members.
the "Windows API reference guide volume II" as written by
Borland International, but GCC fiddles with the alignment of
the internal members.
*/
......@@ -77,59 +72,53 @@ struct BitmapInfoHeader {
guint biClrImportant;
};
#ifdef DUMPBIH
/*
DumpBIH printf's the values in a BitmapInfoHeader to the screen, for
debugging purposes.
*/
static void DumpBIH(unsigned char *BIH)
{ /* For debugging */
{
printf("biSize = %i \n",
(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
(int)(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
printf("biWidth = %i \n",
(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
(int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
printf("biHeight = %i \n",
(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
(int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
(BIH[8]));
printf("biPlanes = %i \n", (BIH[13] << 8) + (BIH[12]));
printf("biBitCount = %i \n", (BIH[15] << 8) + (BIH[14]));
printf("biPlanes = %i \n", (int)(BIH[13] << 8) + (BIH[12]));
printf("biBitCount = %i \n", (int)(BIH[15] << 8) + (BIH[14]));
printf("biCompress = %i \n",
(BIH[19] << 24) + (BIH[18] << 16) + (BIH