rixmap 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,347 @@
1
+ // -*- coding: utf-8 -*-
2
+ /**
3
+ * Rixmap実装時のヘルパー関数定義.
4
+ * 一応グローバルに使えるようなものを定義しておきます.
5
+ *
6
+ * ※ API系列とはまた別
7
+ */
8
+ #pragma once
9
+ #include "common.hxx"
10
+ #include "color.hxx"
11
+ #include "palette.hxx"
12
+ #include "image.hxx"
13
+ #include "converter.hxx"
14
+ #include "interpolator.hxx"
15
+
16
+ namespace Rixmap {
17
+
18
+ /**
19
+ * ヘルパー関数名前空間
20
+ */
21
+ namespace Helper {
22
+ /**
23
+ * パレットデータを更新します.
24
+ *
25
+ * @param [Rixmap::PaletteData*] palette
26
+ * @param [long] offset
27
+ * @param [VALUE] object
28
+ * @return [bool] 更新できた場合はtrue. 更新できなかった場合はfalse
29
+ */
30
+ static bool UpdatePalette(Rixmap::PaletteData* palette, long offset, VALUE object) {
31
+ Rixmap::Color color(0, 0, 0, 255);
32
+
33
+ // カラーオブジェクトを解析
34
+ if (RB_TYPE_P(object, T_STRING)) {
35
+ // Color.newを使ってオブジェクトを構築
36
+ VALUE objColor = rb_funcall(cRixmapColor, rb_intern("new"), 1, object);
37
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(objColor);
38
+ color = data->getColor();
39
+ } else if (RTEST(rb_obj_is_kind_of(object, cRixmapColor))) {
40
+ // Rixmap::Colorそのもの
41
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(object);
42
+ color = data->getColor();
43
+ } else {
44
+ // 配列から
45
+ VALUE aryColor = rb_Array(object);
46
+ long arylen = RARRAY_LEN(aryColor);
47
+ VALUE* aryptr = RARRAY_PTR(aryColor);
48
+ VALUE objColor = rb_funcall2(cRixmapColor, rb_intern("new"), arylen, aryptr);
49
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(objColor);
50
+ color = data->getColor();
51
+ }
52
+
53
+ // 範囲チェック && 更新
54
+ // FIXME unsignedからsignedへの変換になってる
55
+ //long length = static_cast<long>(palette->getSize());
56
+ try {
57
+ palette->set(offset, color);
58
+ return true;
59
+ } catch (const std::out_of_range& e) {
60
+ // ( ´゚д゚`)エー
61
+ rb_warning(e.what());
62
+ return false;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * ピクセルを取得します.
68
+ */
69
+ static VALUE GetPixel(Rixmap::ImageData* image, int32_t xpos, int32_t ypos) {
70
+ // TODO imageがNULLの時対策
71
+
72
+ // 範囲チェック
73
+ if (image->isOutside(xpos, ypos)) {
74
+ // 範囲外はnil
75
+ return Qnil;
76
+ }
77
+
78
+ const Rixmap::ChannelArray& channels = image->getModeInfo().getChannels();
79
+ size_t nchannel = channels.size();
80
+
81
+ if (nchannel == 0) {
82
+ // ない場合はnil
83
+ return Qnil;
84
+ } else if (nchannel == 1) {
85
+ // 一つの場合は整数値で返す
86
+ Rixmap::Channel channel = channels.at(0);
87
+ uint8_t value = image->get(channel, xpos, ypos);
88
+ return INT2FIX(value);
89
+ } else {
90
+ // それ以外は配列で返す
91
+ VALUE pixel = rb_ary_new2(nchannel);
92
+ for (size_t i = 0; i < nchannel; i++) {
93
+ Rixmap::Channel channel = channels.at(i);
94
+ uint8_t value = image->get(channel, xpos, ypos);
95
+ rb_ary_store(pixel, i, INT2FIX(value));
96
+ }
97
+ return pixel;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * ピクセルを更新します.
103
+ */
104
+ static void UpdatePixel(Rixmap::ImageData* image, int32_t xpos, int32_t ypos, VALUE pixel) {
105
+ // TODO imageがNULLの時対策
106
+ const Rixmap::ModeInfo& mode = image->getModeInfo();
107
+
108
+ // 範囲チェック
109
+ if (image->isInside(xpos, ypos)) {
110
+ if (RB_TYPE_P(pixel, T_ARRAY)) {
111
+ // 配列
112
+ const Rixmap::ChannelArray& channels = mode.getChannels();
113
+ for (size_t i = 0; i < channels.size(); i++) {
114
+ Rixmap::Channel channel = channels.at(i);
115
+ VALUE objItem = rb_ary_entry(pixel, i);
116
+ if (!NIL_P(objItem)) {
117
+ int value = ROUND2BYTE(NUM2INT(rb_Integer(objItem)));
118
+ image->set(channel, xpos, ypos, static_cast<uint8_t>(value));
119
+ }
120
+ }
121
+ } else if (RB_TYPE_P(pixel, T_FIXNUM) || RB_TYPE_P(pixel, T_FLOAT)) {
122
+ //} else if (RB_TYPE_P(pixel, T_FIXNUM) /* || RB_TYPE_P(pixel, T_BIGNUM) */) {
123
+ // 数値
124
+ int value = ROUND2BYTE(NUM2INT(rb_Integer(pixel)));
125
+ const Rixmap::ChannelArray& channels = mode.getChannels();
126
+ for (auto it = channels.begin(); it != channels.end(); it++) {
127
+ image->set(*it, xpos, ypos, static_cast<uint8_t>(value));
128
+ }
129
+ } else if (RTEST(rb_obj_is_kind_of(pixel, cRixmapColor))) {
130
+ // カラーオブジェクト
131
+ Rixmap::ColorData* col = rixmap_unwrap<Rixmap::ColorData>(pixel);
132
+ switch (mode.getType()) {
133
+ case Rixmap::MODE_TYPE_INDEXED:
134
+ {
135
+ const Rixmap::PaletteData* pal = image->getPaletteData();
136
+ size_t off = 0;
137
+ if (pal == NULL) {
138
+ off = 0;
139
+ } else {
140
+ off = pal->closest(col->getColor());
141
+ }
142
+ image->set(Rixmap::Channel::PALETTE, xpos, ypos, static_cast<uint8_t>(off));
143
+ }
144
+ break;
145
+
146
+ case Rixmap::MODE_TYPE_GRAYSCALE:
147
+ image->set(Rixmap::Channel::LUMINANCE, xpos, ypos, col->getLuminance());
148
+ break;
149
+
150
+ case Rixmap::MODE_TYPE_RGB:
151
+ image->set(Rixmap::Channel::RED, xpos, ypos, col->getRed());
152
+ image->set(Rixmap::Channel::GREEN, xpos, ypos, col->getGreen());
153
+ image->set(Rixmap::Channel::BLUE, xpos, ypos, col->getBlue());
154
+ break;
155
+
156
+ default:
157
+ // DO NOTHING
158
+ break;
159
+ }
160
+
161
+ if (mode.hasAlpha()) {
162
+ image->set(Rixmap::Channel::ALPHA, xpos, ypos, col->getAlpha());
163
+ }
164
+ } else {
165
+ // 非対応(`・ω・´)
166
+ rb_raise(rb_eArgError, "unexpected pixel data type: %s", rb_obj_classname(pixel));
167
+ }
168
+ } else {
169
+ // 範囲外は何もしないお
170
+ rb_warning("point (%d, %d) is outside of image", xpos, ypos);
171
+ }
172
+ }
173
+
174
+ /**
175
+ * スキャンラインから指定したチャンネルのバンドデータを取得します.
176
+ */
177
+ static VALUE GetBand(Rixmap::ImageLineData* line, Rixmap::Channel channel) {
178
+ if (line->isValid()) {
179
+ Rixmap::ImageData* parent = line->getImageData();
180
+ const Rixmap::ModeInfo& mode = parent->getModeInfo();
181
+ if (mode.has(channel)) {
182
+ int32_t length = line->getLength();
183
+ int32_t lineno = line->getLineNumber();
184
+ uint8_t* band = parent->get(channel, lineno);
185
+ VALUE bytes = rb_ary_new2(length);
186
+ for (int32_t i = 0; i < length; i++) {
187
+ rb_ary_store(bytes, i, INT2FIX(band[i]));
188
+ }
189
+ return bytes;
190
+ } else {
191
+ return Qnil;
192
+ }
193
+ } else {
194
+ return Qnil;
195
+ }
196
+ }
197
+
198
+ /**
199
+ * スキャンライン内の指定チャンネルデータを更新します.
200
+ */
201
+ static bool UpdateBand(Rixmap::ImageLineData* line, Rixmap::Channel channel, VALUE argBand) {
202
+ if (line->isValid()) {
203
+ Rixmap::ImageData* parent = line->getImageData();
204
+ const Rixmap::ModeInfo& mode = parent->getModeInfo();
205
+ int32_t lineLength = line->getLength();
206
+ int32_t lineno = line->getLineNumber();
207
+ if (mode.has(channel)) {
208
+ // 型ごとにチェックして処理
209
+ if (RB_TYPE_P(argBand, T_ARRAY)) {
210
+ // 配列の場合はいったん全要素を調べる
211
+ long aryLength = RARRAY_LEN(argBand);
212
+ int32_t length = (aryLength < lineLength) ? aryLength : lineLength;
213
+ for (int32_t i = 0; i < length; i++) {
214
+ VALUE item = rb_ary_entry(argBand, i);
215
+ if (!RB_TYPE_P(item, T_FIXNUM)) {
216
+ rb_raise(rb_eArgError, "unexpected band data type in line data: %s", rb_obj_classname(item));
217
+ }
218
+ }
219
+
220
+ // OK
221
+ for (int32_t i = 0; i < length; i++) {
222
+ VALUE item = rb_ary_entry(argBand, i);
223
+ int byte = FIX2INT(item);
224
+ parent->set(channel, i, lineno, static_cast<uint8_t>(byte));
225
+ }
226
+ } else {
227
+ VALUE objBand = rb_String(argBand);
228
+ long nbyte = RSTRING_LEN(objBand);
229
+ char* bytes = StringValuePtr(objBand);
230
+ int32_t length = (nbyte < lineLength) ? nbyte : lineLength;
231
+ for (int32_t i = 0; i < length; i++) {
232
+ parent->set(channel, i, lineno, static_cast<uint8_t>(bytes[i]));
233
+ }
234
+ }
235
+ return true;
236
+ } else {
237
+ rb_warning("channel %c is not supported of this line", static_cast<char>(channel));
238
+ return false;
239
+ }
240
+ } else {
241
+ rb_warning("line is not valid");
242
+ return false;
243
+ }
244
+ }
245
+
246
+ /**
247
+ * 画像形式変換処理クラスオブジェクトを取得します.
248
+ */
249
+ static Rixmap::Converter* GetImageConverter(const Rixmap::Mode input, const Rixmap::Mode output) {
250
+ // コンバータオブジェクト
251
+ // FIXME これ大丈夫かしら
252
+ static Rixmap::RGB2GrayScaleConverter rgb2gray;
253
+ static Rixmap::RGB2IndexConverter rgb2index;
254
+ static Rixmap::GrayScale2RGBConverter gray2rgb;
255
+ static Rixmap::GrayScale2IndexConverter gray2index;
256
+ static Rixmap::Index2RGBConverter index2rgb;
257
+ static Rixmap::Index2GrayScaleConverter index2gray;
258
+
259
+ // チャンネル増減
260
+ static Rixmap::RGB2RGBConverter rgb2rgb;
261
+ static Rixmap::GrayScale2RGBConverter gray2gray;
262
+ static Rixmap::Index2IndexConverter index2index;
263
+
264
+ // 判別処理
265
+ switch (input) {
266
+ case Rixmap::Mode::INDEXED:
267
+ switch (output) {
268
+ case Rixmap::Mode::INDEXED:
269
+ return &index2index;
270
+
271
+ case Rixmap::Mode::RGB:
272
+ case Rixmap::Mode::RGBA:
273
+ return &index2rgb;
274
+
275
+ case Rixmap::Mode::GRAYSCALE:
276
+ case Rixmap::Mode::GRAYALPHA:
277
+ return &index2gray;
278
+
279
+ default:
280
+ // 何もできない
281
+ // (警告抑制)
282
+ break;
283
+ }
284
+ break;
285
+
286
+ case Rixmap::Mode::RGB:
287
+ case Rixmap::Mode::RGBA:
288
+ switch (output) {
289
+ case Rixmap::Mode::RGB:
290
+ case Rixmap::Mode::RGBA:
291
+ return &rgb2rgb;
292
+
293
+ case Rixmap::Mode::GRAYSCALE:
294
+ case Rixmap::Mode::GRAYALPHA:
295
+ return &rgb2gray;
296
+
297
+ case Rixmap::Mode::INDEXED:
298
+ return &rgb2index;
299
+
300
+ default:
301
+ // 何もできない
302
+ // (警告抑制)
303
+ break;
304
+ }
305
+ break;
306
+
307
+ case Rixmap::Mode::GRAYSCALE:
308
+ case Rixmap::Mode::GRAYALPHA:
309
+ switch (output) {
310
+ case Rixmap::Mode::GRAYSCALE:
311
+ case Rixmap::Mode::GRAYALPHA:
312
+ return &gray2gray;
313
+
314
+ case Rixmap::Mode::RGB:
315
+ case Rixmap::Mode::RGBA:
316
+ return &gray2rgb;
317
+
318
+ case Rixmap::Mode::INDEXED:
319
+ return &gray2index;
320
+
321
+ default:
322
+ // 何もできない
323
+ // (警告抑制)
324
+ break;
325
+ }
326
+ break;
327
+
328
+ default:
329
+ // 何もできない
330
+ // (警告抑制)
331
+ break;
332
+ }
333
+
334
+ // 見つからない
335
+ std::ostringstream err;
336
+ err << "image converter between "
337
+ << Rixmap::ModeInfo::GetModeName(input) << " and "
338
+ << Rixmap::ModeInfo::GetModeName(output) << " is not implemented.";
339
+ throw std::invalid_argument(err.str());
340
+ }
341
+ } /* Rixmap::Helper */
342
+ } /* Rixmap */
343
+
344
+
345
+ //============================================================================//
346
+ // $Id: helper.hxx,v 753dbf70cab3 2014/05/16 16:13:38 chikuchikugonzalez $
347
+ // vim: set sts=4 ts=4 sw=4 expandtab foldmethod=marker: