Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

View File

@ -0,0 +1,431 @@
/* 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
*
* 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 "libpikaconfig/pikaconfig.h"
#include "core/core-types.h"
#include "core/pika.h"
#include "core/pikabrush.h"
#include "core/pikabrush-load.h"
#include "core/pikabrush-private.h"
#include "core/pikadrawable.h"
#include "core/pikaimage.h"
#include "core/pikalayer-new.h"
#include "core/pikaimage-resize.h"
#include "core/pikaparamspecs.h"
#include "core/pikatempbuf.h"
#include "pdb/pikaprocedure.h"
#include "file-data-gbr.h"
#include "pika-intl.h"
/* local function prototypes */
static PikaImage * file_gbr_brush_to_image (Pika *pika,
PikaBrush *brush);
static PikaBrush * file_gbr_image_to_brush (PikaImage *image,
PikaDrawable *drawable,
const gchar *name,
gdouble spacing);
/* public functions */
PikaValueArray *
file_gbr_load_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
PikaValueArray *return_vals;
PikaImage *image = NULL;
GFile *file;
GInputStream *input;
GError *my_error = NULL;
pika_set_busy (pika);
file = g_value_get_object (pika_value_array_index (args, 1));
input = G_INPUT_STREAM (g_file_read (file, NULL, &my_error));
if (input)
{
PikaBrush *brush = pika_brush_load_brush (context, file, input, error);
if (brush)
{
image = file_gbr_brush_to_image (pika, brush);
g_object_unref (brush);
}
g_object_unref (input);
}
else
{
g_propagate_prefixed_error (error, my_error,
_("Could not open '%s' for reading: "),
pika_file_get_utf8_name (file));
}
return_vals = pika_procedure_get_return_values (procedure, image != NULL,
error ? *error : NULL);
if (image)
g_value_set_object (pika_value_array_index (return_vals, 1), image);
pika_unset_busy (pika);
return return_vals;
}
PikaValueArray *
file_gbr_save_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
PikaValueArray *return_vals;
PikaImage *image;
PikaDrawable *drawable;
PikaBrush *brush;
const gchar *name;
GFile *file;
gint spacing;
gboolean success;
pika_set_busy (pika);
image = g_value_get_object (pika_value_array_index (args, 1));
drawable = g_value_get_object (pika_value_array_index (args, 2));
file = g_value_get_object (pika_value_array_index (args, 3));
spacing = g_value_get_int (pika_value_array_index (args, 4));
name = g_value_get_string (pika_value_array_index (args, 5));
brush = file_gbr_image_to_brush (image, drawable, name, spacing);
pika_data_set_file (PIKA_DATA (brush), file, TRUE, TRUE);
success = pika_data_save (PIKA_DATA (brush), error);
g_object_unref (brush);
return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
pika_unset_busy (pika);
return return_vals;
}
PikaLayer *
file_gbr_brush_to_layer (PikaImage *image,
PikaBrush *brush)
{
PikaLayer *layer;
const Babl *format;
gboolean alpha;
gint width;
gint height;
gint image_width;
gint image_height;
PikaTempBuf *mask;
PikaTempBuf *pixmap;
GeglBuffer *buffer;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (PIKA_IS_BRUSH (brush), NULL);
mask = pika_brush_get_mask (brush);
pixmap = pika_brush_get_pixmap (brush);
if (pixmap)
alpha = TRUE;
else
alpha = FALSE;
width = pika_temp_buf_get_width (mask);
height = pika_temp_buf_get_height (mask);
image_width = pika_image_get_width (image);
image_height = pika_image_get_height (image);
if (width > image_width || height > image_height)
{
gint new_width = MAX (image_width, width);
gint new_height = MAX (image_height, height);
pika_image_resize (image, pika_get_user_context (image->pika),
new_width, new_height,
(new_width - image_width) / 2,
(new_height - image_height) / 2,
NULL);
image_width = new_width;
image_height = new_height;
}
format = pika_image_get_layer_format (image, alpha);
layer = pika_layer_new (image, width, height, format,
pika_object_get_name (brush),
1.0, PIKA_LAYER_MODE_NORMAL);
pika_item_set_offset (PIKA_ITEM (layer),
(image_width - width) / 2,
(image_height - height) / 2);
buffer = pika_drawable_get_buffer (PIKA_DRAWABLE (layer));
if (pixmap)
{
guchar *pixmap_data;
guchar *mask_data;
guchar *p;
guchar *m;
gint i;
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
babl_format ("R'G'B' u8"),
pika_temp_buf_get_data (pixmap), GEGL_AUTO_ROWSTRIDE);
pixmap_data = gegl_buffer_linear_open (buffer, NULL, NULL, NULL);
mask_data = pika_temp_buf_get_data (mask);
for (i = 0, p = pixmap_data, m = mask_data;
i < width * height;
i++, p += 4, m += 1)
{
p[3] = *m;
}
gegl_buffer_linear_close (buffer, pixmap_data);
}
else
{
guchar *mask_data = pika_temp_buf_get_data (mask);
gint i;
for (i = 0; i < width * height; i++)
mask_data[i] = 255 - mask_data[i];
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
babl_format ("Y' u8"),
mask_data, GEGL_AUTO_ROWSTRIDE);
}
return layer;
}
PikaBrush *
file_gbr_drawable_to_brush (PikaDrawable *drawable,
const GeglRectangle *rect,
const gchar *name,
gdouble spacing)
{
PikaBrush *brush;
GeglBuffer *buffer;
PikaTempBuf *mask;
PikaTempBuf *pixmap = NULL;
gint width;
gint height;
g_return_val_if_fail (PIKA_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail (rect != NULL, NULL);
buffer = pika_drawable_get_buffer (drawable);
width = rect->width;
height = rect->height;
brush = g_object_new (PIKA_TYPE_BRUSH,
"name", name,
"mime-type", "image/x-pika-gbr",
"spacing", spacing,
NULL);
mask = pika_temp_buf_new (width, height, babl_format ("Y u8"));
if (pika_drawable_is_gray (drawable))
{
guchar *m = pika_temp_buf_get_data (mask);
gint i;
if (pika_drawable_has_alpha (drawable))
{
GeglBufferIterator *iter;
PikaRGB white;
pika_rgba_set_uchar (&white, 255, 255, 255, 255);
iter = gegl_buffer_iterator_new (buffer, rect, 0,
babl_format ("Y'A u8"),
GEGL_ACCESS_READ, GEGL_ABYSS_NONE,
1);
while (gegl_buffer_iterator_next (iter))
{
guint8 *data = (guint8 *) iter->items[0].data;
gint j;
for (j = 0; j < iter->length; j++)
{
PikaRGB gray;
gint x, y;
gint dest;
pika_rgba_set_uchar (&gray,
data[0], data[0], data[0],
data[1]);
pika_rgb_composite (&gray, &white,
PIKA_RGB_COMPOSITE_BEHIND);
x = iter->items[0].roi.x + j % iter->items[0].roi.width;
y = iter->items[0].roi.y + j / iter->items[0].roi.width;
dest = y * width + x;
pika_rgba_get_uchar (&gray, &m[dest], NULL, NULL, NULL);
data += 2;
}
}
}
else
{
gegl_buffer_get (buffer, rect, 1.0,
babl_format ("Y' u8"), m,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
}
/* invert */
for (i = 0; i < width * height; i++)
m[i] = 255 - m[i];
}
else
{
pixmap = pika_temp_buf_new (width, height, babl_format ("R'G'B' u8"));
gegl_buffer_get (buffer, rect, 1.0,
babl_format ("R'G'B' u8"),
pika_temp_buf_get_data (pixmap),
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gegl_buffer_get (buffer, rect, 1.0,
babl_format ("A u8"),
pika_temp_buf_get_data (mask),
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
}
brush->priv->mask = mask;
brush->priv->pixmap = pixmap;
return brush;
}
/* private functions */
static PikaImage *
file_gbr_brush_to_image (Pika *pika,
PikaBrush *brush)
{
PikaImage *image;
PikaLayer *layer;
PikaImageBaseType base_type;
gint width;
gint height;
PikaTempBuf *mask = pika_brush_get_mask (brush);
PikaTempBuf *pixmap = pika_brush_get_pixmap (brush);
GString *string;
PikaConfigWriter *writer;
PikaParasite *parasite;
if (pixmap)
base_type = PIKA_RGB;
else
base_type = PIKA_GRAY;
width = pika_temp_buf_get_width (mask);
height = pika_temp_buf_get_height (mask);
image = pika_image_new (pika, width, height, base_type,
PIKA_PRECISION_U8_NON_LINEAR);
string = g_string_new (NULL);
writer = pika_config_writer_new_from_string (string);
pika_config_writer_open (writer, "spacing");
pika_config_writer_printf (writer, "%d", pika_brush_get_spacing (brush));
pika_config_writer_close (writer);
pika_config_writer_linefeed (writer);
pika_config_writer_open (writer, "description");
pika_config_writer_string (writer, pika_object_get_name (brush));
pika_config_writer_close (writer);
pika_config_writer_finish (writer, NULL, NULL);
parasite = pika_parasite_new ("PikaProcedureConfig-file-gbr-save-last",
PIKA_PARASITE_PERSISTENT,
string->len + 1, string->str);
pika_image_parasite_attach (image, parasite, FALSE);
pika_parasite_free (parasite);
g_string_free (string, TRUE);
layer = file_gbr_brush_to_layer (image, brush);
pika_image_add_layer (image, layer, NULL, 0, FALSE);
return image;
}
static PikaBrush *
file_gbr_image_to_brush (PikaImage *image,
PikaDrawable *drawable,
const gchar *name,
gdouble spacing)
{
gint width = pika_item_get_width (PIKA_ITEM (drawable));
gint height = pika_item_get_height (PIKA_ITEM (drawable));
return file_gbr_drawable_to_brush (drawable,
GEGL_RECTANGLE (0, 0, width, height),
name, spacing);
}

View File

@ -0,0 +1,48 @@
/* 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
*
* 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/>.
*/
#ifndef __FILE_DATA_GBR_H__
#define __FILE_DATA_GBR_H__
PikaValueArray * file_gbr_load_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error);
PikaValueArray * file_gbr_save_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error);
PikaLayer * file_gbr_brush_to_layer (PikaImage *image,
PikaBrush *brush);
PikaBrush * file_gbr_drawable_to_brush (PikaDrawable *drawable,
const GeglRectangle *rect,
const gchar *name,
gdouble spacing);
#endif /* __FILE_DATA_GBR_H__ */

View File

@ -0,0 +1,572 @@
/* 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
* 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 <appstream-glib.h>
#include <archive.h>
#include <archive_entry.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include <glib.h>
#include <zlib.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "core/core-types.h"
#include "core/pika.h"
#include "core/pikabrush.h"
#include "core/pikabrush-load.h"
#include "core/pikabrush-private.h"
#include "core/pikadrawable.h"
#include "core/pikaextension.h"
#include "core/pikaextensionmanager.h"
#include "core/pikaextension-error.h"
#include "core/pikaimage.h"
#include "core/pikalayer-new.h"
#include "core/pikaparamspecs.h"
#include "core/pikatempbuf.h"
#include "core/pika-utils.h"
#include "pdb/pikaprocedure.h"
#include "file-data-gex.h"
#include "pika-intl.h"
/* local function prototypes */
typedef struct
{
GInputStream *input;
void *buffer;
} GexReadData;
static int file_gex_open_callback (struct archive *a,
void *client_data);
static la_ssize_t file_gex_read_callback (struct archive *a,
void *client_data,
const void **buffer);
static int file_gex_close_callback (struct archive *a,
void *client_data);
static gboolean file_gex_validate_path (const gchar *path,
const gchar *file_name,
gboolean first,
gchar **plugin_id,
GError **error);
static gboolean file_gex_validate (GFile *file,
AsApp **appstream,
GError **error);
static gchar * file_gex_decompress (GFile *file,
gchar *plugin_id,
GError **error);
static int
file_gex_open_callback (struct archive *a,
void *client_data)
{
/* File already opened when we start with libarchive. */
GexReadData *data = client_data;
data->buffer = g_malloc0 (2048);
return ARCHIVE_OK;
}
static la_ssize_t
file_gex_read_callback (struct archive *a,
void *client_data,
const void **buffer)
{
GexReadData *data = client_data;
GError *error = NULL;
gssize read_count;
read_count = g_input_stream_read (data->input, data->buffer, 2048, NULL, &error);
if (read_count == -1)
{
archive_set_error (a, 0, "%s: %s", G_STRFUNC, error->message);
g_clear_error (&error);
return ARCHIVE_FATAL;
}
*buffer = data->buffer;
return read_count;
}
static int
file_gex_close_callback (struct archive *a,
void *client_data)
{
/* Input allocated outside, let's also unref it outside. */
GexReadData *data = client_data;
g_free (data->buffer);
return ARCHIVE_OK;
}
static gboolean
file_gex_validate_path (const gchar *path,
const gchar *file_name,
gboolean first,
gchar **plugin_id,
GError **error)
{
gchar *dirname = g_path_get_dirname (path);
gboolean valid = TRUE;
if (g_path_is_absolute (path) || g_strcmp0 (dirname, "/") == 0)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("Absolute path are forbidden in PIKA extension '%s': %s"),
file_name, path);
g_free (dirname);
return FALSE;
}
if (g_strcmp0 (dirname, ".") == 0)
{
if (first)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("File not allowed in root of PIKA extension '%s': %s"),
file_name, path);
valid = FALSE;
}
else
{
if (*plugin_id)
{
if (g_strcmp0 (path, *plugin_id) != 0)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("File not in PIKA extension '%s' folder id '%s': %s"),
file_name, *plugin_id, path);
valid = FALSE;
}
}
else
{
*plugin_id = g_strdup (path);
}
}
}
else
{
valid = file_gex_validate_path (dirname, file_name, FALSE, plugin_id, error);
}
g_free (dirname);
return valid;
}
/**
* file_gex_validate:
* @file:
* @appstream:
* @error:
*
* Validate the extension file with the following tests:
* - No absolute path allowed.
* - All files must be in a single folder which determines the extension
* ID.
* - This folder must contain the AppStream metadata file which must be
* valid AppStream XML format.
* - The extension ID resulting from the AppStream parsing must
* correspond to the extension ID resulting from the top folder.
*
* Returns: TRUE on success and allocates @appstream, FALSE otherwise
* with @error set.
*/
static gboolean
file_gex_validate (GFile *file,
AsApp **appstream,
GError **error)
{
GInputStream *input;
gboolean success = FALSE;
g_return_val_if_fail (error != NULL && *error == NULL, FALSE);
g_return_val_if_fail (appstream != NULL && *appstream == NULL, FALSE);
input = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (input)
{
struct archive *a;
struct archive_entry *entry;
int r;
GexReadData user_data;
user_data.input = input;
if ((a = archive_read_new ()))
{
archive_read_support_format_zip (a);
r = archive_read_open (a, &user_data, file_gex_open_callback,
file_gex_read_callback, file_gex_close_callback);
if (r == ARCHIVE_OK)
{
gchar *appdata_path = NULL;
GBytes *appdata = NULL;
gchar *plugin_id = NULL;
while (archive_read_next_header (a, &entry) == ARCHIVE_OK &&
file_gex_validate_path (archive_entry_pathname (entry),
pika_file_get_utf8_name (file),
TRUE, &plugin_id, error))
{
if (plugin_id && ! appdata_path)
appdata_path = g_strdup_printf ("%s/%s.metainfo.xml", plugin_id, plugin_id);
if (appdata_path)
{
if (g_strcmp0 (appdata_path, archive_entry_pathname (entry)) == 0)
{
const void *buffer;
GString *appstring = g_string_new ("");
la_int64_t offset;
size_t size;
while (TRUE)
{
r = archive_read_data_block (a, &buffer, &size, &offset);
if (r == ARCHIVE_FATAL)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("Fatal error when uncompressing PIKA extension '%s': %s"),
pika_file_get_utf8_name (file),
archive_error_string (a));
g_string_free (appstring, TRUE);
break;
}
else if (r == ARCHIVE_EOF)
{
appdata = g_string_free_to_bytes (appstring);
break;
}
appstring = g_string_append_len (appstring, (const gchar *) buffer, size);
}
continue;
}
}
archive_read_data_skip (a);
}
if (! (*error))
{
if (appdata)
{
*appstream = as_app_new ();
if (! as_app_parse_data (*appstream, appdata,
AS_APP_PARSE_FLAG_USE_HEURISTICS,
error))
{
g_clear_object (appstream);
}
else if (g_strcmp0 (as_app_get_id (*appstream), plugin_id) != 0)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("PIKA extension '%s' directory (%s) different from AppStream id: %s"),
pika_file_get_utf8_name (file),
plugin_id, as_app_get_id (*appstream));
g_clear_object (appstream);
}
}
else
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("PIKA extension '%s' requires an AppStream file: %s"),
pika_file_get_utf8_name (file),
appdata_path);
}
}
if (appdata_path)
g_free (appdata_path);
if (appdata)
g_bytes_unref (appdata);
if (plugin_id)
g_free (plugin_id);
}
else
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("Invalid PIKA extension '%s': %s"),
pika_file_get_utf8_name (file),
archive_error_string (a));
}
archive_read_close (a);
archive_read_free (a);
if (! *error)
success = TRUE;
}
else
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
"%s: archive_read_new() failed.", G_STRFUNC);
}
g_object_unref (input);
}
else
{
g_prefix_error (error, _("Could not open '%s' for reading: "),
pika_file_get_utf8_name (file));
}
return success;
}
static gchar *
file_gex_decompress (GFile *file,
gchar *plugin_id,
GError **error)
{
GInputStream *input;
GFile *ext_dir = pika_directory_file ("extensions", NULL);
gchar *plugin_dir = NULL;
gboolean success = FALSE;
g_return_val_if_fail (error != NULL && *error == NULL, FALSE);
g_return_val_if_fail (plugin_id != NULL, FALSE);
input = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (input)
{
struct archive *a;
struct archive *ext;
struct archive_entry *entry;
int r;
GexReadData user_data;
const void *buffer;
user_data.input = input;
if ((a = archive_read_new ()))
{
archive_read_support_format_zip (a);
ext = archive_write_disk_new ();
archive_write_disk_set_options (ext,
ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM |
ARCHIVE_EXTRACT_ACL | ARCHIVE_EXTRACT_FFLAGS |
ARCHIVE_EXTRACT_SECURE_NODOTDOT |
ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_NO_OVERWRITE);
archive_write_disk_set_standard_lookup (ext);
r = archive_read_open (a, &user_data, file_gex_open_callback,
file_gex_read_callback, file_gex_close_callback);
if (r == ARCHIVE_OK)
{
while (archive_read_next_header (a, &entry) == ARCHIVE_OK &&
/* Re-validate just in case the archive got swapped
* between validation and decompression. */
file_gex_validate_path (archive_entry_pathname (entry),
pika_file_get_utf8_name (file),
TRUE, &plugin_id, error))
{
gchar *path;
size_t size;
la_int64_t offset;
path = g_build_filename (g_file_get_path (ext_dir), archive_entry_pathname (entry), NULL);
archive_entry_set_pathname (entry, path);
g_free (path);
r = archive_write_header (ext, entry);
if (r < ARCHIVE_WARN)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("Fatal error when uncompressing PIKA extension '%s': %s"),
pika_file_get_utf8_name (file),
archive_error_string (ext));
break;
}
if (archive_entry_size (entry) > 0)
{
while (TRUE)
{
r = archive_read_data_block (a, &buffer, &size, &offset);
if (r == ARCHIVE_EOF)
{
break;
}
else if (r < ARCHIVE_WARN)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("Fatal error when uncompressing PIKA extension '%s': %s"),
pika_file_get_utf8_name (file),
archive_error_string (a));
break;
}
r = archive_write_data_block (ext, buffer, size, offset);
if (r == ARCHIVE_WARN)
{
g_printerr (_("Warning when uncompressing PIKA extension '%s': %s\n"),
pika_file_get_utf8_name (file),
archive_error_string (ext));
break;
}
else if (r < ARCHIVE_OK)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("Fatal error when uncompressing PIKA extension '%s': %s"),
pika_file_get_utf8_name (file),
archive_error_string (ext));
break;
}
}
}
if (*error)
break;
r = archive_write_finish_entry (ext);
if (r < ARCHIVE_OK)
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("Fatal error when uncompressing PIKA extension '%s': %s"),
pika_file_get_utf8_name (file),
archive_error_string (ext));
break;
}
}
}
else
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
_("Invalid PIKA extension '%s': %s"),
pika_file_get_utf8_name (file),
archive_error_string (a));
}
archive_read_close (a);
archive_read_free (a);
archive_write_close(ext);
archive_write_free(ext);
if (! *error)
success = TRUE;
}
else
{
*error = g_error_new (PIKA_EXTENSION_ERROR, PIKA_EXTENSION_FAILED,
"%s: archive_read_new() failed.", G_STRFUNC);
}
g_object_unref (input);
}
else
{
g_prefix_error (error, _("Could not open '%s' for reading: "),
pika_file_get_utf8_name (file));
}
if (success)
plugin_dir = g_build_filename (g_file_get_path (ext_dir), plugin_id, NULL);
g_object_unref (ext_dir);
return plugin_dir;
}
/* public functions */
PikaValueArray *
file_gex_load_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
PikaValueArray *return_vals;
GFile *file;
gchar *ext_dir = NULL;
AsApp *appdata = NULL;
gboolean success = FALSE;
pika_set_busy (pika);
file = g_value_get_object (pika_value_array_index (args, 1));
success = file_gex_validate (file, &appdata, error);
if (success)
ext_dir = file_gex_decompress (file, (gchar *) as_app_get_id (appdata),
error);
if (ext_dir)
{
PikaExtension *extension;
GError *rm_error = NULL;
extension = pika_extension_new (ext_dir, TRUE);
success = pika_extension_manager_install (pika->extension_manager,
extension, error);
if (! success)
{
GFile *file;
g_object_unref (extension);
file = g_file_new_for_path (ext_dir);
if (! pika_file_delete_recursive (file, &rm_error))
{
g_warning ("%s: %s\n", G_STRFUNC, rm_error->message);
g_error_free (rm_error);
}
g_object_unref (file);
}
g_free (ext_dir);
}
else
{
success = FALSE;
}
return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
pika_unset_busy (pika);
return return_vals;
}

View File

@ -0,0 +1,36 @@
/* 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
* 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/>.
*/
#ifndef __FILE_DATA_GEX_H__
#define __FILE_DATA_GEX_H__
PikaValueArray * file_gex_load_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error);
#endif /* __FILE_DATA_GEX_H__ */

View File

@ -0,0 +1,365 @@
/* 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
*
* 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 "libpikabase/pikaparasiteio.h"
#include "libpikacolor/pikacolor.h"
#include "core/core-types.h"
#include "core/pika.h"
#include "core/pikabrushpipe.h"
#include "core/pikabrushpipe-load.h"
#include "core/pikabrush-private.h"
#include "core/pikadrawable.h"
#include "core/pikaimage.h"
#include "core/pikalayer-new.h"
#include "core/pikaparamspecs.h"
#include "core/pikatempbuf.h"
#include "pdb/pikaprocedure.h"
#include "file-data-gbr.h"
#include "file-data-gih.h"
#include "pika-intl.h"
/* local function prototypes */
static PikaImage * file_gih_pipe_to_image (Pika *pika,
PikaBrushPipe *pipe);
static PikaBrushPipe * file_gih_image_to_pipe (PikaImage *image,
const gchar *name,
gdouble spacing,
const gchar *paramstring);
/* public functions */
PikaValueArray *
file_gih_load_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
PikaValueArray *return_vals;
PikaImage *image = NULL;
GFile *file;
GInputStream *input;
GError *my_error = NULL;
pika_set_busy (pika);
file = g_value_get_object (pika_value_array_index (args, 1));
input = G_INPUT_STREAM (g_file_read (file, NULL, &my_error));
if (input)
{
GList *list = pika_brush_pipe_load (context, file, input, error);
if (list)
{
PikaBrushPipe *pipe = list->data;
g_list_free (list);
image = file_gih_pipe_to_image (pika, pipe);
g_object_unref (pipe);
}
g_object_unref (input);
}
else
{
g_propagate_prefixed_error (error, my_error,
_("Could not open '%s' for reading: "),
pika_file_get_utf8_name (file));
}
return_vals = pika_procedure_get_return_values (procedure, image != NULL,
error ? *error : NULL);
if (image)
g_value_set_object (pika_value_array_index (return_vals, 1), image);
pika_unset_busy (pika);
return return_vals;
}
PikaValueArray *
file_gih_save_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
PikaValueArray *return_vals;
PikaImage *image;
PikaBrushPipe *pipe;
const gchar *name;
const gchar *params;
GFile *file;
gint spacing;
gboolean success;
pika_set_busy (pika);
image = g_value_get_object (pika_value_array_index (args, 1));
/* XXX: drawable list is currently unused. GIH saving just uses the
* whole layer list.
*/
file = g_value_get_object (pika_value_array_index (args, 4));
spacing = g_value_get_int (pika_value_array_index (args, 5));
name = g_value_get_string (pika_value_array_index (args, 6));
params = g_value_get_string (pika_value_array_index (args, 7));
pipe = file_gih_image_to_pipe (image, name, spacing, params);
pika_data_set_file (PIKA_DATA (pipe), file, TRUE, TRUE);
success = pika_data_save (PIKA_DATA (pipe), error);
g_object_unref (pipe);
return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
pika_unset_busy (pika);
return return_vals;
}
/* private functions */
static PikaImage *
file_gih_pipe_to_image (Pika *pika,
PikaBrushPipe *pipe)
{
PikaImage *image;
const gchar *name;
PikaImageBaseType base_type;
PikaParasite *parasite;
gchar spacing[8];
gint i;
if (pika_brush_get_pixmap (pipe->current))
base_type = PIKA_RGB;
else
base_type = PIKA_GRAY;
name = pika_object_get_name (pipe);
image = pika_image_new (pika, 1, 1, base_type,
PIKA_PRECISION_U8_NON_LINEAR);
parasite = pika_parasite_new ("pika-brush-pipe-name",
PIKA_PARASITE_PERSISTENT,
strlen (name) + 1, name);
pika_image_parasite_attach (image, parasite, FALSE);
pika_parasite_free (parasite);
g_snprintf (spacing, sizeof (spacing), "%d",
pika_brush_get_spacing (PIKA_BRUSH (pipe)));
parasite = pika_parasite_new ("pika-brush-pipe-spacing",
PIKA_PARASITE_PERSISTENT,
strlen (spacing) + 1, spacing);
pika_image_parasite_attach (image, parasite, FALSE);
pika_parasite_free (parasite);
for (i = 0; i < pipe->n_brushes; i++)
{
PikaLayer *layer;
layer = file_gbr_brush_to_layer (image, pipe->brushes[i]);
pika_image_add_layer (image, layer, NULL, i, FALSE);
}
if (pipe->params)
{
PikaPixPipeParams params;
gchar *paramstring;
/* Since we do not (yet) load the pipe as described in the
* header, but use one layer per brush, we have to alter the
* paramstring before attaching it as a parasite.
*
* (this comment copied over from file-gih, whatever "as
* described in the header" means) -- mitch
*/
pika_pixpipe_params_init (&params);
pika_pixpipe_params_parse (pipe->params, &params);
params.cellwidth = pika_image_get_width (image);
params.cellheight = pika_image_get_height (image);
params.cols = 1;
params.rows = 1;
paramstring = pika_pixpipe_params_build (&params);
if (paramstring)
{
parasite = pika_parasite_new ("pika-brush-pipe-parameters",
PIKA_PARASITE_PERSISTENT,
strlen (paramstring) + 1,
paramstring);
pika_image_parasite_attach (image, parasite, FALSE);
pika_parasite_free (parasite);
g_free (paramstring);
}
pika_pixpipe_params_free (&params);
}
return image;
}
static PikaBrushPipe *
file_gih_image_to_pipe (PikaImage *image,
const gchar *name,
gdouble spacing,
const gchar *paramstring)
{
PikaBrushPipe *pipe;
PikaPixPipeParams params;
GList *layers;
GList *list;
GList *brushes = NULL;
gint image_width;
gint image_height;
gint i;
pipe = g_object_new (PIKA_TYPE_BRUSH_PIPE,
"name", name,
"mime-type", "image/x-pika-gih",
"spacing", spacing,
NULL);
pika_pixpipe_params_init (&params);
pika_pixpipe_params_parse (paramstring, &params);
image_width = pika_image_get_width (image);
image_height = pika_image_get_height (image);
layers = pika_image_get_layer_iter (image);
for (list = layers; list; list = g_list_next (list))
{
PikaLayer *layer = list->data;
gint width;
gint height;
gint offset_x;
gint offset_y;
gint row;
width = pika_item_get_width (PIKA_ITEM (layer));
height = pika_item_get_height (PIKA_ITEM (layer));
pika_item_get_offset (PIKA_ITEM (layer), &offset_x, &offset_y);
/* Since we assume positive layer offsets we need to make sure this
* is always the case or we will crash for grayscale layers.
* See issue #6436. */
if (offset_x < 0)
{
g_warning (_("Negative x offset: %d for layer %s corrected."),
offset_x, pika_object_get_name (layer));
width += offset_x;
offset_x = 0;
}
if (offset_y < 0)
{
g_warning (_("Negative y offset: %d for layer %s corrected."),
offset_y, pika_object_get_name (layer));
height += offset_y;
offset_y = 0;
}
for (row = 0; row < params.rows; row++)
{
gint y, ynext;
gint thisy, thish;
gint col;
y = (row * image_height) / params.rows;
ynext = ((row + 1) * image_height / params.rows);
/* Assume layer is offset to positive direction in x and y.
* That's reasonable, as otherwise all of the layer
* won't be visible.
* thisy and thisx are in the drawable's coordinate space.
*/
thisy = MAX (0, y - offset_y);
thish = (ynext - offset_y) - thisy;
thish = MIN (thish, height - thisy);
for (col = 0; col < params.cols; col++)
{
PikaBrush *brush;
gint x, xnext;
gint thisx, thisw;
x = (col * image_width / params.cols);
xnext = ((col + 1) * image_width / params.cols);
thisx = MAX (0, x - offset_x);
thisw = (xnext - offset_x) - thisx;
thisw = MIN (thisw, width - thisx);
brush = file_gbr_drawable_to_brush (PIKA_DRAWABLE (layer),
GEGL_RECTANGLE (thisx, thisy,
thisw, thish),
pika_object_get_name (layer),
spacing);
brushes = g_list_prepend (brushes, brush);
}
}
}
brushes = g_list_reverse (brushes);
pipe->n_brushes = g_list_length (brushes);
pipe->brushes = g_new0 (PikaBrush *, pipe->n_brushes);
for (list = brushes, i = 0; list; list = g_list_next (list), i++)
pipe->brushes[i] = list->data;
g_list_free (brushes);
pika_pixpipe_params_free (&params);
pika_brush_pipe_set_params (pipe, paramstring);
return pipe;
}

View File

@ -0,0 +1,41 @@
/* 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
*
* 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/>.
*/
#ifndef __FILE_DATA_GIH_H__
#define __FILE_DATA_GIH_H__
PikaValueArray * file_gih_load_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error);
PikaValueArray * file_gih_save_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error);
#endif /* __FILE_DATA_GIH_H__ */

View File

@ -0,0 +1,310 @@
/* 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
*
* 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 <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "core/core-types.h"
#include "gegl/pika-babl.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadrawable.h"
#include "core/pikaimage.h"
#include "core/pikaimage-new.h"
#include "core/pikaimage-resize.h"
#include "core/pikalayer-new.h"
#include "core/pikaparamspecs.h"
#include "core/pikapattern.h"
#include "core/pikapattern-load.h"
#include "core/pikapickable.h"
#include "core/pikatempbuf.h"
#include "pdb/pikaprocedure.h"
#include "file-data-pat.h"
#include "pika-intl.h"
/* local function prototypes */
static PikaImage * file_pat_pattern_to_image (Pika *pika,
PikaPattern *pattern);
static PikaPattern * file_pat_image_to_pattern (PikaImage *image,
PikaContext *context,
gint n_drawables,
PikaDrawable **drawables,
const gchar *name);
/* public functions */
PikaValueArray *
file_pat_load_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
PikaValueArray *return_vals;
PikaImage *image = NULL;
GFile *file;
GInputStream *input;
GError *my_error = NULL;
pika_set_busy (pika);
file = g_value_get_object (pika_value_array_index (args, 1));
input = G_INPUT_STREAM (g_file_read (file, NULL, &my_error));
if (input)
{
GList *list = pika_pattern_load (context, file, input, error);
if (list)
{
PikaPattern *pattern = list->data;
g_list_free (list);
image = file_pat_pattern_to_image (pika, pattern);
g_object_unref (pattern);
}
g_object_unref (input);
}
else
{
g_propagate_prefixed_error (error, my_error,
_("Could not open '%s' for reading: "),
pika_file_get_utf8_name (file));
}
return_vals = pika_procedure_get_return_values (procedure, image != NULL,
error ? *error : NULL);
if (image)
g_value_set_object (pika_value_array_index (return_vals, 1), image);
pika_unset_busy (pika);
return return_vals;
}
PikaValueArray *
file_pat_save_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
PikaValueArray *return_vals;
PikaImage *image;
PikaPattern *pattern;
const gchar *name;
GFile *file;
PikaDrawable **drawables;
gint n_drawables;
gboolean success;
pika_set_busy (pika);
image = g_value_get_object (pika_value_array_index (args, 1));
n_drawables = g_value_get_int (pika_value_array_index (args, 2));
drawables = (PikaDrawable **) pika_value_get_object_array (pika_value_array_index (args, 3));
file = g_value_get_object (pika_value_array_index (args, 4));
name = g_value_get_string (pika_value_array_index (args, 5));
pattern = file_pat_image_to_pattern (image, context, n_drawables, drawables, name);
pika_data_set_file (PIKA_DATA (pattern), file, TRUE, TRUE);
success = pika_data_save (PIKA_DATA (pattern), error);
g_object_unref (pattern);
return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
pika_unset_busy (pika);
return return_vals;
}
/* private functions */
static PikaImage *
file_pat_pattern_to_image (Pika *pika,
PikaPattern *pattern)
{
PikaImage *image;
PikaLayer *layer;
const Babl *format;
PikaImageBaseType base_type;
gboolean alpha;
gint width;
gint height;
PikaTempBuf *mask = pika_pattern_get_mask (pattern);
GeglBuffer *buffer;
GString *string;
PikaConfigWriter *writer;
PikaParasite *parasite;
format = pika_temp_buf_get_format (mask);
switch (babl_format_get_bytes_per_pixel (format))
{
case 1:
base_type = PIKA_GRAY;
alpha = FALSE;
break;
case 2:
base_type = PIKA_GRAY;
alpha = TRUE;
break;
case 3:
base_type = PIKA_RGB;
alpha = FALSE;
break;
case 4:
base_type = PIKA_RGB;
alpha = TRUE;
break;
default:
g_return_val_if_reached (NULL);
}
width = pika_temp_buf_get_width (mask);
height = pika_temp_buf_get_height (mask);
image = pika_image_new (pika, width, height, base_type,
PIKA_PRECISION_U8_NON_LINEAR);
string = g_string_new (NULL);
writer = pika_config_writer_new_from_string (string);
pika_config_writer_open (writer, "description");
pika_config_writer_string (writer, pika_object_get_name (pattern));
pika_config_writer_close (writer);
pika_config_writer_finish (writer, NULL, NULL);
parasite = pika_parasite_new ("PikaProcedureConfig-file-pat-save-last",
PIKA_PARASITE_PERSISTENT,
string->len + 1, string->str);
pika_image_parasite_attach (image, parasite, FALSE);
pika_parasite_free (parasite);
g_string_free (string, TRUE);
format = pika_image_get_layer_format (image, alpha);
layer = pika_layer_new (image, width, height, format,
pika_object_get_name (pattern),
1.0, PIKA_LAYER_MODE_NORMAL);
pika_image_add_layer (image, layer, NULL, 0, FALSE);
buffer = pika_drawable_get_buffer (PIKA_DRAWABLE (layer));
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
NULL,
pika_temp_buf_get_data (mask), GEGL_AUTO_ROWSTRIDE);
return image;
}
static PikaPattern *
file_pat_image_to_pattern (PikaImage *image,
PikaContext *context,
gint n_drawables,
PikaDrawable **drawables,
const gchar *name)
{
PikaPattern *pattern;
PikaImage *subimage = NULL;
const Babl *format;
gint width;
gint height;
g_return_val_if_fail (n_drawables > 0, NULL);
if (n_drawables > 1)
{
GList *drawable_list = NULL;
for (gint i = 0; i < n_drawables; i++)
drawable_list = g_list_prepend (drawable_list, drawables[i]);
subimage = pika_image_new_from_drawables (image->pika, drawable_list, FALSE, FALSE);
g_list_free (drawable_list);
pika_container_remove (image->pika->images, PIKA_OBJECT (subimage));
pika_image_resize_to_layers (subimage, context,
NULL, NULL, NULL, NULL, NULL);
width = pika_image_get_width (subimage);
height = pika_image_get_width (subimage);
pika_pickable_flush (PIKA_PICKABLE (subimage));
}
else
{
width = pika_item_get_width (PIKA_ITEM (drawables[0]));
height = pika_item_get_height (PIKA_ITEM (drawables[0]));
}
format = pika_babl_format (pika_drawable_is_gray (drawables[0]) ?
PIKA_GRAY : PIKA_RGB,
PIKA_PRECISION_U8_NON_LINEAR,
(subimage && pika_image_has_alpha (subimage)) ||
pika_drawable_has_alpha (drawables[0]),
NULL);
pattern = g_object_new (PIKA_TYPE_PATTERN,
"name", name,
"mime-type", "image/x-pika-pat",
NULL);
pattern->mask = pika_temp_buf_new (width, height, format);
gegl_buffer_get (subimage != NULL ? pika_pickable_get_buffer (PIKA_PICKABLE (subimage)) :
pika_drawable_get_buffer (drawables[0]),
GEGL_RECTANGLE (0, 0, width, height), 1.0,
format, pika_temp_buf_get_data (pattern->mask),
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
g_clear_object (&subimage);
return pattern;
}

View File

@ -0,0 +1,41 @@
/* 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
*
* 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/>.
*/
#ifndef __FILE_DATA_PAT_H__
#define __FILE_DATA_PAT_H__
PikaValueArray * file_pat_load_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error);
PikaValueArray * file_pat_save_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error);
#endif /* __FILE_DATA_PAT_H__ */

522
app/file-data/file-data.c Normal file
View File

@ -0,0 +1,522 @@
/* 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
*
* 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 <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "core/core-types.h"
#include "core/pika.h"
#include "core/pikadrawable.h"
#include "core/pikaparamspecs.h"
#include "plug-in/pikapluginmanager.h"
#include "plug-in/pikapluginprocedure.h"
#include "file-data.h"
#include "file-data-gbr.h"
#include "file-data-gex.h"
#include "file-data-gih.h"
#include "file-data-pat.h"
#include "pika-intl.h"
void
file_data_init (Pika *pika)
{
PikaPlugInProcedure *proc;
GFile *file;
PikaProcedure *procedure;
g_return_if_fail (PIKA_IS_PIKA (pika));
/* file-gbr-load */
file = g_file_new_for_path ("file-gbr-load");
procedure = pika_plug_in_procedure_new (PIKA_PDB_PROC_TYPE_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = PIKA_PDB_PROC_TYPE_INTERNAL;
procedure->marshal_func = file_gbr_load_invoker;
proc = PIKA_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("PIKA brush"));
pika_plug_in_procedure_set_icon (proc, PIKA_ICON_TYPE_ICON_NAME,
(const guint8 *) "pika-brush",
strlen ("pika-brush") + 1,
NULL);
pika_plug_in_procedure_set_image_types (proc, NULL);
pika_plug_in_procedure_set_file_proc (proc, "gbr, gbp", "",
"20, string, PIKA");
pika_plug_in_procedure_set_mime_types (proc, "image/pika-x-gbr");
pika_plug_in_procedure_set_handles_remote (proc);
pika_object_set_static_name (PIKA_OBJECT (procedure), "file-gbr-load");
pika_procedure_set_static_help (procedure,
"Loads PIKA brushes",
"Loads PIKA brushes (1 or 4 bpp "
"and old .gpb format)",
NULL);
pika_procedure_set_static_attribution (procedure,
"Tim Newsome, Jens Lautenbacher, "
"Sven Neumann, Michael Natterer",
"Tim Newsome, Jens Lautenbacher, "
"Sven Neumann, Michael Natterer",
"1995-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
PIKA_RUN_INTERACTIVE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_object ("file",
"File",
"The file to load",
G_TYPE_FILE,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
pika_param_spec_image ("image",
"Image",
"Output image",
FALSE,
PIKA_PARAM_READWRITE));
pika_plug_in_manager_add_procedure (pika->plug_in_manager, proc);
g_object_unref (procedure);
/* file-gbr-save-internal */
file = g_file_new_for_path ("file-gbr-save-internal");
procedure = pika_plug_in_procedure_new (PIKA_PDB_PROC_TYPE_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = PIKA_PDB_PROC_TYPE_INTERNAL;
procedure->marshal_func = file_gbr_save_invoker;
proc = PIKA_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("PIKA brush"));
pika_plug_in_procedure_set_icon (proc, PIKA_ICON_TYPE_ICON_NAME,
(const guint8 *) "pika-brush",
strlen ("pika-brush") + 1,
NULL);
#if 0
/* do not register as file procedure */
pika_plug_in_procedure_set_image_types (proc, "RGB*, GRAY*, INDEXED*");
pika_plug_in_procedure_set_file_proc (proc, "gbr", "", NULL);
pika_plug_in_procedure_set_mime_types (proc, "image/x-pika-gbr");
pika_plug_in_procedure_set_handles_remote (proc);
#endif
pika_object_set_static_name (PIKA_OBJECT (procedure),
"file-gbr-save-internal");
pika_procedure_set_static_help (procedure,
"Exports Pika brush file (.GBR)",
"Exports Pika brush file (.GBR)",
NULL);
pika_procedure_set_static_attribution (procedure,
"Tim Newsome, Michael Natterer",
"Tim Newsome, Michael Natterer",
"1995-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
PIKA_RUN_INTERACTIVE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_image ("image",
"Image",
"Input image",
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_drawable ("drawable",
"Drawable",
"Active drawable "
"of input image",
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_object ("file",
"File",
"The file to export",
G_TYPE_FILE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_int ("spacing",
"spacing",
"Spacing of the brush",
1, 1000, 10,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("name",
"name",
"The name of the "
"brush",
FALSE, FALSE, TRUE,
"PIKA Brush",
PIKA_PARAM_READWRITE));
pika_plug_in_manager_add_procedure (pika->plug_in_manager, proc);
g_object_unref (procedure);
/* file-gih-load */
file = g_file_new_for_path ("file-gih-load");
procedure = pika_plug_in_procedure_new (PIKA_PDB_PROC_TYPE_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = PIKA_PDB_PROC_TYPE_INTERNAL;
procedure->marshal_func = file_gih_load_invoker;
proc = PIKA_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("PIKA brush (animated)"));
pika_plug_in_procedure_set_icon (proc, PIKA_ICON_TYPE_ICON_NAME,
(const guint8 *) "pika-brush",
strlen ("pika-brush") + 1,
NULL);
pika_plug_in_procedure_set_image_types (proc, NULL);
pika_plug_in_procedure_set_file_proc (proc, "gih", "", "");
pika_plug_in_procedure_set_mime_types (proc, "image/pika-x-gih");
pika_plug_in_procedure_set_handles_remote (proc);
pika_object_set_static_name (PIKA_OBJECT (procedure), "file-gih-load");
pika_procedure_set_static_help (procedure,
"Loads PIKA animated brushes",
"This procedure loads a PIKA brush "
"pipe as an image.",
NULL);
pika_procedure_set_static_attribution (procedure,
"Tor Lillqvist, Michael Natterer",
"Tor Lillqvist, Michael Natterer",
"1999-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
PIKA_RUN_INTERACTIVE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_object ("file",
"File",
"The file to load",
G_TYPE_FILE,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
pika_param_spec_image ("image",
"Image",
"Output image",
FALSE,
PIKA_PARAM_READWRITE));
pika_plug_in_manager_add_procedure (pika->plug_in_manager, proc);
g_object_unref (procedure);
/* file-gih-save-internal */
file = g_file_new_for_path ("file-gih-save-internal");
procedure = pika_plug_in_procedure_new (PIKA_PDB_PROC_TYPE_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = PIKA_PDB_PROC_TYPE_INTERNAL;
procedure->marshal_func = file_gih_save_invoker;
proc = PIKA_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("PIKA brush (animated)"));
pika_plug_in_procedure_set_icon (proc, PIKA_ICON_TYPE_ICON_NAME,
(const guint8 *) "pika-brush",
strlen ("pika-brush") + 1,
NULL);
#if 0
/* do not register as file procedure */
pika_plug_in_procedure_set_image_types (proc, "RGB*, GRAY*, INDEXED*");
pika_plug_in_procedure_set_file_proc (proc, "gih", "", NULL);
pika_plug_in_procedure_set_mime_types (proc, "image/x-pika-gih");
pika_plug_in_procedure_set_handles_remote (proc);
#endif
pika_object_set_static_name (PIKA_OBJECT (procedure),
"file-gih-save-internal");
pika_procedure_set_static_help (procedure,
"Exports Pika animated brush file (.gih)",
"Exports Pika animated brush file (.gih)",
NULL);
pika_procedure_set_static_attribution (procedure,
"Tor Lillqvist, Michael Natterer",
"Tor Lillqvist, Michael Natterer",
"1999-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
PIKA_RUN_INTERACTIVE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_image ("image",
"Image",
"Input image",
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_int ("num-drawables",
"num drawables",
"The number of drawables to save",
1, G_MAXINT32, 1,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_object_array ("drawables",
"drawables",
"Drawables to save",
PIKA_TYPE_DRAWABLE,
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
pika_procedure_add_argument (procedure,
g_param_spec_object ("file",
"File",
"The file to export",
G_TYPE_FILE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_int ("spacing",
"spacing",
"Spacing of the brush",
1, 1000, 10,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("name",
"name",
"The name of the "
"brush",
FALSE, FALSE, TRUE,
"PIKA Brush",
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("params",
"params",
"The pipe's parameters",
FALSE, FALSE, TRUE,
NULL,
PIKA_PARAM_READWRITE));
pika_plug_in_manager_add_procedure (pika->plug_in_manager, proc);
g_object_unref (procedure);
/* file-pat-load */
file = g_file_new_for_path ("file-pat-load");
procedure = pika_plug_in_procedure_new (PIKA_PDB_PROC_TYPE_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = PIKA_PDB_PROC_TYPE_INTERNAL;
procedure->marshal_func = file_pat_load_invoker;
proc = PIKA_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("PIKA pattern"));
pika_plug_in_procedure_set_icon (proc, PIKA_ICON_TYPE_ICON_NAME,
(const guint8 *) "pika-pattern",
strlen ("pika-pattern") + 1,
NULL);
pika_plug_in_procedure_set_image_types (proc, NULL);
pika_plug_in_procedure_set_file_proc (proc, "pat", "",
"20,string,GPAT");
pika_plug_in_procedure_set_mime_types (proc, "image/pika-x-pat");
pika_plug_in_procedure_set_handles_remote (proc);
pika_object_set_static_name (PIKA_OBJECT (procedure), "file-pat-load");
pika_procedure_set_static_help (procedure,
"Loads PIKA patterns",
"Loads PIKA patterns",
NULL);
pika_procedure_set_static_attribution (procedure,
"Tim Newsome, Michael Natterer",
"Tim Newsome, Michael Natterer",
"1997-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
PIKA_RUN_INTERACTIVE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_object ("file",
"File",
"The file to load",
G_TYPE_FILE,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
pika_param_spec_image ("image",
"Image",
"Output image",
FALSE,
PIKA_PARAM_READWRITE));
pika_plug_in_manager_add_procedure (pika->plug_in_manager, proc);
g_object_unref (procedure);
/* file-pat-save-internal */
file = g_file_new_for_path ("file-pat-save-internal");
procedure = pika_plug_in_procedure_new (PIKA_PDB_PROC_TYPE_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = PIKA_PDB_PROC_TYPE_INTERNAL;
procedure->marshal_func = file_pat_save_invoker;
proc = PIKA_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("PIKA pattern"));
pika_plug_in_procedure_set_icon (proc, PIKA_ICON_TYPE_ICON_NAME,
(const guint8 *) "pika-pattern",
strlen ("pika-pattern") + 1,
NULL);
#if 0
/* do not register as file procedure */
pika_plug_in_procedure_set_image_types (proc, "RGB*, GRAY*, INDEXED*");
pika_plug_in_procedure_set_file_proc (proc, "pat", "", NULL);
pika_plug_in_procedure_set_mime_types (proc, "image/x-pika-pat");
pika_plug_in_procedure_set_handles_remote (proc);
#endif
pika_object_set_static_name (PIKA_OBJECT (procedure),
"file-pat-save-internal");
pika_procedure_set_static_help (procedure,
"Exports Pika pattern file (.PAT)",
"Exports Pika pattern file (.PAT)",
NULL);
pika_procedure_set_static_attribution (procedure,
"Tim Newsome, Michael Natterer",
"Tim Newsome, Michael Natterer",
"1995-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
PIKA_RUN_INTERACTIVE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_image ("image",
"Image",
"Input image",
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_int ("n-drawables",
"Num drawables",
"Number of drawables",
1, G_MAXINT, 1,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_object_array ("drawables",
"Drawables",
"Selected drawables",
PIKA_TYPE_DRAWABLE,
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
pika_procedure_add_argument (procedure,
g_param_spec_object ("file",
"File",
"The file to export",
G_TYPE_FILE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("name",
"name",
"The name of the "
"pattern",
FALSE, FALSE, TRUE,
"PIKA Pattern",
PIKA_PARAM_READWRITE));
pika_plug_in_manager_add_procedure (pika->plug_in_manager, proc);
g_object_unref (procedure);
/* file-gex-load */
file = g_file_new_for_path ("file-gex-load");
procedure = pika_plug_in_procedure_new (PIKA_PDB_PROC_TYPE_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = PIKA_PDB_PROC_TYPE_INTERNAL;
procedure->marshal_func = file_gex_load_invoker;
proc = PIKA_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("PIKA extension"));
pika_plug_in_procedure_set_icon (proc, PIKA_ICON_TYPE_ICON_NAME,
(const guint8 *) "pika-plugin",
strlen ("pika-plugin") + 1,
NULL);
pika_plug_in_procedure_set_file_proc (proc, "gex", "",
"20, string, PIKA");
pika_plug_in_procedure_set_generic_file_proc (proc, TRUE);
pika_plug_in_procedure_set_mime_types (proc, "image/pika-x-gex");
pika_plug_in_procedure_set_handles_remote (proc);
pika_object_set_static_name (PIKA_OBJECT (procedure), "file-gex-load");
pika_procedure_set_static_help (procedure,
"Loads PIKA extension",
"Loads PIKA extension",
NULL);
pika_procedure_set_static_attribution (procedure,
"Jehan", "Jehan", "2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
PIKA_RUN_INTERACTIVE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_object ("file",
"File",
"The file to load",
G_TYPE_FILE,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
pika_param_spec_string ("extension-id",
"ID of installed extension",
"Identifier of the newly installed extension",
FALSE, TRUE, FALSE, NULL,
PIKA_PARAM_READWRITE));
pika_plug_in_manager_add_procedure (pika->plug_in_manager, proc);
g_object_unref (procedure);
}
void
file_data_exit (Pika *pika)
{
g_return_if_fail (PIKA_IS_PIKA (pika));
}

30
app/file-data/file-data.h Normal file
View File

@ -0,0 +1,30 @@
/* 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
*
* 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/>.
*/
#ifndef __FILE_DATA_H__
#define __FILE_DATA_H__
void file_data_init (Pika *pika);
void file_data_exit (Pika *pika);
#endif /* __FILE_DATA_H__ */

21
app/file-data/meson.build Normal file
View File

@ -0,0 +1,21 @@
libappfiledata_sources = [
'file-data-gbr.c',
'file-data-gex.c',
'file-data-gih.c',
'file-data-pat.c',
'file-data.c',
]
libappfiledata = static_library('appfiledata',
libappfiledata_sources,
include_directories: [ rootInclude, rootAppInclude, ],
c_args: '-DG_LOG_DOMAIN="Pika-File-Data"',
dependencies: [
appstream_glib,
cairo,
gdk_pixbuf,
gegl,
libarchive,
],
)