rixmap 0.1.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,3209 @@
1
+ // -*- coding: utf-8 -*-
2
+ /**
3
+ * Rixmapコア実装.
4
+ */
5
+ #include "rixmapcore.hxx"
6
+
7
+ //----------------------------------------------------------------------------//
8
+ // オブジェクトプール実装
9
+ //----------------------------------------------------------------------------//
10
+ /**
11
+ * 画像形式オブジェクトプール
12
+ */
13
+ class RixmapModePool {/*{{{*/
14
+ private: // 非公開クラスメンバ
15
+ static std::map<Rixmap::Mode, VALUE> _pool;
16
+
17
+ public: // 公開クラスメンバ
18
+ /**
19
+ * オブジェクトプールから取得します.
20
+ */
21
+ static inline VALUE Get(Rixmap::Mode mode) {
22
+ auto found = _pool.find(mode);
23
+ if (found != _pool.end()) {
24
+ return found->second;
25
+ } else {
26
+ volatile VALUE instance = rb_obj_alloc(cRixmapMode);
27
+ Rixmap::ModeData* data = rixmap_unwrap<Rixmap::ModeData>(instance);
28
+ data->setMode(mode);
29
+
30
+ rb_gc_register_mark_object(instance);
31
+ _pool[mode] = instance;
32
+
33
+ return instance;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * オブジェクトプールからオブジェクトを削除します.
39
+ */
40
+ static inline void Remove(Rixmap::Mode mode) {
41
+ auto found = _pool.find(mode);
42
+ if (found != _pool.end()) {
43
+ _pool.erase(found);
44
+ }
45
+ }
46
+
47
+ private: // 非公開コンストラクタ
48
+ RixmapModePool() {}
49
+
50
+ public: // 仮想デストラクタ
51
+ virtual ~RixmapModePool() = 0;
52
+ };/*}}}*/
53
+
54
+ /**
55
+ * カラーオブジェクトプール
56
+ */
57
+ class RixmapColorPool {/*{{{*/
58
+ private: // 非公開クラスメンバ
59
+ static std::map<uint32_t, VALUE> _pool;
60
+
61
+ public: // 公開クラスメンバ
62
+ /**
63
+ * オブジェクトプールから取得します.
64
+ */
65
+ static inline VALUE Get(const Rixmap::Color& color) {
66
+ uint32_t value = color.getValue();
67
+ auto found = _pool.find(value);
68
+ if (found != _pool.end()) {
69
+ return found->second;
70
+ } else {
71
+ volatile VALUE instance = rb_obj_alloc(cRixmapColor);
72
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(instance);
73
+ *data = color;
74
+ rb_gc_register_mark_object(instance);
75
+ _pool[value] = instance;
76
+ return instance;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * オブジェクトプールから削除します.
82
+ */
83
+ static inline void Remove(const Rixmap::Color& color) {
84
+ uint32_t value = color.getValue();
85
+ auto found = _pool.find(value);
86
+ if (found != _pool.end()) {
87
+ _pool.erase(found);
88
+ }
89
+ }
90
+
91
+ private: // 非公開コンストラクタ
92
+ RixmapColorPool() {}
93
+
94
+ public: // 仮想デストラクタ
95
+ virtual ~RixmapColorPool() = 0;
96
+ };/*}}}*/
97
+
98
+ // プール実体定義
99
+ std::map<Rixmap::Mode, VALUE> RixmapModePool::_pool;
100
+ std::map<uint32_t, VALUE> RixmapColorPool::_pool;
101
+
102
+ //----------------------------------------------------------------------------//
103
+ // オブジェクト実体定義
104
+ //----------------------------------------------------------------------------//
105
+ VALUE mRixmap = Qnil;
106
+ VALUE cRixmapBinary = Qnil;
107
+ VALUE cRixmapMode = Qnil;
108
+ VALUE cRixmapColor = Qnil;
109
+ VALUE cRixmapPalette = Qnil;
110
+ VALUE cRixmapImage = Qnil;
111
+ VALUE cRixmapImageLine = Qnil;
112
+
113
+ //----------------------------------------------------------------------------//
114
+ // ヘルパー関数
115
+ //----------------------------------------------------------------------------//
116
+ namespace RixmapHelper {/*{{{*/
117
+ /**
118
+ * 指定色数のパレットを作成します.
119
+ */
120
+ static VALUE CreatePalette(size_t size = 256) {
121
+ VALUE args[1] = {
122
+ ULONG2NUM(size)
123
+ };
124
+ return rb_class_new_instance(1, args, cRixmapPalette);
125
+ }
126
+
127
+ /**
128
+ * スキャンラインオブジェクトを作成します.
129
+ */
130
+ static VALUE CreateImageLine(VALUE image, int32_t lineno) {
131
+ VALUE args[2] = {
132
+ image,
133
+ LONG2NUM(lineno)
134
+ };
135
+ return rb_class_new_instance(2, args, cRixmapImageLine);
136
+ }
137
+
138
+ /**
139
+ * ピクセルを取得します.
140
+ */
141
+ static VALUE GetPixel(Rixmap::ImageData* image, int32_t xpos, int32_t ypos) {
142
+ // TODO imageがNULLの時対策
143
+
144
+ // 範囲チェック
145
+ if (image->isOutside(xpos, ypos)) {
146
+ // 範囲外はnil
147
+ return Qnil;
148
+ }
149
+
150
+ const Rixmap::ChannelArray& channels = image->getModeInfo().getChannels();
151
+ size_t nchannel = channels.size();
152
+
153
+ if (nchannel == 0) {
154
+ // ない場合はnil
155
+ return Qnil;
156
+ } else if (nchannel == 1) {
157
+ // 一つの場合は整数値で返す
158
+ Rixmap::Channel channel = channels.at(0);
159
+ uint8_t value = image->get(channel, xpos, ypos);
160
+ return INT2FIX(value);
161
+ } else {
162
+ // それ以外は配列で返す
163
+ VALUE pixel = rb_ary_new2(nchannel);
164
+ for (size_t i = 0; i < nchannel; i++) {
165
+ Rixmap::Channel channel = channels.at(i);
166
+ uint8_t value = image->get(channel, xpos, ypos);
167
+ rb_ary_store(pixel, i, INT2FIX(value));
168
+ }
169
+ return pixel;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * ピクセルを更新します.
175
+ */
176
+ static void UpdatePixel(Rixmap::ImageData* image, int32_t xpos, int32_t ypos, VALUE pixel) {
177
+ // TODO imageがNULLの時対策
178
+ const Rixmap::ModeInfo& mode = image->getModeInfo();
179
+
180
+ // 範囲チェック
181
+ if (image->isInside(xpos, ypos)) {
182
+ if (RB_TYPE_P(pixel, T_ARRAY)) {
183
+ // 配列
184
+ const Rixmap::ChannelArray& channels = mode.getChannels();
185
+ for (size_t i = 0; i < channels.size(); i++) {
186
+ Rixmap::Channel channel = channels.at(i);
187
+ VALUE objItem = rb_ary_entry(pixel, i);
188
+ if (!NIL_P(objItem)) {
189
+ int value = ROUND2BYTE(NUM2INT(rb_Integer(objItem)));
190
+ image->set(channel, xpos, ypos, static_cast<uint8_t>(value));
191
+ }
192
+ }
193
+ } else if (RB_TYPE_P(pixel, T_FIXNUM) || RB_TYPE_P(pixel, T_FLOAT)) {
194
+ //} else if (RB_TYPE_P(pixel, T_FIXNUM) /* || RB_TYPE_P(pixel, T_BIGNUM) */) {
195
+ // 数値
196
+ int value = ROUND2BYTE(NUM2INT(rb_Integer(pixel)));
197
+ const Rixmap::ChannelArray& channels = mode.getChannels();
198
+ for (auto it = channels.begin(); it != channels.end(); it++) {
199
+ image->set(*it, xpos, ypos, static_cast<uint8_t>(value));
200
+ }
201
+ } else if (RTEST(rb_obj_is_kind_of(pixel, cRixmapColor))) {
202
+ // カラーオブジェクト
203
+ Rixmap::ColorData* col = rixmap_unwrap<Rixmap::ColorData>(pixel);
204
+ switch (mode.getType()) {
205
+ case Rixmap::MODE_TYPE_INDEXED:
206
+ {
207
+ const Rixmap::PaletteData* pal = image->getPaletteData();
208
+ size_t off = 0;
209
+ if (pal == NULL) {
210
+ off = 0;
211
+ } else {
212
+ off = pal->closest(col->getColor());
213
+ }
214
+ image->set(Rixmap::Channel::PALETTE, xpos, ypos, static_cast<uint8_t>(off));
215
+ }
216
+ break;
217
+
218
+ case Rixmap::MODE_TYPE_GRAYSCALE:
219
+ image->set(Rixmap::Channel::LUMINANCE, xpos, ypos, col->getLuminance());
220
+ break;
221
+
222
+ case Rixmap::MODE_TYPE_RGB:
223
+ image->set(Rixmap::Channel::RED, xpos, ypos, col->getRed());
224
+ image->set(Rixmap::Channel::GREEN, xpos, ypos, col->getGreen());
225
+ image->set(Rixmap::Channel::BLUE, xpos, ypos, col->getBlue());
226
+ break;
227
+
228
+ default:
229
+ // DO NOTHING
230
+ break;
231
+ }
232
+
233
+ if (mode.hasAlpha()) {
234
+ image->set(Rixmap::Channel::ALPHA, xpos, ypos, col->getAlpha());
235
+ }
236
+ } else {
237
+ // 非対応(`・ω・´)
238
+ rb_raise(rb_eArgError, "unexpected pixel data type: %s", rb_obj_classname(pixel));
239
+ }
240
+ } else {
241
+ // 範囲外は何もしないお
242
+ rb_warning("point (%d, %d) is outside of image", xpos, ypos);
243
+ }
244
+ }
245
+
246
+ /**
247
+ * スキャンラインから指定したチャンネルのバンドデータを取得します.
248
+ */
249
+ static VALUE GetBand(Rixmap::ImageLineData* line, Rixmap::Channel channel) {
250
+ if (line->isValid()) {
251
+ Rixmap::ImageData* parent = line->getImageData();
252
+ const Rixmap::ModeInfo& mode = parent->getModeInfo();
253
+ if (mode.has(channel)) {
254
+ int32_t length = line->getLength();
255
+ int32_t lineno = line->getLineNumber();
256
+ uint8_t* band = parent->get(channel, lineno);
257
+ VALUE bytes = rb_ary_new2(length);
258
+ for (int32_t i = 0; i < length; i++) {
259
+ rb_ary_store(bytes, i, INT2FIX(band[i]));
260
+ }
261
+ return bytes;
262
+ } else {
263
+ return Qnil;
264
+ }
265
+ } else {
266
+ return Qnil;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * スキャンライン内の指定チャンネルデータを更新します.
272
+ */
273
+ static bool UpdateBand(Rixmap::ImageLineData* line, Rixmap::Channel channel, VALUE argBand) {
274
+ if (line->isValid()) {
275
+ Rixmap::ImageData* parent = line->getImageData();
276
+ const Rixmap::ModeInfo& mode = parent->getModeInfo();
277
+ int32_t lineLength = line->getLength();
278
+ int32_t lineno = line->getLineNumber();
279
+ if (mode.has(channel)) {
280
+ // 型ごとにチェックして処理
281
+ if (RB_TYPE_P(argBand, T_ARRAY)) {
282
+ // 配列の場合はいったん全要素を調べる
283
+ long aryLength = RARRAY_LEN(argBand);
284
+ int32_t length = (aryLength < lineLength) ? aryLength : lineLength;
285
+ for (int32_t i = 0; i < length; i++) {
286
+ VALUE item = rb_ary_entry(argBand, i);
287
+ if (!RB_TYPE_P(item, T_FIXNUM)) {
288
+ rb_raise(rb_eArgError, "unexpected band data type in line data: %s", rb_obj_classname(item));
289
+ }
290
+ }
291
+
292
+ // OK
293
+ for (int32_t i = 0; i < length; i++) {
294
+ VALUE item = rb_ary_entry(argBand, i);
295
+ int byte = FIX2INT(item);
296
+ parent->set(channel, i, lineno, static_cast<uint8_t>(byte));
297
+ }
298
+ } else {
299
+ VALUE objBand = rb_String(argBand);
300
+ long nbyte = RSTRING_LEN(objBand);
301
+ char* bytes = StringValuePtr(objBand);
302
+ int32_t length = (nbyte < lineLength) ? nbyte : lineLength;
303
+ for (int32_t i = 0; i < length; i++) {
304
+ parent->set(channel, i, lineno, static_cast<uint8_t>(bytes[i]));
305
+ }
306
+ }
307
+ return true;
308
+ } else {
309
+ rb_warning("channel %c is not supported of this line", static_cast<char>(channel));
310
+ return false;
311
+ }
312
+ } else {
313
+ rb_warning("line is not valid");
314
+ return false;
315
+ }
316
+ }
317
+ }/*}}}*/
318
+
319
+ //----------------------------------------------------------------------------//
320
+ // ライブラリ実装
321
+ //----------------------------------------------------------------------------//
322
+ /* Rixmap::Binary {{{ */
323
+ static void Binary_Free(Rixmap::BinaryData* data) {
324
+ rixmap_xdelete(data);
325
+ }
326
+
327
+ static VALUE Binary_Alloc(VALUE klass) {
328
+ Rixmap::BinaryData* data = rixmap_xnew<Rixmap::BinaryData>();
329
+ return Data_Wrap_Struct(klass, RIXMAP_DEFAULT_MARK, Binary_Free, data);
330
+ }
331
+
332
+ /**
333
+ * バイナリ配列オブジェクトを初期化します
334
+ *
335
+ * @overload initialize(size = 0, value = 0)
336
+ * 指定したサイズのバイナリ配列を作成します. 配列内はすべて `value` で初期化されます.
337
+ *
338
+ * @param [Integer] size バイナリ配列サイズ
339
+ * @param [Integer] value 初期値
340
+ * @return [void]
341
+ *
342
+ * @overload initialize(ary)
343
+ * 指定された配列を複製した、新しいバイナリ配列として初期化します.
344
+ *
345
+ * @param [Array<Integer>,Rixmap::Binary] ary 元の配列
346
+ * @return [void]
347
+ *
348
+ * @overload initialize(bytes)
349
+ * 指定されたバイナリ文字列を元に、バイナリ配列を初期化します.
350
+ *
351
+ * @param [String] bytes 元にする文字列
352
+ * @return [void]
353
+ */
354
+ static VALUE Binary_initialize(int argc, VALUE* argv, VALUE self) {
355
+ VALUE arg0, arg1;
356
+ rb_scan_args(argc, argv, "02", &arg0, &arg1);
357
+
358
+ // 自分ポインタ
359
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
360
+ _this->clear(); // 何も入ってないと思うけど念のため
361
+
362
+ // 型別に初期化処理を分岐
363
+ if (!NIL_P(arg0)) {
364
+ // 最初の引数有
365
+ if (RB_TYPE_P(arg0, T_ARRAY) || rb_respond_to(arg0, rb_intern("to_ary"))) {
366
+ // 配列型
367
+ VALUE aryItems = rb_Array(arg0);
368
+ long nitem = RARRAY_LEN(aryItems);
369
+ for (long i = 0; i < nitem; i++) {
370
+ VALUE item = rb_Integer(rb_ary_entry(aryItems, i));
371
+ uint8_t value = static_cast<uint8_t>(NUM2INT(item));
372
+ _this->push_back(value);
373
+ }
374
+ } else if (RB_TYPE_P(arg0, T_STRING) || rb_respond_to(arg0, rb_intern("to_str"))) {
375
+ // 文字列型
376
+ VALUE strItems = rb_String(arg0);
377
+ long nitem = RSTRING_LEN(strItems);
378
+ const char* items = StringValuePtr(strItems);
379
+ _this->insert(_this->end(), &(items[0]), &(items[nitem]));
380
+ } else {
381
+ // サイズ指定っぽい
382
+ size_t size = NUM2ULONG(rb_Integer(arg0));
383
+
384
+ // リサイズ
385
+ _this->resize(size);
386
+
387
+ // 第二引数ある?
388
+ if (!NIL_P(arg1)) {
389
+ // 初期値
390
+ uint8_t value = static_cast<uint8_t>(NUM2INT(rb_Integer(arg1)));
391
+ for (auto it = _this->begin(); it != _this->end(); it++) {
392
+ *it = value;
393
+ }
394
+ }
395
+ }
396
+ }
397
+
398
+ return self;
399
+ }
400
+
401
+ /**
402
+ * バイナリ配列の複製を初期化します.
403
+ *
404
+ * @param [Object] obj 複製元
405
+ * @return [void]
406
+ * @see Object#clone
407
+ * @see Object#dup
408
+ */
409
+ static VALUE Binary_initializeCopy(VALUE self, VALUE argObject) {
410
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
411
+ Rixmap::BinaryData* _that = rixmap_unwrap<Rixmap::BinaryData>(argObject);
412
+
413
+ // 自分を消去して追加
414
+ _this->clear();
415
+ _this->insert(_this->end(), _that->begin(), _that->end());
416
+
417
+ return self;
418
+ }
419
+
420
+ /**
421
+ * バイナリ配列の内容を`times`回繰り返した新しいバイナリ配列を返します.
422
+ *
423
+ * @param [Integer] times 繰り返す回数
424
+ * @return [Rixmap::Binary] 繰り返されたバイナリ配列
425
+ * @see Array#*
426
+ */
427
+ static VALUE Binary_operatorMul(VALUE self, VALUE argTimes) {
428
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
429
+ long times = NUM2LONG(rb_Integer(argTimes));
430
+
431
+ if (times < 0) {
432
+ rb_raise(rb_eArgError, "negative repeat times is not supported: %ld", times);
433
+ }
434
+
435
+ // 新しいバイナリ配列を確保
436
+ VALUE objResult = rb_class_new_instance(0, NULL, cRixmapBinary);
437
+ Rixmap::BinaryData* _result = rixmap_unwrap<Rixmap::BinaryData>(objResult);
438
+
439
+ // 指定回数だけ複製
440
+ for (long i = 0; i < times; i++) {
441
+ _result->insert(_result->end(), _this->begin(), _this->end());
442
+ }
443
+
444
+ // 戻る
445
+ return objResult;
446
+ }
447
+
448
+ /**
449
+ * バイナリ配列の末尾に別の配列を連結した新しいバイナリ配列を返します.
450
+ *
451
+ * @param [Array,String,Rixmap::Binary] other 連結する配列
452
+ * @return [Rixmap::Binary] 連結後の新しいバイナリ配列
453
+ * @raise TypeError `other` が配列ではなかった場合
454
+ * @see Array#+
455
+ */
456
+ static VALUE Binary_operatorAdd(VALUE self, VALUE argOther) {
457
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
458
+
459
+ // 返却用オブジェクトを確保
460
+ VALUE objResult = rb_class_new_instance(0, NULL, cRixmapBinary);
461
+ Rixmap::BinaryData* _result = rixmap_unwrap<Rixmap::BinaryData>(objResult);
462
+
463
+ // 型を判定
464
+ if (RTEST(rb_obj_is_kind_of(argOther, cRixmapBinary))) {
465
+ Rixmap::BinaryData* _other = rixmap_unwrap<Rixmap::BinaryData>(argOther);
466
+ _result->insert(_result->end(), _this->begin(), _this->end());
467
+ _result->insert(_result->end(), _other->begin(), _other->end());
468
+ } else if (RB_TYPE_P(argOther, T_ARRAY) || rb_respond_to(argOther, rb_intern("to_ary"))) {
469
+ VALUE aryItems = rb_Array(argOther);
470
+ long nitem = RARRAY_LEN(aryItems);
471
+ std::vector<uint8_t> items;
472
+ for (long i = 0; i < nitem; i++) {
473
+ int item = NUM2INT(rb_ary_entry(aryItems, i));
474
+ items.push_back(static_cast<uint8_t>(item));
475
+ }
476
+ _result->insert(_result->end(), _this->begin(), _this->end());
477
+ _result->insert(_result->end(), items.begin(), items.end());
478
+ } else if (RB_TYPE_P(argOther, T_STRING) || rb_respond_to(argOther, rb_intern("to_str"))) {
479
+ VALUE strItems = rb_String(argOther);
480
+ long nitem = RSTRING_LEN(strItems);
481
+ const char* items = StringValuePtr(strItems);
482
+
483
+ _result->insert(_result->end(), _this->begin(), _this->end());
484
+ _result->insert(_result->end(), &(items[0]), &(items[nitem]));
485
+ } else {
486
+ rb_raise(rb_eTypeError, "unexpected object type: %s", rb_obj_classname(argOther));
487
+ }
488
+
489
+ return objResult;
490
+ }
491
+
492
+ /**
493
+ * バイナリ配列の末尾に整数値を追加します.
494
+ *
495
+ * @param [Integer] value 追加する整数値
496
+ * @return [Rixmap::Binary] selfを返します.
497
+ * @raise TypeError `value` が整数値でない場合
498
+ * @see Array#<<
499
+ */
500
+ static VALUE Binary_operatorLShift(VALUE self, VALUE argValue) {
501
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
502
+ VALUE objValue = rb_Integer(argValue);
503
+ uint8_t value = static_cast<uint8_t>(NUM2INT(objValue));
504
+ _this->push_back(value);
505
+ return self;
506
+ }
507
+
508
+ /**
509
+ * バイナリ配列とほかの配列を比較します.
510
+ *
511
+ * @param [Object] other 比較する配列
512
+ * @return [Integer] 比較結果を数値で返します.
513
+ * - 負数の場合 ==> `self`が`other`より小さい
514
+ * - `0`の場合 ==> `self`と`other`が等しい
515
+ * - 正数の場合 ==> `self`が`other`より大きい
516
+ * - `nil`の場合 == > `other`が配列でない
517
+ * @see Array#<=>
518
+ */
519
+ static VALUE Binary_operatorCompare(VALUE self, VALUE argOther) {
520
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
521
+
522
+ // 型を判定
523
+ if (RTEST(rb_obj_is_kind_of(argOther, cRixmapBinary))) {
524
+ Rixmap::BinaryData* _other = rixmap_unwrap<Rixmap::BinaryData>(argOther);
525
+ size_t thisSize = _this->size();
526
+ size_t otherSize = _other->size();
527
+ size_t i = 0, j = 0;
528
+ for (; i < thisSize && j < otherSize; i++, j++) {
529
+ uint8_t lvalue = _this->at(i);
530
+ uint8_t rvalue = _other->at(i);
531
+ if (!(lvalue == rvalue)) {
532
+ return INT2FIX(static_cast<int>(lvalue) - static_cast<int>(rvalue));
533
+ }
534
+ }
535
+ if (i == thisSize && j == otherSize) {
536
+ return INT2FIX(0);
537
+ } else {
538
+ if (thisSize > otherSize) {
539
+ return INT2FIX(1);
540
+ } else {
541
+ return INT2FIX(-1);
542
+ }
543
+ }
544
+ } else if (RB_TYPE_P(argOther, T_ARRAY) || rb_respond_to(argOther, rb_intern("to_ary"))) {
545
+ VALUE aryItems = rb_Array(argOther);
546
+ size_t thisSize = _this->size();
547
+ size_t otherSize = RARRAY_LEN(aryItems);
548
+ size_t i = 0, j = 0;
549
+ for (; i < thisSize && j < otherSize; i++, j++) {
550
+ uint8_t lvalue = _this->at(i);
551
+ uint8_t rvalue = static_cast<uint8_t>(NUM2INT(rb_Integer(rb_ary_entry(aryItems, j))));
552
+ if (!(lvalue == rvalue)) {
553
+ return INT2FIX(static_cast<int>(lvalue) - static_cast<int>(rvalue));
554
+ }
555
+ }
556
+ if (i == thisSize && j == otherSize) {
557
+ return INT2FIX(0);
558
+ } else {
559
+ if (thisSize > otherSize) {
560
+ return INT2FIX(1);
561
+ } else {
562
+ return INT2FIX(-1);
563
+ }
564
+ }
565
+ } else if (RB_TYPE_P(argOther, T_STRING) || rb_respond_to(argOther, rb_intern("to_str"))) {
566
+ VALUE strItems = rb_String(argOther);
567
+ size_t thisSize = _this->size();
568
+ size_t otherSize = RSTRING_LEN(strItems);
569
+ const char* items = StringValuePtr(strItems);
570
+
571
+ size_t i = 0, j = 0;
572
+ for (; i < thisSize && j < otherSize; i++, j++) {
573
+ uint8_t lvalue = _this->at(i);
574
+ uint8_t rvalue = static_cast<uint8_t>(items[j]);
575
+ if (!(lvalue == rvalue)) {
576
+ return INT2FIX(static_cast<int>(lvalue) - static_cast<int>(rvalue));
577
+ }
578
+ }
579
+ if (i == thisSize && j == otherSize) {
580
+ return INT2FIX(0);
581
+ } else {
582
+ if (thisSize > otherSize) {
583
+ return INT2FIX(1);
584
+ } else {
585
+ return INT2FIX(-1);
586
+ }
587
+ }
588
+ } else {
589
+ return Qnil;
590
+ }
591
+ }
592
+
593
+ /**
594
+ * バイナリ配列とほかのオブジェクトとを比較し、同じバイナリ配列か銅貨を返します.
595
+ *
596
+ * @param [Rixmap::Binary] other 比較対象のバイナリ配列
597
+ */
598
+ static VALUE Binary_operatorEquals(VALUE self, VALUE argOther) {
599
+ if (!RTEST(rb_obj_is_kind_of(argOther, cRixmapBinary))) {
600
+ return Qfalse;
601
+ }
602
+
603
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
604
+ Rixmap::BinaryData* _that = rixmap_unwrap<Rixmap::BinaryData>(argOther);
605
+
606
+ if (*_this == *_that) {
607
+ return Qtrue;
608
+ } else {
609
+ return Qfalse;
610
+ }
611
+ }
612
+
613
+ /**
614
+ * @overload [](offset)
615
+ * 指定オフセットのバイトデータを取得します.
616
+ *
617
+ * オフセットが負数の場合は末尾からの逆向き指定と解釈します.
618
+ * オフセットが範囲外の場合は`nil`を返します.
619
+ *
620
+ * @param [Integer] offset 取得オフセット
621
+ * @return [Integer,nil] バイトデータ
622
+ *
623
+ * @overload [](offset, length)
624
+ * `offset`から最大で`length`個の要素を持った部分バイナリ配列を取得します.
625
+ *
626
+ * オフセットが負数の場合は末尾からの逆向き指定と解釈します.
627
+ * 戻り値については以下のルールになっています.
628
+ *
629
+ * - `length`が負数の場合は`nil`
630
+ * - `offset`が範囲外の場合は`nil`
631
+ * - ただし、`offset`が #length と同じだった場合は空配列
632
+ *
633
+ * @param [Integer] offset 取得開始位置
634
+ * @param [Integer] length 取得する最大要素数
635
+ * @return [Rixmap::Binary,nil] 指定範囲のデータを含む部分配列
636
+ *
637
+ * @overload [](range)
638
+ * 指定された範囲オブジェクトの範囲内の要素からなる部分バイナリ配列を返します.
639
+ *
640
+ * 戻り値は以下のようになります.
641
+ *
642
+ * - Range#first が配列の範囲外の場合は`nil`
643
+ * - Range#first が Raneg#end より後ろの場合は空の配列
644
+ *
645
+ * @param [Range] range 取得する範囲
646
+ * @return [Rixmap::Binary] 指定範囲のバイナリ配列
647
+ *
648
+ * @see Array#[]
649
+ */
650
+ static VALUE Binary_offsetGet(int argc, VALUE* argv, VALUE self) {
651
+ // 引数
652
+ VALUE argOffset, argLength;
653
+ rb_scan_args(argc, argv, "11", &argOffset, &argLength);
654
+
655
+ // 自分
656
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
657
+
658
+ // 長さを long として取得しておく
659
+ // FIXME 危険('A`)
660
+ long dataLength = static_cast<long>(_this->size());
661
+
662
+ // 型別に処理
663
+ if (RTEST(rb_obj_is_kind_of(argOffset, rb_cRange))) {
664
+ // 範囲オブジェクトなので、まず先頭と末尾を取得する
665
+ VALUE objFirst, objLast;
666
+ int excludeLast = 0;
667
+ rb_range_values(argOffset, &objFirst, &objLast, &excludeLast);
668
+
669
+ // 整数値へ
670
+ long first = NUM2LONG(objFirst);
671
+ long last = NUM2LONG(objLast);
672
+
673
+ // 負数の場合は、後ろからのオフセットへ変換
674
+ if (first < 0) {
675
+ first += dataLength;
676
+ }
677
+ if (last < 0) {
678
+ last += dataLength;
679
+ }
680
+
681
+ // 終端を含まない場合は縮める
682
+ if (excludeLast) {
683
+ last--;
684
+ }
685
+
686
+ // 範囲チェック
687
+ if (first < 0 || first > dataLength) {
688
+ // 先頭が範囲外
689
+ return Qnil;
690
+ } else {
691
+ VALUE objResult = rb_class_new_instance(0, NULL, cRixmapBinary);
692
+ Rixmap::BinaryData* _result = rixmap_unwrap<Rixmap::BinaryData>(objResult);
693
+ for (long i = first; i < last && i < dataLength; i++) {
694
+ _result->push_back(_this->at(i));
695
+ }
696
+ return objResult;
697
+ }
698
+ } else {
699
+ // 整数値 (にする)
700
+ VALUE numOffset = rb_Integer(argOffset);
701
+ long offset = NUM2LONG(numOffset);
702
+
703
+ // 負数の場合は後ろからのオフセットとしてずらす
704
+ if (offset < 0) {
705
+ offset += dataLength;
706
+ }
707
+
708
+ // 範囲外かどうか (1)
709
+ if (offset < 0) {
710
+ return Qnil;
711
+ }
712
+
713
+ if (NIL_P(argLength)) {
714
+ // オフセットのみ
715
+ if (offset < dataLength) { // 範囲外チェック (2.1)
716
+ return INT2FIX(_this->at(offset));
717
+ } else {
718
+ return Qnil;
719
+ }
720
+ } else {
721
+ // 長さある
722
+
723
+ // 範囲外チェック (2.2)
724
+ if (offset > dataLength) {
725
+ // NOTE Arrayと挙動合わせたらこんなことになった
726
+ return Qnil;
727
+ }
728
+
729
+ VALUE numLength = rb_Integer(argLength);
730
+ long length = NUM2LONG(numLength);
731
+
732
+ // 戻り値用
733
+ VALUE objResult = rb_class_new_instance(0, NULL, cRixmapBinary);
734
+ Rixmap::BinaryData* _result = rixmap_unwrap<Rixmap::BinaryData>(objResult);
735
+
736
+ // 追加
737
+ for (long i = 0, j = offset; i < length && j < dataLength; i++, j++) {
738
+ _result->push_back(_this->at(j));
739
+ }
740
+
741
+ return objResult;
742
+ }
743
+ }
744
+ }
745
+
746
+ /**
747
+ * @overload []=(offset, value)
748
+ * 指定位置のバイトデータを `value` に設定します.
749
+ *
750
+ * `offset` が #length より後ろだった場合は配列自体を拡張します.
751
+ *
752
+ * @param [Integer] offset 設定位置
753
+ * @param [Integer] value 設定するバイトデータ
754
+ * @return [void]
755
+ *
756
+ * @overload []=(offset, length, values)
757
+ * `offset`から`length`個の要素を`values`で置き換えます.
758
+ *
759
+ * `values`は配列または配列に変換できる値であり、それ以外は要素数が1の配列として扱われます.
760
+ * また、`length`が0の場合は`offset`の前に`values`を挿入します.
761
+ *
762
+ * @param [Integer] offset 開始オフセット
763
+ * @param [Integer] length 置き換える長さ
764
+ * @param [Array,Rixmap::Binary] values 置き換える値
765
+ * @return [void]
766
+ *
767
+ * @overload []=(range, values)
768
+ * 指定範囲を`values`で置き換えます.
769
+ *
770
+ * @param [Range] range 置き換える範囲
771
+ * @param [Array,Rixmap::Binary] values 置き換える値
772
+ * @return [void]
773
+ *
774
+ * @see Array#[]=
775
+ */
776
+ static VALUE Binary_offsetSet(int argc, VALUE* argv, VALUE self) {
777
+ // 引数取得
778
+ VALUE arg0, arg1, arg2; // arg1 or arg2 が設定する値
779
+ rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2);
780
+
781
+ // 自分情報
782
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
783
+ long dataLength = static_cast<long>(_this->size());
784
+
785
+ // 更新情報
786
+ long start = -1;
787
+ long count = -1;
788
+ VALUE objValues = Qnil;
789
+
790
+ // 型チェック (Rangeかそれ以外か)
791
+ if (RTEST(rb_obj_is_kind_of(arg0, rb_cRange))) {
792
+ // Range (arg1が値)
793
+ objValues = arg1;
794
+
795
+ // 範囲オブジェクトを展開
796
+ VALUE objFirst = Qnil, objLast = Qnil;
797
+ int excludeLast = 0;
798
+ rb_range_values(arg0, &objFirst, &objLast, &excludeLast);
799
+
800
+ // Ruby Obj -> C Type
801
+ long first = NUM2LONG(objFirst);
802
+ long last = NUM2LONG(objLast);
803
+ if (first < 0) {
804
+ first += dataLength;
805
+
806
+ // 範囲外チェック
807
+ if (first < 0) {
808
+ // NOTE Arrayと挙動合わせた
809
+ VALUE strRange = rb_inspect(arg0);
810
+ rb_raise(rb_eRangeError, "%s is out of range", StringValueCStr(strRange));
811
+ }
812
+ }
813
+ if (last < 0) {
814
+ last += dataLength;
815
+ }
816
+ if (excludeLast) {
817
+ last--;
818
+ }
819
+
820
+ // 範囲
821
+ start = first;
822
+ count = (last - start) + 1;
823
+ } else {
824
+ // それ以外
825
+ VALUE objOffset = rb_Integer(arg0);
826
+ long offset = NUM2LONG(objOffset);
827
+ if (offset < 0) {
828
+ // 範囲外チェック
829
+ // NOTE Arrayと挙動合わせた
830
+ if ((offset + dataLength) < 0) {
831
+ rb_raise(rb_eIndexError, "index %ld too small for array; minimum: -%ld", offset, dataLength);
832
+ }
833
+ offset += dataLength;
834
+ }
835
+ start = offset;
836
+
837
+ // 第2引数と第3引数の関係を処理
838
+ if (NIL_P(arg2)) {
839
+ // 第3引数なし => arg1がvalue
840
+ objValues = arg1;
841
+ count = 1; // 長さ1
842
+ } else {
843
+ // 第3引数あり => arg2がvalue
844
+ objValues = arg2;
845
+ count = NUM2LONG(rb_Integer(arg1));
846
+ }
847
+ }
848
+
849
+ // 値チェック
850
+ if (NIL_P(objValues)) {
851
+ rb_raise(rb_eArgError, "unexpected value type: %s", rb_obj_classname(objValues));
852
+ }
853
+
854
+ /* 以下変更処理 */
855
+ // 値をC配列へ
856
+ std::deque<uint8_t> input;
857
+ if (RTEST(rb_obj_is_kind_of(objValues, cRixmapBinary))) {
858
+ // Rixmap::Binary
859
+ Rixmap::BinaryData* values = rixmap_unwrap<Rixmap::BinaryData>(objValues);
860
+ input.insert(input.end(), values->begin(), values->end());
861
+ } else if (RB_TYPE_P(objValues, T_ARRAY) || rb_respond_to(objValues, rb_intern("to_ary"))) {
862
+ // Ruby配列
863
+ VALUE aryValues = rb_Array(objValues);
864
+ long aryLength = RARRAY_LEN(aryValues);
865
+ for (long i = 0; i < aryLength; i++) {
866
+ VALUE aryItem = rb_Integer(rb_ary_entry(aryValues, i));
867
+ input.push_back(static_cast<uint8_t>(NUM2INT(aryItem)));
868
+ }
869
+ } else if (RB_TYPE_P(objValues, T_STRING) || rb_respond_to(objValues, rb_intern("to_str"))) {
870
+ // Ruby文字列
871
+ VALUE strValues = rb_String(objValues);
872
+ long strLength = RSTRING_LEN(strValues);
873
+ const char* strData = StringValuePtr(strValues);
874
+ input.insert(input.end(), &(strData[0]), &(strData[strLength]));
875
+ } else {
876
+ // その他. 数値変換を試す
877
+ int value = NUM2INT(rb_Integer(objValues));
878
+ input.push_back(static_cast<uint8_t>(value));
879
+ }
880
+
881
+ // 始点分だけ伸ばす
882
+ if (start >= dataLength) {
883
+ // 伸ばす
884
+ _this->resize(start + 1);
885
+ dataLength = static_cast<long>(_this->size());
886
+ }
887
+
888
+ // 変更長から挿入位置を分けるよー
889
+ // NOTE Arrayに合わせた
890
+ if (count <= 0) {
891
+ // 前に挿入
892
+ auto iter = _this->begin() + start;
893
+ _this->insert(iter, input.begin(), input.end());
894
+ } else {
895
+ // 挿入位置を基準に前と後ろの分割点を探す
896
+ auto firstEndIter = _this->begin() + start; // 一応startに関しては↑で伸ばしてあるので平気
897
+ auto secondStartIter = _this->begin();
898
+
899
+ if ((start + count) < dataLength) {
900
+ // 終端まで収まってる
901
+ secondStartIter = _this->begin() + (start + count);
902
+ } else {
903
+ // 収まってない
904
+ secondStartIter = _this->end();
905
+ }
906
+
907
+ // バッファへ入れて入れ替える
908
+ std::deque<uint8_t> buffer;
909
+ buffer.insert(buffer.end(), _this->begin(), firstEndIter);
910
+ buffer.insert(buffer.end(), input.begin(), input.end());
911
+ buffer.insert(buffer.end(), secondStartIter, _this->end());
912
+ _this->swap(buffer);
913
+ }
914
+
915
+ // 戻る
916
+ return objValues;
917
+ }
918
+
919
+ /**
920
+ * バイナリ配列の長さを取得します.
921
+ *
922
+ * @return [Integer] 配列長.
923
+ */
924
+ static VALUE Binary_getLength(VALUE self) {
925
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
926
+ return ULONG2NUM(_this->size());
927
+ }
928
+
929
+ /**
930
+ * バイナリ配列をRuby配列へ変換します.
931
+ *
932
+ * @return [Array<Integer>] バイナリデータが格納された整数値配列
933
+ */
934
+ static VALUE Binary_toArray(VALUE self) {
935
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
936
+ VALUE ary = rb_ary_new2(_this->size());
937
+
938
+ // Rubyオブジェクトへ変換しつつ格納
939
+ for (size_t i = 0; i < _this->size(); i++) {
940
+ rb_ary_store(ary, i, INT2FIX(_this->at(i)));
941
+ }
942
+
943
+ return ary;
944
+ }
945
+
946
+ /**
947
+ * バイナリ配列をバイト文字列へ変換します.
948
+ *
949
+ * @return [String] バイナリ配列のデータによる文字列
950
+ */
951
+ static VALUE Binary_toString(VALUE self) {
952
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
953
+ std::string str;
954
+ str.insert(str.end(), _this->begin(), _this->end());
955
+ return rb_enc_str_new(str.data(), str.size(), rb_ascii8bit_encoding());
956
+ }
957
+
958
+ /**
959
+ * バイナリ配列を配列形式の文字列として返します.
960
+ *
961
+ * @return [String] 配列形式文字列
962
+ * @see Array#to_s
963
+ */
964
+ static VALUE Binary_toTextString(VALUE self) {
965
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
966
+ std::ostringstream buffer;
967
+
968
+ buffer << "[";
969
+ for (auto it = _this->begin(); it != _this->end(); it++) {
970
+ if (it != _this->begin()) {
971
+ buffer << ", ";
972
+ }
973
+ buffer << static_cast<unsigned int>(*it);
974
+ }
975
+ buffer << "]";
976
+ std::string text = buffer.str();
977
+
978
+ return rb_enc_str_new(text.data(), text.size(), rb_ascii8bit_encoding());
979
+ }
980
+
981
+ /**
982
+ * バイナリ配列オブジェクトの、オブジェクトとしての文字列表現を返します.
983
+ *
984
+ * @return [String] オブジェクト文字列表現
985
+ */
986
+ static VALUE Binary_inspect(VALUE self) {
987
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
988
+ VALUE text = rb_funcall(self, rb_intern("to_s"), 0);
989
+ return rb_enc_sprintf(
990
+ rb_usascii_encoding(),
991
+ "#<%s:%p size=%d, data=%s>",
992
+ rb_obj_classname(self), reinterpret_cast<void*>(self),
993
+ _this->size(), StringValueCStr(text));
994
+ }
995
+
996
+ /**
997
+ * 指定位置のバイトデータを取得します.
998
+ *
999
+ * これは #[offset] と同じです.
1000
+ *
1001
+ * @param [Integer] offset 配列位置
1002
+ * @return [Integer,nil] バイトデータ
1003
+ * @see Rixmap::Binary#[]
1004
+ */
1005
+ static VALUE Binary_at(VALUE self, VALUE argOffset) {
1006
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
1007
+ long size = static_cast<long>(_this->size());
1008
+ long offset = NUM2LONG(rb_Integer(argOffset));
1009
+ if (offset < 0) {
1010
+ offset += size;
1011
+ }
1012
+ if (0 <= offset && offset < size) {
1013
+ return INT2FIX(_this->at(offset));
1014
+ } else {
1015
+ return Qnil;
1016
+ }
1017
+ }
1018
+
1019
+ /**
1020
+ * 末尾に値を追加します.
1021
+ *
1022
+ * @overload push(*items)
1023
+ * @param [*Integer] *items 追加する値
1024
+ * @return [Rixmap::Binary] selfを返します
1025
+ *
1026
+ * @see Array#push
1027
+ */
1028
+ static VALUE Binary_push(int argc, VALUE* argv, VALUE self) {
1029
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
1030
+ for (int i = 0; i < argc; i++) {
1031
+ VALUE arg = argv[i];
1032
+ long value = NUM2LONG(rb_Integer(arg));
1033
+ _this->push_back(static_cast<uint8_t>(value));
1034
+ }
1035
+ return self;
1036
+ }
1037
+
1038
+ /**
1039
+ * @overload pop()
1040
+ * 末尾から要素を取り除き、取り除かれた要素を返します.
1041
+ *
1042
+ * @return [Integer,nil] 取り除かれたバイトデータ.
1043
+ * 配列が空だった場合は`nil`.
1044
+ *
1045
+ * @overload pop(num)
1046
+ * 末尾から指定された数だけ要素を取り除き、取り除かれた要素を配列で返します.
1047
+ *
1048
+ * @param [Integer] num 取り除く要素数
1049
+ * @return [Rixmap::Binary] 取り除かれたバイトデータの配列.
1050
+ * 空配列だった場合は空配列が返されます.
1051
+ *
1052
+ * @see Array#pop
1053
+ */
1054
+ static VALUE Binary_pop(int argc, VALUE* argv, VALUE self) {
1055
+ // 引数
1056
+ VALUE argCount = Qnil;
1057
+ rb_scan_args(argc, argv, "01", &argCount);
1058
+
1059
+ // 自分
1060
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
1061
+
1062
+ // 引数の有無で挙動を変える
1063
+ if (NIL_P(argCount)) {
1064
+ if (_this->empty()) {
1065
+ return Qnil;
1066
+ } else {
1067
+ uint8_t value = _this->back();
1068
+ _this->pop_back();
1069
+ return INT2FIX(value);
1070
+ }
1071
+ } else {
1072
+ long num = NUM2LONG(rb_Integer(argCount));
1073
+ VALUE objResult = rb_class_new_instance(0, NULL, cRixmapBinary);
1074
+ Rixmap::BinaryData* result = rixmap_unwrap<Rixmap::BinaryData>(objResult);
1075
+ for (long i = 0; i < num && !_this->empty(); i++) {
1076
+ result->push_front(_this->back());
1077
+ _this->pop_back();
1078
+ }
1079
+ return objResult;
1080
+ }
1081
+ }
1082
+
1083
+ /**
1084
+ * @overload shift()
1085
+ * 先頭の要素を取り除き、取り除かれたバイトデータを返します.
1086
+ *
1087
+ * @return [Integer,nil] 取り除かれたバイトデータ.
1088
+ * `self`が空配列だった場合は`nil`.
1089
+ *
1090
+ * @overload shift(num)
1091
+ * 先頭の要素を指定された数だけ取り除き、取り除かれたバイトデータを配列で返します.
1092
+ *
1093
+ * @param [Integer] num 取り除く要素数
1094
+ * @return [Rixmap::Binary] 取り除かれたバイトデータの配列.
1095
+ * `self`が空配列だった場合は空配列になります.
1096
+ *
1097
+ * @see Array#shift
1098
+ */
1099
+ static VALUE Binary_shift(int argc, VALUE* argv, VALUE self) {
1100
+ // 引数
1101
+ VALUE argCount = Qnil;
1102
+ rb_scan_args(argc, argv, "01", &argCount);
1103
+
1104
+ // 自分
1105
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
1106
+
1107
+ // 引数の有無で挙動を変える
1108
+ if (NIL_P(argCount)) {
1109
+ if (_this->empty()) {
1110
+ return Qnil;
1111
+ } else {
1112
+ uint8_t value = _this->front();
1113
+ _this->pop_front();
1114
+ return INT2FIX(value);
1115
+ }
1116
+ } else {
1117
+ long num = NUM2LONG(rb_Integer(argCount));
1118
+ VALUE objResult = rb_class_new_instance(0, NULL, cRixmapBinary);
1119
+ Rixmap::BinaryData* result = rixmap_unwrap<Rixmap::BinaryData>(objResult);
1120
+ for (long i = 0; i < num && !_this->empty(); i++) {
1121
+ result->push_back(_this->front());
1122
+ _this->pop_front();
1123
+ }
1124
+ return objResult;
1125
+ }
1126
+ }
1127
+
1128
+ /**
1129
+ * @overload unshift(*items)
1130
+ * 先頭に指定された要素をすべて追加します.
1131
+ *
1132
+ * @param [*Integer] *items 追加するバイトデータ
1133
+ * @return [Rixmap::Binary] selfを返します
1134
+ *
1135
+ * @see Array#unshift
1136
+ */
1137
+ static VALUE Binary_unshift(int argc, VALUE* argv, VALUE self) {
1138
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
1139
+ std::deque<uint8_t> buffer;
1140
+ for (int i = 0; i < argc; i++) {
1141
+ VALUE item = argv[i];
1142
+ buffer.push_back(static_cast<uint8_t>(NUM2INT(rb_Integer(item))));
1143
+ }
1144
+ _this->insert(_this->begin(), buffer.begin(), buffer.end());
1145
+ return self;
1146
+ }
1147
+
1148
+ /**
1149
+ * @overload each()
1150
+ * 全てのバイトデータを走査するEnumeratorを返します.
1151
+ * @return [Enumerator] バイトデータを走査するイテレータ
1152
+ *
1153
+ * @overload each()
1154
+ * 全てのバイトデータを順に引数としてブロックを呼び出します.
1155
+ * @yield [byte] バイトデータを引数としてブロックを呼び出します.
1156
+ * @yieldparam [Integer] byte バイトデータ
1157
+ * @return [void]
1158
+ *
1159
+ * @see Array#each
1160
+ */
1161
+ static VALUE Binary_each(VALUE self) {
1162
+ if (rb_block_given_p()) {
1163
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
1164
+ for (auto it = _this->begin(); it != _this->end(); it++) {
1165
+ VALUE item = INT2FIX(*it);
1166
+ rb_yield_values(1, item);
1167
+ }
1168
+ return self;
1169
+ } else {
1170
+ // TODO サイズ計算関数の追加
1171
+ return rb_enumeratorize(self, ID2SYM(rb_frame_this_func()), 0, NULL);
1172
+ }
1173
+ }
1174
+
1175
+ /**
1176
+ * バイナリ配列を破壊的に逆順に並べなおします.
1177
+ *
1178
+ * @return [Rixmap::Binary] self
1179
+ * @see Array#reverse!
1180
+ */
1181
+ static VALUE Binary_reverse(VALUE self) {
1182
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
1183
+ std::reverse(_this->begin(), _this->end());
1184
+ return self;
1185
+ }
1186
+
1187
+ /**
1188
+ * 逆順に並べられたバイナリ配列の複製を返します.
1189
+ *
1190
+ * @return [Rixmap::Binary] 逆順に並べられたバイナリ配列
1191
+ * @see Array#reverse
1192
+ */
1193
+ static VALUE Binary_copyReverse(VALUE self) {
1194
+ Rixmap::BinaryData* _this = rixmap_unwrap<Rixmap::BinaryData>(self);
1195
+ VALUE objResult = rb_class_new_instance(0, NULL, cRixmapBinary);
1196
+ Rixmap::BinaryData* result = rixmap_unwrap<Rixmap::BinaryData>(objResult);
1197
+ result->insert(result->begin(), _this->rbegin(), _this->rend());
1198
+ return objResult;
1199
+ }
1200
+ /* }}} */
1201
+ /* Rixmap::Mode {{{ */
1202
+ static void Mode_Free(Rixmap::ModeData* data) {
1203
+ // オブジェクトプールから削除
1204
+ RixmapModePool::Remove(data->getMode());
1205
+
1206
+ // メモリを解放
1207
+ rixmap_xdelete(data);
1208
+ }
1209
+
1210
+ static VALUE Mode_Alloc(VALUE klass) {
1211
+ Rixmap::ModeData* data = rixmap_xnew<Rixmap::ModeData>();
1212
+ return Data_Wrap_Struct(klass, RIXMAP_DEFAULT_MARK, Mode_Free, data);
1213
+ }
1214
+
1215
+ /**
1216
+ * 画像形式名を文字列として取得します.
1217
+ *
1218
+ * @return [String] 画像形式名
1219
+ */
1220
+ static VALUE Mode_getName(VALUE self) {
1221
+ Rixmap::ModeData* _this = rixmap_unwrap<Rixmap::ModeData>(self);
1222
+ const std::string& name = _this->getName();
1223
+ return rb_str_new_cstr(name.c_str());
1224
+ }
1225
+
1226
+ /**
1227
+ * ピクセルあたりのビット数を返します.
1228
+ *
1229
+ * @return [Integer]
1230
+ */
1231
+ static VALUE Mode_getDepth(VALUE self) {
1232
+ Rixmap::ModeData* _this = rixmap_unwrap<Rixmap::ModeData>(self);
1233
+ return INT2FIX(_this->getDepth());
1234
+ }
1235
+
1236
+ /**
1237
+ * RGBカラー形式かどうかを返します.
1238
+ *
1239
+ * @return [Boolean] RGBカラー形式ならtrue
1240
+ */
1241
+ static VALUE Mode_isRGBType(VALUE self) {
1242
+ Rixmap::ModeData* _this = rixmap_unwrap<Rixmap::ModeData>(self);
1243
+ if (_this->isRGBType()) {
1244
+ return Qtrue;
1245
+ } else {
1246
+ return Qfalse;
1247
+ }
1248
+ }
1249
+
1250
+ /**
1251
+ * グレースケール形式かどうかを返します.
1252
+ *
1253
+ * @return [Boolean] グレースケール形式ならtrue
1254
+ */
1255
+ static VALUE Mode_isGrayScaleType(VALUE self) {
1256
+ Rixmap::ModeData* _this = rixmap_unwrap<Rixmap::ModeData>(self);
1257
+ if (_this->isGrayScaleType()) {
1258
+ return Qtrue;
1259
+ } else {
1260
+ return Qfalse;
1261
+ }
1262
+ }
1263
+
1264
+ /**
1265
+ * インデックスカラー形式かどうかを返します.
1266
+ *
1267
+ * @return [Boolean] インデックスカラー形式ならtrue
1268
+ */
1269
+ static VALUE Mode_isIndexedType(VALUE self) {
1270
+ Rixmap::ModeData* _this = rixmap_unwrap<Rixmap::ModeData>(self);
1271
+ if (_this->isIndexedType()) {
1272
+ return Qtrue;
1273
+ } else {
1274
+ return Qfalse;
1275
+ }
1276
+ }
1277
+
1278
+ /**
1279
+ * 透明度をサポートしているかを返します.
1280
+ *
1281
+ * @return [Boolean] 透明度をサポートしているならtrue
1282
+ */
1283
+ static VALUE Mode_hasAlpha(VALUE self) {
1284
+ Rixmap::ModeData* _this = rixmap_unwrap<Rixmap::ModeData>(self);
1285
+ if (_this->hasAlpha()) {
1286
+ return Qtrue;
1287
+ } else {
1288
+ return Qfalse;
1289
+ }
1290
+ }
1291
+
1292
+ /**
1293
+ * 画像形式値を整数値に変換します.
1294
+ *
1295
+ * @return [Integer] 画像形式値.
1296
+ */
1297
+ static VALUE Mode_toInteger(VALUE self) {
1298
+ Rixmap::ModeData* _this = rixmap_unwrap<Rixmap::ModeData>(self);
1299
+ return ULONG2NUM(_this->getValue());
1300
+ }
1301
+
1302
+ /**
1303
+ * オブジェクトとしての文字列表現を返します.
1304
+ *
1305
+ * @return [String] 文字列表現
1306
+ */
1307
+ static VALUE Mode_inspect(VALUE self) {
1308
+ Rixmap::ModeData* _this = rixmap_unwrap<Rixmap::ModeData>(self);
1309
+ const std::string& name = _this->getName();
1310
+ return rb_enc_sprintf(
1311
+ rb_usascii_encoding(),
1312
+ "#<%s:%p name=%s, depth=%d>",
1313
+ rb_obj_classname(self), reinterpret_cast<void*>(self),
1314
+ name.c_str(), _this->getDepth());
1315
+ }
1316
+ /* }}} */
1317
+ /* Rixmap::Color {{{ */
1318
+ static void Color_Free(Rixmap::ColorData* data) {
1319
+ RixmapColorPool::Remove(data->getColor());
1320
+ rixmap_xdelete(data);
1321
+ }
1322
+
1323
+ static VALUE Color_Alloc(VALUE klass) {
1324
+ Rixmap::ColorData* data = rixmap_xnew<Rixmap::ColorData>();
1325
+ return Data_Wrap_Struct(klass, RIXMAP_DEFAULT_MARK, Color_Free, data);
1326
+ }
1327
+
1328
+ /**
1329
+ * カラーオブジェクトを取得します.
1330
+ * 作成されたインスタンスはGCで回収されるまでキャッシュされるため、
1331
+ * 既存インスタンスがあればそれを返します.
1332
+ *
1333
+ * @overload new(html)
1334
+ * @param [String] html HTMLによる色表現. この場合は透明度を指定できません.
1335
+ *
1336
+ * @overload new(luminance, alpha=255)
1337
+ * @param [Integer] luminance 輝度値 (グレースケール値)
1338
+ * この場合は #red, #green, #blue それぞれに同じ値が設定されます.
1339
+ * @param [Integer] alpha 透明度
1340
+ *
1341
+ * @overload new(red, green, blue, alpha=255)
1342
+ * @param [Integer] red 赤要素値
1343
+ * @param [Integer] green 緑要素値
1344
+ * @param [Integer] blue 青要素値
1345
+ * @param [Integer] alpha 透明度
1346
+ *
1347
+ * @return [Rixmap::Color] カラーオブジェクト
1348
+ */
1349
+ static VALUE Color_New(int argc, VALUE* argv, VALUE self) {
1350
+ // 引数解析
1351
+ VALUE arg0, arg1, arg2, arg3;
1352
+ rb_scan_args(argc, argv, "13", &arg0, &arg1, &arg2, &arg3);
1353
+
1354
+ // 引数解析
1355
+ uint8_t red = 0, green = 0, blue = 0, alpha = 255;
1356
+ switch (argc) {
1357
+ case 1: // HTML形式 or 輝度値のみ
1358
+ if (RB_TYPE_P(arg0, T_STRING)) {
1359
+ // HTML形式として解析する
1360
+ {
1361
+ long codeSize = RSTRING_LEN(arg0);
1362
+ char* codeData = StringValueCStr(arg0);
1363
+
1364
+ if (codeData[0] == '#') {
1365
+ long codeLength = codeSize -1;
1366
+ long codeValue = 0;
1367
+ switch (codeLength) {
1368
+ case 3: // 3桁 (RGB各1桁表現)
1369
+ codeValue = std::strtol(&(codeData[1]), NULL, 16); // 16進数として解析
1370
+ red = (codeValue & 0x00000F00) >> 8;
1371
+ green = (codeValue & 0x000000F0) >> 4;
1372
+ blue = (codeValue & 0x0000000F);
1373
+ red += (red << 4);
1374
+ green += (green << 4);
1375
+ blue += (blue << 4);
1376
+ break;
1377
+
1378
+ case 6: // 6桁 (RGB各2桁表現
1379
+ codeValue = std::strtol(&(codeData[1]), NULL, 16);
1380
+ red = (codeValue & 0x00FF0000) >> 16;
1381
+ green = (codeValue & 0x0000FF00) >> 8;
1382
+ blue = (codeValue & 0x000000FF);
1383
+ break;
1384
+
1385
+ default:
1386
+ // HTMLカラーコードとしてはおかしい
1387
+ rb_raise(rb_eArgError, "unexpected HTML Color: %s", codeData);
1388
+ break;
1389
+ }
1390
+ } else {
1391
+ // 先頭が '#' で始まっていてほしい
1392
+ rb_raise(rb_eArgError, "unexpected HTML Color: %s", codeData);
1393
+ }
1394
+ }
1395
+ } else {
1396
+ // 輝度値をRGBに設定
1397
+ {
1398
+ uint8_t luminance = ROUND2BYTE(NUM2INT(rb_Integer(arg0)));
1399
+ red = luminance;
1400
+ green = luminance;
1401
+ blue = luminance;
1402
+ }
1403
+ }
1404
+ break;
1405
+ case 2: // 輝度値 + 透明度
1406
+ {
1407
+ uint8_t luminance = ROUND2BYTE(NUM2INT(rb_Integer(arg0)));
1408
+ red = luminance;
1409
+ green = luminance;
1410
+ blue = luminance;
1411
+ alpha = ROUND2BYTE(NUM2INT(rb_Integer(arg1)));
1412
+ }
1413
+ break;
1414
+ case 3: // RGB値
1415
+ red = ROUND2BYTE(NUM2INT(rb_Integer(arg0)));
1416
+ green = ROUND2BYTE(NUM2INT(rb_Integer(arg1)));
1417
+ blue = ROUND2BYTE(NUM2INT(rb_Integer(arg2)));
1418
+ break;
1419
+ case 4: // RGB + 透明度
1420
+ red = ROUND2BYTE(NUM2INT(rb_Integer(arg0)));
1421
+ green = ROUND2BYTE(NUM2INT(rb_Integer(arg1)));
1422
+ blue = ROUND2BYTE(NUM2INT(rb_Integer(arg2)));
1423
+ alpha = ROUND2BYTE(NUM2INT(rb_Integer(arg3)));
1424
+ break;
1425
+ default:
1426
+ // ココには来ないとは思う
1427
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..4)", argc);
1428
+ break;
1429
+ }
1430
+
1431
+ Rixmap::Color color(red, green, blue, alpha);
1432
+ return RixmapColorPool::Get(color);
1433
+ }
1434
+
1435
+ /**
1436
+ * 赤要素値を取得します.
1437
+ *
1438
+ * @return [Integer] 赤要素値
1439
+ */
1440
+ static VALUE Color_getRed(VALUE self) {
1441
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1442
+ return INT2FIX(data->getRed());
1443
+ }
1444
+
1445
+ /**
1446
+ * 緑要素値を取得します.
1447
+ *
1448
+ * @return [Integer] 緑要素値
1449
+ */
1450
+ static VALUE Color_getGreen(VALUE self) {
1451
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1452
+ return INT2FIX(data->getGreen());
1453
+ }
1454
+
1455
+ /**
1456
+ * 青要素値を取得します.
1457
+ *
1458
+ * @return [Integer] 青要素値
1459
+ */
1460
+ static VALUE Color_getBlue(VALUE self) {
1461
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1462
+ return INT2FIX(data->getBlue());
1463
+ }
1464
+
1465
+ /**
1466
+ * 透明度を取得します.
1467
+ *
1468
+ * @return [Integer] 透明度
1469
+ */
1470
+ static VALUE Color_getAlpha(VALUE self) {
1471
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1472
+ return INT2FIX(data->getAlpha());
1473
+ }
1474
+
1475
+ /**
1476
+ * 輝度値を取得します.
1477
+ *
1478
+ * `(#red + #green + #blue) / 3` と同じです.
1479
+ *
1480
+ * @return [Integer] 輝度値
1481
+ */
1482
+ static VALUE Color_getLuminance(VALUE self) {
1483
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1484
+ return INT2FIX(data->getLuminance());
1485
+ }
1486
+
1487
+ /**
1488
+ * オブジェクトと比較し、同じカラーかどうかを返します.
1489
+ *
1490
+ * @param [Object] obj 比較対象のオブジェクト
1491
+ * @return [Boolean] 同じカラーを表現しているならtrue
1492
+ */
1493
+ static VALUE Color_operatorEquals(VALUE self, VALUE argObject) {
1494
+ if (RTEST(rb_obj_is_kind_of(argObject, cRixmapColor))) {
1495
+ Rixmap::ColorData* _this = rixmap_unwrap<Rixmap::ColorData>(self);
1496
+ Rixmap::ColorData* _that = rixmap_unwrap<Rixmap::ColorData>(argObject);
1497
+
1498
+ if (*_this == *_that) {
1499
+ return Qtrue;
1500
+ } else {
1501
+ return Qfalse;
1502
+ }
1503
+ } else {
1504
+ return Qfalse;
1505
+ }
1506
+ }
1507
+
1508
+ /**
1509
+ * 配列とみなし、指定ししたオフセットに対応する要素のバイトデータを取得します.
1510
+ *
1511
+ * 配列としての並びは {#to_a} を参照してください.
1512
+ *
1513
+ * @param [Integer] offset 取得オフセット
1514
+ * @return [Integer,nil] 対応するバイトデータ. 範囲外の場合はnil.
1515
+ * @see #to_a
1516
+ */
1517
+ static VALUE Color_offsetGet(VALUE self, VALUE argOffset) {
1518
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1519
+ size_t offset = NUM2ULONG(rb_Integer(argOffset));
1520
+ if (/* 0 <= offset && */ offset < 4) {
1521
+ return INT2FIX((*data)[offset]);
1522
+ } else {
1523
+ return Qnil;
1524
+ }
1525
+ }
1526
+
1527
+ /**
1528
+ * 整数値に変換したカラー情報を返します.
1529
+ *
1530
+ * @return [Integer] カラーの整数値表現
1531
+ */
1532
+ static VALUE Color_toInteger(VALUE self) {
1533
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1534
+ return ULONG2NUM(data->getValue());
1535
+ }
1536
+
1537
+ /**
1538
+ * 各要素値を持った配列を返します.
1539
+ *
1540
+ * 配列の中身は `[R, G, B, A]` の並びになります.
1541
+ *
1542
+ * @return [Array<Integer>] 要素配列
1543
+ * @example
1544
+ * color = Rixmap::Color.new(10, 20, 30, 255)
1545
+ * color.to_a #=> [10, 20, 30, 255]
1546
+ * @see #[]
1547
+ */
1548
+ static VALUE Color_toArray(VALUE self) {
1549
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1550
+ VALUE elems = rb_ary_new();
1551
+ rb_ary_store(elems, 0, INT2FIX(data->getRed()));
1552
+ rb_ary_store(elems, 1, INT2FIX(data->getGreen()));
1553
+ rb_ary_store(elems, 2, INT2FIX(data->getBlue()));
1554
+ rb_ary_store(elems, 3, INT2FIX(data->getAlpha()));
1555
+ return elems;
1556
+ }
1557
+
1558
+ /**
1559
+ * オブジェクトとしての文字列表現を返します.
1560
+ *
1561
+ * @return [String] オブジェクト文字列表現
1562
+ */
1563
+ static VALUE Color_inspect(VALUE self) {
1564
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(self);
1565
+ return rb_enc_sprintf(
1566
+ rb_usascii_encoding(),
1567
+ "#<%s:%p red=%d, green=%d, blue=%d, alpha=%d>",
1568
+ rb_obj_classname(self), reinterpret_cast<void*>(self),
1569
+ data->getRed(), data->getGreen(), data->getBlue(), data->getAlpha());
1570
+ }
1571
+ /* }}} */
1572
+ /* Rixmap::Palette {{{ */
1573
+ static void Palette_Free(Rixmap::PaletteData* data) {
1574
+ rixmap_xdelete(data);
1575
+ }
1576
+
1577
+ static VALUE Palette_Alloc(VALUE klass) {
1578
+ Rixmap::PaletteData* data = rixmap_xnew<Rixmap::PaletteData>(0);
1579
+ return Data_Wrap_Struct(klass, RIXMAP_DEFAULT_MARK, Palette_Free, data);
1580
+ }
1581
+
1582
+ /**
1583
+ * パレットを新しく作成します.
1584
+ *
1585
+ * @overload initialize(size=256)
1586
+ * 指定したサイズのパレットを作成します.
1587
+ * @param [Integer] size パレットサイズ.
1588
+ * @return [void]
1589
+ */
1590
+ static VALUE Palette_initialize(int argc, VALUE* argv, VALUE self) {
1591
+ VALUE argSize;
1592
+ rb_scan_args(argc, argv, "01", &argSize);
1593
+
1594
+ long size = 256;
1595
+ if (!NIL_P(argSize)) {
1596
+ size = NUM2LONG(rb_Integer(argSize));
1597
+ }
1598
+ if (size <= 0) {
1599
+ rb_raise(rb_eArgError, "palette size must be positive: %ld", size);
1600
+ }
1601
+
1602
+ // パレットを拡張
1603
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1604
+ _this->resize(size);
1605
+
1606
+ return self;
1607
+ }
1608
+
1609
+ /**
1610
+ * 複製されたオブジェクトを初期化します.
1611
+ *
1612
+ * @param [Object] 複製元オブジェクト
1613
+ * @return [void]
1614
+ */
1615
+ static VALUE Palette_initializeCopy(VALUE self, VALUE argObject) {
1616
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1617
+ Rixmap::PaletteData* _that = rixmap_unwrap<Rixmap::PaletteData>(argObject);
1618
+
1619
+ _this->setDefaultColor(_that->getDefaultColor());
1620
+ _this->setColors(_that->getColors());
1621
+
1622
+ return self;
1623
+ }
1624
+
1625
+ /**
1626
+ * パレットサイズを取得します.
1627
+ *
1628
+ * @return [Integer] パレットサイズ
1629
+ */
1630
+ static VALUE Palette_getSize(VALUE self) {
1631
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1632
+ return ULONG2NUM(_this->getSize());
1633
+ }
1634
+
1635
+ /**
1636
+ * パレットからカラーオブジェクトを取得します.
1637
+ *
1638
+ * @param [Integer] offset 取得オフセット. 負数の場合は末尾から数えます.
1639
+ * @return [Rixmap::Color,nil] オフセットの位置のカラーオブジェクト.
1640
+ * オフセットが範囲外の場合nilになります.
1641
+ */
1642
+ static VALUE Palette_offsetGet(VALUE self, VALUE argOffset) {
1643
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1644
+ long length = static_cast<long>(_this->getSize()); // FIXME unsigned -> signedなのであぶねぇ
1645
+ long offset = NUM2LONG(rb_Integer(argOffset));
1646
+ long pos = offset;
1647
+
1648
+ if (pos < 0) {
1649
+ // 末尾からのオフセットとして取得
1650
+ pos += length;
1651
+ }
1652
+
1653
+ // 範囲チェック
1654
+ if (0 <= pos && pos < length) {
1655
+ return RixmapColorPool::Get(_this->get(pos));
1656
+ } else {
1657
+ rb_warning("offset %ld is out of range", offset);
1658
+ return Qnil;
1659
+ }
1660
+ }
1661
+
1662
+ /**
1663
+ * パレットのカラーオブジェクトを設定します.
1664
+ *
1665
+ * @param [Integer] offset 設定するオフセット. 負数の場合は末尾から数えます.
1666
+ * @param [String,Array,Rixmap::Color] color 設定するカラーオブジェクト
1667
+ * @return [void]
1668
+ * @see Color.new
1669
+ */
1670
+ static VALUE Palette_offsetSet(VALUE self, VALUE argOffset, VALUE argColor) {
1671
+ Rixmap::Color color(0, 0, 0, 255);
1672
+
1673
+ // カラーオブジェクトを解析
1674
+ if (RB_TYPE_P(argColor, T_STRING)) {
1675
+ // Color.newを使ってオブジェクトを構築
1676
+ VALUE objColor = rb_funcall(cRixmapColor, rb_intern("new"), 1, argColor);
1677
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(objColor);
1678
+ color = data->getColor();
1679
+ } else if (RTEST(rb_obj_is_kind_of(argColor, cRixmapColor))) {
1680
+ // Rixmap::Colorそのもの
1681
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(argColor);
1682
+ color = data->getColor();
1683
+ } else {
1684
+ // 配列から
1685
+ VALUE aryColor = rb_Array(argColor);
1686
+ long arylen = RARRAY_LEN(aryColor);
1687
+ VALUE* aryptr = RARRAY_PTR(aryColor);
1688
+ VALUE objColor = rb_funcall2(cRixmapColor, rb_intern("new"), arylen, aryptr);
1689
+ Rixmap::ColorData* data = rixmap_unwrap<Rixmap::ColorData>(objColor);
1690
+ color = data->getColor();
1691
+ }
1692
+
1693
+ // 内部データポインタ
1694
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1695
+
1696
+ // 対象オフセット
1697
+ long length = static_cast<long>(_this->getSize()); // FIXME unsigned から signed 変換
1698
+ long offset = NUM2LONG(rb_Integer(argOffset));
1699
+ long pos = offset;
1700
+ if (pos < 0) {
1701
+ pos += length;
1702
+ }
1703
+
1704
+ // 範囲チェック
1705
+ if (0 <= pos && pos < length) {
1706
+ _this->set(pos, color);
1707
+ } else {
1708
+ rb_warning("offset %ld is out of range", offset);
1709
+ }
1710
+ return argColor;
1711
+ }
1712
+
1713
+ /**
1714
+ * オブジェクトと比較して、同じパレットデータかどうかを調べます.
1715
+ *
1716
+ * @param [Object] obj 比較対象のオブジェクト
1717
+ * @return [Boolean] 同じパレットデータならtrue
1718
+ */
1719
+ static VALUE Palette_operatorEquals(VALUE self, VALUE argObject) {
1720
+ if (RTEST(rb_obj_is_kind_of(argObject, cRixmapPalette))) {
1721
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1722
+ Rixmap::PaletteData* _that = rixmap_unwrap<Rixmap::PaletteData>(argObject);
1723
+ if (*_this == *_that) {
1724
+ return Qtrue;
1725
+ } else {
1726
+ return Qfalse;
1727
+ }
1728
+ } else {
1729
+ return Qfalse;
1730
+ }
1731
+ }
1732
+
1733
+ /**
1734
+ * パレットをバイト列へと変換します.
1735
+ *
1736
+ * @overload to_s(layout='RGBA')
1737
+ * パレットをバイト列に変換します.
1738
+ * レイアウトが指定されている場合は、色ごとに各要素をレイアウトに沿うように配置します.
1739
+ * @param [String,Symbol,Array] layout バイト列の並び順. 使用可能な文字は 'R', 'G', 'B', 'A', 'L' です.
1740
+ * レイアウトに含まれないチャンネルはバイト列に含まれなくなるため、
1741
+ * 単色バイト列も作成できます.
1742
+ * @example
1743
+ * palette = Rixmap::Palette.new(256)
1744
+ * palette.to_s
1745
+ * #=> 1024バイト (RGBA×256) のバイト列データ
1746
+ * palette.to_s('RGB')
1747
+ * #=> 768バイト (RGB×256) データ
1748
+ * palette.to_s(:R)
1749
+ * #=> 赤要素のみの256バイトデータ
1750
+ */
1751
+ static VALUE Palette_toString(int argc, VALUE* argv, VALUE self) {
1752
+ // 引数解析
1753
+ VALUE argLayout = Qnil;
1754
+ rb_scan_args(argc, argv, "01", &argLayout);
1755
+
1756
+ // 対象チャンネルリスト
1757
+ Rixmap::ChannelArray channels;
1758
+ if (!NIL_P(argLayout)) {
1759
+ if (RB_TYPE_P(argLayout, T_ARRAY)) {
1760
+ long arylen = RARRAY_LEN(argLayout);
1761
+ for (long i = 0; i < arylen; i++) {
1762
+ VALUE item = rb_String(rb_ary_entry(argLayout, i));
1763
+ item = rb_funcall(item, rb_intern("upcase"), 0);
1764
+ long len = RSTRING_LEN(item);
1765
+ char* ptr = StringValuePtr(item);
1766
+ if (len > 0) {
1767
+ // 先頭文字のみ見る
1768
+ channels.push_back(static_cast<Rixmap::Channel>(ptr[0]));
1769
+ }
1770
+ }
1771
+ } else {
1772
+ VALUE objLayout = rb_funcall(rb_String(argLayout), rb_intern("upcase"), 0);
1773
+ long len = RSTRING_LEN(objLayout);
1774
+ char* ptr = StringValuePtr(objLayout);
1775
+ for (long i = 0; i < len; i++) {
1776
+ channels.push_back(static_cast<Rixmap::Channel>(ptr[i]));
1777
+ }
1778
+ }
1779
+ }
1780
+ if (channels.empty()) {
1781
+ channels.push_back(Rixmap::Channel::RED);
1782
+ channels.push_back(Rixmap::Channel::GREEN);
1783
+ channels.push_back(Rixmap::Channel::BLUE);
1784
+ channels.push_back(Rixmap::Channel::ALPHA);
1785
+ }
1786
+
1787
+ // バイト列へ
1788
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1789
+ Rixmap::CharBuffer bytes;
1790
+ const Rixmap::ColorArray& colors = _this->getColors();
1791
+ for (auto colit = colors.begin(); colit != colors.end(); colit++) {
1792
+ const Rixmap::Color& color = *colit;
1793
+ for (auto chit = channels.begin(); chit != channels.end(); chit++) {
1794
+ Rixmap::Channel ch = *chit;
1795
+ switch (ch) {
1796
+ case Rixmap::Channel::RED:
1797
+ case Rixmap::Channel::GREEN:
1798
+ case Rixmap::Channel::BLUE:
1799
+ case Rixmap::Channel::ALPHA:
1800
+ case Rixmap::Channel::LUMINANCE:
1801
+ bytes.push_back(color[*chit]);
1802
+ break;
1803
+ default:
1804
+ // DO NOTHING
1805
+ // TODO 存在しないチャンネルだった場合にスキップするか0x00で埋めるかのフラグを作るべきだろか
1806
+ break;
1807
+ }
1808
+ }
1809
+ }
1810
+
1811
+ return rb_enc_str_new(bytes.data(), bytes.size(), rb_ascii8bit_encoding());
1812
+ }
1813
+
1814
+ /**
1815
+ * パレットをカラーオブジェクト配列に変換します.
1816
+ *
1817
+ * @return [Array<Rixmap::Color>] カラー配列
1818
+ */
1819
+ static VALUE Palette_toArray(VALUE self) {
1820
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1821
+ size_t size = _this->getSize();
1822
+ VALUE ary = rb_ary_new2(size);
1823
+ for (size_t i = 0; i < size; i++) {
1824
+ rb_ary_store(ary, i, RixmapColorPool::Get(_this->at(i)));
1825
+ }
1826
+ return ary;
1827
+ }
1828
+
1829
+ /**
1830
+ * パレットの各色を順番に走査するイテレータを返すか、各色を順にブロックに渡して走査します.
1831
+ *
1832
+ * ブロックが渡された場合はカラーオブジェクト引数にブロックを呼び出します.
1833
+ * ブロックが渡されていない場合はイテレータを返します.
1834
+ *
1835
+ * @overload each()
1836
+ * @return [Enumerator] イテレータ
1837
+ *
1838
+ * @overload each()
1839
+ * @yield [color] パレット内の各カラーオブジェクトを引数としてブロックを呼び出します
1840
+ * @yieldparam color [Rixmap::Color] カラーオブジェクト
1841
+ * @return [void]
1842
+ */
1843
+ static VALUE Palette_each(VALUE self) {
1844
+ if (rb_block_given_p()) { // ブロック有
1845
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1846
+ const Rixmap::ColorArray& colors = _this->getColors();
1847
+ for (auto it = colors.begin(); it != colors.end(); it++) {
1848
+ VALUE color = RixmapColorPool::Get(*it);
1849
+ rb_yield_values(1, color);
1850
+ }
1851
+ return self;
1852
+ } else { // ブロック無
1853
+ // TODO サイズ計算関数の追加
1854
+ // その時は rb_enumeratorize_with_sizeを使おう
1855
+ // (RETURN_SIZED_ENUMERATORでもいいかも)
1856
+ return rb_enumeratorize(self, ID2SYM(rb_frame_this_func()), 0, NULL);
1857
+ }
1858
+ }
1859
+
1860
+ /**
1861
+ * オブジェクトとしての文字列表現を返します.
1862
+ *
1863
+ * @return [String] 文字列表現
1864
+ */
1865
+ static VALUE Palette_inspect(VALUE self) {
1866
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1867
+
1868
+ // カラーリスト構築
1869
+ //std::ostringstream text;
1870
+ //text << "[";
1871
+ //const Rixmap::ColorArray& colors = _this->getColors();
1872
+ //for (auto it = colors.begin(); it != colors.end(); it++) {
1873
+ // const Rixmap::Color& color = *it;
1874
+ // if (it != colors.begin()) {
1875
+ // text << ", ";
1876
+ // }
1877
+ // text << "["
1878
+ // << static_cast<int>(color.getRed()) << ", "
1879
+ // << static_cast<int>(color.getGreen()) << ", "
1880
+ // << static_cast<int>(color.getBlue()) << ", "
1881
+ // << static_cast<int>(color.getAlpha()) << "]";
1882
+ //}
1883
+ //text << "]";
1884
+
1885
+ // 文字列構築
1886
+ return rb_enc_sprintf(
1887
+ rb_usascii_encoding(),
1888
+ /* "#<%s:%p size=%d, colors=%s>", */
1889
+ "#<%s:%p size=%d>",
1890
+ rb_obj_classname(self), reinterpret_cast<void*>(self),
1891
+ _this->getSize()
1892
+ /*, text.str().c_str()*/
1893
+ );
1894
+ }
1895
+ /* }}} */
1896
+ /* Rixmap::Palette::VGA {{{ */
1897
+ static VALUE VGAPalette_initialize(VALUE self) {
1898
+ // 16色パレットとして初期化
1899
+ {
1900
+ VALUE args[1];
1901
+ args[0] = INT2FIX(16);
1902
+ rb_call_super(1, args);
1903
+ }
1904
+
1905
+ // 色を設定
1906
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1907
+ _this->set(0 , Rixmap::Color(255, 255, 255)); // White
1908
+ _this->set(1 , Rixmap::Color(192, 192, 192)); // Silver
1909
+ _this->set(2 , Rixmap::Color(128, 128, 192)); // Gray
1910
+ _this->set(3 , Rixmap::Color( 0, 0, 0)); // Black
1911
+ _this->set(4 , Rixmap::Color(255, 0, 0)); // Red
1912
+ _this->set(5 , Rixmap::Color(128, 0, 0)); // Maroon
1913
+ _this->set(6 , Rixmap::Color(255, 255, 0)); // Yellow
1914
+ _this->set(7 , Rixmap::Color(128, 128, 0)); // Olive
1915
+ _this->set(8 , Rixmap::Color( 0, 255, 0)); // Green
1916
+ _this->set(9 , Rixmap::Color( 0, 128, 0)); // Lime
1917
+ _this->set(10, Rixmap::Color( 0, 255, 255)); // Aqua
1918
+ _this->set(11, Rixmap::Color( 0, 128, 128)); // Teal
1919
+ _this->set(12, Rixmap::Color( 0, 0, 255)); // Blue
1920
+ _this->set(13, Rixmap::Color( 0, 0, 128)); // Navy
1921
+ _this->set(14, Rixmap::Color(255, 0, 255)); // Fucshia
1922
+ _this->set(15, Rixmap::Color(128, 0, 128)); // Purple
1923
+
1924
+ // 凍結
1925
+ OBJ_FREEZE(self);
1926
+
1927
+ return self;
1928
+ }
1929
+ /* }}} */
1930
+ /* Rixmap::Palette::WebSafe {{{ */
1931
+ static VALUE WebSafePalette_initialize(VALUE self) {
1932
+ // 色要素
1933
+ static uint8_t _levels[6] = {0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF};
1934
+
1935
+ // 216色パレット
1936
+ {
1937
+ VALUE args[1];
1938
+ args[0] = INT2FIX(216);
1939
+ rb_call_super(1, args);
1940
+ }
1941
+
1942
+ // 色を設定
1943
+ Rixmap::PaletteData* _this = rixmap_unwrap<Rixmap::PaletteData>(self);
1944
+
1945
+ int num = 0;
1946
+ for (int ri = 0; ri < 6; ri++) {
1947
+ for (int gi = 0; gi < 6; gi++) {
1948
+ for (int bi = 0; bi < 6; bi++) {
1949
+ _this->set(num++, Rixmap::Color(_levels[ri], _levels[gi], _levels[bi]));
1950
+ }
1951
+ }
1952
+ }
1953
+
1954
+ // 凍結
1955
+ OBJ_FREEZE(self);
1956
+
1957
+ return self;
1958
+ }
1959
+ /* }}} */
1960
+ /* Rixmap::Image {{{ */
1961
+ static void Image_Mark(Rixmap::ImageData* data) {
1962
+ data->gcmark();
1963
+ }
1964
+
1965
+ static void Image_Free(Rixmap::ImageData* data) {
1966
+ rixmap_xdelete(data);
1967
+ }
1968
+
1969
+ static VALUE Image_Alloc(VALUE klass) {
1970
+ Rixmap::ImageData* data = rixmap_xnew<Rixmap::ImageData>();
1971
+ return Data_Wrap_Struct(klass, Image_Mark, Image_Free, data);
1972
+ }
1973
+
1974
+ /**
1975
+ * 新規画像を作成します.
1976
+ *
1977
+ * @overload initialize(mode, width, height, options={})
1978
+ * 形式とサイズを指定して画像を作成します.
1979
+ * @param [Rixmap::Mode] mode 画像形式
1980
+ * @param [Integer] width 横幅 (ピクセル数)
1981
+ * @param [Integer] height 高さ (ピクセル数)
1982
+ * @param [Hash] options オプションパラメータ
1983
+ * @option options [Rixmap::Palette] :palette パレットデータ
1984
+ * @return [void]
1985
+ */
1986
+ static VALUE Image_initialize(int argc, VALUE* argv, VALUE self) {
1987
+ // 引数解析
1988
+ VALUE argMode, argWidth, argHeight, argOptions;
1989
+ rb_scan_args(argc, argv, "31", &argMode, &argWidth, &argHeight, &argOptions);
1990
+
1991
+ // オブジェクト -> 画像形式定数
1992
+ Rixmap::Mode mode = Rixmap::Mode::NONE;
1993
+ if (!RTEST(rb_obj_is_kind_of(argMode, cRixmapMode))) {
1994
+ VALUE strMode = rb_funcall(rb_String(argMode), rb_intern("upcase"), 0);
1995
+ std::string name(StringValueCStr(strMode));
1996
+ mode = Rixmap::ModeInfo::GetModeByName(name);
1997
+ } else {
1998
+ Rixmap::ModeData* mdata = rixmap_unwrap<Rixmap::ModeData>(argMode);
1999
+ mode = mdata->getMode();
2000
+ }
2001
+
2002
+ // 画像サイズ
2003
+ long width = NUM2LONG(argWidth);
2004
+ long height = NUM2LONG(argHeight);
2005
+
2006
+ // データポインタを取得
2007
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2008
+ try {
2009
+ _this->init(mode, width, height);
2010
+ } catch (const std::exception& e) {
2011
+ rb_raise(rb_eArgError, e.what());
2012
+ } catch (...) {
2013
+ rb_raise(rb_eRuntimeError, "unknown error occurred");
2014
+ }
2015
+
2016
+ // オプションパラメータからパレットを拾う
2017
+ VALUE optPalette = Qnil;
2018
+ if (RB_TYPE_P(argOptions, T_HASH)) {
2019
+ optPalette = rb_hash_lookup(argOptions, ID2SYM(rb_intern("palette")));
2020
+ // TODO 型チェック
2021
+ }
2022
+
2023
+ // パレットの処置
2024
+ if (_this->getModeInfo().isIndexedType() && NIL_P(optPalette)) {
2025
+ // インデックスカラー形式でかつ、パレットが指定されてない場合は作る
2026
+ optPalette = RixmapHelper::CreatePalette(256);
2027
+ }
2028
+
2029
+ // パレットの設定
2030
+ _this->setPalette(optPalette);
2031
+
2032
+ // 戻る
2033
+ return self;
2034
+ }
2035
+
2036
+ /**
2037
+ * 画像形式を取得します.
2038
+ *
2039
+ * @return [Rixmap::Mode] 画像形式
2040
+ */
2041
+ static VALUE Image_getMode(VALUE self) {
2042
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2043
+ return RixmapModePool::Get(_this->getMode());
2044
+ }
2045
+
2046
+ /**
2047
+ * 画像の横幅を取得します.
2048
+ *
2049
+ * @return [Integer] 横幅
2050
+ */
2051
+ static VALUE Image_getWidth(VALUE self) {
2052
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2053
+ return LONG2NUM(_this->getWidth());
2054
+ }
2055
+
2056
+ /**
2057
+ * 画像の高さを取得します.
2058
+ *
2059
+ * @return [Integer] 高さ
2060
+ */
2061
+ static VALUE Image_getHeight(VALUE self) {
2062
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2063
+ return LONG2NUM(_this->getHeight());
2064
+ }
2065
+
2066
+ /**
2067
+ * 設定されているパレットを取得します.
2068
+ *
2069
+ * @return [Rixmap::Palette,nil] パレット
2070
+ */
2071
+ static VALUE Image_getPalette(VALUE self) {
2072
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2073
+ return _this->getPalette();
2074
+ }
2075
+
2076
+ /**
2077
+ * パレットを設定します.
2078
+ *
2079
+ * @param [Rixmap::Palette] パレットデータ
2080
+ * @return [void]
2081
+ */
2082
+ static VALUE Image_setPalette(VALUE self, VALUE argPalette) {
2083
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2084
+ if (RTEST(rb_obj_is_kind_of(argPalette, cRixmapPalette))) {
2085
+ _this->setPalette(argPalette);
2086
+ } else {
2087
+ rb_raise(rb_eArgError, "palette expected %s, but %s", rb_class2name(cRixmapPalette), rb_obj_classname(argPalette));
2088
+ }
2089
+ return argPalette;
2090
+ }
2091
+
2092
+ /**
2093
+ * 画像サイズを配列で返します.
2094
+ *
2095
+ * @return [Array<Integer>] (横幅, 高さ) で返される二要素の配列
2096
+ */
2097
+ static VALUE Image_getSize(VALUE self) {
2098
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2099
+ VALUE objSize = rb_ary_new2(2);
2100
+ rb_ary_store(objSize, 0, LONG2NUM(_this->getWidth()));
2101
+ rb_ary_store(objSize, 1, LONG2NUM(_this->getHeight()));
2102
+ OBJ_FREEZE(objSize);
2103
+ return objSize;
2104
+ }
2105
+
2106
+ /**
2107
+ * 画像の寸法を配列で返します.
2108
+ *
2109
+ * 寸法には
2110
+ *
2111
+ * - 横幅
2112
+ * - 高さ
2113
+ * - チャンネル数
2114
+ *
2115
+ * が含まれます.
2116
+ *
2117
+ * @return [Array<Integer>] 寸法を格納した配列
2118
+ * @see #size
2119
+ */
2120
+ static VALUE Image_getDimension(VALUE self) {
2121
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2122
+ VALUE objDim = rb_ary_new2(3);
2123
+ rb_ary_store(objDim, 0, LONG2NUM(_this->getWidth()));
2124
+ rb_ary_store(objDim, 1, LONG2NUM(_this->getHeight()));
2125
+ rb_ary_store(objDim, 2, INT2FIX(_this->getModeInfo().getChannels().size()));
2126
+ OBJ_FREEZE(objDim);
2127
+ return objDim;
2128
+ }
2129
+
2130
+ /**
2131
+ * この画像がインデックスカラー形式かどうかを返します.
2132
+ *
2133
+ * @return [Boolean] インデックスカラー形式ならtrue
2134
+ * @see Rixmap::Mode#indexed?
2135
+ */
2136
+ static VALUE Image_isIndexedImage(VALUE self) {
2137
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2138
+ if (_this->getModeInfo().isIndexedType()) {
2139
+ return Qtrue;
2140
+ } else {
2141
+ return Qfalse;
2142
+ }
2143
+ }
2144
+
2145
+ /**
2146
+ * この画像がグレースケール形式かどうかを返します.
2147
+ *
2148
+ * @return [Boolean] グレースケール形式ならtrue
2149
+ * @see Rixmap::Mode#grayscale?
2150
+ */
2151
+ static VALUE Image_isGrayScaleImage(VALUE self) {
2152
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2153
+ if (_this->getModeInfo().isGrayScaleType()) {
2154
+ return Qtrue;
2155
+ } else {
2156
+ return Qfalse;
2157
+ }
2158
+ }
2159
+
2160
+ /**
2161
+ * この画像がRGBカラー形式かどうかを返します.
2162
+ *
2163
+ * @return [Boolean] RGBカラー形式ならtrue
2164
+ * @see Rixmap::Mode#rgb?
2165
+ */
2166
+ static VALUE Image_isRGBImage(VALUE self) {
2167
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2168
+ if (_this->getModeInfo().isRGBType()) {
2169
+ return Qtrue;
2170
+ } else {
2171
+ return Qfalse;
2172
+ }
2173
+ }
2174
+
2175
+ /**
2176
+ * この画像が透明度を持っているかを返します.
2177
+ *
2178
+ * @return [Boolean] 透明度をサポートしている場合はtrue
2179
+ * @see Rixmap::Mode#has_alpha?
2180
+ */
2181
+ static VALUE Image_hasAlphaChannel(VALUE self) {
2182
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2183
+ if (_this->getModeInfo().hasAlpha()) {
2184
+ return Qtrue;
2185
+ } else {
2186
+ return Qfalse;
2187
+ }
2188
+ }
2189
+
2190
+ /**
2191
+ * 指定したスキャンラインまたはピクセルデータを取得します.
2192
+ *
2193
+ * @overload [](lineno)
2194
+ * 指定行番号に対応するスキャンラインオブジェクトを返します.
2195
+ * @param [Integer] lineno 行番号
2196
+ * @return [Rixmap::Image::Line] スキャンライン
2197
+ *
2198
+ * @overload [](x, y)
2199
+ * 指定座標のピクセルデータを取得します.
2200
+ *
2201
+ * ピクセルデータは画像形式ごとに以下の形式で返されます.
2202
+ *
2203
+ * ###### RGB, RGBA, GRAYALPHA形式の場合
2204
+ * 戻り値は各要素値を含んだ配列になります.
2205
+ *
2206
+ * ###### GRAYSCALE, INDEXED形式の場合
2207
+ * 戻り値は輝度値またはパレットインデックスである整数値になります.
2208
+ *
2209
+ * @param [Integer] x X軸座標
2210
+ * @param [Integer] y Y軸座標
2211
+ * @return [Integer,Array<Integer>,nil] ピクセルデータ. 範囲外の場合は`nil`
2212
+ *
2213
+ * @example 基本形
2214
+ * img = Rixmap::Image.new('RGB', 32, 32)
2215
+ * img[0, 0] = [10, 20, 30]
2216
+ * img[0] #=> ImageLineインスタンス
2217
+ * img[0, 0] #=> [10, 20, 30]
2218
+ *
2219
+ * @example パレットの場合
2220
+ * img = Rixmap::Image.new('INDEXED', 32, 32)
2221
+ * img[0, 0] = [240]
2222
+ * img[0, 0] #=> 240
2223
+ */
2224
+ static VALUE Image_offsetGet(int argc, VALUE* argv, VALUE self) {
2225
+ // 引数を解析
2226
+ VALUE arg0 = Qnil, arg1 = Qnil;
2227
+ rb_scan_args(argc, argv, "11", &arg0, &arg1);
2228
+
2229
+ if (NIL_P(arg1)) {
2230
+ // [line] 形式
2231
+ // TODO [nil, nil] とかどうするよ
2232
+ long lineno = NUM2LONG(rb_Integer(arg0));
2233
+ return RixmapHelper::CreateImageLine(self, lineno);
2234
+ } else {
2235
+ // [x, y] 形式ですよねー
2236
+ // TODO [nil, 0] とかどうするよ
2237
+ long xpos = NUM2LONG(rb_Integer(arg0));
2238
+ long ypos = NUM2LONG(rb_Integer(arg1));
2239
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2240
+
2241
+ return RixmapHelper::GetPixel(_this, xpos, ypos);
2242
+ }
2243
+ }
2244
+
2245
+ /**
2246
+ * スキャンラインまたはピクセルを更新します.
2247
+ *
2248
+ * @overload []=(lineno, data)
2249
+ * スキャンラインをまとめて更新します.
2250
+ *
2251
+ * 更新する内容はピクセルデータを含む配列または文字列です.
2252
+ * 文字列の場合はバイト列データとして扱われ、画像の持つチャンネル毎に
2253
+ * ピクセルとして扱われます.
2254
+ * ピクセルデータの扱いについては {#[]=} の二要素版を参照してください.
2255
+ *
2256
+ * @param [Integer] lineno 対象行番号
2257
+ * @param [String,Array] data 更新データ
2258
+ * @return [void]
2259
+ *
2260
+ * @overload []=(x, y, data)
2261
+ * ピクセルデータを更新します.
2262
+ *
2263
+ * ピクセルデータは以下の形式で設定できます.
2264
+ *
2265
+ * ###### Integer
2266
+ * 整数値の場合、画像の持つチャンネル数すべてに複製されます.
2267
+ * そのため、透明度を持つ場合などは配列で指定したほうが安全です.
2268
+ *
2269
+ * ###### Array
2270
+ * 配列の場合は各要素を `to_i` によって整数値に変換した後、チャンネル順に設定していきます.
2271
+ * そのため、チャンネル数に足りていない場合は更新されない要素があることに注意してください.
2272
+ * また、`nil` になっている要素は無視されます.
2273
+ *
2274
+ * ###### {Rixmap::Color}
2275
+ * カラーオブジェクトの場合、以下の処理を行います.
2276
+ *
2277
+ * - RGB形式の場合は {Rixmap::Color#red}, {Rixmap::Color#green}, {Rixmap::Color#blue} を設定します.
2278
+ * - GRAYSCALE形式の場合は {Rixmap::Color#luminance} で得られた値を使用します.
2279
+ * - INDEXED形式の場合は {Rixmap::Palette#closest} を使用して、最も近い色のインデックスを設定します.
2280
+ * - 透明度を持つ画像の場合は、{Rixmap::Color#alpha} を透明度に設定します.
2281
+ *
2282
+ * @param [Integer] x X軸座標
2283
+ * @param [Integer] y Y軸座標
2284
+ * @param [Integer,Array,Rixmap::Color] data ピクセルデータ
2285
+ * @return [void]
2286
+ *
2287
+ * @example 使用例 (RGB形式)
2288
+ * img = Rixmap::Image.new('RGB', 32, 32)
2289
+ * img[0, 0] = [16, 32,480] # 基本はこんな感じ
2290
+ * img[1, 0] = 24 # 全要素に設定
2291
+ * img[1, 0] = [24, 24, 24] # 上と同じことをやっている
2292
+ * img[2, 0] = [24, 26] # 青要素を更新しない
2293
+ * img[3, 0] = [nil, nil, 0] # 青要素のみ更新
2294
+ *
2295
+ * @example 使用例 (インデックスカラー)
2296
+ * img = Rixmap::Image.new('INDEXED', 32, 32)
2297
+ * img[0, 0] = 10 # 基本
2298
+ * img[1, 0] = [3] # 配列の場合は、先頭のみ使用
2299
+ * img[2, 0] = [3, 4, 5] # 後ろは無視されます
2300
+ * img[3, 0] = [nil, nil, 7] # 更新されません
2301
+ * img[4, 0] = Rixmap::Color.new(10, 20, 30)
2302
+ * # 最も近い色を {#palette} から探します
2303
+ *
2304
+ * @example 透明度がある場合
2305
+ * img = Rixmap::Image.new('RGBA', 32, 32)
2306
+ * img[0, 0] = 10 # 透明度は更新せず
2307
+ * img[1, 0] = [5, 5, 5] # 同じく更新せず
2308
+ * img[2, 0] = [nil, nil, nil, 128]
2309
+ * # 透明度のみ更新
2310
+ * @example スキャンライン単位で更新する場合
2311
+ * img = Rixmap::Image.new('RGB', 32, 32)
2312
+ * img[0] = [[0, 1, 2], [3, 4, 5]]
2313
+ * # img[0, 0] = [0, 1, 2], img[0, 1] = [3, 4, 5] と同じ
2314
+ * # 先頭から埋めていくので、不足している場合は更新されない要素が発生します.
2315
+ * img[1] = [0, 1, 2, 3, 4, 5]
2316
+ * # img[0, 0] = 0, img[0, 1] = 1, ... と同じ扱いです
2317
+ * # 先頭から3要素ずつとるとかいう気の利いたことはしません('A`)
2318
+ * img[2] = "\x00\x01\x02\x03\x04\x05"
2319
+ * # img[0, 0] = [0, 1, 2], img[0, 1] = [3, 4, 5] と同じ扱い
2320
+ * # なんでこっちは気の利いたことすんだよって感じですな('A`)
2321
+ *
2322
+ * # FIXME この辺の動作の定義
2323
+ */
2324
+ static VALUE Image_offsetSet(int argc, VALUE* argv, VALUE self) {
2325
+ // 引数解析
2326
+ VALUE arg0 = Qnil, arg1 = Qnil, arg2 = Qnil;
2327
+ rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2);
2328
+
2329
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2330
+ const Rixmap::ModeInfo& mode = _this->getModeInfo();
2331
+ VALUE argLineNumber = Qnil, argX = Qnil, argY = Qnil;
2332
+ VALUE argData = Qnil;
2333
+ if (NIL_P(arg2)) {
2334
+ // [lineno] = data 形式
2335
+ argLineNumber = arg0;
2336
+ argData = arg1;
2337
+
2338
+ int32_t lineno = NUM2LONG(argLineNumber);
2339
+
2340
+ // 範囲チェック
2341
+ if (_this->isInside(0, lineno)) {
2342
+ // 引数チェック
2343
+ if (RTEST(rb_obj_is_kind_of(argData, cRixmapBinary))) {
2344
+ Rixmap::BinaryData* data = rixmap_unwrap<Rixmap::BinaryData>(argData);
2345
+ int32_t dataLength = static_cast<int32_t>(data->size());
2346
+
2347
+ int32_t width = _this->getWidth();
2348
+ const Rixmap::ChannelArray& channels = mode.getChannels();
2349
+ int nchannel = channels.size();
2350
+
2351
+ int32_t maxLength = width * nchannel; // FIXME 場合によってはオーバーフロー
2352
+ int32_t length = (dataLength < maxLength) ? dataLength : maxLength;
2353
+
2354
+ for (int32_t i = 0; i < length; i++) {
2355
+ int32_t w = (i / nchannel);
2356
+ int32_t c = (i % nchannel);
2357
+ Rixmap::Channel channel = channels.at(c);
2358
+ _this->set(channel, w, lineno, data->at(i));
2359
+ }
2360
+ } else if (RB_TYPE_P(argData, T_ARRAY)) {
2361
+ // 配列なので、いったん全要素をチェックする
2362
+ long nitem = RARRAY_LEN(argData);
2363
+ int32_t width = _this->getWidth();
2364
+ int32_t length = (width < nitem) ? width : nitem;
2365
+ for (int32_t i = 0; i < length; i++) {
2366
+ VALUE item = rb_ary_entry(argData, i);
2367
+ if (RB_TYPE_P(item, T_FIXNUM) || RB_TYPE_P(item, T_ARRAY) || RTEST(rb_obj_is_kind_of(item, cRixmapColor))) {
2368
+ } else {
2369
+ rb_raise(rb_eArgError, "unexpected pixel data type in line data: %s", rb_obj_classname(item));
2370
+ }
2371
+ }
2372
+
2373
+ // 要素を更新
2374
+ for (int32_t i = 0; i < length; i++) {
2375
+ VALUE item = rb_ary_entry(argData, i);
2376
+ RixmapHelper::UpdatePixel(_this, i, lineno, item);
2377
+ }
2378
+ } else if (RB_TYPE_P(argData, T_STRING)) {
2379
+ // TODO rb_String使って強制的に文字列化する
2380
+ // 文字列
2381
+ long nbyte = RSTRING_LEN(argData);
2382
+ const char* bytes = RSTRING_PTR(argData);
2383
+ int32_t width = _this->getWidth();
2384
+ const Rixmap::ChannelArray& channels = mode.getChannels();
2385
+ int nchannel = channels.size();
2386
+
2387
+ int32_t maxlength = width * nchannel; // FIXME 場合によってはオーバーフローするよなぁこれ
2388
+ int32_t length = (nbyte < maxlength) ? nbyte : maxlength;
2389
+
2390
+ for (int32_t i = 0; i < length; i++) {
2391
+ int32_t w = (i / nchannel);
2392
+ int32_t c = (i % nchannel);
2393
+ Rixmap::Channel channel = channels.at(c);
2394
+ _this->set(channel, w, lineno, bytes[i]);
2395
+ }
2396
+ } else {
2397
+ // 非対応(´・ω・`)
2398
+ rb_raise(rb_eArgError, "unexpected line data type: %s", rb_obj_classname(argData));
2399
+ }
2400
+ } else {
2401
+ // 範囲外
2402
+ rb_warning("line %d is outside of image", lineno);
2403
+ }
2404
+ } else {
2405
+ // [x, y] = data 形式
2406
+ argX = arg0;
2407
+ argY = arg1;
2408
+ argData = arg2;
2409
+
2410
+ // ネイティブ値へ
2411
+ int32_t xpos = NUM2LONG(rb_Integer(argX));
2412
+ int32_t ypos = NUM2LONG(rb_Integer(argY));
2413
+
2414
+ RixmapHelper::UpdatePixel(_this, xpos, ypos, argData);
2415
+ }
2416
+
2417
+ // 戻る
2418
+ return argData;
2419
+ }
2420
+
2421
+ /**
2422
+ * オブジェクトと比較して、同じ画像かどうかを返します.
2423
+ *
2424
+ * @param [Object] obj 比較対象のオブジェクト
2425
+ * @return [Boolean] 同じ画像ならtrue
2426
+ */
2427
+ static VALUE Image_operatorEquals(VALUE self, VALUE argObject) {
2428
+ if (self == argObject) {
2429
+ // 自分自身はtrue
2430
+ return Qtrue;
2431
+ }
2432
+
2433
+ if (RTEST(rb_obj_is_kind_of(argObject, cRixmapImage))) {
2434
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2435
+ Rixmap::ImageData* _that = rixmap_unwrap<Rixmap::ImageData>(argObject);
2436
+
2437
+ if (*_this == *_that) {
2438
+ return Qtrue;
2439
+ } else {
2440
+ return Qfalse;
2441
+ }
2442
+ } else {
2443
+ // クラスが違う場合はfalse
2444
+ return Qfalse;
2445
+ }
2446
+ }
2447
+
2448
+ /**
2449
+ * スキャンライン走査するイテレータを返します.
2450
+ * ブロックが渡されている場合は各スキャンラインを引数としてブロックを呼び出します.
2451
+ *
2452
+ * @overload each_line()
2453
+ * @return [Enumerator] イテレータ
2454
+ *
2455
+ * @overload each_line()
2456
+ * @yield [line] スキャンラインを引数としてブロックを呼び出します
2457
+ * @yieldparam line [Rixmap::Image::Line] スキャンラインオブジェクト
2458
+ * @return [void]
2459
+ */
2460
+ static VALUE Image_eachLine(VALUE self) {
2461
+ if (rb_block_given_p()) { // ブロック有
2462
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2463
+ for (int32_t h = 0; h < _this->getHeight(); h++) {
2464
+ VALUE line = RixmapHelper::CreateImageLine(self, h);
2465
+ rb_yield_values(1, line);
2466
+ }
2467
+ return self;
2468
+ } else { // ブロック無
2469
+ // TODO サイズ計算関数の追加
2470
+ // その時は rb_enumeratorize_with_sizeを使おう
2471
+ // (RETURN_SIZED_ENUMERATORでもいいかも)
2472
+ return rb_enumeratorize(self, ID2SYM(rb_frame_this_func()), 0, NULL);
2473
+ }
2474
+ }
2475
+
2476
+ /**
2477
+ * ピクセルを走査するイテレータを返します.
2478
+ * ブロックが渡されている場合は各ピクセルを引数としてブロックを呼び出します.
2479
+ *
2480
+ * ピクセルの走査は左上から右下へ、スキャンラインを左から右へ向かって行います.
2481
+ *
2482
+ * @overload each_pixel()
2483
+ * @return [Enumerator] イテレータ
2484
+ *
2485
+ * @overload each_pixel()
2486
+ * @yield [pixel] ピクセルデータを引数としてブロックを呼び出します
2487
+ * @yieldparam pixel [Array<Integer>,Integer] ピクセルデータ
2488
+ * @return [void]
2489
+ */
2490
+ static VALUE Image_eachPixel(VALUE self) {
2491
+ if (rb_block_given_p()) { // ブロック有
2492
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2493
+ for (int32_t h = 0; h < _this->getHeight(); h++) {
2494
+ for (int32_t w = 0; w < _this->getWidth(); w++) {
2495
+ VALUE pixel = RixmapHelper::GetPixel(_this, w, h);
2496
+ rb_yield_values(1, pixel);
2497
+ }
2498
+ }
2499
+ return self;
2500
+ } else { // ブロック無
2501
+ // TODO サイズ計算関数の追加
2502
+ // その時は rb_enumeratorize_with_sizeを使おう
2503
+ // (RETURN_SIZED_ENUMERATORでもいいかも)
2504
+ return rb_enumeratorize(self, ID2SYM(rb_frame_this_func()), 0, NULL);
2505
+ }
2506
+ }
2507
+
2508
+ /**
2509
+ * この画像の全てのスキャンラインを含む配列を返します.
2510
+ *
2511
+ * @return [Array<Rixmap::Image::Line>] スキャンライン配列
2512
+ * @see #each_line
2513
+ */
2514
+ static VALUE Image_getLines(VALUE self) {
2515
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2516
+ VALUE aryLines = rb_ary_new2(_this->getHeight());
2517
+
2518
+ for (int32_t h = 0; h < _this->getHeight(); h++) {
2519
+ VALUE line = RixmapHelper::CreateImageLine(self, h);
2520
+ rb_ary_store(aryLines, h, line);
2521
+ }
2522
+
2523
+ return aryLines;
2524
+ }
2525
+
2526
+ /**
2527
+ * この画像のすべてのピクセルデータを含む配列を返します.
2528
+ *
2529
+ * ピクセルデータはスキャンラインごとに入れ子の配列になります.
2530
+ *
2531
+ * @return [Array<Array>] 全ピクセルデータ
2532
+ * @see #each_pixel
2533
+ * @see Rixmap::Image::Line
2534
+ */
2535
+ static VALUE Image_getPixels(VALUE self) {
2536
+ // TODO NArrayがある場合はそっちを使いたいねぇ
2537
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2538
+ VALUE aryPixels = rb_ary_new2(_this->getHeight());
2539
+
2540
+ for (int32_t h = 0; h < _this->getHeight(); h++) {
2541
+ VALUE aryLine = rb_ary_new2(_this->getWidth());
2542
+ for (int32_t w = 0; w < _this->getWidth(); w++) {
2543
+ VALUE pixel = RixmapHelper::GetPixel(_this, w, h);
2544
+ rb_ary_store(aryLine, w, pixel);
2545
+ }
2546
+ rb_ary_store(aryPixels, h, aryLine);
2547
+ }
2548
+
2549
+ return aryPixels;
2550
+ }
2551
+
2552
+ /**
2553
+ * オブジェクトとしての文字列表現を返します.
2554
+ *
2555
+ * @return [String] 文字列表現
2556
+ */
2557
+ static VALUE Image_inspect(VALUE self) {
2558
+ Rixmap::ImageData* _this = rixmap_unwrap<Rixmap::ImageData>(self);
2559
+ volatile VALUE objPalette = _this->getPalette();
2560
+ volatile VALUE paletteText = rb_inspect(objPalette);
2561
+ return rb_enc_sprintf(
2562
+ rb_usascii_encoding(),
2563
+ "#<%s:%p mode=%s, size=(%d, %d), palette=%s>",
2564
+ rb_obj_classname(self), reinterpret_cast<void*>(self),
2565
+ _this->getModeInfo().getName().c_str(),
2566
+ _this->getWidth(),
2567
+ _this->getHeight(),
2568
+ StringValueCStr(paletteText));
2569
+ }
2570
+ /* }}} */
2571
+ /* Rixmap::Image::Line {{{ */
2572
+ static void ImageLine_Mark(Rixmap::ImageLineData* data) {
2573
+ data->gcmark();
2574
+ }
2575
+
2576
+ static void ImageLine_Free(Rixmap::ImageLineData* data) {
2577
+ rixmap_xdelete(data);
2578
+ }
2579
+
2580
+ static VALUE ImageLine_Alloc(VALUE klass) {
2581
+ Rixmap::ImageLineData* data = rixmap_xnew<Rixmap::ImageLineData>(Qnil, 0);
2582
+ return Data_Wrap_Struct(klass, ImageLine_Mark, ImageLine_Free, data);
2583
+ }
2584
+
2585
+ /**
2586
+ * スキャンラインオブジェクトを初期化します.
2587
+ *
2588
+ * @param [Rixmap::Image] image 参照先画像
2589
+ * @param [Integer] lineno 参照先行番号
2590
+ * @return [void]
2591
+ */
2592
+ static VALUE ImageLine_initialize(VALUE self, VALUE argImage, VALUE argLineNumber) {
2593
+ // 引数のチェック
2594
+ if (!RTEST(rb_obj_is_kind_of(argImage, cRixmapImage))) {
2595
+ rb_raise(rb_eArgError, "parent image expected %s, but %s", rb_class2name(argImage), rb_obj_classname(argImage));
2596
+ }
2597
+ int32_t lineno = NUM2LONG(rb_Integer(argLineNumber));
2598
+
2599
+ // データを初期化
2600
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2601
+ _this->setImage(argImage);
2602
+ _this->setLineNumber(lineno);
2603
+
2604
+ return self;
2605
+ }
2606
+
2607
+ /**
2608
+ * 参照先の親画像を返します.
2609
+ *
2610
+ * @return [Rixmap::Image] 参照先画像
2611
+ */
2612
+ static VALUE ImageLine_getImage(VALUE self) {
2613
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2614
+ return _this->getImage();
2615
+ }
2616
+
2617
+ /**
2618
+ * 参照先の行番号を返します.
2619
+ *
2620
+ * @return [Integer] 行番号
2621
+ */
2622
+ static VALUE ImageLine_getLineNumber(VALUE self) {
2623
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2624
+ return LONG2NUM(_this->getLineNumber());
2625
+ }
2626
+
2627
+ /**
2628
+ * このスキャンラインが有効な画像と行番号への参照になっているかを返します.
2629
+ *
2630
+ * @return [Boolean] 有効なスキャンラインオブジェクトならtrue
2631
+ */
2632
+ static VALUE ImageLine_isValid(VALUE self) {
2633
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2634
+ if (_this->isValid()) {
2635
+ return Qtrue;
2636
+ } else {
2637
+ return Qfalse;
2638
+ }
2639
+ }
2640
+
2641
+ /**
2642
+ * スキャンライン内のピクセルデータの、赤要素のみのバイトデータを配列で取得します.
2643
+ * 赤要素チャンネルを持たない場合や、スキャンラインが無効な場合はnilを返します.
2644
+ *
2645
+ * @return [Array<Integer>] 赤要素のみのバイトデータ.
2646
+ */
2647
+ static VALUE ImageLine_getRedBand(VALUE self) {
2648
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2649
+ return RixmapHelper::GetBand(_this, Rixmap::Channel::RED);
2650
+ }
2651
+
2652
+ /**
2653
+ * スキャンライン内のピクセルデータの、赤要素のみを更新します.
2654
+ *
2655
+ * @param [String,Array] band 更新データ
2656
+ * @return [void]
2657
+ */
2658
+ static VALUE ImageLine_setRedBand(VALUE self, VALUE argBand) {
2659
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2660
+ RixmapHelper::UpdateBand(_this, Rixmap::Channel::RED, argBand);
2661
+ return argBand;
2662
+ }
2663
+
2664
+ /**
2665
+ * スキャンライン内のピクセルデータの、緑要素のみのバイトデータを配列で取得します.
2666
+ * 緑要素チャンネルを持たない場合や、スキャンラインが無効な場合はnilを返します.
2667
+ *
2668
+ * @return [Array<Integer>] 緑要素のみのバイトデータ.
2669
+ */
2670
+ static VALUE ImageLine_getGreenBand(VALUE self) {
2671
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2672
+ return RixmapHelper::GetBand(_this, Rixmap::Channel::GREEN);
2673
+ }
2674
+
2675
+ /**
2676
+ * スキャンライン内のピクセルデータの、緑要素のみを更新します.
2677
+ *
2678
+ * @param [String,Array] band 更新データ
2679
+ * @return [void]
2680
+ */
2681
+ static VALUE ImageLine_setGreenBand(VALUE self, VALUE argBand) {
2682
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2683
+ RixmapHelper::UpdateBand(_this, Rixmap::Channel::GREEN, argBand);
2684
+ return argBand;
2685
+ }
2686
+
2687
+ /**
2688
+ * スキャンライン内のピクセルデータの、青要素のみのバイトデータを配列で取得します.
2689
+ * 青要素チャンネルを持たない場合や、スキャンラインが無効な場合はnilを返します.
2690
+ *
2691
+ * @return [Array<Integer>] 青要素のみのバイトデータ.
2692
+ */
2693
+ static VALUE ImageLine_getBlueBand(VALUE self) {
2694
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2695
+ return RixmapHelper::GetBand(_this, Rixmap::Channel::BLUE);
2696
+ }
2697
+
2698
+ /**
2699
+ * スキャンライン内のピクセルデータの、青要素のみを更新します.
2700
+ *
2701
+ * @param [String,Array] band 更新データ
2702
+ * @return [void]
2703
+ */
2704
+ static VALUE ImageLine_setBlueBand(VALUE self, VALUE argBand) {
2705
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2706
+ RixmapHelper::UpdateBand(_this, Rixmap::Channel::BLUE, argBand);
2707
+ return argBand;
2708
+ }
2709
+
2710
+ /**
2711
+ * スキャンライン内のピクセルデータの、透明度のみのバイトデータを配列で取得します.
2712
+ * 透明度チャンネルを持たない場合や、スキャンラインが無効な場合はnilを返します.
2713
+ *
2714
+ * @return [Array<Integer>] 透明度のみのバイトデータ.
2715
+ */
2716
+ static VALUE ImageLine_getAlphaBand(VALUE self) {
2717
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2718
+ return RixmapHelper::GetBand(_this, Rixmap::Channel::ALPHA);
2719
+ }
2720
+
2721
+ /**
2722
+ * スキャンライン内のピクセルデータの、透明度のみを更新します.
2723
+ *
2724
+ * @param [String,Array] band 更新データ
2725
+ * @return [void]
2726
+ */
2727
+ static VALUE ImageLine_setAlphaBand(VALUE self, VALUE argBand) {
2728
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2729
+ RixmapHelper::UpdateBand(_this, Rixmap::Channel::ALPHA, argBand);
2730
+ return argBand;
2731
+ }
2732
+
2733
+ /**
2734
+ * スキャンライン内のピクセルデータの、輝度値のみのバイトデータを配列で取得します.
2735
+ * 輝度値チャンネルを持たない場合や、スキャンラインが無効な場合はnilを返します.
2736
+ *
2737
+ * @return [Array<Integer>] 輝度値のみのバイトデータ.
2738
+ */
2739
+ static VALUE ImageLine_getLuminanceBand(VALUE self) {
2740
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2741
+ return RixmapHelper::GetBand(_this, Rixmap::Channel::LUMINANCE);
2742
+ }
2743
+
2744
+ /**
2745
+ * スキャンライン内のピクセルデータの、輝度値のみを更新します.
2746
+ *
2747
+ * @param [String,Array] band 更新データ
2748
+ * @return [void]
2749
+ */
2750
+ static VALUE ImageLine_setLuminanceBand(VALUE self, VALUE argBand) {
2751
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2752
+ RixmapHelper::UpdateBand(_this, Rixmap::Channel::LUMINANCE, argBand);
2753
+ return argBand;
2754
+ }
2755
+
2756
+ /**
2757
+ * スキャンライン内のピクセルデータの、パレットインデックスのみのバイトデータを配列で取得します.
2758
+ * パレットインデックスチャンネルを持たない場合や、スキャンラインが無効な場合はnilを返します.
2759
+ *
2760
+ * @return [Array<Integer>] パレットインデックスのみのバイトデータ.
2761
+ */
2762
+ static VALUE ImageLine_getPaletteBand(VALUE self) {
2763
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2764
+ return RixmapHelper::GetBand(_this, Rixmap::Channel::PALETTE);
2765
+ }
2766
+
2767
+ /**
2768
+ * スキャンライン内のピクセルデータの、パレットインデックスのみを更新します.
2769
+ *
2770
+ * @param [String,Array] band 更新データ
2771
+ * @return [void]
2772
+ */
2773
+ static VALUE ImageLine_setPaletteBand(VALUE self, VALUE argBand) {
2774
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2775
+ RixmapHelper::UpdateBand(_this, Rixmap::Channel::PALETTE, argBand);
2776
+ return argBand;
2777
+ }
2778
+
2779
+ /**
2780
+ * スキャンライン内の指定位置のピクセルデータを取得します.
2781
+ *
2782
+ * ピクセルデータの形式は {Rixmap::Image#[]} を参照してください.
2783
+ *
2784
+ * @param [Integer] offset 取得オフセット
2785
+ * @return [Integer,Array,nil] ピクセルデータ
2786
+ * @see Rixmap::Image#[]
2787
+ */
2788
+ static VALUE ImageLine_offsetGet(VALUE self, VALUE argOffset) {
2789
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2790
+ long offset = NUM2LONG(rb_Integer(argOffset));
2791
+
2792
+ return RixmapHelper::GetPixel(_this->getImageData(), offset, _this->getLineNumber());
2793
+ }
2794
+
2795
+ /**
2796
+ * スキャンライン内の指定位置のピクセルデータを更新します.
2797
+ *
2798
+ * ピクセルデータの形式は {Rixmap::Image#[]=} を参照してください.
2799
+ *
2800
+ * @param [Integer] offset 更新オフセット
2801
+ * @param [Integer,Array,Rixmap::Color] color 更新データ
2802
+ * @return [void]
2803
+ * @see Rixmap::Image#[]=
2804
+ */
2805
+ static VALUE ImageLine_offsetSet(VALUE self, VALUE argOffset, VALUE argColor) {
2806
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2807
+ long offset = NUM2LONG(rb_Integer(argOffset));
2808
+
2809
+ RixmapHelper::UpdatePixel(_this->getImageData(), offset, _this->getLineNumber(), argColor);
2810
+
2811
+ return argColor;
2812
+ }
2813
+
2814
+ /**
2815
+ * スキャンライン内のピクセルデータを配列で返します.
2816
+ *
2817
+ * @return [Array,nil] ピクセルデータの配列. スキャンライン自体が無効な場合はnilになります.
2818
+ * @example
2819
+ * rgb = Rixmap::Image.new('RGB', 32, 32)
2820
+ * rgb[0].to_a #=> [[0, 0, 0], [0, 0, 0], ...]
2821
+ *
2822
+ * idx = Rixmap::Image.new('INDEXED', 32, 32)
2823
+ * idx[0].to_a #=> [0, 0, 0, ...]
2824
+ */
2825
+ static VALUE ImageLine_toArray(VALUE self) {
2826
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2827
+ if (_this->isValid()) {
2828
+ Rixmap::ImageData* _parent = _this->getImageData();
2829
+ int32_t length = _this->getLength();
2830
+ int32_t lineno = _this->getLineNumber();
2831
+ VALUE pixels = rb_ary_new2(length);
2832
+ for (int32_t i = 0; i < length; i++) {
2833
+ VALUE pixel = RixmapHelper::GetPixel(_parent, i, lineno);
2834
+ rb_ary_store(pixels, i, pixel);
2835
+ }
2836
+ return pixels;
2837
+ } else {
2838
+ return Qnil;
2839
+ }
2840
+ }
2841
+
2842
+ /**
2843
+ * スキャンラインのピクセルデータを格納した文字列データ (バイト列データ) を返します.
2844
+ *
2845
+ * @overload to_s(layout=nil)
2846
+ * ピクセルデータをバイト列として取得します.
2847
+ * レイアウトが指定されている場合は、対応するチャンネル毎に並べなおします.
2848
+ * レイアウトが指定されていない場合はバイト列をすべて格納していきます.
2849
+ * その時、RGB(A)形式は`R-G-B(-A)`の順に並び、GRAYALPHA形式も同様に透明度が後ろになります.
2850
+ * @param [String,Symbol,Array] layout 各ピクセルの並び順. 使用可能なものは 'R', 'G', 'B', 'A', 'L', 'P' です.
2851
+ * 指定されたチャンネルを持たない画像の場合は、その部分は欠落します.
2852
+ * @see Palette#to_s
2853
+ * @example
2854
+ * rgb = Rixmap::Image.new('RGB', 32, 32)
2855
+ * rgb[0].to_s #=> 96バイト
2856
+ * rgb[1].to_s('L') #=> 0バイト (チャンネルを含まないため)
2857
+ * rgb[2].to_s('R') #=> 32バイト (赤要素のみ)
2858
+ */
2859
+ static VALUE ImageLine_toString(int argc, VALUE* argv, VALUE self) {
2860
+ // 引数解析
2861
+ VALUE argLayout = Qnil;
2862
+ rb_scan_args(argc, argv, "01", &argLayout);
2863
+
2864
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2865
+ Rixmap::CharBuffer bytes;
2866
+
2867
+ // 有効かどうかを判定
2868
+ if (_this->isValid()) {
2869
+ Rixmap::ImageData* _parent = _this->getImageData();
2870
+ int32_t length = _this->getLength();
2871
+ int32_t lineno = _this->getLineNumber();
2872
+ const Rixmap::ModeInfo& mode = _parent->getModeInfo();
2873
+ const Rixmap::ChannelArray& channels = mode.getChannels();
2874
+
2875
+ // 対象チャンネルを保存
2876
+ std::vector<Rixmap::Channel> layout;
2877
+ if (NIL_P(argLayout)) {
2878
+ // 無指定の場合はチャンネルデータをすべて有効化
2879
+ for (auto it = channels.begin(); it != channels.end(); it++) {
2880
+ layout.push_back(*it);
2881
+ }
2882
+ } else {
2883
+ // 指定されている場合は解析する
2884
+ // TODO パレットのほうと共通化
2885
+ if (RB_TYPE_P(argLayout, T_ARRAY)) {
2886
+ long arylen = RARRAY_LEN(argLayout);
2887
+ for (long i = 0; i < arylen; i++) {
2888
+ VALUE item = rb_String(rb_ary_entry(argLayout, i));
2889
+ item = rb_funcall(item, rb_intern("upcase"), 0);
2890
+ long slen = RSTRING_LEN(item);
2891
+ char* sptr = StringValuePtr(item);
2892
+ if (slen > 0) {
2893
+ // 先頭文字を入れる
2894
+ Rixmap::Channel ch = static_cast<Rixmap::Channel>(sptr[0]);
2895
+ if (mode.has(ch)) {
2896
+ // 対応している場合のみ
2897
+ layout.push_back(ch);
2898
+ }
2899
+ }
2900
+ }
2901
+ } else {
2902
+ // 文字列にして各バイトで入れ込む
2903
+ VALUE objLayout = rb_funcall(rb_String(argLayout), rb_intern("upcase"), 0);
2904
+ long slen = RSTRING_LEN(objLayout);
2905
+ char* sptr = StringValuePtr(objLayout);
2906
+ for (long i = 0; i < slen; i++) {
2907
+ Rixmap::Channel ch = static_cast<Rixmap::Channel>(sptr[i]);
2908
+ if (mode.has(ch)) {
2909
+ layout.push_back(ch);
2910
+ }
2911
+ }
2912
+ }
2913
+ }
2914
+
2915
+ // 各チャンネル毎にバイトとして追加
2916
+ for (int32_t i = 0; i < length; i++) {
2917
+ for (auto it = layout.begin(); it != layout.end(); it++) {
2918
+ Rixmap::Channel ch = *it;
2919
+ bytes.push_back(_parent->get(ch, i, lineno));
2920
+ }
2921
+ }
2922
+ }
2923
+
2924
+ // 文字列化
2925
+ return rb_enc_str_new(bytes.data(), bytes.size(), rb_ascii8bit_encoding());
2926
+ }
2927
+
2928
+ /**
2929
+ * スキャンライン内の各ピクセルを走査するイテレータを返します.
2930
+ * ブロックが渡されている場合はイテレータを返す代わりに、各ピクセルデータを引数として
2931
+ * ブロックを呼び出します.
2932
+ *
2933
+ * @overload each()
2934
+ * ブロックが渡されていない場合はピクセル走査用イテレータを返します.
2935
+ * @return [Enumerator] ピクセル走査用イテレータ
2936
+ *
2937
+ * @overload each()
2938
+ * ブロックが渡されている場合は各ピクセルデータを引数として、渡されたブロックを呼び出します.
2939
+ * 戻り値はこのスキャンラインオブジェクトになります.
2940
+ * @yield [pixel] ピクセルを引数として呼び出します.
2941
+ * @yieldparam pixel [Integer,Array] ピクセルデータ
2942
+ * @return [Rixmap::ImageLine] self自身を返します.
2943
+ */
2944
+ static VALUE ImageLine_each(VALUE self) {
2945
+ if (rb_block_given_p()) { // ブロック有り
2946
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2947
+ if (_this->isValid()) {
2948
+ Rixmap::ImageData* _parent = _this->getImageData();
2949
+ int32_t length = _this->getLength();
2950
+ int32_t lineno = _this->getLineNumber();
2951
+ for (int32_t i = 0; i < length; i++) {
2952
+ VALUE pixel = RixmapHelper::GetPixel(_parent, i, lineno);
2953
+ rb_yield_values(1, pixel);
2954
+ }
2955
+ }
2956
+ return self;
2957
+ } else { // ブロック無し
2958
+ // TODO サイズ計算関数の追加
2959
+ // その時は rb_enumeratorize_with_sizeを使おう
2960
+ // (RETURN_SIZED_ENUMERATORでもいいかも)
2961
+ return rb_enumeratorize(self, ID2SYM(rb_frame_this_func()), 0, NULL);
2962
+ }
2963
+ }
2964
+
2965
+ /**
2966
+ * オブジェクトとしての文字列表現を返します.
2967
+ *
2968
+ * @return [String] 文字列表現
2969
+ */
2970
+ static VALUE ImageLine_inspect(VALUE self) {
2971
+ Rixmap::ImageLineData* _this = rixmap_unwrap<Rixmap::ImageLineData>(self);
2972
+ VALUE imageText = rb_inspect(_this->getImage());
2973
+ return rb_enc_sprintf(
2974
+ rb_usascii_encoding(),
2975
+ "#<%s:%p image=%s, lineno=%d>",
2976
+ rb_obj_classname(self), reinterpret_cast<void*>(self),
2977
+ StringValueCStr(imageText), _this->getLineNumber());
2978
+ }
2979
+ /* }}} */
2980
+
2981
+ //----------------------------------------------------------------------------//
2982
+ // 内部API実装
2983
+ //----------------------------------------------------------------------------//
2984
+ /**
2985
+ * ライブラリ初期化処理
2986
+ */
2987
+ void RixmapCore_Init() {
2988
+ /**
2989
+ * Document-module: Rixmap
2990
+ *
2991
+ * Rixmapライブラリモジュール.
2992
+ */
2993
+ mRixmap = rb_define_module("Rixmap");
2994
+
2995
+ /**
2996
+ * Document-class: Rixmap::Binary
2997
+ *
2998
+ * バイナリ配列クラス.
2999
+ * RubyのArrayと違い、0~255の範囲でしか値を扱えなくしてあります.
3000
+ * この範囲を超える場合はオーバーフローします.
3001
+ *
3002
+ * 上の特徴のため、たとえば {Binary#[]} で得られる値は常に Fixnum になります.
3003
+ */
3004
+ cRixmapBinary = rb_define_class_under(mRixmap, "Binary", rb_cObject);
3005
+ rb_define_alloc_func(cRixmapBinary, Binary_Alloc);
3006
+ rb_define_private_method(cRixmapBinary, "initialize", RUBY_METHOD_FUNC(Binary_initialize), -1);
3007
+ rb_define_private_method(cRixmapBinary, "initialize_copy", RUBY_METHOD_FUNC(Binary_initializeCopy), 1);
3008
+ rb_define_method(cRixmapBinary, "*", RUBY_METHOD_FUNC(Binary_operatorMul), 1);
3009
+ rb_define_method(cRixmapBinary, "+", RUBY_METHOD_FUNC(Binary_operatorAdd), 1);
3010
+ rb_define_method(cRixmapBinary, "<<", RUBY_METHOD_FUNC(Binary_operatorLShift), 1);
3011
+ rb_define_method(cRixmapBinary, "<=>", RUBY_METHOD_FUNC(Binary_operatorCompare), 1);
3012
+ rb_define_method(cRixmapBinary, "==", RUBY_METHOD_FUNC(Binary_operatorEquals), 1);
3013
+ rb_define_method(cRixmapBinary, "[]", RUBY_METHOD_FUNC(Binary_offsetGet), -1);
3014
+ rb_define_method(cRixmapBinary, "[]=", RUBY_METHOD_FUNC(Binary_offsetSet), -1);
3015
+ rb_define_method(cRixmapBinary, "at", RUBY_METHOD_FUNC(Binary_at), 1);
3016
+ rb_define_method(cRixmapBinary, "inspect", RUBY_METHOD_FUNC(Binary_inspect), 0);
3017
+ rb_define_method(cRixmapBinary, "length", RUBY_METHOD_FUNC(Binary_getLength), 0);
3018
+ rb_define_method(cRixmapBinary, "push", RUBY_METHOD_FUNC(Binary_push), -1);
3019
+ rb_define_method(cRixmapBinary, "pop", RUBY_METHOD_FUNC(Binary_pop), -1);
3020
+ rb_define_method(cRixmapBinary, "shift", RUBY_METHOD_FUNC(Binary_shift), -1);
3021
+ rb_define_method(cRixmapBinary, "unshift", RUBY_METHOD_FUNC(Binary_unshift), -1);
3022
+ rb_define_method(cRixmapBinary, "each", RUBY_METHOD_FUNC(Binary_each), 0);
3023
+ rb_define_method(cRixmapBinary, "reverse", RUBY_METHOD_FUNC(Binary_copyReverse), 0);
3024
+ rb_define_method(cRixmapBinary, "reverse!", RUBY_METHOD_FUNC(Binary_reverse), 0);
3025
+ rb_define_method(cRixmapBinary, "to_ary", RUBY_METHOD_FUNC(Binary_toArray), 0);
3026
+ rb_define_method(cRixmapBinary, "to_str", RUBY_METHOD_FUNC(Binary_toString), 0);
3027
+ rb_define_method(cRixmapBinary, "to_s", RUBY_METHOD_FUNC(Binary_toTextString), 0);
3028
+ rb_define_method(cRixmapBinary, "to_a", RUBY_METHOD_FUNC(Binary_toArray), 0);
3029
+ rb_alias(cRixmapBinary, rb_intern("size"), rb_intern("length"));
3030
+ rb_alias(cRixmapBinary, rb_intern("slice"), rb_intern("[]"));
3031
+ rb_include_module(cRixmapBinary, rb_mEnumerable);
3032
+
3033
+ /**
3034
+ * Document-class: Rixmap::Mode
3035
+ *
3036
+ * 画像形式情報クラス.
3037
+ */
3038
+ cRixmapMode = rb_define_class_under(mRixmap, "Mode", rb_cData);
3039
+ rb_undef(CLASS_OF(cRixmapMode), rb_intern("new")); // インスタンス化させない方針
3040
+ rb_define_alloc_func(cRixmapMode, Mode_Alloc);
3041
+ rb_define_method(cRixmapMode, "name", RUBY_METHOD_FUNC(Mode_getName), 0);
3042
+ rb_define_method(cRixmapMode, "depth", RUBY_METHOD_FUNC(Mode_getDepth), 0);
3043
+ rb_define_method(cRixmapMode, "rgb?", RUBY_METHOD_FUNC(Mode_isRGBType), 0);
3044
+ rb_define_method(cRixmapMode, "grayscale?", RUBY_METHOD_FUNC(Mode_isGrayScaleType), 0);
3045
+ rb_define_method(cRixmapMode, "indexed?", RUBY_METHOD_FUNC(Mode_isIndexedType), 0);
3046
+ rb_define_method(cRixmapMode, "has_alpha?", RUBY_METHOD_FUNC(Mode_hasAlpha), 0);
3047
+ rb_define_method(cRixmapMode, "to_i", RUBY_METHOD_FUNC(Mode_toInteger), 0);
3048
+ rb_define_method(cRixmapMode, "inspect", RUBY_METHOD_FUNC(Mode_inspect), 0);
3049
+ rb_alias(cRixmapMode, rb_intern("to_s"), rb_intern("name"));
3050
+
3051
+ // 画像形式定数を設置
3052
+ /** インデックスカラー形式定数 */
3053
+ rb_define_const(mRixmap, "INDEXED", RixmapModePool::Get(Rixmap::Mode::INDEXED));
3054
+
3055
+ /** グレースケール形式定数 */
3056
+ rb_define_const(mRixmap, "GRAYSCALE", RixmapModePool::Get(Rixmap::Mode::GRAYSCALE));
3057
+
3058
+ /** 透明度付グレースケール形式定数 */
3059
+ rb_define_const(mRixmap, "GRAYALPHA", RixmapModePool::Get(Rixmap::Mode::GRAYALPHA));
3060
+
3061
+ /** RGBカラー形式定数 */
3062
+ rb_define_const(mRixmap, "RGB", RixmapModePool::Get(Rixmap::Mode::RGB));
3063
+
3064
+ /** 透明度付RGBカラー形式定数 */
3065
+ rb_define_const(mRixmap, "RGBA", RixmapModePool::Get(Rixmap::Mode::RGBA));
3066
+
3067
+ /**
3068
+ * Document-class: Rixmap::Color
3069
+ *
3070
+ * RGBカラー情報クラス.
3071
+ *
3072
+ * @example
3073
+ * c0 = Rixmap::Color.new(16, 32, 48) # RGBカラー
3074
+ * c1 = Rixmap::Color.new(16, 32, 48, 96) # RGBAカラー
3075
+ * g0 = Rixmap::Color.new(128) # グレースケール
3076
+ * g1 = Rixmap::Color.new(128, 128) # グレースケール (αチャンネル付)
3077
+ * h0 = RIxmap::Color.new("#00BBCC") # HTML色表現
3078
+ */
3079
+ cRixmapColor = rb_define_class_under(mRixmap, "Color", rb_cData);
3080
+ rb_undef(CLASS_OF(cRixmapColor), rb_intern("new"));
3081
+ rb_define_alloc_func(cRixmapColor, Color_Alloc);
3082
+ rb_define_singleton_method(cRixmapColor, "new", RUBY_METHOD_FUNC(Color_New), -1);
3083
+ rb_define_method(cRixmapColor, "red", RUBY_METHOD_FUNC(Color_getRed), 0);
3084
+ rb_define_method(cRixmapColor, "green", RUBY_METHOD_FUNC(Color_getGreen), 0);
3085
+ rb_define_method(cRixmapColor, "blue", RUBY_METHOD_FUNC(Color_getBlue), 0);
3086
+ rb_define_method(cRixmapColor, "alpha", RUBY_METHOD_FUNC(Color_getAlpha), 0);
3087
+ rb_define_method(cRixmapColor, "luminance", RUBY_METHOD_FUNC(Color_getLuminance), 0);
3088
+ rb_define_method(cRixmapColor, "==", RUBY_METHOD_FUNC(Color_operatorEquals), 1);
3089
+ rb_define_method(cRixmapColor, "[]", RUBY_METHOD_FUNC(Color_offsetGet), 1);
3090
+ rb_define_method(cRixmapColor, "to_i", RUBY_METHOD_FUNC(Color_toInteger), 0);
3091
+ rb_define_method(cRixmapColor, "to_a", RUBY_METHOD_FUNC(Color_toArray), 0);
3092
+ rb_define_method(cRixmapColor, "inspect", RUBY_METHOD_FUNC(Color_inspect), 0);
3093
+ rb_undef(CLASS_OF(cRixmapColor), rb_intern("clone"));
3094
+ rb_undef(CLASS_OF(cRixmapColor), rb_intern("dup"));
3095
+
3096
+ /**
3097
+ * Document-class: Rixmap::Palette
3098
+ *
3099
+ * パレット情報クラス.
3100
+ *
3101
+ * @todo 文字列からレイアウトに沿って更新するメソッド (#to_s の逆) の実装
3102
+ */
3103
+ cRixmapPalette = rb_define_class_under(mRixmap, "Palette", rb_cObject);
3104
+ rb_define_alloc_func(cRixmapPalette, Palette_Alloc);
3105
+ rb_define_private_method(cRixmapPalette, "initialize", RUBY_METHOD_FUNC(Palette_initialize), -1);
3106
+ rb_define_private_method(cRixmapPalette, "initialize_copy", RUBY_METHOD_FUNC(Palette_initializeCopy), 1);
3107
+ rb_define_method(cRixmapPalette, "size", RUBY_METHOD_FUNC(Palette_getSize), 0);
3108
+ rb_define_method(cRixmapPalette, "[]", RUBY_METHOD_FUNC(Palette_offsetGet), 1);
3109
+ rb_define_method(cRixmapPalette, "[]=", RUBY_METHOD_FUNC(Palette_offsetSet), 2);
3110
+ rb_define_method(cRixmapPalette, "==", RUBY_METHOD_FUNC(Palette_operatorEquals), 1);
3111
+ rb_define_method(cRixmapPalette, "to_s", RUBY_METHOD_FUNC(Palette_toString), -1); // バイト列への変換
3112
+ rb_define_method(cRixmapPalette, "to_a", RUBY_METHOD_FUNC(Palette_toArray), 0); // カラー配列への変換 (self.each.to_aでもいいかも)
3113
+ rb_define_method(cRixmapPalette, "each", RUBY_METHOD_FUNC(Palette_each), 0);
3114
+ rb_define_method(cRixmapPalette, "inspect", RUBY_METHOD_FUNC(Palette_inspect), 0);
3115
+ rb_include_module(cRixmapPalette, rb_mEnumerable);
3116
+
3117
+ /**
3118
+ * Document-class: Rixmap::Palette::VGA
3119
+ *
3120
+ * 16色 VGAパレットクラス.
3121
+ */
3122
+ VALUE cRixmapVGAPalette = rb_define_class_under(cRixmapPalette, "VGA", cRixmapPalette);
3123
+ rb_define_private_method(cRixmapVGAPalette, "initialize", RUBY_METHOD_FUNC(VGAPalette_initialize), 0);
3124
+
3125
+ /**
3126
+ * Document-class: Rixmap::Palette::WebSafe
3127
+ *
3128
+ * 216色 ウェブセーフカラーパレットクラス.
3129
+ */
3130
+ VALUE cRixmapWebSafePalette = rb_define_class_under(cRixmapPalette, "WebSafe", cRixmapPalette);
3131
+ rb_define_private_method(cRixmapWebSafePalette, "initialize", RUBY_METHOD_FUNC(WebSafePalette_initialize), 0);
3132
+
3133
+ /**
3134
+ * Document-class: Rixmap::Image
3135
+ *
3136
+ * 画像クラス.
3137
+ */
3138
+ cRixmapImage = rb_define_class_under(mRixmap, "Image", rb_cObject);
3139
+ rb_define_alloc_func(cRixmapImage, Image_Alloc);
3140
+ rb_define_private_method(cRixmapImage, "initialize", RUBY_METHOD_FUNC(Image_initialize), -1);
3141
+ rb_define_method(cRixmapImage, "mode", RUBY_METHOD_FUNC(Image_getMode), 0);
3142
+ rb_define_method(cRixmapImage, "width", RUBY_METHOD_FUNC(Image_getWidth), 0);
3143
+ rb_define_method(cRixmapImage, "height", RUBY_METHOD_FUNC(Image_getHeight), 0);
3144
+ rb_define_method(cRixmapImage, "palette", RUBY_METHOD_FUNC(Image_getPalette), 0);
3145
+ rb_define_method(cRixmapImage, "palette=", RUBY_METHOD_FUNC(Image_setPalette), 1);
3146
+ rb_define_method(cRixmapImage, "size", RUBY_METHOD_FUNC(Image_getSize), 0);
3147
+ rb_define_method(cRixmapImage, "dimension", RUBY_METHOD_FUNC(Image_getDimension), 0);
3148
+ rb_define_method(cRixmapImage, "indexed?", RUBY_METHOD_FUNC(Image_isIndexedImage), 0);
3149
+ rb_define_method(cRixmapImage, "grayscale?", RUBY_METHOD_FUNC(Image_isGrayScaleImage), 0);
3150
+ rb_define_method(cRixmapImage, "rgb?", RUBY_METHOD_FUNC(Image_isRGBImage), 0);
3151
+ rb_define_method(cRixmapImage, "has_alpha?", RUBY_METHOD_FUNC(Image_hasAlphaChannel), 0);
3152
+ rb_define_method(cRixmapImage, "[]", RUBY_METHOD_FUNC(Image_offsetGet), -1);
3153
+ rb_define_method(cRixmapImage, "[]=", RUBY_METHOD_FUNC(Image_offsetSet), -1);
3154
+ rb_define_method(cRixmapImage, "==", RUBY_METHOD_FUNC(Image_operatorEquals), 1);
3155
+ rb_define_method(cRixmapImage, "each_line", RUBY_METHOD_FUNC(Image_eachLine), 0);
3156
+ rb_define_method(cRixmapImage, "each_pixel", RUBY_METHOD_FUNC(Image_eachPixel), 0);
3157
+ rb_define_method(cRixmapImage, "lines", RUBY_METHOD_FUNC(Image_getLines), 0);
3158
+ rb_define_method(cRixmapImage, "pixels", RUBY_METHOD_FUNC(Image_getPixels), 0);
3159
+ rb_define_method(cRixmapImage, "inspect", RUBY_METHOD_FUNC(Image_inspect), 0);
3160
+ rb_alias(cRixmapImage, rb_intern("dim"), rb_intern("dimension"));
3161
+
3162
+ /**
3163
+ * Document-class: Rixmap::Image::Line
3164
+ *
3165
+ * スキャンラインクラス.
3166
+ *
3167
+ * @todo 文字列からレイアウトに沿って更新するメソッド (#to_s の逆) の実装
3168
+ */
3169
+ cRixmapImageLine = rb_define_class_under(cRixmapImage, "Line", rb_cObject);
3170
+ rb_define_alloc_func(cRixmapImageLine, ImageLine_Alloc);
3171
+ rb_define_private_method(cRixmapImageLine, "initialize", RUBY_METHOD_FUNC(ImageLine_initialize), 2);
3172
+ rb_define_method(cRixmapImageLine, "image", RUBY_METHOD_FUNC(ImageLine_getImage), 0);
3173
+ rb_define_method(cRixmapImageLine, "lineno", RUBY_METHOD_FUNC(ImageLine_getLineNumber), 0);
3174
+ rb_define_method(cRixmapImageLine, "valid?", RUBY_METHOD_FUNC(ImageLine_isValid), 0);
3175
+ rb_define_method(cRixmapImageLine, "red", RUBY_METHOD_FUNC(ImageLine_getRedBand), 0);
3176
+ rb_define_method(cRixmapImageLine, "red=", RUBY_METHOD_FUNC(ImageLine_setRedBand), 1);
3177
+ rb_define_method(cRixmapImageLine, "green", RUBY_METHOD_FUNC(ImageLine_getGreenBand), 0);
3178
+ rb_define_method(cRixmapImageLine, "green=", RUBY_METHOD_FUNC(ImageLine_setGreenBand), 1);
3179
+ rb_define_method(cRixmapImageLine, "blue", RUBY_METHOD_FUNC(ImageLine_getBlueBand), 0);
3180
+ rb_define_method(cRixmapImageLine, "blue=", RUBY_METHOD_FUNC(ImageLine_setBlueBand), 1);
3181
+ rb_define_method(cRixmapImageLine, "alpha", RUBY_METHOD_FUNC(ImageLine_getAlphaBand), 0);
3182
+ rb_define_method(cRixmapImageLine, "alpha=", RUBY_METHOD_FUNC(ImageLine_setAlphaBand), 1);
3183
+ rb_define_method(cRixmapImageLine, "luminance", RUBY_METHOD_FUNC(ImageLine_getLuminanceBand), 0);
3184
+ rb_define_method(cRixmapImageLine, "luminance=", RUBY_METHOD_FUNC(ImageLine_setLuminanceBand), 1);
3185
+ rb_define_method(cRixmapImageLine, "palette", RUBY_METHOD_FUNC(ImageLine_getPaletteBand), 0);
3186
+ rb_define_method(cRixmapImageLine, "palette=", RUBY_METHOD_FUNC(ImageLine_setPaletteBand), 1);
3187
+ rb_define_method(cRixmapImageLine, "[]", RUBY_METHOD_FUNC(ImageLine_offsetGet), 1);
3188
+ rb_define_method(cRixmapImageLine, "[]=", RUBY_METHOD_FUNC(ImageLine_offsetSet), 2);
3189
+ rb_define_method(cRixmapImageLine, "to_a", RUBY_METHOD_FUNC(ImageLine_toArray), 0);
3190
+ rb_define_method(cRixmapImageLine, "to_s", RUBY_METHOD_FUNC(ImageLine_toString), -1);
3191
+ rb_define_method(cRixmapImageLine, "each", RUBY_METHOD_FUNC(ImageLine_each), 0);
3192
+ rb_define_method(cRixmapImageLine, "inspect", RUBY_METHOD_FUNC(ImageLine_inspect), 0);
3193
+ rb_alias(cRixmapImageLine, rb_intern("to_ary"), rb_intern("to_a"));
3194
+ rb_include_module(cRixmapImageLine, rb_mEnumerable);
3195
+
3196
+ // グローバル変数としてマーク
3197
+ rb_global_variable(&mRixmap);
3198
+ rb_global_variable(&cRixmapBinary);
3199
+ rb_global_variable(&cRixmapMode);
3200
+ rb_global_variable(&cRixmapColor);
3201
+ rb_global_variable(&cRixmapPalette);
3202
+ rb_global_variable(&cRixmapImage);
3203
+ rb_global_variable(&cRixmapImageLine);
3204
+ }
3205
+
3206
+
3207
+ //============================================================================//
3208
+ // $Id: rixmapcore.cxx,v 5b9a0968eca5 2014/04/20 13:37:36 chikuchikugonzalez $
3209
+ // vim: set sts=4 ts=4 sw=4 expandtab foldmethod=marker: