Add render::Dithering() class to store all dithering parameters

This commit is contained in:
David Capello 2019-04-03 19:32:24 -03:00
parent fcf272bb69
commit 109e6fa205
17 changed files with 120 additions and 118 deletions

View File

@ -68,9 +68,7 @@ private:
SetPixelFormat::SetPixelFormat(Sprite* sprite,
const PixelFormat newFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
const double ditheringFactor,
const render::Dithering& dithering,
render::TaskDelegate* delegate)
: WithSprite(sprite)
, m_oldFormat(sprite->pixelFormat())
@ -86,9 +84,7 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
ImageRef new_image(
render::convert_pixel_format
(old_image.get(), nullptr, newFormat,
ditheringAlgorithm,
ditheringMatrix,
ditheringFactor,
dithering,
sprite->rgbMap(cel->frame()),
sprite->palette(cel->frame()),
cel->layer()->isBackground(),

View File

@ -12,14 +12,13 @@
#include "app/cmd/with_sprite.h"
#include "app/cmd_sequence.h"
#include "doc/pixel_format.h"
#include "render/dithering_algorithm.h"
namespace doc {
class Sprite;
}
namespace render {
class DitheringMatrix;
class Dithering;
class TaskDelegate;
}
@ -31,9 +30,7 @@ namespace cmd {
public:
SetPixelFormat(doc::Sprite* sprite,
const doc::PixelFormat newFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
const double ditheringFactor,
const render::Dithering& dithering,
render::TaskDelegate* delegate);
protected:

View File

@ -33,6 +33,7 @@
#include "doc/layer.h"
#include "doc/sprite.h"
#include "fmt/format.h"
#include "render/dithering.h"
#include "render/dithering_algorithm.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
@ -77,9 +78,7 @@ public:
const doc::Sprite* sprite,
const doc::frame_t frame,
const doc::PixelFormat pixelFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
const double ditheringFactor,
const render::Dithering& dithering,
const gfx::Point& pos,
const bool newBlend)
: m_image(dstImage)
@ -91,15 +90,11 @@ public:
[this,
sprite, frame,
pixelFormat,
ditheringAlgorithm,
ditheringMatrix,
ditheringFactor,
dithering,
newBlend]() { // Copy the matrix
run(sprite, frame,
pixelFormat,
ditheringAlgorithm,
ditheringMatrix,
ditheringFactor,
dithering,
newBlend);
})
{
@ -122,9 +117,7 @@ private:
void run(const Sprite* sprite,
const doc::frame_t frame,
const doc::PixelFormat pixelFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
const double ditheringFactor,
const render::Dithering& dithering,
const bool newBlend) {
doc::ImageRef tmp(
Image::create(sprite->pixelFormat(),
@ -144,9 +137,7 @@ private:
tmp.get(),
m_image.get(),
pixelFormat,
ditheringAlgorithm,
ditheringMatrix,
ditheringFactor,
dithering,
sprite->rgbMap(frame),
sprite->palette(frame),
(sprite->backgroundLayer() != nullptr),
@ -247,18 +238,14 @@ public:
return m_selectedItem->pixelFormat();
}
render::DitheringAlgorithm ditheringAlgorithm() const {
return (m_ditheringSelector ? m_ditheringSelector->ditheringAlgorithm():
render::DitheringAlgorithm::None);
}
render::DitheringMatrix ditheringMatrix() const {
return (m_ditheringSelector ? m_ditheringSelector->ditheringMatrix():
render::BayerMatrix(8));
}
double ditheringFactor() const {
return double(factor()->getValue()) / 100.0;
render::Dithering dithering() const {
render::Dithering d;
if (m_ditheringSelector) {
d.algorithm(m_ditheringSelector->ditheringAlgorithm());
d.matrix(m_ditheringSelector->ditheringMatrix());
}
d.factor(double(factor()->getValue()) / 100.0);
return d;
}
bool flattenEnabled() const {
@ -266,7 +253,7 @@ public:
}
// Save the dithering method used for the future
void saveDitheringAlgorithm() {
void saveDitheringOptions() {
if (m_ditheringSelector) {
if (auto item = m_ditheringSelector->getSelectedItem()) {
Preferences::instance().quantization.ditheringAlgorithm(
@ -344,9 +331,7 @@ private:
m_editor->sprite(),
m_editor->frame(),
dstPixelFormat,
ditheringAlgorithm(),
ditheringMatrix(),
ditheringFactor(),
dithering(),
visibleBounds.origin(),
Preferences::instance().experimental.newBlend()));
@ -403,9 +388,7 @@ protected:
private:
bool m_useUI;
doc::PixelFormat m_format;
render::DitheringAlgorithm m_ditheringAlgorithm;
render::DitheringMatrix m_ditheringMatrix;
double m_ditheringFactor;
render::Dithering m_dithering;
};
ChangePixelFormatCommand::ChangePixelFormatCommand()
@ -413,8 +396,7 @@ ChangePixelFormatCommand::ChangePixelFormatCommand()
{
m_useUI = true;
m_format = IMAGE_RGB;
m_ditheringAlgorithm = render::DitheringAlgorithm::None;
m_ditheringFactor = 1.0;
m_dithering = render::Dithering();
}
void ChangePixelFormatCommand::onLoadParams(const Params& params)
@ -430,13 +412,13 @@ void ChangePixelFormatCommand::onLoadParams(const Params& params)
std::string dithering = params.get("dithering");
if (dithering == "ordered")
m_ditheringAlgorithm = render::DitheringAlgorithm::Ordered;
m_dithering.algorithm(render::DitheringAlgorithm::Ordered);
else if (dithering == "old")
m_ditheringAlgorithm = render::DitheringAlgorithm::Old;
m_dithering.algorithm(render::DitheringAlgorithm::Old);
else if (dithering == "error-diffusion")
m_ditheringAlgorithm = render::DitheringAlgorithm::ErrorDiffusion;
m_dithering.algorithm(render::DitheringAlgorithm::ErrorDiffusion);
else
m_ditheringAlgorithm = render::DitheringAlgorithm::None;
m_dithering.algorithm(render::DitheringAlgorithm::None);
std::string matrix = params.get("dithering-matrix");
if (!matrix.empty()) {
@ -444,17 +426,20 @@ void ChangePixelFormatCommand::onLoadParams(const Params& params)
const render::DitheringMatrix* knownMatrix =
App::instance()->extensions().ditheringMatrix(matrix);
if (knownMatrix) {
m_ditheringMatrix = *knownMatrix;
m_dithering.matrix(*knownMatrix);
}
// Then, if the matrix doesn't exist we try to load it from a file
else if (!load_dithering_matrix_from_sprite(matrix, m_ditheringMatrix)) {
throw std::runtime_error("Invalid matrix name");
else {
render::DitheringMatrix ditMatrix;
if (!load_dithering_matrix_from_sprite(matrix, ditMatrix))
throw std::runtime_error("Invalid matrix name");
m_dithering.matrix(ditMatrix);
}
}
// Default dithering matrix is BayerMatrix(8)
else {
// TODO object slicing here (from BayerMatrix -> DitheringMatrix)
m_ditheringMatrix = render::BayerMatrix(8);
m_dithering.matrix(render::BayerMatrix(8));
}
}
@ -471,7 +456,7 @@ bool ChangePixelFormatCommand::onEnabled(Context* context)
if (sprite->pixelFormat() == IMAGE_INDEXED &&
m_format == IMAGE_INDEXED &&
m_ditheringAlgorithm != render::DitheringAlgorithm::None)
m_dithering.algorithm() != render::DitheringAlgorithm::None)
return false;
return true;
@ -488,7 +473,7 @@ bool ChangePixelFormatCommand::onChecked(Context* context)
if (sprite &&
sprite->pixelFormat() == IMAGE_INDEXED &&
m_format == IMAGE_INDEXED &&
m_ditheringAlgorithm != render::DitheringAlgorithm::None)
m_dithering.algorithm() != render::DitheringAlgorithm::None)
return false;
return
@ -515,12 +500,10 @@ void ChangePixelFormatCommand::onExecute(Context* context)
return;
m_format = window.pixelFormat();
m_ditheringAlgorithm = window.ditheringAlgorithm();
m_ditheringMatrix = window.ditheringMatrix();
m_ditheringFactor = window.ditheringFactor();
m_dithering = window.dithering();
flatten = window.flattenEnabled();
window.saveDitheringAlgorithm();
window.saveDitheringOptions();
}
#endif // ENABLE_UI
@ -553,9 +536,7 @@ void ChangePixelFormatCommand::onExecute(Context* context)
job.tx()(
new cmd::SetPixelFormat(
sprite, m_format,
m_ditheringAlgorithm,
m_ditheringMatrix,
m_ditheringFactor,
m_dithering,
&job)); // SpriteJob is a render::TaskDelegate
});
job.waitJob();
@ -578,7 +559,7 @@ std::string ChangePixelFormatCommand::onGetFriendlyName() const
conversion = Strings::commands_ChangePixelFormat_Grayscale();
break;
case IMAGE_INDEXED:
switch (m_ditheringAlgorithm) {
switch (m_dithering.algorithm()) {
case render::DitheringAlgorithm::None:
conversion = Strings::commands_ChangePixelFormat_Indexed();
break;

View File

@ -27,6 +27,7 @@
#include "doc/layer.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "render/dithering.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
#include "render/render.h"
@ -282,8 +283,7 @@ void NewLayerCommand::onExecute(Context* context)
pasteImage.get(),
nullptr,
sprite->pixelFormat(),
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
sprite->rgbMap(dstFrame),
pasteSpr->palette(fr),
(pasteSpr->backgroundLayer() ? true: false),

View File

@ -25,6 +25,7 @@
#include "base/string.h"
#include "doc/image.h"
#include "doc/image_ref.h"
#include "render/dithering.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
#include "ui/system.h"
@ -184,8 +185,7 @@ void PasteTextCommand::onExecute(Context* ctx)
image.reset(
render::convert_pixel_format(
image.get(), NULL, sprite->pixelFormat(),
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
rgbmap, sprite->palette(editor->frame()),
false, 0));
}

View File

@ -39,7 +39,7 @@
#include "doc/sprite.h"
#include "gfx/packing_rects.h"
#include "gfx/size.h"
#include "render/dithering_algorithm.h"
#include "render/dithering.h"
#include "render/ordered_dither.h"
#include "render/render.h"
@ -743,8 +743,7 @@ void DocExporter::renderTexture(Context* ctx, const Samples& samples, Image* tex
cmd::SetPixelFormat(
sample.sprite(),
textureImage->pixelFormat(),
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
nullptr) // TODO add a delegate to show progress
.execute(ctx);
}

View File

@ -24,6 +24,7 @@
#include "base/file_handle.h"
#include "base/fs.h"
#include "doc/doc.h"
#include "render/dithering.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
#include "render/render.h"
@ -745,8 +746,7 @@ private:
ImageRef newImage(
render::convert_pixel_format
(oldImage, NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
nullptr,
m_sprite->palette(cel->frame()),
m_opaque,
@ -758,8 +758,7 @@ private:
m_currentImage.reset(
render::convert_pixel_format
(m_currentImage.get(), NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
nullptr,
m_sprite->palette(m_frameNum),
m_opaque,
@ -768,8 +767,7 @@ private:
m_previousImage.reset(
render::convert_pixel_format
(m_previousImage.get(), NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
nullptr,
m_sprite->palette(MAX(0, m_frameNum-1)),
m_opaque,

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018 Igara Studio S.A.
// Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -50,6 +50,8 @@
#include "os/surface.h"
#include "os/system.h"
#include "render/dithering.h"
#include "render/error_diffusion.h"
#include "render/ordered_dither.h"
#include "ui/button.h"
#include "ui/combobox.h"
#include "ui/int_entry.h"

View File

@ -20,10 +20,11 @@
#include "doc/image.h"
#include "doc/image_ref.h"
#include "doc/primitives.h"
#include "render/gradient.h"
#include "render/quantization.h"
#include "os/surface.h"
#include "os/system.h"
#include "render/dithering.h"
#include "render/gradient.h"
#include "render/quantization.h"
#include "ui/graphics.h"
#include "ui/listitem.h"
#include "ui/paint_event.h"
@ -43,8 +44,7 @@ public:
const std::string& text)
: ListItem(text)
, m_matrixOnly(false)
, m_algo(algo)
, m_matrix(matrix)
, m_dithering(algo, matrix)
, m_preview(nullptr)
, m_palId(0)
, m_palMods(0)
@ -55,16 +55,20 @@ public:
const std::string& text)
: ListItem(text)
, m_matrixOnly(true)
, m_algo(render::DitheringAlgorithm::None)
, m_matrix(matrix)
, m_dithering(render::DitheringAlgorithm::None, matrix)
, m_preview(nullptr)
, m_palId(0)
, m_palMods(0)
{
}
render::DitheringAlgorithm algo() const { return m_algo; }
render::DitheringMatrix matrix() const { return m_matrix; }
render::DitheringAlgorithm algo() const {
return m_dithering.algorithm();
}
render::DitheringMatrix matrix() const {
return m_dithering.matrix();
}
private:
os::Surface* preview() {
@ -91,7 +95,8 @@ private:
gfx::Point(w-1, 0),
doc::rgba(0, 0, 0, 255),
doc::rgba(255, 255, 255, 255),
m_matrixOnly ? m_matrix: render::DitheringMatrix());
(m_matrixOnly ? m_dithering.matrix():
render::DitheringMatrix()));
doc::ImageRef image2;
if (m_matrixOnly) {
@ -102,8 +107,7 @@ private:
doc::clear_image(image2.get(), 0);
render::convert_pixel_format(
image1.get(), image2.get(), IMAGE_INDEXED,
m_algo, m_matrix, 1.0,
nullptr, palette, true, -1, nullptr);
m_dithering, nullptr, palette, true, -1, nullptr);
}
m_preview = os::instance()->createRgbaSurface(w, h);
@ -152,8 +156,7 @@ private:
}
bool m_matrixOnly;
render::DitheringAlgorithm m_algo;
render::DitheringMatrix m_matrix;
render::Dithering m_dithering;
os::Surface* m_preview;
doc::ObjectId m_palId;
int m_palMods;

View File

@ -35,6 +35,7 @@
#include "base/shared_ptr.h"
#include "clip/clip.h"
#include "doc/doc.h"
#include "render/dithering.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
@ -366,8 +367,7 @@ void paste()
src_image.reset(
render::convert_pixel_format(
clipboard_image.get(), NULL, dstSpr->pixelFormat(),
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
dst_rgbmap, clipboard_palette.get(),
false,
0));

View File

@ -16,6 +16,7 @@
#include "doc/palette.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "render/dithering.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
#include "render/render.h"
@ -54,8 +55,7 @@ Cel* create_cel_copy(const Cel* srcCel,
celImage,
tmpImage.get(),
IMAGE_RGB,
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
srcCel->sprite()->rgbMap(srcCel->frame()),
srcCel->sprite()->palette(srcCel->frame()),
srcCel->layer()->isBackground(),
@ -65,8 +65,7 @@ Cel* create_cel_copy(const Cel* srcCel,
tmpImage.get(),
dstCel->image(),
IMAGE_INDEXED,
render::DitheringAlgorithm::None,
render::DitheringMatrix(), 1.0,
render::Dithering(),
dstSprite->rgbMap(dstFrame),
dstSprite->palette(dstFrame),
srcCel->layer()->isBackground(),

View File

@ -11,7 +11,33 @@
#include "render/dithering_algorithm.h"
#include "render/dithering_matrix.h"
#include "render/error_diffusion.h"
#include "render/ordered_dither.h"
namespace render {
class Dithering {
public:
Dithering(
DitheringAlgorithm algorithm = DitheringAlgorithm::None,
const DitheringMatrix& matrix = DitheringMatrix(),
double factor = 1.0)
: m_algorithm(algorithm)
, m_matrix(matrix)
, m_factor(factor){ }
DitheringAlgorithm algorithm() const { return m_algorithm; }
DitheringMatrix matrix() const { return m_matrix; }
double factor() const { return m_factor; }
void algorithm(const DitheringAlgorithm algorithm) { m_algorithm = algorithm; }
void matrix(const DitheringMatrix& matrix) { m_matrix = matrix; }
void factor(const double factor) { m_factor = factor; }
private:
DitheringAlgorithm m_algorithm;
DitheringMatrix m_matrix;
double m_factor;
};
} // namespace render
#endif

View File

@ -12,6 +12,8 @@
#include "render/ordered_dither.h"
#include "base/base.h"
#include "render/dithering.h"
#include "render/dithering_matrix.h"
#include <algorithm>
#include <limits>
@ -228,8 +230,7 @@ doc::color_t OrderedDither2::ditherRgbPixelToIndex(
void dither_rgb_image_to_indexed(
DitheringAlgorithmBase& algorithm,
const DitheringMatrix& matrix,
const double factor,
const Dithering& dithering,
const doc::Image* srcImage,
doc::Image* dstImage,
const doc::RgbMap* rgbmap,
@ -239,7 +240,7 @@ void dither_rgb_image_to_indexed(
const int w = srcImage->width();
const int h = srcImage->height();
algorithm.start(srcImage, dstImage, factor);
algorithm.start(srcImage, dstImage, dithering.factor());
if (algorithm.dimensions() == 1) {
const doc::LockImageBits<doc::RgbTraits> srcBits(srcImage);
@ -251,7 +252,8 @@ void dither_rgb_image_to_indexed(
for (int x=0; x<w; ++x, ++srcIt, ++dstIt) {
ASSERT(srcIt != srcBits.end());
ASSERT(dstIt != dstBits.end());
*dstIt = algorithm.ditherRgbPixelToIndex(matrix, *srcIt, x, y, rgbmap, palette);
*dstIt = algorithm.ditherRgbPixelToIndex(
dithering.matrix(), *srcIt, x, y, rgbmap, palette);
if (delegate) {
if (!delegate->continueTask())

View File

@ -15,11 +15,13 @@
#include "doc/rgbmap.h"
#include "gfx/point.h"
#include "gfx/size.h"
#include "render/dithering_matrix.h"
#include "render/task_delegate.h"
namespace render {
class Dithering;
class DitheringMatrix;
class DitheringAlgorithmBase {
public:
virtual ~DitheringAlgorithmBase() { }
@ -77,8 +79,7 @@ namespace render {
void dither_rgb_image_to_indexed(
DitheringAlgorithmBase& algorithm,
const DitheringMatrix& matrix,
const double factor,
const Dithering& dithering,
const doc::Image* srcImage,
doc::Image* dstImage,
const doc::RgbMap* rgbmap,

View File

@ -1,4 +1,5 @@
// Aseprite Render Library
// Copyright (c) 2019 Igara Studio S.A.
// Copyright (c) 2001-2017 David Capello
//
// This file is released under the terms of the MIT license.
@ -10,6 +11,7 @@
#include <gtest/gtest.h>
#include "render/dithering_matrix.h"
#include "render/ordered_dither.h"
using namespace doc;

View File

@ -20,6 +20,7 @@
#include "doc/sprite.h"
#include "gfx/hsv.h"
#include "gfx/rgb.h"
#include "render/dithering.h"
#include "render/error_diffusion.h"
#include "render/ordered_dither.h"
#include "render/render.h"
@ -84,9 +85,7 @@ Image* convert_pixel_format(
const Image* image,
Image* new_image,
PixelFormat pixelFormat,
DitheringAlgorithm ditheringAlgorithm,
const DitheringMatrix& ditheringMatrix,
const double ditheringFactor,
const Dithering& dithering,
const RgbMap* rgbmap,
const Palette* palette,
bool is_background,
@ -100,9 +99,9 @@ Image* convert_pixel_format(
// RGB -> Indexed with ordered dithering
if (image->pixelFormat() == IMAGE_RGB &&
pixelFormat == IMAGE_INDEXED &&
ditheringAlgorithm != DitheringAlgorithm::None) {
dithering.algorithm() != DitheringAlgorithm::None) {
std::unique_ptr<DitheringAlgorithmBase> dither;
switch (ditheringAlgorithm) {
switch (dithering.algorithm()) {
case DitheringAlgorithm::Ordered:
dither.reset(new OrderedDither2(is_background ? -1: new_mask_color));
break;
@ -115,7 +114,7 @@ Image* convert_pixel_format(
}
if (dither)
dither_rgb_image_to_indexed(
*dither, ditheringMatrix, ditheringFactor,
*dither, dithering,
image, new_image, rgbmap, palette, delegate);
return new_image;
}

View File

@ -12,7 +12,6 @@
#include "doc/frame.h"
#include "doc/pixel_format.h"
#include "render/color_histogram.h"
#include "render/dithering_algorithm.h"
#include <vector>
@ -24,7 +23,7 @@ namespace doc {
}
namespace render {
class DitheringMatrix;
class Dithering;
class TaskDelegate;
class PaletteOptimizer {
@ -53,9 +52,7 @@ namespace render {
const doc::Image* src,
doc::Image* dst, // Can be NULL to create a new image
doc::PixelFormat pixelFormat,
render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
const double ditheringFactor,
const render::Dithering& dithering,
const doc::RgbMap* rgbmap,
const doc::Palette* palette,
bool is_background,