~ubuntu-branches/ubuntu/intrepid/digikam/intrepid

« back to all changes in this revision

Viewing changes to digikam/imageplugins/filmgrain/filmgrain.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2008-07-17 20:25:39 UTC
  • mfrom: (1.3.2 upstream) (37 hardy)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: james.westby@ubuntu.com-20080717202539-1bw3w3nrsso7yj4z
* New upstream release
  - digiKam 0.9.4 Release Plan (KDE3) ~ 13 July 08 (Closes: #490144)
* DEB_CONFIGURE_EXTRA_FLAGS := --without-included-sqlite3
* Debhelper compatibility level V7
* Install pixmaps in debian/*.install
* Add debian/digikam.lintian-overrides

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ============================================================
 
2
 *
 
3
 * This file is a part of digiKam project
 
4
 * http://www.digikam.org
 
5
 *
 
6
 * Date        : 2005-05-25
 
7
 * Description : FilmGrain threaded image filter.
 
8
 * 
 
9
 * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
 
10
 * Copyright (C) 2005-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
 
11
 * 
 
12
 * This program is free software; you can redistribute it
 
13
 * and/or modify it under the terms of the GNU General
 
14
 * Public License as published by the Free Software Foundation;
 
15
 * either version 2, or (at your option)
 
16
 * any later version.
 
17
 * 
 
18
 * This program is distributed in the hope that it will be useful,
 
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
 * GNU General Public License for more details.
 
22
 * 
 
23
 * ============================================================ */
 
24
 
 
25
// C++ includes. 
 
26
 
 
27
#include <cmath>
 
28
#include <cstdlib>
 
29
 
 
30
// Qt includes.
 
31
 
 
32
#include <qdatetime.h> 
 
33
 
 
34
// Local includes.
 
35
 
 
36
#include "ddebug.h"
 
37
#include "dimg.h"
 
38
#include "dimggaussianblur.h"
 
39
#include "imagecurves.h"
 
40
#include "imagehistogram.h"
 
41
#include "dimgimagefilters.h"
 
42
#include "filmgrain.h"
 
43
 
 
44
namespace DigikamFilmGrainImagesPlugin
 
45
{
 
46
 
 
47
FilmGrain::FilmGrain(Digikam::DImg *orgImage, QObject *parent, int sensibility)
 
48
         : Digikam::DImgThreadedFilter(orgImage, parent, "FilmGrain")
 
49
{
 
50
    m_sensibility = sensibility;
 
51
    initFilter();
 
52
}
 
53
 
 
54
void FilmGrain::filterImage(void)
 
55
{
 
56
    filmgrainImage(&m_orgImage, m_sensibility);
 
57
}
 
58
 
 
59
// This method is based on the Simulate Film grain tutorial from GimpGuru.org web site 
 
60
// available at this url : http://www.gimpguru.org/Tutorials/FilmGrain
 
61
 
 
62
void FilmGrain::filmgrainImage(Digikam::DImg *orgImage, int Sensibility)
 
63
{
 
64
    // Sensibility: 800..6400
 
65
 
 
66
    if (Sensibility <= 0) return;
 
67
 
 
68
    int Width = orgImage->width();
 
69
    int Height = orgImage->height();
 
70
    int bytesDepth = orgImage->bytesDepth();
 
71
    bool sixteenBit = orgImage->sixteenBit();
 
72
    uchar* data = orgImage->bits();
 
73
 
 
74
    Digikam::DImg grain(Width, Height, sixteenBit);      // Grain blured without curves adjustment.
 
75
    Digikam::DImg mask(Width, Height, sixteenBit);       // Grain mask with curves adjustment.
 
76
    uchar* pGrainBits = grain.bits();
 
77
    uchar* pMaskBits  = mask.bits();
 
78
    uchar* pOutBits = m_destImage.bits(); // Destination image with merged grain mask and original.
 
79
 
 
80
    int Noise, Shade, nRand, component, progress;
 
81
    uchar *ptr;
 
82
    Digikam::DColor blendData, grainData, maskData, outData;
 
83
 
 
84
    if (sixteenBit)
 
85
        Noise = (Sensibility / 10 + 1) * 256 - 1;
 
86
    else
 
87
        Noise = Sensibility / 10;
 
88
 
 
89
    // This value controls the shading pixel effect between original image and grain mask.
 
90
    if (sixteenBit)
 
91
        Shade = (52 + 1) * 256 - 1;
 
92
    else
 
93
        Shade = 52;
 
94
 
 
95
    QDateTime dt = QDateTime::currentDateTime();
 
96
    QDateTime Y2000( QDate(2000, 1, 1), QTime(0, 0, 0) );
 
97
    uint seed = (uint) dt.secsTo(Y2000);
 
98
 
 
99
    // Make gray grain mask.
 
100
 
 
101
    grainData.setSixteenBit(sixteenBit);
 
102
 
 
103
    for (int x = 0; !m_cancel && x < Width; x++)
 
104
    {
 
105
        for (int y = 0; !m_cancel && y < Height; y++)
 
106
        {
 
107
            ptr = pGrainBits + x*bytesDepth + (y*Width*bytesDepth);
 
108
 
 
109
            nRand = (rand_r(&seed) % Noise) - (Noise / 2);
 
110
            if (sixteenBit)
 
111
                component = CLAMP(32768 + nRand, 0, 65535);
 
112
            else
 
113
                component = CLAMP(128 + nRand, 0, 255);
 
114
 
 
115
            grainData.setRed  (component);
 
116
            grainData.setGreen(component);
 
117
            grainData.setBlue (component);
 
118
            grainData.setAlpha(0);
 
119
 
 
120
            grainData.setPixel(ptr);
 
121
        }
 
122
 
 
123
        // Update progress bar in dialog.
 
124
        progress = (int) (((double)x * 25.0) / Width);
 
125
 
 
126
        if (progress%5 == 0)
 
127
            postProgress( progress );
 
128
    }
 
129
 
 
130
    // Smooth grain mask using gaussian blur with radius 1.
 
131
    Digikam::DImgGaussianBlur(this, grain, grain, 25, 30, 1);
 
132
 
 
133
    // Normally, film grain tends to be most noticeable in the midtones, and much less 
 
134
    // so in the shadows and highlights. Adjust histogram curve to adjust grain like this.
 
135
 
 
136
    Digikam::ImageCurves *grainCurves = new Digikam::ImageCurves(sixteenBit);
 
137
 
 
138
    // We modify only global luminosity of the grain.
 
139
    if (sixteenBit)
 
140
    {
 
141
        grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0,  QPoint(0,     0));
 
142
        grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 8,  QPoint(32768, 32768));
 
143
        grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, QPoint(65535, 0));
 
144
    }
 
145
    else
 
146
    {
 
147
        grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0,  QPoint(0,   0));
 
148
        grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 8,  QPoint(128, 128));
 
149
        grainCurves->setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, QPoint(255, 0));
 
150
    }
 
151
 
 
152
    // Calculate curves and lut to apply on grain.
 
153
    grainCurves->curvesCalculateCurve(Digikam::ImageHistogram::ValueChannel);
 
154
    grainCurves->curvesLutSetup(Digikam::ImageHistogram::AlphaChannel);
 
155
    grainCurves->curvesLutProcess(pGrainBits, pMaskBits, Width, Height);
 
156
 
 
157
    grain.reset();
 
158
    delete grainCurves;
 
159
 
 
160
    // Update progress bar in dialog.
 
161
    postProgress( 40 );
 
162
 
 
163
    // Merge src image with grain using shade coefficient.
 
164
 
 
165
    int alpha;
 
166
    // get composer for default blending
 
167
    Digikam::DColorComposer *composer = Digikam::DColorComposer::getComposer(Digikam::DColorComposer::PorterDuffNone);
 
168
 
 
169
    for (int x = 0; !m_cancel && x < Width; x++)
 
170
    {
 
171
        for (int y = 0; !m_cancel && y < Height; y++)
 
172
        {
 
173
            int offset = x*bytesDepth + (y*Width*bytesDepth);
 
174
 
 
175
            // read color from orig image
 
176
            blendData.setColor(data + offset, sixteenBit);
 
177
            // read color from mask
 
178
            maskData.setColor(pMaskBits + offset, sixteenBit);
 
179
            // set shade as alpha value - it will be used as source alpha when blending
 
180
            maskData.setAlpha(Shade);
 
181
 
 
182
            // compose, write result to blendData.
 
183
            // Preserve alpha, do not blend it (taken from old algorithm - correct?)
 
184
            alpha = blendData.alpha();
 
185
            composer->compose(blendData, maskData);
 
186
            blendData.setAlpha(alpha);
 
187
 
 
188
            // write to destination
 
189
            blendData.setPixel(pOutBits + offset);
 
190
        }
 
191
 
 
192
        // Update progress bar in dialog.
 
193
        progress = (int) (50.0 + ((double)x * 50.0) / Width);
 
194
 
 
195
        if (progress%5 == 0)
 
196
           postProgress( progress );
 
197
    }
 
198
 
 
199
    delete composer;
 
200
}
 
201
 
 
202
}  // NameSpace DigikamFilmGrainImagesPlugin