GNOME Bugzilla – Bug 142165
Alpha extensions to BMP
Last modified: 2005-06-05 22:33:43 UTC
Since Windows XP uses 32 bit alpha channel BMPs we can assume it is now part of the spec. Here's a patch to support it. --------------------------------------------------- --- bmp/bmp.c Tue Nov 25 05:49:15 2003 +++ /sw/src/gimp2-noprint-2.0.0-2/gimp-2.0.0/plug-ins/bmp/bmp.c Sat May 8 20:36:35 2004 @@ -27,7 +27,9 @@ /* 06.05.2000 Overhaul for 16&24-bit */ /* plus better OS/2 code */ /* by njl195@zepler.org.uk */ - +/* 07.05.2004 Added 32 bit alpha */ +/* extensions */ +/* -Troy D. Gillette */ /* * The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis @@ -217,7 +219,8 @@ export = gimp_export_image (&image_ID, &drawable_ID, "BMP", (GIMP_EXPORT_CAN_HANDLE_RGB | GIMP_EXPORT_CAN_HANDLE_GRAY | - GIMP_EXPORT_CAN_HANDLE_INDEXED)); + GIMP_EXPORT_CAN_HANDLE_INDEXED | + GIMP_EXPORT_CAN_HANDLE_ALPHA)); if (export == GIMP_EXPORT_CANCEL) { values[0].data.d_status = GIMP_PDB_CANCEL; --- bmp/bmpread.c Mon Jan 19 03:13:32 2004 +++ /sw/src/gimp2-noprint-2.0.0-2/gimp-2.0.0/plug-ins/bmp/bmpread.c Sat May 8 20:35:57 2004 @@ -391,14 +391,22 @@ /* Make a new image in the gimp */ - if (bpp >= 16) - { + if (bpp == 32) + { + image = gimp_image_new (width, height, GIMP_RGB); + layer = gimp_layer_new (image, _("Background"), + width, height, + GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE); + channels = 4; + } + else if (bpp >= 16) + { image = gimp_image_new (width, height, GIMP_RGB); layer = gimp_layer_new (image, _("Background"), width, height, GIMP_RGB_IMAGE, 100, GIMP_NORMAL_MODE); channels = 3; - } + } else if (grey) { image = gimp_image_new (width, height, GIMP_GRAY); @@ -438,9 +446,10 @@ temp = dest + (ypos * rowstride); for (xpos= 0; xpos < width; ++xpos) { - *(temp++)= buffer[xpos * 4 + 2]; - *(temp++)= buffer[xpos * 4 + 1]; - *(temp++)= buffer[xpos * 4]; + *(temp++) = buffer[xpos * 4 + 2]; + *(temp++) = buffer[xpos * 4 + 1]; + *(temp++) = buffer[xpos * 4]; + *(temp++) = buffer[xpos * 4 + 3]^0xff; } --ypos; /* next line */ cur_progress++; --- bmp/bmpwrite.c Tue Jan 20 09:07:15 2004 +++ /sw/src/gimp2-noprint-2.0.0-2/gimp-2.0.0/plug-ins/bmp/bmpwrite.c Sat May 8 20:33:07 2004 @@ -49,7 +49,10 @@ static gint cur_progress = 0; static gint max_progress = 0; static gint encoded = 0; - +static gint bits32 = 0; +static gint bits24 = 0; +static gint alpha32 = 0; +static GtkWidget *a32toggle; static void WriteImage (FILE *f, guchar *src, @@ -61,7 +64,7 @@ gint spzeile, gint MapSize); static gboolean save_dialog (void); - +static gboolean save_dialogRGB (gboolean alpha); static void FromL (gint32 wert, @@ -131,23 +134,36 @@ gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); - if (gimp_drawable_has_alpha (drawable_ID)) - { - g_message (_("Cannot save images with alpha channel.")); - return GIMP_PDB_EXECUTION_ERROR; - } - + if (BitsPerPixel >= 24) + { + if (! save_dialogRGB (drawable_type == GIMP_RGBA_IMAGE)) + return GIMP_PDB_CANCEL; + } + /* We can save it. So what colors do we use? */ switch (drawable_type) { - case GIMP_RGB_IMAGE: + case GIMP_RGBA_IMAGE: + if(bits32) { + colors = 0; + BitsPerPixel = 32; + MapSize = 0; + channels = 4; + } else { + colors = 0; + BitsPerPixel = 24; + MapSize = 0; + channels = 4; + } + break; + case GIMP_RGB_IMAGE: colors = 0; BitsPerPixel = 24; MapSize = 0; channels = 3; break; - case GIMP_GRAY_IMAGE: + case GIMP_GRAY_IMAGE: colors = 256; BitsPerPixel = 8; MapSize = 1024; @@ -219,7 +235,7 @@ rows = drawable->height; /* ... that we write to our headers. */ - if ((BitsPerPixel != 24) && + if ((BitsPerPixel < 24) && (cols % (8/BitsPerPixel))) Spcols = (((cols / (8 / BitsPerPixel)) + 1) * (8 / BitsPerPixel)); else @@ -349,9 +365,38 @@ xpos = 0; rowstride = width * channels; - /* We'll begin with the 24 bit Bitmaps, they are easy :-) */ + /* We'll begin with the 32 and 24 bit Bitmaps, they are easy :-) */ - if (bpp == 24) + if (bpp == 32) + { + for (ypos = height - 1; ypos >= 0; ypos--) /* for each row */ + { + for (i = 0; i < width; i++) /* for each pixel */ + { + temp = src + (ypos * rowstride) + (xpos * channels); + buf[2] = (guchar) *temp; + temp++; + buf[1] = (guchar) *temp; + temp++; + buf[0] = (guchar) *temp; + temp++; + if(alpha32) + buf[3] = (guchar) *temp^0xff; + else + buf[3] = 0; + xpos++; + Write (f, buf, 4); + } + Write (f, &buf[4], spzeile - (width * 4)); + + cur_progress++; + if ((cur_progress % 5) == 0) + gimp_progress_update ((gdouble) cur_progress / (gdouble) max_progress); + + xpos = 0; + } + } + else if (bpp == 24) { for (ypos = height - 1; ypos >= 0; ypos--) /* for each row */ { @@ -577,6 +622,85 @@ g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &encoded); + + gtk_widget_show (vbox); + gtk_widget_show (frame); + gtk_widget_show (dlg); + + run = (gimp_dialog_run (GIMP_DIALOG (dlg)) == GTK_RESPONSE_OK); + + gtk_widget_destroy (dlg); + + return run; +} + +void RGBdialog_callback( GtkWidget *widget, + gpointer callback_data ) +{ +char *str = (char *)callback_data; + if(str[0] == '3') { + bits24 = 1; + bits32 = 0; + gtk_widget_set_sensitive (a32toggle, FALSE); + } else { + bits24 = 0; + bits32 = 1; + gtk_widget_set_sensitive (a32toggle, TRUE); + } +} + +static gboolean +save_dialogRGB (gboolean alpha) +{ + GtkWidget *dlg; + GtkWidget *radio; + GtkWidget *frame; + GtkWidget *vbox; + GSList *group; + gboolean run; + + dlg = gimp_dialog_new (_("Save as BMP"), "bmp", + NULL, 0, + gimp_standard_help_func, "file-bmp-save", + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); + + /* parameter settings */ + frame = gtk_frame_new (_("Save Options")); + gtk_container_set_border_width (GTK_CONTAINER (frame), 6); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0); + + vbox = gtk_vbox_new (FALSE, 2); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); + gtk_container_add (GTK_CONTAINER (frame), vbox); + + radio = gtk_radio_button_new_with_mnemonic (NULL,_("_24 Bit")); + gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), bits24); + gtk_widget_show (radio); + + g_signal_connect (radio, "toggled", + G_CALLBACK (RGBdialog_callback), + "3"); + + group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio)); + radio = gtk_radio_button_new_with_mnemonic (group,_("_32 Bit")); + gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0); + gtk_widget_show (radio); + + g_signal_connect (radio, "toggled", + G_CALLBACK (RGBdialog_callback), + "4"); + + a32toggle = gtk_check_button_new_with_mnemonic (_("Save Alpha Channel")); + gtk_box_pack_start (GTK_BOX (vbox), a32toggle, FALSE, FALSE, 0); + gtk_widget_set_sensitive (a32toggle, FALSE); + gtk_widget_show (a32toggle); + + g_signal_connect (a32toggle, "toggled", + G_CALLBACK (gimp_toggle_button_update), + &alpha32); gtk_widget_show (vbox); gtk_widget_show (frame);
Please do not paste patches into the comment field where they usually get garbled. Can you please attach the diff to the bug report instead?
Created attachment 27562 [details] [review] Diff file for the plug-ins bmp directory.
The patch doesn't follow the GIMP coding style, thus it will need some fixing when it is applied. Also I don't understand the logic of the dialog. I only looked the code but it seems that it gives the choice for 24 or 32 bit and adds a check button on whether to save the alpha channel? Isn't that somewhat duplicated? I am also missing changes to the plug-in registration code. It should announce that it can now handle an alpha channel or it won't show up properly in the file-save menu.
Adding Nick Lamb to Cc: in the hope that he can comment on this change to the BMP plug-in.
Troy, are you going to answer my questions on your patch or did you loose interest?
Created attachment 29612 [details] [review] Possible cleaned up patch Quick stab at a clean-up; this removes the dialog on save, and will simply save an RGBA image as alpha. Also included is the plugin registration change to get it to show up properly. I'm not 100% sure it actually works, though; the specs on MSDN are really vague, and I haven't found anything that's known to read and write 32-bit alpha BMPs correctly, nor known-good sample files to test with. The only sample files I've found are at http://cgi.glyphlab.com/php/gl/articles/eight_bit_alpha1.php and *do not work* with this patch, as the values for the alpha channel are inverted. Vague MSDN specs for bitmap files: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_4v1h.asp
Created attachment 29617 [details] Sample PNG image with alpha channel
Created attachment 29618 [details] Sample BMP image with transparency (created by ImageMagick) The above PNG image converted to BMP-with-alpha by ImageMagick 5.5.6. This file does not load with the current patch, it looks like it uses the newer version header (see MSDN link above) which is not handled. If I try converting a 32-bit BMP as saved from gimp w/ the current patch back to PNG via ImageMagick, the alpha channel is lost. This makes me suspect that (at least for ImageMagick), alpha isn't really allowed except with the newer header.
Created attachment 29819 [details] [review] Partial support for bmp files with newer header format This is where I last left off; it will load the sample image created by ImageMagick, but doesn't use the new header format on save, so ImageMagick will ignore the GIMP-saved alpha channel. Without some known good sample files or apps to interoperate with, it's hard to test this. :)
Comment on attachment 27562 [details] [review] Diff file for the plug-ins bmp directory. This patch was obsoleted by patch #29612
Comment on attachment 29819 [details] [review] Partial support for bmp files with newer header format I propose that attachment #29819 [details] (Brion Vibber's last patch) be committed, since it doesn't break existing support, and adds some support for a more esoteric BMP filetype. That should close this bug FIXED.
I would not recommend committing the patch as is; I'm pretty sure it doesn't save in the correct format.
Moving from the 2.2 milestone to Future then. We should try to get this done in the next development cycle.
http://netghost.narod.ru/gff/graphics/summary/micbmp.htm is a good reference of various BMP versions.
See also the links mentioned in bug #168628. Those pages seem to load faster, at least.
Created attachment 46443 [details] [review] Alternate patch for alpha support in BMP plugin. I added alpha functionality to the BMP plugin several months back for my use in a Windows app with the intent to submit the patch. So I finally got around to submitting it. It's been tested against some images created by Photoshop and this plugin holds more closely to the specs I found than does Photoshop. I'll attach some of the images I was working with.
Created attachment 46444 [details] BMP with alpha transparency created in Photoshop As promised, here is a bitmap with alpha channel. I also forgot to mention that patch 46443 is for version 2.2.7 of The Gimp. It also contains two lines of code that I posted in bug 303972 regarding the bitmap resolution.
Brandon opened a new bug report on this issue and attached and updated patched there. Closing this report as duplicate of the new one. *** This bug has been marked as a duplicate of 306339 ***