rixmap 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: