883 lines
33 KiB
C
883 lines
33 KiB
C
|
/* PIKA - Photo and Image Kooker Application
|
||
|
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||
|
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||
|
*
|
||
|
* Original copyright, applying to most contents (license remains unchanged):
|
||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||
|
*
|
||
|
* pikaimageproxy.c
|
||
|
* Copyright (C) 2019 Ell
|
||
|
*
|
||
|
* 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 <cairo.h>
|
||
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||
|
#include <gegl.h>
|
||
|
|
||
|
#include "libpikabase/pikabase.h"
|
||
|
#include "libpikacolor/pikacolor.h"
|
||
|
|
||
|
#include "core-types.h"
|
||
|
|
||
|
#include "gegl/pika-babl.h"
|
||
|
#include "gegl/pika-gegl-loops.h"
|
||
|
|
||
|
#include "pikaimage.h"
|
||
|
#include "pikaimage-color-profile.h"
|
||
|
#include "pikaimage-preview.h"
|
||
|
#include "pikaimageproxy.h"
|
||
|
#include "pikapickable.h"
|
||
|
#include "pikaprojectable.h"
|
||
|
#include "pikatempbuf.h"
|
||
|
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
PROP_0,
|
||
|
PROP_IMAGE,
|
||
|
PROP_SHOW_ALL,
|
||
|
PROP_BUFFER
|
||
|
};
|
||
|
|
||
|
|
||
|
struct _PikaImageProxyPrivate
|
||
|
{
|
||
|
PikaImage *image;
|
||
|
gboolean show_all;
|
||
|
|
||
|
GeglRectangle bounding_box;
|
||
|
gboolean frozen;
|
||
|
};
|
||
|
|
||
|
|
||
|
/* local function prototypes */
|
||
|
|
||
|
static void pika_image_proxy_pickable_iface_init (PikaPickableInterface *iface);
|
||
|
static void pika_image_proxy_color_managed_iface_init (PikaColorManagedInterface *iface);
|
||
|
|
||
|
static void pika_image_proxy_finalize (GObject *object);
|
||
|
static void pika_image_proxy_set_property (GObject *object,
|
||
|
guint property_id,
|
||
|
const GValue *value,
|
||
|
GParamSpec *pspec);
|
||
|
static void pika_image_proxy_get_property (GObject *object,
|
||
|
guint property_id,
|
||
|
GValue *value,
|
||
|
GParamSpec *pspec);
|
||
|
|
||
|
static gboolean pika_image_proxy_get_size (PikaViewable *viewable,
|
||
|
gint *width,
|
||
|
gint *height);
|
||
|
static void pika_image_proxy_get_preview_size (PikaViewable *viewable,
|
||
|
gint size,
|
||
|
gboolean is_popup,
|
||
|
gboolean dot_for_dot,
|
||
|
gint *width,
|
||
|
gint *height);
|
||
|
static gboolean pika_image_proxy_get_popup_size (PikaViewable *viewable,
|
||
|
gint width,
|
||
|
gint height,
|
||
|
gboolean dot_for_dot,
|
||
|
gint *popup_width,
|
||
|
gint *popup_height);
|
||
|
static PikaTempBuf * pika_image_proxy_get_new_preview (PikaViewable *viewable,
|
||
|
PikaContext *context,
|
||
|
gint width,
|
||
|
gint height);
|
||
|
static GdkPixbuf * pika_image_proxy_get_new_pixbuf (PikaViewable *viewable,
|
||
|
PikaContext *context,
|
||
|
gint width,
|
||
|
gint height);
|
||
|
static gchar * pika_image_proxy_get_description (PikaViewable *viewable,
|
||
|
gchar **tooltip);
|
||
|
|
||
|
static void pika_image_proxy_flush (PikaPickable *pickable);
|
||
|
static const Babl * pika_image_proxy_get_format (PikaPickable *pickable);
|
||
|
static const Babl * pika_image_proxy_get_format_with_alpha (PikaPickable *pickable);
|
||
|
static GeglBuffer * pika_image_proxy_get_buffer (PikaPickable *pickable);
|
||
|
static gboolean pika_image_proxy_get_pixel_at (PikaPickable *pickable,
|
||
|
gint x,
|
||
|
gint y,
|
||
|
const Babl *format,
|
||
|
gpointer pixel);
|
||
|
static gdouble pika_image_proxy_get_opacity_at (PikaPickable *pickable,
|
||
|
gint x,
|
||
|
gint y);
|
||
|
static void pika_image_proxy_get_pixel_average (PikaPickable *pickable,
|
||
|
const GeglRectangle *rect,
|
||
|
const Babl *format,
|
||
|
gpointer pixel);
|
||
|
static void pika_image_proxy_pixel_to_rgb (PikaPickable *pickable,
|
||
|
const Babl *format,
|
||
|
gpointer pixel,
|
||
|
PikaRGB *color);
|
||
|
static void pika_image_proxy_rgb_to_pixel (PikaPickable *pickable,
|
||
|
const PikaRGB *color,
|
||
|
const Babl *format,
|
||
|
gpointer pixel);
|
||
|
|
||
|
static const guint8 * pika_image_proxy_get_icc_profile (PikaColorManaged *managed,
|
||
|
gsize *len);
|
||
|
static PikaColorProfile * pika_image_proxy_get_color_profile (PikaColorManaged *managed);
|
||
|
static void pika_image_proxy_profile_changed (PikaColorManaged *managed);
|
||
|
|
||
|
static void pika_image_proxy_image_frozen_notify (PikaImage *image,
|
||
|
const GParamSpec *pspec,
|
||
|
PikaImageProxy *image_proxy);
|
||
|
static void pika_image_proxy_image_invalidate_preview (PikaImage *image,
|
||
|
PikaImageProxy *image_proxy);
|
||
|
static void pika_image_proxy_image_size_changed (PikaImage *image,
|
||
|
PikaImageProxy *image_proxy);
|
||
|
static void pika_image_proxy_image_bounds_changed (PikaImage *image,
|
||
|
gint old_x,
|
||
|
gint old_y,
|
||
|
PikaImageProxy *image_proxy);
|
||
|
static void pika_image_proxy_image_profile_changed (PikaImage *image,
|
||
|
PikaImageProxy *image_proxy);
|
||
|
|
||
|
static void pika_image_proxy_set_image (PikaImageProxy *image_proxy,
|
||
|
PikaImage *image);
|
||
|
static PikaPickable * pika_image_proxy_get_pickable (PikaImageProxy *image_proxy);
|
||
|
static void pika_image_proxy_update_bounding_box (PikaImageProxy *image_proxy);
|
||
|
static void pika_image_proxy_update_frozen (PikaImageProxy *image_proxy);
|
||
|
|
||
|
|
||
|
G_DEFINE_TYPE_WITH_CODE (PikaImageProxy, pika_image_proxy, PIKA_TYPE_VIEWABLE,
|
||
|
G_ADD_PRIVATE (PikaImageProxy)
|
||
|
G_IMPLEMENT_INTERFACE (PIKA_TYPE_PICKABLE,
|
||
|
pika_image_proxy_pickable_iface_init)
|
||
|
G_IMPLEMENT_INTERFACE (PIKA_TYPE_COLOR_MANAGED,
|
||
|
pika_image_proxy_color_managed_iface_init))
|
||
|
|
||
|
#define parent_class pika_image_proxy_parent_class
|
||
|
|
||
|
|
||
|
/* private functions */
|
||
|
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_class_init (PikaImageProxyClass *klass)
|
||
|
{
|
||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
|
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||
|
|
||
|
object_class->finalize = pika_image_proxy_finalize;
|
||
|
object_class->set_property = pika_image_proxy_set_property;
|
||
|
object_class->get_property = pika_image_proxy_get_property;
|
||
|
|
||
|
viewable_class->default_icon_name = "pika-image";
|
||
|
viewable_class->get_size = pika_image_proxy_get_size;
|
||
|
viewable_class->get_preview_size = pika_image_proxy_get_preview_size;
|
||
|
viewable_class->get_popup_size = pika_image_proxy_get_popup_size;
|
||
|
viewable_class->get_new_preview = pika_image_proxy_get_new_preview;
|
||
|
viewable_class->get_new_pixbuf = pika_image_proxy_get_new_pixbuf;
|
||
|
viewable_class->get_description = pika_image_proxy_get_description;
|
||
|
|
||
|
g_object_class_install_property (object_class, PROP_IMAGE,
|
||
|
g_param_spec_object ("image",
|
||
|
NULL, NULL,
|
||
|
PIKA_TYPE_IMAGE,
|
||
|
PIKA_PARAM_READWRITE |
|
||
|
G_PARAM_CONSTRUCT_ONLY));
|
||
|
|
||
|
g_object_class_install_property (object_class, PROP_SHOW_ALL,
|
||
|
g_param_spec_boolean ("show-all",
|
||
|
NULL, NULL,
|
||
|
FALSE,
|
||
|
PIKA_PARAM_READWRITE |
|
||
|
G_PARAM_CONSTRUCT));
|
||
|
|
||
|
g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_pickable_iface_init (PikaPickableInterface *iface)
|
||
|
{
|
||
|
iface->flush = pika_image_proxy_flush;
|
||
|
iface->get_image = (gpointer) pika_image_proxy_get_image;
|
||
|
iface->get_format = pika_image_proxy_get_format;
|
||
|
iface->get_format_with_alpha = pika_image_proxy_get_format_with_alpha;
|
||
|
iface->get_buffer = pika_image_proxy_get_buffer;
|
||
|
iface->get_pixel_at = pika_image_proxy_get_pixel_at;
|
||
|
iface->get_opacity_at = pika_image_proxy_get_opacity_at;
|
||
|
iface->get_pixel_average = pika_image_proxy_get_pixel_average;
|
||
|
iface->pixel_to_rgb = pika_image_proxy_pixel_to_rgb;
|
||
|
iface->rgb_to_pixel = pika_image_proxy_rgb_to_pixel;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_color_managed_iface_init (PikaColorManagedInterface *iface)
|
||
|
{
|
||
|
iface->get_icc_profile = pika_image_proxy_get_icc_profile;
|
||
|
iface->get_color_profile = pika_image_proxy_get_color_profile;
|
||
|
iface->profile_changed = pika_image_proxy_profile_changed;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_init (PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
image_proxy->priv = pika_image_proxy_get_instance_private (image_proxy);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_finalize (GObject *object)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (object);
|
||
|
|
||
|
pika_image_proxy_set_image (image_proxy, NULL);
|
||
|
|
||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_set_property (GObject *object,
|
||
|
guint property_id,
|
||
|
const GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (object);
|
||
|
|
||
|
switch (property_id)
|
||
|
{
|
||
|
case PROP_IMAGE:
|
||
|
pika_image_proxy_set_image (image_proxy,
|
||
|
g_value_get_object (value));
|
||
|
break;
|
||
|
|
||
|
case PROP_SHOW_ALL:
|
||
|
pika_image_proxy_set_show_all (image_proxy,
|
||
|
g_value_get_boolean (value));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_get_property (GObject *object,
|
||
|
guint property_id,
|
||
|
GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (object);
|
||
|
|
||
|
switch (property_id)
|
||
|
{
|
||
|
case PROP_IMAGE:
|
||
|
g_value_set_object (value,
|
||
|
pika_image_proxy_get_image (image_proxy));
|
||
|
break;
|
||
|
|
||
|
case PROP_SHOW_ALL:
|
||
|
g_value_set_boolean (value,
|
||
|
pika_image_proxy_get_show_all (image_proxy));
|
||
|
break;
|
||
|
|
||
|
case PROP_BUFFER:
|
||
|
g_value_set_object (value,
|
||
|
pika_pickable_get_buffer (
|
||
|
PIKA_PICKABLE (image_proxy)));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
pika_image_proxy_get_size (PikaViewable *viewable,
|
||
|
gint *width,
|
||
|
gint *height)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (viewable);
|
||
|
|
||
|
*width = image_proxy->priv->bounding_box.width;
|
||
|
*height = image_proxy->priv->bounding_box.height;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_get_preview_size (PikaViewable *viewable,
|
||
|
gint size,
|
||
|
gboolean is_popup,
|
||
|
gboolean dot_for_dot,
|
||
|
gint *width,
|
||
|
gint *height)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (viewable);
|
||
|
PikaImage *image = image_proxy->priv->image;
|
||
|
gdouble xres;
|
||
|
gdouble yres;
|
||
|
gint viewable_width;
|
||
|
gint viewable_height;
|
||
|
|
||
|
pika_image_get_resolution (image, &xres, &yres);
|
||
|
|
||
|
pika_viewable_get_size (viewable, &viewable_width, &viewable_height);
|
||
|
|
||
|
pika_viewable_calc_preview_size (viewable_width,
|
||
|
viewable_height,
|
||
|
size,
|
||
|
size,
|
||
|
dot_for_dot,
|
||
|
xres,
|
||
|
yres,
|
||
|
width,
|
||
|
height,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
pika_image_proxy_get_popup_size (PikaViewable *viewable,
|
||
|
gint width,
|
||
|
gint height,
|
||
|
gboolean dot_for_dot,
|
||
|
gint *popup_width,
|
||
|
gint *popup_height)
|
||
|
{
|
||
|
gint viewable_width;
|
||
|
gint viewable_height;
|
||
|
|
||
|
pika_viewable_get_size (viewable, &viewable_width, &viewable_height);
|
||
|
|
||
|
if (viewable_width > width || viewable_height > height)
|
||
|
{
|
||
|
gboolean scaling_up;
|
||
|
|
||
|
pika_viewable_calc_preview_size (viewable_width,
|
||
|
viewable_height,
|
||
|
width * 2,
|
||
|
height * 2,
|
||
|
dot_for_dot, 1.0, 1.0,
|
||
|
popup_width,
|
||
|
popup_height,
|
||
|
&scaling_up);
|
||
|
|
||
|
if (scaling_up)
|
||
|
{
|
||
|
*popup_width = viewable_width;
|
||
|
*popup_height = viewable_height;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static PikaTempBuf *
|
||
|
pika_image_proxy_get_new_preview (PikaViewable *viewable,
|
||
|
PikaContext *context,
|
||
|
gint width,
|
||
|
gint height)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (viewable);
|
||
|
PikaImage *image = image_proxy->priv->image;
|
||
|
PikaPickable *pickable;
|
||
|
const Babl *format;
|
||
|
GeglRectangle bounding_box;
|
||
|
PikaTempBuf *buf;
|
||
|
gdouble scale_x;
|
||
|
gdouble scale_y;
|
||
|
gdouble scale;
|
||
|
|
||
|
pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
bounding_box = pika_image_proxy_get_bounding_box (image_proxy);
|
||
|
|
||
|
scale_x = (gdouble) width / (gdouble) bounding_box.width;
|
||
|
scale_y = (gdouble) height / (gdouble) bounding_box.height;
|
||
|
|
||
|
scale = MIN (scale_x, scale_y);
|
||
|
|
||
|
format = pika_image_get_preview_format (image);
|
||
|
|
||
|
buf = pika_temp_buf_new (width, height, format);
|
||
|
|
||
|
gegl_buffer_get (pika_pickable_get_buffer (pickable),
|
||
|
GEGL_RECTANGLE (bounding_box.x * scale,
|
||
|
bounding_box.y * scale,
|
||
|
width,
|
||
|
height),
|
||
|
scale,
|
||
|
pika_temp_buf_get_format (buf),
|
||
|
pika_temp_buf_get_data (buf),
|
||
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
|
||
|
|
||
|
return buf;
|
||
|
}
|
||
|
|
||
|
static GdkPixbuf *
|
||
|
pika_image_proxy_get_new_pixbuf (PikaViewable *viewable,
|
||
|
PikaContext *context,
|
||
|
gint width,
|
||
|
gint height)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (viewable);
|
||
|
PikaImage *image = image_proxy->priv->image;
|
||
|
PikaPickable *pickable;
|
||
|
GeglRectangle bounding_box;
|
||
|
GdkPixbuf *pixbuf;
|
||
|
gdouble scale_x;
|
||
|
gdouble scale_y;
|
||
|
gdouble scale;
|
||
|
PikaColorTransform *transform;
|
||
|
|
||
|
pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
bounding_box = pika_image_proxy_get_bounding_box (image_proxy);
|
||
|
|
||
|
scale_x = (gdouble) width / (gdouble) bounding_box.width;
|
||
|
scale_y = (gdouble) height / (gdouble) bounding_box.height;
|
||
|
|
||
|
scale = MIN (scale_x, scale_y);
|
||
|
|
||
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
|
||
|
width, height);
|
||
|
|
||
|
transform = pika_image_get_color_transform_to_srgb_u8 (image);
|
||
|
|
||
|
if (transform)
|
||
|
{
|
||
|
PikaTempBuf *temp_buf;
|
||
|
GeglBuffer *src_buf;
|
||
|
GeglBuffer *dest_buf;
|
||
|
|
||
|
temp_buf = pika_temp_buf_new (width, height,
|
||
|
pika_pickable_get_format (pickable));
|
||
|
|
||
|
gegl_buffer_get (pika_pickable_get_buffer (pickable),
|
||
|
GEGL_RECTANGLE (bounding_box.x * scale,
|
||
|
bounding_box.y * scale,
|
||
|
width,
|
||
|
height),
|
||
|
scale,
|
||
|
pika_temp_buf_get_format (temp_buf),
|
||
|
pika_temp_buf_get_data (temp_buf),
|
||
|
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
|
||
|
|
||
|
src_buf = pika_temp_buf_create_buffer (temp_buf);
|
||
|
dest_buf = pika_pixbuf_create_buffer (pixbuf);
|
||
|
|
||
|
pika_temp_buf_unref (temp_buf);
|
||
|
|
||
|
pika_color_transform_process_buffer (transform,
|
||
|
src_buf,
|
||
|
GEGL_RECTANGLE (0, 0,
|
||
|
width, height),
|
||
|
dest_buf,
|
||
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
||
|
|
||
|
g_object_unref (src_buf);
|
||
|
g_object_unref (dest_buf);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gegl_buffer_get (pika_pickable_get_buffer (pickable),
|
||
|
GEGL_RECTANGLE (bounding_box.x * scale,
|
||
|
bounding_box.y * scale,
|
||
|
width,
|
||
|
height),
|
||
|
scale,
|
||
|
pika_pixbuf_get_format (pixbuf),
|
||
|
gdk_pixbuf_get_pixels (pixbuf),
|
||
|
gdk_pixbuf_get_rowstride (pixbuf),
|
||
|
GEGL_ABYSS_CLAMP);
|
||
|
}
|
||
|
|
||
|
return pixbuf;
|
||
|
}
|
||
|
|
||
|
static gchar *
|
||
|
pika_image_proxy_get_description (PikaViewable *viewable,
|
||
|
gchar **tooltip)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (viewable);
|
||
|
PikaImage *image = image_proxy->priv->image;
|
||
|
|
||
|
if (tooltip)
|
||
|
*tooltip = g_strdup (pika_image_get_display_path (image));
|
||
|
|
||
|
return g_strdup_printf ("%s-%d",
|
||
|
pika_image_get_display_name (image),
|
||
|
pika_image_get_id (image));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_flush (PikaPickable *pickable)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
pika_pickable_flush (proxy_pickable);
|
||
|
}
|
||
|
|
||
|
static const Babl *
|
||
|
pika_image_proxy_get_format (PikaPickable *pickable)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
return pika_pickable_get_format (proxy_pickable);
|
||
|
}
|
||
|
|
||
|
static const Babl *
|
||
|
pika_image_proxy_get_format_with_alpha (PikaPickable *pickable)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
return pika_pickable_get_format_with_alpha (proxy_pickable);
|
||
|
}
|
||
|
|
||
|
static GeglBuffer *
|
||
|
pika_image_proxy_get_buffer (PikaPickable *pickable)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
return pika_pickable_get_buffer (proxy_pickable);
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
pika_image_proxy_get_pixel_at (PikaPickable *pickable,
|
||
|
gint x,
|
||
|
gint y,
|
||
|
const Babl *format,
|
||
|
gpointer pixel)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
return pika_pickable_get_pixel_at (proxy_pickable, x, y, format, pixel);
|
||
|
}
|
||
|
|
||
|
static gdouble
|
||
|
pika_image_proxy_get_opacity_at (PikaPickable *pickable,
|
||
|
gint x,
|
||
|
gint y)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
return pika_pickable_get_opacity_at (proxy_pickable, x, y);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_get_pixel_average (PikaPickable *pickable,
|
||
|
const GeglRectangle *rect,
|
||
|
const Babl *format,
|
||
|
gpointer pixel)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
pika_pickable_get_pixel_average (proxy_pickable, rect, format, pixel);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_pixel_to_rgb (PikaPickable *pickable,
|
||
|
const Babl *format,
|
||
|
gpointer pixel,
|
||
|
PikaRGB *color)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
pika_pickable_pixel_to_rgb (proxy_pickable, format, pixel, color);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_rgb_to_pixel (PikaPickable *pickable,
|
||
|
const PikaRGB *color,
|
||
|
const Babl *format,
|
||
|
gpointer pixel)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (pickable);
|
||
|
PikaPickable *proxy_pickable;
|
||
|
|
||
|
proxy_pickable = pika_image_proxy_get_pickable (image_proxy);
|
||
|
|
||
|
pika_pickable_rgb_to_pixel (proxy_pickable, color, format, pixel);
|
||
|
}
|
||
|
|
||
|
static const guint8 *
|
||
|
pika_image_proxy_get_icc_profile (PikaColorManaged *managed,
|
||
|
gsize *len)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (managed);
|
||
|
|
||
|
return pika_color_managed_get_icc_profile (
|
||
|
PIKA_COLOR_MANAGED (image_proxy->priv->image),
|
||
|
len);
|
||
|
}
|
||
|
|
||
|
static PikaColorProfile *
|
||
|
pika_image_proxy_get_color_profile (PikaColorManaged *managed)
|
||
|
{
|
||
|
PikaImageProxy *image_proxy = PIKA_IMAGE_PROXY (managed);
|
||
|
|
||
|
return pika_color_managed_get_color_profile (
|
||
|
PIKA_COLOR_MANAGED (image_proxy->priv->image));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_profile_changed (PikaColorManaged *managed)
|
||
|
{
|
||
|
pika_viewable_invalidate_preview (PIKA_VIEWABLE (managed));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_image_frozen_notify (PikaImage *image,
|
||
|
const GParamSpec *pspec,
|
||
|
PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
pika_image_proxy_update_frozen (image_proxy);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_image_invalidate_preview (PikaImage *image,
|
||
|
PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
pika_viewable_invalidate_preview (PIKA_VIEWABLE (image_proxy));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_image_size_changed (PikaImage *image,
|
||
|
PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
pika_image_proxy_update_bounding_box (image_proxy);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_image_bounds_changed (PikaImage *image,
|
||
|
gint old_x,
|
||
|
gint old_y,
|
||
|
PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
pika_image_proxy_update_bounding_box (image_proxy);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_image_profile_changed (PikaImage *image,
|
||
|
PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
pika_color_managed_profile_changed (PIKA_COLOR_MANAGED (image_proxy));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_set_image (PikaImageProxy *image_proxy,
|
||
|
PikaImage *image)
|
||
|
{
|
||
|
if (image_proxy->priv->image)
|
||
|
{
|
||
|
g_signal_handlers_disconnect_by_func (
|
||
|
image_proxy->priv->image,
|
||
|
pika_image_proxy_image_frozen_notify,
|
||
|
image_proxy);
|
||
|
g_signal_handlers_disconnect_by_func (
|
||
|
image_proxy->priv->image,
|
||
|
pika_image_proxy_image_invalidate_preview,
|
||
|
image_proxy);
|
||
|
g_signal_handlers_disconnect_by_func (
|
||
|
image_proxy->priv->image,
|
||
|
pika_image_proxy_image_size_changed,
|
||
|
image_proxy);
|
||
|
g_signal_handlers_disconnect_by_func (
|
||
|
image_proxy->priv->image,
|
||
|
pika_image_proxy_image_bounds_changed,
|
||
|
image_proxy);
|
||
|
g_signal_handlers_disconnect_by_func (
|
||
|
image_proxy->priv->image,
|
||
|
pika_image_proxy_image_profile_changed,
|
||
|
image_proxy);
|
||
|
|
||
|
g_object_unref (image_proxy->priv->image);
|
||
|
}
|
||
|
|
||
|
image_proxy->priv->image = image;
|
||
|
|
||
|
if (image_proxy->priv->image)
|
||
|
{
|
||
|
g_object_ref (image_proxy->priv->image);
|
||
|
|
||
|
g_signal_connect (
|
||
|
image_proxy->priv->image, "notify::frozen",
|
||
|
G_CALLBACK (pika_image_proxy_image_frozen_notify),
|
||
|
image_proxy);
|
||
|
g_signal_connect (
|
||
|
image_proxy->priv->image, "invalidate-preview",
|
||
|
G_CALLBACK (pika_image_proxy_image_invalidate_preview),
|
||
|
image_proxy);
|
||
|
g_signal_connect (
|
||
|
image_proxy->priv->image, "size-changed",
|
||
|
G_CALLBACK (pika_image_proxy_image_size_changed),
|
||
|
image_proxy);
|
||
|
g_signal_connect (
|
||
|
image_proxy->priv->image, "bounds-changed",
|
||
|
G_CALLBACK (pika_image_proxy_image_bounds_changed),
|
||
|
image_proxy);
|
||
|
g_signal_connect (
|
||
|
image_proxy->priv->image, "profile-changed",
|
||
|
G_CALLBACK (pika_image_proxy_image_profile_changed),
|
||
|
image_proxy);
|
||
|
|
||
|
pika_image_proxy_update_bounding_box (image_proxy);
|
||
|
pika_image_proxy_update_frozen (image_proxy);
|
||
|
|
||
|
pika_viewable_invalidate_preview (PIKA_VIEWABLE (image_proxy));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static PikaPickable *
|
||
|
pika_image_proxy_get_pickable (PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
PikaImage *image = image_proxy->priv->image;
|
||
|
|
||
|
if (! image_proxy->priv->show_all)
|
||
|
return PIKA_PICKABLE (image);
|
||
|
else
|
||
|
return PIKA_PICKABLE (pika_image_get_projection (image));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_update_bounding_box (PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
PikaImage *image = image_proxy->priv->image;
|
||
|
GeglRectangle bounding_box;
|
||
|
|
||
|
if (pika_viewable_preview_is_frozen (PIKA_VIEWABLE (image_proxy)))
|
||
|
return;
|
||
|
|
||
|
if (! image_proxy->priv->show_all)
|
||
|
{
|
||
|
bounding_box.x = 0;
|
||
|
bounding_box.y = 0;
|
||
|
bounding_box.width = pika_image_get_width (image);
|
||
|
bounding_box.height = pika_image_get_height (image);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bounding_box = pika_projectable_get_bounding_box (
|
||
|
PIKA_PROJECTABLE (image));
|
||
|
}
|
||
|
|
||
|
if (! gegl_rectangle_equal (&bounding_box,
|
||
|
&image_proxy->priv->bounding_box))
|
||
|
{
|
||
|
image_proxy->priv->bounding_box = bounding_box;
|
||
|
|
||
|
pika_viewable_size_changed (PIKA_VIEWABLE (image_proxy));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_image_proxy_update_frozen (PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
gboolean frozen;
|
||
|
|
||
|
frozen = pika_viewable_preview_is_frozen (
|
||
|
PIKA_VIEWABLE (image_proxy->priv->image));
|
||
|
|
||
|
if (frozen != image_proxy->priv->frozen)
|
||
|
{
|
||
|
image_proxy->priv->frozen = frozen;
|
||
|
|
||
|
if (frozen)
|
||
|
{
|
||
|
pika_viewable_preview_freeze (PIKA_VIEWABLE (image_proxy));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pika_viewable_preview_thaw (PIKA_VIEWABLE (image_proxy));
|
||
|
|
||
|
pika_image_proxy_update_bounding_box (image_proxy);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* public functions */
|
||
|
|
||
|
|
||
|
PikaImageProxy *
|
||
|
pika_image_proxy_new (PikaImage *image)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
|
||
|
|
||
|
return g_object_new (PIKA_TYPE_IMAGE_PROXY,
|
||
|
"image", image,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
PikaImage *
|
||
|
pika_image_proxy_get_image (PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_IMAGE_PROXY (image_proxy), NULL);
|
||
|
|
||
|
return image_proxy->priv->image;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
pika_image_proxy_set_show_all (PikaImageProxy *image_proxy,
|
||
|
gboolean show_all)
|
||
|
{
|
||
|
g_return_if_fail (PIKA_IS_IMAGE_PROXY (image_proxy));
|
||
|
|
||
|
if (show_all != image_proxy->priv->show_all)
|
||
|
{
|
||
|
image_proxy->priv->show_all = show_all;
|
||
|
|
||
|
pika_image_proxy_update_bounding_box (image_proxy);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gboolean
|
||
|
pika_image_proxy_get_show_all (PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_IMAGE_PROXY (image_proxy), FALSE);
|
||
|
|
||
|
return image_proxy->priv->show_all;
|
||
|
}
|
||
|
|
||
|
GeglRectangle
|
||
|
pika_image_proxy_get_bounding_box (PikaImageProxy *image_proxy)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_IMAGE_PROXY (image_proxy),
|
||
|
*GEGL_RECTANGLE (0, 0, 0, 0));
|
||
|
|
||
|
return image_proxy->priv->bounding_box;
|
||
|
}
|