Skip to content

Commit

Permalink
Use current view mode for flat image saving
Browse files Browse the repository at this point in the history
Instead of always using normal view. This is consistent with how
exporting selections works as well.

Fixes #1374.
  • Loading branch information
askmeaboutlo0m committed Sep 29, 2024
1 parent 88cd602 commit bc0e021
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 20 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Unreleased Version 2.2.2-pre
* Feature: Show a color preview when picking a color from the canvas. Can be toggled in the tool preferences.
* Fix: In layer view mode, render the layer truly in isolation instead of applying opacities, visibilities or alpha preserve to it. Thanks MachKerman and incoheart for reporting.
* Feature: Add Layer > Group View to show the parent group of the current layer in isolation. Thanks Rylan for suggesting.
* Fix: Save and export images according to the current view mode. Thanks incoheart for reporting.

2024-08-09 Version 2.2.2-beta.3
* Fix: Use more accurate timers for performance profiles if the platform supports it.
Expand Down
44 changes: 32 additions & 12 deletions src/drawdance/libimpex/dpimpex/save.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ DP_SaveImageType DP_save_image_type_guess(const char *path)
}


bool DP_save_image_type_is_flat_image(DP_SaveImageType type)
{
switch (type) {
case DP_SAVE_IMAGE_ORA:
case DP_SAVE_IMAGE_PSD:
return false;
case DP_SAVE_IMAGE_PNG:
case DP_SAVE_IMAGE_JPEG:
case DP_SAVE_IMAGE_WEBP:
return true;
case DP_SAVE_IMAGE_UNKNOWN:
break;
}
DP_warn("Unknown save format %d", type);
return true;
}


typedef struct DP_SaveOraLayer {
int layer_id;
int index;
Expand Down Expand Up @@ -781,13 +799,15 @@ static void bake_annotations(DP_AnnotationList *al, DP_DrawContext *dc,
}
}

static DP_SaveResult save_flat_image(
DP_CanvasState *cs, DP_DrawContext *dc, DP_Rect *crop, const char *path,
DP_SaveResult (*save_fn)(DP_Image *, DP_Output *), DP_ViewModeFilter vmf,
DP_SaveBakeAnnotationFn bake_annotation, void *user)
static DP_SaveResult
save_flat_image(DP_CanvasState *cs, DP_DrawContext *dc, DP_Rect *crop,
const char *path,
DP_SaveResult (*save_fn)(DP_Image *, DP_Output *),
const DP_ViewModeFilter *vmf_or_null,
DP_SaveBakeAnnotationFn bake_annotation, void *user)
{
DP_Image *img = DP_canvas_state_to_flat_image(
cs, DP_FLAT_IMAGE_RENDER_FLAGS, crop, &vmf);
cs, DP_FLAT_IMAGE_RENDER_FLAGS, crop, vmf_or_null);
if (!img) {
DP_warn("Save: %s", DP_error());
return DP_SAVE_RESULT_FLATTEN_ERROR;
Expand All @@ -814,22 +834,20 @@ static DP_SaveResult save_flat_image(

static DP_SaveResult save(DP_CanvasState *cs, DP_DrawContext *dc,
DP_SaveImageType type, const char *path,
const DP_ViewModeFilter *vmf_or_null,
DP_SaveBakeAnnotationFn bake_annotation, void *user)
{
switch (type) {
case DP_SAVE_IMAGE_ORA:
return save_ora(cs, path, dc);
case DP_SAVE_IMAGE_PNG:
return save_flat_image(cs, dc, NULL, path, save_png,
DP_view_mode_filter_make_default(),
return save_flat_image(cs, dc, NULL, path, save_png, vmf_or_null,
bake_annotation, user);
case DP_SAVE_IMAGE_JPEG:
return save_flat_image(cs, dc, NULL, path, save_jpeg,
DP_view_mode_filter_make_default(),
return save_flat_image(cs, dc, NULL, path, save_jpeg, vmf_or_null,
bake_annotation, user);
case DP_SAVE_IMAGE_WEBP:
return save_flat_image(cs, dc, NULL, path, save_webp,
DP_view_mode_filter_make_default(),
return save_flat_image(cs, dc, NULL, path, save_webp, vmf_or_null,
bake_annotation, user);
case DP_SAVE_IMAGE_PSD:
return DP_save_psd(cs, path, dc);
Expand All @@ -841,11 +859,13 @@ static DP_SaveResult save(DP_CanvasState *cs, DP_DrawContext *dc,

DP_SaveResult DP_save(DP_CanvasState *cs, DP_DrawContext *dc,
DP_SaveImageType type, const char *path,
const DP_ViewModeFilter *vmf_or_null,
DP_SaveBakeAnnotationFn bake_annotation, void *user)
{
if (cs && path) {
DP_PERF_BEGIN_DETAIL(fn, "image", "path=%s", path);
DP_SaveResult result = save(cs, dc, type, path, bake_annotation, user);
DP_SaveResult result =
save(cs, dc, type, path, vmf_or_null, bake_annotation, user);
DP_PERF_END(fn);
return result;
}
Expand Down
4 changes: 4 additions & 0 deletions src/drawdance/libimpex/dpimpex/save.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ typedef struct DP_Annotation DP_Annotation;
typedef struct DP_CanvasState DP_CanvasState;
typedef struct DP_DrawContext DP_DrawContext;
typedef struct DP_Rect DP_Rect;
typedef struct DP_ViewModeFilter DP_ViewModeFilter;


typedef struct DP_SaveFormat {
Expand All @@ -24,8 +25,11 @@ typedef bool (*DP_SaveBakeAnnotationFn)(void *user, DP_Annotation *a,

DP_SaveImageType DP_save_image_type_guess(const char *path);

bool DP_save_image_type_is_flat_image(DP_SaveImageType type);

DP_SaveResult DP_save(DP_CanvasState *cs, DP_DrawContext *dc,
DP_SaveImageType type, const char *path,
const DP_ViewModeFilter *vmf_or_null,
DP_SaveBakeAnnotationFn bake_annotation, void *user);


Expand Down
4 changes: 4 additions & 0 deletions src/drawdance/rust/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7985,12 +7985,16 @@ pub type DP_SaveBakeAnnotationFn = ::std::option::Option<
extern "C" {
pub fn DP_save_image_type_guess(path: *const ::std::os::raw::c_char) -> DP_SaveImageType;
}
extern "C" {
pub fn DP_save_image_type_is_flat_image(type_: DP_SaveImageType) -> bool;
}
extern "C" {
pub fn DP_save(
cs: *mut DP_CanvasState,
dc: *mut DP_DrawContext,
type_: DP_SaveImageType,
path: *const ::std::os::raw::c_char,
vmf_or_null: *const DP_ViewModeFilter,
bake_annotation: DP_SaveBakeAnnotationFn,
user: *mut ::std::os::raw::c_void,
) -> DP_SaveResult;
Expand Down
1 change: 1 addition & 0 deletions src/drawdance/rust/engine/paint_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ impl PaintEngine {
self.main_dc.as_ptr(),
DP_SAVE_IMAGE_ORA,
cpath.as_ptr(),
ptr::null(),
None,
ptr::null_mut(),
)
Expand Down
11 changes: 9 additions & 2 deletions src/libclient/canvas/paintengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,12 +763,19 @@ int PaintEngine::frameCount() const
return historyCanvasState().frameCount();
}

DP_ViewModeFilter PaintEngine::viewModeFilter(
drawdance::ViewModeBuffer &vmb,
const drawdance::CanvasState &canvasState) const
{
return DP_paint_engine_view_mode_filter(
m_paintEngine.get(), vmb.get(), canvasState.get());
}

QImage PaintEngine::getFlatImage(
drawdance::ViewModeBuffer &vmb, const drawdance::CanvasState &canvasState,
bool includeBackground, bool includeSublayers, const QRect *rect) const
{
DP_ViewModeFilter vmf = DP_paint_engine_view_mode_filter(
m_paintEngine.get(), vmb.get(), canvasState.get());
DP_ViewModeFilter vmf = viewModeFilter(vmb, canvasState);
return canvasState.toFlatImage(
includeBackground, includeSublayers, rect, &vmf);
}
Expand Down
4 changes: 4 additions & 0 deletions src/libclient/canvas/paintengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ class PaintEngine final : public QObject {
//! Get the number of frames in an animated canvas
int frameCount() const;

DP_ViewModeFilter viewModeFilter(
drawdance::ViewModeBuffer &vmb,
const drawdance::CanvasState &canvasState) const;

//! Get a flat image of the given canvas state using the current view mode.
QImage getFlatImage(
drawdance::ViewModeBuffer &vmb,
Expand Down
4 changes: 2 additions & 2 deletions src/libclient/document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,8 +880,8 @@ void Document::saveCanvasState(
Q_ASSERT(!m_saveInProgress);
m_saveInProgress = true;

CanvasSaverRunnable *saver =
new CanvasSaverRunnable(canvasState, type, path);
CanvasSaverRunnable *saver = new CanvasSaverRunnable(
canvasState, type, path, m_canvas ? m_canvas->paintEngine() : nullptr);
if(isCurrentState) {
unmarkDirty();
}
Expand Down
12 changes: 10 additions & 2 deletions src/libclient/export/canvassaverrunnable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
extern "C" {
#include <dpimpex/save.h>
}
#include "libclient/canvas/paintengine.h"
#include "libclient/drawdance/annotation.h"
#include "libclient/drawdance/global.h"
#include "libclient/export/canvassaverrunnable.h"
Expand All @@ -17,17 +18,23 @@ extern "C" {

CanvasSaverRunnable::CanvasSaverRunnable(
const drawdance::CanvasState &canvasState, DP_SaveImageType type,
const QString &path, QTemporaryDir *tempDir, QObject *parent)
const QString &path, const canvas::PaintEngine *paintEngine,
QTemporaryDir *tempDir, QObject *parent)
: QObject(parent)
, m_canvasState(canvasState)
, m_type(type)
, m_path(path)
, m_tempDir(tempDir)
{
if(paintEngine && DP_save_image_type_is_flat_image(type)) {
m_vmb = new drawdance::ViewModeBuffer;
m_vmf = paintEngine->viewModeFilter(*m_vmb, m_canvasState);
}
}

CanvasSaverRunnable::~CanvasSaverRunnable()
{
delete m_vmb;
delete m_tempDir;
}

Expand All @@ -49,7 +56,8 @@ void CanvasSaverRunnable::run()
const char *path = pathBytes.constData();
drawdance::DrawContext dc = drawdance::DrawContextPool::acquire();
DP_SaveResult result = DP_save(
m_canvasState.get(), dc.get(), m_type, path, bakeAnnotation, this);
m_canvasState.get(), dc.get(), m_type, path, m_vmb ? &m_vmf : nullptr,
bakeAnnotation, this);

#ifdef Q_OS_ANDROID
QFile tempFile(tempPath);
Expand Down
11 changes: 9 additions & 2 deletions src/libclient/export/canvassaverrunnable.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ extern "C" {
#include <dpengine/save_enums.h>
}
#include "libclient/drawdance/canvasstate.h"
#include "libclient/drawdance/viewmode.h"
#include <QByteArray>
#include <QObject>
#include <QRunnable>

class QFile;
class QTemporaryDir;

namespace canvas {
class PaintEngine;
}

/**
* @brief A runnable for saving a canvas in a background thread
*/
Expand All @@ -20,8 +25,8 @@ class CanvasSaverRunnable final : public QObject, public QRunnable {
public:
CanvasSaverRunnable(
const drawdance::CanvasState &canvasState, DP_SaveImageType type,
const QString &path, QTemporaryDir *tempDir = nullptr,
QObject *parent = nullptr);
const QString &path, const canvas::PaintEngine *paintEngine = nullptr,
QTemporaryDir *tempDir = nullptr, QObject *parent = nullptr);

~CanvasSaverRunnable() override;

Expand All @@ -47,6 +52,8 @@ class CanvasSaverRunnable final : public QObject, public QRunnable {
drawdance::CanvasState m_canvasState;
DP_SaveImageType m_type;
QString m_path;
drawdance::ViewModeBuffer *m_vmb = nullptr;
DP_ViewModeFilter m_vmf;
QTemporaryDir *m_tempDir;
};

Expand Down

0 comments on commit bc0e021

Please sign in to comment.