1 /*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "metadata/ColorFilterArray.h"
22 #include "common/Common.h" // for writeLog, DEBUG_PRIO_EXTRA
23 #include "common/Point.h" // for iPoint2D, iPoint2D::value_...
24 #include "decoders/RawDecoderException.h" // for ThrowRDE
25 #include <algorithm> // for fill
26 #include <cstdarg> // for va_arg, va_end, va_list
27 #include <cstdlib> // for size_t, abs
28 #include <map> // for map
29 #include <stdexcept> // for out_of_range
30 #include <string> // for string
31
32 using std::vector;
33 using std::string;
34 using std::out_of_range;
35 using std::map;
36
37 namespace rawspeed {
38
ColorFilterArray(const iPoint2D & _size)39 ColorFilterArray::ColorFilterArray(const iPoint2D &_size) {
40 setSize(_size);
41 }
42
setSize(const iPoint2D & _size)43 void ColorFilterArray::setSize(const iPoint2D& _size)
44 {
45 size = _size;
46
47 if (size.area() > 36) {
48 // Bayer, FC() supports 2x8 pattern
49 // X-Trans is 6x6 pattern
50 // is there anything bigger?
51 ThrowRDE("if your CFA pattern is really %zu pixels "
52 "in area we may as well give up now",
53 size.area());
54 }
55 if (size.area() <= 0)
56 return;
57 cfa.resize(size.area());
58 fill(cfa.begin(), cfa.end(), CFA_UNKNOWN);
59 }
60
getColorAt(int x,int y) const61 CFAColor ColorFilterArray::getColorAt( int x, int y ) const
62 {
63 if (cfa.empty())
64 ThrowRDE("No CFA size set");
65
66 // calculate the positive modulo [0 .. size-1]
67 x = (x % size.x + size.x) % size.x;
68 y = (y % size.y + size.y) % size.y;
69
70 return cfa[x + static_cast<size_t>(y) * size.x];
71 }
72
setCFA(iPoint2D in_size,...)73 void ColorFilterArray::setCFA( iPoint2D in_size, ... )
74 {
75 if (in_size != size) {
76 setSize(in_size);
77 }
78 va_list arguments;
79 va_start(arguments, in_size);
80 for (auto i = 0UL; i < size.area(); i++) {
81 cfa[i] = static_cast<CFAColor>(va_arg(arguments, int));
82 }
83 va_end (arguments);
84 }
85
shiftLeft(int n)86 void ColorFilterArray::shiftLeft(int n) {
87 if (cfa.empty())
88 ThrowRDE("No CFA size set (or set to zero)");
89
90 writeLog(DEBUG_PRIO_EXTRA, "Shift left:%d", n);
91 n %= size.x;
92 if (n == 0)
93 return;
94
95 vector<CFAColor> tmp(size.area());
96 for (int y = 0; y < size.y; ++y) {
97 for (int x = 0; x < size.x; ++x) {
98 tmp[x + static_cast<size_t>(y) * size.x] = getColorAt(x + n, y);
99 }
100 }
101 cfa = tmp;
102 }
103
shiftDown(int n)104 void ColorFilterArray::shiftDown(int n) {
105 if (cfa.empty())
106 ThrowRDE("No CFA size set (or set to zero)");
107
108 writeLog(DEBUG_PRIO_EXTRA, "Shift down:%d", n);
109 n %= size.y;
110 if (n == 0)
111 return;
112 vector<CFAColor> tmp(size.area());
113 for (int y = 0; y < size.y; ++y) {
114 for (int x = 0; x < size.x; ++x) {
115 tmp[x + static_cast<size_t>(y) * size.x] = getColorAt(x, y + n);
116 }
117 }
118 cfa = tmp;
119 }
120
asString() const121 string ColorFilterArray::asString() const {
122 string dst;
123 for (int y = 0; y < size.y; y++) {
124 for (int x = 0; x < size.x; x++) {
125 dst += colorToString(getColorAt(x,y));
126 dst += (x == size.x - 1) ? "\n" : ",";
127 }
128 }
129 return dst;
130 }
131
shiftDcrawFilter(uint32_t filter,int x,int y)132 uint32_t ColorFilterArray::shiftDcrawFilter(uint32_t filter, int x, int y) {
133 // filter is a series of 4 bytes that describe a 2x8 matrix. 2 is the width,
134 // 8 is the height. each byte describes a 2x2 pixel block. so each pixel has
135 // 2 bits of information. This allows to distinguish 4 different colors.
136
137 if (std::abs(x) & 1) {
138 // A shift in x direction means swapping the first and second half of each
139 // nibble.
140 // see http://graphics.stanford.edu/~seander/bithacks.html#SwappingBitsXOR
141 for (int n = 0; n < 8; ++n) {
142 int i = n * 4;
143 int j = i + 2;
144 uint32_t t = ((filter >> i) ^ (filter >> j)) & ((1U << 2) - 1);
145 filter = filter ^ ((t << i) | (t << j));
146 }
147 }
148
149 if (y == 0)
150 return filter;
151
152 // A shift in y direction means rotating the whole int by 4 bits.
153 y *= 4;
154 y = y >= 0 ? y % 32 : 32 - ((-y) % 32);
155 filter = (filter >> y) | (filter << (32 - y));
156
157 return filter;
158 }
159
160 const map<CFAColor, string> ColorFilterArray::color2String = {
161 {CFA_RED, "RED"}, {CFA_GREEN, "GREEN"},
162 {CFA_BLUE, "BLUE"}, {CFA_CYAN, "CYAN"},
163 {CFA_MAGENTA, "MAGENTA"}, {CFA_YELLOW, "YELLOW"},
164 {CFA_WHITE, "WHITE"}, {CFA_FUJI_GREEN, "FUJIGREEN"},
165 {CFA_UNKNOWN, "UNKNOWN"}};
166
colorToString(CFAColor c)167 string ColorFilterArray::colorToString(CFAColor c)
168 {
169 try {
170 return color2String.at(c);
171 } catch (std::out_of_range&) {
172 ThrowRDE("Unsupported CFA Color: %u", c);
173 }
174 }
175
setColorAt(iPoint2D pos,CFAColor c)176 void ColorFilterArray::setColorAt(iPoint2D pos, CFAColor c) {
177 if (pos.x >= size.x || pos.x < 0)
178 ThrowRDE("position out of CFA pattern");
179 if (pos.y >= size.y || pos.y < 0)
180 ThrowRDE("position out of CFA pattern");
181 cfa[pos.x + static_cast<size_t>(pos.y) * size.x] = c;
182 }
183
toDcrawColor(CFAColor c)184 static uint32_t toDcrawColor(CFAColor c) {
185 switch (c) {
186 case CFA_FUJI_GREEN:
187 case CFA_RED: return 0;
188 case CFA_MAGENTA:
189 case CFA_GREEN: return 1;
190 case CFA_CYAN:
191 case CFA_BLUE: return 2;
192 case CFA_YELLOW: return 3;
193 default:
194 throw out_of_range(ColorFilterArray::colorToString(c));
195 }
196 }
197
getDcrawFilter() const198 uint32_t ColorFilterArray::getDcrawFilter() const {
199 //dcraw magic
200 if (size.x == 6 && size.y == 6)
201 return 9;
202
203 if (cfa.empty() || size.x > 2 || size.y > 8 || !isPowerOfTwo(size.y))
204 return 1;
205
206 uint32_t ret = 0;
207 for (int x = 0; x < 2; x++) {
208 for (int y = 0; y < 8; y++) {
209 uint32_t c = toDcrawColor(getColorAt(x, y));
210 int g = (x >> 1) * 8;
211 ret |= c << ((x&1)*2 + y*4 + g);
212 }
213 }
214
215 writeLog(DEBUG_PRIO_EXTRA, "%s", asString().c_str());
216 writeLog(DEBUG_PRIO_EXTRA, "DCRAW filter:%x", ret);
217
218 return ret;
219 }
220
221 } // namespace rawspeed
222