Add --dithering-matrix CLI option

Now the dithering matrix used in ordered dithering algorithm is configurable.
This commit is contained in:
David Capello 2017-05-19 15:49:31 -03:00
parent 4b7a90318a
commit 5ef6aac925
17 changed files with 252 additions and 98 deletions

View File

@ -35,6 +35,7 @@ AppOptions::AppOptions(int argc, const char* argv[])
, m_palette(m_po.add("palette").requiresValue("<filename>").description("Change the palette of the last given sprite"))
, m_scale(m_po.add("scale").requiresValue("<factor>").description("Resize all previously opened sprites"))
, m_ditheringAlgorithm(m_po.add("dithering-algorithm").requiresValue("<algorithm>").description("Dithering algorithm used in --color-mode\nto convert images from RGB to Indexed\n none\n ordered\n old-ordered"))
, m_ditheringMatrix(m_po.add("dithering-matrix").requiresValue("<id>").description("Matrix used in ordered dithering algorithm\n bayer2x2\n bayer4x4\n bayer8x8\n filename.png"))
, m_colorMode(m_po.add("color-mode").requiresValue("<mode>").description("Change color mode of all previously\nopened sprites:\n rgb\n grayscale\n indexed"))
, m_shrinkTo(m_po.add("shrink-to").requiresValue("width,height").description("Shrink each sprite if it is\nlarger than width or height"))
, m_data(m_po.add("data").requiresValue("<filename.json>").description("File to store the sprite sheet metadata"))

View File

@ -49,6 +49,7 @@ public:
const Option& palette() const { return m_palette; }
const Option& scale() const { return m_scale; }
const Option& ditheringAlgorithm() const { return m_ditheringAlgorithm; }
const Option& ditheringMatrix() const { return m_ditheringMatrix; }
const Option& colorMode() const { return m_colorMode; }
const Option& shrinkTo() const { return m_shrinkTo; }
const Option& data() const { return m_data; }
@ -103,6 +104,7 @@ private:
Option& m_palette;
Option& m_scale;
Option& m_ditheringAlgorithm;
Option& m_ditheringMatrix;
Option& m_colorMode;
Option& m_shrinkTo;
Option& m_data;

View File

@ -140,6 +140,7 @@ void CliProcessor::process()
SpriteSheetType sheetType = SpriteSheetType::None;
app::Document* lastDoc = nullptr;
render::DitheringAlgorithm ditheringAlgorithm = render::DitheringAlgorithm::None;
std::string ditheringMatrix;
for (const auto& value : m_options.values()) {
const AppOptions::Option* opt = value.option();
@ -357,6 +358,10 @@ void CliProcessor::process()
"Usage: --dithering-algorithm <algorithm>\n"
"Where <algorithm> can be none, old-ordered, or ordered");
}
// --dithering-matrix <id>
else if (opt == &m_options.ditheringMatrix()) {
ditheringMatrix = value.value();
}
// --color-mode <mode>
else if (opt == &m_options.colorMode()) {
Command* command = CommandsModule::instance()->getCommandByName(CommandId::ChangePixelFormat);
@ -380,6 +385,11 @@ void CliProcessor::process()
params.set("dithering", "ordered");
break;
}
if (ditheringAlgorithm != render::DitheringAlgorithm::None &&
!ditheringMatrix.empty()) {
params.set("dithering-matrix", ditheringMatrix.c_str());
}
}
else {
throw std::runtime_error("--color-mode needs a valid color mode for conversion\n"

View File

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

View File

@ -18,6 +18,7 @@ namespace doc {
}
namespace render {
class DitheringMatrix;
class TaskDelegate;
}
@ -29,7 +30,8 @@ namespace cmd {
public:
SetPixelFormat(doc::Sprite* sprite,
const doc::PixelFormat newFormat,
const render::DitheringAlgorithm dithering,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
render::TaskDelegate* delegate);
protected:

View File

@ -14,6 +14,7 @@
#include "app/commands/command.h"
#include "app/commands/params.h"
#include "app/context_access.h"
#include "app/file/file.h"
#include "app/modules/editors.h"
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
@ -26,6 +27,7 @@
#include "doc/image.h"
#include "doc/sprite.h"
#include "render/dithering_algorithm.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
#include "render/render.h"
#include "render/task_delegate.h"
@ -85,6 +87,7 @@ public:
const doc::frame_t frame,
const doc::PixelFormat pixelFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
const gfx::Point& pos)
: m_image(dstImage)
, m_pos(pos)
@ -95,10 +98,12 @@ public:
[this,
sprite, frame,
pixelFormat,
ditheringAlgorithm]() {
ditheringAlgorithm,
ditheringMatrix]() { // Copy the matrix
run(sprite, frame,
pixelFormat,
ditheringAlgorithm);
ditheringAlgorithm,
ditheringMatrix);
})
{
}
@ -120,7 +125,8 @@ private:
void run(const Sprite* sprite,
const doc::frame_t frame,
const doc::PixelFormat pixelFormat,
const render::DitheringAlgorithm ditheringAlgorithm) {
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix) {
doc::ImageRef tmp(
Image::create(sprite->pixelFormat(),
m_image->width(),
@ -139,6 +145,7 @@ private:
m_image.get(),
pixelFormat,
ditheringAlgorithm,
ditheringMatrix,
sprite->rgbMap(frame),
sprite->palette(frame),
(sprite->backgroundLayer() != nullptr),
@ -277,6 +284,7 @@ private:
m_editor->frame(),
item->pixelFormat(),
item->ditheringAlgorithm(),
render::BayerMatrix(8), // TODO this must be configurable
visibleBounds.origin()));
m_timer.start();
@ -326,7 +334,8 @@ protected:
private:
bool m_useUI;
doc::PixelFormat m_format;
render::DitheringAlgorithm m_dithering;
render::DitheringAlgorithm m_ditheringAlgorithm;
render::DitheringMatrix m_ditheringMatrix;
};
ChangePixelFormatCommand::ChangePixelFormatCommand()
@ -336,7 +345,7 @@ ChangePixelFormatCommand::ChangePixelFormatCommand()
{
m_useUI = true;
m_format = IMAGE_RGB;
m_dithering = render::DitheringAlgorithm::None;
m_ditheringAlgorithm = render::DitheringAlgorithm::None;
}
void ChangePixelFormatCommand::onLoadParams(const Params& params)
@ -352,11 +361,54 @@ void ChangePixelFormatCommand::onLoadParams(const Params& params)
std::string dithering = params.get("dithering");
if (dithering == "ordered")
m_dithering = render::DitheringAlgorithm::Ordered;
m_ditheringAlgorithm = render::DitheringAlgorithm::Ordered;
else if (dithering == "old-ordered")
m_dithering = render::DitheringAlgorithm::OldOrdered;
m_ditheringAlgorithm = render::DitheringAlgorithm::OldOrdered;
else
m_dithering = render::DitheringAlgorithm::None;
m_ditheringAlgorithm = render::DitheringAlgorithm::None;
std::string matrix = params.get("dithering-matrix");
// TODO object slicing here (from BayerMatrix -> DitheringMatrix
if (!matrix.empty()) {
if (matrix == "bayer2x2")
m_ditheringMatrix = render::BayerMatrix(2);
else if (matrix == "bayer4x4")
m_ditheringMatrix = render::BayerMatrix(4);
else if (matrix == "bayer8x8")
m_ditheringMatrix = render::BayerMatrix(8);
else {
// Load a matrix from a file
base::UniquePtr<doc::Document> doc(load_document(nullptr, matrix));
if (doc) {
// Flatten layers
doc::Sprite* spr = doc->sprite();
app::Context ctx;
cmd::FlattenLayers(spr).execute(&ctx);
const doc::Layer* lay = spr->root()->firstLayer();
const doc::Image* img = (lay && lay->cel(0) ?
lay->cel(0)->image(): nullptr);
if (img) {
const int w = spr->width();
const int h = spr->height();
m_ditheringMatrix = render::DitheringMatrix(h, w);
for (int i=0; i<h; ++i)
for (int j=0; j<w; ++j)
m_ditheringMatrix(i, j) = img->getPixel(j, i);
m_ditheringMatrix.calcMaxValue();
}
else {
m_ditheringMatrix = render::DitheringMatrix();
}
}
else
throw std::runtime_error("Invalid matrix name");
}
}
// Default dithering matrix is BayerMatrix(8)
else {
m_ditheringMatrix = render::BayerMatrix(8);
}
}
bool ChangePixelFormatCommand::onEnabled(Context* context)
@ -372,7 +424,7 @@ bool ChangePixelFormatCommand::onEnabled(Context* context)
if (sprite->pixelFormat() == IMAGE_INDEXED &&
m_format == IMAGE_INDEXED &&
m_dithering != render::DitheringAlgorithm::None)
m_ditheringAlgorithm != render::DitheringAlgorithm::None)
return false;
return true;
@ -389,7 +441,7 @@ bool ChangePixelFormatCommand::onChecked(Context* context)
if (sprite &&
sprite->pixelFormat() == IMAGE_INDEXED &&
m_format == IMAGE_INDEXED &&
m_dithering != render::DitheringAlgorithm::None)
m_ditheringAlgorithm != render::DitheringAlgorithm::None)
return false;
return
@ -412,7 +464,7 @@ void ChangePixelFormatCommand::onExecute(Context* context)
return;
m_format = window.pixelFormat();
m_dithering = window.ditheringAlgorithm();
m_ditheringAlgorithm = window.ditheringAlgorithm();
flatten = window.flattenEnabled();
}
@ -432,7 +484,9 @@ void ChangePixelFormatCommand::onExecute(Context* context)
transaction.execute(
new cmd::SetPixelFormat(
sprite, m_format, m_dithering, &job));
sprite, m_format,
m_ditheringAlgorithm,
m_ditheringMatrix, &job));
if (!job.isCanceled())
transaction.commit();
});
@ -454,7 +508,7 @@ std::string ChangePixelFormatCommand::onGetFriendlyName() const
break;
case IMAGE_INDEXED:
text += " to Indexed";
switch (m_dithering) {
switch (m_ditheringAlgorithm) {
case render::DitheringAlgorithm::None:
break;
case render::DitheringAlgorithm::OldOrdered:

View File

@ -25,6 +25,7 @@
#include "doc/layer.h"
#include "doc/primitives.h"
#include "doc/sprite.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
#include "render/render.h"
#include "ui/ui.h"
@ -271,6 +272,7 @@ void NewLayerCommand::onExecute(Context* context)
nullptr,
sprite->pixelFormat(),
render::DitheringAlgorithm::None,
render::DitheringMatrix(),
sprite->rgbMap(dstFrame),
pasteSpr->palette(fr),
(pasteSpr->backgroundLayer() ? true: false),

View File

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

View File

@ -38,6 +38,7 @@
#include "gfx/packing_rects.h"
#include "gfx/size.h"
#include "render/dithering_algorithm.h"
#include "render/ordered_dither.h"
#include "render/render.h"
#include <cstdio>
@ -708,6 +709,7 @@ void DocumentExporter::renderTexture(const Samples& samples, Image* textureImage
sample.sprite(),
textureImage->pixelFormat(),
render::DitheringAlgorithm::None,
render::DitheringMatrix(),
nullptr) // TODO add a delegate to show progress
.execute(UIContext::instance());
}

View File

@ -22,6 +22,7 @@
#include "base/fs.h"
#include "base/unique_ptr.h"
#include "doc/doc.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
#include "render/render.h"
#include "ui/alert.h"
@ -697,6 +698,7 @@ private:
render::convert_pixel_format
(oldImage, NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
render::DitheringMatrix(),
nullptr,
m_sprite->palette(cel->frame()),
m_opaque,
@ -709,6 +711,7 @@ private:
render::convert_pixel_format
(m_currentImage.get(), NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
render::DitheringMatrix(),
nullptr,
m_sprite->palette(m_frameNum),
m_opaque,
@ -718,6 +721,7 @@ private:
render::convert_pixel_format
(m_previousImage.get(), NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
render::DitheringMatrix(),
nullptr,
m_sprite->palette(MAX(0, m_frameNum-1)),
m_opaque,

View File

@ -32,6 +32,7 @@
#include "app/util/new_image_from_mask.h"
#include "base/shared_ptr.h"
#include "doc/doc.h"
#include "render/ordered_dither.h"
#include "render/quantization.h"
#include <stdexcept>
@ -333,6 +334,7 @@ void paste()
render::convert_pixel_format(
clipboard_image.get(), NULL, dstSpr->pixelFormat(),
render::DitheringAlgorithm::None,
render::DitheringMatrix(),
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/ordered_dither.h"
#include "render/quantization.h"
#include "render/render.h"
@ -53,6 +54,7 @@ Cel* create_cel_copy(const Cel* srcCel,
tmpImage.get(),
IMAGE_RGB,
render::DitheringAlgorithm::None,
render::DitheringMatrix(),
srcCel->sprite()->rgbMap(srcCel->frame()),
srcCel->sprite()->palette(srcCel->frame()),
srcCel->layer()->isBackground(),
@ -63,6 +65,7 @@ Cel* create_cel_copy(const Cel* srcCel,
dstCel->image(),
IMAGE_INDEXED,
render::DitheringAlgorithm::None,
render::DitheringMatrix(),
dstSprite->rgbMap(dstFrame),
dstSprite->palette(dstFrame),
srcCel->layer()->isBackground(),

View File

@ -1,8 +1,9 @@
# Aseprite Render Library
# Copyright (C) 2001-2016 David Capello
# Copyright (C) 2001-2017 David Capello
add_library(render-lib
get_sprite_pixel.cpp
ordered_dither.cpp
quantization.cpp
render.cpp
zoom.cpp)

View File

@ -0,0 +1,55 @@
// Aseprite Render Library
// Copyright (c) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "render/ordered_dither.h"
namespace render {
// Base 2x2 dither matrix, called D(2):
int BayerMatrix::D2[4] = { 0, 2,
3, 1 };
void dither_rgb_image_to_indexed(
DitheringAlgorithmBase& algorithm,
const DitheringMatrix& matrix,
const doc::Image* srcImage,
doc::Image* dstImage,
int u, int v,
const doc::RgbMap* rgbmap,
const doc::Palette* palette,
TaskDelegate* delegate)
{
const doc::LockImageBits<doc::RgbTraits> srcBits(srcImage);
doc::LockImageBits<doc::IndexedTraits> dstBits(dstImage);
auto srcIt = srcBits.begin();
auto dstIt = dstBits.begin();
int w = srcImage->width();
int h = srcImage->height();
for (int y=0; y<h; ++y) {
for (int x=0; x<w; ++x, ++srcIt, ++dstIt) {
ASSERT(srcIt != srcBits.end());
ASSERT(dstIt != dstBits.end());
*dstIt = algorithm.ditherRgbPixelToIndex(matrix, *srcIt, x+u, y+v, rgbmap, palette);
if (delegate) {
if (!delegate->continueTask())
return;
}
}
if (delegate) {
delegate->notifyTaskProgress(
double(y+1) / double(h));
}
}
}
} // namespace render

View File

@ -14,33 +14,61 @@
#include "doc/rgbmap.h"
#include "render/task_delegate.h"
#include <algorithm>
#include <limits>
#include <vector>
namespace render {
// Creates a Bayer dither matrix.
template<int N>
class BayerMatrix {
static int D2[4];
int m_matrix[N*N];
class DitheringMatrix {
public:
int maxValue() const { return N*N-1; }
DitheringMatrix()
: m_rows(1), m_cols(1)
, m_matrix(1, 1)
, m_maxValue(1) {
}
BayerMatrix() {
int c = 0;
for (int i=0; i<N; ++i)
for (int j=0; j<N; ++j)
m_matrix[c++] = Dn(i, j, N);
DitheringMatrix(int rows, int cols)
: m_rows(rows), m_cols(cols)
, m_matrix(rows*cols, 0)
, m_maxValue(1) {
}
int rows() const { return m_rows; }
int cols() const { return m_cols; }
int maxValue() const { return m_maxValue; }
void calcMaxValue() {
m_maxValue = *std::max_element(m_matrix.begin(),
m_matrix.end());
m_maxValue = std::max(m_maxValue, 1);
}
int operator()(int i, int j) const {
return m_matrix[(i%N)*N + (j%N)];
return m_matrix[(i%m_rows)*m_cols + (j%m_cols)];
}
int operator[](int i) const {
return m_matrix[i];
int& operator()(int i, int j) {
return m_matrix[(i%m_rows)*m_cols + (j%m_cols)];
}
private:
int m_rows, m_cols;
std::vector<int> m_matrix;
int m_maxValue;
};
// Creates a Bayer dither matrix.
class BayerMatrix : public DitheringMatrix {
static int D2[4];
public:
BayerMatrix(int n) : DitheringMatrix(n, n) {
for (int i=0; i<n; ++i)
for (int j=0; j<n; ++j)
operator()(i, j) = Dn(i, j, n);
calcMaxValue();
}
private:
@ -57,12 +85,19 @@ namespace render {
}
};
// Base 2x2 dither matrix, called D(2):
template<int N>
int BayerMatrix<N>::D2[4] = { 0, 2,
3, 1 };
class DitheringAlgorithmBase {
public:
virtual ~DitheringAlgorithmBase() { }
virtual doc::color_t ditherRgbPixelToIndex(
const DitheringMatrix& matrix,
const doc::color_t color,
const int x,
const int y,
const doc::RgbMap* rgbmap,
const doc::Palette* palette) = 0;
};
class OrderedDither {
class OrderedDither : public DitheringAlgorithmBase {
static int colorDistance(int r1, int g1, int b1, int a1,
int r2, int g2, int b2, int a2) {
// The factor for RGB components came from doc::rba_luma()
@ -76,13 +111,13 @@ namespace render {
OrderedDither(int transparentIndex = -1) : m_transparentIndex(transparentIndex) {
}
template<typename Matrix>
doc::color_t ditherRgbPixelToIndex(
const Matrix& matrix,
doc::color_t color,
int x, int y,
const DitheringMatrix& matrix,
const doc::color_t color,
const int x,
const int y,
const doc::RgbMap* rgbmap,
const doc::Palette* palette) {
const doc::Palette* palette) override {
// Alpha=0, output transparent color
if (m_transparentIndex >= 0 &&
doc::rgba_geta(color) == 0)
@ -143,7 +178,7 @@ namespace render {
// with the threshold. If d > threshold, it means that we're
// closer to 'nearest2rgb' than to 'nearest1rgb'.
d = matrix.maxValue() * d / D;
int threshold = matrix(x, y);
int threshold = matrix(y, x);
return (d > threshold ? nearest2idx:
nearest1idx);
@ -163,7 +198,7 @@ namespace render {
// Some ideas from:
// http://bisqwit.iki.fi/story/howto/dither/jy/
//
class OrderedDither2 {
class OrderedDither2 : public DitheringAlgorithmBase {
static int colorDistance(int r1, int g1, int b1, int a1,
int r2, int g2, int b2, int a2) {
int result = 0;
@ -183,13 +218,13 @@ namespace render {
OrderedDither2(int transparentIndex = -1) : m_transparentIndex(transparentIndex) {
}
template<typename Matrix>
doc::color_t ditherRgbPixelToIndex(
const Matrix& matrix,
doc::color_t color,
int x, int y,
const DitheringMatrix& matrix,
const doc::color_t color,
const int x,
const int y,
const doc::RgbMap* rgbmap,
const doc::Palette* palette) {
const doc::Palette* palette) override {
// Alpha=0, output transparent color
if (m_transparentIndex >= 0 &&
doc::rgba_geta(color) == 0) {
@ -269,7 +304,7 @@ namespace render {
// Using the bestMix factor the dithering matrix tells us if we
// should paint with altIndex or index in this x,y position.
if (altIndex >= 0 && matrix(x, y) < bestMix)
if (altIndex >= 0 && matrix(y, x) < bestMix)
return altIndex;
else
return index;
@ -279,41 +314,15 @@ namespace render {
int m_transparentIndex;
};
template<typename Dithering,
typename Matrix>
void dither_rgb_image_to_indexed(Dithering& dithering,
const Matrix& matrix,
void dither_rgb_image_to_indexed(
DitheringAlgorithmBase& algorithm,
const DitheringMatrix& matrix,
const doc::Image* srcImage,
doc::Image* dstImage,
int u, int v,
const doc::RgbMap* rgbmap,
const doc::Palette* palette,
TaskDelegate* delegate = nullptr) {
const doc::LockImageBits<doc::RgbTraits> srcBits(srcImage);
doc::LockImageBits<doc::IndexedTraits> dstBits(dstImage);
auto srcIt = srcBits.begin();
auto dstIt = dstBits.begin();
int w = srcImage->width();
int h = srcImage->height();
for (int y=0; y<h; ++y) {
for (int x=0; x<w; ++x, ++srcIt, ++dstIt) {
ASSERT(srcIt != srcBits.end());
ASSERT(dstIt != dstBits.end());
*dstIt = dithering.ditherRgbPixelToIndex(matrix, *srcIt, x+u, y+v, rgbmap, palette);
if (delegate) {
if (!delegate->continueTask())
return;
}
}
if (delegate) {
delegate->notifyTaskProgress(
double(y+1) / double(h));
}
}
}
TaskDelegate* delegate = nullptr);
} // namespace render

View File

@ -10,7 +10,7 @@
#include "render/quantization.h"
#include "base/base.h"
#include "base/unique_ptr.h"
#include "doc/image_impl.h"
#include "doc/images_collector.h"
#include "doc/layer.h"
@ -82,6 +82,7 @@ Image* convert_pixel_format(
Image* new_image,
PixelFormat pixelFormat,
DitheringAlgorithm ditheringAlgorithm,
const DitheringMatrix& ditheringMatrix,
const RgbMap* rgbmap,
const Palette* palette,
bool is_background,
@ -96,19 +97,18 @@ Image* convert_pixel_format(
if (image->pixelFormat() == IMAGE_RGB &&
pixelFormat == IMAGE_INDEXED &&
ditheringAlgorithm != DitheringAlgorithm::None) {
BayerMatrix<8> matrix;
base::UniquePtr<DitheringAlgorithmBase> dither;
switch (ditheringAlgorithm) {
case DitheringAlgorithm::OldOrdered: {
OrderedDither dither(is_background ? -1: new_mask_color);
dither_rgb_image_to_indexed(dither, matrix, image, new_image, 0, 0, rgbmap, palette, delegate);
case DitheringAlgorithm::OldOrdered:
dither.reset(new OrderedDither(is_background ? -1: new_mask_color));
break;
case DitheringAlgorithm::Ordered:
dither.reset(new OrderedDither2(is_background ? -1: new_mask_color));
break;
}
case DitheringAlgorithm::Ordered: {
OrderedDither2 dither(is_background ? -1: new_mask_color);
dither_rgb_image_to_indexed(dither, matrix, image, new_image, 0, 0, rgbmap, palette, delegate);
break;
}
}
if (dither)
dither_rgb_image_to_indexed(
*dither, ditheringMatrix, image, new_image, 0, 0, rgbmap, palette, delegate);
return new_image;
}

View File

@ -23,6 +23,7 @@ namespace doc {
}
namespace render {
class DitheringMatrix;
class TaskDelegate;
class PaletteOptimizer {
@ -51,6 +52,7 @@ namespace render {
doc::Image* dst, // Can be NULL to create a new image
doc::PixelFormat pixelFormat,
render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
const doc::RgbMap* rgbmap,
const doc::Palette* palette,
bool is_background,