PIKApp/libpika/pikadrawable.c

437 lines
14 KiB
C

/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikadrawable.c
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "pika.h"
#include "pikapixbuf.h"
#include "pikatilebackendplugin.h"
G_DEFINE_ABSTRACT_TYPE (PikaDrawable, pika_drawable, PIKA_TYPE_ITEM)
#define parent_class pika_drawable_parent_class
static void
pika_drawable_class_init (PikaDrawableClass *klass)
{
}
static void
pika_drawable_init (PikaDrawable *drawable)
{
}
/* Public API. */
/**
* pika_drawable_get_by_id:
* @drawable_id: The drawable id.
*
* Returns a #PikaDrawable representing @drawable_id. This function
* calls pika_item_get_by_id() and returns the item if it is drawable
* or %NULL otherwise.
*
* Returns: (nullable) (transfer none): a #PikaDrawable for
* @drawable_id or %NULL if @drawable_id does not represent a
* valid drawable. The object belongs to libpika and you must
* not modify or unref it.
*
* Since: 3.0
**/
PikaDrawable *
pika_drawable_get_by_id (gint32 drawable_id)
{
PikaItem *item = pika_item_get_by_id (drawable_id);
if (PIKA_IS_DRAWABLE (item))
return (PikaDrawable *) item;
return NULL;
}
/**
* pika_drawable_get_thumbnail_data:
* @drawable: the drawable
* @width: the requested thumbnail width (<= 1024 pixels)
* @height: the requested thumbnail height (<= 1024 pixels)
* @actual_width: (out): the resulting thumbnail's actual width
* @actual_height: (out): the resulting thumbnail's actual height
* @bpp: (out): the bytes per pixel of the returned thubmnail data
*
* Retrieves thumbnail data for the drawable identified by @drawable.
* The thumbnail will be not larger than the requested size.
*
* Returns: (transfer full) (nullable): thumbnail data or %NULL if
* @drawable is invalid.
**/
GBytes *
pika_drawable_get_thumbnail_data (PikaDrawable *drawable,
gint width,
gint height,
gint *actual_width,
gint *actual_height,
gint *bpp)
{
GBytes *image_data;
g_return_val_if_fail (actual_width != NULL, NULL);
g_return_val_if_fail (actual_height != NULL, NULL);
g_return_val_if_fail (bpp != NULL, NULL);
_pika_drawable_thumbnail (drawable,
width,
height,
actual_width,
actual_height,
bpp,
&image_data);
return image_data;
}
/**
* pika_drawable_get_thumbnail:
* @drawable: the drawable
* @width: the requested thumbnail width (<= 1024 pixels)
* @height: the requested thumbnail height (<= 1024 pixels)
* @alpha: how to handle an alpha channel
*
* Retrieves a thumbnail pixbuf for the drawable identified by
* @drawable. The thumbnail will be not larger than the requested
* size.
*
* Returns: (transfer full): a new #GdkPixbuf
*
* Since: 2.2
**/
GdkPixbuf *
pika_drawable_get_thumbnail (PikaDrawable *drawable,
gint width,
gint height,
PikaPixbufTransparency alpha)
{
gint thumb_width, thumb_height, thumb_bpp;
GBytes *data;
gsize data_size;
GdkPixbuf *pixbuf = NULL;
g_return_val_if_fail (width > 0 && width <= 1024, NULL);
g_return_val_if_fail (height > 0 && height <= 1024, NULL);
data = pika_drawable_get_thumbnail_data (drawable,
width,
height,
&thumb_width,
&thumb_height,
&thumb_bpp);
if (data)
pixbuf = _pika_pixbuf_from_data (g_bytes_unref_to_data (data, &data_size),
thumb_width, thumb_height, thumb_bpp,
alpha);
return pixbuf;
}
/**
* pika_drawable_get_sub_thumbnail_data:
* @drawable: the drawable ID
* @src_x: the x coordinate of the area
* @src_y: the y coordinate of the area
* @src_width: the width of the area
* @src_height: the height of the area
* @dest_width: the requested thumbnail width (<= 1024 pixels)
* @dest_height: the requested thumbnail height (<= 1024 pixels)
* @actual_width: (out): the width of the returned thumbnail
* @actual_height: (out): the height of the returned thumbnail
* @bpp: (out): the bytes per pixel of the returned thumbnail data
*
* Retrieves thumbnail data for the drawable identified by @drawable.
* The thumbnail will be not larger than the requested size.
*
* Returns: (transfer full): thumbnail data or %NULL if
* @drawable is invalid.
**/
GBytes *
pika_drawable_get_sub_thumbnail_data (PikaDrawable *drawable,
gint src_x,
gint src_y,
gint src_width,
gint src_height,
gint dest_width,
gint dest_height,
gint *actual_width,
gint *actual_height,
gint *bpp)
{
GBytes *image_bytes;
_pika_drawable_sub_thumbnail (drawable,
src_x, src_y,
src_width, src_height,
dest_width,
dest_height,
actual_width,
actual_height,
bpp,
&image_bytes);
return image_bytes;
}
/**
* pika_drawable_get_sub_thumbnail:
* @drawable: the drawable ID
* @src_x: the x coordinate of the area
* @src_y: the y coordinate of the area
* @src_width: the width of the area
* @src_height: the height of the area
* @dest_width: the requested thumbnail width (<= 1024 pixels)
* @dest_height: the requested thumbnail height (<= 1024 pixels)
* @alpha: how to handle an alpha channel
*
* Retrieves a thumbnail pixbuf for the drawable identified by
* @drawable. The thumbnail will be not larger than the requested
* size.
*
* Returns: (transfer full): a new #GdkPixbuf
*
* Since: 2.2
**/
GdkPixbuf *
pika_drawable_get_sub_thumbnail (PikaDrawable *drawable,
gint src_x,
gint src_y,
gint src_width,
gint src_height,
gint dest_width,
gint dest_height,
PikaPixbufTransparency alpha)
{
gint thumb_width = dest_width;
gint thumb_height = dest_height;
gint thumb_bpp;
GBytes *data;
gsize data_size;
GdkPixbuf *pixbuf = NULL;
g_return_val_if_fail (src_x >= 0, NULL);
g_return_val_if_fail (src_y >= 0, NULL);
g_return_val_if_fail (src_width > 0, NULL);
g_return_val_if_fail (src_height > 0, NULL);
g_return_val_if_fail (dest_width > 0 && dest_width <= 1024, NULL);
g_return_val_if_fail (dest_height > 0 && dest_height <= 1024, NULL);
data = pika_drawable_get_sub_thumbnail_data (drawable,
src_x, src_y,
src_width, src_height,
dest_width, dest_height,
&thumb_width,
&thumb_height,
&thumb_bpp);
if (data)
pixbuf = _pika_pixbuf_from_data (g_bytes_unref_to_data (data, &data_size),
thumb_width, thumb_height, thumb_bpp,
alpha);
g_bytes_unref (data);
return pixbuf;
}
/**
* pika_drawable_get_buffer:
* @drawable: the ID of the #PikaDrawable to get the buffer for.
*
* Returns a #GeglBuffer of a specified drawable. The buffer can be used
* like any other GEGL buffer. Its data will we synced back with the core
* drawable when the buffer gets destroyed, or when gegl_buffer_flush()
* is called.
*
* Returns: (transfer full): The #GeglBuffer.
*
* See Also: pika_drawable_get_shadow_buffer()
*
* Since: 2.10
*/
GeglBuffer *
pika_drawable_get_buffer (PikaDrawable *drawable)
{
if (pika_item_is_valid (PIKA_ITEM (drawable)))
{
GeglTileBackend *backend;
GeglBuffer *buffer;
backend = _pika_tile_backend_plugin_new (drawable, FALSE);
buffer = gegl_buffer_new_for_backend (NULL, backend);
g_object_unref (backend);
return buffer;
}
return NULL;
}
/**
* pika_drawable_get_shadow_buffer:
* @drawable: the ID of the #PikaDrawable to get the buffer for.
*
* Returns a #GeglBuffer of a specified drawable's shadow tiles. The
* buffer can be used like any other GEGL buffer. Its data will we
* synced back with the core drawable's shadow tiles when the buffer
* gets destroyed, or when gegl_buffer_flush() is called.
*
* Returns: (transfer full): The #GeglBuffer.
*
* Since: 2.10
*/
GeglBuffer *
pika_drawable_get_shadow_buffer (PikaDrawable *drawable)
{
if (pika_item_is_valid (PIKA_ITEM (drawable)))
{
GeglTileBackend *backend;
GeglBuffer *buffer;
backend = _pika_tile_backend_plugin_new (drawable, TRUE);
buffer = gegl_buffer_new_for_backend (NULL, backend);
g_object_unref (backend);
return buffer;
}
return NULL;
}
/**
* pika_drawable_get_format:
* @drawable: the ID of the #PikaDrawable to get the format for.
*
* Returns the #Babl format of the drawable.
*
* Returns: The #Babl format.
*
* Since: 2.10
*/
const Babl *
pika_drawable_get_format (PikaDrawable *drawable)
{
const Babl *format = NULL;
gchar *format_str = _pika_drawable_get_format (drawable);
/* _pika_drawable_get_format() only returns the encoding, so we
* create the actual space from the image's profile
*/
if (format_str)
{
const Babl *space = NULL;
PikaImage *image = pika_item_get_image (PIKA_ITEM (drawable));
if (pika_item_is_layer (PIKA_ITEM (drawable)))
{
PikaColorProfile *profile = pika_image_get_color_profile (image);
if (profile)
{
GError *error = NULL;
space = pika_color_profile_get_space
(profile,
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
&error);
if (! space)
{
g_printerr ("%s: failed to create Babl space from "
"profile: %s\n",
G_STRFUNC, error->message);
g_clear_error (&error);
}
g_object_unref (profile);
}
}
if (pika_drawable_is_indexed (drawable))
{
const Babl *palette;
const Babl *palette_alpha;
guchar *colormap;
gint colormap_len, n_colors;
babl_new_palette_with_space (format_str, space,
&palette, &palette_alpha);
if (pika_drawable_has_alpha (drawable))
format = palette_alpha;
else
format = palette;
colormap = pika_image_get_colormap (image, &colormap_len, &n_colors);
if (colormap)
{
babl_palette_set_palette (format,
babl_format_with_space ("R'G'B' u8",
space),
colormap, n_colors);
g_free (colormap);
}
}
else
{
format = babl_format_with_space (format_str, space);
}
g_free (format_str);
}
return format;
}
/**
* pika_drawable_get_thumbnail_format:
* @drawable: the ID of the #PikaDrawable to get the thumbnail format for.
*
* Returns the #Babl thumbnail format of the drawable.
*
* Returns: The #Babl thumbnail format.
*
* Since: 2.10.14
*/
const Babl *
pika_drawable_get_thumbnail_format (PikaDrawable *drawable)
{
const Babl *format = NULL;
gchar *format_str = _pika_drawable_get_thumbnail_format (drawable);
if (format_str)
{
format = babl_format (format_str);
g_free (format_str);
}
return format;
}