/* 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 * * pikaoperationprofiletransform.c * Copyright (C) 2016 Michael Natterer * * 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 . */ #include "config.h" #include #include #include #include "libpikaconfig/pikaconfig.h" #include "libpikacolor/pikacolor.h" #include "operations-types.h" #include "pikaoperationprofiletransform.h" enum { PROP_0, PROP_SRC_PROFILE, PROP_SRC_FORMAT, PROP_DEST_PROFILE, PROP_DEST_FORMAT, PROP_RENDERING_INTENT, PROP_BLACK_POINT_COMPENSATION }; static void pika_operation_profile_transform_finalize (GObject *object); static void pika_operation_profile_transform_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); static void pika_operation_profile_transform_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void pika_operation_profile_transform_prepare (GeglOperation *operation); static gboolean pika_operation_profile_transform_process (GeglOperation *operation, void *in_buf, void *out_buf, glong samples, const GeglRectangle *roi, gint level); G_DEFINE_TYPE (PikaOperationProfileTransform, pika_operation_profile_transform, GEGL_TYPE_OPERATION_POINT_FILTER) #define parent_class pika_operation_profile_transform_parent_class static void pika_operation_profile_transform_class_init (PikaOperationProfileTransformClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); object_class->finalize = pika_operation_profile_transform_finalize; object_class->set_property = pika_operation_profile_transform_set_property; object_class->get_property = pika_operation_profile_transform_get_property; gegl_operation_class_set_keys (operation_class, "name", "pika:profile-transform", "categories", "color", "description", "Transform between two color profiles", NULL); operation_class->prepare = pika_operation_profile_transform_prepare; point_class->process = pika_operation_profile_transform_process; g_object_class_install_property (object_class, PROP_SRC_PROFILE, g_param_spec_object ("src-profile", "Source Profile", "Source Profile", PIKA_TYPE_COLOR_PROFILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_SRC_FORMAT, g_param_spec_pointer ("src-format", "Source Format", "Source Format", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_DEST_PROFILE, g_param_spec_object ("dest-profile", "Destination Profile", "Destination Profile", PIKA_TYPE_COLOR_PROFILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_DEST_FORMAT, g_param_spec_pointer ("dest-format", "Destination Format", "Destination Format", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_RENDERING_INTENT, g_param_spec_enum ("rendering-intent", "Rendering Intent", "Rendering Intent", PIKA_TYPE_COLOR_RENDERING_INTENT, PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_BLACK_POINT_COMPENSATION, g_param_spec_boolean ("black-point-compensation", "Black Point Compensation", "Black Point Compensation", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); } static void pika_operation_profile_transform_init (PikaOperationProfileTransform *self) { } static void pika_operation_profile_transform_finalize (GObject *object) { PikaOperationProfileTransform *self = PIKA_OPERATION_PROFILE_TRANSFORM (object); g_clear_object (&self->src_profile); g_clear_object (&self->dest_profile); g_clear_object (&self->transform); G_OBJECT_CLASS (parent_class)->finalize (object); } static void pika_operation_profile_transform_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { PikaOperationProfileTransform *self = PIKA_OPERATION_PROFILE_TRANSFORM (object); switch (property_id) { case PROP_SRC_PROFILE: g_value_set_object (value, self->src_profile); break; case PROP_SRC_FORMAT: g_value_set_pointer (value, (gpointer) self->src_format); break; case PROP_DEST_PROFILE: g_value_set_object (value, self->dest_profile); break; case PROP_DEST_FORMAT: g_value_set_pointer (value, (gpointer) self->dest_format); break; case PROP_RENDERING_INTENT: g_value_set_enum (value, self->rendering_intent); break; case PROP_BLACK_POINT_COMPENSATION: g_value_set_boolean (value, self->black_point_compensation); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void pika_operation_profile_transform_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { PikaOperationProfileTransform *self = PIKA_OPERATION_PROFILE_TRANSFORM (object); switch (property_id) { case PROP_SRC_PROFILE: if (self->src_profile) g_object_unref (self->src_profile); self->src_profile = g_value_dup_object (value); break; case PROP_SRC_FORMAT: self->src_format = g_value_get_pointer (value); break; case PROP_DEST_PROFILE: if (self->dest_profile) g_object_unref (self->dest_profile); self->dest_profile = g_value_dup_object (value); break; case PROP_DEST_FORMAT: self->dest_format = g_value_get_pointer (value); break; case PROP_RENDERING_INTENT: self->rendering_intent = g_value_get_enum (value); break; case PROP_BLACK_POINT_COMPENSATION: self->black_point_compensation = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void pika_operation_profile_transform_prepare (GeglOperation *operation) { PikaOperationProfileTransform *self = PIKA_OPERATION_PROFILE_TRANSFORM (operation); g_clear_object (&self->transform); if (! self->src_format) self->src_format = babl_format ("RGBA float"); if (! self->dest_format) self->dest_format = babl_format ("RGBA float"); if (self->src_profile && self->dest_profile) { PikaColorTransformFlags flags = 0; if (self->black_point_compensation) flags |= PIKA_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION; flags |= PIKA_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE; self->transform = pika_color_transform_new (self->src_profile, self->src_format, self->dest_profile, self->dest_format, self->rendering_intent, flags); } gegl_operation_set_format (operation, "input", self->src_format); gegl_operation_set_format (operation, "output", self->dest_format); } static gboolean pika_operation_profile_transform_process (GeglOperation *operation, void *in_buf, void *out_buf, glong samples, const GeglRectangle *roi, gint level) { PikaOperationProfileTransform *self = PIKA_OPERATION_PROFILE_TRANSFORM (operation); gpointer *src = in_buf; gpointer *dest = out_buf; if (self->transform) { pika_color_transform_process_pixels (self->transform, self->src_format, src, self->dest_format, dest, samples); } else { babl_process (babl_fish (self->src_format, self->dest_format), src, dest, samples); } return TRUE; }