39
39
#include "document/abstractdocumenteditor.h"
40
40
#include "paintutils.h"
45
class RedEyeReductionJob : public ThreadedDocumentJob {
45
class RedEyeReductionJob : public ThreadedDocumentJob
47
RedEyeReductionJob(const QRectF& rectF)
48
RedEyeReductionJob(const QRectF& rectF)
51
void threadedStart() {
52
if (!checkDocumentEditor()) {
55
QImage img = document()->image();
56
RedEyeReductionImageOperation::apply(&img, mRectF);
57
document()->editor()->setImage(img);
54
if (!checkDocumentEditor()) {
57
QImage img = document()->image();
58
RedEyeReductionImageOperation::apply(&img, mRectF);
59
document()->editor()->setImage(img);
66
67
struct RedEyeReductionImageOperationPrivate {
68
QImage mOriginalImage;
69
QImage mOriginalImage;
72
72
RedEyeReductionImageOperation::RedEyeReductionImageOperation(const QRectF& rectF)
73
: d(new RedEyeReductionImageOperationPrivate) {
75
setText(i18n("RedEyeReduction"));
79
RedEyeReductionImageOperation::~RedEyeReductionImageOperation() {
84
void RedEyeReductionImageOperation::redo() {
85
QImage img = document()->image();
86
QRect rect = PaintUtils::containingRect(d->mRectF);
87
d->mOriginalImage = img.copy(rect);
88
redoAsDocumentJob(new RedEyeReductionJob(d->mRectF));
92
void RedEyeReductionImageOperation::undo() {
93
if (!document()->editor()) {
94
kWarning() << "!document->editor()";
97
QImage img = document()->image();
99
QPainter painter(&img);
100
painter.setCompositionMode(QPainter::CompositionMode_Source);
101
QRect rect = PaintUtils::containingRect(d->mRectF);
102
painter.drawImage(rect.topLeft(), d->mOriginalImage);
104
document()->editor()->setImage(img);
73
: d(new RedEyeReductionImageOperationPrivate)
76
setText(i18n("RedEyeReduction"));
79
RedEyeReductionImageOperation::~RedEyeReductionImageOperation()
84
void RedEyeReductionImageOperation::redo()
86
QImage img = document()->image();
87
QRect rect = PaintUtils::containingRect(d->mRectF);
88
d->mOriginalImage = img.copy(rect);
89
redoAsDocumentJob(new RedEyeReductionJob(d->mRectF));
92
void RedEyeReductionImageOperation::undo()
94
if (!document()->editor()) {
95
kWarning() << "!document->editor()";
98
QImage img = document()->image();
100
QPainter painter(&img);
101
painter.setCompositionMode(QPainter::CompositionMode_Source);
102
QRect rect = PaintUtils::containingRect(d->mRectF);
103
painter.drawImage(rect.topLeft(), d->mOriginalImage);
105
document()->editor()->setImage(img);
109
109
* This code is inspired from code found in a Paint.net plugin:
110
110
* http://paintdotnet.forumer.com/viewtopic.php?f=27&t=26193&p=205954&hilit=red+eye#p205954
112
inline qreal computeRedEyeAlpha(const QColor& src) {
114
src.getHsv(&hue, &sat, &value);
118
static const Ramp ramp(30, 35, 0., 1.);
121
const Ramp ramp(hue * 2 + 29, hue * 2 + 40, 0., 1.);
125
return qBound(0., double(src.alphaF()) * axs, 1.);
129
void RedEyeReductionImageOperation::apply(QImage* img, const QRectF& rectF) {
130
const QRect rect = PaintUtils::containingRect(rectF);
131
const qreal radius = rectF.width() / 2;
132
const qreal centerX = rectF.x() + radius;
133
const qreal centerY = rectF.y() + radius;
134
const Ramp radiusRamp(qMin(double(radius * 0.7), double(radius - 1)), radius, 1., 0.);
136
uchar* line = img->scanLine(rect.top()) + rect.left() * 4;
137
for (int y = rect.top(); y < rect.bottom(); ++y, line += img->bytesPerLine()) {
138
QRgb* ptr = (QRgb*)line;
140
for (int x = rect.left(); x < rect.right(); ++x, ++ptr) {
141
const qreal currentRadius = sqrt(pow(y - centerY, 2) + pow(x - centerX, 2));
142
qreal alpha = radiusRamp(currentRadius);
143
if (qFuzzyCompare(alpha, 0)) {
147
const QColor src(*ptr);
148
alpha *= computeRedEyeAlpha(src);
153
// Replace red with green, and blend according to alpha
154
dst.setRed (int((1 - alpha) * r + alpha * g));
155
dst.setGreen(int((1 - alpha) * g + alpha * g));
156
dst.setBlue (int((1 - alpha) * b + alpha * b));
112
inline qreal computeRedEyeAlpha(const QColor& src)
115
src.getHsv(&hue, &sat, &value);
119
static const Ramp ramp(30, 35, 0., 1.);
122
const Ramp ramp(hue * 2 + 29, hue * 2 + 40, 0., 1.);
126
return qBound(0., double(src.alphaF()) * axs, 1.);
129
void RedEyeReductionImageOperation::apply(QImage* img, const QRectF& rectF)
131
const QRect rect = PaintUtils::containingRect(rectF);
132
const qreal radius = rectF.width() / 2;
133
const qreal centerX = rectF.x() + radius;
134
const qreal centerY = rectF.y() + radius;
135
const Ramp radiusRamp(qMin(double(radius * 0.7), double(radius - 1)), radius, 1., 0.);
137
uchar* line = img->scanLine(rect.top()) + rect.left() * 4;
138
for (int y = rect.top(); y < rect.bottom(); ++y, line += img->bytesPerLine()) {
139
QRgb* ptr = (QRgb*)line;
141
for (int x = rect.left(); x < rect.right(); ++x, ++ptr) {
142
const qreal currentRadius = sqrt(pow(y - centerY, 2) + pow(x - centerX, 2));
143
qreal alpha = radiusRamp(currentRadius);
144
if (qFuzzyCompare(alpha, 0)) {
148
const QColor src(*ptr);
149
alpha *= computeRedEyeAlpha(src);
154
// Replace red with green, and blend according to alpha
155
dst.setRed(int((1 - alpha) * r + alpha * g));
156
dst.setGreen(int((1 - alpha) * g + alpha * g));
157
dst.setBlue(int((1 - alpha) * b + alpha * b));