rixmap 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/src/rixmap/image.hxx CHANGED
@@ -9,10 +9,110 @@
9
9
  #include "palette.hxx"
10
10
 
11
11
  namespace Rixmap {
12
+
13
+ // ピクセルデータ用コンテナ
14
+ typedef std::map<Channel, uint8_t**> Pixels;
15
+
16
+ // 反転方向定数
17
+ enum class FlipDirection : int {
18
+ HORIZONTAL = 0x01,
19
+ VERTICAL = 0x02,
20
+ DIAGONAL = 0x03
21
+ };
22
+
12
23
  /**
13
24
  * Ruby用画像情報クラスデータ
14
25
  */
15
26
  class ImageData {
27
+ private: // 非公開クラスメンバ関数
28
+ /**
29
+ * ピクセルデータを指定された情報に従って解放します.
30
+ *
31
+ * @param [Pixels&] pixels ピクセルデータ.
32
+ * @param [int32_t] width 画像の横幅
33
+ * @param [int32_t] height 画像の高さ
34
+ */
35
+ static void DeallocatePixels(Pixels& pixels, int32_t width, int32_t height) {
36
+ for (auto it = pixels.begin(); it != pixels.end(); it++) {
37
+ uint8_t** plane = it->second;
38
+ if (plane != NULL) {
39
+ for (int32_t h = 0; h < height; h++) {
40
+ if (plane[h] != NULL) {
41
+ delete[] plane[h];
42
+ }
43
+ }
44
+ delete[] plane;
45
+ it->second = NULL;
46
+ }
47
+ }
48
+ pixels.clear();
49
+ }
50
+
51
+ /**
52
+ * ピクセルデータリストを指定チャンネル分だけ確保します.
53
+ *
54
+ * 注意点として、pixelsは未初期化 (確保したて) を想定しています.
55
+ * 中身が二重ポインタのせいで正確に解放できないためです.
56
+ *
57
+ * @param [Pixels&] pixels データ格納先.
58
+ * @param [ChannelArray&] channels 確保するチャンネルリスト
59
+ * @param [int32_t] width 画像の横幅
60
+ * @param [int32_t] height 画像の高さ
61
+ * @param [bool] cleared 初期化するかのフラグ (default=true)
62
+ */
63
+ static void AllocatePixels(Pixels& pixels, const ChannelArray& channels, int32_t width, int32_t height, bool cleared = true) {
64
+ // メモリ不足時に投げる例外オブジェクト
65
+ static std::bad_alloc excNoMemory;
66
+
67
+ // 確保処理
68
+ try {
69
+ for (auto it = channels.begin(); it != channels.end(); it++) {
70
+ Channel channel = *it;
71
+
72
+ // NULLポインタで初期化
73
+ // TODO ところでこれ、nullptrのほうがいいんですかね
74
+ pixels[channel] = NULL;
75
+
76
+ // ピクセルデータを確保
77
+ uint8_t** plane = new uint8_t*[height];
78
+ if (plane == NULL) {
79
+ // 確保できてない
80
+ throw excNoMemory;
81
+ }
82
+
83
+ // 確保できたらpixelsに入れる
84
+ pixels[channel] = plane;
85
+
86
+ // 中身を確保
87
+ for (int32_t h = 0; h < height; h++) {
88
+ uint8_t* line = new uint8_t[width];
89
+ if (line == NULL) {
90
+ // 無理でした
91
+ throw excNoMemory;
92
+ }
93
+ plane[h] = line;
94
+
95
+ // 初期化する
96
+ if (cleared) {
97
+ if (channel == Channel::ALPHA) {
98
+ std::memset(&(line[0]), 255, sizeof(uint8_t) * width);
99
+ } else {
100
+ std::memset(&(line[0]), 0, sizeof(uint8_t) * width);
101
+ }
102
+ }
103
+ }
104
+ }
105
+ } catch (const std::bad_alloc& e) {
106
+ // メモリねぇぞ(#゚Д゚)
107
+
108
+ // 今まで確保した分を解放
109
+ ImageData::DeallocatePixels(pixels, width, height);
110
+
111
+ // raise NoMemoryError
112
+ rb_memerror();
113
+ }
114
+ }
115
+
16
116
  private: // 非公開メンバ
17
117
  ModeInfo _mode; // 画像形式
18
118
  int32_t _width; // 横幅
@@ -20,7 +120,7 @@ namespace Rixmap {
20
120
  bool _ready; // 準備完了しているか
21
121
 
22
122
  // ピクセルデータ系
23
- std::map<Channel, uint8_t**> _data;
123
+ Pixels _data;
24
124
  VALUE _palette;
25
125
 
26
126
  public: // コンストラクタ
@@ -36,25 +136,42 @@ namespace Rixmap {
36
136
  this->init(mode, width, height);
37
137
  }
38
138
 
139
+ /**
140
+ * コピーコンストラクタ
141
+ */
142
+ ImageData(const ImageData& image) : _mode(Mode::NONE), _width(0), _height(0), _ready(false), _palette(Qnil) {
143
+ this->init(image.getMode(), image._width, image._height);
144
+ this->_palette = image._palette;
145
+
146
+ // ピクセルの複製
147
+ const ChannelArray& channels = image._mode.getChannels();
148
+ for (auto it = channels.begin(); it != channels.end(); it++) {
149
+ Channel channel = *it;
150
+ uint8_t** dstPlane = this->_data.at(channel);
151
+ uint8_t** srcPlane = image._data.at(channel);
152
+ for (int32_t h = 0; h < image._height; h++) {
153
+ for (int32_t w = 0; w < image._width; w++) {
154
+ dstPlane[h][w] = srcPlane[h][w];
155
+ }
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * ベース画像ののサイズを変更した新しい画像を作成する、部分コピーコンストラクタ.
162
+ * ピクセルデータは複製されません.
163
+ */
164
+ ImageData(const ImageData& image, int32_t width, int32_t height) : _mode(Mode::NONE), _width(0), _height(0), _ready(false), _palette(Qnil) {
165
+ this->init(image.getMode(), width, height);
166
+ this->_palette = image._palette;
167
+ }
168
+
39
169
  /**
40
170
  * デストラクタ
41
171
  */
42
172
  ~ImageData() {
43
- // TODO ピクセルデータの解放処理
44
173
  if (this->_ready) {
45
- for (auto it = this->_data.begin(); it != this->_data.end(); it++) {
46
- uint8_t** plane = it->second;
47
- if (plane != NULL) {
48
- for (int32_t h = 0; h < this->_height; h++) {
49
- if (plane[h] != NULL) {
50
- ruby_xfree(plane[h]);
51
- }
52
- }
53
- ruby_xfree(plane);
54
- it->second = NULL;
55
- }
56
- }
57
- this->_data.clear();
174
+ ImageData::DeallocatePixels(this->_data, this->_width, this->_height);
58
175
  }
59
176
  }
60
177
 
@@ -67,8 +184,8 @@ namespace Rixmap {
67
184
  /**
68
185
  * 画像形式情報を取得します.
69
186
  */
70
- //inline ModeInfo& getModeInfo() { return this->_mode; }
71
187
  inline const ModeInfo& getModeInfo() const { return this->_mode; }
188
+ inline ModeInfo& getModeInfo() { return this->_mode; }
72
189
 
73
190
  /**
74
191
  * 横幅を取得します.
@@ -94,7 +211,7 @@ namespace Rixmap {
94
211
  * パレットオブジェクトの内部データポインタを返します.
95
212
  * パレットがnilの場合はNULLが返されます.
96
213
  */
97
- inline const PaletteData* getPaletteData() const {
214
+ inline PaletteData* getPaletteData() const {
98
215
  if (NIL_P(this->_palette)) {
99
216
  return NULL;
100
217
  } else {
@@ -130,10 +247,10 @@ namespace Rixmap {
130
247
  * 指定チャンネルデータを格納するデータポインタから取得します.
131
248
  * 対象チャンネルを持っていない場合はNULLになります.
132
249
  */
133
- inline uint8_t** get(Channel channel) {
250
+ inline uint8_t** get(Channel channel) const {
134
251
  auto found = this->_data.find(channel);
135
252
  if (found != this->_data.end()) {
136
- return this->_data[channel];
253
+ return this->_data.at(channel);
137
254
  } else {
138
255
  return NULL;
139
256
  }
@@ -143,7 +260,7 @@ namespace Rixmap {
143
260
  * 指定チャンネルの指定行番号に対応するバイト列へのポインタから取得します.
144
261
  * 行番号が範囲外の場合か、非対応のチャンネルの場合はNULLになります.
145
262
  */
146
- inline uint8_t* get(Channel channel, int32_t lineno) {
263
+ inline uint8_t* get(Channel channel, int32_t lineno) const {
147
264
  if (0 <= lineno && lineno < this->_height) {
148
265
  uint8_t** plane = this->get(channel);
149
266
  if (plane != NULL) {
@@ -159,7 +276,7 @@ namespace Rixmap {
159
276
  * Notice: 範囲外だったりチャンネル持ってないときは0になるので、
160
277
  * 実はバイトデータが0の時と判別できないんですよコレ
161
278
  */
162
- inline uint8_t get(Channel channel, int32_t x, int32_t y) {
279
+ inline uint8_t get(Channel channel, int32_t x, int32_t y) const {
163
280
  if (0 <= x && x < this->_width && 0 <= y && y < this->_height) {
164
281
  uint8_t** plane = this->get(channel);
165
282
  if (plane != NULL) {
@@ -183,6 +300,51 @@ namespace Rixmap {
183
300
  return false;
184
301
  }
185
302
 
303
+ /**
304
+ * 指定した座標の色データを取得します.
305
+ */
306
+ inline Color fetch(int32_t x, int32_t y, bool strict = false) const {
307
+ if (0 <= x && x < this->_width && 0 <= y && y < this->_height) {
308
+ switch (this->_mode.getMode()) {
309
+ case Mode::INDEXED:
310
+ {
311
+ uint8_t off = this->get(Channel::PALETTE, x, y);
312
+ return this->getPaletteData()->get(off);
313
+ }
314
+ break;
315
+
316
+ case Mode::GRAYSCALE:
317
+ case Mode::GRAYALPHA:
318
+ {
319
+ uint8_t l = this->get(Channel::LUMINANCE, x, y);
320
+ return Color(l, l, l);
321
+ }
322
+ break;
323
+
324
+ case Mode::RGB:
325
+ case Mode::RGBA:
326
+ {
327
+ uint8_t r = this->get(Channel::RED, x, y);
328
+ uint8_t g = this->get(Channel::GREEN, x, y);
329
+ uint8_t b = this->get(Channel::BLUE, x, y);
330
+ return Color(r, g, b);
331
+ }
332
+ break;
333
+
334
+ default:
335
+ throw std::invalid_argument("unexpected image mode");
336
+ }
337
+ } else {
338
+ if (strict) {
339
+ std::ostringstream err;
340
+ err << "point [" << x << ", " << y << "] is out of image";
341
+ throw std::out_of_range(err.str());
342
+ } else {
343
+ return Color(0, 0, 0);
344
+ }
345
+ }
346
+ }
347
+
186
348
  /**
187
349
  * 画像データを初期化します.
188
350
  */
@@ -203,25 +365,11 @@ namespace Rixmap {
203
365
  // 解析用にモードを設置
204
366
  ModeInfo info(mode);
205
367
  const ChannelArray& channels = info.getChannels();
206
- for (auto it = channels.begin(); it != channels.end(); it++) {
207
- Channel channel = *it;
208
- this->_data[channel] = NULL;
209
-
210
- // 領域を確保
211
- uint8_t** plane = ALLOC_N(uint8_t*, height);
212
- std::memset(plane, 0, sizeof(uint8_t*) * height);
213
- for (int32_t h = 0; h < height; h++) {
214
- plane[h] = ALLOC_N(uint8_t, width);
215
- if (channel == Channel::ALPHA) {
216
- std::memset(&(plane[h][0]), 255, sizeof(uint8_t) * width);
217
- } else {
218
- std::memset(&(plane[h][0]), 0, sizeof(uint8_t) * width);
219
- }
220
- }
221
368
 
222
- this->_data[channel] = plane;
223
- }
369
+ // ピクセルデータを確保
370
+ ImageData::AllocatePixels(this->_data, channels, width, height, true);
224
371
 
372
+ // その他プロパティを初期化
225
373
  this->_mode = info;
226
374
  this->_width = width;
227
375
  this->_height = height;
@@ -236,6 +384,62 @@ namespace Rixmap {
236
384
  rb_gc_mark_maybe(this->_palette);
237
385
  }
238
386
 
387
+ /**
388
+ * 必須ではないオブジェクトのハッシュを返します.
389
+ */
390
+ inline VALUE getMetadata() const {
391
+ VALUE metadata = rb_hash_new();
392
+ rb_hash_aset(metadata, ID2SYM(rb_intern("palette")), this->_palette);
393
+ return metadata;
394
+ }
395
+
396
+ /**
397
+ * 画像の反転処理を行います.
398
+ */
399
+ void flip(FlipDirection direction) {
400
+ const ChannelArray& channels = this->_mode.getChannels();
401
+
402
+ // まずは横方向に反転
403
+ switch (direction) {
404
+ case FlipDirection::HORIZONTAL:
405
+ case FlipDirection::DIAGONAL:
406
+ for (auto it = channels.begin(); it != channels.end(); it++) {
407
+ uint8_t** plane = this->get(*it);
408
+ if (plane == NULL) {
409
+ continue;
410
+ }
411
+ for (int32_t h = 0; h < this->_height; h++) {
412
+ std::reverse(&(plane[h][0]), &(plane[h][this->_width]));
413
+ }
414
+ }
415
+ break;
416
+
417
+ default:
418
+ // DO NOTHING
419
+ // (警告抑制)
420
+ break;
421
+ }
422
+
423
+ // 次に縦方向に反転
424
+ switch (direction) {
425
+ case FlipDirection::VERTICAL:
426
+ case FlipDirection::DIAGONAL:
427
+ for (auto it = channels.begin(); it != channels.end(); it++) {
428
+ uint8_t** plane = this->get(*it);
429
+ if (plane == NULL) {
430
+ continue;
431
+ }
432
+ std::reverse(&(plane[0]), &(plane[this->_height]));
433
+ }
434
+ break;
435
+
436
+ default:
437
+ // DO NOTHING
438
+ // (警告抑制)
439
+ break;
440
+ }
441
+ }
442
+
239
443
  public: // 演算子オーバーロード
240
444
  bool operator==(const ImageData& data) const {
241
445
  if (this->_ready && data._ready && (this->_mode == data._mode) && (this->_width == data._width) && (this->_height == data._height)) {
@@ -267,6 +471,47 @@ namespace Rixmap {
267
471
  }
268
472
  }
269
473
  bool operator!=(const ImageData& data) const { return !(*this == data); }
474
+
475
+ /**
476
+ * 代入演算子実装
477
+ */
478
+ ImageData& operator=(const ImageData& base) {
479
+ // チャンネルリスト
480
+ const ChannelArray& channels = base._mode.getChannels();
481
+
482
+ // ピクセルデータは新しく確保 (破壊防止)
483
+ std::map<Channel, uint8_t**> pixels;
484
+ ImageData::AllocatePixels(pixels, channels, base._width, base._height, false);
485
+
486
+ // ピクセルデータを複製
487
+ for (auto it = channels.begin(); it != channels.end(); it++) {
488
+ Channel channel = *it;
489
+ uint8_t** dstPlane = pixels.at(channel);
490
+ uint8_t** srcPlane = base._data.at(channel);
491
+ for (int32_t h = 0; h < base._height; h++) {
492
+ std::memcpy(&(dstPlane[h][0]), &(srcPlane[h][0]), sizeof(uint8_t) * base._width);
493
+ }
494
+ }
495
+
496
+ // ピクセルを移動
497
+ // TODO swapとか使ってるけど危ないなら複製する方向にしよう
498
+ ImageData::DeallocatePixels(this->_data, this->_width, this->_height);
499
+ this->_data.swap(pixels);
500
+
501
+ // 基本情報を複製
502
+ this->_mode = base._mode;
503
+ this->_width = base._width;
504
+ this->_height = base._height;
505
+
506
+ // パレットは参照
507
+ this->_palette = base._palette;
508
+
509
+ // 準備完了
510
+ this->_ready = true;
511
+
512
+ // 戻る
513
+ return *this;
514
+ }
270
515
  };
271
516
 
272
517
  /**
@@ -367,5 +612,5 @@ namespace Rixmap {
367
612
 
368
613
 
369
614
  //============================================================================//
370
- // $Id: image.hxx,v c10e98a1e0fa 2014/04/20 08:17:37 chikuchikugonzalez $
615
+ // $Id: image.hxx,v 753dbf70cab3 2014/05/16 16:13:38 chikuchikugonzalez $
371
616
  // vim: set sts=4 ts=4 sw=4 expandtab foldmethod=marker:
@@ -0,0 +1,226 @@
1
+ // -*- coding: utf-8 -*-
2
+ /**
3
+ * 変形処理用画素補間処理実装
4
+ */
5
+ #pragma once
6
+ #include <array>
7
+ #include "common.hxx"
8
+ #include "image.hxx"
9
+
10
+ namespace Rixmap {
11
+ /**
12
+ * 補間処理方法.
13
+ */
14
+ enum class Interpolation : int {
15
+ NONE = 0x00,
16
+ //NEAREST = 0x01, // 最近傍 (Nearest-Neighbor)
17
+ //BILINEAR = 0x02, // バイリニア (双一次)
18
+ BICUBIC = 0x03, // バイキュービック (双三次)
19
+ };
20
+
21
+ /**
22
+ * 画素補間処理ベースクラス.
23
+ * 補間処理自体はピクセルベースで実行されます.
24
+ */
25
+ class Interpolator {
26
+ protected:
27
+ ImageData* _base; // 元画像
28
+ ModeInfo* _mode; // 元画像形式
29
+
30
+ // 補間処理キャッシュ
31
+ std::map<Channel, uint8_t> _pixel;
32
+
33
+ public:
34
+ Interpolator(ImageData* base) : _base(base), _mode(&(_base->getModeInfo())) {
35
+ this->reset();
36
+ }
37
+
38
+ virtual ~Interpolator() {}
39
+
40
+ public: // 補間処理用メソッド
41
+ /**
42
+ * 変換後に必要になる画像形式
43
+ */
44
+ virtual Mode getPreferredMode() { return this->_mode->getMode(); }
45
+
46
+ /**
47
+ * 補間処理を実行します.
48
+ */
49
+ virtual void calculate(double x, double y) = 0;
50
+
51
+ /**
52
+ * 計算済みピクセルデータを取得します.
53
+ */
54
+ virtual uint8_t get(Channel channel) { return this->_pixel.at(channel); }
55
+
56
+ protected: // 非公開メンバ
57
+ virtual void reset() {
58
+ const ChannelArray& channels = this->_mode->getChannels();
59
+ for (auto it = channels.begin(); it != channels.end(); it++) {
60
+ Channel channel = *it;
61
+ if (channel == Channel::ALPHA) {
62
+ this->_pixel[channel] = 255;
63
+ } else {
64
+ this->_pixel[channel] = 0;
65
+ }
66
+ }
67
+ }
68
+ };
69
+
70
+ /**
71
+ * なにもしない補間処理実装
72
+ */
73
+ class NOPInterpolator : public Interpolator {
74
+ public:
75
+ NOPInterpolator(ImageData* base) : Interpolator(base) {}
76
+
77
+ public:
78
+ virtual void calculate(double x, double y) override {
79
+ this->reset();
80
+ int32_t dx = static_cast<int32_t>(x);
81
+ int32_t dy = static_cast<int32_t>(y);
82
+ if (this->_base->isInside(dx, dy)) {
83
+ const ChannelArray& channels = this->_mode->getChannels();
84
+ for (auto it = channels.begin(); it != channels.end(); it++) {
85
+ Channel channel = *it;
86
+ this->_pixel[channel] = this->_base->get(channel, dx, dy);
87
+ }
88
+ }
89
+ }
90
+ };
91
+
92
+ /**
93
+ * バイキュービック法による補間処理実装
94
+ */
95
+ class BicubicInterpolator : public Interpolator {
96
+ protected:
97
+ double _factor; // sinc関数パラメータ
98
+ ModeInfo _preferredMode; // 推奨画像形式
99
+
100
+ public:
101
+ BicubicInterpolator(ImageData* base, double factor = -1) : Interpolator(base), _factor(factor) {
102
+ switch (this->_mode->getMode()) {
103
+ case Mode::RGB:
104
+ case Mode::RGBA:
105
+ this->_preferredMode = ModeInfo(this->_mode->getMode());
106
+ break;
107
+
108
+ default:
109
+ this->_preferredMode = ModeInfo(Mode::RGB);
110
+ }
111
+ }
112
+
113
+ protected: // 非公開メンバ関数
114
+ /**
115
+ * sinc関数 (http://ja.wikipedia.org/wiki/Sinc%E9%96%A2%E6%95%B0) の近似式
116
+ */
117
+ static inline double sinc(double t, double f = -1) {
118
+ using namespace std; // powがmingw x86_64版rubyだとstd名前空間付きで使えないため
119
+ double t0 = abs(t);
120
+ if (t0 > 2) {
121
+ return 0.0;
122
+ } else if (t0 <= 1.0) {
123
+ double n0 = (f + 2) * pow(t0, 3.0);
124
+ double n1 = (f + 3) * pow(t0, 2.0);
125
+ return n0 - n1 + 1;
126
+ } else {
127
+ double n0 = f * pow(t0, 3.0);
128
+ double n1 = (5 * f) * pow(t0, 2.0);
129
+ double n2 = (8 * f) * t0;
130
+ double n3 = 4 * f;
131
+ return n0 - n1 + n2 - n3;
132
+ }
133
+ }
134
+
135
+ public:
136
+ virtual Mode getPreferredMode() override {
137
+ return this->_preferredMode.getMode();
138
+ }
139
+
140
+ virtual void calculate(double x, double y) override {
141
+ static int32_t sx[4]; // 周辺座標点 (16点)
142
+ static int32_t sy[4];
143
+ static double dx[4]; // 周辺座標の比率
144
+ static double dy[4];
145
+ static double hx[4]; // sinc関数キャッシュ
146
+ static double hy[4];
147
+ static std::map<Channel, std::array<std::array<uint8_t, 4>, 4>> pixels;
148
+
149
+ // ピクセルデータを初期化
150
+ this->reset();
151
+
152
+ // 周辺座標設定
153
+ sx[1] = lround(std::floor(x)); // [x]
154
+ sx[0] = sx[1] - 1; // [x] - 1
155
+ sx[2] = sx[1] + 1; // [x] + 1
156
+ sx[3] = sx[1] + 2; // [x] + 2
157
+ sy[1] = lround(std::floor(y)); // [y]
158
+ sy[0] = sy[1] - 1; // [y] - 1
159
+ sy[2] = sy[1] + 1; // [y] + 1
160
+ sy[3] = sy[1] + 2; // [y] + 2
161
+
162
+ // 距離を計算
163
+ dx[0] = 1 + x - sx[1];
164
+ dx[1] = x - sx[1];
165
+ dx[2] = sx[1] + 1 - x;
166
+ dx[3] = sx[1] + 2 - x;
167
+ dy[0] = 1 + y - sy[1];
168
+ dy[1] = y - sy[1];
169
+ dy[2] = sy[1] + 1 - y;
170
+ dy[3] = sy[1] + 2 - y;
171
+
172
+ // sinc関数による重み計算
173
+ for (int i = 0; i < 4; i++) {
174
+ hx[i] = BicubicInterpolator::sinc(dx[i], this->_factor);
175
+ hy[i] = BicubicInterpolator::sinc(dy[i], this->_factor);
176
+ }
177
+
178
+ // 周辺ピクセルデータ
179
+ for (int32_t h = 0; h < 4; h++) {
180
+ for (int32_t w = 0; w < 4; w++) {
181
+ Color col = this->_base->fetch(sx[w], sy[h]);
182
+ pixels[Channel::RED ][h][w] = col.getRed();
183
+ pixels[Channel::GREEN][h][w] = col.getGreen();
184
+ pixels[Channel::BLUE ][h][w] = col.getBlue();
185
+ pixels[Channel::ALPHA][h][w] = col.getAlpha();
186
+ }
187
+ }
188
+
189
+ // 画素値を計算
190
+ double matrix[4];
191
+ const ChannelArray& channels = this->_preferredMode.getChannels();
192
+ for (auto it = channels.begin(); it != channels.end(); it++) {
193
+ Channel channel = *it;
194
+ for (int m = 0; m < 4; m++) {
195
+ matrix[m] = 0.0;
196
+ for (int h = 0; h < 4; h++) {
197
+ matrix[m] += hy[h] * pixels[channel][h][m];
198
+ }
199
+ }
200
+ double v = 0.0;
201
+ for (int w = 0; w < 4; w++) {
202
+ v += matrix[w] * hx[w];
203
+ }
204
+ this->_pixel[channel] = ROUND2BYTE(lround(v));
205
+ }
206
+ }
207
+
208
+ protected: // 非公開メンバ
209
+ virtual void reset() {
210
+ const ChannelArray& channels = this->_preferredMode.getChannels();
211
+ for (auto it = channels.begin(); it != channels.end(); it++) {
212
+ Channel channel = *it;
213
+ if (channel == Channel::ALPHA) {
214
+ this->_pixel[channel] = 255;
215
+ } else {
216
+ this->_pixel[channel] = 0;
217
+ }
218
+ }
219
+ }
220
+ };
221
+ }
222
+
223
+
224
+ //============================================================================//
225
+ // $Id: interpolator.hxx,v 753dbf70cab3 2014/05/16 16:13:38 chikuchikugonzalez $
226
+ // vim: set sts=4 ts=4 sw=4 expandtab foldmethod=marker:
@@ -113,7 +113,19 @@ namespace Rixmap {
113
113
  throw std::out_of_range(msg.str());
114
114
  }
115
115
  }
116
- inline const Color& get(size_t offset) const { return this->get(offset); }
116
+
117
+ /**
118
+ * const用実装.
119
+ */
120
+ inline const Color& get(size_t offset) const {
121
+ if (/* 0 <= offset && */ offset <= this->_colors.size()) {
122
+ return this->_colors[offset];
123
+ } else {
124
+ std::ostringstream msg;
125
+ msg << "offsetis out of range: " << offset << " for 0.." << this->_colors.size();
126
+ throw std::out_of_range(msg.str());
127
+ }
128
+ }
117
129
 
118
130
  /**
119
131
  * 指定したオフセットのカラーデータを変更します.
@@ -216,5 +228,5 @@ namespace Rixmap {
216
228
 
217
229
 
218
230
  //============================================================================//
219
- // $Id: palette.hxx,v 5b9a0968eca5 2014/04/20 13:37:36 chikuchikugonzalez $
231
+ // $Id: palette.hxx,v 753dbf70cab3 2014/05/16 16:13:38 chikuchikugonzalez $
220
232
  // vim: set sts=4 ts=4 sw=4 expandtab foldmethod=marker: