diff --git a/data/pref.xml b/data/pref.xml
index 704683a2b..29b19df7e 100644
--- a/data/pref.xml
+++ b/data/pref.xml
@@ -237,6 +237,7 @@
diff --git a/data/strings/en.ini b/data/strings/en.ini
index 49395e7af..ec8820c47 100644
--- a/data/strings/en.ini
+++ b/data/strings/en.ini
@@ -482,6 +482,7 @@ delete = &Delete
[color_mode]
title = Color Mode
+amount = Amount:
flatten = Merge layers
[convolution_matrix]
diff --git a/data/widgets/color_mode.xml b/data/widgets/color_mode.xml
index b0e0fb84b..d2a7c26ac 100644
--- a/data/widgets/color_mode.xml
+++ b/data/widgets/color_mode.xml
@@ -1,5 +1,6 @@
-
+
+
@@ -8,6 +9,11 @@
+
+
+
+
+
diff --git a/src/app/cmd/set_pixel_format.cpp b/src/app/cmd/set_pixel_format.cpp
index d7e9b4298..db9a9c610 100644
--- a/src/app/cmd/set_pixel_format.cpp
+++ b/src/app/cmd/set_pixel_format.cpp
@@ -1,4 +1,5 @@
// Aseprite
+// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@@ -69,6 +70,7 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
const PixelFormat newFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
+ const double ditheringFactor,
render::TaskDelegate* delegate)
: WithSprite(sprite)
, m_oldFormat(sprite->pixelFormat())
@@ -86,6 +88,7 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
(old_image.get(), nullptr, newFormat,
ditheringAlgorithm,
ditheringMatrix,
+ ditheringFactor,
sprite->rgbMap(cel->frame()),
sprite->palette(cel->frame()),
cel->layer()->isBackground(),
diff --git a/src/app/cmd/set_pixel_format.h b/src/app/cmd/set_pixel_format.h
index d033baebf..40ec6a919 100644
--- a/src/app/cmd/set_pixel_format.h
+++ b/src/app/cmd/set_pixel_format.h
@@ -1,4 +1,5 @@
// Aseprite
+// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@@ -32,6 +33,7 @@ namespace cmd {
const doc::PixelFormat newFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
+ const double ditheringFactor,
render::TaskDelegate* delegate);
protected:
diff --git a/src/app/commands/cmd_change_pixel_format.cpp b/src/app/commands/cmd_change_pixel_format.cpp
index b3db46213..ab9453d3f 100644
--- a/src/app/commands/cmd_change_pixel_format.cpp
+++ b/src/app/commands/cmd_change_pixel_format.cpp
@@ -1,5 +1,5 @@
// Aseprite
-// Copyright (C) 2019 Igara Studio S.A.
+// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@@ -79,6 +79,7 @@ public:
const doc::PixelFormat pixelFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
+ const double ditheringFactor,
const gfx::Point& pos,
const bool newBlend)
: m_image(dstImage)
@@ -92,11 +93,13 @@ public:
pixelFormat,
ditheringAlgorithm,
ditheringMatrix,
+ ditheringFactor,
newBlend]() { // Copy the matrix
run(sprite, frame,
pixelFormat,
ditheringAlgorithm,
ditheringMatrix,
+ ditheringFactor,
newBlend);
})
{
@@ -121,6 +124,7 @@ private:
const doc::PixelFormat pixelFormat,
const render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
+ const double ditheringFactor,
const bool newBlend) {
doc::ImageRef tmp(
Image::create(sprite->pixelFormat(),
@@ -142,6 +146,7 @@ private:
pixelFormat,
ditheringAlgorithm,
ditheringMatrix,
+ ditheringFactor,
sprite->rgbMap(frame),
sprite->palette(frame),
(sprite->backgroundLayer() != nullptr),
@@ -208,6 +213,11 @@ public:
m_ditheringSelector->Change.connect(
base::Bind(&ColorModeWindow::onDithering, this));
ditheringPlaceholder()->addChild(m_ditheringSelector);
+
+ factor()->Change.connect(base::Bind(&ColorModeWindow::onDithering, this));
+ }
+ else {
+ amount()->setVisible(false);
}
if (from != IMAGE_GRAYSCALE)
colorMode()->addChild(new ConversionItem(IMAGE_GRAYSCALE));
@@ -221,6 +231,9 @@ public:
progress()->setReadOnly(true);
+ // Default dithering factor
+ factor()->setValue(Preferences::instance().quantization.ditheringFactor());
+
// Select first option
colorMode()->selectIndex(0);
}
@@ -244,6 +257,10 @@ public:
render::BayerMatrix(8));
}
+ double ditheringFactor() const {
+ return double(factor()->getValue()) / 100.0;
+ }
+
bool flattenEnabled() const {
return flatten()->isSelected();
}
@@ -252,7 +269,14 @@ public:
void saveDitheringAlgorithm() {
if (m_ditheringSelector) {
if (auto item = m_ditheringSelector->getSelectedItem()) {
- Preferences::instance().quantization.ditheringAlgorithm(item->text());
+ Preferences::instance().quantization.ditheringAlgorithm(
+ item->text());
+
+ if (m_ditheringSelector->ditheringAlgorithm() ==
+ render::DitheringAlgorithm::ErrorDiffusion) {
+ Preferences::instance().quantization.ditheringFactor(
+ factor()->getValue());
+ }
}
}
}
@@ -285,8 +309,15 @@ private:
doc::PixelFormat dstPixelFormat = item->pixelFormat();
- if (m_ditheringSelector)
- m_ditheringSelector->setVisible(dstPixelFormat == doc::IMAGE_INDEXED);
+ if (m_ditheringSelector) {
+ const bool toIndexed = (dstPixelFormat == doc::IMAGE_INDEXED);
+ m_ditheringSelector->setVisible(toIndexed);
+
+ const bool errorDiff =
+ (m_ditheringSelector->ditheringAlgorithm() ==
+ render::DitheringAlgorithm::ErrorDiffusion);
+ amount()->setVisible(toIndexed && errorDiff);
+ }
m_image.reset(
Image::create(dstPixelFormat,
@@ -315,6 +346,7 @@ private:
dstPixelFormat,
ditheringAlgorithm(),
ditheringMatrix(),
+ ditheringFactor(),
visibleBounds.origin(),
Preferences::instance().experimental.newBlend()));
@@ -373,6 +405,7 @@ private:
doc::PixelFormat m_format;
render::DitheringAlgorithm m_ditheringAlgorithm;
render::DitheringMatrix m_ditheringMatrix;
+ double m_ditheringFactor;
};
ChangePixelFormatCommand::ChangePixelFormatCommand()
@@ -381,6 +414,7 @@ ChangePixelFormatCommand::ChangePixelFormatCommand()
m_useUI = true;
m_format = IMAGE_RGB;
m_ditheringAlgorithm = render::DitheringAlgorithm::None;
+ m_ditheringFactor = 1.0;
}
void ChangePixelFormatCommand::onLoadParams(const Params& params)
@@ -483,6 +517,7 @@ void ChangePixelFormatCommand::onExecute(Context* context)
m_format = window.pixelFormat();
m_ditheringAlgorithm = window.ditheringAlgorithm();
m_ditheringMatrix = window.ditheringMatrix();
+ m_ditheringFactor = window.ditheringFactor();
flatten = window.flattenEnabled();
window.saveDitheringAlgorithm();
@@ -520,6 +555,7 @@ void ChangePixelFormatCommand::onExecute(Context* context)
sprite, m_format,
m_ditheringAlgorithm,
m_ditheringMatrix,
+ m_ditheringFactor,
&job)); // SpriteJob is a render::TaskDelegate
});
job.waitJob();
diff --git a/src/app/commands/cmd_new_layer.cpp b/src/app/commands/cmd_new_layer.cpp
index 148a28a6a..e5bd55527 100644
--- a/src/app/commands/cmd_new_layer.cpp
+++ b/src/app/commands/cmd_new_layer.cpp
@@ -1,5 +1,5 @@
// Aseprite
-// Copyright (C) 2019 Igara Studio S.A.
+// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@@ -283,7 +283,7 @@ void NewLayerCommand::onExecute(Context* context)
nullptr,
sprite->pixelFormat(),
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
sprite->rgbMap(dstFrame),
pasteSpr->palette(fr),
(pasteSpr->backgroundLayer() ? true: false),
diff --git a/src/app/commands/cmd_paste_text.cpp b/src/app/commands/cmd_paste_text.cpp
index 55b85e11a..95d44a469 100644
--- a/src/app/commands/cmd_paste_text.cpp
+++ b/src/app/commands/cmd_paste_text.cpp
@@ -1,4 +1,5 @@
// Aseprite
+// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@@ -184,7 +185,7 @@ void PasteTextCommand::onExecute(Context* ctx)
render::convert_pixel_format(
image.get(), NULL, sprite->pixelFormat(),
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
rgbmap, sprite->palette(editor->frame()),
false, 0));
}
diff --git a/src/app/doc_exporter.cpp b/src/app/doc_exporter.cpp
index fd4de3cfc..22fd6a2c7 100644
--- a/src/app/doc_exporter.cpp
+++ b/src/app/doc_exporter.cpp
@@ -744,7 +744,7 @@ void DocExporter::renderTexture(Context* ctx, const Samples& samples, Image* tex
sample.sprite(),
textureImage->pixelFormat(),
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
nullptr) // TODO add a delegate to show progress
.execute(ctx);
}
diff --git a/src/app/file/gif_format.cpp b/src/app/file/gif_format.cpp
index e57faf4f0..1e361e64e 100644
--- a/src/app/file/gif_format.cpp
+++ b/src/app/file/gif_format.cpp
@@ -746,7 +746,7 @@ private:
render::convert_pixel_format
(oldImage, NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
nullptr,
m_sprite->palette(cel->frame()),
m_opaque,
@@ -759,7 +759,7 @@ private:
render::convert_pixel_format
(m_currentImage.get(), NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
nullptr,
m_sprite->palette(m_frameNum),
m_opaque,
@@ -769,7 +769,7 @@ private:
render::convert_pixel_format
(m_previousImage.get(), NULL, IMAGE_RGB,
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
nullptr,
m_sprite->palette(MAX(0, m_frameNum-1)),
m_opaque,
diff --git a/src/app/ui/dithering_selector.cpp b/src/app/ui/dithering_selector.cpp
index fead5ca7d..fadaeac92 100644
--- a/src/app/ui/dithering_selector.cpp
+++ b/src/app/ui/dithering_selector.cpp
@@ -1,4 +1,5 @@
// Aseprite
+// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2017 David Capello
//
// This program is distributed under the terms of
@@ -101,7 +102,8 @@ private:
doc::clear_image(image2.get(), 0);
render::convert_pixel_format(
image1.get(), image2.get(), IMAGE_INDEXED,
- m_algo, m_matrix, nullptr, palette, true, -1, nullptr);
+ m_algo, m_matrix, 1.0,
+ nullptr, palette, true, -1, nullptr);
}
m_preview = os::instance()->createRgbaSurface(w, h);
diff --git a/src/app/util/clipboard.cpp b/src/app/util/clipboard.cpp
index 66818cf37..6adf06718 100644
--- a/src/app/util/clipboard.cpp
+++ b/src/app/util/clipboard.cpp
@@ -367,7 +367,7 @@ void paste()
render::convert_pixel_format(
clipboard_image.get(), NULL, dstSpr->pixelFormat(),
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
dst_rgbmap, clipboard_palette.get(),
false,
0));
diff --git a/src/app/util/create_cel_copy.cpp b/src/app/util/create_cel_copy.cpp
index ceab5c07d..e80b3f071 100644
--- a/src/app/util/create_cel_copy.cpp
+++ b/src/app/util/create_cel_copy.cpp
@@ -1,4 +1,5 @@
// Aseprite
+// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@@ -54,7 +55,7 @@ Cel* create_cel_copy(const Cel* srcCel,
tmpImage.get(),
IMAGE_RGB,
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
srcCel->sprite()->rgbMap(srcCel->frame()),
srcCel->sprite()->palette(srcCel->frame()),
srcCel->layer()->isBackground(),
@@ -65,7 +66,7 @@ Cel* create_cel_copy(const Cel* srcCel,
dstCel->image(),
IMAGE_INDEXED,
render::DitheringAlgorithm::None,
- render::DitheringMatrix(),
+ render::DitheringMatrix(), 1.0,
dstSprite->rgbMap(dstFrame),
dstSprite->palette(dstFrame),
srcCel->layer()->isBackground(),
diff --git a/src/render/error_diffusion.cpp b/src/render/error_diffusion.cpp
index 48213eccf..b066dbd97 100644
--- a/src/render/error_diffusion.cpp
+++ b/src/render/error_diffusion.cpp
@@ -25,13 +25,15 @@ ErrorDiffusionDither::ErrorDiffusionDither(int transparentIndex)
void ErrorDiffusionDither::start(
const doc::Image* srcImage,
- doc::Image* dstImage)
+ doc::Image* dstImage,
+ const double factor)
{
m_srcImage = srcImage;
m_width = 2+srcImage->width();
for (int i=0; i m_err[kChannels];
+ int m_factor;
};
} // namespace render
diff --git a/src/render/ordered_dither.cpp b/src/render/ordered_dither.cpp
index 12440658f..8176f8fff 100644
--- a/src/render/ordered_dither.cpp
+++ b/src/render/ordered_dither.cpp
@@ -229,6 +229,7 @@ doc::color_t OrderedDither2::ditherRgbPixelToIndex(
void dither_rgb_image_to_indexed(
DitheringAlgorithmBase& algorithm,
const DitheringMatrix& matrix,
+ const double factor,
const doc::Image* srcImage,
doc::Image* dstImage,
const doc::RgbMap* rgbmap,
@@ -238,7 +239,7 @@ void dither_rgb_image_to_indexed(
const int w = srcImage->width();
const int h = srcImage->height();
- algorithm.start(srcImage, dstImage);
+ algorithm.start(srcImage, dstImage, factor);
if (algorithm.dimensions() == 1) {
const doc::LockImageBits srcBits(srcImage);
diff --git a/src/render/ordered_dither.h b/src/render/ordered_dither.h
index 18a8a2dc1..64651f6b8 100644
--- a/src/render/ordered_dither.h
+++ b/src/render/ordered_dither.h
@@ -29,7 +29,8 @@ namespace render {
virtual void start(
const doc::Image* srcImage,
- doc::Image* dstImage) { }
+ doc::Image* dstImage,
+ const double factor) { }
virtual void finish() { }
@@ -77,6 +78,7 @@ namespace render {
void dither_rgb_image_to_indexed(
DitheringAlgorithmBase& algorithm,
const DitheringMatrix& matrix,
+ const double factor,
const doc::Image* srcImage,
doc::Image* dstImage,
const doc::RgbMap* rgbmap,
diff --git a/src/render/quantization.cpp b/src/render/quantization.cpp
index d75b591a5..0dba27640 100644
--- a/src/render/quantization.cpp
+++ b/src/render/quantization.cpp
@@ -86,6 +86,7 @@ Image* convert_pixel_format(
PixelFormat pixelFormat,
DitheringAlgorithm ditheringAlgorithm,
const DitheringMatrix& ditheringMatrix,
+ const double ditheringFactor,
const RgbMap* rgbmap,
const Palette* palette,
bool is_background,
@@ -114,7 +115,8 @@ Image* convert_pixel_format(
}
if (dither)
dither_rgb_image_to_indexed(
- *dither, ditheringMatrix, image, new_image, rgbmap, palette, delegate);
+ *dither, ditheringMatrix, ditheringFactor,
+ image, new_image, rgbmap, palette, delegate);
return new_image;
}
diff --git a/src/render/quantization.h b/src/render/quantization.h
index a76d64eee..01e7640b1 100644
--- a/src/render/quantization.h
+++ b/src/render/quantization.h
@@ -55,6 +55,7 @@ namespace render {
doc::PixelFormat pixelFormat,
render::DitheringAlgorithm ditheringAlgorithm,
const render::DitheringMatrix& ditheringMatrix,
+ const double ditheringFactor,
const doc::RgbMap* rgbmap,
const doc::Palette* palette,
bool is_background,