~ubuntu-branches/ubuntu/precise/gwenview/precise-proposed

« back to all changes in this revision

Viewing changes to lib/redeyereduction/redeyereductionimageoperation.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2011-12-15 14:17:54 UTC
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: package-import@ubuntu.com-20111215141754-z043hyx69dulbggf
Tags: upstream-4.7.90
Import upstream version 4.7.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
 
1
// vim: set tabstop=4 shiftwidth=4 expandtab:
2
2
/*
3
3
Gwenview: an image viewer
4
4
Copyright 2007 Aurélien Gâteau <agateau@kde.org>
39
39
#include "document/abstractdocumenteditor.h"
40
40
#include "paintutils.h"
41
41
 
42
 
namespace Gwenview {
43
 
 
44
 
 
45
 
class RedEyeReductionJob : public ThreadedDocumentJob {
 
42
namespace Gwenview
 
43
{
 
44
 
 
45
class RedEyeReductionJob : public ThreadedDocumentJob
 
46
{
46
47
public:
47
 
        RedEyeReductionJob(const QRectF& rectF)
48
 
        : mRectF(rectF)
49
 
        {}
 
48
    RedEyeReductionJob(const QRectF& rectF)
 
49
        : mRectF(rectF)
 
50
    {}
50
51
 
51
 
        void threadedStart() {
52
 
                if (!checkDocumentEditor()) {
53
 
                        return;
54
 
                }
55
 
                QImage img = document()->image();
56
 
                RedEyeReductionImageOperation::apply(&img, mRectF);
57
 
                document()->editor()->setImage(img);
58
 
                setError(NoError);
59
 
        }
 
52
    void threadedStart()
 
53
    {
 
54
        if (!checkDocumentEditor()) {
 
55
            return;
 
56
        }
 
57
        QImage img = document()->image();
 
58
        RedEyeReductionImageOperation::apply(&img, mRectF);
 
59
        document()->editor()->setImage(img);
 
60
        setError(NoError);
 
61
    }
60
62
 
61
63
private:
62
 
        QRectF mRectF;
 
64
    QRectF mRectF;
63
65
};
64
66
 
65
 
 
66
67
struct RedEyeReductionImageOperationPrivate {
67
 
        QRectF mRectF;
68
 
        QImage mOriginalImage;
 
68
    QRectF mRectF;
 
69
    QImage mOriginalImage;
69
70
};
70
71
 
71
 
 
72
72
RedEyeReductionImageOperation::RedEyeReductionImageOperation(const QRectF& rectF)
73
 
: d(new RedEyeReductionImageOperationPrivate) {
74
 
        d->mRectF = rectF;
75
 
        setText(i18n("RedEyeReduction"));
76
 
}
77
 
 
78
 
 
79
 
RedEyeReductionImageOperation::~RedEyeReductionImageOperation() {
80
 
        delete d;
81
 
}
82
 
 
83
 
 
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));
89
 
}
90
 
 
91
 
 
92
 
void RedEyeReductionImageOperation::undo() {
93
 
        if (!document()->editor()) {
94
 
                kWarning() << "!document->editor()";
95
 
                return;
96
 
        }
97
 
        QImage img = document()->image();
98
 
        {
99
 
                QPainter painter(&img);
100
 
                painter.setCompositionMode(QPainter::CompositionMode_Source);
101
 
                QRect rect = PaintUtils::containingRect(d->mRectF);
102
 
                painter.drawImage(rect.topLeft(), d->mOriginalImage);
103
 
        }
104
 
        document()->editor()->setImage(img);
105
 
}
106
 
 
 
73
: d(new RedEyeReductionImageOperationPrivate)
 
74
{
 
75
    d->mRectF = rectF;
 
76
    setText(i18n("RedEyeReduction"));
 
77
}
 
78
 
 
79
RedEyeReductionImageOperation::~RedEyeReductionImageOperation()
 
80
{
 
81
    delete d;
 
82
}
 
83
 
 
84
void RedEyeReductionImageOperation::redo()
 
85
{
 
86
    QImage img = document()->image();
 
87
    QRect rect = PaintUtils::containingRect(d->mRectF);
 
88
    d->mOriginalImage = img.copy(rect);
 
89
    redoAsDocumentJob(new RedEyeReductionJob(d->mRectF));
 
90
}
 
91
 
 
92
void RedEyeReductionImageOperation::undo()
 
93
{
 
94
    if (!document()->editor()) {
 
95
        kWarning() << "!document->editor()";
 
96
        return;
 
97
    }
 
98
    QImage img = document()->image();
 
99
    {
 
100
        QPainter painter(&img);
 
101
        painter.setCompositionMode(QPainter::CompositionMode_Source);
 
102
        QRect rect = PaintUtils::containingRect(d->mRectF);
 
103
        painter.drawImage(rect.topLeft(), d->mOriginalImage);
 
104
    }
 
105
    document()->editor()->setImage(img);
 
106
}
107
107
 
108
108
/**
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
111
111
 */
112
 
inline qreal computeRedEyeAlpha(const QColor& src) {
113
 
        int hue, sat, value;
114
 
        src.getHsv(&hue, &sat, &value);
115
 
 
116
 
        qreal axs = 1.0;
117
 
        if (hue > 259) {
118
 
                static const Ramp ramp(30, 35, 0., 1.);
119
 
                axs = ramp(sat);
120
 
        } else {
121
 
                const Ramp ramp(hue * 2 + 29, hue * 2 + 40, 0., 1.);
122
 
                axs = ramp(sat);
123
 
        }
124
 
 
125
 
        return qBound(0., double(src.alphaF()) * axs, 1.);
126
 
}
127
 
 
128
 
 
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.);
135
 
 
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;
139
 
 
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)) {
144
 
                                continue;
145
 
                        }
146
 
 
147
 
                        const QColor src(*ptr);
148
 
                        alpha *= computeRedEyeAlpha(src);
149
 
                        int r = src.red();
150
 
                        int g = src.green();
151
 
                        int b = src.blue();
152
 
                        QColor dst;
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));
157
 
                        *ptr = dst.rgba();
158
 
                }
159
 
        }
160
 
}
161
 
 
 
112
inline qreal computeRedEyeAlpha(const QColor& src)
 
113
{
 
114
    int hue, sat, value;
 
115
    src.getHsv(&hue, &sat, &value);
 
116
 
 
117
    qreal axs = 1.0;
 
118
    if (hue > 259) {
 
119
        static const Ramp ramp(30, 35, 0., 1.);
 
120
        axs = ramp(sat);
 
121
    } else {
 
122
        const Ramp ramp(hue * 2 + 29, hue * 2 + 40, 0., 1.);
 
123
        axs = ramp(sat);
 
124
    }
 
125
 
 
126
    return qBound(0., double(src.alphaF()) * axs, 1.);
 
127
}
 
128
 
 
129
void RedEyeReductionImageOperation::apply(QImage* img, const QRectF& rectF)
 
130
{
 
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.);
 
136
 
 
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;
 
140
 
 
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)) {
 
145
                continue;
 
146
            }
 
147
 
 
148
            const QColor src(*ptr);
 
149
            alpha *= computeRedEyeAlpha(src);
 
150
            int r = src.red();
 
151
            int g = src.green();
 
152
            int b = src.blue();
 
153
            QColor dst;
 
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));
 
158
            *ptr = dst.rgba();
 
159
        }
 
160
    }
 
161
}
162
162
 
163
163
} // namespace