Updated with upstream update
This commit is contained in:
parent
098531073c
commit
3bbdd873ef
100
.gitlab-ci.yml
100
.gitlab-ci.yml
|
@ -18,7 +18,8 @@
|
|||
# - PIKA_CI_CROSSROAD_WIN64: trigger the crossroad/meson build for Win 64-bit.
|
||||
# - PIKA_CI_MSYS2_WIN32: trigger the native MSYS2 build for Win 32-bit.
|
||||
# - PIKA_CI_MSYS2_WIN64: trigger the native MSYS2 build for Win 64-bit.
|
||||
# - PIKA_CI_WIN_INSTALLER: trigger both native MSYS2 builds then creates Windows installer.
|
||||
# - PIKA_CI_MSYS2_WIN_AARCH64: trigger the native MSYS2 build for Windows/Aarch64.
|
||||
# - PIKA_CI_WIN_INSTALLER: trigger all native MSYS2 builds then creates Windows installer.
|
||||
# - PIKA_CI_SOURCES: trigger the meson/gcc build and the source tarball job.
|
||||
# - PIKA_CI_CPPCHECK: trigger cppcheck static analysis.
|
||||
# - PIKA_CI_FLATPAK: trigger the nightly flatpak build and publishing.
|
||||
|
@ -375,7 +376,7 @@ pika-meson-raster-icons:
|
|||
- ninja -C _build
|
||||
- ninja -C _build test
|
||||
|
||||
## WINDOWS 64-bit CI (native MSYS2) ##
|
||||
## WINDOWS x86_64 CI (native MSYS2) ##
|
||||
|
||||
deps-win64-native:
|
||||
rules:
|
||||
|
@ -462,7 +463,7 @@ packaging-win64-native:
|
|||
- done-dll.list
|
||||
needs: ["pika-win64-native"]
|
||||
|
||||
## WINDOWS 32-bit CI (native MSYS2) ##
|
||||
## WINDOWS x86 CI (native MSYS2) ##
|
||||
|
||||
deps-win32-native:
|
||||
rules:
|
||||
|
@ -548,6 +549,96 @@ packaging-win32-native:
|
|||
- done-dll.list
|
||||
needs: ["pika-win32-native"]
|
||||
|
||||
## WINDOWS Aarch64 CI (native MSYS2) ##
|
||||
|
||||
deps-win-aarch64-native:
|
||||
rules:
|
||||
# On releases.
|
||||
- if: '$CI_COMMIT_TAG != null'
|
||||
# Custom builds though web GUI, API or schedules.
|
||||
- if: '$PIKA_CI_MSYS2_WIN_AARCH64 != null'
|
||||
- if: '$PIKA_CI_WIN_INSTALLER != null'
|
||||
# Merge requests with appropriate label.
|
||||
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
|
||||
stage: dependencies
|
||||
variables:
|
||||
MSYSTEM: "CLANGARM64"
|
||||
CHERE_INVOKING: "yes"
|
||||
tags:
|
||||
- windows-aarch64
|
||||
script:
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/build-deps-msys2.sh"
|
||||
artifacts:
|
||||
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
|
||||
when: always
|
||||
expire_in: 2 hours
|
||||
paths:
|
||||
- _install-arm64
|
||||
needs: []
|
||||
|
||||
pika-win-aarch64-native:
|
||||
rules:
|
||||
# On releases.
|
||||
- if: '$CI_COMMIT_TAG != null'
|
||||
# Custom builds though web GUI, API or schedules.
|
||||
- if: '$PIKA_CI_MSYS2_WIN_AARCH64 != null'
|
||||
- if: '$PIKA_CI_WIN_INSTALLER != null'
|
||||
# Merge requests with appropriate label.
|
||||
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
|
||||
stage: pika
|
||||
variables:
|
||||
MSYSTEM: "CLANGARM64"
|
||||
CHERE_INVOKING: "yes"
|
||||
tags:
|
||||
- windows-aarch64
|
||||
script:
|
||||
# Temporary patch until we use the latest LLVM.
|
||||
- git apply ./build/windows/patches/0001-clang-rc-files-fix.patch
|
||||
- git apply ./build/windows/patches/0004-clang-windres.patch
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/build-pika-msys2.sh"
|
||||
artifacts:
|
||||
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
|
||||
when: always
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- _install-arm64
|
||||
- _build-arm64/build/windows/installer/
|
||||
- _build-arm64/meson-*/
|
||||
cache:
|
||||
paths:
|
||||
- _ccache/
|
||||
needs: ["deps-win-aarch64-native"]
|
||||
|
||||
packaging-win-aarch64-native:
|
||||
rules:
|
||||
# On releases.
|
||||
- if: '$CI_COMMIT_TAG != null'
|
||||
# Custom builds though web GUI, API or schedules.
|
||||
- if: '$PIKA_CI_WIN_INSTALLER != null'
|
||||
# Merge requests with appropriate label.
|
||||
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
|
||||
stage: packaging
|
||||
variables:
|
||||
MSYSTEM: "CLANGARM64"
|
||||
CHERE_INVOKING: "yes"
|
||||
tags:
|
||||
- windows-aarch64
|
||||
script:
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/package-pika-msys2.sh"
|
||||
- cd pika-arm64
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ../build/windows/gitlab-ci/split-debug-msys2.sh"
|
||||
artifacts:
|
||||
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
|
||||
when: always
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- pika-arm64
|
||||
- done-dll.list
|
||||
needs: ["pika-win-aarch64-native"]
|
||||
|
||||
## WINDOWS 64-bit CI (cross-build crossroad) ##
|
||||
|
||||
deps-win64:
|
||||
|
@ -822,6 +913,7 @@ win-installer-nightly:
|
|||
dependencies:
|
||||
- packaging-win64-native
|
||||
- packaging-win32-native
|
||||
- packaging-win-aarch64-native
|
||||
# This is needed for the BMP image generation for the installer.
|
||||
# See commit e1203e9f76f.
|
||||
- pika-meson-debian
|
||||
|
@ -835,7 +927,7 @@ win-installer-nightly:
|
|||
script:
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/installer-pika-msys2.sh > installer.log 2>&1"
|
||||
needs: ["packaging-win32-native", "packaging-win64-native", "pika-meson-debian"]
|
||||
needs: ["packaging-win32-native", "packaging-win64-native", "packaging-win-aarch64-native", "pika-meson-debian"]
|
||||
|
||||
sources-meson:
|
||||
rules:
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "core/pikaimage-colormap.h"
|
||||
|
||||
#include "widgets/pikaactiongroup.h"
|
||||
#include "widgets/pikacolormapeditor.h"
|
||||
#include "widgets/pikahelp-ids.h"
|
||||
|
||||
#include "actions.h"
|
||||
|
@ -49,6 +50,12 @@ static const PikaActionEntry colormap_actions[] =
|
|||
NC_("colormap-action", "_Edit Color..."), NULL, { NULL },
|
||||
NC_("colormap-action", "Edit this color"),
|
||||
colormap_edit_color_cmd_callback,
|
||||
PIKA_HELP_INDEXED_PALETTE_EDIT },
|
||||
|
||||
{ "colormap-delete-color", PIKA_ICON_EDIT_DELETE,
|
||||
NC_("colormap-action", "_Delete Color..."), NULL, { NULL },
|
||||
NC_("colormap-action", "Delete this color"),
|
||||
colormap_delete_color_cmd_callback,
|
||||
PIKA_HELP_INDEXED_PALETTE_EDIT }
|
||||
};
|
||||
|
||||
|
@ -116,13 +123,14 @@ void
|
|||
colormap_actions_update (PikaActionGroup *group,
|
||||
gpointer data)
|
||||
{
|
||||
PikaImage *image = action_data_get_image (data);
|
||||
PikaContext *context = action_data_get_context (data);
|
||||
gboolean indexed = FALSE;
|
||||
gboolean drawable_indexed = FALSE;
|
||||
gint num_colors = 0;
|
||||
PikaRGB fg;
|
||||
PikaRGB bg;
|
||||
PikaColormapEditor *editor = PIKA_COLORMAP_EDITOR (data);
|
||||
PikaImage *image = action_data_get_image (data);
|
||||
PikaContext *context = action_data_get_context (data);
|
||||
gboolean indexed = FALSE;
|
||||
gboolean drawable_indexed = FALSE;
|
||||
gint num_colors = 0;
|
||||
PikaRGB fg;
|
||||
PikaRGB bg;
|
||||
|
||||
if (image)
|
||||
{
|
||||
|
@ -154,6 +162,9 @@ colormap_actions_update (PikaActionGroup *group,
|
|||
|
||||
SET_SENSITIVE ("colormap-edit-color",
|
||||
indexed && num_colors > 0);
|
||||
SET_SENSITIVE ("colormap-delete-color",
|
||||
indexed && num_colors > 0 &&
|
||||
pika_colormap_editor_is_color_deletable (editor));
|
||||
|
||||
SET_SENSITIVE ("colormap-add-color-from-fg",
|
||||
indexed && num_colors < 256);
|
||||
|
|
|
@ -50,6 +50,16 @@ colormap_edit_color_cmd_callback (PikaAction *action,
|
|||
pika_colormap_editor_edit_color (editor);
|
||||
}
|
||||
|
||||
void
|
||||
colormap_delete_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data)
|
||||
{
|
||||
PikaColormapEditor *editor = PIKA_COLORMAP_EDITOR (data);
|
||||
|
||||
pika_colormap_editor_delete_color (editor);
|
||||
}
|
||||
|
||||
void
|
||||
colormap_add_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
void colormap_edit_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data);
|
||||
void colormap_delete_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data);
|
||||
void colormap_add_color_cmd_callback (PikaAction *action,
|
||||
GVariant *value,
|
||||
gpointer data);
|
||||
|
|
|
@ -446,7 +446,7 @@ pika_gegl_procedure_new (Pika *pika,
|
|||
FALSE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
pika_procedure_add_argument (procedure,
|
||||
g_param_spec_int ("n-drawables",
|
||||
g_param_spec_int ("num-drawables",
|
||||
"N drawables",
|
||||
"The number of drawables",
|
||||
0, G_MAXINT32, 0,
|
||||
|
|
|
@ -50,7 +50,7 @@ _("Timestamp of the last update check.")
|
|||
"Defines the color management behavior."
|
||||
|
||||
#define COLOR_PROFILE_POLICY_BLURB \
|
||||
_("How to handle embedded color profiles when opening a file.")
|
||||
_("What to do when opening a file with an embedded ICC color profile.")
|
||||
|
||||
#define COLOR_PROFILE_PATH_BLURB \
|
||||
_("Sets the default folder path for all color profile file dialogs.")
|
||||
|
|
|
@ -1195,6 +1195,7 @@ pika_undo_type_get_type (void)
|
|||
{ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, "PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE", "group-image-vectors-merge" },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, "PIKA_UNDO_GROUP_IMAGE_QUICK_MASK", "group-image-quick-mask" },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_GRID, "PIKA_UNDO_GROUP_IMAGE_GRID", "group-image-grid" },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, "PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP", "group-image-colormap-remap" },
|
||||
{ PIKA_UNDO_GROUP_GUIDE, "PIKA_UNDO_GROUP_GUIDE", "group-guide" },
|
||||
{ PIKA_UNDO_GROUP_SAMPLE_POINT, "PIKA_UNDO_GROUP_SAMPLE_POINT", "group-sample-point" },
|
||||
{ PIKA_UNDO_GROUP_DRAWABLE, "PIKA_UNDO_GROUP_DRAWABLE", "group-drawable" },
|
||||
|
@ -1303,6 +1304,7 @@ pika_undo_type_get_type (void)
|
|||
{ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, NC_("undo-type", "Merge paths"), NULL },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, NC_("undo-type", "Quick Mask"), NULL },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_GRID, NC_("undo-type", "Grid"), NULL },
|
||||
{ PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, NC_("undo-type", "Colormap remapping"), NULL },
|
||||
{ PIKA_UNDO_GROUP_GUIDE, NC_("undo-type", "Guide"), NULL },
|
||||
{ PIKA_UNDO_GROUP_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL },
|
||||
{ PIKA_UNDO_GROUP_DRAWABLE, NC_("undo-type", "Layer/Channel"), NULL },
|
||||
|
|
|
@ -548,6 +548,7 @@ typedef enum /*< pdb-skip >*/
|
|||
PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, /*< desc="Merge paths" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, /*< desc="Quick Mask" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_GRID, /*< desc="Grid" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, /*< desc="Colormap remapping" >*/
|
||||
PIKA_UNDO_GROUP_GUIDE, /*< desc="Guide" >*/
|
||||
PIKA_UNDO_GROUP_SAMPLE_POINT, /*< desc="Sample Point" >*/
|
||||
PIKA_UNDO_GROUP_DRAWABLE, /*< desc="Layer/Channel" >*/
|
||||
|
|
|
@ -33,8 +33,10 @@
|
|||
#include "pikacontainer.h"
|
||||
#include "pikacontext.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikadrawable.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaprogress.h"
|
||||
#include "pikaresource.h"
|
||||
#include "pikawaitable.h"
|
||||
|
||||
#include "about.h"
|
||||
|
@ -325,17 +327,17 @@ pika_get_empty_display (Pika *pika)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
guint32
|
||||
GBytes *
|
||||
pika_get_display_window_id (Pika *pika,
|
||||
PikaDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), -1);
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), -1);
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), NULL);
|
||||
|
||||
if (pika->gui.display_get_window_id)
|
||||
return pika->gui.display_get_window_id (display);
|
||||
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PikaDisplay *
|
||||
|
@ -407,10 +409,11 @@ gboolean
|
|||
pika_pdb_dialog_new (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
GBytes *parent_handle,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
...)
|
||||
{
|
||||
gboolean retval = FALSE;
|
||||
|
@ -418,7 +421,10 @@ pika_pdb_dialog_new (Pika *pika,
|
|||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), FALSE);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
|
||||
g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE), FALSE);
|
||||
g_return_val_if_fail (object == NULL ||
|
||||
g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
|
||||
g_return_val_if_fail (title != NULL, FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
|
||||
|
@ -426,12 +432,11 @@ pika_pdb_dialog_new (Pika *pika,
|
|||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, object_name);
|
||||
va_start (args, object);
|
||||
|
||||
retval = pika->gui.pdb_dialog_new (pika, context, progress,
|
||||
container, title,
|
||||
callback_name, object_name,
|
||||
args);
|
||||
contents_type, parent_handle, title,
|
||||
callback_name, object, args);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
@ -440,27 +445,28 @@ pika_pdb_dialog_new (Pika *pika,
|
|||
}
|
||||
|
||||
gboolean
|
||||
pika_pdb_dialog_set (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
pika_pdb_dialog_set (Pika *pika,
|
||||
GType contents_type,
|
||||
const gchar *callback_name,
|
||||
PikaObject *object,
|
||||
...)
|
||||
{
|
||||
gboolean retval = FALSE;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
|
||||
contents_type == PIKA_TYPE_DRAWABLE, FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
g_return_val_if_fail (object_name != NULL, FALSE);
|
||||
g_return_val_if_fail (object == NULL || g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
|
||||
|
||||
if (pika->gui.pdb_dialog_set)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, object_name);
|
||||
va_start (args, object);
|
||||
|
||||
retval = pika->gui.pdb_dialog_set (pika, container, callback_name,
|
||||
object_name, args);
|
||||
retval = pika->gui.pdb_dialog_set (pika, contents_type, callback_name,
|
||||
object, args);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
@ -470,15 +476,16 @@ pika_pdb_dialog_set (Pika *pika,
|
|||
|
||||
gboolean
|
||||
pika_pdb_dialog_close (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
|
||||
contents_type == PIKA_TYPE_DRAWABLE, FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
|
||||
if (pika->gui.pdb_dialog_close)
|
||||
return pika->gui.pdb_dialog_close (pika, container, callback_name);
|
||||
return pika->gui.pdb_dialog_close (pika, contents_type, callback_name);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ struct _PikaGui
|
|||
|
||||
PikaObject * (* get_window_strategy) (Pika *pika);
|
||||
PikaDisplay * (* get_empty_display) (Pika *pika);
|
||||
guint32 (* display_get_window_id) (PikaDisplay *display);
|
||||
GBytes * (* display_get_window_id) (PikaDisplay *display);
|
||||
PikaDisplay * (* display_create) (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
|
@ -77,18 +77,19 @@ struct _PikaGui
|
|||
gboolean (* pdb_dialog_new) (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
GBytes *parent_handle,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
va_list args);
|
||||
gboolean (* pdb_dialog_set) (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
va_list args);
|
||||
gboolean (* pdb_dialog_close) (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name);
|
||||
gboolean (* recent_list_add_file) (Pika *pika,
|
||||
GFile *file,
|
||||
|
@ -126,7 +127,7 @@ PikaDisplay * pika_get_display_by_id (Pika *pika,
|
|||
gint ID);
|
||||
gint pika_get_display_id (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
guint32 pika_get_display_window_id (Pika *pika,
|
||||
GBytes * pika_get_display_window_id (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
PikaDisplay * pika_create_display (Pika *pika,
|
||||
PikaImage *image,
|
||||
|
@ -175,19 +176,21 @@ GFile * pika_get_icon_theme_dir (Pika *pika);
|
|||
gboolean pika_pdb_dialog_new (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
GBytes *parent_handle,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
gboolean pika_pdb_dialog_set (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
PikaObject *object,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
gboolean pika_pdb_dialog_close (Pika *pika,
|
||||
PikaContainer *container,
|
||||
GType contents_type,
|
||||
const gchar *callback_name);
|
||||
|
||||
gboolean pika_recent_list_add_file (Pika *pika,
|
||||
GFile *file,
|
||||
const gchar *mime_type);
|
||||
|
|
|
@ -202,6 +202,7 @@ pika_container_class_init (PikaContainerClass *klass)
|
|||
klass->search = NULL;
|
||||
klass->get_unique_names = NULL;
|
||||
klass->get_child_by_name = NULL;
|
||||
klass->get_children_by_name = NULL;
|
||||
klass->get_child_by_index = NULL;
|
||||
klass->get_child_index = NULL;
|
||||
|
||||
|
@ -885,6 +886,34 @@ pika_container_get_unique_names (PikaContainer *container)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
GList *
|
||||
pika_container_get_children_by_name (PikaContainer *container,
|
||||
const gchar *name)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), NULL);
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (PIKA_CONTAINER_GET_CLASS (container)->get_children_by_name != NULL &&
|
||||
! pika_container_get_unique_names (container))
|
||||
{
|
||||
return PIKA_CONTAINER_GET_CLASS (container)->get_children_by_name (container,
|
||||
name);
|
||||
}
|
||||
else
|
||||
{
|
||||
PikaObject *child;
|
||||
|
||||
child = PIKA_CONTAINER_GET_CLASS (container)->get_child_by_name (container, name);
|
||||
|
||||
if (child != NULL)
|
||||
return g_list_prepend (NULL, child);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PikaObject *
|
||||
pika_container_get_child_by_name (PikaContainer *container,
|
||||
const gchar *name)
|
||||
|
|
|
@ -79,6 +79,8 @@ struct _PikaContainerClass
|
|||
gboolean (* get_unique_names) (PikaContainer *container);
|
||||
PikaObject * (* get_child_by_name) (PikaContainer *container,
|
||||
const gchar *name);
|
||||
GList * (* get_children_by_name) (PikaContainer *container,
|
||||
const gchar *name);
|
||||
PikaObject * (* get_child_by_index) (PikaContainer *container,
|
||||
gint index);
|
||||
gint (* get_child_index) (PikaContainer *container,
|
||||
|
@ -121,6 +123,8 @@ PikaObject * pika_container_search (PikaContainer *contain
|
|||
|
||||
gboolean pika_container_get_unique_names (PikaContainer *container);
|
||||
|
||||
GList * pika_container_get_children_by_name (PikaContainer *container,
|
||||
const gchar *name);
|
||||
PikaObject * pika_container_get_child_by_name (PikaContainer *container,
|
||||
const gchar *name);
|
||||
PikaObject * pika_container_get_child_by_index (PikaContainer *container,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "pika-memsize.h"
|
||||
#include "pikadata.h"
|
||||
#include "pikaidtable.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikatag.h"
|
||||
#include "pikatagged.h"
|
||||
|
||||
|
@ -51,6 +52,7 @@ enum
|
|||
PROP_0,
|
||||
PROP_ID,
|
||||
PROP_FILE,
|
||||
PROP_IMAGE,
|
||||
PROP_WRITABLE,
|
||||
PROP_DELETABLE,
|
||||
PROP_MIME_TYPE
|
||||
|
@ -59,8 +61,10 @@ enum
|
|||
|
||||
struct _PikaDataPrivate
|
||||
{
|
||||
gint ID;
|
||||
GFile *file;
|
||||
gint ID;
|
||||
GFile *file;
|
||||
PikaImage *image;
|
||||
|
||||
GQuark mime_type;
|
||||
guint writable : 1;
|
||||
guint deletable : 1;
|
||||
|
@ -172,6 +176,11 @@ pika_data_class_init (PikaDataClass *klass)
|
|||
G_TYPE_FILE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_IMAGE,
|
||||
g_param_spec_object ("image", NULL, NULL,
|
||||
PIKA_TYPE_IMAGE,
|
||||
PIKA_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_WRITABLE,
|
||||
g_param_spec_boolean ("writable", NULL, NULL,
|
||||
FALSE,
|
||||
|
@ -268,6 +277,12 @@ pika_data_set_property (GObject *object,
|
|||
private->deletable);
|
||||
break;
|
||||
|
||||
case PROP_IMAGE:
|
||||
pika_data_set_image (data,
|
||||
g_value_get_object (value),
|
||||
private->writable,
|
||||
private->deletable);
|
||||
break;
|
||||
case PROP_WRITABLE:
|
||||
private->writable = g_value_get_boolean (value);
|
||||
break;
|
||||
|
@ -307,6 +322,10 @@ pika_data_get_property (GObject *object,
|
|||
g_value_set_object (value, private->file);
|
||||
break;
|
||||
|
||||
case PROP_IMAGE:
|
||||
g_value_set_object (value, private->image);
|
||||
break;
|
||||
|
||||
case PROP_WRITABLE:
|
||||
g_value_set_boolean (value, private->writable);
|
||||
break;
|
||||
|
@ -462,7 +481,7 @@ pika_data_get_identifier (PikaTagged *tagged)
|
|||
gchar *identifier = NULL;
|
||||
gchar *collection = NULL;
|
||||
|
||||
g_return_val_if_fail (private->internal || private->file != NULL, NULL);
|
||||
g_return_val_if_fail (private->internal || private->file != NULL || private->image != NULL, NULL);
|
||||
|
||||
collection = pika_data_get_collection (data);
|
||||
/* The identifier is guaranteed to be unique because we use 2 directory
|
||||
|
@ -503,7 +522,7 @@ pika_data_get_collection (PikaData *data)
|
|||
PikaDataPrivate *private = PIKA_DATA_GET_PRIVATE (data);
|
||||
gchar *collection = NULL;
|
||||
|
||||
g_return_val_if_fail (private->internal || private->file != NULL, NULL);
|
||||
g_return_val_if_fail (private->internal || private->file != NULL || private->image != NULL, NULL);
|
||||
|
||||
if (private->file)
|
||||
{
|
||||
|
@ -551,6 +570,10 @@ pika_data_get_collection (PikaData *data)
|
|||
|
||||
g_free (path);
|
||||
}
|
||||
else if (private->image)
|
||||
{
|
||||
collection = g_strdup_printf ("[image-id-%d]", pika_image_get_id (private->image));
|
||||
}
|
||||
else if (private->internal)
|
||||
{
|
||||
collection = g_strdup (private->collection);
|
||||
|
@ -603,7 +626,7 @@ pika_data_save (PikaData *data,
|
|||
|
||||
g_return_val_if_fail (private->writable == TRUE, FALSE);
|
||||
|
||||
if (private->internal)
|
||||
if (private->internal || private->image != NULL)
|
||||
{
|
||||
private->dirty = FALSE;
|
||||
return TRUE;
|
||||
|
@ -862,6 +885,8 @@ pika_data_set_file (PikaData *data,
|
|||
if (private->internal)
|
||||
return;
|
||||
|
||||
g_return_if_fail (private->image == NULL);
|
||||
|
||||
g_set_object (&private->file, file);
|
||||
|
||||
private->writable = FALSE;
|
||||
|
@ -937,6 +962,53 @@ pika_data_get_file (PikaData *data)
|
|||
return private->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_data_set_image:
|
||||
* @data: A #PikaData object
|
||||
* @image: Image to assign to @data.
|
||||
* @writable: %TRUE if we want to be able to write to this file.
|
||||
* @deletable: %TRUE if we want to be able to delete this file.
|
||||
*
|
||||
* This function assigns an image to @data. This can only be done if no file has
|
||||
* been assigned (a non-internal data can be attached either to a file or to an
|
||||
* image).
|
||||
**/
|
||||
void
|
||||
pika_data_set_image (PikaData *data,
|
||||
PikaImage *image,
|
||||
gboolean writable,
|
||||
gboolean deletable)
|
||||
{
|
||||
PikaDataPrivate *private;
|
||||
|
||||
g_return_if_fail (PIKA_IS_DATA (data));
|
||||
g_return_if_fail (PIKA_IS_IMAGE (image));
|
||||
|
||||
private = PIKA_DATA_GET_PRIVATE (data);
|
||||
|
||||
if (private->internal)
|
||||
return;
|
||||
|
||||
g_return_if_fail (private->file == NULL);
|
||||
|
||||
g_set_object (&private->image, image);
|
||||
|
||||
private->writable = writable ? TRUE : FALSE;
|
||||
private->deletable = deletable ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
pika_data_get_image (PikaData *data)
|
||||
{
|
||||
PikaDataPrivate *private;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_DATA (data), NULL);
|
||||
|
||||
private = PIKA_DATA_GET_PRIVATE (data);
|
||||
|
||||
return private->image;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_data_create_filename:
|
||||
* @data: a #Pikadata object.
|
||||
|
|
|
@ -102,6 +102,11 @@ void pika_data_set_file (PikaData *data,
|
|||
gboolean writable,
|
||||
gboolean deletable);
|
||||
GFile * pika_data_get_file (PikaData *data);
|
||||
void pika_data_set_image (PikaData *data,
|
||||
PikaImage *image,
|
||||
gboolean writable,
|
||||
gboolean deletable);
|
||||
PikaImage * pika_data_get_image (PikaData *data);
|
||||
|
||||
void pika_data_create_filename (PikaData *data,
|
||||
GFile *dest_dir);
|
||||
|
|
|
@ -403,6 +403,9 @@ pika_data_factory_real_data_save (PikaDataFactory *factory)
|
|||
PikaData *data = list->data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (pika_data_get_image (data))
|
||||
continue;
|
||||
|
||||
if (! pika_data_get_file (data))
|
||||
pika_data_create_filename (data, writable_dir);
|
||||
|
||||
|
@ -460,6 +463,7 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
|
|||
gint copy_len;
|
||||
gint number;
|
||||
gchar *new_name;
|
||||
GError *error = NULL;
|
||||
|
||||
ext = strrchr (name, '#');
|
||||
copy_len = strlen (_("copy"));
|
||||
|
@ -479,8 +483,12 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
|
|||
|
||||
pika_object_take_name (PIKA_OBJECT (new_data), new_name);
|
||||
|
||||
if (! pika_data_factory_data_save_single (factory, new_data, &error))
|
||||
g_critical ("%s: data saving failed: %s", G_STRFUNC, error->message);
|
||||
|
||||
pika_container_add (priv->container, PIKA_OBJECT (new_data));
|
||||
g_object_unref (new_data);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
return new_data;
|
||||
|
@ -674,8 +682,14 @@ pika_data_factory_data_new (PikaDataFactory *factory,
|
|||
|
||||
if (data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (! pika_data_factory_data_save_single (factory, data, &error))
|
||||
g_critical ("%s: data saving failed: %s", G_STRFUNC, error->message);
|
||||
|
||||
pika_container_add (priv->container, PIKA_OBJECT (data));
|
||||
g_object_unref (data);
|
||||
g_clear_error (&error);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -750,7 +764,7 @@ pika_data_factory_data_save_single (PikaDataFactory *factory,
|
|||
g_return_val_if_fail (PIKA_IS_DATA (data), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (! pika_data_is_dirty (data))
|
||||
if (! pika_data_is_dirty (data) || pika_data_get_image (data))
|
||||
return TRUE;
|
||||
|
||||
if (! pika_data_get_file (data))
|
||||
|
|
|
@ -31,25 +31,43 @@
|
|||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "config/pikageglconfig.h"
|
||||
|
||||
#include "gegl/pika-babl.h"
|
||||
#include "gegl/pika-gegl-loops.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pikacontainer.h"
|
||||
#include "pikadatafactory.h"
|
||||
#include "pikadrawable.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaimage-colormap.h"
|
||||
#include "pikaimage-private.h"
|
||||
#include "pikaimage-undo.h"
|
||||
#include "pikaimage-undo-push.h"
|
||||
#include "pikapalette.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GeglBuffer *buffer;
|
||||
const Babl *format;
|
||||
|
||||
/* Shared by jobs. */
|
||||
gboolean *found;
|
||||
GRWLock *lock;
|
||||
} IndexUsedJobData;
|
||||
|
||||
|
||||
/* local function prototype */
|
||||
|
||||
static void pika_image_colormap_set_palette_entry (PikaImage *image,
|
||||
const PikaRGB *color,
|
||||
gint index);
|
||||
static void pika_image_colormap_set_palette_entry (PikaImage *image,
|
||||
const PikaRGB *color,
|
||||
gint index);
|
||||
static void pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
|
||||
gint index);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
@ -80,7 +98,7 @@ pika_image_colormap_init (PikaImage *image)
|
|||
|
||||
pika_palette_set_columns (private->palette, 16);
|
||||
|
||||
pika_data_make_internal (PIKA_DATA (private->palette), palette_id);
|
||||
pika_data_set_image (PIKA_DATA (private->palette), image, TRUE, FALSE);
|
||||
|
||||
palettes = pika_data_factory_get_container (image->pika->palette_factory);
|
||||
|
||||
|
@ -319,9 +337,8 @@ pika_image_set_colormap (PikaImage *image,
|
|||
pika_image_colormap_set_palette_entry (image, &color, i);
|
||||
}
|
||||
|
||||
pika_data_thaw (PIKA_DATA (private->palette));
|
||||
|
||||
pika_image_colormap_changed (image, -1);
|
||||
pika_data_thaw (PIKA_DATA (private->palette));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -347,6 +364,45 @@ pika_image_unset_colormap (PikaImage *image,
|
|||
pika_image_colormap_changed (image, -1);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_image_colormap_is_index_used (PikaImage *image,
|
||||
gint color_index)
|
||||
{
|
||||
GList *layers;
|
||||
GList *iter;
|
||||
GThreadPool *pool;
|
||||
GRWLock lock;
|
||||
gboolean found = FALSE;
|
||||
gint num_processors;
|
||||
|
||||
g_rw_lock_init (&lock);
|
||||
num_processors = PIKA_GEGL_CONFIG (image->pika->config)->num_processors;
|
||||
layers = pika_image_get_layer_list (image);
|
||||
|
||||
pool = g_thread_pool_new_full ((GFunc) pika_image_colormap_thread_is_index_used,
|
||||
GINT_TO_POINTER (color_index),
|
||||
(GDestroyNotify) g_free,
|
||||
num_processors, TRUE, NULL);
|
||||
for (iter = layers; iter; iter = g_list_next (iter))
|
||||
{
|
||||
IndexUsedJobData *job_data;
|
||||
|
||||
job_data = g_malloc (sizeof (IndexUsedJobData ));
|
||||
job_data->buffer = pika_drawable_get_buffer (iter->data);
|
||||
job_data->format = pika_drawable_get_format_without_alpha (iter->data);
|
||||
job_data->found = &found;
|
||||
job_data->lock = &lock;
|
||||
|
||||
g_thread_pool_push (pool, job_data, NULL);
|
||||
}
|
||||
|
||||
g_thread_pool_free (pool, FALSE, TRUE);
|
||||
g_rw_lock_clear (&lock);
|
||||
g_list_free (layers);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void
|
||||
pika_image_get_colormap_entry (PikaImage *image,
|
||||
gint color_index,
|
||||
|
@ -420,6 +476,57 @@ pika_image_add_colormap_entry (PikaImage *image,
|
|||
pika_image_colormap_changed (image, -1);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_image_delete_colormap_entry (PikaImage *image,
|
||||
gint color_index,
|
||||
gboolean push_undo)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
|
||||
|
||||
if (! pika_image_colormap_is_index_used (image, color_index))
|
||||
{
|
||||
PikaImagePrivate *private;
|
||||
PikaPaletteEntry *entry;
|
||||
GList *layers;
|
||||
GList *iter;
|
||||
|
||||
if (push_undo)
|
||||
{
|
||||
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP,
|
||||
C_("undo-type", "Delete Colormap entry"));
|
||||
|
||||
pika_image_undo_push_image_colormap (image, NULL);
|
||||
}
|
||||
|
||||
private = PIKA_IMAGE_GET_PRIVATE (image);
|
||||
layers = pika_image_get_layer_list (image);
|
||||
|
||||
for (iter = layers; iter; iter = g_list_next (iter))
|
||||
{
|
||||
if (push_undo)
|
||||
pika_image_undo_push_drawable_mod (image, NULL, iter->data, TRUE);
|
||||
|
||||
pika_gegl_shift_index (pika_drawable_get_buffer (iter->data), NULL,
|
||||
pika_drawable_get_format (iter->data),
|
||||
color_index, -1);
|
||||
}
|
||||
|
||||
entry = pika_palette_get_entry (private->palette, color_index);
|
||||
pika_palette_delete_entry (private->palette, entry);
|
||||
|
||||
g_list_free (layers);
|
||||
|
||||
if (push_undo)
|
||||
pika_image_undo_group_end (image);
|
||||
|
||||
pika_image_colormap_changed (image, -1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
@ -442,3 +549,22 @@ pika_image_colormap_set_palette_entry (PikaImage *image,
|
|||
|
||||
pika_palette_set_entry (private->palette, index, name, color);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
|
||||
gint index)
|
||||
{
|
||||
g_rw_lock_reader_lock (data->lock);
|
||||
if (*data->found)
|
||||
{
|
||||
g_rw_lock_reader_unlock (data->lock);
|
||||
return;
|
||||
}
|
||||
g_rw_lock_reader_unlock (data->lock);
|
||||
if (pika_gegl_is_index_used (data->buffer, NULL, data->format, index))
|
||||
{
|
||||
g_rw_lock_writer_lock (data->lock);
|
||||
*data->found = TRUE;
|
||||
g_rw_lock_writer_unlock (data->lock);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ void pika_image_set_colormap (PikaImage *image,
|
|||
void pika_image_unset_colormap (PikaImage *image,
|
||||
gboolean push_undo);
|
||||
|
||||
gboolean pika_image_colormap_is_index_used (PikaImage *image,
|
||||
gint color_index);
|
||||
|
||||
void pika_image_get_colormap_entry (PikaImage *image,
|
||||
gint color_index,
|
||||
PikaRGB *color);
|
||||
|
@ -59,6 +62,9 @@ void pika_image_set_colormap_entry (PikaImage *image,
|
|||
|
||||
void pika_image_add_colormap_entry (PikaImage *image,
|
||||
const PikaRGB *color);
|
||||
gboolean pika_image_delete_colormap_entry (PikaImage *image,
|
||||
gint color_index,
|
||||
gboolean push_undo);
|
||||
|
||||
|
||||
#endif /* __PIKA_IMAGE_COLORMAP_H__ */
|
||||
|
|
|
@ -24,17 +24,22 @@
|
|||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
#include <gexiv2/gexiv2.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaimage-color-profile.h"
|
||||
#include "pikaimage-metadata.h"
|
||||
#include "pikaimage-private.h"
|
||||
#include "pikaimage-rotate.h"
|
||||
#include "pikaimage-undo.h"
|
||||
#include "pikaimage-undo-push.h"
|
||||
#include "pikalayer-new.h"
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
@ -186,3 +191,110 @@ pika_image_metadata_update_colorspace (PikaImage *image)
|
|||
pika_metadata_set_colorspace (metadata, space);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_image_metadata_load_thumbnail:
|
||||
* @pika: The #Pika object.
|
||||
* @file: A #GFile image.
|
||||
* @full_image_width: the width of the full image (not the thumbnail).
|
||||
* @full_image_height: the height of the full image (not the thumbnail).
|
||||
* @error: Return location for error message
|
||||
*
|
||||
* Retrieves a thumbnail from metadata in @file if present.
|
||||
* It does not need to actually load the full image, only the metadata through
|
||||
* GExiv2, which makes it fast.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #PikaImage of the @file thumbnail.
|
||||
*/
|
||||
PikaImage *
|
||||
pika_image_metadata_load_thumbnail (Pika *pika,
|
||||
GFile *file,
|
||||
gint *full_image_width,
|
||||
gint *full_image_height,
|
||||
const Babl **format,
|
||||
GError **error)
|
||||
{
|
||||
PikaMetadata *metadata;
|
||||
GInputStream *input_stream;
|
||||
GdkPixbuf *pixbuf;
|
||||
guint8 *thumbnail_buffer;
|
||||
gint thumbnail_size;
|
||||
PikaImage *image = NULL;
|
||||
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
metadata = pika_metadata_load_from_file (file, error);
|
||||
if (! metadata)
|
||||
return NULL;
|
||||
|
||||
if (! gexiv2_metadata_get_exif_thumbnail (GEXIV2_METADATA (metadata),
|
||||
&thumbnail_buffer,
|
||||
&thumbnail_size))
|
||||
{
|
||||
g_object_unref (metadata);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input_stream = g_memory_input_stream_new_from_data (thumbnail_buffer,
|
||||
thumbnail_size,
|
||||
(GDestroyNotify) g_free);
|
||||
pixbuf = gdk_pixbuf_new_from_stream (input_stream, NULL, error);
|
||||
g_object_unref (input_stream);
|
||||
|
||||
if (pixbuf)
|
||||
{
|
||||
PikaLayer *layer;
|
||||
|
||||
image = pika_image_new (pika,
|
||||
gdk_pixbuf_get_width (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf),
|
||||
PIKA_RGB, PIKA_PRECISION_U8_NON_LINEAR);
|
||||
pika_image_undo_disable (image);
|
||||
|
||||
/* XXX This is possibly wrong, because an image of a given color space may
|
||||
* have a thumbnail stored in a different colorspace. This is even more
|
||||
* true with PIKA which always exports RGB thumbnails (see code in
|
||||
* pika_image_metadata_save_filter()), even for say grayscale images.
|
||||
* Nevertheless other software may store thumbnail using the same
|
||||
* colorspace.
|
||||
*/
|
||||
*format = pika_pixbuf_get_format (pixbuf);
|
||||
layer = pika_layer_new_from_pixbuf (pixbuf, image,
|
||||
pika_image_get_layer_format (image, FALSE),
|
||||
/* No need to localize; this image is short-lived. */
|
||||
"Background",
|
||||
PIKA_OPACITY_OPAQUE,
|
||||
pika_image_get_default_new_layer_mode (image));
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
pika_image_add_layer (image, layer, NULL, 0, FALSE);
|
||||
|
||||
pika_image_apply_metadata_orientation (image, pika_get_user_context (pika), metadata, NULL);
|
||||
}
|
||||
|
||||
/* This is the unoriented dimensions. Should we switch when there is a 90 or
|
||||
* 270 degree rotation? We don't actually know if the metadata orientation is
|
||||
* correct.
|
||||
*/
|
||||
*full_image_width = gexiv2_metadata_get_pixel_width (GEXIV2_METADATA (metadata));
|
||||
*full_image_height = gexiv2_metadata_get_pixel_height (GEXIV2_METADATA (metadata));
|
||||
|
||||
if (*full_image_width < 1 || *full_image_height < 1)
|
||||
{
|
||||
/* Dimensions stored in metadata might be less accurate, yet it's still
|
||||
* informational.
|
||||
*/
|
||||
*full_image_width = gexiv2_metadata_try_get_metadata_pixel_width (GEXIV2_METADATA (metadata), NULL);
|
||||
*full_image_height = gexiv2_metadata_try_get_metadata_pixel_width (GEXIV2_METADATA (metadata), NULL);
|
||||
}
|
||||
if (*full_image_width < 1 || *full_image_height < 1)
|
||||
{
|
||||
*full_image_width = 0;
|
||||
*full_image_height = 0;
|
||||
}
|
||||
|
||||
g_object_unref (metadata);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
|
|
@ -33,5 +33,12 @@ void pika_image_metadata_update_bits_per_sample (PikaImage *image);
|
|||
void pika_image_metadata_update_resolution (PikaImage *image);
|
||||
void pika_image_metadata_update_colorspace (PikaImage *image);
|
||||
|
||||
PikaImage * pika_image_metadata_load_thumbnail (Pika *pika,
|
||||
GFile *file,
|
||||
gint *full_image_width,
|
||||
gint *full_image_height,
|
||||
const Babl **format,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_IMAGE_METADATA_H__ */
|
||||
|
|
|
@ -282,6 +282,17 @@ pika_image_import_rotation_metadata (PikaImage *image,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_image_apply_metadata_orientation (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaMetadata *metadata,
|
||||
PikaProgress *progress)
|
||||
{
|
||||
pika_image_metadata_rotate (image, context,
|
||||
gexiv2_metadata_try_get_orientation (GEXIV2_METADATA (metadata), NULL),
|
||||
progress);
|
||||
}
|
||||
|
||||
|
||||
/* Private Functions */
|
||||
|
||||
|
|
|
@ -23,14 +23,20 @@
|
|||
#define __PIKA_IMAGE_ROTATE_H__
|
||||
|
||||
|
||||
void pika_image_rotate (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaRotationType rotate_type,
|
||||
PikaProgress *progress);
|
||||
void pika_image_rotate (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaRotationType rotate_type,
|
||||
PikaProgress *progress);
|
||||
|
||||
void pika_image_import_rotation_metadata (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
gboolean interactive);
|
||||
|
||||
void pika_image_apply_metadata_orientation (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaMetadata *metadata,
|
||||
PikaProgress *progress);
|
||||
|
||||
void pika_image_import_rotation_metadata (PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
gboolean interactive);
|
||||
|
||||
#endif /* __PIKA_IMAGE_ROTATE_H__ */
|
||||
|
|
|
@ -625,6 +625,9 @@ pika_image_undo_dirty_from_type (PikaUndoType undo_type)
|
|||
case PIKA_UNDO_GROUP_IMAGE_CONVERT:
|
||||
return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE;
|
||||
|
||||
case PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP:
|
||||
return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE;
|
||||
|
||||
case PIKA_UNDO_GROUP_IMAGE_LAYERS_MERGE:
|
||||
return PIKA_DIRTY_IMAGE_STRUCTURE | PIKA_DIRTY_DRAWABLE;
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "pikacontainer.h"
|
||||
#include "pikacontext.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaimage-metadata.h"
|
||||
#include "pikaimagefile.h"
|
||||
#include "pikapickable.h"
|
||||
#include "pikaprogress.h"
|
||||
|
@ -486,19 +487,37 @@ pika_imagefile_create_thumbnail (PikaImagefile *imagefile,
|
|||
if (error && *error)
|
||||
{
|
||||
g_printerr ("Info: Thumbnail load procedure failed: %s\n"
|
||||
" Falling back to file load procedure.\n",
|
||||
" Falling back to metadata or file load.\n",
|
||||
(*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
|
||||
image = file_open_image (private->pika, context, progress,
|
||||
private->file,
|
||||
FALSE, NULL, PIKA_RUN_NONINTERACTIVE,
|
||||
&status, &mime_type, error);
|
||||
|
||||
image = pika_image_metadata_load_thumbnail (private->pika, private->file, &width, &height, &format, error);
|
||||
if (image)
|
||||
pika_thumbnail_set_info_from_image (private->thumbnail,
|
||||
mime_type, image);
|
||||
{
|
||||
pika_thumbnail_set_info (private->thumbnail,
|
||||
mime_type, width, height,
|
||||
format, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error && *error)
|
||||
{
|
||||
g_printerr ("Info: metadata load failed: %s\n"
|
||||
" Falling back to file load procedure.\n",
|
||||
(*error)->message);
|
||||
g_clear_error (error);
|
||||
}
|
||||
|
||||
image = file_open_image (private->pika, context, progress,
|
||||
private->file,
|
||||
FALSE, NULL, PIKA_RUN_NONINTERACTIVE,
|
||||
&status, &mime_type, error);
|
||||
|
||||
if (image)
|
||||
pika_thumbnail_set_info_from_image (private->thumbnail,
|
||||
mime_type, image);
|
||||
}
|
||||
}
|
||||
|
||||
|