mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 04:19:12 +00:00
Add progress bar to color conversion
Unified render tasks stop/progress notifications in render::TaskDelegate interface.
This commit is contained in:
parent
7bc0c4fba5
commit
573cad4777
@ -6,8 +6,8 @@
|
||||
<view id="color_mode_view" expansive="true">
|
||||
<listbox id="color_mode" />
|
||||
</view>
|
||||
<slider min="0" max="100" id="progress" minwidth="100" />
|
||||
<separator horizontal="true" />
|
||||
|
||||
<hbox>
|
||||
<boxfiller />
|
||||
<hbox homogeneous="true">
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "render/dithering_algorithm.h"
|
||||
#include "render/quantization.h"
|
||||
#include "render/render.h"
|
||||
#include "render/task_delegate.h"
|
||||
#include "ui/listitem.h"
|
||||
#include "ui/paint_event.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
@ -75,7 +76,7 @@ private:
|
||||
render::DitheringAlgorithm m_dithering;
|
||||
};
|
||||
|
||||
class ConvertThread {
|
||||
class ConvertThread : public render::TaskDelegate {
|
||||
public:
|
||||
ConvertThread(const doc::ImageRef& dstImage,
|
||||
const doc::Sprite* sprite,
|
||||
@ -85,6 +86,7 @@ public:
|
||||
: m_image(dstImage)
|
||||
, m_running(true)
|
||||
, m_stopFlag(false)
|
||||
, m_progress(0.0)
|
||||
, m_thread(
|
||||
[this,
|
||||
sprite, frame,
|
||||
@ -106,6 +108,10 @@ public:
|
||||
return m_running;
|
||||
}
|
||||
|
||||
double progress() const {
|
||||
return m_progress;
|
||||
}
|
||||
|
||||
private:
|
||||
void run(const Sprite* sprite,
|
||||
const doc::frame_t frame,
|
||||
@ -128,15 +134,25 @@ private:
|
||||
sprite->palette(frame),
|
||||
(sprite->backgroundLayer() != nullptr),
|
||||
0,
|
||||
&m_stopFlag);
|
||||
this);
|
||||
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
private:
|
||||
// render::TaskDelegate impl
|
||||
bool continueTask() override {
|
||||
return !m_stopFlag;
|
||||
}
|
||||
|
||||
void notifyTaskProgress(double progress) override {
|
||||
m_progress = progress;
|
||||
}
|
||||
|
||||
doc::ImageRef m_image;
|
||||
bool m_running;
|
||||
bool m_stopFlag;
|
||||
double m_progress;
|
||||
base::thread m_thread;
|
||||
};
|
||||
|
||||
@ -176,6 +192,8 @@ public:
|
||||
colorMode()->Change.connect(base::Bind<void>(&ColorModeWindow::onChangeColorMode, this));
|
||||
m_timer.Tick.connect(base::Bind<void>(&ColorModeWindow::onMonitorProgress, this));
|
||||
|
||||
progress()->setReadOnly(true);
|
||||
|
||||
// Select first option
|
||||
colorMode()->selectIndex(0);
|
||||
}
|
||||
@ -230,6 +248,9 @@ private:
|
||||
|
||||
m_image->clear(0);
|
||||
m_editor->invalidate();
|
||||
progress()->setValue(0);
|
||||
progress()->setVisible(true);
|
||||
layout();
|
||||
|
||||
m_bgThread.reset(
|
||||
new ConvertThread(
|
||||
@ -251,7 +272,12 @@ private:
|
||||
m_timer.stop();
|
||||
m_bgThread->stop();
|
||||
m_bgThread.reset(nullptr);
|
||||
|
||||
progress()->setVisible(false);
|
||||
layout();
|
||||
}
|
||||
else
|
||||
progress()->setValue(100 * m_bgThread->progress());
|
||||
|
||||
m_editor->invalidate();
|
||||
}
|
||||
@ -374,7 +400,6 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
||||
{
|
||||
ContextWriter writer(context);
|
||||
Transaction transaction(writer.context(), "Color Mode Change");
|
||||
Document* document(writer.document());
|
||||
Sprite* sprite(writer.sprite());
|
||||
|
||||
transaction.execute(new cmd::SetPixelFormat(sprite, m_format, m_dithering));
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -25,6 +25,7 @@
|
||||
#include "doc/palette.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "render/quantization.h"
|
||||
#include "render/task_delegate.h"
|
||||
#include "ui/manager.h"
|
||||
|
||||
#include "palette_from_sprite.xml.h"
|
||||
@ -42,7 +43,7 @@ protected:
|
||||
};
|
||||
|
||||
class ColorQuantizationJob : public Job,
|
||||
public render::PaletteOptimizerDelegate {
|
||||
public render::TaskDelegate {
|
||||
public:
|
||||
ColorQuantizationJob(Sprite* sprite, bool withAlpha, Palette* palette)
|
||||
: Job("Creating Palette")
|
||||
@ -59,11 +60,11 @@ private:
|
||||
m_withAlpha, m_palette, this);
|
||||
}
|
||||
|
||||
bool onPaletteOptimizerContinue() override {
|
||||
bool continueTask() override {
|
||||
return !isCanceled();
|
||||
}
|
||||
|
||||
void onPaletteOptimizerProgress(double progress) override {
|
||||
void notifyTaskProgress(double progress) override {
|
||||
jobProgress(progress);
|
||||
}
|
||||
|
||||
|
@ -756,7 +756,7 @@ private:
|
||||
}
|
||||
|
||||
Palette newPalette(0, 256);
|
||||
optimizer.calculate(&newPalette, m_bgIndex, nullptr);
|
||||
optimizer.calculate(&newPalette, m_bgIndex);
|
||||
m_sprite->setPalette(&newPalette, false);
|
||||
}
|
||||
|
||||
@ -1245,7 +1245,7 @@ private:
|
||||
}
|
||||
|
||||
Palette* palette = new Palette(0, 256);
|
||||
optimizer.calculate(palette, m_transparentIndex, nullptr);
|
||||
optimizer.calculate(palette, m_transparentIndex);
|
||||
return palette;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/rgbmap.h"
|
||||
#include "render/task_delegate.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
@ -273,7 +274,7 @@ namespace render {
|
||||
int u, int v,
|
||||
const doc::RgbMap* rgbmap,
|
||||
const doc::Palette* palette,
|
||||
bool* stopFlag = nullptr) {
|
||||
TaskDelegate* delegate = nullptr) {
|
||||
const doc::LockImageBits<doc::RgbTraits> srcBits(srcImage);
|
||||
doc::LockImageBits<doc::IndexedTraits> dstBits(dstImage);
|
||||
auto srcIt = srcBits.begin();
|
||||
@ -286,8 +287,16 @@ namespace render {
|
||||
ASSERT(srcIt != srcBits.end());
|
||||
ASSERT(dstIt != dstBits.end());
|
||||
*dstIt = dithering.ditherRgbPixelToIndex(matrix, *srcIt, x+u, y+v, rgbmap, palette);
|
||||
if (stopFlag && *stopFlag)
|
||||
break;
|
||||
|
||||
if (delegate) {
|
||||
if (!delegate->continueTask())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (delegate) {
|
||||
delegate->notifyTaskProgress(
|
||||
double(y+1) / double(h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "gfx/rgb.h"
|
||||
#include "render/ordered_dither.h"
|
||||
#include "render/render.h"
|
||||
#include "render/task_delegate.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
@ -40,7 +41,7 @@ Palette* create_palette_from_sprite(
|
||||
const frame_t toFrame,
|
||||
const bool withAlpha,
|
||||
Palette* palette,
|
||||
PaletteOptimizerDelegate* delegate)
|
||||
TaskDelegate* delegate)
|
||||
{
|
||||
PaletteOptimizer optimizer;
|
||||
|
||||
@ -58,10 +59,10 @@ Palette* create_palette_from_sprite(
|
||||
optimizer.feedWithImage(flat_image.get(), withAlpha);
|
||||
|
||||
if (delegate) {
|
||||
if (!delegate->onPaletteOptimizerContinue())
|
||||
if (!delegate->continueTask())
|
||||
return nullptr;
|
||||
|
||||
delegate->onPaletteOptimizerProgress(
|
||||
delegate->notifyTaskProgress(
|
||||
double(frame-fromFrame+1) / double(toFrame-fromFrame+1));
|
||||
}
|
||||
}
|
||||
@ -71,8 +72,7 @@ Palette* create_palette_from_sprite(
|
||||
palette,
|
||||
// Transparent color is needed if we have transparent layers
|
||||
(sprite->backgroundLayer() &&
|
||||
sprite->allLayersCount() == 1 ? -1: sprite->transparentColor()),
|
||||
delegate);
|
||||
sprite->allLayersCount() == 1 ? -1: sprite->transparentColor()));
|
||||
|
||||
return palette;
|
||||
}
|
||||
@ -86,7 +86,7 @@ Image* convert_pixel_format(
|
||||
const Palette* palette,
|
||||
bool is_background,
|
||||
color_t new_mask_color,
|
||||
bool* stopFlag)
|
||||
TaskDelegate* delegate)
|
||||
{
|
||||
if (!new_image)
|
||||
new_image = Image::create(pixelFormat, image->width(), image->height());
|
||||
@ -100,12 +100,12 @@ Image* convert_pixel_format(
|
||||
switch (ditheringAlgorithm) {
|
||||
case DitheringAlgorithm::OldOrdered: {
|
||||
OrderedDither dither;
|
||||
dither_rgb_image_to_indexed(dither, matrix, image, new_image, 0, 0, rgbmap, palette, stopFlag);
|
||||
dither_rgb_image_to_indexed(dither, matrix, image, new_image, 0, 0, rgbmap, palette, delegate);
|
||||
break;
|
||||
}
|
||||
case DitheringAlgorithm::Ordered: {
|
||||
OrderedDither2 dither;
|
||||
dither_rgb_image_to_indexed(dither, matrix, image, new_image, 0, 0, rgbmap, palette, stopFlag);
|
||||
dither_rgb_image_to_indexed(dither, matrix, image, new_image, 0, 0, rgbmap, palette, delegate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -388,8 +388,7 @@ void PaletteOptimizer::feedWithRgbaColor(color_t color)
|
||||
m_histogram.addSamples(color, 1);
|
||||
}
|
||||
|
||||
void PaletteOptimizer::calculate(Palette* palette, int maskIndex,
|
||||
PaletteOptimizerDelegate* delegate)
|
||||
void PaletteOptimizer::calculate(Palette* palette, int maskIndex)
|
||||
{
|
||||
bool addMask;
|
||||
|
||||
|
@ -23,21 +23,13 @@ namespace doc {
|
||||
}
|
||||
|
||||
namespace render {
|
||||
|
||||
class PaletteOptimizerDelegate {
|
||||
public:
|
||||
virtual ~PaletteOptimizerDelegate() { }
|
||||
virtual void onPaletteOptimizerProgress(double progress) = 0;
|
||||
virtual bool onPaletteOptimizerContinue() = 0;
|
||||
};
|
||||
class TaskDelegate;
|
||||
|
||||
class PaletteOptimizer {
|
||||
public:
|
||||
void feedWithImage(doc::Image* image, bool withAlpha);
|
||||
void feedWithRgbaColor(doc::color_t color);
|
||||
void calculate(doc::Palette* palette,
|
||||
int maskIndex,
|
||||
render::PaletteOptimizerDelegate* delegate);
|
||||
void calculate(doc::Palette* palette, int maskIndex);
|
||||
|
||||
private:
|
||||
render::ColorHistogram<5, 6, 5, 5> m_histogram;
|
||||
@ -50,7 +42,7 @@ namespace render {
|
||||
const doc::frame_t toFrame,
|
||||
const bool withAlpha,
|
||||
doc::Palette* newPalette, // Can be NULL to create a new palette
|
||||
render::PaletteOptimizerDelegate* delegate);
|
||||
TaskDelegate* delegate);
|
||||
|
||||
// Changes the image pixel format. The dithering method is used only
|
||||
// when you want to convert from RGB to Indexed.
|
||||
@ -63,7 +55,7 @@ namespace render {
|
||||
const doc::Palette* palette,
|
||||
bool is_background,
|
||||
doc::color_t new_mask_color,
|
||||
bool* stopFlag = nullptr);
|
||||
TaskDelegate* delegate = nullptr);
|
||||
|
||||
} // namespace render
|
||||
|
||||
|
22
src/render/task_delegate.h
Normal file
22
src/render/task_delegate.h
Normal file
@ -0,0 +1,22 @@
|
||||
// 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.
|
||||
|
||||
#ifndef RENDER_TASK_DELEGATE_H_INCLUDED
|
||||
#define RENDER_TASK_DELEGATE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
namespace render {
|
||||
|
||||
class TaskDelegate {
|
||||
public:
|
||||
virtual ~TaskDelegate() { }
|
||||
virtual void notifyTaskProgress(double progress) = 0;
|
||||
virtual bool continueTask() = 0;
|
||||
};
|
||||
|
||||
} // namespace render
|
||||
|
||||
#endif // RENDER_TASK_H_INCLUDED
|
Loading…
x
Reference in New Issue
Block a user