~cosme/ubuntu/precise/freeimage/freeimage-3.15.1

« back to all changes in this revision

Viewing changes to Source/OpenEXR/IlmImf/ImfRgbaYca.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Cosme Domínguez Díaz
  • Date: 2010-07-20 13:42:15 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100720134215-xt1454zaedv3b604
Tags: 3.13.1-0ubuntu1
* New upstream release. Closes: (LP: #607800)
 - Updated debian/freeimage-get-orig-source script.
 - Removing no longer necessary debian/patches/* and
   the patch system in debian/rules.
 - Updated debian/rules to work with the new Makefiles.
 - Drop from -O3 to -O2 and use lzma compression saves
   ~10 MB of free space. 
* lintian stuff
 - fixed debhelper-but-no-misc-depends
 - fixed ldconfig-symlink-missing-for-shlib

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//////////////////////////////////////////////////////////////////////////////
2
 
//
3
 
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucasfilm
4
 
// Entertainment Company Ltd.  Portions contributed and copyright held by
5
 
// others as indicated.  All rights reserved.
6
 
//
7
 
// Redistribution and use in source and binary forms, with or without
8
 
// modification, are permitted provided that the following conditions are
9
 
// met:
10
 
//
11
 
//     * Redistributions of source code must retain the above
12
 
//       copyright notice, this list of conditions and the following
13
 
//       disclaimer.
14
 
//
15
 
//     * Redistributions in binary form must reproduce the above
16
 
//       copyright notice, this list of conditions and the following
17
 
//       disclaimer in the documentation and/or other materials provided with
18
 
//       the distribution.
19
 
//
20
 
//     * Neither the name of Industrial Light & Magic nor the names of
21
 
//       any other contributors to this software may be used to endorse or
22
 
//       promote products derived from this software without specific prior
23
 
//       written permission.
24
 
//
25
 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
26
 
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
27
 
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28
 
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29
 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30
 
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31
 
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32
 
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33
 
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34
 
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35
 
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 
//
37
 
//////////////////////////////////////////////////////////////////////////////
38
 
 
39
 
//-----------------------------------------------------------------------------
40
 
//
41
 
//      Conversion between RGBA and YCA data.
42
 
//
43
 
//-----------------------------------------------------------------------------
44
 
 
45
 
#include <ImfRgbaYca.h>
46
 
#include <assert.h>
47
 
#include <algorithm>
48
 
 
49
 
using namespace Imath;
50
 
using namespace std;
51
 
 
52
 
namespace Imf {
53
 
namespace RgbaYca {
54
 
 
55
 
 
56
 
V3f
57
 
computeYw (const Chromaticities &cr)
58
 
{
59
 
    M44f m = RGBtoXYZ (cr, 1);
60
 
    return V3f (m[0][1], m[1][1], m[2][1]) / (m[0][1] + m[1][1] + m[2][1]);
61
 
}
62
 
 
63
 
 
64
 
void
65
 
RGBAtoYCA (const V3f &yw,
66
 
           int n,
67
 
           bool aIsValid,
68
 
           const Rgba rgbaIn[/*n*/],
69
 
           Rgba ycaOut[/*n*/])
70
 
{
71
 
    for (int i = 0; i < n; ++i)
72
 
    {
73
 
        Rgba in = rgbaIn[i];
74
 
        Rgba &out = ycaOut[i];
75
 
 
76
 
        //
77
 
        // Conversion to YCA and subsequent chroma subsampling
78
 
        // work only if R, G and B are finite and non-negative.
79
 
        //
80
 
 
81
 
        if (!in.r.isFinite() || in.r < 0)
82
 
            in.r = 0;
83
 
 
84
 
        if (!in.g.isFinite() || in.g < 0)
85
 
            in.g = 0;
86
 
 
87
 
        if (!in.b.isFinite() || in.b < 0)
88
 
            in.b = 0;
89
 
 
90
 
        if (in.r == in.g && in.g == in.b)
91
 
        {
92
 
            //
93
 
            // Special case -- R, G and B are equal. To avoid rounding
94
 
            // errors, we explicitly set the output luminance channel
95
 
            // to G, and the chroma channels to 0.
96
 
            //
97
 
            // The special cases here and in YCAtoRGBA() ensure that
98
 
            // converting black-and white images from RGBA to YCA and
99
 
            // back is lossless.
100
 
            //
101
 
 
102
 
            out.r = 0;
103
 
            out.g = in.g;
104
 
            out.b = 0;
105
 
        }
106
 
        else
107
 
        {
108
 
            out.g = in.r * yw.x + in.g * yw.y + in.b * yw.z;
109
 
 
110
 
            float Y = out.g;
111
 
 
112
 
            if (abs (in.r - Y) < HALF_MAX * Y)
113
 
                out.r = (in.r - Y) / Y;
114
 
            else
115
 
                out.r = 0;
116
 
 
117
 
            if (abs (in.b - Y) < HALF_MAX * Y)
118
 
                out.b = (in.b - Y) / Y;
119
 
            else
120
 
                out.b = 0;
121
 
        }
122
 
 
123
 
        if (aIsValid)
124
 
            out.a = in.a;
125
 
        else
126
 
            out.a = 1;
127
 
    }
128
 
}
129
 
 
130
 
 
131
 
void
132
 
decimateChromaHoriz (int n,
133
 
                     const Rgba ycaIn[/*n+N-1*/],
134
 
                     Rgba ycaOut[/*n*/])
135
 
{
136
 
    #ifdef DEBUG
137
 
        assert (ycaIn != ycaOut);
138
 
    #endif
139
 
 
140
 
    int begin = N2;
141
 
    int end = begin + n;
142
 
 
143
 
    for (int i = begin, j = 0; i < end; ++i, ++j)
144
 
    {
145
 
        if ((j & 1) == 0)
146
 
        {
147
 
            ycaOut[j].r = ycaIn[i - 13].r *  0.001064 +
148
 
                          ycaIn[i - 11].r * -0.003771 +
149
 
                          ycaIn[i -  9].r *  0.009801 +
150
 
                          ycaIn[i -  7].r * -0.021586 +
151
 
                          ycaIn[i -  5].r *  0.043978 +
152
 
                          ycaIn[i -  3].r * -0.093067 +
153
 
                          ycaIn[i -  1].r *  0.313659 +
154
 
                          ycaIn[i     ].r *  0.499846 +
155
 
                          ycaIn[i +  1].r *  0.313659 +
156
 
                          ycaIn[i +  3].r * -0.093067 +
157
 
                          ycaIn[i +  5].r *  0.043978 +
158
 
                          ycaIn[i +  7].r * -0.021586 +
159
 
                          ycaIn[i +  9].r *  0.009801 +
160
 
                          ycaIn[i + 11].r * -0.003771 +
161
 
                          ycaIn[i + 13].r *  0.001064;
162
 
 
163
 
            ycaOut[j].b = ycaIn[i - 13].b *  0.001064 +
164
 
                          ycaIn[i - 11].b * -0.003771 +
165
 
                          ycaIn[i -  9].b *  0.009801 +
166
 
                          ycaIn[i -  7].b * -0.021586 +
167
 
                          ycaIn[i -  5].b *  0.043978 +
168
 
                          ycaIn[i -  3].b * -0.093067 +
169
 
                          ycaIn[i -  1].b *  0.313659 +
170
 
                          ycaIn[i     ].b *  0.499846 +
171
 
                          ycaIn[i +  1].b *  0.313659 +
172
 
                          ycaIn[i +  3].b * -0.093067 +
173
 
                          ycaIn[i +  5].b *  0.043978 +
174
 
                          ycaIn[i +  7].b * -0.021586 +
175
 
                          ycaIn[i +  9].b *  0.009801 +
176
 
                          ycaIn[i + 11].b * -0.003771 +
177
 
                          ycaIn[i + 13].b *  0.001064;
178
 
        }
179
 
 
180
 
        ycaOut[j].g = ycaIn[i].g;
181
 
        ycaOut[j].a = ycaIn[i].a;
182
 
    }
183
 
}
184
 
 
185
 
 
186
 
void
187
 
decimateChromaVert (int n,
188
 
                    const Rgba * const ycaIn[N],
189
 
                    Rgba ycaOut[/*n*/])
190
 
{
191
 
    for (int i = 0; i < n; ++i)
192
 
    {
193
 
        if ((i & 1) == 0)
194
 
        {
195
 
            ycaOut[i].r = ycaIn[ 0][i].r *  0.001064 +
196
 
                          ycaIn[ 2][i].r * -0.003771 +
197
 
                          ycaIn[ 4][i].r *  0.009801 +
198
 
                          ycaIn[ 6][i].r * -0.021586 +
199
 
                          ycaIn[ 8][i].r *  0.043978 +
200
 
                          ycaIn[10][i].r * -0.093067 +
201
 
                          ycaIn[12][i].r *  0.313659 +
202
 
                          ycaIn[13][i].r *  0.499846 +
203
 
                          ycaIn[14][i].r *  0.313659 +
204
 
                          ycaIn[16][i].r * -0.093067 +
205
 
                          ycaIn[18][i].r *  0.043978 +
206
 
                          ycaIn[20][i].r * -0.021586 +
207
 
                          ycaIn[22][i].r *  0.009801 +
208
 
                          ycaIn[24][i].r * -0.003771 +
209
 
                          ycaIn[26][i].r *  0.001064;
210
 
 
211
 
            ycaOut[i].b = ycaIn[ 0][i].b *  0.001064 +
212
 
                          ycaIn[ 2][i].b * -0.003771 +
213
 
                          ycaIn[ 4][i].b *  0.009801 +
214
 
                          ycaIn[ 6][i].b * -0.021586 +
215
 
                          ycaIn[ 8][i].b *  0.043978 +
216
 
                          ycaIn[10][i].b * -0.093067 +
217
 
                          ycaIn[12][i].b *  0.313659 +
218
 
                          ycaIn[13][i].b *  0.499846 +
219
 
                          ycaIn[14][i].b *  0.313659 +
220
 
                          ycaIn[16][i].b * -0.093067 +
221
 
                          ycaIn[18][i].b *  0.043978 +
222
 
                          ycaIn[20][i].b * -0.021586 +
223
 
                          ycaIn[22][i].b *  0.009801 +
224
 
                          ycaIn[24][i].b * -0.003771 +
225
 
                          ycaIn[26][i].b *  0.001064;
226
 
        }
227
 
 
228
 
        ycaOut[i].g = ycaIn[13][i].g;
229
 
        ycaOut[i].a = ycaIn[13][i].a;
230
 
    }
231
 
}
232
 
 
233
 
 
234
 
void
235
 
roundYCA (int n,
236
 
          unsigned int roundY,
237
 
          unsigned int roundC,
238
 
          const Rgba ycaIn[/*n*/],
239
 
          Rgba ycaOut[/*n*/])
240
 
{
241
 
    for (int i = 0; i < n; ++i)
242
 
    {
243
 
        ycaOut[i].g = ycaIn[i].g.round (roundY);
244
 
        ycaOut[i].a = ycaIn[i].a;
245
 
 
246
 
        if ((i & 1) == 0)
247
 
        {
248
 
            ycaOut[i].r = ycaIn[i].r.round (roundC);
249
 
            ycaOut[i].b = ycaIn[i].b.round (roundC);
250
 
        }
251
 
    }
252
 
}
253
 
 
254
 
 
255
 
void
256
 
reconstructChromaHoriz (int n,
257
 
                        const Rgba ycaIn[/*n+N-1*/],
258
 
                        Rgba ycaOut[/*n*/])
259
 
{
260
 
    #ifdef DEBUG
261
 
        assert (ycaIn != ycaOut);
262
 
    #endif
263
 
 
264
 
    int begin = N2;
265
 
    int end = begin + n;
266
 
 
267
 
    for (int i = begin, j = 0; i < end; ++i, ++j)
268
 
    {
269
 
        if (j & 1)
270
 
        {
271
 
            ycaOut[j].r = ycaIn[i - 13].r *  0.002128 +
272
 
                          ycaIn[i - 11].r * -0.007540 +
273
 
                          ycaIn[i -  9].r *  0.019597 +
274
 
                          ycaIn[i -  7].r * -0.043159 +
275
 
                          ycaIn[i -  5].r *  0.087929 +
276
 
                          ycaIn[i -  3].r * -0.186077 +
277
 
                          ycaIn[i -  1].r *  0.627123 +
278
 
                          ycaIn[i +  1].r *  0.627123 +
279
 
                          ycaIn[i +  3].r * -0.186077 +
280
 
                          ycaIn[i +  5].r *  0.087929 +
281
 
                          ycaIn[i +  7].r * -0.043159 +
282
 
                          ycaIn[i +  9].r *  0.019597 +
283
 
                          ycaIn[i + 11].r * -0.007540 +
284
 
                          ycaIn[i + 13].r *  0.002128;
285
 
 
286
 
            ycaOut[j].b = ycaIn[i - 13].b *  0.002128 +
287
 
                          ycaIn[i - 11].b * -0.007540 +
288
 
                          ycaIn[i -  9].b *  0.019597 +
289
 
                          ycaIn[i -  7].b * -0.043159 +
290
 
                          ycaIn[i -  5].b *  0.087929 +
291
 
                          ycaIn[i -  3].b * -0.186077 +
292
 
                          ycaIn[i -  1].b *  0.627123 +
293
 
                          ycaIn[i +  1].b *  0.627123 +
294
 
                          ycaIn[i +  3].b * -0.186077 +
295
 
                          ycaIn[i +  5].b *  0.087929 +
296
 
                          ycaIn[i +  7].b * -0.043159 +
297
 
                          ycaIn[i +  9].b *  0.019597 +
298
 
                          ycaIn[i + 11].b * -0.007540 +
299
 
                          ycaIn[i + 13].b *  0.002128;
300
 
        }
301
 
        else
302
 
        {
303
 
            ycaOut[j].r = ycaIn[i].r;
304
 
            ycaOut[j].b = ycaIn[i].b;
305
 
        }
306
 
 
307
 
        ycaOut[j].g = ycaIn[i].g;
308
 
        ycaOut[j].a = ycaIn[i].a;
309
 
    }
310
 
}
311
 
 
312
 
 
313
 
void
314
 
reconstructChromaVert (int n,
315
 
                       const Rgba * const ycaIn[N],
316
 
                       Rgba ycaOut[/*n*/])
317
 
{
318
 
    for (int i = 0; i < n; ++i)
319
 
    {
320
 
        ycaOut[i].r = ycaIn[ 0][i].r *  0.002128 +
321
 
                      ycaIn[ 2][i].r * -0.007540 +
322
 
                      ycaIn[ 4][i].r *  0.019597 +
323
 
                      ycaIn[ 6][i].r * -0.043159 +
324
 
                      ycaIn[ 8][i].r *  0.087929 +
325
 
                      ycaIn[10][i].r * -0.186077 +
326
 
                      ycaIn[12][i].r *  0.627123 +
327
 
                      ycaIn[14][i].r *  0.627123 +
328
 
                      ycaIn[16][i].r * -0.186077 +
329
 
                      ycaIn[18][i].r *  0.087929 +
330
 
                      ycaIn[20][i].r * -0.043159 +
331
 
                      ycaIn[22][i].r *  0.019597 +
332
 
                      ycaIn[24][i].r * -0.007540 +
333
 
                      ycaIn[26][i].r *  0.002128;
334
 
 
335
 
        ycaOut[i].b = ycaIn[ 0][i].b *  0.002128 +
336
 
                      ycaIn[ 2][i].b * -0.007540 +
337
 
                      ycaIn[ 4][i].b *  0.019597 +
338
 
                      ycaIn[ 6][i].b * -0.043159 +
339
 
                      ycaIn[ 8][i].b *  0.087929 +
340
 
                      ycaIn[10][i].b * -0.186077 +
341
 
                      ycaIn[12][i].b *  0.627123 +
342
 
                      ycaIn[14][i].b *  0.627123 +
343
 
                      ycaIn[16][i].b * -0.186077 +
344
 
                      ycaIn[18][i].b *  0.087929 +
345
 
                      ycaIn[20][i].b * -0.043159 +
346
 
                      ycaIn[22][i].b *  0.019597 +
347
 
                      ycaIn[24][i].b * -0.007540 +
348
 
                      ycaIn[26][i].b *  0.002128;
349
 
 
350
 
        ycaOut[i].g = ycaIn[13][i].g;
351
 
        ycaOut[i].a = ycaIn[13][i].a;
352
 
    }
353
 
}
354
 
 
355
 
                         
356
 
void
357
 
YCAtoRGBA (const Imath::V3f &yw,
358
 
           int n,
359
 
           const Rgba ycaIn[/*n*/],
360
 
           Rgba rgbaOut[/*n*/])
361
 
{
362
 
    for (int i = 0; i < n; ++i)
363
 
    {
364
 
        const Rgba &in = ycaIn[i];
365
 
        Rgba &out = rgbaOut[i];
366
 
 
367
 
        if (in.r == 0 && in.b == 0)
368
 
        {
369
 
            //
370
 
            // Special case -- both chroma channels are 0.  To avoid
371
 
            // rounding errors, we explicitly set the output R, G and B
372
 
            // channels equal to the input luminance.
373
 
            //
374
 
            // The special cases here and in RGBAtoYCA() ensure that
375
 
            // converting black-and white images from RGBA to YCA and
376
 
            // back is lossless.
377
 
            //
378
 
 
379
 
            out.r = in.g;
380
 
            out.g = in.g;
381
 
            out.b = in.g;
382
 
            out.a = in.a;
383
 
        }
384
 
        else
385
 
        {
386
 
            float Y =  in.g;
387
 
            float r = (in.r + 1) * Y;
388
 
            float b = (in.b + 1) * Y;
389
 
            float g = (Y - r * yw.x - b * yw.z) / yw.y;
390
 
 
391
 
            out.r = r;
392
 
            out.g = g;
393
 
            out.b = b;
394
 
            out.a = in.a;
395
 
        }
396
 
    }
397
 
}
398
 
 
399
 
 
400
 
namespace {
401
 
 
402
 
inline float
403
 
saturation (const Rgba &in)
404
 
{
405
 
    float rgbMax = max (in.r, max (in.g, in.b));
406
 
    float rgbMin = min (in.r, min (in.g, in.b));
407
 
 
408
 
    if (rgbMax > 0)
409
 
        return 1 - rgbMin / rgbMax;
410
 
    else
411
 
        return 0;
412
 
}
413
 
 
414
 
 
415
 
void
416
 
desaturate (const Rgba &in, float f, const V3f &yw, Rgba &out)
417
 
{
418
 
    float rgbMax = max (in.r, max (in.g, in.b));
419
 
 
420
 
    out.r = max (float (rgbMax - (rgbMax - in.r) * f), 0.0f);
421
 
    out.g = max (float (rgbMax - (rgbMax - in.g) * f), 0.0f);
422
 
    out.b = max (float (rgbMax - (rgbMax - in.b) * f), 0.0f);
423
 
    out.a = in.a;
424
 
 
425
 
    float Yin  = in.r  * yw.x + in.g  * yw.y + in.b  * yw.z;
426
 
    float Yout = out.r * yw.x + out.g * yw.y + out.b * yw.z;
427
 
 
428
 
    if (Yout > 0)
429
 
    {
430
 
        out.r *= Yin / Yout;
431
 
        out.g *= Yin / Yout;
432
 
        out.b *= Yin / Yout;
433
 
    }
434
 
}
435
 
 
436
 
} // namespace
437
 
 
438
 
                         
439
 
void
440
 
fixSaturation (const Imath::V3f &yw,
441
 
               int n,
442
 
               const Rgba * const rgbaIn[3],
443
 
               Rgba rgbaOut[/*n*/])
444
 
{
445
 
    for (int i = 0; i < n; ++i)
446
 
    {
447
 
        const int i0 = max (i - 1, 0);
448
 
        const int i1 = min (i + 1, n - 1);
449
 
 
450
 
        const Rgba &neighbor0 = rgbaIn[0][i0];
451
 
        const Rgba &neighbor1 = rgbaIn[0][i1];
452
 
        const Rgba &neighbor2 = rgbaIn[2][i0];
453
 
        const Rgba &neighbor3 = rgbaIn[2][i1];
454
 
 
455
 
        float sMean = min (1.0f, 0.25f * (saturation (neighbor0) +
456
 
                                          saturation (neighbor1) +
457
 
                                          saturation (neighbor2) +
458
 
                                          saturation (neighbor3)));
459
 
 
460
 
        const Rgba &in  = rgbaIn[1][i];
461
 
        Rgba &out = rgbaOut[i];
462
 
 
463
 
        float s = saturation (in);
464
 
 
465
 
        if (s > sMean)
466
 
        {
467
 
            float sMax = min (1.0f, 1 - (1 - sMean) * 0.25f);
468
 
 
469
 
            if (s > sMax)
470
 
            {
471
 
                desaturate (in, sMax / s, yw, out);
472
 
                continue;
473
 
            }
474
 
        }
475
 
 
476
 
        out = in;
477
 
    }
478
 
}
479
 
 
480
 
 
481
 
} // namespace RgbaYca
482
 
} // namespace Imf
 
1
//////////////////////////////////////////////////////////////////////////////
 
2
//
 
3
// Copyright (c) 2004, Industrial Light & Magic, a division of Lucasfilm
 
4
// Entertainment Company Ltd.  Portions contributed and copyright held by
 
5
// others as indicated.  All rights reserved.
 
6
//
 
7
// Redistribution and use in source and binary forms, with or without
 
8
// modification, are permitted provided that the following conditions are
 
9
// met:
 
10
//
 
11
//     * Redistributions of source code must retain the above
 
12
//       copyright notice, this list of conditions and the following
 
13
//       disclaimer.
 
14
//
 
15
//     * Redistributions in binary form must reproduce the above
 
16
//       copyright notice, this list of conditions and the following
 
17
//       disclaimer in the documentation and/or other materials provided with
 
18
//       the distribution.
 
19
//
 
20
//     * Neither the name of Industrial Light & Magic nor the names of
 
21
//       any other contributors to this software may be used to endorse or
 
22
//       promote products derived from this software without specific prior
 
23
//       written permission.
 
24
//
 
25
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
26
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
27
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
28
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
29
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
30
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
31
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
32
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
33
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
34
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
35
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
36
//
 
37
//////////////////////////////////////////////////////////////////////////////
 
38
 
 
39
//-----------------------------------------------------------------------------
 
40
//
 
41
//      Conversion between RGBA and YCA data.
 
42
//
 
43
//-----------------------------------------------------------------------------
 
44
 
 
45
#include <ImfRgbaYca.h>
 
46
#include <assert.h>
 
47
#include <algorithm>
 
48
 
 
49
using namespace Imath;
 
50
using namespace std;
 
51
 
 
52
namespace Imf {
 
53
namespace RgbaYca {
 
54
 
 
55
 
 
56
V3f
 
57
computeYw (const Chromaticities &cr)
 
58
{
 
59
    M44f m = RGBtoXYZ (cr, 1);
 
60
    return V3f (m[0][1], m[1][1], m[2][1]) / (m[0][1] + m[1][1] + m[2][1]);
 
61
}
 
62
 
 
63
 
 
64
void
 
65
RGBAtoYCA (const V3f &yw,
 
66
           int n,
 
67
           bool aIsValid,
 
68
           const Rgba rgbaIn[/*n*/],
 
69
           Rgba ycaOut[/*n*/])
 
70
{
 
71
    for (int i = 0; i < n; ++i)
 
72
    {
 
73
        Rgba in = rgbaIn[i];
 
74
        Rgba &out = ycaOut[i];
 
75
 
 
76
        //
 
77
        // Conversion to YCA and subsequent chroma subsampling
 
78
        // work only if R, G and B are finite and non-negative.
 
79
        //
 
80
 
 
81
        if (!in.r.isFinite() || in.r < 0)
 
82
            in.r = 0;
 
83
 
 
84
        if (!in.g.isFinite() || in.g < 0)
 
85
            in.g = 0;
 
86
 
 
87
        if (!in.b.isFinite() || in.b < 0)
 
88
            in.b = 0;
 
89
 
 
90
        if (in.r == in.g && in.g == in.b)
 
91
        {
 
92
            //
 
93
            // Special case -- R, G and B are equal. To avoid rounding
 
94
            // errors, we explicitly set the output luminance channel
 
95
            // to G, and the chroma channels to 0.
 
96
            //
 
97
            // The special cases here and in YCAtoRGBA() ensure that
 
98
            // converting black-and white images from RGBA to YCA and
 
99
            // back is lossless.
 
100
            //
 
101
 
 
102
            out.r = 0;
 
103
            out.g = in.g;
 
104
            out.b = 0;
 
105
        }
 
106
        else
 
107
        {
 
108
            out.g = in.r * yw.x + in.g * yw.y + in.b * yw.z;
 
109
 
 
110
            float Y = out.g;
 
111
 
 
112
            if (abs (in.r - Y) < HALF_MAX * Y)
 
113
                out.r = (in.r - Y) / Y;
 
114
            else
 
115
                out.r = 0;
 
116
 
 
117
            if (abs (in.b - Y) < HALF_MAX * Y)
 
118
                out.b = (in.b - Y) / Y;
 
119
            else
 
120
                out.b = 0;
 
121
        }
 
122
 
 
123
        if (aIsValid)
 
124
            out.a = in.a;
 
125
        else
 
126
            out.a = 1;
 
127
    }
 
128
}
 
129
 
 
130
 
 
131
void
 
132
decimateChromaHoriz (int n,
 
133
                     const Rgba ycaIn[/*n+N-1*/],
 
134
                     Rgba ycaOut[/*n*/])
 
135
{
 
136
    #ifdef DEBUG
 
137
        assert (ycaIn != ycaOut);
 
138
    #endif
 
139
 
 
140
    int begin = N2;
 
141
    int end = begin + n;
 
142
 
 
143
    for (int i = begin, j = 0; i < end; ++i, ++j)
 
144
    {
 
145
        if ((j & 1) == 0)
 
146
        {
 
147
            ycaOut[j].r = ycaIn[i - 13].r *  0.001064 +
 
148
                          ycaIn[i - 11].r * -0.003771 +
 
149
                          ycaIn[i -  9].r *  0.009801 +
 
150
                          ycaIn[i -  7].r * -0.021586 +
 
151
                          ycaIn[i -  5].r *  0.043978 +
 
152
                          ycaIn[i -  3].r * -0.093067 +
 
153
                          ycaIn[i -  1].r *  0.313659 +
 
154
                          ycaIn[i     ].r *  0.499846 +
 
155
                          ycaIn[i +  1].r *  0.313659 +
 
156
                          ycaIn[i +  3].r * -0.093067 +
 
157
                          ycaIn[i +  5].r *  0.043978 +
 
158
                          ycaIn[i +  7].r * -0.021586 +
 
159
                          ycaIn[i +  9].r *  0.009801 +
 
160
                          ycaIn[i + 11].r * -0.003771 +
 
161
                          ycaIn[i + 13].r *  0.001064;
 
162
 
 
163
            ycaOut[j].b = ycaIn[i - 13].b *  0.001064 +
 
164
                          ycaIn[i - 11].b * -0.003771 +
 
165
                          ycaIn[i -  9].b *  0.009801 +
 
166
                          ycaIn[i -  7].b * -0.021586 +
 
167
                          ycaIn[i -  5].b *  0.043978 +
 
168
                          ycaIn[i -  3].b * -0.093067 +
 
169
                          ycaIn[i -  1].b *  0.313659 +
 
170
                          ycaIn[i     ].b *  0.499846 +
 
171
                          ycaIn[i +  1].b *  0.313659 +
 
172
                          ycaIn[i +  3].b * -0.093067 +
 
173
                          ycaIn[i +  5].b *  0.043978 +
 
174
                          ycaIn[i +  7].b * -0.021586 +
 
175
                          ycaIn[i +  9].b *  0.009801 +
 
176
                          ycaIn[i + 11].b * -0.003771 +
 
177
                          ycaIn[i + 13].b *  0.001064;
 
178
        }
 
179
 
 
180
        ycaOut[j].g = ycaIn[i].g;
 
181
        ycaOut[j].a = ycaIn[i].a;
 
182
    }
 
183
}
 
184
 
 
185
 
 
186
void
 
187
decimateChromaVert (int n,
 
188
                    const Rgba * const ycaIn[N],
 
189
                    Rgba ycaOut[/*n*/])
 
190
{
 
191
    for (int i = 0; i < n; ++i)
 
192
    {
 
193
        if ((i & 1) == 0)
 
194
        {
 
195
            ycaOut[i].r = ycaIn[ 0][i].r *  0.001064 +
 
196
                          ycaIn[ 2][i].r * -0.003771 +
 
197
                          ycaIn[ 4][i].r *  0.009801 +
 
198
                          ycaIn[ 6][i].r * -0.021586 +
 
199
                          ycaIn[ 8][i].r *  0.043978 +
 
200
                          ycaIn[10][i].r * -0.093067 +
 
201
                          ycaIn[12][i].r *  0.313659 +
 
202
                          ycaIn[13][i].r *  0.499846 +
 
203
                          ycaIn[14][i].r *  0.313659 +
 
204
                          ycaIn[16][i].r * -0.093067 +
 
205
                          ycaIn[18][i].r *  0.043978 +
 
206
                          ycaIn[20][i].r * -0.021586 +
 
207
                          ycaIn[22][i].r *  0.009801 +
 
208
                          ycaIn[24][i].r * -0.003771 +
 
209
                          ycaIn[26][i].r *  0.001064;
 
210
 
 
211
            ycaOut[i].b = ycaIn[ 0][i].b *  0.001064 +
 
212
                          ycaIn[ 2][i].b * -0.003771 +
 
213
                          ycaIn[ 4][i].b *  0.009801 +
 
214
                          ycaIn[ 6][i].b * -0.021586 +
 
215
                          ycaIn[ 8][i].b *  0.043978 +
 
216
                          ycaIn[10][i].b * -0.093067 +
 
217
                          ycaIn[12][i].b *  0.313659 +
 
218
                          ycaIn[13][i].b *  0.499846 +
 
219
                          ycaIn[14][i].b *  0.313659 +
 
220
                          ycaIn[16][i].b * -0.093067 +
 
221
                          ycaIn[18][i].b *  0.043978 +
 
222
                          ycaIn[20][i].b * -0.021586 +
 
223
                          ycaIn[22][i].b *  0.009801 +
 
224
                          ycaIn[24][i].b * -0.003771 +
 
225
                          ycaIn[26][i].b *  0.001064;
 
226
        }
 
227
 
 
228
        ycaOut[i].g = ycaIn[13][i].g;
 
229
        ycaOut[i].a = ycaIn[13][i].a;
 
230
    }
 
231
}
 
232
 
 
233
 
 
234
void
 
235
roundYCA (int n,
 
236
          unsigned int roundY,
 
237
          unsigned int roundC,
 
238
          const Rgba ycaIn[/*n*/],
 
239
          Rgba ycaOut[/*n*/])
 
240
{
 
241
    for (int i = 0; i < n; ++i)
 
242
    {
 
243
        ycaOut[i].g = ycaIn[i].g.round (roundY);
 
244
        ycaOut[i].a = ycaIn[i].a;
 
245
 
 
246
        if ((i & 1) == 0)
 
247
        {
 
248
            ycaOut[i].r = ycaIn[i].r.round (roundC);
 
249
            ycaOut[i].b = ycaIn[i].b.round (roundC);
 
250
        }
 
251
    }
 
252
}
 
253
 
 
254
 
 
255
void
 
256
reconstructChromaHoriz (int n,
 
257
                        const Rgba ycaIn[/*n+N-1*/],
 
258
                        Rgba ycaOut[/*n*/])
 
259
{
 
260
    #ifdef DEBUG
 
261
        assert (ycaIn != ycaOut);
 
262
    #endif
 
263
 
 
264
    int begin = N2;
 
265
    int end = begin + n;
 
266
 
 
267
    for (int i = begin, j = 0; i < end; ++i, ++j)
 
268
    {
 
269
        if (j & 1)
 
270
        {
 
271
            ycaOut[j].r = ycaIn[i - 13].r *  0.002128 +
 
272
                          ycaIn[i - 11].r * -0.007540 +
 
273
                          ycaIn[i -  9].r *  0.019597 +
 
274
                          ycaIn[i -  7].r * -0.043159 +
 
275
                          ycaIn[i -  5].r *  0.087929 +
 
276
                          ycaIn[i -  3].r * -0.186077 +
 
277
                          ycaIn[i -  1].r *  0.627123 +
 
278
                          ycaIn[i +  1].r *  0.627123 +
 
279
                          ycaIn[i +  3].r * -0.186077 +
 
280
                          ycaIn[i +  5].r *  0.087929 +
 
281
                          ycaIn[i +  7].r * -0.043159 +
 
282
                          ycaIn[i +  9].r *  0.019597 +
 
283
                          ycaIn[i + 11].r * -0.007540 +
 
284
                          ycaIn[i + 13].r *  0.002128;
 
285
 
 
286
            ycaOut[j].b = ycaIn[i - 13].b *  0.002128 +
 
287
                          ycaIn[i - 11].b * -0.007540 +
 
288
                          ycaIn[i -  9].b *  0.019597 +
 
289
                          ycaIn[i -  7].b * -0.043159 +
 
290
                          ycaIn[i -  5].b *  0.087929 +
 
291
                          ycaIn[i -  3].b * -0.186077 +
 
292
                          ycaIn[i -  1].b *  0.627123 +
 
293
                          ycaIn[i +  1].b *  0.627123 +
 
294
                          ycaIn[i +  3].b * -0.186077 +
 
295
                          ycaIn[i +  5].b *  0.087929 +
 
296
                          ycaIn[i +  7].b * -0.043159 +
 
297
                          ycaIn[i +  9].b *  0.019597 +
 
298
                          ycaIn[i + 11].b * -0.007540 +
 
299
                          ycaIn[i + 13].b *  0.002128;
 
300
        }
 
301
        else
 
302
        {
 
303
            ycaOut[j].r = ycaIn[i].r;
 
304
            ycaOut[j].b = ycaIn[i].b;
 
305
        }
 
306
 
 
307
        ycaOut[j].g = ycaIn[i].g;
 
308
        ycaOut[j].a = ycaIn[i].a;
 
309
    }
 
310
}
 
311
 
 
312
 
 
313
void
 
314
reconstructChromaVert (int n,
 
315
                       const Rgba * const ycaIn[N],
 
316
                       Rgba ycaOut[/*n*/])
 
317
{
 
318
    for (int i = 0; i < n; ++i)
 
319
    {
 
320
        ycaOut[i].r = ycaIn[ 0][i].r *  0.002128 +
 
321
                      ycaIn[ 2][i].r * -0.007540 +
 
322
                      ycaIn[ 4][i].r *  0.019597 +
 
323
                      ycaIn[ 6][i].r * -0.043159 +
 
324
                      ycaIn[ 8][i].r *  0.087929 +
 
325
                      ycaIn[10][i].r * -0.186077 +
 
326
                      ycaIn[12][i].r *  0.627123 +
 
327
                      ycaIn[14][i].r *  0.627123 +
 
328
                      ycaIn[16][i].r * -0.186077 +
 
329
                      ycaIn[18][i].r *  0.087929 +
 
330
                      ycaIn[20][i].r * -0.043159 +
 
331
                      ycaIn[22][i].r *  0.019597 +
 
332
                      ycaIn[24][i].r * -0.007540 +
 
333
                      ycaIn[26][i].r *  0.002128;
 
334
 
 
335
        ycaOut[i].b = ycaIn[ 0][i].b *  0.002128 +
 
336
                      ycaIn[ 2][i].b * -0.007540 +
 
337
                      ycaIn[ 4][i].b *  0.019597 +
 
338
                      ycaIn[ 6][i].b * -0.043159 +
 
339
                      ycaIn[ 8][i].b *  0.087929 +
 
340
                      ycaIn[10][i].b * -0.186077 +
 
341
                      ycaIn[12][i].b *  0.627123 +
 
342
                      ycaIn[14][i].b *  0.627123 +
 
343
                      ycaIn[16][i].b * -0.186077 +
 
344
                      ycaIn[18][i].b *  0.087929 +
 
345
                      ycaIn[20][i].b * -0.043159 +
 
346
                      ycaIn[22][i].b *  0.019597 +
 
347
                      ycaIn[24][i].b * -0.007540 +
 
348
                      ycaIn[26][i].b *  0.002128;
 
349
 
 
350
        ycaOut[i].g = ycaIn[13][i].g;
 
351
        ycaOut[i].a = ycaIn[13][i].a;
 
352
    }
 
353
}
 
354
 
 
355
                         
 
356
void
 
357
YCAtoRGBA (const Imath::V3f &yw,
 
358
           int n,
 
359
           const Rgba ycaIn[/*n*/],
 
360
           Rgba rgbaOut[/*n*/])
 
361
{
 
362
    for (int i = 0; i < n; ++i)
 
363
    {
 
364
        const Rgba &in = ycaIn[i];
 
365
        Rgba &out = rgbaOut[i];
 
366
 
 
367
        if (in.r == 0 && in.b == 0)
 
368
        {
 
369
            //
 
370
            // Special case -- both chroma channels are 0.  To avoid
 
371
            // rounding errors, we explicitly set the output R, G and B
 
372
            // channels equal to the input luminance.
 
373
            //
 
374
            // The special cases here and in RGBAtoYCA() ensure that
 
375
            // converting black-and white images from RGBA to YCA and
 
376
            // back is lossless.
 
377
            //
 
378
 
 
379
            out.r = in.g;
 
380
            out.g = in.g;
 
381
            out.b = in.g;
 
382
            out.a = in.a;
 
383
        }
 
384
        else
 
385
        {
 
386
            float Y =  in.g;
 
387
            float r = (in.r + 1) * Y;
 
388
            float b = (in.b + 1) * Y;
 
389
            float g = (Y - r * yw.x - b * yw.z) / yw.y;
 
390
 
 
391
            out.r = r;
 
392
            out.g = g;
 
393
            out.b = b;
 
394
            out.a = in.a;
 
395
        }
 
396
    }
 
397
}
 
398
 
 
399
 
 
400
namespace {
 
401
 
 
402
inline float
 
403
saturation (const Rgba &in)
 
404
{
 
405
    float rgbMax = max (in.r, max (in.g, in.b));
 
406
    float rgbMin = min (in.r, min (in.g, in.b));
 
407
 
 
408
    if (rgbMax > 0)
 
409
        return 1 - rgbMin / rgbMax;
 
410
    else
 
411
        return 0;
 
412
}
 
413
 
 
414
 
 
415
void
 
416
desaturate (const Rgba &in, float f, const V3f &yw, Rgba &out)
 
417
{
 
418
    float rgbMax = max (in.r, max (in.g, in.b));
 
419
 
 
420
    out.r = max (float (rgbMax - (rgbMax - in.r) * f), 0.0f);
 
421
    out.g = max (float (rgbMax - (rgbMax - in.g) * f), 0.0f);
 
422
    out.b = max (float (rgbMax - (rgbMax - in.b) * f), 0.0f);
 
423
    out.a = in.a;
 
424
 
 
425
    float Yin  = in.r  * yw.x + in.g  * yw.y + in.b  * yw.z;
 
426
    float Yout = out.r * yw.x + out.g * yw.y + out.b * yw.z;
 
427
 
 
428
    if (Yout > 0)
 
429
    {
 
430
        out.r *= Yin / Yout;
 
431
        out.g *= Yin / Yout;
 
432
        out.b *= Yin / Yout;
 
433
    }
 
434
}
 
435
 
 
436
} // namespace
 
437
 
 
438
                         
 
439
void
 
440
fixSaturation (const Imath::V3f &yw,
 
441
               int n,
 
442
               const Rgba * const rgbaIn[3],
 
443
               Rgba rgbaOut[/*n*/])
 
444
{
 
445
    for (int i = 0; i < n; ++i)
 
446
    {
 
447
        const int i0 = max (i - 1, 0);
 
448
        const int i1 = min (i + 1, n - 1);
 
449
 
 
450
        const Rgba &neighbor0 = rgbaIn[0][i0];
 
451
        const Rgba &neighbor1 = rgbaIn[0][i1];
 
452
        const Rgba &neighbor2 = rgbaIn[2][i0];
 
453
        const Rgba &neighbor3 = rgbaIn[2][i1];
 
454
 
 
455
        float sMean = min (1.0f, 0.25f * (saturation (neighbor0) +
 
456
                                          saturation (neighbor1) +
 
457
                                          saturation (neighbor2) +
 
458
                                          saturation (neighbor3)));
 
459
 
 
460
        const Rgba &in  = rgbaIn[1][i];
 
461
        Rgba &out = rgbaOut[i];
 
462
 
 
463
        float s = saturation (in);
 
464
 
 
465
        if (s > sMean)
 
466
        {
 
467
            float sMax = min (1.0f, 1 - (1 - sMean) * 0.25f);
 
468
 
 
469
            if (s > sMax)
 
470
            {
 
471
                desaturate (in, sMax / s, yw, out);
 
472
                continue;
 
473
            }
 
474
        }
 
475
 
 
476
        out = in;
 
477
    }
 
478
}
 
479
 
 
480
 
 
481
} // namespace RgbaYca
 
482
} // namespace Imf