From 0a2b234169b04ce3663a071f1ba8a6bb954f3160 Mon Sep 17 00:00:00 2001 From: Nexoniarz Date: Sat, 20 Jun 2026 13:02:33 +0000 Subject: [PATCH] Update and rename pikture-gimp.c to yapf-gimp.c --- extensions/gimp/pikture-gimp.c | 190 -------------------- extensions/gimp/yapf-gimp.c | 307 +++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+), 190 deletions(-) delete mode 100644 extensions/gimp/pikture-gimp.c create mode 100644 extensions/gimp/yapf-gimp.c diff --git a/extensions/gimp/pikture-gimp.c b/extensions/gimp/pikture-gimp.c deleted file mode 100644 index 754155c..0000000 --- a/extensions/gimp/pikture-gimp.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * pikture.c - * PIKTURE format plugin for GIMP. - * This plugin is designed to interface with GIMP (licensed under GPLv3). This plugin itself is an independent work and is provided under the Apache License 2.0. Users are free to use, modify, and distribute this plugin independently of GIMP's licensing terms. - * Version: 101 - * * Copyright 2026 Nexoniarz - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "pikture.c" -#include - -#define LOAD_PROC "file-pik-load" -#define SAVE_PROC "file-pik-save" - -struct _PikturePlugin { - GimpPlugIn parent_instance; -}; - -#define PIKTURE_PLUGIN_TYPE (pikture_plugin_get_type()) -G_DECLARE_FINAL_TYPE (PikturePlugin, pikture_plugin, PIKTURE, PLUGIN, GimpPlugIn) - -static GList * pikture_plugin_query_procedures (GimpPlugIn *plug_in); -static GimpProcedure * pikture_plugin_create_procedure (GimpPlugIn *plug_in, const gchar *name); - -static GimpValueArray * pikture_load_run (GimpProcedure *procedure, GimpRunMode run_mode, GFile *file, GimpMetadata *metadata, GimpMetadataLoadFlags *flags, GimpProcedureConfig *config, gpointer run_data); -static GimpValueArray * pikture_save_run (GimpProcedure *procedure, GimpRunMode run_mode, GimpImage *image, GFile *file, GimpExportOptions *options, GimpMetadata *metadata, GimpProcedureConfig *config, gpointer run_data); - -G_DEFINE_TYPE (PikturePlugin, pikture_plugin, GIMP_TYPE_PLUG_IN) - -static void pikture_plugin_class_init (PikturePluginClass *klass) { - GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass); - plug_in_class->query_procedures = pikture_plugin_query_procedures; - plug_in_class->create_procedure = pikture_plugin_create_procedure; -} - -static void pikture_plugin_init (PikturePlugin *plugin) {} - -static GList * pikture_plugin_query_procedures (GimpPlugIn *plug_in) { - GList *list = NULL; - list = g_list_append (list, g_strdup (LOAD_PROC)); - list = g_list_append (list, g_strdup (SAVE_PROC)); - return list; -} - -static GimpProcedure * pikture_plugin_create_procedure (GimpPlugIn *plug_in, const gchar *name) { - GimpProcedure *procedure = NULL; - - if (g_strcmp0 (name, LOAD_PROC) == 0) { - procedure = gimp_load_procedure_new (plug_in, name, GIMP_PDB_PROC_TYPE_PLUGIN, pikture_load_run, NULL, NULL); - gimp_procedure_set_menu_label (procedure, "PIKTURE image"); - gimp_procedure_set_documentation (procedure, "Loads a PIKTURE image", "Loads a PIKTURE image", NULL); - gimp_procedure_set_attribution (procedure, "Nexoniarz", "Nexoniarz", "2026"); - gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure), "image/x-pikture"); - gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure), "pik"); - gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure), "0,string,PIK!"); - } else if (g_strcmp0 (name, SAVE_PROC) == 0) { - procedure = gimp_export_procedure_new (plug_in, name, GIMP_PDB_PROC_TYPE_PLUGIN, TRUE, (GimpRunExportFunc) pikture_save_run, NULL, NULL); - - gimp_procedure_set_image_types (procedure, "RGB, RGBA, GRAY, GRAYA"); - - gimp_procedure_set_menu_label (procedure, "PIKTURE image"); - gimp_procedure_set_documentation (procedure, "Exports a PIKTURE image", "Exports a PIKTURE image", NULL); - gimp_procedure_set_attribution (procedure, "Nexoniarz", "Nexoniarz", "2026"); - gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure), "image/x-pikture"); - gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure), "pik"); - } - - return procedure; -} - -static GimpValueArray * pikture_load_run (GimpProcedure *procedure, GimpRunMode run_mode, GFile *file, GimpMetadata *metadata, GimpMetadataLoadFlags *flags, GimpProcedureConfig *config, gpointer run_data) { - GimpValueArray *return_vals; - gchar *filename = g_file_get_path (file); - - pikture_t *pik = pikture_load(filename); - g_free (filename); - - if (!pik) { - GError *error = g_error_new (GIMP_PLUG_IN_ERROR, 0, "Failed to load PIKTURE file."); - return gimp_procedure_new_return_values (procedure, GIMP_PDB_EXECUTION_ERROR, error); - } - - GimpImageBaseType base_type = GIMP_RGB; - GimpImageType layer_type = GIMP_RGBA_IMAGE; - const gchar* b_format = "R'G'B'A u8"; - - if (pik->channels == 1) { - base_type = GIMP_GRAY; - layer_type = GIMP_GRAY_IMAGE; - b_format = "Y' u8"; - } else if (pik->channels == 2) { - base_type = GIMP_GRAY; - layer_type = GIMP_GRAYA_IMAGE; - b_format = "Y'A u8"; - } else if (pik->channels == 3) { - base_type = GIMP_RGB; - layer_type = GIMP_RGB_IMAGE; - b_format = "R'G'B' u8"; - } - - GimpImage *image = gimp_image_new (pik->width, pik->height, base_type); - GimpLayer *layer = gimp_layer_new (image, "Background", pik->width, pik->height, layer_type, 100.0, gimp_image_get_default_new_layer_mode (image)); - gimp_image_insert_layer (image, layer, NULL, 0); - - GeglBuffer *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)); - gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, pik->width, pik->height), 0, babl_format (b_format), pik->pixels, GEGL_AUTO_ROWSTRIDE); - g_object_unref (buffer); - - pikture_free(pik); - - return_vals = gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); - g_value_set_object (gimp_value_array_index (return_vals, 1), image); - return return_vals; -} - -static GimpValueArray * pikture_save_run (GimpProcedure *procedure, GimpRunMode run_mode, GimpImage *image, GFile *file, GimpExportOptions *options, GimpMetadata *metadata, GimpProcedureConfig *config, gpointer run_data) { - gchar *filename = g_file_get_path (file); - - GimpLayer **layers = gimp_image_get_layers (image); - - if (!layers || !layers[0]) { - if (layers) g_free (layers); - g_free (filename); - GError *error = g_error_new (GIMP_PLUG_IN_ERROR, 0, "No layers to export."); - return gimp_procedure_new_return_values (procedure, GIMP_PDB_EXECUTION_ERROR, error); - } - - GimpDrawable *drawable = GIMP_DRAWABLE (layers[0]); - - pikture_t pik; - pik.width = gimp_drawable_get_width (drawable); - pik.height = gimp_drawable_get_height (drawable); - - gboolean has_alpha = gimp_drawable_has_alpha (drawable); - gboolean is_gray = gimp_drawable_is_gray (drawable); - const gchar* b_format = "R'G'B'A u8"; - - if (is_gray) { - if (has_alpha) { - pik.channels = 2; - b_format = "Y'A u8"; - } else { - pik.channels = 1; - b_format = "Y' u8"; - } - } else { - if (has_alpha) { - pik.channels = 4; - b_format = "R'G'B'A u8"; - } else { - pik.channels = 3; - b_format = "R'G'B' u8"; - } - } - - pik.depth = pik.channels * 8; - pik.pixels = malloc (pik.width * pik.height * pik.channels); - - GeglBuffer *buffer = gimp_drawable_get_buffer (drawable); - gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, pik.width, pik.height), 1.0, babl_format (b_format), pik.pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); - g_object_unref (buffer); - - int result = pikture_save(filename, &pik); - - free (pik.pixels); - g_free (filename); - g_free (layers); - - if (!result) { - GError *error = g_error_new (GIMP_PLUG_IN_ERROR, 0, "Failed to export PIKTURE file."); - return gimp_procedure_new_return_values (procedure, GIMP_PDB_EXECUTION_ERROR, error); - } - - return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL); -} - -GIMP_MAIN (PIKTURE_PLUGIN_TYPE) diff --git a/extensions/gimp/yapf-gimp.c b/extensions/gimp/yapf-gimp.c new file mode 100644 index 0000000..869b735 --- /dev/null +++ b/extensions/gimp/yapf-gimp.c @@ -0,0 +1,307 @@ +/* + * yapf-gimp.c — YAPF format plugin for GIMP. + * + * This plugin is an independent work provided under the Apache License 2.0. + * It interfaces with GIMP, which is licensed under GPLv3. Users may use, + * modify, and distribute this plugin independently of GIMP's licensing terms. + * + * Copyright 2026 Nexoniarz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ------------------------------------------------------------------------- + * + * Compilation: + * gimptool --install yapf-gimp.c + * + * yapf.c is embedded via #include below because gimptool compiles a single + * source file. Do NOT link separately — the include IS the build. + */ + +#include + +/* Pull in the entire encoder/decoder as a single translation unit. */ +#include "yapf.c" + +/* ── GIMP procedure names ────────────────────────────────────────────── */ + +#define LOAD_PROC "file-yapf-load" +#define SAVE_PROC "file-yapf-save" + +/* ── Plugin type boilerplate ─────────────────────────────────────────── */ + +struct _YapfPlugin { GimpPlugIn parent_instance; }; + +#define YAPF_PLUGIN_TYPE (yapf_plugin_get_type()) +G_DECLARE_FINAL_TYPE(YapfPlugin, yapf_plugin, YAPF, PLUGIN, GimpPlugIn) + +static GList *yapf_plugin_query_procedures (GimpPlugIn *plug_in); +static GimpProcedure *yapf_plugin_create_procedure (GimpPlugIn *plug_in, + const gchar *name); + +static GimpValueArray *yapf_load_run (GimpProcedure *procedure, + GimpRunMode run_mode, + GFile *file, + GimpMetadata *metadata, + GimpMetadataLoadFlags *flags, + GimpProcedureConfig *config, + gpointer run_data); +static GimpValueArray *yapf_save_run (GimpProcedure *procedure, + GimpRunMode run_mode, + GimpImage *image, + GFile *file, + GimpExportOptions *options, + GimpMetadata *metadata, + GimpProcedureConfig *config, + gpointer run_data); + +G_DEFINE_TYPE(YapfPlugin, yapf_plugin, GIMP_TYPE_PLUG_IN) + +static void yapf_plugin_class_init(YapfPluginClass *klass) { + GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS(klass); + plug_in_class->query_procedures = yapf_plugin_query_procedures; + plug_in_class->create_procedure = yapf_plugin_create_procedure; +} + +static void yapf_plugin_init(YapfPlugin *plugin) { (void)plugin; } + +/* ── Procedure list ──────────────────────────────────────────────────── */ + +static GList *yapf_plugin_query_procedures(GimpPlugIn *plug_in) { + (void)plug_in; + GList *list = NULL; + list = g_list_append(list, g_strdup(LOAD_PROC)); + list = g_list_append(list, g_strdup(SAVE_PROC)); + return list; +} + +/* ── Procedure creation ──────────────────────────────────────────────── */ + +static GimpProcedure *yapf_plugin_create_procedure(GimpPlugIn *plug_in, + const gchar *name) { + GimpProcedure *procedure = NULL; + + if (g_strcmp0(name, LOAD_PROC) == 0) { + procedure = gimp_load_procedure_new(plug_in, name, + GIMP_PDB_PROC_TYPE_PLUGIN, + yapf_load_run, NULL, NULL); + gimp_procedure_set_menu_label(procedure, "YAPF image"); + gimp_procedure_set_documentation(procedure, + "Loads a YAPF (Yet Another Picture Format) image", + "Loads a YAPF image from disk", NULL); + gimp_procedure_set_attribution(procedure, + "Nexoniarz", "Nexoniarz", "2026"); + gimp_file_procedure_set_mime_types(GIMP_FILE_PROCEDURE(procedure), + "image/x-yapf"); + gimp_file_procedure_set_extensions(GIMP_FILE_PROCEDURE(procedure), + "yapf"); + gimp_file_procedure_set_magics(GIMP_FILE_PROCEDURE(procedure), + "0,string,YAPF"); + + } else if (g_strcmp0(name, SAVE_PROC) == 0) { + procedure = gimp_export_procedure_new(plug_in, name, + GIMP_PDB_PROC_TYPE_PLUGIN, TRUE, + (GimpRunExportFunc)yapf_save_run, NULL, NULL); + gimp_procedure_set_image_types(procedure, "RGB, RGBA, GRAY, GRAYA"); + gimp_procedure_set_menu_label(procedure, "YAPF image"); + gimp_procedure_set_documentation(procedure, + "Exports a YAPF (Yet Another Picture Format) image", + "Exports a YAPF image to disk", NULL); + gimp_procedure_set_attribution(procedure, + "Nexoniarz", "Nexoniarz", "2026"); + gimp_file_procedure_set_mime_types(GIMP_FILE_PROCEDURE(procedure), + "image/x-yapf"); + gimp_file_procedure_set_extensions(GIMP_FILE_PROCEDURE(procedure), + "yapf"); + } + + return procedure; +} + +/* ── Load handler ────────────────────────────────────────────────────── */ + +static GimpValueArray *yapf_load_run( + GimpProcedure *procedure, + GimpRunMode run_mode, + GFile *file, + GimpMetadata *metadata, + GimpMetadataLoadFlags *flags, + GimpProcedureConfig *config, + gpointer run_data) +{ + (void)run_mode; (void)metadata; (void)flags; (void)config; (void)run_data; + + gchar *path = g_file_get_path(file); + yapf_image_t *img = yapf_load(path); + g_free(path); + + if (!img) { + GError *err = g_error_new(GIMP_PLUG_IN_ERROR, 0, + "Failed to load YAPF file."); + return gimp_procedure_new_return_values(procedure, + GIMP_PDB_EXECUTION_ERROR, err); + } + + /* Map YAPF channel count to GIMP image / layer types. + * Use gamma-corrected babl formats (R'G'B') when the file carries the + * sRGB flag; fall back to linear (RGB) otherwise. */ + gboolean is_srgb = (img->flags & YAPF_FLAG_SRGB) != 0; + GimpImageBaseType base_type = GIMP_RGB; + GimpImageType layer_type = GIMP_RGBA_IMAGE; + const gchar *babl_fmt = is_srgb ? "R'G'B'A u8" : "RGBA u8"; + + switch (img->channels) { + case YAPF_CHANNELS_GRAY: + base_type = GIMP_GRAY; + layer_type = GIMP_GRAY_IMAGE; + babl_fmt = "Y' u8"; + break; + case YAPF_CHANNELS_GRAY_ALPHA: + base_type = GIMP_GRAY; + layer_type = GIMP_GRAYA_IMAGE; + babl_fmt = "Y'A u8"; + break; + case YAPF_CHANNELS_RGB: + base_type = GIMP_RGB; + layer_type = GIMP_RGB_IMAGE; + babl_fmt = is_srgb ? "R'G'B' u8" : "RGB u8"; + break; + default: /* RGBA */ + break; + } + + GimpImage *image = gimp_image_new(img->width, img->height, base_type); + GimpLayer *layer = gimp_layer_new(image, "Background", + img->width, img->height, layer_type, + 100.0, + gimp_image_get_default_new_layer_mode(image)); + gimp_image_insert_layer(image, layer, NULL, 0); + + GeglBuffer *buffer = gimp_drawable_get_buffer(GIMP_DRAWABLE(layer)); + gegl_buffer_set(buffer, + GEGL_RECTANGLE(0, 0, (gint)img->width, (gint)img->height), + 0, babl_format(babl_fmt), + img->pixels, GEGL_AUTO_ROWSTRIDE); + g_object_unref(buffer); + + yapf_free(img); + + GimpValueArray *ret = gimp_procedure_new_return_values(procedure, + GIMP_PDB_SUCCESS, NULL); + g_value_set_object(gimp_value_array_index(ret, 1), image); + return ret; +} + +/* ── Save handler ────────────────────────────────────────────────────── */ + +static GimpValueArray *yapf_save_run( + GimpProcedure *procedure, + GimpRunMode run_mode, + GimpImage *image, + GFile *file, + GimpExportOptions *options, + GimpMetadata *metadata, + GimpProcedureConfig *config, + gpointer run_data) +{ + (void)run_mode; (void)options; (void)metadata; (void)config; (void)run_data; + + /* Retrieve the top-most layer. */ + GimpLayer **layers = gimp_image_get_layers(image); + gint n_layers = 0; + if (layers) { while (layers[n_layers]) n_layers++; } + + if (!layers || n_layers == 0) { + g_free(layers); + GError *err = g_error_new(GIMP_PLUG_IN_ERROR, 0, + "No layers to export."); + return gimp_procedure_new_return_values(procedure, + GIMP_PDB_EXECUTION_ERROR, err); + } + + GimpDrawable *drawable = GIMP_DRAWABLE(layers[0]); + g_free(layers); + + /* Determine channel layout and GPU format hint. */ + gboolean has_alpha = gimp_drawable_has_alpha(drawable); + gboolean is_gray = gimp_drawable_is_gray(drawable); + const gchar *babl_fmt; + uint8_t ch; + uint8_t gpu_fmt; + uint8_t flags = YAPF_FLAG_SRGB; /* GIMP's native u8 formats are sRGB */ + + if (is_gray) { + if (has_alpha) { + ch = YAPF_CHANNELS_GRAY_ALPHA; babl_fmt = "Y'A u8"; + gpu_fmt = YAPF_GPU_RG8; + flags = 0; /* grayscale has no sRGB GPU hint */ + } else { + ch = YAPF_CHANNELS_GRAY; babl_fmt = "Y' u8"; + gpu_fmt = YAPF_GPU_R8; + flags = 0; + } + } else { + if (has_alpha) { + ch = YAPF_CHANNELS_RGBA; babl_fmt = "R'G'B'A u8"; + gpu_fmt = YAPF_GPU_SRGB8_A8; + } else { + ch = YAPF_CHANNELS_RGB; babl_fmt = "R'G'B' u8"; + gpu_fmt = YAPF_GPU_SRGB8; + } + } + + gint w = gimp_drawable_get_width(drawable); + gint h = gimp_drawable_get_height(drawable); + + /* Read pixel data from GIMP's buffer. */ + uint8_t *pixels = (uint8_t *)malloc((size_t)w * (size_t)h * ch); + if (!pixels) { + GError *err = g_error_new(GIMP_PLUG_IN_ERROR, 0, "Out of memory."); + return gimp_procedure_new_return_values(procedure, + GIMP_PDB_EXECUTION_ERROR, err); + } + + GeglBuffer *buffer = gimp_drawable_get_buffer(drawable); + gegl_buffer_get(buffer, + GEGL_RECTANGLE(0, 0, w, h), + 1.0, babl_format(babl_fmt), + pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + g_object_unref(buffer); + + /* Build yapf_image_t — base level only, no mip chain from GIMP. */ + yapf_image_t img; + img.width = (uint32_t)w; + img.height = (uint32_t)h; + img.channels = ch; + img.gpu_format = gpu_fmt; + img.flags = flags; + img.mip_levels = 1; + img.pixels = pixels; + img.mips = NULL; + + gchar *path = g_file_get_path(file); + int result = yapf_save(path, &img); + g_free(path); + free(pixels); + + if (result != YAPF_OK) { + GError *err = g_error_new(GIMP_PLUG_IN_ERROR, 0, + "Failed to export YAPF file."); + return gimp_procedure_new_return_values(procedure, + GIMP_PDB_EXECUTION_ERROR, err); + } + + return gimp_procedure_new_return_values(procedure, GIMP_PDB_SUCCESS, NULL); +} + +GIMP_MAIN(YAPF_PLUGIN_TYPE)