Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  ico-load.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
 *
 * GIMP Plug-in for Windows Icon files.
 * Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
 *
 * 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 <png.h>

/* #define ICO_DBG */

#include "ico.h"
#include "ico-load.h"

#include "libgimp/stdplugins-intl.h"


#define A_VAL(p) ((guchar *)(p))[3]
#define R_VAL(p) ((guchar *)(p))[2]
#define G_VAL(p) ((guchar *)(p))[1]
#define B_VAL(p) ((guchar *)(p))[0]

#define A_VAL_GIMP(p) ((guchar *)(p))[3]
#define R_VAL_GIMP(p) ((guchar *)(p))[0]
#define G_VAL_GIMP(p) ((guchar *)(p))[1]
#define B_VAL_GIMP(p) ((guchar *)(p))[2]


static gint       ico_read_int8  (FILE        *fp,
                                  guint8      *data,
                                  gint         count);
static gint       ico_read_int16 (FILE        *fp,
                                  guint16     *data,
                                  gint         count);
static gint       ico_read_int32 (FILE        *fp,
                                  guint32     *data,
                                  gint         count);

static gint
ico_read_int32 (FILE    *fp,
                guint32 *data,
                gint     count)
{
  gint i, total;

  total = count;
  if (count > 0)
    {
      if (ico_read_int8 (fp, (guint8 *) data, count * 4) != (count * 4))
        return FALSE;

      for (i = 0; i < count; i++)
        data[i] = GUINT32_FROM_LE (data[i]);
    }

  return total * 4;
}


static gint
ico_read_int16 (FILE    *fp,
                guint16 *data,
                gint     count)
{
  gint i, total;

  total = count;
  if (count > 0)
    {
      if (ico_read_int8 (fp, (guint8 *) data, count * 2) != (count * 2))
        return FALSE;

      for (i = 0; i < count; i++)
        data[i] = GUINT16_FROM_LE (data[i]);
    }

  return total * 2;
}


static gint
ico_read_int8 (FILE   *fp,
               guint8 *data,
               gint    count)
{
  gint total;
  gint bytes;

  total = count;
  while (count > 0)
    {
      bytes = fread ((gchar *) data, sizeof (gchar), count, fp);
      if (bytes != count) /* something bad happened */
        return -1;

      count -= bytes;
      data += bytes;
    }

  return total;
}


static IcoFileHeader
ico_read_init (FILE *fp)
{
  IcoFileHeader header;

  /* read and check file header */
  if (! ico_read_int16 (fp, &header.reserved, 1)      ||
      ! ico_read_int16 (fp, &header.resource_type, 1) ||
      ! ico_read_int16 (fp, &header.icon_count, 1)    ||
      header.reserved != 0 ||
      (header.resource_type != 1 && header.resource_type != 2))
    {
      header.icon_count = 0;
      return header;
    }

  return header;
}


static gboolean
ico_read_size (FILE        *fp,
               gint32       file_offset,
               IcoLoadInfo *info)
{
  png_structp png_ptr;
  png_infop   info_ptr;
  png_uint_32 w, h;
  gint32      bpp;
  gint32      color_type;
  guint32     magic;

  if (fseek (fp, info->offset + file_offset, SEEK_SET) < 0)
    return FALSE;

  ico_read_int32 (fp, &magic, 1);

  if (magic == ICO_PNG_MAGIC)
    {
      png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL,
                                        NULL);
      if (! png_ptr)
        return FALSE;

      info_ptr = png_create_info_struct (png_ptr);
      if (! info_ptr)
        {
          png_destroy_read_struct (&png_ptr, NULL, NULL);
          return FALSE;
        }

      if (setjmp (png_jmpbuf (png_ptr)))
        {
          png_destroy_read_struct (&png_ptr, NULL, NULL);
          return FALSE;
        }
      png_init_io (png_ptr, fp);
      png_set_sig_bytes (png_ptr, 4);
      png_read_info (png_ptr, info_ptr);
      png_get_IHDR (png_ptr, info_ptr, &w, &h, &bpp, &color_type,
                    NULL, NULL, NULL);
      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
      info->width = w;
      info->height = h;
      D(("ico_read_size: PNG: %ix%i\n", info->width, info->height));
      return TRUE;
    }
  else if (magic == 40)
    {
      if (ico_read_int32 (fp, &info->width, 1) &&
          ico_read_int32 (fp, &info->height, 1))
        {
          info->height /= 2;
          D(("ico_read_size: ICO: %ix%i\n", info->width, info->height));
          return TRUE;
        }
      else
        {
          info->width = 0;
          info->height = 0;
          return FALSE;
        }
    }
  return FALSE;
}

static IcoLoadInfo*
ico_read_info (FILE    *fp,
               gint     icon_count,
               gint32   file_offset,
               GError **error)
{
  gint            i;
  IcoFileEntry   *entries;
  IcoLoadInfo    *info;

  /* read icon entries */
  entries = g_new (IcoFileEntry, icon_count);
  if (fread (entries, sizeof (IcoFileEntry), icon_count, fp) <= 0)
    {
      g_set_error (error, G_FILE_ERROR, 0,
                   _("Could not read '%lu' bytes"),
                   (long unsigned int) sizeof (IcoFileEntry));
      g_free (entries);
      return NULL;
    }

  info = g_new (IcoLoadInfo, icon_count);
  for (i = 0; i < icon_count; i++)
    {
      info[i].width  = entries[i].width;
      info[i].height = entries[i].height;
      info[i].planes = entries[i].planes;
      info[i].bpp    = GUINT16_FROM_LE (entries[i].bpp);
      info[i].size   = GUINT32_FROM_LE (entries[i].size);
      info[i].offset = GUINT32_FROM_LE (entries[i].offset);

      if (info[i].width == 0 || info[i].height == 0)
        {
          ico_read_size (fp, file_offset, info + i);
        }

      D(("ico_read_info: %ix%i (%i bits, size: %i, offset: %i)\n",
         info[i].width, info[i].height, info[i].bpp,
         info[i].size, info[i].offset));

      if (info[i].width == 0 || info[i].height == 0)
        {
          g_set_error (error, G_FILE_ERROR, 0,
                       _("Icon #%d has zero width or height"), i);
          g_free (info);
          g_free (entries);
          return NULL;
        }
    }

  g_free (entries);

  return info;
}

static gboolean
ico_read_png (FILE    *fp,
              guint32  header,
              guchar  *buf,
              gint     maxsize,
              gint    *width,
              gint    *height)
{
  png_structp   png_ptr;
  png_infop     info;
  png_uint_32   w;
  png_uint_32   h;
  gint32        bit_depth;
  gint32        color_type;
  guint32     **rows;
  gint          i;

  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (! png_ptr)
    return FALSE;
  info = png_create_info_struct (png_ptr);
  if (! info)
    {
      png_destroy_read_struct (&png_ptr, NULL, NULL);
      return FALSE;
    }

  if (setjmp (png_jmpbuf (png_ptr)))
    {
      png_destroy_read_struct (&png_ptr, &info, NULL);
      return FALSE;
    }

  png_init_io (png_ptr, fp);
  png_set_sig_bytes (png_ptr, 4);
  png_read_info (png_ptr, info);
  png_get_IHDR (png_ptr, info, &w, &h, &bit_depth, &color_type,
                NULL, NULL, NULL);
  /* Check for overflow */
  if ((w * h * 4) < w       ||
      (w * h * 4) < h       ||
      (w * h * 4) < (w * h) ||
      (w * h * 4) > maxsize)
    {
      png_destroy_read_struct (&png_ptr, &info, NULL);
      return FALSE;
    }
  D(("ico_read_png: %ix%i, %i bits, %i type\n", (gint)w, (gint)h,
     bit_depth, color_type));
  switch (color_type)
    {
    case PNG_COLOR_TYPE_GRAY:
      png_set_expand_gray_1_2_4_to_8 (png_ptr);
      if (bit_depth == 16)
        png_set_strip_16 (png_ptr);
      png_set_gray_to_rgb (png_ptr);
      png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
      break;
    case PNG_COLOR_TYPE_GRAY_ALPHA:
      png_set_expand_gray_1_2_4_to_8 (png_ptr);
      if (bit_depth == 16)
        png_set_strip_16 (png_ptr);
      png_set_gray_to_rgb (png_ptr);
      break;
    case PNG_COLOR_TYPE_PALETTE:
      png_set_palette_to_rgb (png_ptr);
      if (png_get_valid (png_ptr, info, PNG_INFO_tRNS))
        png_set_tRNS_to_alpha (png_ptr);
      else
        png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
      break;
    case PNG_COLOR_TYPE_RGB:
      if (bit_depth == 16)
        png_set_strip_16 (png_ptr);
      png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
      break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
      if (bit_depth == 16)
        png_set_strip_16 (png_ptr);
      break;
    }

  *width = w;
  *height = h;
  rows = g_new (guint32*, h);
  rows[0] = (guint32*) buf;
  for (i = 1; i < h; i++)
    rows[i] = rows[i-1] + w;
  png_read_image (png_ptr, (png_bytepp) rows);
  png_destroy_read_struct (&png_ptr, &info, NULL);
  g_free (rows);
  return TRUE;
}

gint
ico_get_bit_from_data (const guint8 *data,
                       gint          line_width,
                       gint          bit)
{
  gint line;
  gint width32;
  gint offset;
  gint result;

  /* width per line in multiples of 32 bits */
  width32 = (line_width % 32 == 0 ? line_width/32 : line_width/32 + 1);
  line = bit / line_width;
  offset = bit % line_width;

  result = (data[line * width32 * 4 + offset/8] & (1 << (7 - (offset % 8))));

  return (result ? 1 : 0);
}


gint
ico_get_nibble_from_data (const guint8 *data,
                          gint          line_width,
                          gint          nibble)
{
  gint line;
  gint width32;
  gint offset;
  gint result;

  /* width per line in multiples of 32 bits */
  width32 = (line_width % 8 == 0 ? line_width/8 : line_width/8 + 1);
  line = nibble / line_width;
  offset = nibble % line_width;

  result =
    (data[line * width32 * 4 + offset/2] & (0x0F << (4 * (1 - offset % 2))));

  if (offset % 2 == 0)
    result = result >> 4;

  return result;
}

gint
ico_get_byte_from_data (const guint8 *data,
                        gint          line_width,
                        gint          byte)
{
  gint line;
  gint width32;
  gint offset;

  /* width per line in multiples of 32 bits */
  width32 = (line_width % 4 == 0 ? line_width / 4 : line_width / 4 + 1);
  line = byte / line_width;
  offset = byte % line_width;

  return data[line * width32 * 4 + offset];
}

static gboolean
ico_read_icon (FILE    *fp,
               guint32  header_size,
               guchar  *buf,
               gint     maxsize,
               gint    *width,
               gint    *height)
{
  IcoFileDataHeader   data;
  gsize               data_size;
  gint                length;
  gint                x, y, w, h;
  guchar             *xor_map, *and_map;
  guint32            *palette;
  guint32            *dest_vec;
  guchar             *row;
  gint                rowstride;

  palette = NULL;

  data.header_size = header_size;
  if (ico_read_int32 (fp, &data.width, 1)   != 4     ||
      ico_read_int32 (fp, &data.height, 1)  != 4     ||
      ico_read_int16 (fp, &data.planes, 1)  != 2     ||
      ico_read_int16 (fp, &data.bpp, 1) != 2         ||
      ico_read_int32 (fp, &data.compression, 1) != 4 ||
      ico_read_int32 (fp, &data.image_size, 1) != 4  ||
      ico_read_int32 (fp, &data.x_res, 1) != 4       ||
      ico_read_int32 (fp, &data.y_res, 1) != 4       ||
      ico_read_int32 (fp, &data.used_clrs, 1) != 4   ||
      ico_read_int32 (fp, &data.important_clrs, 1) != 4)
    {
      D(("skipping image: invalid header\n"));
      return FALSE;
    }

  D(("  header size %i, "
     "w %i, h %i, planes %i, size %i, bpp %i, used %i, imp %i.\n",
     data.header_size, data.width, data.height,
     data.planes, data.image_size, data.bpp,
     data.used_clrs, data.important_clrs));

  if (data.planes      != 1 ||
      data.compression != 0)
    {
      D(("skipping image: invalid header\n"));
      return FALSE;
    }

  if (data.bpp != 1  &&
      data.bpp != 4  &&
      data.bpp != 8  &&
      data.bpp != 24 &&
      data.bpp != 32)
    {
      D(("skipping image: invalid depth: %i\n", data.bpp));
      return FALSE;
    }

  if (! g_size_checked_mul (&data_size, data.width, data.height) ||
      ! g_size_checked_mul (&data_size, data_size, 2)            ||
      data_size > maxsize)
    {
      D(("skipping image: too large\n"));
      return FALSE;
    }

  w = data.width;
  h = data.height / 2;

  if (data.bpp <= 8)
    {
      if (data.used_clrs == 0)
        data.used_clrs = (1 << data.bpp);

      D(("  allocating a %i-slot palette for %i bpp.\n",
         data.used_clrs, data.bpp));

      palette = g_new0 (guint32, data.used_clrs);
      if (ico_read_int8 (fp,
                         (guint8 *) palette,
                         data.used_clrs * 4) != (data.used_clrs * 4))
        {
          D(("skipping image: too large\n"));
          return FALSE;
        }

    }

  xor_map = ico_alloc_map (w, h, data.bpp, &length);
  if (ico_read_int8 (fp, xor_map, length) != length)
    {
      D(("skipping image: too large\n"));
      return FALSE;
    }
  D(("  length of xor_map: %i\n", length));

  /* Read in and_map. It's padded out to 32 bits per line: */
  and_map = ico_alloc_map (w, h, 1, &length);
  if (ico_read_int8 (fp, and_map, length) != length)
    {
      D(("skipping image: too large\n"));
      return FALSE;
    }
  D(("  length of and_map: %i\n", length));

  dest_vec = (guint32 *) buf;
  switch (data.bpp)
    {
    case 1:
      for (y = 0; y < h; y++)
        for (x = 0; x < w; x++)
          {
            guint32 color = palette[ico_get_bit_from_data (xor_map,
                                                           w, y * w + x)];
            guint32 *dest = dest_vec + (h - 1 - y) * w + x;

            R_VAL_GIMP (dest) = R_VAL (&color);
            G_VAL_GIMP (dest) = G_VAL (&color);
            B_VAL_GIMP (dest) = B_VAL (&color);

            if (ico_get_bit_from_data (and_map, w, y * w + x))
              A_VAL_GIMP (dest) = 0;
            else
              A_VAL_GIMP (dest) = 255;
          }
      break;

    case 4:
      for (y = 0; y < h; y++)
        for (x = 0; x < w; x++)
          {
            guint32 color = palette[ico_get_nibble_from_data (xor_map,
                                                              w, y * w + x)];
            guint32 *dest = dest_vec + (h - 1 - y) * w + x;

            R_VAL_GIMP (dest) = R_VAL (&color);
            G_VAL_GIMP (dest) = G_VAL (&color);
            B_VAL_GIMP (dest) = B_VAL (&color);

            if (ico_get_bit_from_data (and_map, w, y * w + x))
              A_VAL_GIMP (dest) = 0;
            else
              A_VAL_GIMP (dest) = 255;
          }
      break;

    case 8:
      for (y = 0; y < h; y++)
        for (x = 0; x < w; x++)
          {
            guint32 color = palette[ico_get_byte_from_data (xor_map,
                                                            w, y * w + x)];
            guint32 *dest = dest_vec + (h - 1 - y) * w + x;

            R_VAL_GIMP (dest) = R_VAL (&color);
            G_VAL_GIMP (dest) = G_VAL (&color);
            B_VAL_GIMP (dest) = B_VAL (&color);

            if (ico_get_bit_from_data (and_map, w, y * w + x))
              A_VAL_GIMP (dest) = 0;
            else
              A_VAL_GIMP (dest) = 255;
          }
      break;

    default:
      {
        gint bytespp = data.bpp / 8;

        rowstride = ico_rowstride (w, data.bpp);

        for (y = 0; y < h; y++)
          {
            row = xor_map + rowstride * y;

            for (x = 0; x < w; x++)
              {
                guint32 *dest = dest_vec + (h - 1 - y) * w + x;

                B_VAL_GIMP (dest) = row[0];
                G_VAL_GIMP (dest) = row[1];
                R_VAL_GIMP (dest) = row[2];

                if (data.bpp < 32)
                  {
                    if (ico_get_bit_from_data (and_map, w, y * w + x))
                      A_VAL_GIMP (dest) = 0;
                    else
                      A_VAL_GIMP (dest) = 255;
                  }
                else
                  {
                    A_VAL_GIMP (dest) = row[3];
                  }

                row += bytespp;
              }
          }
      }
    }
  if (palette)
    g_free (palette);
  g_free (xor_map);
  g_free (and_map);
  *width = w;
  *height = h;
  return TRUE;
}

static GimpLayer *
ico_load_layer (FILE        *fp,
                GimpImage   *image,
                gint32       icon_num,
                guchar      *buf,
                gint         maxsize,
                gint32       file_offset,
                gchar       *layer_prefix,
                IcoLoadInfo *info)
{
  gint        width, height;
  GimpLayer  *layer;
  guint32     first_bytes;
  GeglBuffer *buffer;

  if (fseek (fp, info->offset + file_offset, SEEK_SET) < 0 ||
      ! ico_read_int32 (fp, &first_bytes, 1))
    return NULL;

  if (first_bytes == ICO_PNG_MAGIC)
    {
      if (!ico_read_png (fp, first_bytes, buf, maxsize, &width, &height))
        return NULL;
    }
  else if (first_bytes == 40)
    {
      if (!ico_read_icon (fp, first_bytes, buf, maxsize, &width, &height))
        return NULL;
    }
  else
    {
      return NULL;
    }

  /* read successfully. add to image */
  layer = gimp_layer_new (image, layer_prefix, width, height,
                          GIMP_RGBA_IMAGE, 100,
                          gimp_image_get_default_new_layer_mode (image));
  gimp_image_insert_layer (image, layer, NULL, icon_num);

  buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));

  gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
                   NULL, buf, GEGL_AUTO_ROWSTRIDE);

  g_object_unref (buffer);

  return layer;
}


GimpImage *
ico_load_image (GFile        *file,
                gint32       *file_offset,
                gint          frame_num,
                GError      **error)
{
  FILE          *fp;
  IcoFileHeader  header;
  IcoLoadInfo   *info;
  gint           max_width, max_height;
  gint           i;
  GimpImage     *image;
  guchar        *buf;
  guint          icon_count;
  gint           maxsize;
  gchar         *str;

  if (! file_offset)
    gimp_progress_init_printf (_("Opening '%s'"),
                               gimp_file_get_utf8_name (file));

  fp = g_fopen (g_file_peek_path (file), "rb");

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

  if (file_offset)
    fseek (fp, *file_offset, SEEK_SET);

  header = ico_read_init (fp);
  icon_count = header.icon_count;
  if (!icon_count)
    {
      fclose (fp);
      return NULL;
    }

  info = ico_read_info (fp, icon_count, file_offset ? *file_offset : 0, error);
  if (! info)
    {
      fclose (fp);
      return NULL;
    }

  /* find width and height of image */
  max_width = 0;
  max_height = 0;
  for (i = 0; i < icon_count; i++)
    {
      if (info[i].width > max_width)
        max_width = info[i].width;
      if (info[i].height > max_height)
        max_height = info[i].height;
    }
  if (max_width <= 0 || max_height <= 0)
    {
      g_free (info);
      fclose (fp);
      return NULL;
    }
  D(("image size: %ix%i\n", max_width, max_height));

  image = gimp_image_new (max_width, max_height, GIMP_RGB);

  maxsize = max_width * max_height * 4;
  buf     = g_try_new (guchar, maxsize);
  if (! buf)
    {
      g_free (info);
      fclose (fp);
      return NULL;
    }

  for (i = 0; i < icon_count; i++)
    {
      GimpLayer *layer;
      gchar     *layer_prefix;
      gchar     *icon_metadata;

      if (info[i].bpp)
        icon_metadata = g_strdup_printf ("(%dx%d, %dbpp)", info[i].width,
                                         info[i].height, info[i].bpp);
      else
        icon_metadata = g_strdup_printf ("(%dx%d)", info[i].width,
                                         info[i].height);

      if (frame_num > -1)
        {
          layer_prefix = g_strdup_printf ("Cursor %s Frame #%i", icon_metadata,
                                          frame_num);
        }
      else
        {
          if (header.resource_type == 1)
            layer_prefix = g_strdup_printf ("Icon #%i %s ", i + 1,
                                            icon_metadata);
          else
            layer_prefix = g_strdup_printf ("Cursor #%i %s ", i + 1,
                                            icon_metadata);
        }

      layer = ico_load_layer (fp, image, i + 1, buf, maxsize,
                              file_offset ? *file_offset : 0,
                              layer_prefix, info + i);
      g_free (icon_metadata);
      g_free (layer_prefix);

      /* Save CUR hot spot information */
      if (header.resource_type == 2)
        {
          GimpParasite *parasite;

          str = g_strdup_printf ("%d %d", info[i].planes, info[i].bpp);
          parasite = gimp_parasite_new ("cur-hot-spot",
                                        GIMP_PARASITE_PERSISTENT,
                                        strlen (str) + 1, (gpointer) str);
          g_free (str);
          gimp_item_attach_parasite (GIMP_ITEM (layer), parasite);
          gimp_parasite_free (parasite);
        }
    }

  if (file_offset)
    *file_offset = ftell (fp);

  g_free (buf);
  g_free (info);
  fclose (fp);

  /* Don't update progress here if .ani file */
  if (! file_offset)
    gimp_progress_update (1.0);

  return image;
}

/* Ported from James Huang's ani.c code, under the GPL license, version 3
 * or any later version of the license */

GimpImage *
ani_load_image (GFile   *file,
                gboolean load_thumb,
                gint    *width,
                gint    *height,
                GError **error)
{
  FILE         *fp;
  GimpImage    *image = NULL;
  GimpParasite *parasite;
  gchar         id[4];
  guint32       size;
  guint8        padding;
  gint32        file_offset;
  guint         frame = 1;
  AniFileHeader header;
  gchar        *inam  = NULL;
  gchar        *iart  = NULL;
  gchar        *str;

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

  fp = g_fopen (g_file_peek_path (file), "rb");

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

  while (fread (id, 1, 4, fp) == 4)
    {
      if (memcmp (id, "RIFF", 4) == 0 )
        {
          fread (&size, sizeof (size), 1, fp);
        }
      else if (memcmp (id, "anih", 4) == 0)
        {
          fread (&size, sizeof (size), 1, fp);
          fread (&header, sizeof (header), 1, fp);
        }
      else if (memcmp (id, "rate", 4) == 0)
        {
          fread (&size, sizeof (size), 1, fp);
          fseek (fp, size, SEEK_CUR);
        }
      else if (memcmp (id, "seq ", 4) == 0)
        {
          fread (&size, sizeof (size), 1, fp);
          fseek (fp, size, SEEK_CUR);
        }
      else if (memcmp (id, "LIST", 4) == 0)
        {
          fread (&size, sizeof (size), 1, fp);
        }
      else if (memcmp (id, "INAM", 4) == 0)
        {
          gint n_read = -1;

          fread (&size, sizeof (size), 1, fp);
          if (size > 0)
            {
              if (inam)
                g_free (inam);

              inam = g_try_new0 (gchar, size + 1);
              if (inam == NULL)
                {
                  fclose (fp);
                  g_set_error (error, G_FILE_ERROR,
                               g_file_error_from_errno (errno),
                               _("Invalid ANI metadata"));
                  return NULL;
                }

              n_read = fread (inam, sizeof (gchar), size, fp);
              inam[size] = '\0';
            }

          if (n_read < 1 || (inam && ! g_utf8_validate (inam, -1, NULL)))
            {
              fclose (fp);
              g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                           _("Invalid ANI metadata"));
              return NULL;
            }

          /* Metadata length must be even. If data itself is odd,
           * then an extra 0x00 is added for padding. We read in
           * that extra byte to keep loading properly.
           * See discussion in #8562.
           */

          if (size % 2 != 0)
            fread (&padding, sizeof (padding), 1, fp);
        }
      else if (memcmp (id, "IART", 4) == 0)
        {
          gint n_read = -1;

          fread (&size, sizeof (size), 1, fp);
          if (size > 0)
            {
              if (iart)
                g_free (iart);

              iart = g_try_new0 (gchar, size + 1);
              if (iart == NULL)
                {
                  fclose (fp);
                  g_set_error (error, G_FILE_ERROR,
                               g_file_error_from_errno (errno),
                               _("Invalid ANI metadata"));
                  return NULL;
                }

              n_read = fread (iart, sizeof (gchar), size, fp);
              iart[size] = '\0';
            }

          if (n_read < 1 || (iart && ! g_utf8_validate (iart, -1, NULL)))
            {
              fclose (fp);
              g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
                           _("Invalid ANI metadata"));
              return NULL;
            }

          if (size % 2 != 0)
            fread (&padding, sizeof (padding), 1, fp);
        }
      else if (memcmp (id, "icon", 4) == 0)
        {
          fread (&size, sizeof (size), 1, fp);
          file_offset = ftell (fp);
          if (load_thumb)
            {
              image = ico_load_thumbnail_image (file, width, height, file_offset, error);
              break;
            }
           else
             {
               if (! image)
                 {
                   image = ico_load_image (file, &file_offset, 1, error);
                 }
               else
                 {
                   GimpImage    *temp_image = NULL;
                   GimpLayer   **layers;
                   GimpLayer    *new_layer;

                   temp_image = ico_load_image (file, &file_offset, frame + 1,
                                                error);
                   layers = gimp_image_get_layers (temp_image);
                   if (layers)
                     {
                       for (gint i = 0; layers[i]; i++)
                         {
                           new_layer = gimp_layer_new_from_drawable (GIMP_DRAWABLE (layers[i]),
                                                                     image);
                           gimp_image_insert_layer (image, new_layer, NULL, frame);
                           frame++;
                         }
                       g_free (layers);
                     }
                   gimp_image_delete (temp_image);
                 }

               /* Update position after reading icon data */
               fseek (fp, file_offset, SEEK_SET);
               if (header.frames > 0)
                 gimp_progress_update ((gdouble) frame /
                                       (gdouble) header.frames);
             }
        }
    }
  fclose (fp);

  /* Saving header metadata */
  str = g_strdup_printf ("%d", header.jif_rate);
  parasite = gimp_parasite_new ("ani-header",
                                GIMP_PARASITE_PERSISTENT,
                                strlen (str) + 1, (gpointer) str);
  g_free (str);
  gimp_image_attach_parasite (image, parasite);
  gimp_parasite_free (parasite);

  /* Saving INFO block */
  if (inam && strlen (inam) > 0)
    {
      str = g_strdup_printf ("%s", inam);
      parasite = gimp_parasite_new ("ani-info-inam",
                                    GIMP_PARASITE_PERSISTENT,
                                    strlen (str) + 1, (gpointer) str);
      g_free (str);
      g_free (inam);
      gimp_image_attach_parasite (image, parasite);
      gimp_parasite_free (parasite);
    }

  if (iart && strlen (iart) > 0)
    {
      str = g_strdup_printf ("%s", iart);
      parasite = gimp_parasite_new ("ani-info-iart",
                                    GIMP_PARASITE_PERSISTENT,
                                    strlen (str) + 1, (gpointer) str);
      g_free (str);
      g_free (iart);
      gimp_image_attach_parasite (image, parasite);
      gimp_parasite_free (parasite);
    }

  gimp_progress_update (1.0);

  return image;
}

GimpImage *
ico_load_thumbnail_image (GFile   *file,
                          gint    *width,
                          gint    *height,
                          gint32   file_offset,
                          GError **error)
{
  FILE          *fp;
  IcoLoadInfo   *info;
  IcoFileHeader  header;
  GimpImage     *image;
  gint           max_width;
  gint           max_height;
  gint           w     = 0;
  gint           h     = 0;
  gint           bpp   = 0;
  gint           match = 0;
  gint           i, icon_count;
  guchar        *buf;

  gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
                             gimp_file_get_utf8_name (file));

  fp = g_fopen (g_file_peek_path (file), "rb");

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

  if (file_offset > 0)
    fseek (fp, file_offset, SEEK_SET);

  header = ico_read_init (fp);
  icon_count = header.icon_count;
  if (! icon_count)
    {
      fclose (fp);
      return NULL;
    }

  D(("*** %s: Microsoft icon file, containing %i icon(s)\n",
     gimp_file_get_utf8_name (file), icon_count));

  info = ico_read_info (fp, icon_count, file_offset, error);
  if (! info)
    {
      fclose (fp);
      return NULL;
    }

  max_width  = 0;
  max_height = 0;

  /* Do a quick scan of the icons in the file to find the best match */
  for (i = 0; i < icon_count; i++)
    {
      if (info[i].width > max_width)
        max_width = info[i].width;
      if (info[i].height > max_height)
        max_height = info[i].height;

      if ((info[i].width  > w && w < *width) ||
          (info[i].height > h && h < *height))
        {
          w = info[i].width;
          h = info[i].height;
          bpp = info[i].bpp;

          match = i;
        }
      else if (w == info[i].width  &&
               h == info[i].height &&
               info[i].bpp > bpp)
        {
          /* better quality */
          bpp = info[i].bpp;
          match = i;
        }
    }

  if (w <= 0 || h <= 0)
    return NULL;

  image = gimp_image_new (w, h, GIMP_RGB);
  buf = g_new (guchar, w*h*4);
  ico_load_layer (fp, image, match, buf, w*h*4, file_offset,
                  "Thumbnail", info + match);
  g_free (buf);

  *width  = max_width;
  *height = max_height;

  D(("*** thumbnail successfully loaded.\n\n"));

  gimp_progress_update (1.0);

  g_free (info);
  fclose (fp);

  return image;
}

Messung
CHZG
83979792

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104857
#Domains=438736