guint depth;
guint Negative; /* Negative = 1 -> top down BMP,
Negative = 0 -> bottom up BMP */
+ guint n_colors;
};
/* Data needed for the "state" during decompression */
/* Progressive loading */
struct bmp_progressive_state {
+ GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepared_func;
GdkPixbufModuleUpdatedFunc updated_func;
gpointer user_data;
guint Lines; /* # of finished lines */
guchar *buff;
- gint BufferSize;
- gint BufferDone;
+ guint BufferSize;
+ guint BufferDone;
guchar (*Colormap)[3];
struct bmp_progressive_state *State,
GError **error)
{
+ gint clrUsed;
+
/* FIXME this is totally unrobust against bogus image data. */
if (State->BufferSize < lsb_32 (&BIH[0]) + 14) {
#if DUMPBIH
DumpBIH(BIH);
-#endif
+#endif
State->Header.size = lsb_32 (&BIH[0]);
if (State->Header.size == 40) {
return FALSE;
}
+ if (State->Header.size == 12)
+ clrUsed = 1 << State->Header.depth;
+ else
+ clrUsed = (int) (BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
+
+ if (clrUsed != 0)
+ State->Header.n_colors = clrUsed;
+ else
+ State->Header.n_colors = 1 << State->Header.depth;
+
+ if (State->Header.n_colors > 1 << State->Header.depth) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("BMP image has bogus header data"));
+ State->read_state = READ_STATE_ERROR;
+ return FALSE;
+ }
+
State->Type = State->Header.depth; /* This may be less trivial someday */
/* Negative heights indicates bottom-down pixelorder */
State->LineWidth = (State->LineWidth / 4) * 4 + 4;
if (State->pixbuf == NULL) {
+ if (State->size_func) {
+ gint width = State->Header.width;
+ gint height = State->Header.height;
+
+ (*State->size_func) (&width, &height, State->user_data);
+ if (width == 0 || height == 0) {
+ State->read_state = READ_STATE_DONE;
+ State->BufferSize = 0;
+ return TRUE;
+ }
+ }
+
if (State->Type == 32 ||
State->Compressed == BI_RLE4 ||
State->Compressed == BI_RLE8)
State->pixbuf =
- gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
- (gint) State->Header.width,
- (gint) State->Header.height);
+ gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
+ (gint) State->Header.width,
+ (gint) State->Header.height);
else
State->pixbuf =
- gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
- (gint) State->Header.width,
- (gint) State->Header.height);
-
- if (State->pixbuf == NULL) {
- g_set_error (error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Not enough memory to load bitmap image"));
+ gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
+ (gint) State->Header.width,
+ (gint) State->Header.height);
+
+ if (State->pixbuf == NULL) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+ _("Not enough memory to load bitmap image"));
State->read_state = READ_STATE_ERROR;
- return FALSE;
- }
-
+ return FALSE;
+ }
+
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
(*State->prepared_func) (State->pixbuf, NULL, State->user_data);
-
+
+ /* make all pixels initially transparent */
+ if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
+ memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
+ State->compr.p = State->pixbuf->pixels
+ + State->pixbuf->rowstride * (State->Header.height- 1);
+ }
}
- /* make all pixels initially transparent */
- if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
- memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
- State->compr.p = State->pixbuf->pixels
- + State->pixbuf->rowstride * (State->Header.height- 1);
- }
-
State->BufferDone = 0;
if (State->Type <= 8) {
State->read_state = READ_STATE_PALETTE;
GError **error)
{
gint i;
+ gint samples;
g_assert (State->read_state == READ_STATE_PALETTE);
+ samples = (State->Header.size == 12 ? 3 : 4);
+ if (State->BufferSize < State->Header.n_colors * samples) {
+ State->BufferSize = State->Header.n_colors * samples;
+ if (!grow_buffer (State, error))
+ return FALSE;
+ return TRUE;
+ }
+
State->Colormap = g_malloc ((1 << State->Header.depth) * sizeof (*State->Colormap));
+ for (i = 0; i < State->Header.n_colors; i++)
- for (i = 0; i < (1 << State->Header.depth); i++)
{
- State->Colormap[i][0] = buff[i * (State->Header.size == 12 ? 3 : 4)];
- State->Colormap[i][1] = buff[i * (State->Header.size == 12 ? 3 : 4) + 1];
- State->Colormap[i][2] = buff[i * (State->Header.size == 12 ? 3 : 4) + 2];
+ State->Colormap[i][0] = buff[i * samples];
+ State->Colormap[i][1] = buff[i * samples + 1];
+ State->Colormap[i][2] = buff[i * samples + 2];
#ifdef DUMPCMAP
g_print ("color %d %x %x %x\n", i,
State->Colormap[i][0],
GError **error)
{
struct bmp_progressive_state *context;
-
+
context = g_new0(struct bmp_progressive_state, 1);
+ context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
context->pixbuf = NULL;
-
-
+
return (gpointer) context;
}
/* FIXME this thing needs to report errors if
* we have unused image data
*/
-
+
g_return_val_if_fail(context != NULL, TRUE);
if (context->Colormap != NULL)
*pixels++ = (r << r_lshift) | (r >> r_rshift);
*pixels++ = (g << g_lshift) | (g >> g_rshift);
*pixels++ = (b << b_lshift) | (b >> b_rshift);
- *pixels++ = src[3]; /* alpha */
+ *pixels++ = 0xff;
src += 4;
}
*pixels++ = src[2];
*pixels++ = src[1];
*pixels++ = src[0];
- *pixels++ = src[3];
+ *pixels++ = 0xff;
src += 4;
}
* buf - new image data
* size - length of new image data
*
- * append image data onto inrecrementally built output image
+ * append image data onto incrementally built output image
*/
static gboolean
gdk_pixbuf__bmp_image_load_increment(gpointer data,
return FALSE;
break;
+ case READ_STATE_DONE:
+ return TRUE;
+ break;
default:
g_assert_not_reached ();
info->mime_types = mime_types;
info->extensions = extensions;
info->flags = 0;
+ info->license = "LGPL";
}