Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/plug-ins/file-bmp/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 33 kB image not shown  

Quelle  bmp-export.c   Sprache: C

 

/* bmpwrite.c   Writes Bitmap files. Even RLE encoded ones.      */
/*              (Windows (TM) doesn't read all of those, but who */
/*              cares? ;-)                                       */
/*              I changed a few things over the time, so perhaps */
/*              it dos now, but now there's no Windows left on   */
/*              my computer...                                   */

/* Alexander.Schulz@stud.uni-karlsruhe.de                        */

/*
 * GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>.
 * ----------------------------------------------------------------------------
 */


#include "config.h"

#include <errno.h>
#include <string.h>

#include <glib/gstdio.h>

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

#include "bmp.h"
#include "bmp-export.h"

#include "libgimp/stdplugins-intl.h"


static  gboolean  write_image     (FILE          *f,
                                   guchar        *src,
                                   gint           width,
                                   gint           height,
                                   gboolean       use_run_length_encoding,
                                   gint           channels,
                                   gint           bpp,
                                   gint           spzeile,
                                   gint           MapSize,
                                   RGBMode        rgb_format,
                                   gint           mask_info_size,
                                   gint           color_space_size);

static  gboolean  save_dialog     (GimpProcedure *procedure,
                                   GObject       *config,
                                   GimpImage     *image,
                                   gint           channels,
                                   gint           bpp);


static gboolean
write_color_map (FILE *f,
                 gint  red[MAXCOLORS],
                 gint  green[MAXCOLORS],
                 gint  blue[MAXCOLORS],
                 gint  size)
{
  gchar trgb[4];
  gint  i;

  size /= 4;
  trgb[3] = 0;
  for (i = 0; i < size; i++)
    {
      trgb[0] = (guchar) blue[i];
      trgb[1] = (guchar) green[i];
      trgb[2] = (guchar) red[i];
      if (fwrite (trgb, 1, 4, f) != 4)
        return FALSE;
    }
  return TRUE;
}

static gboolean
warning_dialog (const gchar *primary,
                const gchar *secondary)
{
  GtkWidget *dialog;
  gboolean   ok;

  dialog = gtk_message_dialog_new (NULL, 0,
                                   GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL,
                                   "%s", primary);

  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
                                            "%s", secondary);

  gimp_window_set_transient (GTK_WINDOW (dialog));
  gtk_widget_show (dialog);

  ok = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK);

  gtk_widget_destroy (dialog);

  return ok;
}

GimpPDBStatusType
export_image (GFile         *file,
              GimpImage     *image,
              GimpDrawable  *drawable,
              GimpRunMode    run_mode,
              GimpProcedure *procedure,
              GObject       *config,
              GError       **error)
{
  FILE           *outfile = NULL;
  BitmapFileHead  bitmap_file_head;
  BitmapHead      bitmap_head;
  gint            Red[MAXCOLORS];
  gint            Green[MAXCOLORS];
  gint            Blue[MAXCOLORS];
  guchar         *cmap;
  gint            rows, cols, channels, MapSize;
  gint            bytes_per_row;
  glong           BitsPerPixel;
  gint            colors;
  guchar         *pixels = NULL;
  GeglBuffer     *buffer;
  const Babl     *format;
  GimpImageType   drawable_type;
  gint            drawable_width;
  gint            drawable_height;
  gint            i;
  gint            mask_info_size;
  gint            color_space_size;
  guint32         Mask[4];
  gboolean        use_rle;
  gboolean        write_color_space;
  RGBMode         rgb_format;

  buffer = gimp_drawable_get_buffer (drawable);

  drawable_type   = gimp_drawable_type   (drawable);
  drawable_width  = gimp_drawable_get_width  (drawable);
  drawable_height = gimp_drawable_get_height (drawable);

  switch (drawable_type)
    {
    case GIMP_RGBA_IMAGE:
      format       = babl_format ("R'G'B'A u8");
      colors       = 0;
      BitsPerPixel = 32;
      MapSize      = 0;
      channels     = 4;

      if (run_mode == GIMP_RUN_INTERACTIVE)
        g_object_set (config,
                      "rgb-format", "rgba-8888",
                      "use-rle",    FALSE,
                      NULL);
      else
        g_object_set (config,
                      "use-rle",    FALSE,
                      NULL);
      break;

    case GIMP_RGB_IMAGE:
      format       = babl_format ("R'G'B' u8");
      colors       = 0;
      BitsPerPixel = 24;
      MapSize      = 0;
      channels     = 3;

      if (run_mode == GIMP_RUN_INTERACTIVE)
        g_object_set (config,
                      "rgb-format", "rgb-888",
                      "use-rle",    FALSE,
                      NULL);
      else
        g_object_set (config,
                      "use-rle", FALSE,
                      NULL);
      break;

    case GIMP_GRAYA_IMAGE:
      if (run_mode == GIMP_RUN_INTERACTIVE &&
          ! warning_dialog (_("Cannot export indexed image with "
                              "transparency in BMP file format."),
                            _("Alpha channel will be ignored.")))
        return GIMP_PDB_CANCEL;

     /* fallthrough */

    case GIMP_GRAY_IMAGE:
      colors       = 256;
      BitsPerPixel = 8;
      MapSize      = 1024;

      if (drawable_type == GIMP_GRAYA_IMAGE)
        {
          format   = babl_format ("Y'A u8");
          channels = 2;
        }
      else
        {
          format   = babl_format ("Y' u8");
          channels = 1;
        }

      for (i = 0; i < colors; i++)
        {
          Red[i]   = i;
          Green[i] = i;
          Blue[i]  = i;
        }
      break;

    case GIMP_INDEXEDA_IMAGE:
      if (run_mode == GIMP_RUN_INTERACTIVE &&
          ! warning_dialog (_("Cannot export indexed image with "
                              "transparency in BMP file format."),
                            _("Alpha channel will be ignored.")))
        return GIMP_PDB_CANCEL;

     /* fallthrough */

    case GIMP_INDEXED_IMAGE:
      format   = gimp_drawable_get_format (drawable);
      cmap     = gimp_palette_get_colormap (gimp_image_get_palette (image), babl_format ("R'G'B' u8"), &colors, NULL);
      MapSize  = 4 * colors;

      if (drawable_type == GIMP_INDEXEDA_IMAGE)
        channels = 2;
      else
        channels = 1;

      if (colors > 16)
        BitsPerPixel = 8;
      else if (colors > 2)
        BitsPerPixel = 4;
      else
        {
          BitsPerPixel = 1;
          g_object_set (config,
                        "use-rle", FALSE,
                        NULL);
        }

      for (i = 0; i < colors; i++)
        {
          Red[i]   = *cmap++;
          Green[i] = *cmap++;
          Blue[i]  = *cmap++;
        }
      break;

    default:
      g_assert_not_reached ();
    }

  mask_info_size = 0;

  if (run_mode == GIMP_RUN_INTERACTIVE &&
      (BitsPerPixel == 8 ||
       BitsPerPixel == 4 ||
       BitsPerPixel == 1))
    {
      if (! save_dialog (procedure, config, image, 1, BitsPerPixel))
        return GIMP_PDB_CANCEL;
    }
  else if (BitsPerPixel == 24 ||
           BitsPerPixel == 32)
    {
      if (run_mode == GIMP_RUN_INTERACTIVE)
        {
          if (! save_dialog (procedure, config, image, channels, BitsPerPixel))
            return GIMP_PDB_CANCEL;
        }

      rgb_format =
        gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
                                             "rgb-format");

      /* mask_info_size is only set to non-zero for 16- and 32-bpp */
      switch (rgb_format)
        {
        case RGB_888:
          BitsPerPixel = 24;
          break;
        case RGBA_8888:
          BitsPerPixel   = 32;
          mask_info_size = 16;
          break;
        case RGBX_8888:
          BitsPerPixel   = 32;
          mask_info_size = 16;
          break;
        case RGB_565:
          BitsPerPixel   = 16;
          mask_info_size = 16;
          break;
        case RGBA_5551:
          BitsPerPixel   = 16;
          mask_info_size = 16;
          break;
        case RGB_555:
          BitsPerPixel   = 16;
          mask_info_size = 16;
          break;
        default:
          g_return_val_if_reached (GIMP_PDB_EXECUTION_ERROR);
        }
    }

  g_object_get (config,
                "use-rle",           &use_rle,
                "write-color-space", &write_color_space,
                NULL);
  rgb_format =
    gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
                                         "rgb-format");

  gimp_progress_init_printf (_("Exporting '%s'"),
                             gimp_file_get_utf8_name (file));

  outfile = g_fopen (g_file_peek_path (file), "wb");

  if (! outfile)
    {
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                   _("Could not open '%s' for writing: %s"),
                   gimp_file_get_utf8_name (file), g_strerror (errno));
      return GIMP_PDB_EXECUTION_ERROR;
    }

  /* fetch the image */
  pixels = g_new (guchar, (gsize) drawable_width * drawable_height * channels);

  gegl_buffer_get (buffer,
                   GEGL_RECTANGLE (0, 0, drawable_width, drawable_height), 1.0,
                   format, pixels,
                   GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

  g_object_unref (buffer);

  /* Now, we need some further information ... */
  cols = drawable_width;
  rows = drawable_height;

  /* ... that we write to our headers. */
  /* We should consider rejecting any width > (INT32_MAX - 31) / BitsPerPixel, as
   * the resulting BMP will likely cause integer overflow in other readers.
   * TODO: Revisit as soon as we can add strings again !!! */


  bytes_per_row = (( (guint64) cols * BitsPerPixel + 31) / 32) * 4;

  if (write_color_space)
    {
      /* Always include color mask for BITMAPV5HEADER, see #4155. */
      mask_info_size   = 16;
      color_space_size = 68;
    }
  else
    {
      color_space_size = 0;
    }

  bitmap_file_head.bfSize    = (54 + MapSize + (rows * bytes_per_row) +
                                mask_info_size + color_space_size);
  bitmap_file_head.zzHotX    =  0;
  bitmap_file_head.zzHotY    =  0;
  bitmap_file_head.bfOffs    = (54 + MapSize +
                                mask_info_size + color_space_size);

  bitmap_head.biSize   = 40 + mask_info_size + color_space_size;
  bitmap_head.biWidth  = cols;
  bitmap_head.biHeight = rows;
  bitmap_head.biPlanes = 1;
  bitmap_head.biBitCnt = BitsPerPixel;

  if (! use_rle)
    {
      /* The Microsoft specification for BITMAPV5HEADER says that
       * BI_BITFIELDS is valid for 16 and 32-bits per pixel,
       * Since it doesn't mention 24 bpp or other numbers
       * use BI_RGB for that. See issue #6114. */

      if (mask_info_size > 0 && (BitsPerPixel == 16 || BitsPerPixel == 32))
        bitmap_head.biCompr = BI_BITFIELDS;
      else
        bitmap_head.biCompr = BI_RGB;
    }
  else if (BitsPerPixel == 8)
    {
      bitmap_head.biCompr = BI_RLE8;
    }
  else if (BitsPerPixel == 4)
    {
      bitmap_head.biCompr = BI_RLE4;
    }
  else
    {
      bitmap_head.biCompr = BI_RGB;
    }

  bitmap_head.biSizeIm = bytes_per_row * rows;

  {
    gdouble xresolution;
    gdouble yresolution;

    gimp_image_get_resolution (image, &xresolution, &yresolution);

    if (xresolution > GIMP_MIN_RESOLUTION &&
        yresolution > GIMP_MIN_RESOLUTION)
      {
        /*
         * xresolution and yresolution are in dots per inch.
         * the BMP spec says that biXPels and biYPels are in
         * pixels per meter as long ints (actually, "DWORDS"),
         * so...
         *    n dots    inch     100 cm   m dots
         *    ------ * ------- * ------ = ------
         *     inch    2.54 cm     m       inch
         *
         * We add 0.5 for proper rounding.
         */

        bitmap_head.biXPels = (long int) (xresolution * 100.0 / 2.54 + 0.5);
        bitmap_head.biYPels = (long int) (yresolution * 100.0 / 2.54 + 0.5);
      }
  }

  if (BitsPerPixel <= 8)
    bitmap_head.biClrUsed = colors;
  else
    bitmap_head.biClrUsed = 0;

  bitmap_head.biClrImp = bitmap_head.biClrUsed;

#ifdef DEBUG
  printf ("\nSize: %u, Colors: %u, Bits: %u, Width: %u, Height: %u, Comp: %u, Zeile: %u\n",
          (gint) bitmap_file_head.bfSize,
          (gint) bitmap_head.biClrUsed,
          bitmap_head.biBitCnt,
          (gint) bitmap_head.biWidth,
          (gint) bitmap_head.biHeight,
          (gint) bitmap_head.biCompr, bytes_per_row);
#endif

  /* And now write the header and the colormap (if any) to disk */

  if (fwrite ("BM", 2, 1, outfile) != 1)
    goto abort;

  bitmap_file_head.bfSize = GUINT32_TO_LE (bitmap_file_head.bfSize);
  bitmap_file_head.zzHotX = GUINT16_TO_LE (bitmap_file_head.zzHotX);
  bitmap_file_head.zzHotY = GUINT16_TO_LE (bitmap_file_head.zzHotY);
  bitmap_file_head.bfOffs = GUINT32_TO_LE (bitmap_file_head.bfOffs);

  if (fwrite (&bitmap_file_head.bfSize, 12, 1, outfile) != 1)
    goto abort;

  bitmap_head.biSize    = GUINT32_TO_LE (bitmap_head.biSize);
  bitmap_head.biWidth   = GINT32_TO_LE  (bitmap_head.biWidth);
  bitmap_head.biHeight  = GINT32_TO_LE  (bitmap_head.biHeight);
  bitmap_head.biPlanes  = GUINT16_TO_LE (bitmap_head.biPlanes);
  bitmap_head.biBitCnt  = GUINT16_TO_LE (bitmap_head.biBitCnt);
  bitmap_head.biCompr   = GUINT32_TO_LE (bitmap_head.biCompr);
  bitmap_head.biSizeIm  = GUINT32_TO_LE (bitmap_head.biSizeIm);
  bitmap_head.biXPels   = GUINT32_TO_LE (bitmap_head.biXPels);
  bitmap_head.biYPels   = GUINT32_TO_LE (bitmap_head.biYPels);
  bitmap_head.biClrUsed = GUINT32_TO_LE (bitmap_head.biClrUsed);
  bitmap_head.biClrImp  = GUINT32_TO_LE (bitmap_head.biClrImp);

  if (fwrite (&bitmap_head, 40, 1, outfile) != 1)
    goto abort;

  if (mask_info_size > 0)
    {
      switch (rgb_format)
        {
        default:
        case RGB_888:
        case RGBX_8888:
          Mask[0] = 0x00ff0000;
          Mask[1] = 0x0000ff00;
          Mask[2] = 0x000000ff;
          Mask[3] = 0x00000000;
          break;

        case RGBA_8888:
          Mask[0] = 0x00ff0000;
          Mask[1] = 0x0000ff00;
          Mask[2] = 0x000000ff;
          Mask[3] = 0xff000000;
          break;

        case RGB_565:
          Mask[0] = 0xf800;
          Mask[1] = 0x7e0;
          Mask[2] = 0x1f;
          Mask[3] = 0x0;
          break;

        case RGBA_5551:
          Mask[0] = 0x7c00;
          Mask[1] = 0x3e0;
          Mask[2] = 0x1f;
          Mask[3] = 0x8000;
          break;

        case RGB_555:
          Mask[0] = 0x7c00;
          Mask[1] = 0x3e0;
          Mask[2] = 0x1f;
          Mask[3] = 0x0;
          break;
        }

      Mask[0] = GUINT32_TO_LE (Mask[0]);
      Mask[1] = GUINT32_TO_LE (Mask[1]);
      Mask[2] = GUINT32_TO_LE (Mask[2]);
      Mask[3] = GUINT32_TO_LE (Mask[3]);

      if (fwrite (&Mask, mask_info_size, 1, outfile) != 1)
        goto abort;
    }

  if (write_color_space)
    {
      guint32 buf[0x11];

      /* Write V5 color space fields */

      /* bV5CSType = LCS_sRGB */
      buf[0x00] = GUINT32_TO_LE (0x73524742);

      /* bV5Endpoints is set to 0 (ignored) */
      for (i = 0; i < 0x09; i++)
        buf[i + 1] = 0x00;

      /* bV5GammaRed is set to 0 (ignored) */
      buf[0x0a] = GUINT32_TO_LE (0x0);

      /* bV5GammaGreen is set to 0 (ignored) */
      buf[0x0b] = GUINT32_TO_LE (0x0);

      /* bV5GammaBlue is set to 0 (ignored) */
      buf[0x0c] = GUINT32_TO_LE (0x0);

      /* bV5Intent = LCS_GM_GRAPHICS */
      buf[0x0d] = GUINT32_TO_LE (0x00000002);

      /* bV5ProfileData is set to 0 (ignored) */
      buf[0x0e] = GUINT32_TO_LE (0x0);

      /* bV5ProfileSize is set to 0 (ignored) */
      buf[0x0f] = GUINT32_TO_LE (0x0);

      /* bV5Reserved = 0 */
      buf[0x10] = GUINT32_TO_LE (0x0);

      if (fwrite (buf, color_space_size, 1, outfile) != 1)
        goto abort;
    }

  if (! write_color_map (outfile, Red, Green, Blue, MapSize))
    goto abort;

  /* After that is done, we write the image ... */

  if (! write_image (outfile,
                     pixels, cols, rows,
                     use_rle,
                     channels, BitsPerPixel, bytes_per_row,
                     MapSize, rgb_format,
                     mask_info_size, color_space_size))
    goto abort;

  /* ... and exit normally */

  fclose (outfile);
  g_free (pixels);

  return GIMP_PDB_SUCCESS;

abort:
  if (outfile)
    fclose (outfile);
  g_free(pixels);

  g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
               _("Error writing to file."));

  return GIMP_PDB_EXECUTION_ERROR;
}

static inline void
Make565 (guchar  r,
         guchar  g,
         guchar  b,
         guchar *buf)
{
  gint p;

  p = ((((gint) (r / 255.0 * 31.0 + 0.5)) << 11) |
       (((gint) (g / 255.0 * 63.0 + 0.5)) <<  5) |
       (((gint) (b / 255.0 * 31.0 + 0.5))));

  buf[0] = (guchar) (p & 0xff);
  buf[1] = (guchar) (p >> 8);
}

static inline void
Make5551 (guchar  r,
          guchar  g,
          guchar  b,
          guchar  a,
          guchar *buf)
{
  gint p;

  p = ((((gint) (r / 255.0 * 31.0 + 0.5)) << 10) |
       (((gint) (g / 255.0 * 31.0 + 0.5)) <<  5) |
       (((gint) (b / 255.0 * 31.0 + 0.5)))       |
       (((gint) (a / 255.0 +  0.5)        << 15)));

  buf[0] = (guchar) (p & 0xff);
  buf[1] = (guchar) (p >> 8);
}

static gboolean
write_image (FILE     *f,
             guchar   *src,
             gint      width,
             gint      height,
             gboolean  use_run_length_encoding,
             gint      channels,
             gint      bpp,
             gint      bytes_per_row,
             gint      MapSize,
             RGBMode   rgb_format,
             gint      mask_info_size,
             gint      color_space_size)
{
  guchar  buf[16];
  guint32 uint32buf;
  guchar *temp, v;
  guchar *row    = NULL;
  guchar *chains = NULL;
  gint    xpos, ypos, i, j, rowstride, length, thiswidth;
  gint    breite, k;
  guchar  n, r, g, b, a;
  gint    cur_progress;
  gint    max_progress;
  gint    padding;

  xpos = 0;
  rowstride = width * channels;

  cur_progress = 0;
  max_progress = height;

  /* We'll begin with the 16/24/32 bit Bitmaps, they are easy :-) */

  if (bpp > 8)
    {
      padding = bytes_per_row - (width * (bpp / 8));
      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);
              switch (rgb_format)
                {
                default:
                case RGB_888:
                  buf[2] = *temp++;
                  buf[1] = *temp++;
                  buf[0] = *temp++;
                  xpos++;
                  if (channels > 3 && (guchar) *temp == 0)
                    buf[0] = buf[1] = buf[2] = 0xff;

                  if (fwrite (buf, 1, 3, f) != 3)
                    goto abort;
                  break;
                case RGBX_8888:
                  buf[2] = *temp++;
                  buf[1] = *temp++;
                  buf[0] = *temp++;
                  buf[3] = 0;
                  xpos++;
                  if (channels > 3 && (guchar) *temp == 0)
                    buf[0] = buf[1] = buf[2] = 0xff;

                  if (fwrite (buf, 1, 4, f) != 4)
                    goto abort;
                  break;
                case RGBA_8888:
                  buf[2] = *temp++;
                  buf[1] = *temp++;
                  buf[0] = *temp++;
                  buf[3] = *temp;
                  xpos++;

                  if (fwrite (buf, 1, 4, f) != 4)
                    goto abort;
                  break;
                case RGB_565:
                  r = *temp++;
                  g = *temp++;
                  b = *temp++;
                  if (channels > 3 && (guchar) *temp == 0)
                    r = g = b = 0xff;
                  Make565 (r, g, b, buf);
                  xpos++;

                  if (fwrite (buf, 1, 2, f) != 2)
                    goto abort;
                  break;
                case RGB_555:
                  r = *temp++;
                  g = *temp++;
                  b = *temp++;
                  if (channels > 3 && (guchar) *temp == 0)
                    r = g = b = 0xff;
                  Make5551 (r, g, b, 0x0, buf);
                  xpos++;

                  if (fwrite (buf, 1, 2, f) != 2)
                    goto abort;
                  break;
                case RGBA_5551:
                  r = *temp++;
                  g = *temp++;
                  b = *temp++;
                  a = *temp;
                  Make5551 (r, g, b, a, buf);
                  xpos++;

                  if (fwrite (buf, 1, 2, f) != 2)
                    goto abort;
                  break;
                }
            }

          for (int j = 0; j < padding; j++)
            {
              if (EOF == putc (0, f))
                goto abort;
            }

          cur_progress++;
          if ((cur_progress % 5) == 0)
            gimp_progress_update ((gdouble) cur_progress /
                                  (gdouble) max_progress);

          xpos = 0;
        }
    }
  else
    {
      /* now it gets more difficult */
      if (! use_run_length_encoding || bpp == 1)
        {
          /* uncompressed 1,4 and 8 bit */

          thiswidth = (width * bpp + 7) / 8;
          padding = bytes_per_row - thiswidth;

          for (ypos = height - 1; ypos >= 0; ypos--) /* for each row */
            {
              for (xpos = 0; xpos < width;)  /* for each _byte_ */
                {
                  v = 0;
                  for (i = 1;
                       (i <= (8 / bpp)) && (xpos < width);
                       i++, xpos++)  /* for each pixel */
                    {
                      temp = src + (ypos * rowstride) + (xpos * channels);
                      if (channels > 1 && *(temp+1) == 0) *temp = 0x0;
                      v=v | ((guchar) *temp << (8 - (i * bpp)));
                    }

                  if (fwrite (&v, 1, 1, f) != 1)
                    goto abort;
                }

              for (int j = 0; j < padding; j++)
                {
                  if (EOF == putc (0, f))
                    goto abort;
                }

              xpos = 0;

              cur_progress++;
              if ((cur_progress % 5) == 0)
                gimp_progress_update ((gdouble) cur_progress /
                                        (gdouble) max_progress);
            }
        }
      else
        {
          /* Save RLE encoded file, quite difficult */

          length = 0;

          row    = g_new (guchar, width / (8 / bpp) + 10);
          chains = g_new (guchar, width / (8 / bpp) + 10);

          for (ypos = height - 1; ypos >= 0; ypos--)
            {
              /* each row separately */
              j = 0;

              /* first copy the pixels to a buffer, making one byte
               * from two 4bit pixels
               */

              for (xpos = 0; xpos < width;)
                {
                  v = 0;

                  for (i = 1;
                       (i <= (8 / bpp)) && (xpos < width);
                       i++, xpos++)
                    {
                      /* for each pixel */

                      temp = src + (ypos * rowstride) + (xpos * channels);
                      if (channels > 1 && *(temp+1) == 0) *temp = 0x0;
                      v = v | ((guchar) * temp << (8 - (i * bpp)));
                    }

                  row[j++] = v;
                }

              breite = width / (8 / bpp);
              if (width % (8 / bpp))
                breite++;

              /* then check for strings of equal bytes */
              for (i = 0; i < breite; i += j)
                {
                  j = 0;

                  while ((i + j < breite) &&
                         (j < (255 / (8 / bpp))) &&
                         (row[i + j] == row[i]))
                    j++;

                  chains[i] = j;
                }

              /* then write the strings and the other pixels to the file */
              for (i = 0; i < breite;)
                {
                  if (chains[i] < 3)
                    {
                      /* strings of different pixels ... */

                      j = 0;

                      while ((i + j < breite) &&
                             (j < (255 / (8 / bpp))) &&
                             (chains[i + j] < 3))
                        j += chains[i + j];

                      /* this can only happen if j jumps over the end
                       * with a 2 in chains[i+j]
                       */

                      if (j > (255 / (8 / bpp)))
                        j -= 2;

                      /* 00 01 and 00 02 are reserved */
                      if (j > 2)
                        {
                          n = j * (8 / bpp);
                          if (n + i * (8 / bpp) > width)
                            n--;

                          if (EOF == putc (0, f) || EOF == putc (n, f))
                            goto abort;

                          length += 2;

                          if (fwrite (&row[i], 1, j, f) != j)
                            goto abort;

                          length += j;
                          if ((j) % 2)
                            {
                              if (EOF == putc (0, f))
                                goto abort;
                              length++;
                            }
                        }
                      else
                        {
                          for (k = i; k < i + j; k++)
                            {
                              n = (8 / bpp);
                              if (n + i * (8 / bpp) > width)
                                n--;

                              if (EOF == putc (n, f) || EOF == putc (row[k], f))
                                goto abort;
                              length += 2;
                            }
                        }

                      i += j;
                    }
                  else
                    {
                      /* strings of equal pixels */

                      n = chains[i] * (8 / bpp);
                      if (n + i * (8 / bpp) > width)
                        n--;

                      if (EOF == putc (n, f) || EOF == putc (row[i], f))
                        goto abort;

                      i += chains[i];
                      length += 2;
                    }
                }

              if (EOF == putc (0, f) || EOF == putc (0, f))  /* End of row */
                goto abort;
              length += 2;

              cur_progress++;
              if ((cur_progress % 5) == 0)
                gimp_progress_update ((gdouble) cur_progress /
                                      (gdouble) max_progress);
            }

          if (fseek (f, -2, SEEK_CUR))                  /* Overwrite last End of row ... */
            goto abort;
          if (EOF == putc (0, f) || EOF == putc (1, f))   /* ... with End of file */
            goto abort;

          if (fseek (f, 0x22, SEEK_SET))                /* Write length of image */
            goto abort;
          uint32buf = GUINT32_TO_LE (length);
          if (fwrite (&uint32buf, 4, 1, f) != 1)
            goto abort;

          if (fseek (f, 0x02, SEEK_SET))                /* Write length of file */
            goto abort;
          length += (0x36 + MapSize + mask_info_size + color_space_size);
          uint32buf = GUINT32_TO_LE (length);
          if (fwrite (&uint32buf, 4, 1, f) != 1)
            goto abort;

          g_free (chains);
          g_free (row);
        }
    }

  gimp_progress_update (1.0);
  return TRUE;

abort:
  g_free (chains);
  g_free (row);

  return FALSE;
}

static gboolean
format_sensitive_callback (GObject *config,
                           gpointer data)
{
  gint value;
  gint channels = GPOINTER_TO_INT (data);

  value = gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
                                               "rgb-format");

  switch (value)
    {
    case RGBA_5551:
    case RGBA_8888:
      return channels == 4;

    default:
      return TRUE;
    };
}

static void
config_notify (GObject          *config,
               const GParamSpec *pspec,
               gpointer          data)
{
  gint    channels = GPOINTER_TO_INT (data);
  RGBMode format;

  format = gimp_procedure_config_get_choice_id (GIMP_PROCEDURE_CONFIG (config),
                                                "rgb-format");

  switch (format)
    {
    case RGBA_5551:
    case RGBA_8888:
      if (channels != 4)
        {
          g_signal_handlers_block_by_func (config, config_notify, data);

          if (format == RGBA_5551)
            g_object_set (config, "rgb-format", "rgb-565", NULL);
          else if (format == RGBA_8888)
            g_object_set (config, "rgb-format", "rgb-888", NULL);

          g_signal_handlers_unblock_by_func (config, config_notify, data);
        }
      break;

    default:
      break;
    };
}

static gboolean
save_dialog (GimpProcedure *procedure,
             GObject       *config,
             GimpImage     *image,
             gint           channels,
             gint           bpp)
{
  GtkWidget *dialog;
  GtkWidget *toggle;
  GtkWidget *vbox;
  GtkWidget *combo;
  gboolean   is_format_sensitive;
  gboolean   run;

  dialog = gimp_export_procedure_dialog_new (GIMP_EXPORT_PROCEDURE (procedure),
                                             GIMP_PROCEDURE_CONFIG (config),
                                             image);

  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

  /* Run-Length Encoded */
  gimp_procedure_dialog_set_sensitive (GIMP_PROCEDURE_DIALOG (dialog),
                                       "use-rle",
                                       ! (channels > 1 || bpp == 1),
                                       NULL, NULL, FALSE);

  /* Compatibility Options */
  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "color-space-title", _("Compatibility"),
                                   FALSE, FALSE);
  toggle = gimp_procedure_dialog_get_widget (GIMP_PROCEDURE_DIALOG (dialog),
                                             "write-color-space",
                                             GTK_TYPE_CHECK_BUTTON);
  gimp_help_set_help_data (toggle,
                           _("Some applications can not read BMP images that "
                             "include color space information. GIMP writes "
                             "color space information by default. Disabling "
                             "this option will cause GIMP to not write color "
                             "space information to the file."),
                           NULL);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "color-space-frame", "color-space-title",
                                    FALSE, "write-color-space");

  /* RGB Encoding Options */
  combo = gimp_procedure_dialog_get_widget (GIMP_PROCEDURE_DIALOG (dialog),
                                            "rgb-format", G_TYPE_NONE);
  g_object_set (combo, "margin", 12, NULL);

  /* Determine if RGB Format combo should be initially sensitive */
  is_format_sensitive = format_sensitive_callback (config,
                                                   GINT_TO_POINTER (channels));
  gimp_procedure_dialog_set_sensitive (GIMP_PROCEDURE_DIALOG (dialog),
                                       "rgb-format",
                                       is_format_sensitive,
                                       NULL, NULL, FALSE);

  gimp_procedure_dialog_set_sensitive (GIMP_PROCEDURE_DIALOG (dialog),
                                       "rgb-format",
                                       (channels >= 3),
                                       NULL, NULL, FALSE);

  /* Formatting the dialog */
  vbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                         "bmp-save-vbox",
                                         "use-rle",
                                         "color-space-frame",
                                         "rgb-format",
                                         NULL);
  gtk_box_set_spacing (GTK_BOX (vbox), 12);

  gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
                              "bmp-save-vbox",
                              NULL);

  gtk_widget_show (dialog);

  g_signal_connect (config, "notify::rgb-format",
                    G_CALLBACK (config_notify),
                    GINT_TO_POINTER (channels));

  run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));

  g_signal_handlers_disconnect_by_func (config,
                                        config_notify,
                                        GINT_TO_POINTER (channels));

  gtk_widget_destroy (dialog);

  return run;
}

Messung
CHZG
839510092

¤ Dauer der Verarbeitung: 0.8 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.