mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-10-06 01:12:40 +02:00
As discussed with NikcDC, this will be useful, for instance for the SVG export to know the mime type of the linked file. If not PNG, JPG or SVG, we may want to output a small warning that some viewers may not be able to read such files, since the SVG spec makes the support of these 3 formats only as mandatory.
749 lines
22 KiB
C
749 lines
22 KiB
C
/* GIMP - The GNU Image Manipulation Program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* GimpLink
|
|
* Copyright (C) 2019 Jehan
|
|
*
|
|
* 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 <cairo.h>
|
|
#include <gegl.h>
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
#include "core-types.h"
|
|
|
|
#include "gimp.h"
|
|
#include "gimpimage.h"
|
|
#include "gimplink.h"
|
|
#include "gimpmarshal.h"
|
|
#include "gimppickable.h"
|
|
#include "gimpprojection.h"
|
|
|
|
#include "file/file-open.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_GIMP,
|
|
PROP_FILE,
|
|
PROP_ABSOLUTE_PATH,
|
|
N_PROPS
|
|
};
|
|
|
|
enum
|
|
{
|
|
CHANGED,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
struct _GimpLinkPrivate
|
|
{
|
|
Gimp *gimp;
|
|
GFile *file;
|
|
GFileMonitor *monitor;
|
|
gboolean absolute_path;
|
|
|
|
GeglBuffer *buffer;
|
|
gboolean broken;
|
|
GError *error;
|
|
guint idle_changed_source;
|
|
|
|
gboolean is_vector;
|
|
gint width;
|
|
gint height;
|
|
gboolean keep_ratio;
|
|
GimpImageBaseType base_type;
|
|
GimpPrecision precision;
|
|
GimpPlugInProcedure *load_proc;
|
|
const gchar *mime_type;
|
|
};
|
|
|
|
static void gimp_link_finalize (GObject *object);
|
|
static void gimp_link_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_link_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_link_file_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
GimpLink *link);
|
|
static gboolean gimp_link_emit_changed (gpointer data);
|
|
|
|
static void gimp_link_update_buffer (GimpLink *link,
|
|
GimpProgress *progress,
|
|
GError **error);
|
|
static void gimp_link_start_monitoring (GimpLink *link);
|
|
static gchar * gimp_link_get_relative_path (GimpLink *link,
|
|
GFile *parent,
|
|
gint n_back);
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GimpLink, gimp_link, GIMP_TYPE_OBJECT)
|
|
|
|
#define parent_class gimp_link_parent_class
|
|
|
|
static guint link_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
static GParamSpec *link_props[N_PROPS] = { NULL, };
|
|
|
|
static void
|
|
gimp_link_class_init (GimpLinkClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
link_signals[CHANGED] =
|
|
g_signal_new ("changed",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (GimpLinkClass, changed),
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 0);
|
|
|
|
object_class->finalize = gimp_link_finalize;
|
|
object_class->get_property = gimp_link_get_property;
|
|
object_class->set_property = gimp_link_set_property;
|
|
|
|
link_props[PROP_GIMP] = g_param_spec_object ("gimp", NULL, NULL,
|
|
GIMP_TYPE_GIMP,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY);
|
|
link_props[PROP_FILE] = g_param_spec_object ("file", NULL, NULL,
|
|
G_TYPE_FILE,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_EXPLICIT_NOTIFY);
|
|
link_props[PROP_ABSOLUTE_PATH] = g_param_spec_boolean ("absolute-path", NULL, NULL,
|
|
FALSE,
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, link_props);
|
|
}
|
|
|
|
static void
|
|
gimp_link_init (GimpLink *link)
|
|
{
|
|
link->p = gimp_link_get_instance_private (link);
|
|
link->p->gimp = NULL;
|
|
link->p->file = NULL;
|
|
link->p->monitor = NULL;
|
|
link->p->buffer = NULL;
|
|
link->p->broken = TRUE;
|
|
link->p->error = NULL;
|
|
link->p->width = 0;
|
|
link->p->height = 0;
|
|
link->p->base_type = GIMP_RGB;
|
|
link->p->precision = GIMP_PRECISION_U8_PERCEPTUAL;
|
|
link->p->load_proc = NULL;
|
|
|
|
link->p->idle_changed_source = 0;
|
|
}
|
|
|
|
static void
|
|
gimp_link_finalize (GObject *object)
|
|
{
|
|
GimpLink *link = GIMP_LINK (object);
|
|
|
|
g_clear_object (&link->p->file);
|
|
g_clear_object (&link->p->monitor);
|
|
g_clear_object (&link->p->buffer);
|
|
g_clear_error (&link->p->error);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gimp_link_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpLink *link = GIMP_LINK (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_GIMP:
|
|
g_value_set_object (value, link->p->gimp);
|
|
break;
|
|
case PROP_FILE:
|
|
g_value_set_object (value, link->p->file);
|
|
break;
|
|
case PROP_ABSOLUTE_PATH:
|
|
g_value_set_boolean (value, link->p->absolute_path);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_link_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpLink *link = GIMP_LINK (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_GIMP:
|
|
link->p->gimp = g_value_get_object (value);
|
|
break;
|
|
case PROP_FILE:
|
|
gimp_link_set_file (link, g_value_get_object (value), 0, 0, FALSE, NULL, NULL);
|
|
break;
|
|
case PROP_ABSOLUTE_PATH:
|
|
link->p->absolute_path = g_value_get_boolean (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_link_file_changed (GFileMonitor *monitor,
|
|
GFile *file,
|
|
GFile *other_file,
|
|
GFileMonitorEvent event_type,
|
|
GimpLink *link)
|
|
{
|
|
switch (event_type)
|
|
{
|
|
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
|
|
if (link->p->idle_changed_source == 0)
|
|
link->p->idle_changed_source = g_idle_add_full (G_PRIORITY_LOW,
|
|
gimp_link_emit_changed,
|
|
link, NULL);
|
|
break;
|
|
case G_FILE_MONITOR_EVENT_CREATED:
|
|
g_signal_emit (link, link_signals[CHANGED], 0);
|
|
break;
|
|
case G_FILE_MONITOR_EVENT_DELETED:
|
|
link->p->broken = TRUE;
|
|
g_clear_error (&link->p->error);
|
|
g_set_error_literal (&link->p->error,
|
|
G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
_("The file got deleted"));
|
|
break;
|
|
|
|
default:
|
|
/* No need to signal for changes where nothing can be done anyway.
|
|
* In particular a file deletion, the link is broken, yet we don't
|
|
* want to re-render.
|
|
* Don't emit either on G_FILE_MONITOR_EVENT_CHANGED because too
|
|
* many such events may be emitted for a single file writing.
|
|
*/
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
static gboolean
|
|
gimp_link_emit_changed (gpointer data)
|
|
{
|
|
GimpLink *link = GIMP_LINK (data);
|
|
|
|
gimp_link_update_buffer (link, NULL, NULL);
|
|
|
|
g_signal_emit (link, link_signals[CHANGED], 0);
|
|
link->p->idle_changed_source = 0;
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
gimp_link_update_buffer (GimpLink *link,
|
|
GimpProgress *progress,
|
|
GError **error)
|
|
{
|
|
GeglBuffer *buffer = NULL;
|
|
GError *real_error = NULL;
|
|
|
|
g_return_if_fail (GIMP_IS_LINK (link));
|
|
g_return_if_fail (error == NULL || *error == NULL);
|
|
|
|
link->p->is_vector = FALSE;
|
|
g_clear_error (&link->p->error);
|
|
|
|
if (link->p->file)
|
|
{
|
|
GimpImage *image;
|
|
GimpPDBStatusType status;
|
|
|
|
link->p->mime_type = NULL;
|
|
image = file_open_image (link->p->gimp,
|
|
gimp_get_user_context (link->p->gimp),
|
|
progress,
|
|
link->p->file,
|
|
link->p->width, link->p->height,
|
|
link->p->keep_ratio,
|
|
FALSE, NULL,
|
|
/* XXX We might want interactive opening
|
|
* for a first opening (when done through
|
|
* GUI), but not for every re-render.
|
|
*/
|
|
GIMP_RUN_NONINTERACTIVE,
|
|
&link->p->is_vector,
|
|
&status, &link->p->mime_type,
|
|
&real_error);
|
|
|
|
if (image && status == GIMP_PDB_SUCCESS)
|
|
{
|
|
/* If we don't flush the projection first, the buffer may be empty.
|
|
* I do wonder if the flushing and updating of the link could
|
|
* not be multi-threaded with gimp_projection_flush() instead,
|
|
* then notifying the update through signals. For very heavy
|
|
* images, would it be a better UX? XXX
|
|
*/
|
|
gimp_projection_flush_now (gimp_image_get_projection (image), TRUE);
|
|
buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image));
|
|
g_object_ref (buffer);
|
|
|
|
link->p->base_type = gimp_image_get_base_type (image);
|
|
link->p->precision = gimp_image_get_precision (image);
|
|
link->p->width = gimp_image_get_width (image);
|
|
link->p->height = gimp_image_get_height (image);
|
|
link->p->load_proc = gimp_image_get_load_proc (image);
|
|
}
|
|
|
|
/* Only keep the buffer, free the rest. */
|
|
g_clear_object (&image);
|
|
}
|
|
|
|
link->p->broken = (buffer == NULL);
|
|
if (link->p->broken)
|
|
{
|
|
if (real_error)
|
|
link->p->error = g_error_copy (real_error);
|
|
else
|
|
g_set_error_literal (&link->p->error,
|
|
G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
_("No file was set"));
|
|
}
|
|
|
|
if (error)
|
|
*error = real_error;
|
|
else
|
|
g_clear_error (&real_error);
|
|
|
|
if (buffer)
|
|
{
|
|
/* Keep the old buffer if the link is broken (outdated image is
|
|
* better than none).
|
|
*/
|
|
g_clear_object (&link->p->buffer);
|
|
link->p->buffer = buffer;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_link_start_monitoring (GimpLink *link)
|
|
{
|
|
link->p->monitor = g_file_monitor_file (link->p->file,
|
|
G_FILE_MONITOR_WATCH_HARD_LINKS,
|
|
NULL, NULL);
|
|
g_signal_connect (link->p->monitor, "changed",
|
|
G_CALLBACK (gimp_link_file_changed),
|
|
link);
|
|
}
|
|
|
|
/**
|
|
* gimp_link_get_relative_path:
|
|
* @link: the image this link is associated with.
|
|
* @parent: (transfer full): a #GFile object.
|
|
* @n_back: set it to 0 when calling it initially.
|
|
*
|
|
* This is a variant of g_file_get_relative_path() which will work even
|
|
* when the @link file is not a child of @parent. In this case, the
|
|
* relative link will use "../" as many times as necessary until a
|
|
* common parent folder is found.
|
|
*
|
|
* In case no parent is found (it may happen for instance on Windows,
|
|
* with various file system roots), an absolute path is returned
|
|
* instead, ensuring that we never return %NULL.
|
|
*
|
|
* Note that this function takes ownership of @parent and will take care
|
|
* of freeing it. This allows for tail recursion.
|
|
*
|
|
* Returns: a path from @link relatively to @parent, falling back
|
|
* to an absolute path if a relative path cannot be constructed.
|
|
**/
|
|
static gchar *
|
|
gimp_link_get_relative_path (GimpLink *link,
|
|
GFile *parent,
|
|
gint n_back)
|
|
{
|
|
gchar *relative_path;
|
|
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
|
|
g_return_val_if_fail (parent != NULL && n_back >= 0, NULL);
|
|
|
|
relative_path = g_file_get_relative_path (parent, link->p->file);
|
|
|
|
if (relative_path == NULL)
|
|
{
|
|
GFile *grand_parent = g_file_get_parent (parent);
|
|
|
|
g_object_unref (parent);
|
|
|
|
if (grand_parent == NULL)
|
|
/* This may happen e.g. on Windows where there are several roots
|
|
* so it is not always possible to make a relative path.
|
|
*/
|
|
return g_file_get_path (link->p->file);
|
|
else
|
|
return gimp_link_get_relative_path (link, grand_parent, n_back + 1);
|
|
}
|
|
else
|
|
{
|
|
g_object_unref (parent);
|
|
|
|
if (n_back > 0)
|
|
{
|
|
GStrvBuilder *builder;
|
|
gchar **array;
|
|
gchar *dots;
|
|
gchar *relpath;
|
|
|
|
builder = g_strv_builder_new ();
|
|
for (gint i = 0; i < n_back; i++)
|
|
g_strv_builder_add (builder, "..");
|
|
|
|
array = g_strv_builder_end (builder);
|
|
dots = g_strjoinv (G_DIR_SEPARATOR_S, array);
|
|
relpath = g_build_filename (dots, relative_path, NULL);
|
|
|
|
g_free (relative_path);
|
|
g_free (dots);
|
|
g_strfreev (array);
|
|
g_strv_builder_unref (builder);
|
|
|
|
relative_path = relpath;
|
|
}
|
|
|
|
return relative_path;
|
|
}
|
|
}
|
|
|
|
|
|
/* public functions */
|
|
|
|
/**
|
|
* gimp_link_new:
|
|
* @gimp: #Gimp object.
|
|
* @file: a #GFile object.
|
|
*
|
|
* Creates a new link object. By default, all link objects are created
|
|
* as being relative to the path of the image they will be associated
|
|
* with.
|
|
*
|
|
* Return value: a new #GimpLink or %NULL in case of a problem
|
|
**/
|
|
GimpLink *
|
|
gimp_link_new (Gimp *gimp,
|
|
GFile *file,
|
|
gint vector_width,
|
|
gint vector_height,
|
|
gboolean keep_ratio,
|
|
GimpProgress *progress,
|
|
GError **error)
|
|
{
|
|
GimpLink *link;
|
|
|
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
|
|
|
link = g_object_new (GIMP_TYPE_LINK,
|
|
"gimp", gimp,
|
|
"absolute-path", FALSE,
|
|
NULL);
|
|
|
|
gimp_link_set_file (link, file, vector_width, vector_height, keep_ratio, progress, error);
|
|
|
|
return GIMP_LINK (link);
|
|
}
|
|
|
|
GimpLink *
|
|
gimp_link_duplicate (GimpLink *link)
|
|
{
|
|
GimpLink *new_link;
|
|
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
|
|
|
|
new_link = g_object_new (GIMP_TYPE_LINK,
|
|
"gimp", link->p->gimp,
|
|
"absolute-path", gimp_link_get_absolute_path (link),
|
|
NULL);
|
|
|
|
/* Copy things manually as we do not need to trigger a load. */
|
|
new_link->p->file = link->p->file ? g_object_ref (link->p->file) : NULL;
|
|
|
|
new_link->p->buffer = link->p->buffer ? gegl_buffer_dup (link->p->buffer) : NULL;
|
|
new_link->p->broken = link->p->broken;
|
|
new_link->p->error = link->p->error ? g_error_copy (link->p->error) : NULL;
|
|
|
|
new_link->p->is_vector = link->p->is_vector;
|
|
new_link->p->width = link->p->width;
|
|
new_link->p->height = link->p->height;
|
|
new_link->p->base_type = link->p->base_type;
|
|
new_link->p->precision = link->p->precision;
|
|
new_link->p->load_proc = link->p->load_proc;
|
|
|
|
if (new_link->p->file)
|
|
{
|
|
gchar *basename;
|
|
|
|
basename = g_file_get_basename (new_link->p->file);
|
|
gimp_object_set_name_safe (GIMP_OBJECT (new_link), basename);
|
|
g_free (basename);
|
|
|
|
if (gimp_link_is_monitored (link))
|
|
gimp_link_start_monitoring (new_link);
|
|
}
|
|
|
|
return new_link;
|
|
}
|
|
|
|
/*
|
|
* gimp_link_get_file:
|
|
* @link: the #GimpLink object.
|
|
* @xcf_file: optional XCF file from which @path will be relative to.
|
|
* @path: optional returned path of the returned file.
|
|
*
|
|
* If @path is non-%NULL, it will be set to the file system path for the
|
|
* returned %GFile, either as an absolute or relative path, depending on
|
|
* how @link was set.
|
|
* Note that it is possible for @path to be absolute even when it is set
|
|
* to be a relative path, in cases where no relative path can be
|
|
* constructed from @xcf_file.
|
|
*
|
|
* Returns: the %GFile which %link is syncing too.
|
|
*/
|
|
GFile *
|
|
gimp_link_get_file (GimpLink *link,
|
|
GFile *xcf_file,
|
|
gchar **path)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
|
|
g_return_val_if_fail ((path == NULL && xcf_file == NULL) ||
|
|
(*path == NULL && xcf_file != NULL &&
|
|
g_file_has_parent (xcf_file, NULL)), NULL);
|
|
|
|
if (path != NULL)
|
|
{
|
|
if (link->p->absolute_path)
|
|
*path = g_file_get_path (link->p->file);
|
|
else
|
|
*path = gimp_link_get_relative_path (link,
|
|
g_file_get_parent (xcf_file),
|
|
0);
|
|
}
|
|
|
|
return link->p->file;
|
|
}
|
|
|
|
void
|
|
gimp_link_set_file (GimpLink *link,
|
|
GFile *file,
|
|
gint vector_width,
|
|
gint vector_height,
|
|
gboolean keep_ratio,
|
|
GimpProgress *progress,
|
|
GError **error)
|
|
{
|
|
g_return_if_fail (GIMP_IS_LINK (link));
|
|
g_return_if_fail (G_IS_FILE (file) || file == NULL);
|
|
g_return_if_fail (error == NULL || *error == NULL);
|
|
|
|
if (file == link->p->file ||
|
|
(file && link->p->file && g_file_equal (file, link->p->file)))
|
|
{
|
|
if (link->p->width != vector_width ||
|
|
link->p->height != vector_height ||
|
|
link->p->keep_ratio != keep_ratio)
|
|
gimp_link_set_size (link, vector_width, vector_height, keep_ratio);
|
|
|
|
return;
|
|
}
|
|
|
|
link->p->width = vector_width;
|
|
link->p->height = vector_height;
|
|
link->p->keep_ratio = keep_ratio;
|
|
|
|
g_clear_object (&link->p->monitor);
|
|
|
|
g_set_object (&link->p->file, file);
|
|
|
|
gimp_link_update_buffer (link, progress, error);
|
|
|
|
if (link->p->file)
|
|
{
|
|
gchar *basename;
|
|
|
|
basename = g_file_get_basename (link->p->file);
|
|
gimp_object_set_name_safe (GIMP_OBJECT (link), basename);
|
|
g_free (basename);
|
|
|
|
gimp_link_start_monitoring (link);
|
|
}
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (link), link_props[PROP_FILE]);
|
|
}
|
|
|
|
gboolean
|
|
gimp_link_get_absolute_path (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), FALSE);
|
|
|
|
return link->p->absolute_path;
|
|
}
|
|
|
|
void
|
|
gimp_link_set_absolute_path (GimpLink *link,
|
|
gboolean absolute_path)
|
|
{
|
|
g_return_if_fail (GIMP_IS_LINK (link));
|
|
|
|
link->p->absolute_path = absolute_path;
|
|
}
|
|
|
|
const gchar *
|
|
gimp_link_get_mime_type (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
|
|
|
|
return link->p->mime_type;
|
|
}
|
|
|
|
void
|
|
gimp_link_freeze (GimpLink *link)
|
|
{
|
|
g_return_if_fail (GIMP_IS_LINK (link));
|
|
g_return_if_fail (link->p->monitor != NULL);
|
|
|
|
g_clear_object (&link->p->monitor);
|
|
}
|
|
|
|
void
|
|
gimp_link_thaw (GimpLink *link)
|
|
{
|
|
g_return_if_fail (GIMP_IS_LINK (link));
|
|
g_return_if_fail (G_IS_FILE (link->p->file) && link->p->monitor == NULL);
|
|
|
|
gimp_link_update_buffer (link, NULL, NULL);
|
|
gimp_link_start_monitoring (link);
|
|
}
|
|
|
|
gboolean
|
|
gimp_link_is_monitored (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), FALSE);
|
|
|
|
return (link->p->monitor != NULL);
|
|
}
|
|
|
|
gboolean
|
|
gimp_link_is_broken (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), TRUE);
|
|
|
|
return link->p->broken;
|
|
}
|
|
|
|
void
|
|
gimp_link_set_size (GimpLink *link,
|
|
gint width,
|
|
gint height,
|
|
gboolean keep_ratio)
|
|
{
|
|
g_return_if_fail (GIMP_IS_LINK (link));
|
|
|
|
link->p->width = width;
|
|
link->p->height = height;
|
|
link->p->keep_ratio = keep_ratio;
|
|
|
|
if (link->p->monitor && link->p->is_vector)
|
|
gimp_link_update_buffer (link, NULL, NULL);
|
|
}
|
|
|
|
void
|
|
gimp_link_get_size (GimpLink *link,
|
|
gint *width,
|
|
gint *height)
|
|
{
|
|
g_return_if_fail (GIMP_IS_LINK (link));
|
|
|
|
*width = link->p->width;
|
|
*height = link->p->height;
|
|
}
|
|
|
|
GimpImageBaseType
|
|
gimp_link_get_base_type (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link) && ! link->p->broken, GIMP_RGB);
|
|
|
|
return link->p->base_type;
|
|
}
|
|
|
|
GimpPrecision
|
|
gimp_link_get_precision (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link) && ! link->p->broken, GIMP_PRECISION_U8_PERCEPTUAL);
|
|
|
|
return link->p->precision;
|
|
}
|
|
|
|
GimpPlugInProcedure *
|
|
gimp_link_get_load_proc (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link) && ! link->p->broken, NULL);
|
|
|
|
return link->p->load_proc;
|
|
}
|
|
|
|
gboolean
|
|
gimp_link_is_vector (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), FALSE);
|
|
|
|
return link->p->is_vector;
|
|
}
|
|
|
|
GeglBuffer *
|
|
gimp_link_get_buffer (GimpLink *link)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), NULL);
|
|
|
|
return link->p->buffer;
|
|
}
|