Initial checkin of Pika from heckimp
This commit is contained in:
115
app/file/file-import.c
Normal file
115
app/file/file-import.c
Normal file
@ -0,0 +1,115 @@
|
||||
/* 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
|
||||
*
|
||||
* file-import.c
|
||||
*
|
||||
* 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 "core/core-types.h"
|
||||
|
||||
#include "config/pikacoreconfig.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaimage-color-profile.h"
|
||||
#include "core/pikaimage-convert-precision.h"
|
||||
#include "core/pikaimage-rotate.h"
|
||||
#include "core/pikalayer.h"
|
||||
#include "core/pikaprogress.h"
|
||||
|
||||
#include "text/pikatextlayer.h"
|
||||
|
||||
#include "file-import.h"
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
file_import_image (PikaImage *image,
|
||||
PikaContext *context,
|
||||
GFile *file,
|
||||
gboolean interactive,
|
||||
PikaProgress *progress)
|
||||
{
|
||||
PikaCoreConfig *config;
|
||||
|
||||
g_return_if_fail (PIKA_IS_IMAGE (image));
|
||||
g_return_if_fail (PIKA_IS_CONTEXT (context));
|
||||
g_return_if_fail (G_IS_FILE (file));
|
||||
g_return_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress));
|
||||
|
||||
config = image->pika->config;
|
||||
|
||||
if (interactive && pika_image_get_base_type (image) != PIKA_INDEXED)
|
||||
{
|
||||
if (config->import_promote_float)
|
||||
{
|
||||
PikaPrecision old_precision = pika_image_get_precision (image);
|
||||
|
||||
if (old_precision != PIKA_PRECISION_FLOAT_LINEAR)
|
||||
{
|
||||
pika_image_convert_precision (image,
|
||||
PIKA_PRECISION_FLOAT_LINEAR,
|
||||
GEGL_DITHER_NONE,
|
||||
GEGL_DITHER_NONE,
|
||||
GEGL_DITHER_NONE,
|
||||
progress);
|
||||
|
||||
if (config->import_promote_dither &&
|
||||
old_precision == PIKA_PRECISION_U8_NON_LINEAR)
|
||||
{
|
||||
pika_image_convert_dither_u8 (image, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config->import_add_alpha)
|
||||
{
|
||||
GList *layers = pika_image_get_layer_list (image);
|
||||
GList *list;
|
||||
|
||||
for (list = layers; list; list = g_list_next (list))
|
||||
{
|
||||
if (! pika_viewable_get_children (list->data) &&
|
||||
! pika_item_is_text_layer (list->data) &&
|
||||
! pika_drawable_has_alpha (list->data))
|
||||
{
|
||||
pika_layer_add_alpha (list->data);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (layers);
|
||||
}
|
||||
}
|
||||
|
||||
pika_image_import_color_profile (image, context, progress, interactive);
|
||||
pika_image_import_rotation_metadata (image, context, progress, interactive);
|
||||
|
||||
/* Remember the import source */
|
||||
pika_image_set_imported_file (image, file);
|
||||
|
||||
/* We shall treat this file as an Untitled file */
|
||||
pika_image_set_file (image, NULL);
|
||||
}
|
35
app/file/file-import.h
Normal file
35
app/file/file-import.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* 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
|
||||
*
|
||||
* file-import.h
|
||||
*
|
||||
* 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_IMPORT_H__
|
||||
#define __FILE_IMPORT_H__
|
||||
|
||||
|
||||
void file_import_image (PikaImage *image,
|
||||
PikaContext *context,
|
||||
GFile *file,
|
||||
gboolean interactive,
|
||||
PikaProgress *progress);
|
||||
|
||||
|
||||
#endif /* __FILE_IMPORT_H__ */
|
816
app/file/file-open.c
Normal file
816
app/file/file-open.c
Normal file
@ -0,0 +1,816 @@
|
||||
/* 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, 1996, 1997 Spencer Kimball and Peter Mattis
|
||||
* Copyright (C) 1997 Josh MacDonald
|
||||
*
|
||||
* file-open.c
|
||||
*
|
||||
* 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 "gegl/pika-babl.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikadocumentlist.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaimage-merge.h"
|
||||
#include "core/pikaimage-undo.h"
|
||||
#include "core/pikaimagefile.h"
|
||||
#include "core/pikalayer.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
#include "core/pikaprogress.h"
|
||||
|
||||
#include "pdb/pikapdb.h"
|
||||
|
||||
#include "plug-in/pikapluginmanager-file.h"
|
||||
#include "plug-in/pikapluginprocedure.h"
|
||||
|
||||
#include "file-import.h"
|
||||
#include "file-open.h"
|
||||
#include "file-remote.h"
|
||||
#include "pika-file.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
static void file_open_sanitize_image (PikaImage *image,
|
||||
gboolean as_new);
|
||||
static void file_open_convert_items (PikaImage *dest_image,
|
||||
const gchar *basename,
|
||||
GList *items);
|
||||
static GList * file_open_get_layers (PikaImage *image,
|
||||
gboolean merge_visible,
|
||||
gint *n_visible);
|
||||
static gboolean file_open_file_proc_is_import (PikaPlugInProcedure *file_proc);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaImage *
|
||||
file_open_image (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
gboolean as_new,
|
||||
PikaPlugInProcedure *file_proc,
|
||||
PikaRunMode run_mode,
|
||||
PikaPDBStatusType *status,
|
||||
const gchar **mime_type,
|
||||
GError **error)
|
||||
{
|
||||
PikaValueArray *return_vals;
|
||||
GFile *orig_file;
|
||||
PikaImage *image = NULL;
|
||||
GFile *local_file = NULL;
|
||||
gboolean mounted = TRUE;
|
||||
GError *my_error = NULL;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (status != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
*status = PIKA_PDB_EXECUTION_ERROR;
|
||||
|
||||
orig_file = file;
|
||||
|
||||
if (! g_file_is_native (file) &&
|
||||
! file_remote_mount_file (pika, file, progress, &my_error))
|
||||
{
|
||||
if (my_error)
|
||||
{
|
||||
g_printerr ("%s: mounting remote volume failed, trying to download "
|
||||
"the file: %s\n",
|
||||
G_STRFUNC, my_error->message);
|
||||
g_clear_error (&my_error);
|
||||
|
||||
mounted = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*status = PIKA_PDB_CANCEL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME enable these tests for remote files again, needs testing */
|
||||
if (g_file_is_native (file) &&
|
||||
g_file_query_exists (file, NULL))
|
||||
{
|
||||
GFileInfo *info;
|
||||
|
||||
info = g_file_query_info (file,
|
||||
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
|
||||
G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
NULL, error);
|
||||
if (! info)
|
||||
return NULL;
|
||||
|
||||
if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
|
||||
{
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("Not a regular file"));
|
||||
g_object_unref (info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (! g_file_info_get_attribute_boolean (info,
|
||||
G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
|
||||
{
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("Permission denied"));
|
||||
g_object_unref (info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
if (! file_proc)
|
||||
file_proc = pika_plug_in_manager_file_procedure_find (pika->plug_in_manager,
|
||||
PIKA_FILE_PROCEDURE_GROUP_OPEN,
|
||||
file, error);
|
||||
|
||||
if (! file_proc || ! file_proc->handles_remote || ! mounted)
|
||||
{
|
||||
gchar *my_path = g_file_get_path (file);
|
||||
|
||||
if (! my_path)
|
||||
{
|
||||
g_clear_error (error);
|
||||
|
||||
local_file = file_remote_download_image (pika, file, progress,
|
||||
&my_error);
|
||||
|
||||
if (! local_file)
|
||||
{
|
||||
if (my_error)
|
||||
g_propagate_error (error, my_error);
|
||||
else
|
||||
*status = PIKA_PDB_CANCEL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* if we don't have a file proc yet, try again on the local
|
||||
* file
|
||||
*/
|
||||
if (! file_proc)
|
||||
file_proc = pika_plug_in_manager_file_procedure_find (pika->plug_in_manager,
|
||||
PIKA_FILE_PROCEDURE_GROUP_OPEN,
|
||||
local_file, error);
|
||||
|
||||
file = local_file;
|
||||
}
|
||||
|
||||
g_free (my_path);
|
||||
}
|
||||
|
||||
if (! file_proc)
|
||||
{
|
||||
if (local_file)
|
||||
{
|
||||
g_file_delete (local_file, NULL, NULL);
|
||||
g_object_unref (local_file);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (progress)
|
||||
g_object_add_weak_pointer (G_OBJECT (progress), (gpointer) &progress);
|
||||
|
||||
return_vals =
|
||||
pika_pdb_execute_procedure_by_name (pika->pdb,
|
||||
context, progress, error,
|
||||
pika_object_get_name (file_proc),
|
||||
PIKA_TYPE_RUN_MODE, run_mode,
|
||||
G_TYPE_FILE, file,
|
||||
G_TYPE_NONE);
|
||||
|
||||
if (progress)
|
||||
g_object_remove_weak_pointer (G_OBJECT (progress), (gpointer) &progress);
|
||||
|
||||
*status = g_value_get_enum (pika_value_array_index (return_vals, 0));
|
||||
|
||||
if (*status == PIKA_PDB_SUCCESS && ! file_proc->generic_file_proc)
|
||||
image = g_value_get_object (pika_value_array_index (return_vals, 1));
|
||||
|
||||
/* set the file on all images, plug-ins are not required to do it
|
||||
* any longer
|
||||
*/
|
||||
if (image)
|
||||
pika_image_set_file (image, orig_file);
|
||||
|
||||
if (local_file)
|
||||
{
|
||||
g_file_delete (local_file, NULL, NULL);
|
||||
g_object_unref (local_file);
|
||||
}
|
||||
|
||||
if (*status == PIKA_PDB_SUCCESS)
|
||||
{
|
||||
if (image)
|
||||
{
|
||||
/* Only set the load procedure if it hasn't already been set. */
|
||||
if (! pika_image_get_load_proc (image))
|
||||
pika_image_set_load_proc (image, file_proc);
|
||||
|
||||
file_proc = pika_image_get_load_proc (image);
|
||||
|
||||
if (mime_type)
|
||||
*mime_type = g_slist_nth_data (file_proc->mime_types_list, 0);
|
||||
}
|
||||
else if (! file_proc->generic_file_proc)
|
||||
{
|
||||
if (error && ! *error)
|
||||
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("%s plug-in returned SUCCESS but did not "
|
||||
"return an image"),
|
||||
pika_procedure_get_label (PIKA_PROCEDURE (file_proc)));
|
||||
|
||||
*status = PIKA_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
}
|
||||
else if (*status != PIKA_PDB_CANCEL)
|
||||
{
|
||||
if (error && ! *error)
|
||||
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("%s plug-in could not open image"),
|
||||
pika_procedure_get_label (PIKA_PROCEDURE (file_proc)));
|
||||
}
|
||||
|
||||
pika_value_array_unref (return_vals);
|
||||
|
||||
if (image)
|
||||
{
|
||||
pika_image_undo_disable (image);
|
||||
|
||||
if (file_open_file_proc_is_import (file_proc))
|
||||
{
|
||||
file_import_image (image, context, orig_file,
|
||||
run_mode == PIKA_RUN_INTERACTIVE,
|
||||
progress);
|
||||
}
|
||||
|
||||
/* Enables undo again */
|
||||
file_open_sanitize_image (image, as_new);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_open_thumbnail:
|
||||
* @pika:
|
||||
* @context:
|
||||
* @progress:
|
||||
* @file: an image file
|
||||
* @size: requested size of the thumbnail
|
||||
* @mime_type: return location for image MIME type
|
||||
* @image_width: return location for image width
|
||||
* @image_height: return location for image height
|
||||
* @format: return location for image format (set to NULL if unknown)
|
||||
* @num_layers: return location for number of layers
|
||||
* (set to -1 if the number of layers is not known)
|
||||
* @error:
|
||||
*
|
||||
* Attempts to load a thumbnail by using a registered thumbnail loader.
|
||||
*
|
||||
* Returns: the thumbnail image
|
||||
*/
|
||||
PikaImage *
|
||||
file_open_thumbnail (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
gint size,
|
||||
const gchar **mime_type,
|
||||
gint *image_width,
|
||||
gint *image_height,
|
||||
const Babl **format,
|
||||
gint *num_layers,
|
||||
GError **error)
|
||||
{
|
||||
PikaPlugInProcedure *file_proc;
|
||||
PikaProcedure *procedure;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (mime_type != NULL, NULL);
|
||||
g_return_val_if_fail (image_width != NULL, NULL);
|
||||
g_return_val_if_fail (image_height != NULL, NULL);
|
||||
g_return_val_if_fail (format != NULL, NULL);
|
||||
g_return_val_if_fail (num_layers != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
*image_width = 0;
|
||||
*image_height = 0;
|
||||
*format = NULL;
|
||||
*num_layers = -1;
|
||||
|
||||
file_proc = pika_plug_in_manager_file_procedure_find (pika->plug_in_manager,
|
||||
PIKA_FILE_PROCEDURE_GROUP_OPEN,
|
||||
file, NULL);
|
||||
|
||||
if (! file_proc || ! file_proc->thumb_loader)
|
||||
return NULL;
|
||||
|
||||
procedure = pika_pdb_lookup_procedure (pika->pdb, file_proc->thumb_loader);
|
||||
|
||||
if (procedure && procedure->num_args >= 2 && procedure->num_values >= 1)
|
||||
{
|
||||
PikaPDBStatusType status;
|
||||
PikaValueArray *return_vals;
|
||||
PikaImage *image = NULL;
|
||||
gchar *uri = NULL;
|
||||
|
||||
uri = g_file_get_uri (file);
|
||||
|
||||
return_vals =
|
||||
pika_pdb_execute_procedure_by_name (pika->pdb,
|
||||
context, progress, error,
|
||||
pika_object_get_name (procedure),
|
||||
G_TYPE_FILE, file,
|
||||
G_TYPE_INT, size,
|
||||
G_TYPE_NONE);
|
||||
|
||||
g_free (uri);
|
||||
|
||||
status = g_value_get_enum (pika_value_array_index (return_vals, 0));
|
||||
|
||||
if (status == PIKA_PDB_SUCCESS &&
|
||||
PIKA_VALUE_HOLDS_IMAGE (pika_value_array_index (return_vals, 1)))
|
||||
{
|
||||
image = g_value_get_object (pika_value_array_index (return_vals, 1));
|
||||
|
||||
if (pika_value_array_length (return_vals) >= 3 &&
|
||||
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 2)) &&
|
||||
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 3)))
|
||||
{
|
||||
*image_width =
|
||||
MAX (0, g_value_get_int (pika_value_array_index (return_vals, 2)));
|
||||
|
||||
*image_height =
|
||||
MAX (0, g_value_get_int (pika_value_array_index (return_vals, 3)));
|
||||
|
||||
if (pika_value_array_length (return_vals) >= 5 &&
|
||||
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 4)))
|
||||
{
|
||||
gint value = g_value_get_int (pika_value_array_index (return_vals, 4));
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case PIKA_RGB_IMAGE:
|
||||
*format = pika_babl_format (PIKA_RGB,
|
||||
PIKA_PRECISION_U8_NON_LINEAR,
|
||||
FALSE, NULL);
|
||||
break;
|
||||
|
||||
case PIKA_RGBA_IMAGE:
|
||||
*format = pika_babl_format (PIKA_RGB,
|
||||
PIKA_PRECISION_U8_NON_LINEAR,
|
||||
TRUE, NULL);
|
||||
break;
|
||||
|
||||
case PIKA_GRAY_IMAGE:
|
||||
*format = pika_babl_format (PIKA_GRAY,
|
||||
PIKA_PRECISION_U8_NON_LINEAR,
|
||||
FALSE, NULL);
|
||||
break;
|
||||
|
||||
case PIKA_GRAYA_IMAGE:
|
||||
*format = pika_babl_format (PIKA_GRAY,
|
||||
PIKA_PRECISION_U8_NON_LINEAR,
|
||||
TRUE, NULL);
|
||||
break;
|
||||
|
||||
case PIKA_INDEXED_IMAGE:
|
||||
case PIKA_INDEXEDA_IMAGE:
|
||||
{
|
||||
const Babl *rgb;
|
||||
const Babl *rgba;
|
||||
|
||||
babl_new_palette ("-pika-indexed-format-dummy",
|
||||
&rgb, &rgba);
|
||||
|
||||
if (value == PIKA_INDEXED_IMAGE)
|
||||
*format = rgb;
|
||||
else
|
||||
*format = rgba;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pika_value_array_length (return_vals) >= 6 &&
|
||||
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 5)))
|
||||
{
|
||||
*num_layers =
|
||||
MAX (0, g_value_get_int (pika_value_array_index (return_vals, 5)));
|
||||
}
|
||||
}
|
||||
|
||||
if (image)
|
||||
{
|
||||
file_open_sanitize_image (image, FALSE);
|
||||
|
||||
*mime_type = g_slist_nth_data (file_proc->mime_types_list, 0);
|
||||
|
||||
#ifdef PIKA_UNSTABLE
|
||||
g_printerr ("opened thumbnail at %d x %d\n",
|
||||
pika_image_get_width (image),
|
||||
pika_image_get_height (image));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
pika_value_array_unref (return_vals);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
file_open_with_display (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
gboolean as_new,
|
||||
GObject *monitor,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error)
|
||||
{
|
||||
return file_open_with_proc_and_display (pika, context, progress,
|
||||
file, as_new, NULL,
|
||||
monitor,
|
||||
status, error);
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
file_open_with_proc_and_display (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
gboolean as_new,
|
||||
PikaPlugInProcedure *file_proc,
|
||||
GObject *monitor,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error)
|
||||
{
|
||||
PikaImage *image;
|
||||
const gchar *mime_type = NULL;
|
||||
PikaRunMode run_mode = PIKA_RUN_INTERACTIVE;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (monitor == NULL || G_IS_OBJECT (monitor), NULL);
|
||||
g_return_val_if_fail (status != NULL, NULL);
|
||||
|
||||
if (pika->no_interface)
|
||||
run_mode = PIKA_RUN_NONINTERACTIVE;
|
||||
|
||||
image = file_open_image (pika, context, progress,
|
||||
file,
|
||||
as_new,
|
||||
file_proc,
|
||||
run_mode,
|
||||
status,
|
||||
&mime_type,
|
||||
error);
|
||||
|
||||
if (image)
|
||||
{
|
||||
/* If the file was imported we want to set the layer name to the
|
||||
* file name. For now, assume that multi-layered imported images
|
||||
* have named the layers already, so only rename the layer of
|
||||
* single-layered imported files. Note that this will also
|
||||
* rename already named layers from e.g. single-layered PSD
|
||||
* files. To solve this properly, we would need new file plug-in
|
||||
* API.
|
||||
*/
|
||||
if (! file_proc)
|
||||
file_proc = pika_image_get_load_proc (image);
|
||||
|
||||
if (file_open_file_proc_is_import (file_proc) &&
|
||||
pika_image_get_n_layers (image) == 1)
|
||||
{
|
||||
PikaObject *layer = pika_image_get_layer_iter (image)->data;
|
||||
gchar *basename;
|
||||
|
||||
basename = g_path_get_basename (pika_file_get_utf8_name (file));
|
||||
|
||||
pika_item_rename (PIKA_ITEM (layer), basename, NULL);
|
||||
pika_image_undo_free (image);
|
||||
pika_image_clean_all (image);
|
||||
|
||||
g_free (basename);
|
||||
}
|
||||
|
||||
if (pika_create_display (image->pika, image, PIKA_UNIT_PIXEL, 1.0,
|
||||
monitor))
|
||||
{
|
||||
/* the display owns the image now */
|
||||
g_object_unref (image);
|
||||
}
|
||||
|
||||
if (! as_new)
|
||||
{
|
||||
PikaDocumentList *documents = PIKA_DOCUMENT_LIST (pika->documents);
|
||||
PikaImagefile *imagefile;
|
||||
GFile *any_file;
|
||||
|
||||
imagefile = pika_document_list_add_file (documents, file, mime_type);
|
||||
|
||||
/* can only create a thumbnail if the passed file and the
|
||||
* resulting image's file match. Use any_file() here so we
|
||||
* create thumbnails for both XCF and imported images.
|
||||
*/
|
||||
any_file = pika_image_get_any_file (image);
|
||||
|
||||
if (any_file && g_file_equal (file, any_file))
|
||||
{
|
||||
/* no need to save a thumbnail if there's a good one already */
|
||||
if (! pika_imagefile_check_thumbnail (imagefile))
|
||||
{
|
||||
pika_imagefile_save_thumbnail (imagefile, mime_type, image,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* announce that we opened this image */
|
||||
pika_image_opened (image->pika, file);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
GList *
|
||||
file_open_layers (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaImage *dest_image,
|
||||
gboolean merge_visible,
|
||||
GFile *file,
|
||||
PikaRunMode run_mode,
|
||||
PikaPlugInProcedure *file_proc,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error)
|
||||
{
|
||||
PikaImage *new_image;
|
||||
GList *layers = NULL;
|
||||
const gchar *mime_type = NULL;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (dest_image), NULL);
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (status != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
new_image = file_open_image (pika, context, progress,
|
||||
file, FALSE,
|
||||
file_proc,
|
||||
run_mode,
|
||||
status, &mime_type, error);
|
||||
|
||||
if (new_image)
|
||||
{
|
||||
gint n_visible = 0;
|
||||
|
||||
pika_image_undo_disable (new_image);
|
||||
|
||||
layers = file_open_get_layers (new_image, merge_visible, &n_visible);
|
||||
|
||||
if (merge_visible && n_visible > 1)
|
||||
{
|
||||
g_list_free (layers);
|
||||
|
||||
layers = pika_image_merge_visible_layers (new_image, context,
|
||||
PIKA_CLIP_TO_IMAGE,
|
||||
FALSE, FALSE,
|
||||
NULL);
|
||||
layers = g_list_copy (layers);
|
||||
}
|
||||
|
||||
if (layers)
|
||||
{
|
||||
gchar *basename;
|
||||
|
||||
basename = g_path_get_basename (pika_file_get_utf8_name (file));
|
||||
file_open_convert_items (dest_image, basename, layers);
|
||||
g_free (basename);
|
||||
|
||||
pika_document_list_add_file (PIKA_DOCUMENT_LIST (pika->documents),
|
||||
file, mime_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("Image doesn't contain any layers"));
|
||||
*status = PIKA_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
g_object_unref (new_image);
|
||||
}
|
||||
|
||||
return g_list_reverse (layers);
|
||||
}
|
||||
|
||||
|
||||
/* This function is called for filenames passed on the command-line
|
||||
* or from the D-Bus service.
|
||||
*/
|
||||
gboolean
|
||||
file_open_from_command_line (Pika *pika,
|
||||
GFile *file,
|
||||
gboolean as_new,
|
||||
GObject *monitor)
|
||||
|
||||
{
|
||||
PikaImage *image;
|
||||
PikaDisplay *display;
|
||||
PikaPDBStatusType status;
|
||||
gboolean success = FALSE;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
||||
g_return_val_if_fail (monitor == NULL || G_IS_OBJECT (monitor), FALSE);
|
||||
|
||||
display = pika_get_empty_display (pika);
|
||||
|
||||
/* show the progress in the last opened display, see bug #704896 */
|
||||
if (! display)
|
||||
display = pika_context_get_display (pika_get_user_context (pika));
|
||||
|
||||
if (display)
|
||||
g_object_add_weak_pointer (G_OBJECT (display), (gpointer) &display);
|
||||
|
||||
image = file_open_with_display (pika,
|
||||
pika_get_user_context (pika),
|
||||
PIKA_PROGRESS (display),
|
||||
file, as_new,
|
||||
monitor,
|
||||
&status, &error);
|
||||
|
||||
if (image)
|
||||
{
|
||||
success = TRUE;
|
||||
|
||||
g_object_set_data_full (G_OBJECT (pika), PIKA_FILE_OPEN_LAST_FILE_KEY,
|
||||
g_object_ref (file),
|
||||
(GDestroyNotify) g_object_unref);
|
||||
}
|
||||
else if (status != PIKA_PDB_SUCCESS && status != PIKA_PDB_CANCEL && display)
|
||||
{
|
||||
pika_message (pika, G_OBJECT (display), PIKA_MESSAGE_ERROR,
|
||||
_("Opening '%s' failed: %s"),
|
||||
pika_file_get_utf8_name (file), error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
if (display)
|
||||
g_object_remove_weak_pointer (G_OBJECT (display), (gpointer) &display);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
file_open_sanitize_image (PikaImage *image,
|
||||
gboolean as_new)
|
||||
{
|
||||
if (as_new)
|
||||
pika_image_set_file (image, NULL);
|
||||
|
||||
/* clear all undo steps */
|
||||
pika_image_undo_free (image);
|
||||
|
||||
/* make sure that undo is enabled */
|
||||
while (! pika_image_undo_is_enabled (image))
|
||||
pika_image_undo_thaw (image);
|
||||
|
||||
/* Set the image to clean. Note that export dirtiness is not set to
|
||||
* clean here; we can only consider export clean after the first
|
||||
* export
|
||||
*/
|
||||
pika_image_clean_all (image);
|
||||
|
||||
/* Make sure the projection is completely constructed from valid
|
||||
* layers, this is needed in case something triggers projection or
|
||||
* image preview creation before all layers are loaded, see bug #767663.
|
||||
*/
|
||||
pika_image_invalidate_all (image);
|
||||
|
||||
/* Make sure all image states are up-to-date */
|
||||
pika_image_flush (image);
|
||||
}
|
||||
|
||||
/* Converts items from one image to another */
|
||||
static void
|
||||
file_open_convert_items (PikaImage *dest_image,
|
||||
const gchar *basename,
|
||||
GList *items)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
for (list = items; list; list = g_list_next (list))
|
||||
{
|
||||
PikaItem *src = list->data;
|
||||
PikaItem *item;
|
||||
|
||||
item = pika_item_convert (src, dest_image, G_TYPE_FROM_INSTANCE (src));
|
||||
|
||||
if (g_list_length (items) == 1)
|
||||
{
|
||||
pika_object_set_name (PIKA_OBJECT (item), basename);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_object_set_name (PIKA_OBJECT (item),
|
||||
pika_object_get_name (src));
|
||||
}
|
||||
|
||||
list->data = item;
|
||||
}
|
||||
}
|
||||
|
||||
static GList *
|
||||
file_open_get_layers (PikaImage *image,
|
||||
gboolean merge_visible,
|
||||
gint *n_visible)
|
||||
{
|
||||
GList *iter = NULL;
|
||||
GList *layers = NULL;
|
||||
|
||||
for (iter = pika_image_get_layer_iter (image);
|
||||
iter;
|
||||
iter = g_list_next (iter))
|
||||
{
|
||||
PikaItem *item = iter->data;
|
||||
|
||||
if (! merge_visible)
|
||||
layers = g_list_prepend (layers, item);
|
||||
|
||||
if (pika_item_get_visible (item))
|
||||
{
|
||||
if (n_visible)
|
||||
(*n_visible)++;
|
||||
|
||||
if (! layers)
|
||||
layers = g_list_prepend (layers, item);
|
||||
}
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
file_open_file_proc_is_import (PikaPlugInProcedure *file_proc)
|
||||
{
|
||||
return !(file_proc &&
|
||||
file_proc->mime_types &&
|
||||
strcmp (file_proc->mime_types, "image/x-xcf") == 0);
|
||||
}
|
86
app/file/file-open.h
Normal file
86
app/file/file-open.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* 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
|
||||
*
|
||||
* file-open.h
|
||||
*
|
||||
* 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_OPEN_H__
|
||||
#define __FILE_OPEN_H__
|
||||
|
||||
|
||||
PikaImage * file_open_image (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
gboolean as_new,
|
||||
PikaPlugInProcedure *file_proc,
|
||||
PikaRunMode run_mode,
|
||||
PikaPDBStatusType *status,
|
||||
const gchar **mime_type,
|
||||
GError **error);
|
||||
|
||||
PikaImage * file_open_thumbnail (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
gint size,
|
||||
const gchar **mime_type,
|
||||
gint *image_width,
|
||||
gint *image_height,
|
||||
const Babl **format,
|
||||
gint *num_layers,
|
||||
GError **error);
|
||||
PikaImage * file_open_with_display (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
gboolean as_new,
|
||||
GObject *monitor,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error);
|
||||
|
||||
PikaImage * file_open_with_proc_and_display (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
gboolean as_new,
|
||||
PikaPlugInProcedure *file_proc,
|
||||
GObject *monitor,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error);
|
||||
|
||||
GList * file_open_layers (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaImage *dest_image,
|
||||
gboolean merge_visible,
|
||||
GFile *file,
|
||||
PikaRunMode run_mode,
|
||||
PikaPlugInProcedure *file_proc,
|
||||
PikaPDBStatusType *status,
|
||||
GError **error);
|
||||
|
||||
gboolean file_open_from_command_line (Pika *pika,
|
||||
GFile *file,
|
||||
gboolean as_new,
|
||||
GObject *monitor);
|
||||
|
||||
|
||||
#endif /* __FILE_OPEN_H__ */
|
405
app/file/file-remote.c
Normal file
405
app/file/file-remote.c
Normal file
@ -0,0 +1,405 @@
|
||||
/* 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-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* file-remote.c
|
||||
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* Based on: URI plug-in, GIO/GVfs backend
|
||||
* Copyright (C) 2008 Sven Neumann <sven@gimp.org>
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core/core-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikaprogress.h"
|
||||
|
||||
#include "file-remote.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DOWNLOAD,
|
||||
UPLOAD
|
||||
} RemoteCopyMode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PikaProgress *progress;
|
||||
GCancellable *cancellable;
|
||||
gboolean cancel;
|
||||
GMainLoop *main_loop;
|
||||
GError *error;
|
||||
} RemoteMount;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RemoteCopyMode mode;
|
||||
PikaProgress *progress;
|
||||
GCancellable *cancellable;
|
||||
gboolean cancel;
|
||||
gint64 last_time;
|
||||
} RemoteProgress;
|
||||
|
||||
|
||||
static void file_remote_mount_volume_ready (GFile *file,
|
||||
GAsyncResult *result,
|
||||
RemoteMount *mount);
|
||||
static void file_remote_mount_file_cancel (PikaProgress *progress,
|
||||
RemoteMount *mount);
|
||||
|
||||
static GFile * file_remote_get_temp_file (Pika *pika,
|
||||
GFile *file);
|
||||
static gboolean file_remote_copy_file (Pika *pika,
|
||||
GFile *src_file,
|
||||
GFile *dest_file,
|
||||
RemoteCopyMode mode,
|
||||
PikaProgress *progress,
|
||||
GError **error);
|
||||
static void file_remote_copy_file_cancel (PikaProgress *progress,
|
||||
RemoteProgress *remote_progress);
|
||||
|
||||
static void file_remote_progress_callback (goffset current_num_bytes,
|
||||
goffset total_num_bytes,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
gboolean
|
||||
file_remote_mount_file (Pika *pika,
|
||||
GFile *file,
|
||||
PikaProgress *progress,
|
||||
GError **error)
|
||||
{
|
||||
GMountOperation *operation;
|
||||
RemoteMount mount = { 0, };
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
mount.progress = progress;
|
||||
mount.main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
operation = pika_get_mount_operation (pika, progress);
|
||||
|
||||
if (progress)
|
||||
{
|
||||
pika_progress_start (progress, TRUE, _("Mounting remote volume"));
|
||||
|
||||
mount.cancellable = g_cancellable_new ();
|
||||
|
||||
g_signal_connect (progress, "cancel",
|
||||
G_CALLBACK (file_remote_mount_file_cancel),
|
||||
&mount);
|
||||
}
|
||||
|
||||
g_file_mount_enclosing_volume (file, G_MOUNT_MOUNT_NONE,
|
||||
operation, mount.cancellable,
|
||||
(GAsyncReadyCallback) file_remote_mount_volume_ready,
|
||||
&mount);
|
||||
|
||||
g_main_loop_run (mount.main_loop);
|
||||
g_main_loop_unref (mount.main_loop);
|
||||
|
||||
if (progress)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (progress,
|
||||
file_remote_mount_file_cancel,
|
||||
&mount);
|
||||
|
||||
g_object_unref (mount.cancellable);
|
||||
|
||||
pika_progress_end (progress);
|
||||
}
|
||||
|
||||
g_object_unref (operation);
|
||||
|
||||
if (mount.error)
|
||||
{
|
||||
if (mount.error->domain != G_IO_ERROR ||
|
||||
mount.error->code != G_IO_ERROR_ALREADY_MOUNTED)
|
||||
{
|
||||
g_propagate_error (error, mount.error);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_error (&mount.error);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GFile *
|
||||
file_remote_download_image (Pika *pika,
|
||||
GFile *file,
|
||||
PikaProgress *progress,
|
||||
GError **error)
|
||||
{
|
||||
GFile *local_file;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
local_file = file_remote_get_temp_file (pika, file);
|
||||
|
||||
if (! file_remote_copy_file (pika, file, local_file, DOWNLOAD,
|
||||
progress, error))
|
||||
{
|
||||
g_object_unref (local_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return local_file;
|
||||
}
|
||||
|
||||
GFile *
|
||||
file_remote_upload_image_prepare (Pika *pika,
|
||||
GFile *file,
|
||||
PikaProgress *progress,
|
||||
GError **error)
|
||||
{
|
||||
GFile *local_file;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
local_file = file_remote_get_temp_file (pika, file);
|
||||
|
||||
return local_file;
|
||||
}
|
||||
|
||||
gboolean
|
||||
file_remote_upload_image_finish (Pika *pika,
|
||||
GFile *file,
|
||||
GFile *local_file,
|
||||
PikaProgress *progress,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
||||
g_return_val_if_fail (G_IS_FILE (local_file), FALSE);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (! file_remote_copy_file (pika, local_file, file, UPLOAD,
|
||||
progress, error))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
file_remote_mount_volume_ready (GFile *file,
|
||||
GAsyncResult *result,
|
||||
RemoteMount *mount)
|
||||
{
|
||||
g_file_mount_enclosing_volume_finish (file, result, &mount->error);
|
||||
|
||||
g_main_loop_quit (mount->main_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
file_remote_mount_file_cancel (PikaProgress *progress,
|
||||
RemoteMount *mount)
|
||||
{
|
||||
mount->cancel = TRUE;
|
||||
|
||||
g_cancellable_cancel (mount->cancellable);
|
||||
}
|
||||
|
||||
static GFile *
|
||||
file_remote_get_temp_file (Pika *pika,
|
||||
GFile *file)
|
||||
{
|
||||
gchar *basename;
|
||||
GFile *temp_file = NULL;
|
||||
|
||||
basename = g_path_get_basename (pika_file_get_utf8_name (file));
|
||||
|
||||
if (basename)
|
||||
{
|
||||
const gchar *ext = strchr (basename, '.');
|
||||
|
||||
if (ext && strlen (ext))
|
||||
temp_file = pika_get_temp_file (pika, ext + 1);
|
||||
|
||||
g_free (basename);
|
||||
}
|
||||
|
||||
if (! temp_file)
|
||||
temp_file = pika_get_temp_file (pika, "xxx");
|
||||
|
||||
return temp_file;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
file_remote_copy_file (Pika *pika,
|
||||
GFile *src_file,
|
||||
GFile *dest_file,
|
||||
RemoteCopyMode mode,
|
||||
PikaProgress *progress,
|
||||
GError **error)
|
||||
{
|
||||
RemoteProgress remote_progress = { 0, };
|
||||
gboolean success;
|
||||
GError *my_error = NULL;
|
||||
|
||||
remote_progress.mode = mode;
|
||||
remote_progress.progress = progress;
|
||||
|
||||
if (progress)
|
||||
{
|
||||
pika_progress_start (progress, TRUE, _("Opening remote file"));
|
||||
|
||||
remote_progress.cancellable = g_cancellable_new ();
|
||||
|
||||
g_signal_connect (progress, "cancel",
|
||||
G_CALLBACK (file_remote_copy_file_cancel),
|
||||
&remote_progress);
|
||||
|
||||
success = g_file_copy (src_file, dest_file, G_FILE_COPY_OVERWRITE,
|
||||
remote_progress.cancellable,
|
||||
file_remote_progress_callback, &remote_progress,
|
||||
&my_error);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (progress,
|
||||
file_remote_copy_file_cancel,
|
||||
&remote_progress);
|
||||
|
||||
g_object_unref (remote_progress.cancellable);
|
||||
|
||||
pika_progress_set_value (progress, 1.0);
|
||||
pika_progress_end (progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = g_file_copy (src_file, dest_file, G_FILE_COPY_OVERWRITE,
|
||||
NULL, NULL, NULL,
|
||||
&my_error);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
file_remote_copy_file_cancel (PikaProgress *progress,
|
||||
RemoteProgress *remote_progress)
|
||||
{
|
||||
remote_progress->cancel = TRUE;
|
||||
|
||||
g_cancellable_cancel (remote_progress->cancellable);
|
||||
}
|
||||
|
||||
static void
|
||||
file_remote_progress_callback (goffset current_num_bytes,
|
||||
goffset total_num_bytes,
|
||||
gpointer user_data)
|
||||
{
|
||||
RemoteProgress *progress = user_data;
|
||||
gint64 now;
|
||||
|
||||
/* update the progress only up to 10 times a second */
|
||||
now = g_get_monotonic_time ();
|
||||
|
||||
if ((now - progress->last_time) / 1000 < 100)
|
||||
return;
|
||||
|
||||
progress->last_time = now;
|
||||
|
||||
if (total_num_bytes > 0)
|
||||
{
|
||||
const gchar *format;
|
||||
gchar *done = g_format_size (current_num_bytes);
|
||||
gchar *total = g_format_size (total_num_bytes);
|
||||
|
||||
switch (progress->mode)
|
||||
{
|
||||
case DOWNLOAD:
|
||||
format = _("Downloading image (%s of %s)");
|
||||
break;
|
||||
|
||||
case UPLOAD:
|
||||
format = _("Uploading image (%s of %s)");
|
||||
break;
|
||||
|
||||
default:
|
||||
pika_assert_not_reached ();
|
||||
}
|
||||
|
||||
pika_progress_set_text (progress->progress, format, done, total);
|
||||
g_free (total);
|
||||
g_free (done);
|
||||
|
||||
pika_progress_set_value (progress->progress,
|
||||
(gdouble) current_num_bytes /
|
||||
(gdouble) total_num_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
const gchar *format;
|
||||
gchar *done = g_format_size (current_num_bytes);
|
||||
|
||||
switch (progress->mode)
|
||||
{
|
||||
case DOWNLOAD:
|
||||
format = _("Downloaded %s of image data");
|
||||
break;
|
||||
|
||||
case UPLOAD:
|
||||
format = _("Uploaded %s of image data");
|
||||
break;
|
||||
|
||||
default:
|
||||
pika_assert_not_reached ();
|
||||
}
|
||||
|
||||
pika_progress_set_text (progress->progress, format, done);
|
||||
g_free (done);
|
||||
|
||||
pika_progress_pulse (progress->progress);
|
||||
}
|
||||
|
||||
while (! progress->cancel && g_main_context_pending (NULL))
|
||||
g_main_context_iteration (NULL, FALSE);
|
||||
}
|
52
app/file/file-remote.h
Normal file
52
app/file/file-remote.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* 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-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* file-remote.h
|
||||
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* Based on: URI plug-in, GIO/GVfs backend
|
||||
* Copyright (C) 2008 Sven Neumann <sven@gimp.org>
|
||||
*
|
||||
* 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_REMOTE_H__
|
||||
#define __FILE_REMOTE_H__
|
||||
|
||||
|
||||
gboolean file_remote_mount_file (Pika *pika,
|
||||
GFile *file,
|
||||
PikaProgress *progress,
|
||||
GError **error);
|
||||
|
||||
GFile * file_remote_download_image (Pika *pika,
|
||||
GFile *file,
|
||||
PikaProgress *progress,
|
||||
GError **error);
|
||||
|
||||
GFile * file_remote_upload_image_prepare (Pika *pika,
|
||||
GFile *file,
|
||||
PikaProgress *progress,
|
||||
GError **error);
|
||||
gboolean file_remote_upload_image_finish (Pika *pika,
|
||||
GFile *file,
|
||||
GFile *local_file,
|
||||
PikaProgress *progress,
|
||||
GError **error);
|
||||
|
||||
#endif /* __FILE_REMOTE_H__ */
|
323
app/file/file-save.c
Normal file
323
app/file/file-save.c
Normal file
@ -0,0 +1,323 @@
|
||||
/* 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, 1996, 1997 Spencer Kimball and Peter Mattis
|
||||
* Copyright (C) 1997 Josh MacDonald
|
||||
*
|
||||
* file-save.c
|
||||
*
|
||||
* 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 "config/pikacoreconfig.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikacontext.h"
|
||||
#include "core/pikadocumentlist.h"
|
||||
#include "core/pikadrawable.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaimagefile.h"
|
||||
#include "core/pikaparamspecs.h"
|
||||
#include "core/pikaprogress.h"
|
||||
|
||||
#include "pdb/pikapdb.h"
|
||||
|
||||
#include "plug-in/pikapluginprocedure.h"
|
||||
|
||||
#include "file-remote.h"
|
||||
#include "file-save.h"
|
||||
#include "pika-file.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaPDBStatusType
|
||||
file_save (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
PikaPlugInProcedure *file_proc,
|
||||
PikaRunMode run_mode,
|
||||
gboolean change_saved_state,
|
||||
gboolean export_backward,
|
||||
gboolean export_forward,
|
||||
GError **error)
|
||||
{
|
||||
PikaValueArray *return_vals;
|
||||
GFile *orig_file;
|
||||
PikaPDBStatusType status = PIKA_PDB_EXECUTION_ERROR;
|
||||
GFile *local_file = NULL;
|
||||
gboolean mounted = TRUE;
|
||||
GError *my_error = NULL;
|
||||
GList *drawables_list;
|
||||
PikaDrawable **drawables = NULL;
|
||||
gint n_drawables;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), PIKA_PDB_CALLING_ERROR);
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), PIKA_PDB_CALLING_ERROR);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress),
|
||||
PIKA_PDB_CALLING_ERROR);
|
||||
g_return_val_if_fail (G_IS_FILE (file), PIKA_PDB_CALLING_ERROR);
|
||||
g_return_val_if_fail (PIKA_IS_PLUG_IN_PROCEDURE (file_proc),
|
||||
PIKA_PDB_CALLING_ERROR);
|
||||
g_return_val_if_fail ((export_backward && export_forward) == FALSE,
|
||||
PIKA_PDB_CALLING_ERROR);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL,
|
||||
PIKA_PDB_CALLING_ERROR);
|
||||
|
||||
orig_file = file;
|
||||
|
||||
/* ref image and file, so they can't get deleted during save */
|
||||
g_object_ref (image);
|
||||
g_object_ref (orig_file);
|
||||
|
||||
pika_image_saving (image);
|
||||
|
||||
drawables_list = pika_image_get_selected_drawables (image);
|
||||
|
||||
if (drawables_list)
|
||||
{
|
||||
GList *iter;
|
||||
gint i;
|
||||
|
||||
n_drawables = g_list_length (drawables_list);
|
||||
drawables = g_new (PikaDrawable *, n_drawables);
|
||||
for (iter = drawables_list, i = 0; iter; iter = iter->next, i++)
|
||||
drawables[i] = iter->data;
|
||||
|
||||
g_list_free (drawables_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("There is no active layer to save"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME enable these tests for remote files again, needs testing */
|
||||
if (g_file_is_native (file) &&
|
||||
g_file_query_exists (file, NULL))
|
||||
{
|
||||
GFileInfo *info;
|
||||
|
||||
info = g_file_query_info (file,
|
||||
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
|
||||
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
NULL, error);
|
||||
if (! info)
|
||||
{
|
||||
/* extra paranoia */
|
||||
if (error && ! *error)
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("Failed to get file information"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
|
||||
{
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("Not a regular file"));
|
||||
g_object_unref (info);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (! g_file_info_get_attribute_boolean (info,
|
||||
G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
|
||||
{
|
||||
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("Permission denied"));
|
||||
g_object_unref (info);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
if (! g_file_is_native (file) &&
|
||||
! file_remote_mount_file (pika, file, progress, &my_error))
|
||||
{
|
||||
if (my_error)
|
||||
{
|
||||
g_printerr ("%s: mounting remote volume failed, trying to upload "
|
||||
"the file: %s\n",
|
||||
G_STRFUNC, my_error->message);
|
||||
g_clear_error (&my_error);
|
||||
|
||||
mounted = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = PIKA_PDB_CANCEL;
|
||||
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (! file_proc->handles_remote || ! mounted)
|
||||
{
|
||||
gchar *my_path = g_file_get_path (file);
|
||||
|
||||
if (! my_path)
|
||||
{
|
||||
local_file = file_remote_upload_image_prepare (pika, file, progress,
|
||||
&my_error);
|
||||
|
||||
if (! local_file)
|
||||
{
|
||||
if (my_error)
|
||||
g_propagate_error (error, my_error);
|
||||
else
|
||||
status = PIKA_PDB_CANCEL;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
file = local_file;
|
||||
}
|
||||
|
||||
g_free (my_path);
|
||||
}
|
||||
|
||||
return_vals =
|
||||
pika_pdb_execute_procedure_by_name (image->pika->pdb,
|
||||
pika_get_user_context (pika),
|
||||
progress, error,
|
||||
pika_object_get_name (file_proc),
|
||||
PIKA_TYPE_RUN_MODE, run_mode,
|
||||
PIKA_TYPE_IMAGE, image,
|
||||
G_TYPE_INT, n_drawables,
|
||||
PIKA_TYPE_OBJECT_ARRAY, drawables,
|
||||
G_TYPE_FILE, file,
|
||||
G_TYPE_NONE);
|
||||
status = g_value_get_enum (pika_value_array_index (return_vals, 0));
|
||||
|
||||
pika_value_array_unref (return_vals);
|
||||
g_clear_pointer (&drawables, g_free);
|
||||
|
||||
if (local_file)
|
||||
{
|
||||
if (status == PIKA_PDB_SUCCESS)
|
||||
{
|
||||
GError *my_error = NULL;
|
||||
|
||||
if (! file_remote_upload_image_finish (pika, orig_file, local_file,
|
||||
progress, &my_error))
|
||||
{
|
||||
status = PIKA_PDB_EXECUTION_ERROR;
|
||||
|
||||
if (my_error)
|
||||
g_propagate_error (error, my_error);
|
||||
else
|
||||
status = PIKA_PDB_CANCEL;
|
||||
}
|
||||
}
|
||||
|
||||
g_file_delete (local_file, NULL, NULL);
|
||||
g_object_unref (local_file);
|
||||
}
|
||||
|
||||
if (status == PIKA_PDB_SUCCESS)
|
||||
{
|
||||
PikaDocumentList *documents;
|
||||
PikaImagefile *imagefile;
|
||||
|
||||
if (change_saved_state)
|
||||
{
|
||||
pika_image_set_file (image, orig_file);
|
||||
pika_image_set_save_proc (image, file_proc);
|
||||
|
||||
/* Forget the import source when we save. We interpret a
|
||||
* save as that the user is not interested in being able
|
||||
* to quickly export back to the original any longer
|
||||
*/
|
||||
pika_image_set_imported_file (image, NULL);
|
||||
|
||||
pika_image_clean_all (image);
|
||||
}
|
||||
else if (export_backward)
|
||||
{
|
||||
/* We exported the image back to its imported source,
|
||||
* change nothing about export/import flags, only set
|
||||
* the export state to clean
|
||||
*/
|
||||
pika_image_export_clean_all (image);
|
||||
}
|
||||
else if (export_forward)
|
||||
{
|
||||
/* Remember the last entered Export URI for the image. We
|
||||
* only need to do this explicitly when exporting. It
|
||||
* happens implicitly when saving since the PikaObject name
|
||||
* of a PikaImage is the last-save URI
|
||||
*/
|
||||
pika_image_set_exported_file (image, orig_file);
|
||||
pika_image_set_export_proc (image, file_proc);
|
||||
|
||||
/* An image can not be considered both exported and imported
|
||||
* at the same time, so stop consider it as imported now
|
||||
* that we consider it exported.
|
||||
*/
|
||||
pika_image_set_imported_file (image, NULL);
|
||||
|
||||
pika_image_export_clean_all (image);
|
||||
}
|
||||
|
||||
if (export_backward || export_forward)
|
||||
pika_image_exported (image, orig_file);
|
||||
else
|
||||
pika_image_saved (image, orig_file);
|
||||
|
||||
documents = PIKA_DOCUMENT_LIST (image->pika->documents);
|
||||
|
||||
imagefile = pika_document_list_add_file (documents, orig_file,
|
||||
g_slist_nth_data (file_proc->mime_types_list, 0));
|
||||
|
||||
/* only save a thumbnail if we are saving as XCF, see bug #25272 */
|
||||
if (PIKA_PROCEDURE (file_proc)->proc_type == PIKA_PDB_PROC_TYPE_INTERNAL)
|
||||
pika_imagefile_save_thumbnail (imagefile,
|
||||
g_slist_nth_data (file_proc->mime_types_list, 0),
|
||||
image,
|
||||
NULL);
|
||||
}
|
||||
else if (status != PIKA_PDB_CANCEL)
|
||||
{
|
||||
if (error && *error == NULL)
|
||||
{
|
||||
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
_("%s plug-in could not save image"),
|
||||
pika_procedure_get_label (PIKA_PROCEDURE (file_proc)));
|
||||
}
|
||||
}
|
||||
|
||||
pika_image_flush (image);
|
||||
|
||||
out:
|
||||
g_object_unref (orig_file);
|
||||
g_object_unref (image);
|
||||
|
||||
return status;
|
||||
}
|
40
app/file/file-save.h
Normal file
40
app/file/file-save.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* 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
|
||||
*
|
||||
* file-save.h
|
||||
*
|
||||
* 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_SAVE_H__
|
||||
#define __FILE_SAVE_H__
|
||||
|
||||
|
||||
PikaPDBStatusType file_save (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaProgress *progress,
|
||||
GFile *file,
|
||||
PikaPlugInProcedure *file_proc,
|
||||
PikaRunMode run_mode,
|
||||
gboolean change_saved_state,
|
||||
gboolean export_backward,
|
||||
gboolean export_forward,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __FILE_SAVE_H__ */
|
250
app/file/file-utils.c
Normal file
250
app/file/file-utils.c
Normal file
@ -0,0 +1,250 @@
|
||||
/* 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, 1996, 1997 Spencer Kimball and Peter Mattis
|
||||
* Copyright (C) 1997 Josh MacDonald
|
||||
*
|
||||
* file-utils.c
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#include <gegl.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikathumb/pikathumb.h"
|
||||
|
||||
#include "core/core-types.h"
|
||||
|
||||
#include "core/pika.h"
|
||||
#include "core/pikaimage.h"
|
||||
#include "core/pikaimagefile.h"
|
||||
|
||||
#include "plug-in/pikapluginmanager-file.h"
|
||||
|
||||
#include "file-utils.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
static gboolean
|
||||
file_utils_filename_is_uri (const gchar *filename,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (filename != NULL, FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (strstr (filename, "://"))
|
||||
{
|
||||
gchar *scheme;
|
||||
gchar *canon;
|
||||
|
||||
scheme = g_strndup (filename, (strstr (filename, "://") - filename));
|
||||
canon = g_strdup (scheme);
|
||||
|
||||
g_strcanon (canon, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.", '-');
|
||||
|
||||
if (strcmp (scheme, canon) || ! g_ascii_isgraph (canon[0]))
|
||||
{
|
||||
g_set_error (error, G_FILE_ERROR, 0,
|
||||
_("'%s:' is not a valid URI scheme"), scheme);
|
||||
|
||||
g_free (scheme);
|
||||
g_free (canon);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (scheme);
|
||||
g_free (canon);
|
||||
|
||||
if (! g_utf8_validate (filename, -1, NULL))
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
G_CONVERT_ERROR,
|
||||
G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
|
||||
_("Invalid character sequence in URI"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GFile *
|
||||
file_utils_filename_to_file (Pika *pika,
|
||||
const gchar *filename,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
gchar *absolute;
|
||||
GError *temp_error = NULL;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (filename != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
file = g_file_new_for_uri (filename);
|
||||
|
||||
if (! file)
|
||||
{
|
||||
/* Despite the docs says it never fails, it actually can on Windows.
|
||||
* See issue #3093 (and glib#1819).
|
||||
*/
|
||||
g_set_error_literal (error,
|
||||
G_CONVERT_ERROR,
|
||||
G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
|
||||
_("Invalid character sequence in URI"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check for prefixes like http or ftp */
|
||||
if (pika_plug_in_manager_file_procedure_find_by_prefix (pika->plug_in_manager,
|
||||
PIKA_FILE_PROCEDURE_GROUP_OPEN,
|
||||
file))
|
||||
{
|
||||
if (g_utf8_validate (filename, -1, NULL))
|
||||
{
|
||||
return file;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
G_CONVERT_ERROR,
|
||||
G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
|
||||
_("Invalid character sequence in URI"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (file_utils_filename_is_uri (filename, &temp_error))
|
||||
{
|
||||
return file;
|
||||
}
|
||||
else if (temp_error)
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
g_object_unref (file);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
|
||||
if (! g_path_is_absolute (filename))
|
||||
{
|
||||
gchar *current;
|
||||
|
||||
current = g_get_current_dir ();
|
||||
absolute = g_build_filename (current, filename, NULL);
|
||||
g_free (current);
|
||||
}
|
||||
else
|
||||
{
|
||||
absolute = g_strdup (filename);
|
||||
}
|
||||
|
||||
file = g_file_new_for_path (absolute);
|
||||
|
||||
g_free (absolute);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
GdkPixbuf *
|
||||
file_utils_load_thumbnail (GFile *file)
|
||||
{
|
||||
PikaThumbnail *thumbnail = NULL;
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
gchar *uri;
|
||||
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
|
||||
uri = g_file_get_uri (file);
|
||||
|
||||
thumbnail = pika_thumbnail_new ();
|
||||
pika_thumbnail_set_uri (thumbnail, uri);
|
||||
|
||||
g_free (uri);
|
||||
|
||||
pixbuf = pika_thumbnail_load_thumb (thumbnail,
|
||||
(PikaThumbSize) PIKA_THUMBNAIL_SIZE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (pixbuf)
|
||||
{
|
||||
gint width = gdk_pixbuf_get_width (pixbuf);
|
||||
gint height = gdk_pixbuf_get_height (pixbuf);
|
||||
|
||||
if (gdk_pixbuf_get_n_channels (pixbuf) != 3)
|
||||
{
|
||||
GdkPixbuf *tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
|
||||
width, height);
|
||||
|
||||
gdk_pixbuf_composite_color (pixbuf, tmp,
|
||||
0, 0, width, height, 0, 0, 1.0, 1.0,
|
||||
GDK_INTERP_NEAREST, 255,
|
||||
0, 0, PIKA_CHECK_SIZE_SM,
|
||||
0x66666666, 0x99999999);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
pixbuf = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
gboolean
|
||||
file_utils_save_thumbnail (PikaImage *image,
|
||||
GFile *file)
|
||||
{
|
||||
GFile *image_file;
|
||||
gboolean success = FALSE;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
|
||||
g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
||||
|
||||
image_file = pika_image_get_file (image);
|
||||
|
||||
if (image_file)
|
||||
{
|
||||
gchar *image_uri = g_file_get_uri (image_file);
|
||||
gchar *uri = g_file_get_uri (file);
|
||||
|
||||
if (uri && image_uri && ! strcmp (uri, image_uri))
|
||||
{
|
||||
PikaImagefile *imagefile;
|
||||
|
||||
imagefile = pika_imagefile_new (image->pika, file);
|
||||
success = pika_imagefile_save_thumbnail (imagefile, NULL, image,
|
||||
NULL);
|
||||
g_object_unref (imagefile);
|
||||
}
|
||||
|
||||
g_free (image_uri);
|
||||
g_free (uri);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
37
app/file/file-utils.h
Normal file
37
app/file/file-utils.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* 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
|
||||
*
|
||||
* file-utils.h
|
||||
*
|
||||
* 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_UTILS_H__
|
||||
#define __FILE_UTILS_H__
|
||||
|
||||
|
||||
GFile * file_utils_filename_to_file (Pika *pika,
|
||||
const gchar *filename,
|
||||
GError **error);
|
||||
|
||||
GdkPixbuf * file_utils_load_thumbnail (GFile *file);
|
||||
gboolean file_utils_save_thumbnail (PikaImage *image,
|
||||
GFile *file);
|
||||
|
||||
|
||||
#endif /* __FILE_UTILS_H__ */
|
16
app/file/meson.build
Normal file
16
app/file/meson.build
Normal file
@ -0,0 +1,16 @@
|
||||
libappfile_sources = [
|
||||
'file-import.c',
|
||||
'file-open.c',
|
||||
'file-remote.c',
|
||||
'file-save.c',
|
||||
'file-utils.c',
|
||||
]
|
||||
|
||||
libappfile = static_library('appfile',
|
||||
libappfile_sources,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
c_args: '-DG_LOG_DOMAIN="Pika-File"',
|
||||
dependencies: [
|
||||
gegl, gdk_pixbuf,
|
||||
],
|
||||
)
|
34
app/file/pika-file.h
Normal file
34
app/file/pika-file.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-file.h
|
||||
* Copyright (C) 2009 Martin Nordholts <martinn@src.gnome.org>
|
||||
*
|
||||
* 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 __PIKA_FILE_H__
|
||||
#define __PIKA_FILE_H__
|
||||
|
||||
/* Data keys for Pika */
|
||||
#define PIKA_FILE_OPEN_LAST_FILE_KEY "pika-file-open-last-file"
|
||||
#define PIKA_FILE_SAVE_LAST_FILE_KEY "pika-file-save-last-file"
|
||||
#define PIKA_FILE_EXPORT_LAST_FILE_KEY "pika-file-export-last-file"
|
||||
|
||||
|
||||
#endif /* __PIKA_FILE_H__ */
|
Reference in New Issue
Block a user