Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  gimpimagefile.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * gimpimagefile.c
 *
 * Copyright (C) 2001-2004  Sven Neumann <sven@gimp.org>
 *                          Michael Natterer <mitch@gimp.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 <string.h>

#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>

#include "libgimpbase/gimpbase.h"
#include "libgimpthumb/gimpthumb.h"

#include "core-types.h"

#include "config/gimpcoreconfig.h"

#include "gegl/gimp-babl.h"
#include "gegl/gimp-gegl-utils.h"

#include "gimp.h"
#include "gimpcontainer.h"
#include "gimpcontext.h"
#include "gimpimage.h"
#include "gimpimage-metadata.h"
#include "gimpimagefile.h"
#include "gimppickable.h"
#include "gimpprogress.h"

#include "file/file-open.h"

#include "gimp-intl.h"


enum
{
  INFO_CHANGED,
  LAST_SIGNAL
};


typedef struct _GimpImagefilePrivate GimpImagefilePrivate;

struct _GimpImagefilePrivate
{
  Gimp          *gimp;

  GFile         *file;
  GimpThumbnail *thumbnail;
  GIcon         *icon;
  GCancellable  *icon_cancellable;

  gchar         *description;
  gboolean       static_desc;

  gint           popup_size;
  gint           popup_width;
  gint           popup_height;
};

#define GET_PRIVATE(imagefile) ((GimpImagefilePrivate *) gimp_imagefile_get_instance_private ((GimpImagefile *) (imagefile)))


static void        gimp_imagefile_dispose          (GObject        *object);
static void        gimp_imagefile_finalize         (GObject        *object);

static void        gimp_imagefile_name_changed     (GimpObject     *object);

static gboolean    gimp_imagefile_get_popup_size   (GimpViewable  *viewable,
                                                    gint           width,
                                                    gint           height,
                                                    gboolean       dot_for_dot,
                                                    gint          *popup_width,
                                                    gint          *popup_height);
static GdkPixbuf * gimp_imagefile_get_new_pixbuf   (GimpViewable   *viewable,
                                                    GimpContext    *context,
                                                    gint            width,
                                                    gint            height,
                                                    GeglColor      *fg_color);
static gchar     * gimp_imagefile_get_description  (GimpViewable   *viewable,
                                                    gchar         **tooltip);

static void        gimp_imagefile_info_changed     (GimpImagefile  *imagefile);
static void        gimp_imagefile_notify_thumbnail (GimpImagefile  *imagefile,
                                                    GParamSpec     *pspec);

static void        gimp_imagefile_icon_callback    (GObject        *source_object,
                                                    GAsyncResult   *result,
                                                    gpointer        data);

static GdkPixbuf * gimp_imagefile_load_thumb       (GimpImagefile  *imagefile,
                                                    gint            width,
                                                    gint            height);
static gboolean    gimp_imagefile_save_thumb       (GimpImagefile  *imagefile,
                                                    GimpImage      *image,
                                                    gint            size,
                                                    gboolean        replace,
                                                    GError        **error);

static void     gimp_thumbnail_set_info_from_image (GimpThumbnail  *thumbnail,
                                                    const gchar    *mime_type,
                                                    GimpImage      *image);
static void     gimp_thumbnail_set_info            (GimpThumbnail  *thumbnail,
                                                    const gchar    *mime_type,
                                                    gint            width,
                                                    gint            height,
                                                    const Babl     *format,
                                                    gint            num_layers);


G_DEFINE_TYPE_WITH_PRIVATE (GimpImagefile, gimp_imagefile, GIMP_TYPE_VIEWABLE)

#define parent_class gimp_imagefile_parent_class

static guint gimp_imagefile_signals[LAST_SIGNAL] = { 0 };


static void
gimp_imagefile_class_init (GimpImagefileClass *klass)
{
  GObjectClass      *object_class      = G_OBJECT_CLASS (klass);
  GimpObjectClass   *gimp_object_class = GIMP_OBJECT_CLASS (klass);
  GimpViewableClass *viewable_class    = GIMP_VIEWABLE_CLASS (klass);
  gchar             *creator;

  gimp_imagefile_signals[INFO_CHANGED] =
    g_signal_new ("info-changed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GimpImagefileClass, info_changed),
                  NULL, NULL, NULL,
                  G_TYPE_NONE, 0);

  object_class->dispose               = gimp_imagefile_dispose;
  object_class->finalize              = gimp_imagefile_finalize;

  gimp_object_class->name_changed     = gimp_imagefile_name_changed;

  viewable_class->name_changed_signal = "info-changed";
  viewable_class->get_popup_size      = gimp_imagefile_get_popup_size;
  viewable_class->get_new_pixbuf      = gimp_imagefile_get_new_pixbuf;
  viewable_class->get_description     = gimp_imagefile_get_description;

  g_type_class_ref (GIMP_TYPE_IMAGE_TYPE);

  creator = g_strdup_printf ("gimp-%d.%d",
                             GIMP_MAJOR_VERSION, GIMP_MINOR_VERSION);

  gimp_thumb_init (creator, NULL);

  g_free (creator);
}

static void
gimp_imagefile_init (GimpImagefile *imagefile)
{
  GimpImagefilePrivate *private = GET_PRIVATE (imagefile);

  private->thumbnail = gimp_thumbnail_new ();

  g_signal_connect_object (private->thumbnail, "notify",
                           G_CALLBACK (gimp_imagefile_notify_thumbnail),
                           imagefile, G_CONNECT_SWAPPED);
}

static void
gimp_imagefile_dispose (GObject *object)
{
  GimpImagefilePrivate *private = GET_PRIVATE (object);

  if (private->icon_cancellable)
    {
      g_cancellable_cancel (private->icon_cancellable);
      g_clear_object (&private->icon_cancellable);
    }

  G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
gimp_imagefile_finalize (GObject *object)
{
  GimpImagefilePrivate *private = GET_PRIVATE (object);

  if (private->description)
    {
      if (! private->static_desc)
        g_free (private->description);

      private->description = NULL;
    }

  g_clear_object (&private->thumbnail);
  g_clear_object (&private->icon);
  g_clear_object (&private->file);

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
gimp_imagefile_name_changed (GimpObject *object)
{
  GimpImagefilePrivate *private = GET_PRIVATE (object);

  if (GIMP_OBJECT_CLASS (parent_class)->name_changed)
    GIMP_OBJECT_CLASS (parent_class)->name_changed (object);

  gimp_thumbnail_set_uri (private->thumbnail, gimp_object_get_name (object));

  g_clear_object (&private->file);

  if (gimp_object_get_name (object))
    private->file = g_file_new_for_uri (gimp_object_get_name (object));
}

static gboolean
gimp_imagefile_get_popup_size (GimpViewable *viewable,
                               gint          width,
                               gint          height,
                               gboolean      dot_for_dot,
                               gint         *popup_width,
                               gint         *popup_height)
{
  GimpImagefilePrivate *private = GET_PRIVATE (viewable);

  if (width  < private->popup_width ||
      height < private->popup_height)
    {
      *popup_width  = private->popup_width;
      *popup_height = private->popup_height;

      return TRUE;
    }

  return FALSE;
}

static GdkPixbuf *
gimp_imagefile_get_new_pixbuf (GimpViewable *viewable,
                               GimpContext  *context,
                               gint          width,
                               gint          height,
                               GeglColor    *fg_color G_GNUC_UNUSED)
{
  GimpImagefile *imagefile = GIMP_IMAGEFILE (viewable);

  if (! gimp_object_get_name (imagefile))
    return NULL;

  return gimp_imagefile_load_thumb (imagefile, width, height);
}

static gchar *
gimp_imagefile_get_description (GimpViewable   *viewable,
                                gchar         **tooltip)
{
  GimpImagefile        *imagefile = GIMP_IMAGEFILE (viewable);
  GimpImagefilePrivate *private   = GET_PRIVATE (imagefile);
  GimpThumbnail        *thumbnail = private->thumbnail;
  gchar                *basename;
  gint                  image_width;
  gint                  image_height;

  if (! private->file)
    return NULL;

  g_object_get (thumbnail,
                "image-width",  &image_width,
                "image-height", &image_height,
                NULL);

  if (tooltip)
    {
      const gchar *name;
      const gchar *desc;

      name = gimp_file_get_utf8_name (private->file);
      desc = gimp_imagefile_get_desc_string (imagefile);

      if (desc)
        *tooltip = g_strdup_printf ("%s\n%s", name, desc);
      else
        *tooltip = g_strdup (name);
    }

  basename = g_path_get_basename (gimp_file_get_utf8_name (private->file));

  if (image_width > 0 && image_height > 0)
    {
      gchar *tmp = basename;

      basename = g_strdup_printf ("%s (%d × %d)",
                                  tmp,
                                  image_width,
                                  image_height);
      g_free (tmp);
    }

  return basename;
}


/*  public functions  */

GimpImagefile *
gimp_imagefile_new (Gimp  *gimp,
                    GFile *file)
{
  GimpImagefile *imagefile;

  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
  g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);

  imagefile = g_object_new (GIMP_TYPE_IMAGEFILE, NULL);

  GET_PRIVATE (imagefile)->gimp = gimp;

  if (file)
    {
      gimp_object_take_name (GIMP_OBJECT (imagefile), g_file_get_uri (file));

      /* file member gets created by gimp_imagefile_name_changed() */
    }

  return imagefile;
}

GFile *
gimp_imagefile_get_file (GimpImagefile *imagefile)
{
  g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), NULL);

  return GET_PRIVATE (imagefile)->file;
}

void
gimp_imagefile_set_file (GimpImagefile *imagefile,
                         GFile         *file)
{
  g_return_if_fail (GIMP_IS_IMAGEFILE (imagefile));
  g_return_if_fail (file == NULL || G_IS_FILE (file));

  if (GET_PRIVATE (imagefile)->file != file)
    {
      gimp_object_take_name (GIMP_OBJECT (imagefile),
                             file ? g_file_get_uri (file) : NULL);
    }
}

GimpThumbnail *
gimp_imagefile_get_thumbnail (GimpImagefile *imagefile)
{
  g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), NULL);

  return GET_PRIVATE (imagefile)->thumbnail;
}

GIcon *
gimp_imagefile_get_gicon (GimpImagefile *imagefile)
{
  GimpImagefilePrivate *private;

  g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), NULL);

  private = GET_PRIVATE (imagefile);

  if (private->icon)
    return private->icon;

  if (private->file && ! private->icon_cancellable)
    {
      private->icon_cancellable = g_cancellable_new ();

      g_file_query_info_async (private->file, "standard::icon",
                               G_FILE_QUERY_INFO_NONE,
                               G_PRIORITY_DEFAULT,
                               private->icon_cancellable,
                               gimp_imagefile_icon_callback,
                               imagefile);
    }

  return NULL;
}

void
gimp_imagefile_set_mime_type (GimpImagefile *imagefile,
                              const gchar   *mime_type)
{
  g_return_if_fail (GIMP_IS_IMAGEFILE (imagefile));

  g_object_set (GET_PRIVATE (imagefile)->thumbnail,
                "image-mimetype", mime_type,
                NULL);
}

void
gimp_imagefile_update (GimpImagefile *imagefile)
{
  GimpImagefilePrivate *private;
  gchar                *uri;

  g_return_if_fail (GIMP_IS_IMAGEFILE (imagefile));

  private = GET_PRIVATE (imagefile);

  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (imagefile));

  g_object_get (private->thumbnail,
                "image-uri", &uri,
                NULL);

  if (uri)
    {
      GimpImagefile *documents_imagefile = (GimpImagefile *)
        gimp_container_get_child_by_name (private->gimp->documents, uri);

      if (documents_imagefile != imagefile &&
          GIMP_IS_IMAGEFILE (documents_imagefile))
        gimp_viewable_invalidate_preview (GIMP_VIEWABLE (documents_imagefile));

      g_free (uri);
    }
}

gboolean
gimp_imagefile_create_thumbnail (GimpImagefile  *imagefile,
                                 GimpContext    *context,
                                 GimpProgress   *progress,
                                 gint            size,
                                 gboolean        replace,
                                 GError        **error)
{
  GimpImagefilePrivate *private;
  GimpThumbnail        *thumbnail;
  GimpThumbState        image_state;

  g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), FALSE);
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE);
  g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  /* thumbnailing is disabled, we successfully did nothing */
  if (size < 1)
    return TRUE;

  private = GET_PRIVATE (imagefile);

  thumbnail = private->thumbnail;

  gimp_thumbnail_set_uri (thumbnail,
                          gimp_object_get_name (imagefile));

  image_state = gimp_thumbnail_peek_image (thumbnail);

  if (image_state == GIMP_THUMB_STATE_REMOTE ||
      image_state >= GIMP_THUMB_STATE_EXISTS)
    {
      GimpImage     *image;
      gboolean       success;
      gint           width      = 0;
      gint           height     = 0;
      const gchar   *mime_type  = NULL;
      const Babl    *format     = NULL;
      gint           num_layers = -1;

      /*  we only want to attempt thumbnailing on readable, regular files  */
      if (g_file_is_native (private->file))
        {
          GFileInfo *file_info;
          gboolean   regular;
          gboolean   readable;

          file_info = g_file_query_info (private->file,
                                         G_FILE_ATTRIBUTE_STANDARD_TYPE ","
                                         G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
                                         G_FILE_QUERY_INFO_NONE,
                                         NULL, NULL);

          regular  = (g_file_info_get_attribute_uint32 (file_info, G_FILE_ATTRIBUTE_STANDARD_TYPE) == G_FILE_TYPE_REGULAR);
          readable = g_file_info_get_attribute_boolean (file_info,
                                                        G_FILE_ATTRIBUTE_ACCESS_CAN_READ);

          g_object_unref (file_info);

          if (! (regular && readable))
            return TRUE;
        }

      g_object_ref (imagefile);

      image = file_open_thumbnail (private->gimp, context, progress,
                                   private->file, size,
                                   &mime_type, &width, &height,
                                   &format, &num_layers, error);

      if (image)
        {
          gimp_thumbnail_set_info (private->thumbnail,
                                   mime_type, width, height,
                                   format, num_layers);
        }
      else
        {
          GimpPDBStatusType  status;

          if (error && *error)
            {
              g_printerr ("Info: Thumbnail load procedure failed: %s\n"
                          "      Falling back to metadata or file load.\n",
                          (*error)->message);
              g_clear_error (error);
            }

          image = gimp_image_metadata_load_thumbnail (private->gimp, private->file, &width, &height, &format,&nbsp;error);
          if (image)
            {
              gimp_thumbnail_set_info (private->thumbnail,
                                       mime_type, width, height,
                                       format, 0);
            }
          else
            {
              if (error && *error)
                {
                  g_printerr ("Info: metadata load failed: %s\n"
                              "      Falling back to file load procedure.\n",
                              (*error)->message);
                  g_clear_error (error);
                }

              image = file_open_image (private->gimp, context, progress,
                                       private->file, size, size, TRUE,
                                       FALSE, NULL,
                                       GIMP_RUN_NONINTERACTIVE,
                                       NULL, &status, &mime_type, error);

              if (image)
                gimp_thumbnail_set_info_from_image (private->thumbnail,
                                                    mime_type, image);
            }
        }

      if (image)
        {
          success = gimp_imagefile_save_thumb (imagefile,
                                               image, size, replace,
                                               error);

          g_object_unref (image);
        }
      else
        {
          /* If the error object is already set (i.e. we have an error
           * message for why the thumbnail creation failed), this is the
           * error we want to return. Ignore any error from failed
           * thumbnail saving.
           */

          gimp_thumbnail_save_failure (thumbnail,
                                       "GIMP " GIMP_VERSION,
                                       error && *error ? NULL : error);
          gimp_imagefile_update (imagefile);
          success = FALSE;
        }

      g_object_unref (imagefile);

      if (! success)
        {
          g_object_set (thumbnail,
                        "thumb-state", GIMP_THUMB_STATE_FAILED,
                        NULL);
        }

      return success;
    }

  return TRUE;
}

/*  The weak version doesn't ref the imagefile but deals gracefully
 *  with an imagefile that is destroyed while the thumbnail is
 *  created. This allows one to use this function w/o the need to
 *  block the user interface.
 */

void
gimp_imagefile_create_thumbnail_weak (GimpImagefile *imagefile,
                                      GimpContext   *context,
                                      GimpProgress  *progress,
                                      gint           size,
                                      gboolean       replace)
{
  GimpImagefilePrivate *private;
  GimpImagefile        *local;

  g_return_if_fail (GIMP_IS_IMAGEFILE (imagefile));

  if (size < 1)
    return;

  private = GET_PRIVATE (imagefile);

  if (! private->file)
    return;

  local = gimp_imagefile_new (private->gimp, private->file);

  g_object_add_weak_pointer (G_OBJECT (imagefile), (gpointer) &imagefile);

  if (! gimp_imagefile_create_thumbnail (local, context, progress, size, replace,
                                         NULL))
    {
      /* The weak version works on a local copy so the thumbnail
       * status of the actual image is not properly updated in case of
       * creation failure, thus it would end up in a generic
       * GIMP_THUMB_STATE_NOT_FOUND, which is less informative.
       */

      g_object_set (private->thumbnail,
                    "thumb-state", GIMP_THUMB_STATE_FAILED,
                    NULL);
    }

  if (imagefile)
    {
      GFile *file = gimp_imagefile_get_file (imagefile);

      if (file && g_file_equal (file, gimp_imagefile_get_file (local)))
        {
          gimp_imagefile_update (imagefile);
        }

      g_object_remove_weak_pointer (G_OBJECT (imagefile),
                                    (gpointer) &imagefile);
    }

  g_object_unref (local);
}

gboolean
gimp_imagefile_check_thumbnail (GimpImagefile *imagefile)
{
  GimpImagefilePrivate *private;
  gint                  size;

  g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), FALSE);

  private = GET_PRIVATE (imagefile);

  size = private->gimp->config->thumbnail_size;

  if (size > 0)
    {
      GimpThumbState  state;

      state = gimp_thumbnail_check_thumb (private->thumbnail, size);

      return (state == GIMP_THUMB_STATE_OK);
    }

  return TRUE;
}

gboolean
gimp_imagefile_save_thumbnail (GimpImagefile  *imagefile,
                               const gchar    *mime_type,
                               GimpImage      *image,
                               GError        **error)
{
  GimpImagefilePrivate *private;
  gint                  size;
  gboolean              success = TRUE;

  g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), FALSE);
  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  private = GET_PRIVATE (imagefile);

  size = private->gimp->config->thumbnail_size;

  if (size > 0)
    {
      gimp_thumbnail_set_info_from_image (private->thumbnail,
                                          mime_type, image);

      success = gimp_imagefile_save_thumb (imagefile,
                                           image, size, FALSE,
                                           error);
    }

  return success;
}


/*  private functions  */

static void
gimp_imagefile_info_changed (GimpImagefile *imagefile)
{
  GimpImagefilePrivate *private = GET_PRIVATE (imagefile);

  if (private->description)
    {
      if (! private->static_desc)
        g_free (private->description);

      private->description = NULL;
    }

  g_clear_object (&private->icon);

  g_signal_emit (imagefile, gimp_imagefile_signals[INFO_CHANGED], 0);
}

static void
gimp_imagefile_notify_thumbnail (GimpImagefile *imagefile,
                                 GParamSpec    *pspec)
{
  if (strcmp (pspec->name, "image-state") == 0 ||
      strcmp (pspec->name, "thumb-state") == 0)
    {
      gimp_imagefile_info_changed (imagefile);
    }
}

static void
gimp_imagefile_icon_callback (GObject      *source_object,
                              GAsyncResult *result,
                              gpointer      data)
{
  GimpImagefile        *imagefile;
  GimpImagefilePrivate *private;
  GFile                *file  = G_FILE (source_object);
  GError               *error = NULL;
  GFileInfo            *file_info;

  file_info = g_file_query_info_finish (file, result, &error);

  if (error)
    {
      /* we were cancelled from dispose() and the imagefile is
       * long gone, bail out
       */

      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        {
          g_clear_error (&error);
          return;
        }

#ifdef GIMP_UNSTABLE
      g_printerr ("%s: %s\n", G_STRFUNC, error->message);
#endif

      g_clear_error (&error);
    }

  imagefile = GIMP_IMAGEFILE (data);
  private   = GET_PRIVATE (imagefile);

  if (file_info)
    {
      private->icon = g_object_ref (G_ICON (g_file_info_get_attribute_object (file_info, G_FILE_ATTRIBUTE_STANDARD_ICON)));
      g_object_unref (file_info);
    }

  g_clear_object (&private->icon_cancellable);

  if (private->icon)
    gimp_viewable_invalidate_preview (GIMP_VIEWABLE (imagefile));
}

const gchar *
gimp_imagefile_get_desc_string (GimpImagefile *imagefile)
{
  GimpImagefilePrivate *private;
  GimpThumbnail        *thumbnail;
  GimpThumbState        image_state;
  GimpThumbState        thumb_state;
  gint                  image_width;
  gint                  image_height;
  gchar                *image_uri;
  gchar                *image_type;
  gint64                image_filesize;
  gint                  image_num_layers;
  gint                  image_not_found_errno;

  g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), NULL);

  private = GET_PRIVATE (imagefile);

  if (private->description)
    return (const gchar *) private->description;

  thumbnail = private->thumbnail;

  g_object_get (thumbnail,
                "image-state",           &image_state,
                "thumb-state",           &thumb_state,
                "image-width",           &image_width,
                "image-height",          &image_height,
                "image-uri",             &image_uri,
                "image-type",            &image_type,
                "image-filesize",        &image_filesize,
                "image-num-layers",      &image_num_layers,
                "image-not-found-errno", &image_not_found_errno,
                NULL);

  switch (image_state)
    {
    case GIMP_THUMB_STATE_UNKNOWN:
      private->description = NULL;
      private->static_desc = TRUE;
      break;

    case GIMP_THUMB_STATE_FOLDER:
      private->description = (gchar *) _("Folder");
      private->static_desc = TRUE;
      break;

    case GIMP_THUMB_STATE_SPECIAL:
      private->description = (gchar *) _("Special File");
      private->static_desc = TRUE;
      break;

    case GIMP_THUMB_STATE_NOT_FOUND:
      private->description =
        (gchar *) g_strerror (image_not_found_errno);
      private->static_desc = TRUE;
      break;

    default:
      {
        GString *str = g_string_new (NULL);

        if (image_state == GIMP_THUMB_STATE_REMOTE)
          {
            g_string_append (str, _("Remote File"));
          }

        if (image_filesize > 0)
          {
            gchar *size = g_format_size (image_filesize);

            if (str->len > 0)
              g_string_append_c (str, '\n');

            g_string_append (str, size);
            g_free (size);
          }

        switch (thumb_state)
          {
          case GIMP_THUMB_STATE_NOT_FOUND:
            if (str->len > 0)
              g_string_append_c (str, '\n');
            g_string_append (str, _("Click to create preview"));
            break;

          case GIMP_THUMB_STATE_EXISTS:
            if (str->len > 0)
              g_string_append_c (str, '\n');
            g_string_append (str, _("Loading preview..."));
            break;

          case GIMP_THUMB_STATE_OLD:
            if (str->len > 0)
              g_string_append_c (str, '\n');
            g_string_append (str, _("Preview is out of date"));
            break;

          case GIMP_THUMB_STATE_FAILED:
            if (str->len > 0)
              g_string_append_c (str, '\n');
            g_string_append (str, _("Cannot create preview"));
            break;

          case GIMP_THUMB_STATE_OK:
            {
              if (image_state == GIMP_THUMB_STATE_REMOTE)
                {
                  if (str->len > 0)
                    g_string_append_c (str, '\n');

                  g_string_append (str, _("(Preview may be out of date)"));
                }

              if (image_width > 0 && image_height > 0)
                {
                  if (str->len > 0)
                    g_string_append_c (str, '\n');

                  g_string_append_printf (str,
                                          ngettext ("%d × %d pixel",
                                                    "%d × %d pixels",
                                                    image_height),
                                          image_width,
                                          image_height);
                }

              if (image_type)
                {
                  if (str->len > 0)
                    g_string_append_c (str, '\n');

                  g_string_append (str, gettext (image_type));
                }

              if (image_num_layers > 0)
                {
                  if (image_type)
                    g_string_append_len (str, ", ", 2);
                  else if (str->len > 0)
                    g_string_append_c (str, '\n');

                  g_string_append_printf (str,
                                          ngettext ("%d layer",
                                                    "%d layers",
                                                    image_num_layers),
                                          image_num_layers);
                }
            }
            break;

          default:
            break;
          }

        private->description = g_string_free (str, FALSE);
        private->static_desc = FALSE;
      }
    }

  return (const gchar *) private->description;
}

static GdkPixbuf *
gimp_imagefile_load_thumb (GimpImagefile *imagefile,
                           gint           width,
                           gint           height)
{
  GimpImagefilePrivate *private   = GET_PRIVATE (imagefile);
  GimpThumbnail        *thumbnail = private->thumbnail;
  GimpThumbState        image_state;
  gchar                *image_uri;
  gint                  image_width;
  gint                  image_height;
  GdkPixbuf            *pixbuf = NULL;
  GError               *error  = NULL;
  gint                  size;
  gint                  preview_width;
  gint                  preview_height;

  g_object_get (thumbnail,
                "image-state",  &image_state,
                "image-uri",    &image_uri,
                "image-width",  &image_width,
                "image-height", &image_height,
                NULL);

  /*  use the size remembered below if a pixbuf of the remembered
   *  dimensions is requested
   */

  if (width  == private->popup_width &&
      height == private->popup_height)
    {
      size = private->popup_size;
    }
  else
    {
      size = MAX (width, height);
    }

  if (gimp_thumbnail_peek_thumb (thumbnail, size) < GIMP_THUMB_STATE_EXISTS)
    return NULL;

  if (image_state == GIMP_THUMB_STATE_NOT_FOUND)
    return NULL;

  pixbuf = gimp_thumbnail_load_thumb (thumbnail, size, &error);

  if (! pixbuf)
    {
      if (error)
        {
          GimpThumbSize  thumb_size = size;
          gchar         *thumb_filename;

          thumb_filename = gimp_thumb_find_thumb (image_uri, &thumb_size);

          gimp_message (private->gimp, NULL, GIMP_MESSAGE_ERROR,
                        _("Could not open thumbnail '%s': %s"),
                        thumb_filename, error->message);
          g_clear_error (&error);

          if (thumb_filename)
            g_free (thumb_filename);
        }

      return NULL;
    }

  /*  remember the actual dimensions of the returned pixbuf, and the
   *  size used to request it, so we can later use that size to get a
   *  popup.
   */

  private->popup_size   = size;
  private->popup_width  = gdk_pixbuf_get_width  (pixbuf);
  private->popup_height = gdk_pixbuf_get_height (pixbuf);

  gimp_viewable_calc_preview_size (private->popup_width,
                                   private->popup_height,
                                   width,
                                   height,
                                   TRUE, 1.0, 1.0,
                                   &preview_width,
                                   &preview_height,
                                   NULL);

  if (preview_width  != private->popup_width ||
      preview_height != private->popup_height)
    {
      GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf,
                                                   preview_width,
                                                   preview_height,
                                                   GDK_INTERP_BILINEAR);
      g_object_unref (pixbuf);
      pixbuf = scaled;
    }

  if (gdk_pixbuf_get_n_channels (pixbuf) != 3)
    {
      GdkPixbuf *tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
                                       preview_width, preview_height);

      gdk_pixbuf_composite_color (pixbuf, tmp,
                                  0, 0, preview_width, preview_height,
                                  0.0, 0.0, 1.0, 1.0,
                                  GDK_INTERP_NEAREST, 255,
                                  0, 0, GIMP_CHECK_SIZE_SM,
                                  0x66666666, 0x99999999);

      g_object_unref (pixbuf);
      pixbuf = tmp;
    }

  return pixbuf;
}

static gboolean
gimp_imagefile_save_thumb (GimpImagefile  *imagefile,
                           GimpImage      *image,
                           gint            size,
                           gboolean        replace,
                           GError        **error)
{
  GimpImagefilePrivate *private   = GET_PRIVATE (imagefile);
  GimpThumbnail        *thumbnail = private->thumbnail;
  GdkPixbuf            *pixbuf;
  gint                  width, height;
  gboolean              success = FALSE;

  if (size < 1)
    return TRUE;

  if (gimp_image_get_width  (image) <= size &&
      gimp_image_get_height (image) <= size)
    {
      width  = gimp_image_get_width  (image);
      height = gimp_image_get_height (image);

      size = MAX (width, height);
    }
  else
    {
      if (gimp_image_get_width (image) < gimp_image_get_height (image))
        {
          height = size;
          width  = MAX (1, (size * gimp_image_get_width (image) /
                            gimp_image_get_height (image)));
        }
      else
        {
          width  = size;
          height = MAX (1, (size * gimp_image_get_height (image) /
                            gimp_image_get_width (image)));
        }
    }

  /*  we need the projection constructed NOW, not some time later  */
  gimp_pickable_flush (GIMP_PICKABLE (image));

  pixbuf = gimp_viewable_get_new_pixbuf (GIMP_VIEWABLE (image),
                                         /* random context, unused */
                                         gimp_get_user_context (image->gimp),
                                         width, height, NULL);

  /*  when layer previews are disabled, we won't get a pixbuf  */
  if (! pixbuf)
    return TRUE;

  success = gimp_thumbnail_save_thumb (thumbnail,
                                       pixbuf,
                                       "GIMP " GIMP_VERSION,
                                       error);

  g_object_unref (pixbuf);

  if (success)
    {
      if (replace)
        gimp_thumbnail_delete_others (thumbnail, size);
      else
        gimp_thumbnail_delete_failure (thumbnail);

      gimp_imagefile_update (imagefile);
    }

  return success;
}

static void
gimp_thumbnail_set_info_from_image (GimpThumbnail *thumbnail,
                                    const gchar   *mime_type,
                                    GimpImage     *image)
{
  const Babl *format;

  /*  peek the thumbnail to make sure that mtime and filesize are set  */
  gimp_thumbnail_peek_image (thumbnail);

  format = gimp_image_get_layer_format (image,
                                        gimp_image_has_alpha (image));

  g_object_set (thumbnail,
                "image-mimetype",   mime_type,
                "image-width",      gimp_image_get_width  (image),
                "image-height",     gimp_image_get_height (image),
                "image-type",       gimp_babl_format_get_description (format),
                "image-num-layers", gimp_image_get_n_layers (image),
                NULL);
}

/**
 * gimp_thumbnail_set_info:
 * @thumbnail: #GimpThumbnail object
 * @mime_type:  MIME type of the image associated with this thumbnail
 * @width:      width of the image associated with this thumbnail
 * @height:     height of the image associated with this thumbnail
 * @format:     format of the image (or NULL if the type is not known)
 * @num_layers: number of layers in the image
 *              (or -1 if the number of layers is not known)
 *
 * Set information about the image associated with the @thumbnail object.
 */

static void
gimp_thumbnail_set_info (GimpThumbnail *thumbnail,
                         const gchar   *mime_type,
                         gint           width,
                         gint           height,
                         const Babl    *format,
                         gint           num_layers)
{
  /*  peek the thumbnail to make sure that mtime and filesize are set  */
  gimp_thumbnail_peek_image (thumbnail);

  g_object_set (thumbnail,
                "image-mimetype", mime_type,
                "image-width",    width,
                "image-height",   height,
                NULL);

  if (format)
    g_object_set (thumbnail,
                  "image-type", gimp_babl_format_get_description (format),
                  NULL);

  if (num_layers != -1)
    g_object_set (thumbnail,
                  "image-num-layers", num_layers,
                  NULL);
}

Messung
CHZG
811009893

¤ Dauer der Verarbeitung: 0.7 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104856
#Domains=417315