Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  file-icns-load.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
 *
 * file-icns-load.c
 * Copyright (C) 2004 Brion Vibber <brion@pobox.com>
 *
 * 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 ICNS_DBG */

#include "file-icns.h"
#include "file-icns-data.h"
#include "file-icns-load.h"

#include "libgimp/stdplugins-intl.h"

IcnsResource * resource_load     (FILE         *file);

IcnsResource * resource_find     (GList        *resources,
                                  gchar        *type,
                                  gint          max);

gboolean       resource_get_next (IcnsResource *icns,
                                  IcnsResource *res);

void           icns_slurp        (guchar       *dest,
                                  IconType     *icontype,
                                  IcnsResource *icns,
                                  IcnsResource *mask);

gboolean       icns_decompress   (guchar       *dest,
                                  IconType     *icontype,
                                  gint          n_channels,
                                  IcnsResource *image,
                                  IcnsResource *mask);

void           icns_attach_image (GimpImage    *image,
                                  IconType     *icontype,
                                  IcnsResource *icns,
                                  IcnsResource *mask,
                                  gboolean      isOSX);

GimpImage *    icns_load         (IcnsResource *icns,
                                  GFile        *file);

/* Ported from Brion Vibber's icnsload.c code, under the GPL license, version 3
 * or any later version of the license */

IcnsResource *
resource_load (FILE *file)
{
  IcnsResource *res = NULL;

  if (file)
    {
      IcnsResourceHeader header;

      if (1 == fread (&header, sizeof (IcnsResourceHeader), 1, file))
        {
          gchar   type[5];
          guint32 size;

          strncpy (type, header.type, 4);
          type[4] = '\0';
          size = GUINT32_FROM_BE (header.size);

          if (! strncmp (header.type, "icns", 4) && size > sizeof (IcnsResourceHeader))
            {
              res = (IcnsResource *) g_new (guchar, sizeof (IcnsResource) + size);
              strncpy (res->type, header.type, 4);
              res->type[4] = '\0';
              res->size = size;
              res->cursor = sizeof (IcnsResourceHeader);
              res->data = (guchar *) res + sizeof (IcnsResource);
              fseek (file, 0, SEEK_SET);

              if (size != fread (res->data, 1, res->size, file))
                {
                  g_message ("** expected %d bytes\n", size);
                  g_free (res);
                  res = NULL;
                }
            }
        }
      else
        {
          g_message (("** couldn't read icns header.\n"));
        }
    }
  else
    {
      g_message (("** couldn't open file.\n"));
    }
  return res;
}

IcnsResource *
resource_find (GList        *resources,
               gchar        *type,
               gint          max)
{
  GList *list;

  for (list = resources; list; list = g_list_next (list))
    {
      IcnsResource *res = list->data;

      if (! strncmp (res->type, type, 4))
        return res;
    }
  return NULL;
}

gboolean
resource_get_next (IcnsResource *icns,
                   IcnsResource *res)
{
  IcnsResourceHeader *header;

  if (icns->size - icns->cursor < sizeof (IcnsResourceHeader))
    return FALSE;

  header = (IcnsResourceHeader *) &(icns->data[icns->cursor]);
  strncpy (res->type, header->type, 4);
  res->size   = GUINT32_FROM_BE (header->size);
  res->cursor = sizeof (IcnsResourceHeader);
  res->data   = &(icns->data[icns->cursor]);

  if (! res->size)
    return FALSE;

  icns->cursor += res->size;
  if (icns->cursor > icns->size)
    {
      gchar typestring[5];

      fourcc_get_string (icns->type, typestring);
      g_message ("icns resource_get_next: resource too big! type '%s', size %u\n",
                 typestring, icns->size);

      return FALSE;
    }
  return TRUE;
}

GimpImage *
icns_load (IcnsResource *icns,
           GFile        *file)
{
  GList        *resources;
  IcnsResource *resource;
  guint         nResources;
  gfloat        current_resources = 0;
  GimpImage    *image;

  resources = NULL;
  resource  = g_new (IcnsResource, 1);

  /* Largest .icns icon is 1024 x 1024 */
  image = gimp_image_new (1024, 1024, GIMP_RGB);

  nResources = 0;
  while (resource_get_next (icns, resource))
    {
      resources = g_list_append (resources, resource);

      resource = g_new (IcnsResource, 1);
    }

  for (gint i = 0; iconTypes[i].type; i++)
    {
      IcnsResource *icns;
      IcnsResource *mask = NULL;

      if ((icns = resource_find (resources, iconTypes[i].type, nResources)))
        {
          if (! iconTypes[i].isModern && iconTypes[i].mask)
            mask = resource_find (resources, iconTypes[i].mask, nResources);

          icns_attach_image (image, &iconTypes[i], icns, mask, iconTypes[i].isModern);

          gimp_progress_update (current_resources++ / nResources);
        }
    }

  gimp_image_resize_to_layers (image);
  g_list_free_full (resources, g_free);
  g_free (resource);
  return image;
}

void
icns_slurp (guchar       *dest,
            IconType     *icontype,
            IcnsResource *icns,
            IcnsResource *mask)
{
  guint  out;
  guint  max;
  guchar bucket = 0;
  guchar bit;
  guint  index;

  max = icontype->width * icontype->height;
  icns->cursor = sizeof (IcnsResourceHeader);

  switch (icontype->bits)
    {
      case 1:
        for (out = 0; out < max; out++)
          {
            if (out % 8 == 0)
              bucket = icns->data[icns->cursor++];

            bit = (bucket & 0x80) ? 0 : 255;
            bucket = bucket << 1;
            dest[out * 4]     = bit;
            dest[out * 4 + 1] = bit;
            dest[out * 4 + 2] = bit;
            if (! mask)
              dest[out * 4 + 3] = 255;
          }
        break;
      case 4:
        for (out = 0; out < max; out++)
          {
            if (out % 2 == 0)
              bucket = icns->data[icns->cursor++];

            index = 3 * (bucket & 0xf0) >> 4;
            bucket = bucket << 4;
            dest[out * 4]     = icns_colormap_4[index];
            dest[out * 4 + 1] = icns_colormap_4[index + 1];
            dest[out * 4 + 2] = icns_colormap_4[index + 2];
          }
        break;
      case 8:
        for (out = 0; out < max; out++)
          {
            index = 3 * icns->data[icns->cursor++];
            dest[out * 4]     = icns_colormap_8[index];
            dest[out * 4 + 1] = icns_colormap_8[index + 1];
            dest[out * 4 + 2] = icns_colormap_8[index + 2];
            dest[out * 4 + 3] = 255;
          }
        break;
      case 32:
        for (out = 0; out < max; out++)
          {
            dest[out * 4]     = icns->data[icns->cursor++];
            dest[out * 4 + 1] = icns->data[icns->cursor++];
            dest[out * 4 + 2] = icns->data[icns->cursor++];
            /* Throw away alpha, use the mask */
            icns->cursor++;
            if (mask)
              dest[out * 4 + 3] = icns->data[mask->cursor++];
            else
              dest[out * 4 + 3] = 255;
          }
        break;
      }

    /* Now for the mask */
    if (mask && icontype->bits != 32)
      {
        mask->cursor = sizeof (IcnsResourceHeader) + icontype->width * icontype->height / 8;
        for (out = 0; out < max; out++)
          {
            if (out % 8 == 0)
              bucket = mask->data[mask->cursor++];

            bit = (bucket & 0x80) ? 255 : 0;
            bucket = bucket << 1;
            dest[out * 4 + 3] = bit;
          }
      }
}

gboolean
icns_decompress (guchar       *dest,
                 IconType     *icontype,
                 gint          n_channels,
                 IcnsResource *image,
                 IcnsResource *mask)
{
  guint  max;
  guint  channel;
  guint  out;
  guchar run;
  guchar val;

  max = icontype->width * icontype->height;
  memset (dest, 255, max * 4);

  /* For some reason there seem to be 4 null bytes at the start of an it32. */
  if (! strncmp (icontype->type, "it32", 4))
    image->cursor += 4;

  for (channel = 0; channel < n_channels; channel++)
    {
      out = 0;
      while (out < max)
        {
          run = image->data[image->cursor++];

          if (run & 0x80)
            {
              /* Compressed */
              if (image->cursor >= image->size)
                {
                  g_message ("Corrupt icon: compressed run overflows input size.");
                  return FALSE;
                }

              val = image->data[image->cursor++];

              for (run -= 125; run > 0; run--)
                {
                  if (out >= max)
                    {
                      g_message ("Corrupt icon? compressed run overflows output size.");
                      return FALSE;
                    }
                  dest[out++ * 4 + channel] = val;
                }
            }
          else
            {
              /* Uncompressed */
              for (run += 1; run > 0; run--)
                {
                  if (image->cursor >= image->size)
                    {
                      g_message ("Corrupt icon: uncompressed run overflows input size.");
                      return FALSE;
                    }
                  if (out >= max)
                    {
                      g_message ("Corrupt icon: uncompressed run overflows output size.");
                      return FALSE;
                    }
                  dest[out++ * 4 + channel] = image->data[image->cursor++];
                }
            }
        }
    }

  /* If we have four channels, this is compressed ARGB data and
     we need to rotate the channels */

  if (n_channels == 4)
    {
      gint pixel_max = max * 4;

      for (gint i = 0; i < pixel_max; i += 4)
        {
          guchar alpha = dest[i];

          for (gint j = 0; j < 3; j++)
            dest[i + j] = dest[i + j + 1];

          dest[i + 3] = alpha;
        }
    }
  else if (mask)
    {
      gchar typestring[5];
      fourcc_get_string (mask->type, typestring);

      for (out = 0; out < max; out++)
        dest[out * 4 + 3] = mask->data[mask->cursor++];
    }
  return TRUE;
}

void
icns_attach_image (GimpImage    *image,
                   IconType     *icontype,
                   IcnsResource *icns,
                   IcnsResource *mask,
                   gboolean      isOSX)
{
  gchar           layer_name[5];
  guchar         *dest;
  GimpLayer      *layer;
  GeglBuffer     *buffer;
  guint           row;
  guint           expected_size;
  gboolean        layer_loaded = FALSE;

  strncpy (layer_name, icontype->type, 4);
  layer_name[4] = '\0';

  row = 4 * icontype->width;
  dest = g_malloc (row * icontype->height);

  expected_size =
    (icontype->width * icontype->height * icontype->bits) / 8;

  if (icns == mask)
    expected_size *= 2;

  expected_size += sizeof (IcnsResourceHeader);

  if (isOSX)
    {
      gchar           image_type[5];
      GimpImage      *temp_image;
      GFile          *temp_file      = NULL;
      FILE           *fp;
      GimpValueArray *return_vals    = NULL;
      GimpLayer     **layers;
      GimpLayer      *new_layer;
      gchar          *temp_file_type = NULL;
      gchar          *procedure_name = NULL;

      temp_image = gimp_image_new (icontype->width, icontype->height,
                                   gimp_image_get_base_type (image));

      strncpy (image_type, (gchar *) icns->data + 8, 4);
      image_type[4] = '\0';

      /* PNG */
      if (! strncmp (image_type, "\x89\x50\x4E\x47", 4))
        {
          temp_file_type = "png";
          procedure_name = "file-png-load";
        }
      /* JPEG 2000 */
      else if (! strncmp (image_type, "\x0CjP", 3))
        {
          temp_file_type = "jp2";
          procedure_name = "file-jp2-load";
        }
      /* ARGB (compressed */
      else if (! strncmp (image_type, "ARGB", 4))
        {
          icns->cursor += 4;
          icns_decompress (dest, icontype, 4, icns, FALSE);
        }

      if (temp_file_type && procedure_name)
        {
          GimpProcedure *procedure;

          temp_file = gimp_temp_file (temp_file_type);
          fp = g_fopen (g_file_peek_path (temp_file), "wb");

          if (! fp)
            {
              g_message (_("Error trying to open temporary %s file '%s' "
                         "for icns loading: %s"),
                         temp_file_type,
                         gimp_file_get_utf8_name (temp_file),
                         g_strerror (errno));
              return;
            }

          fwrite (icns->data + 8, sizeof (guchar), icns->size - 8, fp);
          fclose (fp);

          procedure   = gimp_pdb_lookup_procedure (gimp_get_pdb (), procedure_name);
          return_vals = gimp_procedure_run (procedure,
                                            "run-mode", GIMP_RUN_NONINTERACTIVE,
                                            "file",     temp_file,
                                            NULL);
        }

      if (temp_image && return_vals)
        {
          temp_image = g_value_get_object (gimp_value_array_index (return_vals, 1));

          layers = gimp_image_get_layers (temp_image);
          new_layer = gimp_layer_new_from_drawable (GIMP_DRAWABLE (layers[0]), image);
          gimp_item_set_name (GIMP_ITEM (new_layer), layer_name);
          gimp_image_insert_layer (image, new_layer, NULL, 0);

          layer_loaded = TRUE;

          /* Use the first color profile we encounter */
          if (! gimp_image_get_color_profile (image) &&
              gimp_image_get_color_profile (temp_image))
            {
              GimpColorProfile *profile;

              profile = gimp_image_get_color_profile (temp_image);
              gimp_image_set_color_profile (image, profile);

              g_object_unref (profile);
            }

          g_file_delete (temp_file, NULL, NULL);
          g_object_unref (temp_file);
          g_free (layers);
        }
      g_clear_pointer (&return_vals, gimp_value_array_unref);
    }
  else
    {
      if (icontype->bits != 32 || expected_size == icns->size)
        icns_slurp (dest, icontype, icns, mask);
      else
        icns_decompress (dest, icontype, 3, icns, mask);
    }

  if (! layer_loaded)
    {
      layer = gimp_layer_new (image, layer_name, icontype->width, icontype->height,
                              GIMP_RGBA_IMAGE, 100,
                              gimp_image_get_default_new_layer_mode (image));

      buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));

      gegl_buffer_set (buffer,
                       GEGL_RECTANGLE (0, 0, icontype->width, icontype->height),
                       0, NULL,
                       dest, GEGL_AUTO_ROWSTRIDE);

      gimp_image_insert_layer (image, layer, NULL, 0);

      g_object_unref (buffer);
    }

  g_free (dest);
}

GimpImage *
icns_load_image (GFile        *file,
                 gint32       *file_offset,
                 GError      **error)
{
  FILE          *fp;
  IcnsResource  *icns;
  GimpImage     *image;

  gegl_init (NULL, NULL);

  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;
    }

  icns = resource_load (fp);

  fclose (fp);

  if (! icns)
    {
      g_message ("Invalid or corrupt icns resource file.");
      return NULL;
    }

  image = icns_load (icns, file);

  g_free (icns);

  gimp_progress_update (1.0);

  return image;
}

GimpImage *
icns_load_thumbnail_image (GFile   *file,
                           gint    *width,
                           gint    *height,
                           gint32   file_offset,
                           GError **error)
{
  gint          w          = 0;
  gint          target_w   = *width;
  FILE         *fp;
  GimpImage    *image      = NULL;
  IcnsResource *icns;
  GList        *resources;
  IcnsResource *resource;
  IcnsResource *mask       = NULL;
  guint         i;
  gint          match      = -1;
  guint         nResources = 0;

  gegl_init (NULL, NULL);

  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;
    }

  icns = resource_load (fp);
  fclose (fp);

  if (! icns)
    {
      g_message ("Invalid or corrupt icns resource file.");
      return NULL;
    }

  image = gimp_image_new (1024, 1024, GIMP_RGB);

  resources = NULL;
  resource  = g_new (IcnsResource, 1);

  while (resource_get_next (icns, resource))
    {
      resources = g_list_append (resources, resource);

      resource = g_new (IcnsResource, 1);
    }

  *width  = 0;
  *height = 0;
  for (i = 0; iconTypes[i].type; i++)
    {
      if ((icns = resource_find (resources, iconTypes[i].type, nResources)))
        {
          if (iconTypes[i].width > w && iconTypes[i].width <= target_w)
            {
              w = iconTypes[i].width;
              match = i;
            }
        }
      *width  = MAX (*width, iconTypes[i].width);
      *height = MAX (*height, iconTypes[i].height);
    }

  if (match == -1)
    {
      /* We didn't find any icon with size smaller or equal to the target.
       * Settle with the smallest bigger icon instead.
       */

      for (i = 0; iconTypes[i].type; i++)
        {
          if ((icns = resource_find (resources, iconTypes[i].type, nResources)))
            {
              if (match == -1 || iconTypes[i].width < w)
                {
                  w = iconTypes[i].width;
                  match = i;
                }
            }
        }
    }

  if (match > -1)
    {
      icns = resource_find (resources, iconTypes[match].type, nResources);

      if (! iconTypes[match].isModern && iconTypes[i].mask)
        mask = resource_find (resources, iconTypes[match].mask, nResources);

      icns_attach_image (image, &iconTypes[match], icns, mask, iconTypes[match].isModern);

      gimp_image_resize_to_layers (image);
    }
  else
    {
      g_message ("Invalid or corrupt icns resource file.");
      return NULL;
    }

  g_list_free_full (resources, g_free);
  g_free (resource);

  gimp_progress_update (1.0);

  return image;
}

Messung
CHZG
81939790

¤ Dauer der Verarbeitung: 0.7 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=1104852
#Domains=417160