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 fe9928b commit a7672e5
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 20 deletions.
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 a7672e5

Please sign in to comment.