1 /* bmpwrite.c   Writes Bitmap files. Even RLE encoded ones.      */
2 /*              (Windows (TM) doesn't read all of those, but who */
3 /*              cares? ;-)                                       */
4 /*              I changed a few things over the time, so perhaps */
5 /*              it dos now, but now there's no Windows left on   */
6 /*              my computer...                                   */
7 
8 /* Alexander.Schulz@stud.uni-karlsruhe.de                        */
9 
10 /*
11  * GIMP - The GNU Image Manipulation Program
12  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
13  *
14  * This program is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
26  * ----------------------------------------------------------------------------
27  */
28 
29 #include "config.h"
30 
31 #include <errno.h>
32 #include <string.h>
33 
34 #include <glib/gstdio.h>
35 
36 #include <libgimp/gimp.h>
37 #include <libgimp/gimpui.h>
38 
39 #include "bmp.h"
40 #include "bmp-save.h"
41 
42 #include "libgimp/stdplugins-intl.h"
43 
44 
45 typedef enum
46 {
47   RGB_565,
48   RGBA_5551,
49   RGB_555,
50   RGB_888,
51   RGBA_8888,
52   RGBX_8888
53 } RGBMode;
54 
55 
56 static  void      write_image     (FILE   *f,
57                                    guchar *src,
58                                    gint    width,
59                                    gint    height,
60                                    gint    use_run_length_encoding,
61                                    gint    channels,
62                                    gint    bpp,
63                                    gint    spzeile,
64                                    gint    MapSize,
65                                    RGBMode rgb_format,
66                                    gint    mask_info_size,
67                                    gint    color_space_size);
68 
69 static  gboolean  save_dialog     (gint    channels,
70                                    gint    bpp);
71 
72 
73 static struct
74 {
75   RGBMode rgb_format;
76   gint    use_run_length_encoding;
77 
78   /* Whether or not to write BITMAPV5HEADER color space data */
79   gint    dont_write_color_space_data;
80 } BMPSaveData;
81 
82 
83 static void
write_color_map(FILE * f,gint red[MAXCOLORS],gint green[MAXCOLORS],gint blue[MAXCOLORS],gint size)84 write_color_map (FILE *f,
85                  gint  red[MAXCOLORS],
86                  gint  green[MAXCOLORS],
87                  gint  blue[MAXCOLORS],
88                  gint  size)
89 {
90   gchar trgb[4];
91   gint  i;
92 
93   size /= 4;
94   trgb[3] = 0;
95   for (i = 0; i < size; i++)
96     {
97       trgb[0] = (guchar) blue[i];
98       trgb[1] = (guchar) green[i];
99       trgb[2] = (guchar) red[i];
100       Write (f, trgb, 4);
101     }
102 }
103 
104 static gboolean
warning_dialog(const gchar * primary,const gchar * secondary)105 warning_dialog (const gchar *primary,
106                 const gchar *secondary)
107 {
108   GtkWidget *dialog;
109   gboolean   ok;
110 
111   dialog = gtk_message_dialog_new (NULL, 0,
112                                    GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL,
113                                    "%s", primary);
114 
115   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
116                                             "%s", secondary);
117 
118   gimp_window_set_transient (GTK_WINDOW (dialog));
119 
120   ok = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK);
121 
122   gtk_widget_destroy (dialog);
123 
124   return ok;
125 }
126 
127 GimpPDBStatusType
save_image(const gchar * filename,gint32 image,gint32 drawable_ID,GimpRunMode run_mode,GError ** error)128 save_image (const gchar  *filename,
129             gint32        image,
130             gint32        drawable_ID,
131             GimpRunMode   run_mode,
132             GError      **error)
133 {
134   FILE           *outfile;
135   BitmapFileHead  bitmap_file_head;
136   BitmapHead      bitmap_head;
137   gint            Red[MAXCOLORS];
138   gint            Green[MAXCOLORS];
139   gint            Blue[MAXCOLORS];
140   guchar         *cmap;
141   gint            rows, cols, Spcols, channels, MapSize, SpZeile;
142   glong           BitsPerPixel;
143   gint            colors;
144   guchar         *pixels;
145   GeglBuffer     *buffer;
146   const Babl     *format;
147   GimpImageType    drawable_type;
148   gint            drawable_width;
149   gint            drawable_height;
150   gint            i;
151   gint            mask_info_size;
152   gint            color_space_size;
153   guint32         Mask[4];
154 
155   buffer = gimp_drawable_get_buffer (drawable_ID);
156 
157   drawable_type   = gimp_drawable_type   (drawable_ID);
158   drawable_width  = gimp_drawable_width  (drawable_ID);
159   drawable_height = gimp_drawable_height (drawable_ID);
160 
161   switch (drawable_type)
162     {
163     case GIMP_RGBA_IMAGE:
164       format       = babl_format ("R'G'B'A u8");
165       colors       = 0;
166       BitsPerPixel = 32;
167       MapSize      = 0;
168       channels     = 4;
169       BMPSaveData.rgb_format = RGBA_8888;
170       break;
171 
172     case GIMP_RGB_IMAGE:
173       format       = babl_format ("R'G'B' u8");
174       colors       = 0;
175       BitsPerPixel = 24;
176       MapSize      = 0;
177       channels     = 3;
178       BMPSaveData.rgb_format = RGB_888;
179       break;
180 
181     case GIMP_GRAYA_IMAGE:
182       if (run_mode == GIMP_RUN_INTERACTIVE &&
183           ! warning_dialog (_("Cannot export indexed image with "
184                               "transparency in BMP file format."),
185                             _("Alpha channel will be ignored.")))
186         return GIMP_PDB_CANCEL;
187 
188      /* fallthrough */
189 
190     case GIMP_GRAY_IMAGE:
191       colors       = 256;
192       BitsPerPixel = 8;
193       MapSize      = 1024;
194 
195       if (drawable_type == GIMP_GRAYA_IMAGE)
196         {
197           format   = babl_format ("Y'A u8");
198           channels = 2;
199         }
200       else
201         {
202           format   = babl_format ("Y' u8");
203           channels = 1;
204         }
205 
206       for (i = 0; i < colors; i++)
207         {
208           Red[i]   = i;
209           Green[i] = i;
210           Blue[i]  = i;
211         }
212       break;
213 
214     case GIMP_INDEXEDA_IMAGE:
215       if (run_mode == GIMP_RUN_INTERACTIVE &&
216           ! warning_dialog (_("Cannot export indexed image with "
217                               "transparency in BMP file format."),
218                             _("Alpha channel will be ignored.")))
219         return GIMP_PDB_CANCEL;
220 
221      /* fallthrough */
222 
223     case GIMP_INDEXED_IMAGE:
224       format   = gimp_drawable_get_format (drawable_ID);
225       cmap     = gimp_image_get_colormap (image, &colors);
226       MapSize  = 4 * colors;
227 
228       if (drawable_type == GIMP_INDEXEDA_IMAGE)
229         channels = 2;
230       else
231         channels = 1;
232 
233       if (colors > 16)
234         BitsPerPixel = 8;
235       else if (colors > 2)
236         BitsPerPixel = 4;
237       else
238         BitsPerPixel = 1;
239 
240       for (i = 0; i < colors; i++)
241         {
242           Red[i]   = *cmap++;
243           Green[i] = *cmap++;
244           Blue[i]  = *cmap++;
245         }
246       break;
247 
248     default:
249       g_assert_not_reached ();
250     }
251 
252   BMPSaveData.use_run_length_encoding = 0;
253   BMPSaveData.dont_write_color_space_data = 0;
254   mask_info_size = 0;
255 
256   if (run_mode != GIMP_RUN_NONINTERACTIVE)
257     {
258       gimp_get_data (SAVE_PROC, &BMPSaveData);
259     }
260 
261   if (run_mode == GIMP_RUN_INTERACTIVE &&
262       (BitsPerPixel == 8 ||
263        BitsPerPixel == 4 ||
264        BitsPerPixel == 1))
265     {
266       if (! save_dialog (1, BitsPerPixel))
267         return GIMP_PDB_CANCEL;
268     }
269   else if (BitsPerPixel == 24 ||
270            BitsPerPixel == 32)
271     {
272       if (run_mode == GIMP_RUN_INTERACTIVE)
273         {
274           if (! save_dialog (channels, BitsPerPixel))
275             return GIMP_PDB_CANCEL;
276         }
277 
278       /* mask_info_size is only set to non-zero for 16- and 32-bpp */
279       switch (BMPSaveData.rgb_format)
280         {
281         case RGB_888:
282           BitsPerPixel = 24;
283           break;
284         case RGBA_8888:
285           BitsPerPixel   = 32;
286           mask_info_size = 16;
287           break;
288         case RGBX_8888:
289           BitsPerPixel   = 32;
290           mask_info_size = 16;
291           break;
292         case RGB_565:
293           BitsPerPixel   = 16;
294           mask_info_size = 16;
295           break;
296         case RGBA_5551:
297           BitsPerPixel   = 16;
298           mask_info_size = 16;
299           break;
300         case RGB_555:
301           BitsPerPixel   = 16;
302           mask_info_size = 16;
303           break;
304         default:
305           g_return_val_if_reached (GIMP_PDB_EXECUTION_ERROR);
306         }
307     }
308 
309   gimp_set_data (SAVE_PROC, &BMPSaveData, sizeof (BMPSaveData));
310 
311   /* Let's begin the progress */
312   gimp_progress_init_printf (_("Exporting '%s'"),
313                              gimp_filename_to_utf8 (filename));
314 
315   /* Let's take some file */
316   outfile = g_fopen (filename, "wb");
317   if (!outfile)
318     {
319       g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
320                    _("Could not open '%s' for writing: %s"),
321                    gimp_filename_to_utf8 (filename), g_strerror (errno));
322       return GIMP_PDB_EXECUTION_ERROR;
323     }
324 
325   /* fetch the image */
326   pixels = g_new (guchar, drawable_width * drawable_height * channels);
327 
328   gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0,
329                                            drawable_width, drawable_height), 1.0,
330                    format, pixels,
331                    GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
332 
333   g_object_unref (buffer);
334 
335   /* Now, we need some further information ... */
336   cols = drawable_width;
337   rows = drawable_height;
338 
339   /* ... that we write to our headers. */
340   if ((BitsPerPixel <= 8) && (cols % (8 / BitsPerPixel)))
341     Spcols = (((cols / (8 / BitsPerPixel)) + 1) * (8 / BitsPerPixel));
342   else
343     Spcols = cols;
344 
345   if ((((Spcols * BitsPerPixel) / 8) % 4) == 0)
346     SpZeile = ((Spcols * BitsPerPixel) / 8);
347   else
348     SpZeile = ((gint) (((Spcols * BitsPerPixel) / 8) / 4) + 1) * 4;
349 
350   if (! BMPSaveData.dont_write_color_space_data)
351     {
352       /* Always include color mask for BITMAPV5HEADER, see #4155. */
353       mask_info_size = 16;
354       color_space_size = 68;
355     }
356   else
357     {
358       color_space_size = 0;
359     }
360 
361   bitmap_file_head.bfSize    = (0x36 + MapSize + (rows * SpZeile) +
362                                 mask_info_size + color_space_size);
363   bitmap_file_head.zzHotX    =  0;
364   bitmap_file_head.zzHotY    =  0;
365   bitmap_file_head.bfOffs    = (0x36 + MapSize +
366                                 mask_info_size + color_space_size);
367   bitmap_file_head.biSize    =  40 + mask_info_size + color_space_size;
368 
369   bitmap_head.biWidth  = cols;
370   bitmap_head.biHeight = rows;
371   bitmap_head.biPlanes = 1;
372   bitmap_head.biBitCnt = BitsPerPixel;
373 
374   if (BMPSaveData.use_run_length_encoding == 0)
375     {
376       /* The Microsoft specification for BITMAPV5HEADER says that
377        * BI_BITFIELDS is valid for 16 and 32-bits per pixel,
378        * Since it doesn't mention 24 bpp or other numbers
379        * use BI_RGB for that. See issue #6114. */
380       if (mask_info_size > 0 && (BitsPerPixel == 16 || BitsPerPixel == 32))
381         bitmap_head.biCompr = 3; /* BI_BITFIELDS */
382       else
383         bitmap_head.biCompr = 0; /* BI_RGB */
384     }
385   else if (BitsPerPixel == 8)
386     {
387       bitmap_head.biCompr = 1;
388     }
389   else if (BitsPerPixel == 4)
390     {
391       bitmap_head.biCompr = 2;
392     }
393   else
394     {
395       bitmap_head.biCompr = 0;
396     }
397 
398   bitmap_head.biSizeIm = SpZeile * rows;
399 
400   {
401     gdouble xresolution;
402     gdouble yresolution;
403     gimp_image_get_resolution (image, &xresolution, &yresolution);
404 
405     if (xresolution > GIMP_MIN_RESOLUTION &&
406         yresolution > GIMP_MIN_RESOLUTION)
407       {
408         /*
409          * xresolution and yresolution are in dots per inch.
410          * the BMP spec says that biXPels and biYPels are in
411          * pixels per meter as long ints (actually, "DWORDS"),
412          * so...
413          *    n dots    inch     100 cm   m dots
414          *    ------ * ------- * ------ = ------
415          *     inch    2.54 cm     m       inch
416          *
417          * We add 0.5 for proper rounding.
418          */
419         bitmap_head.biXPels = (long int) (xresolution * 100.0 / 2.54 + 0.5);
420         bitmap_head.biYPels = (long int) (yresolution * 100.0 / 2.54 + 0.5);
421       }
422   }
423 
424   if (BitsPerPixel <= 8)
425     bitmap_head.biClrUsed = colors;
426   else
427     bitmap_head.biClrUsed = 0;
428 
429   bitmap_head.biClrImp = bitmap_head.biClrUsed;
430 
431 #ifdef DEBUG
432   printf ("\nSize: %u, Colors: %u, Bits: %u, Width: %u, Height: %u, Comp: %u, Zeile: %u\n",
433           (int)bitmap_file_head.bfSize,
434           (int)bitmap_head.biClrUsed,
435           bitmap_head.biBitCnt,
436           (int)bitmap_head.biWidth,
437           (int)bitmap_head.biHeight,
438           (int)bitmap_head.biCompr,SpZeile);
439 #endif
440 
441   /* And now write the header and the colormap (if any) to disk */
442 
443   Write (outfile, "BM", 2);
444 
445   bitmap_file_head.bfSize = GUINT32_TO_LE (bitmap_file_head.bfSize);
446   bitmap_file_head.zzHotX = GUINT16_TO_LE (bitmap_file_head.zzHotX);
447   bitmap_file_head.zzHotY = GUINT16_TO_LE (bitmap_file_head.zzHotY);
448   bitmap_file_head.bfOffs = GUINT32_TO_LE (bitmap_file_head.bfOffs);
449   bitmap_file_head.biSize = GUINT32_TO_LE (bitmap_file_head.biSize);
450 
451   Write (outfile, &bitmap_file_head.bfSize, 16);
452 
453   bitmap_head.biWidth   = GINT32_TO_LE  (bitmap_head.biWidth);
454   bitmap_head.biHeight  = GINT32_TO_LE  (bitmap_head.biHeight);
455   bitmap_head.biPlanes  = GUINT16_TO_LE (bitmap_head.biPlanes);
456   bitmap_head.biBitCnt  = GUINT16_TO_LE (bitmap_head.biBitCnt);
457   bitmap_head.biCompr   = GUINT32_TO_LE (bitmap_head.biCompr);
458   bitmap_head.biSizeIm  = GUINT32_TO_LE (bitmap_head.biSizeIm);
459   bitmap_head.biXPels   = GUINT32_TO_LE (bitmap_head.biXPels);
460   bitmap_head.biYPels   = GUINT32_TO_LE (bitmap_head.biYPels);
461   bitmap_head.biClrUsed = GUINT32_TO_LE (bitmap_head.biClrUsed);
462   bitmap_head.biClrImp  = GUINT32_TO_LE (bitmap_head.biClrImp);
463 
464   Write (outfile, &bitmap_head, 36);
465 
466   if (mask_info_size > 0)
467     {
468       switch (BMPSaveData.rgb_format)
469         {
470         default:
471         case RGB_888:
472         case RGBX_8888:
473           Mask[0] = 0x00ff0000;
474           Mask[1] = 0x0000ff00;
475           Mask[2] = 0x000000ff;
476           Mask[3] = 0x00000000;
477           break;
478 
479         case RGBA_8888:
480           Mask[0] = 0x00ff0000;
481           Mask[1] = 0x0000ff00;
482           Mask[2] = 0x000000ff;
483           Mask[3] = 0xff000000;
484           break;
485 
486         case RGB_565:
487           Mask[0] = 0xf800;
488           Mask[1] = 0x7e0;
489           Mask[2] = 0x1f;
490           Mask[3] = 0x0;
491           break;
492 
493         case RGBA_5551:
494           Mask[0] = 0x7c00;
495           Mask[1] = 0x3e0;
496           Mask[2] = 0x1f;
497           Mask[3] = 0x8000;
498           break;
499 
500         case RGB_555:
501           Mask[0] = 0x7c00;
502           Mask[1] = 0x3e0;
503           Mask[2] = 0x1f;
504           Mask[3] = 0x0;
505           break;
506         }
507 
508       Mask[0] = GUINT32_TO_LE (Mask[0]);
509       Mask[1] = GUINT32_TO_LE (Mask[1]);
510       Mask[2] = GUINT32_TO_LE (Mask[2]);
511       Mask[3] = GUINT32_TO_LE (Mask[3]);
512 
513       Write (outfile, &Mask, mask_info_size);
514     }
515 
516   if (! BMPSaveData.dont_write_color_space_data)
517     {
518       guint32 buf[0x11];
519 
520       /* Write V5 color space fields */
521 
522       /* bV5CSType = LCS_sRGB */
523       buf[0x00] = GUINT32_TO_LE (0x73524742);
524 
525       /* bV5Endpoints is set to 0 (ignored) */
526       for (i = 0; i < 0x09; i++)
527         buf[i + 1] = 0x00;
528 
529       /* bV5GammaRed is set to 0 (ignored) */
530       buf[0x0a] = GUINT32_TO_LE (0x0);
531 
532       /* bV5GammaGreen is set to 0 (ignored) */
533       buf[0x0b] = GUINT32_TO_LE (0x0);
534 
535       /* bV5GammaBlue is set to 0 (ignored) */
536       buf[0x0c] = GUINT32_TO_LE (0x0);
537 
538       /* bV5Intent = LCS_GM_GRAPHICS */
539       buf[0x0d] = GUINT32_TO_LE (0x00000002);
540 
541       /* bV5ProfileData is set to 0 (ignored) */
542       buf[0x0e] = GUINT32_TO_LE (0x0);
543 
544       /* bV5ProfileSize is set to 0 (ignored) */
545       buf[0x0f] = GUINT32_TO_LE (0x0);
546 
547       /* bV5Reserved = 0 */
548       buf[0x10] = GUINT32_TO_LE (0x0);
549 
550       Write (outfile, buf, color_space_size);
551     }
552 
553   write_color_map (outfile, Red, Green, Blue, MapSize);
554 
555   /* After that is done, we write the image ... */
556 
557   write_image (outfile,
558                pixels, cols, rows,
559                BMPSaveData.use_run_length_encoding,
560                channels, BitsPerPixel, SpZeile,
561                MapSize, BMPSaveData.rgb_format,
562                mask_info_size, color_space_size);
563 
564   /* ... and exit normally */
565 
566   fclose (outfile);
567   g_free (pixels);
568 
569   return GIMP_PDB_SUCCESS;
570 }
571 
572 static inline void
Make565(guchar r,guchar g,guchar b,guchar * buf)573 Make565 (guchar  r,
574          guchar  g,
575          guchar  b,
576          guchar *buf)
577 {
578   gint p;
579 
580   p = ((((gint) (r / 255.0 * 31.0 + 0.5)) << 11) |
581        (((gint) (g / 255.0 * 63.0 + 0.5)) <<  5) |
582        (((gint) (b / 255.0 * 31.0 + 0.5))));
583 
584   buf[0] = (guchar) (p & 0xff);
585   buf[1] = (guchar) (p >> 8);
586 }
587 
588 static inline void
Make5551(guchar r,guchar g,guchar b,guchar a,guchar * buf)589 Make5551 (guchar  r,
590           guchar  g,
591           guchar  b,
592           guchar  a,
593           guchar *buf)
594 {
595   gint p;
596 
597   p = ((((gint) (r / 255.0 * 31.0 + 0.5)) << 10) |
598        (((gint) (g / 255.0 * 31.0 + 0.5)) <<  5) |
599        (((gint) (b / 255.0 * 31.0 + 0.5)))       |
600        (((gint) (a / 255.0 +  0.5)        << 15)));
601 
602   buf[0] = (guchar) (p & 0xff);
603   buf[1] = (guchar) (p >> 8);
604 }
605 
606 static void
write_image(FILE * f,guchar * src,gint width,gint height,gint use_run_length_encoding,gint channels,gint bpp,gint spzeile,gint MapSize,RGBMode rgb_format,gint mask_info_size,gint color_space_size)607 write_image (FILE   *f,
608              guchar *src,
609              gint    width,
610              gint    height,
611              gint    use_run_length_encoding,
612              gint    channels,
613              gint    bpp,
614              gint    spzeile,
615              gint    MapSize,
616              RGBMode rgb_format,
617              gint    mask_info_size,
618              gint    color_space_size)
619 {
620   guchar  buf[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0 };
621   guint32 uint32buf;
622   guchar *temp, v;
623   guchar *row, *ketten;
624   gint    xpos, ypos, i, j, rowstride, length, thiswidth;
625   gint    breite, k;
626   guchar  n, r, g, b, a;
627   gint    cur_progress;
628   gint    max_progress;
629 
630   xpos = 0;
631   rowstride = width * channels;
632 
633   cur_progress = 0;
634   max_progress = height;
635 
636   /* We'll begin with the 16/24/32 bit Bitmaps, they are easy :-) */
637 
638   if (bpp > 8)
639     {
640       for (ypos = height - 1; ypos >= 0; ypos--)  /* for each row   */
641         {
642           for (i = 0; i < width; i++)  /* for each pixel */
643             {
644               temp = src + (ypos * rowstride) + (xpos * channels);
645               switch (rgb_format)
646                 {
647                 default:
648                 case RGB_888:
649                   buf[2] = *temp++;
650                   buf[1] = *temp++;
651                   buf[0] = *temp++;
652                   xpos++;
653                   if (channels > 3 && (guchar) *temp == 0)
654                     buf[0] = buf[1] = buf[2] = 0xff;
655                   Write (f, buf, 3);
656                   break;
657                 case RGBX_8888:
658                   buf[2] = *temp++;
659                   buf[1] = *temp++;
660                   buf[0] = *temp++;
661                   buf[3] = 0;
662                   xpos++;
663                   if (channels > 3 && (guchar) *temp == 0)
664                     buf[0] = buf[1] = buf[2] = 0xff;
665                   Write (f, buf, 4);
666                   break;
667                 case RGBA_8888:
668                   buf[2] = *temp++;
669                   buf[1] = *temp++;
670                   buf[0] = *temp++;
671                   buf[3] = *temp;
672                   xpos++;
673                   Write (f, buf, 4);
674                   break;
675                 case RGB_565:
676                   r = *temp++;
677                   g = *temp++;
678                   b = *temp++;
679                   if (channels > 3 && (guchar) *temp == 0)
680                     r = g = b = 0xff;
681                   Make565 (r, g, b, buf);
682                   xpos++;
683                   Write (f, buf, 2);
684                   break;
685                 case RGB_555:
686                   r = *temp++;
687                   g = *temp++;
688                   b = *temp++;
689                   if (channels > 3 && (guchar) *temp == 0)
690                     r = g = b = 0xff;
691                   Make5551 (r, g, b, 0x0, buf);
692                   xpos++;
693                   Write (f, buf, 2);
694                   break;
695                 case RGBA_5551:
696                   r = *temp++;
697                   g = *temp++;
698                   b = *temp++;
699                   a = *temp;
700                   Make5551 (r, g, b, a, buf);
701                   xpos++;
702                   Write (f, buf, 2);
703                   break;
704                 }
705             }
706 
707           Write (f, &buf[4], spzeile - (width * (bpp/8)));
708 
709           cur_progress++;
710           if ((cur_progress % 5) == 0)
711             gimp_progress_update ((gdouble) cur_progress /
712                                   (gdouble) max_progress);
713 
714           xpos = 0;
715         }
716     }
717   else
718     {
719       if (bpp == 1)
720         use_run_length_encoding = 0;
721       switch (use_run_length_encoding)  /* now it gets more difficult */
722         {               /* uncompressed 1,4 and 8 bit */
723         case 0:
724           {
725             thiswidth = (width / (8 / bpp));
726             if (width % (8 / bpp))
727               thiswidth++;
728 
729             for (ypos = height - 1; ypos >= 0; ypos--) /* for each row */
730               {
731                 for (xpos = 0; xpos < width;)  /* for each _byte_ */
732                   {
733                     v = 0;
734                     for (i = 1;
735                          (i <= (8 / bpp)) && (xpos < width);
736                          i++, xpos++)  /* for each pixel */
737                       {
738                         temp = src + (ypos * rowstride) + (xpos * channels);
739                         if (channels > 1 && *(temp+1) == 0) *temp = 0x0;
740                         v=v | ((guchar) *temp << (8 - (i * bpp)));
741                       }
742                     Write (f, &v, 1);
743                   }
744                 Write (f, &buf[3], spzeile - thiswidth);
745                 xpos = 0;
746 
747                 cur_progress++;
748                 if ((cur_progress % 5) == 0)
749                   gimp_progress_update ((gdouble) cur_progress /
750                                         (gdouble) max_progress);
751               }
752             break;
753           }
754         default:
755           {              /* Save RLE encoded file, quite difficult */
756             length = 0;
757             buf[12] = 0;
758             buf[13] = 1;
759             buf[14] = 0;
760             buf[15] = 0;
761             row = g_new (guchar, width / (8 / bpp) + 10);
762             ketten = g_new (guchar, width / (8 / bpp) + 10);
763             for (ypos = height - 1; ypos >= 0; ypos--)
764               { /* each row separately */
765                 j = 0;
766                 /* first copy the pixels to a buffer,
767                  * making one byte from two 4bit pixels
768                  */
769                 for (xpos = 0; xpos < width;)
770                   {
771                     v = 0;
772                     for (i = 1;
773                          (i <= (8 / bpp)) && (xpos < width);
774                          i++, xpos++)
775                       { /* for each pixel */
776                         temp = src + (ypos * rowstride) + (xpos * channels);
777                         if (channels > 1 && *(temp+1) == 0) *temp = 0x0;
778                         v = v | ((guchar) * temp << (8 - (i * bpp)));
779                       }
780                     row[j++] = v;
781                   }
782                 breite = width / (8 / bpp);
783                 if (width % (8 / bpp))
784                   breite++;
785 
786                 /* then check for strings of equal bytes */
787                 for (i = 0; i < breite; i += j)
788                   {
789                     j = 0;
790                     while ((i + j < breite) &&
791                            (j < (255 / (8 / bpp))) &&
792                            (row[i + j] == row[i]))
793                       j++;
794 
795                     ketten[i] = j;
796                   }
797 
798                 /* then write the strings and the other pixels to the file */
799                 for (i = 0; i < breite;)
800                   {
801                     if (ketten[i] < 3)
802                       /* strings of different pixels ... */
803                       {
804                         j = 0;
805                         while ((i + j < breite) &&
806                                (j < (255 / (8 / bpp))) &&
807                                (ketten[i + j] < 3))
808                           j += ketten[i + j];
809 
810                         /* this can only happen if j jumps over
811                          * the end with a 2 in ketten[i+j]
812                          */
813                         if (j > (255 / (8 / bpp)))
814                           j -= 2;
815                         /* 00 01 and 00 02 are reserved */
816                         if (j > 2)
817                           {
818                             Write (f, &buf[12], 1);
819                             n = j * (8 / bpp);
820                             if (n + i * (8 / bpp) > width)
821                               n--;
822                             Write (f, &n, 1);
823                             length += 2;
824                             Write (f, &row[i], j);
825                             length += j;
826                             if ((j) % 2)
827                               {
828                                 Write (f, &buf[12], 1);
829                                 length++;
830                               }
831                           }
832                         else
833                           {
834                             for (k = i; k < i + j; k++)
835                               {
836                                 n = (8 / bpp);
837                                 if (n + i * (8 / bpp) > width)
838                                   n--;
839                                 Write (f, &n, 1);
840                                 Write (f, &row[k], 1);
841                                 /*printf("%i.#|",n); */
842                                 length += 2;
843                               }
844                           }
845                         i += j;
846                       }
847                     else
848                       /* strings of equal pixels */
849                       {
850                         n = ketten[i] * (8 / bpp);
851                         if (n + i * (8 / bpp) > width)
852                           n--;
853                         Write (f, &n, 1);
854                         Write (f, &row[i], 1);
855                         i += ketten[i];
856                         length += 2;
857                       }
858                   }
859 
860                 Write (f, &buf[14], 2);          /* End of row */
861                 length += 2;
862 
863                 cur_progress++;
864                 if ((cur_progress % 5) == 0)
865                   gimp_progress_update ((gdouble) cur_progress /
866                                         (gdouble) max_progress);
867               }
868 
869             fseek (f, -2, SEEK_CUR);     /* Overwrite last End of row ... */
870             Write (f, &buf[12], 2);      /* ... with End of file */
871 
872             fseek (f, 0x22, SEEK_SET);            /* Write length of image */
873             uint32buf = GUINT32_TO_LE (length);
874             Write (f, &uint32buf, 4);
875 
876             fseek (f, 0x02, SEEK_SET);            /* Write length of file */
877             length += (0x36 + MapSize + mask_info_size + color_space_size);
878             uint32buf = GUINT32_TO_LE (length);
879             Write (f, &uint32buf, 4);
880 
881             g_free (ketten);
882             g_free (row);
883             break;
884           }
885         }
886     }
887 
888   gimp_progress_update (1.0);
889 }
890 
891 static void
format_callback(GtkToggleButton * toggle,gpointer data)892 format_callback (GtkToggleButton *toggle,
893                  gpointer         data)
894 {
895   if (gtk_toggle_button_get_active (toggle))
896     BMPSaveData.rgb_format = GPOINTER_TO_INT (data);
897 }
898 
899 static gboolean
save_dialog(gint channels,gint bpp)900 save_dialog (gint channels, gint bpp)
901 {
902   GtkWidget *dialog;
903   GtkWidget *toggle;
904   GtkWidget *vbox_main;
905   GtkWidget *vbox;
906   GtkWidget *vbox2;
907   GtkWidget *expander;
908   GtkWidget *frame;
909   GSList    *group;
910   gboolean   run;
911 
912   /* Dialog init */
913   dialog = gimp_export_dialog_new ("BMP", PLUG_IN_BINARY, SAVE_PROC);
914 
915   gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
916 
917   vbox_main = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
918   gtk_container_set_border_width (GTK_CONTAINER (vbox_main), 12);
919   gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
920                       vbox_main, TRUE, TRUE, 0);
921   gtk_widget_show (vbox_main);
922 
923   /* Run-Length Encoded */
924   toggle = gtk_check_button_new_with_mnemonic (_("_Run-Length Encoded"));
925   gtk_box_pack_start (GTK_BOX (vbox_main), toggle, FALSE, FALSE, 0);
926   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
927                                 BMPSaveData.use_run_length_encoding);
928   gtk_widget_show (toggle);
929   if (channels > 1 || bpp == 1)
930     gtk_widget_set_sensitive (toggle, FALSE);
931 
932   g_signal_connect (toggle, "toggled",
933                     G_CALLBACK (gimp_toggle_button_update),
934                     &BMPSaveData.use_run_length_encoding);
935 
936   /* Compatibility Options */
937   expander = gtk_expander_new_with_mnemonic (_("Co_mpatibility Options"));
938 
939   gtk_box_pack_start (GTK_BOX (vbox_main), expander, TRUE, TRUE, 0);
940   gtk_widget_show (expander);
941 
942   vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
943   gtk_container_set_border_width (GTK_CONTAINER (vbox2), 12);
944   gtk_container_add (GTK_CONTAINER (expander), vbox2);
945   gtk_widget_show (vbox2);
946 
947   toggle = gtk_check_button_new_with_mnemonic (_("_Do not write color space information"));
948   gimp_help_set_help_data (toggle,
949                            _("Some applications can not read BMP images that "
950                              "include color space information. GIMP writes "
951                              "color space information by default. Enabling "
952                              "this option will cause GIMP to not write color "
953                              "space information to the file."),
954                            NULL);
955   gtk_box_pack_start (GTK_BOX (vbox2), toggle, FALSE, FALSE, 0);
956   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
957                                 BMPSaveData.dont_write_color_space_data);
958   gtk_widget_show (toggle);
959 
960   g_signal_connect (toggle, "toggled",
961                     G_CALLBACK (gimp_toggle_button_update),
962                     &BMPSaveData.dont_write_color_space_data);
963 
964   /* Advanced Options */
965   expander = gtk_expander_new_with_mnemonic (_("_Advanced Options"));
966 
967   gtk_box_pack_start (GTK_BOX (vbox_main), expander, TRUE, TRUE, 0);
968   gtk_widget_show (expander);
969 
970   if (channels < 3)
971     gtk_widget_set_sensitive (expander, FALSE);
972 
973   vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
974   gtk_container_set_border_width (GTK_CONTAINER (vbox2), 12);
975   gtk_container_add (GTK_CONTAINER (expander), vbox2);
976   gtk_widget_show (vbox2);
977 
978   group = NULL;
979 
980   frame = gimp_frame_new (_("16 bits"));
981   gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, 0);
982   gtk_widget_show (frame);
983 
984   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
985   gtk_container_add (GTK_CONTAINER (frame), vbox);
986   gtk_widget_show (vbox);
987 
988   toggle = gtk_radio_button_new_with_mnemonic (group, "_R5 G6 B5");
989   group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
990   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
991   gtk_widget_show (toggle);
992   g_signal_connect (toggle, "toggled",
993                     G_CALLBACK (format_callback),
994                     GINT_TO_POINTER (RGB_565));
995 
996   toggle = gtk_radio_button_new_with_mnemonic (group, "_A1 R5 G5 B5");
997   group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
998   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
999 
1000   if (channels < 4)
1001     gtk_widget_set_sensitive (toggle, FALSE);
1002 
1003   gtk_widget_show (toggle);
1004 
1005   g_signal_connect (toggle, "toggled",
1006                     G_CALLBACK (format_callback),
1007                     GINT_TO_POINTER (RGBA_5551));
1008   toggle = gtk_radio_button_new_with_mnemonic (group, "_X1 R5 G5 B5");
1009   group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
1010   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1011   gtk_widget_show (toggle);
1012   g_signal_connect (toggle, "toggled",
1013                     G_CALLBACK (format_callback),
1014                     GINT_TO_POINTER (RGB_555));
1015 
1016   frame = gimp_frame_new (_("24 bits"));
1017   gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0);
1018   gtk_widget_show (frame);
1019 
1020   toggle = gtk_radio_button_new_with_mnemonic (group, "R_8 G8 B8");
1021   group = gtk_radio_button_get_group (GTK_RADIO_BUTTON(toggle));
1022   gtk_container_add (GTK_CONTAINER (frame), toggle);
1023   gtk_widget_show (toggle);
1024   g_signal_connect (toggle, "toggled",
1025                     G_CALLBACK (format_callback),
1026                     GINT_TO_POINTER (RGB_888));
1027   if (channels < 4)
1028     {
1029       BMPSaveData.rgb_format = RGB_888;
1030       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), TRUE);
1031     }
1032 
1033   frame = gimp_frame_new (_("32 bits"));
1034   gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0);
1035   gtk_widget_show (frame);
1036 
1037   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1038   gtk_container_add (GTK_CONTAINER (frame), vbox);
1039   gtk_widget_show (vbox);
1040 
1041   toggle = gtk_radio_button_new_with_mnemonic (group, "A8 R8 G8 _B8");
1042   group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
1043   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1044   gtk_widget_show (toggle);
1045   g_signal_connect (toggle, "toggled",
1046                     G_CALLBACK (format_callback),
1047                     GINT_TO_POINTER (RGBA_8888));
1048 
1049 
1050   if (channels < 4)
1051     {
1052       gtk_widget_set_sensitive (toggle, FALSE);
1053     }
1054   else
1055     {
1056       BMPSaveData.rgb_format = RGBA_8888;
1057       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), TRUE);
1058     }
1059 
1060   toggle = gtk_radio_button_new_with_mnemonic (group, "X8 R8 G8 _B8");
1061   group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle));
1062   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1063   gtk_widget_show (toggle);
1064   g_signal_connect (toggle, "toggled",
1065                     G_CALLBACK (format_callback),
1066                     GINT_TO_POINTER (RGBX_8888));
1067 
1068   /* Dialog show */
1069   gtk_widget_show (dialog);
1070 
1071   run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
1072 
1073   gtk_widget_destroy (dialog);
1074 
1075   return run;
1076 }
1077