rixmap 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,371 @@
1
+ // -*- coding: utf-8 -*-
2
+ /**
3
+ * 画像情報クラスデータ定義ヘッダ
4
+ */
5
+ #pragma once
6
+ #include "common.hxx"
7
+ #include "mode.hxx"
8
+ #include "color.hxx"
9
+ #include "palette.hxx"
10
+
11
+ namespace Rixmap {
12
+ /**
13
+ * Ruby用画像情報クラスデータ
14
+ */
15
+ class ImageData {
16
+ private: // 非公開メンバ
17
+ ModeInfo _mode; // 画像形式
18
+ int32_t _width; // 横幅
19
+ int32_t _height; // 高さ
20
+ bool _ready; // 準備完了しているか
21
+
22
+ // ピクセルデータ系
23
+ std::map<Channel, uint8_t**> _data;
24
+ VALUE _palette;
25
+
26
+ public: // コンストラクタ
27
+ /**
28
+ * デフォルトコンストラクタ
29
+ */
30
+ ImageData() : _mode(Mode::NONE), _width(0), _height(0), _ready(false), _palette(Qnil) {}
31
+
32
+ /**
33
+ * 一応初期データつき
34
+ */
35
+ ImageData(Mode mode, int32_t width, int32_t height) : _mode(Mode::NONE), _width(0), _height(0), _ready(false), _palette(Qnil) {
36
+ this->init(mode, width, height);
37
+ }
38
+
39
+ /**
40
+ * デストラクタ
41
+ */
42
+ ~ImageData() {
43
+ // TODO ピクセルデータの解放処理
44
+ if (this->_ready) {
45
+ for (auto it = this->_data.begin(); it != this->_data.end(); it++) {
46
+ uint8_t** plane = it->second;
47
+ if (plane != NULL) {
48
+ for (int32_t h = 0; h < this->_height; h++) {
49
+ if (plane[h] != NULL) {
50
+ ruby_xfree(plane[h]);
51
+ }
52
+ }
53
+ ruby_xfree(plane);
54
+ it->second = NULL;
55
+ }
56
+ }
57
+ this->_data.clear();
58
+ }
59
+ }
60
+
61
+ public: // プロパティメンバ関数
62
+ /**
63
+ * 画像形式定数を取得します.
64
+ */
65
+ inline Mode getMode() const { return this->_mode.getMode(); }
66
+
67
+ /**
68
+ * 画像形式情報を取得します.
69
+ */
70
+ //inline ModeInfo& getModeInfo() { return this->_mode; }
71
+ inline const ModeInfo& getModeInfo() const { return this->_mode; }
72
+
73
+ /**
74
+ * 横幅を取得します.
75
+ */
76
+ inline int32_t getWidth() const { return this->_width; }
77
+
78
+ /**
79
+ * 高さを取得します.
80
+ */
81
+ inline int32_t getHeight() const { return this->_height; }
82
+
83
+ /**
84
+ * 画像サイズ (横幅と高さ) をタプル形式で取得します.
85
+ */
86
+ inline std::tuple<int32_t, int32_t> getSize() const { return std::make_tuple(this->_width, this->_height); }
87
+
88
+ /**
89
+ * パレットオブジェクトを取得します.
90
+ */
91
+ inline VALUE getPalette() const { return this->_palette; }
92
+
93
+ /**
94
+ * パレットオブジェクトの内部データポインタを返します.
95
+ * パレットがnilの場合はNULLが返されます.
96
+ */
97
+ inline const PaletteData* getPaletteData() const {
98
+ if (NIL_P(this->_palette)) {
99
+ return NULL;
100
+ } else {
101
+ return rixmap_unwrap<Rixmap::PaletteData>(this->_palette);
102
+ }
103
+ }
104
+
105
+ /**
106
+ * パレットを設定します.
107
+ */
108
+ inline void setPalette(VALUE obj) {
109
+ // TODO 型チェック
110
+ // TODO INDEXED以外で設定を許容するか
111
+ this->_palette = obj;
112
+ }
113
+
114
+ public: // 公開メンバ関数
115
+ /**
116
+ * 指定座標が画像範囲内かどうかを返します.
117
+ */
118
+ inline bool isInside(int32_t x, int32_t y) const {
119
+ return ((0 <= x && x < this->_width) && (0 <= y && y < this->_height));
120
+ }
121
+
122
+ /**
123
+ * 指定座標が画像の範囲外かどうかを返します.
124
+ */
125
+ inline bool isOutside(int32_t x, int32_t y) const {
126
+ return ((x < 0 || this->_width <= x) || (y < 0 || this->_height <= y));
127
+ }
128
+
129
+ /**
130
+ * 指定チャンネルデータを格納するデータポインタから取得します.
131
+ * 対象チャンネルを持っていない場合はNULLになります.
132
+ */
133
+ inline uint8_t** get(Channel channel) {
134
+ auto found = this->_data.find(channel);
135
+ if (found != this->_data.end()) {
136
+ return this->_data[channel];
137
+ } else {
138
+ return NULL;
139
+ }
140
+ }
141
+
142
+ /**
143
+ * 指定チャンネルの指定行番号に対応するバイト列へのポインタから取得します.
144
+ * 行番号が範囲外の場合か、非対応のチャンネルの場合はNULLになります.
145
+ */
146
+ inline uint8_t* get(Channel channel, int32_t lineno) {
147
+ if (0 <= lineno && lineno < this->_height) {
148
+ uint8_t** plane = this->get(channel);
149
+ if (plane != NULL) {
150
+ return plane[lineno];
151
+ }
152
+ }
153
+ return NULL;
154
+ }
155
+
156
+ /**
157
+ * 指定座標の指定チャンネルのバイトデータを取得します.
158
+ *
159
+ * Notice: 範囲外だったりチャンネル持ってないときは0になるので、
160
+ * 実はバイトデータが0の時と判別できないんですよコレ
161
+ */
162
+ inline uint8_t get(Channel channel, int32_t x, int32_t y) {
163
+ if (0 <= x && x < this->_width && 0 <= y && y < this->_height) {
164
+ uint8_t** plane = this->get(channel);
165
+ if (plane != NULL) {
166
+ return plane[y][x];
167
+ }
168
+ }
169
+ return 0;
170
+ }
171
+
172
+ /**
173
+ * 指定チャンネルの指定座標のバイトデータを更新します.
174
+ */
175
+ inline bool set(Channel channel, int32_t x, int32_t y, uint8_t value) {
176
+ if (0 <= x && x < this->_width && 0 <= y && y < this->_height) {
177
+ uint8_t** plane = this->get(channel);
178
+ if (plane != NULL) {
179
+ plane[y][x] = value;
180
+ return true;
181
+ }
182
+ }
183
+ return false;
184
+ }
185
+
186
+ /**
187
+ * 画像データを初期化します.
188
+ */
189
+ inline bool init(Mode mode, int32_t width, int32_t height) {
190
+ if (this->_ready) {
191
+ // 準備完了済みの場合はなにもしない.
192
+ // 別のメソッド使ってくれ('A`)
193
+ return false;
194
+ }
195
+
196
+ // 画像サイズチェック
197
+ if (width <= 0 || height <= 0) {
198
+ std::ostringstream msg;
199
+ msg << "image size must be positive: " << width << " x " << height;
200
+ throw std::invalid_argument(msg.str());
201
+ }
202
+
203
+ // 解析用にモードを設置
204
+ ModeInfo info(mode);
205
+ const ChannelArray& channels = info.getChannels();
206
+ for (auto it = channels.begin(); it != channels.end(); it++) {
207
+ Channel channel = *it;
208
+ this->_data[channel] = NULL;
209
+
210
+ // 領域を確保
211
+ uint8_t** plane = ALLOC_N(uint8_t*, height);
212
+ std::memset(plane, 0, sizeof(uint8_t*) * height);
213
+ for (int32_t h = 0; h < height; h++) {
214
+ plane[h] = ALLOC_N(uint8_t, width);
215
+ if (channel == Channel::ALPHA) {
216
+ std::memset(&(plane[h][0]), 255, sizeof(uint8_t) * width);
217
+ } else {
218
+ std::memset(&(plane[h][0]), 0, sizeof(uint8_t) * width);
219
+ }
220
+ }
221
+
222
+ this->_data[channel] = plane;
223
+ }
224
+
225
+ this->_mode = info;
226
+ this->_width = width;
227
+ this->_height = height;
228
+ this->_ready = true;
229
+ return true;
230
+ }
231
+
232
+ /**
233
+ * 内部オブジェクトにGC用マークを付けます.
234
+ */
235
+ inline void gcmark() {
236
+ rb_gc_mark_maybe(this->_palette);
237
+ }
238
+
239
+ public: // 演算子オーバーロード
240
+ bool operator==(const ImageData& data) const {
241
+ if (this->_ready && data._ready && (this->_mode == data._mode) && (this->_width == data._width) && (this->_height == data._height)) {
242
+ if (!(NIL_P(this->_palette) && NIL_P(data._palette))) {
243
+ if (!RTEST(rb_equal(this->_palette, data._palette))) {
244
+ return false;
245
+ }
246
+ }
247
+
248
+ // ピクセルを比較
249
+ const ChannelArray& channels = this->_mode.getChannels();
250
+ for (auto chiter = channels.begin(); chiter != channels.end(); chiter++) {
251
+ Channel channel = *chiter;
252
+ uint8_t** lhsPlane = this->_data.at(channel);
253
+ uint8_t** rhsPlane = data._data.at(channel);
254
+ for (int32_t h = 0; h < this->_height; h++) {
255
+ for (int32_t w = 0; w < this->_width; w++) {
256
+ uint8_t lhs = lhsPlane[h][w];
257
+ uint8_t rhs = rhsPlane[h][w];
258
+ if (lhs != rhs) {
259
+ return false;
260
+ }
261
+ }
262
+ }
263
+ }
264
+ return true;
265
+ } else {
266
+ return false;
267
+ }
268
+ }
269
+ bool operator!=(const ImageData& data) const { return !(*this == data); }
270
+ };
271
+
272
+ /**
273
+ * Ruby用スキャンラインデータクラス
274
+ */
275
+ class ImageLineData {
276
+ private: // 非公開メンバ
277
+ VALUE _image; // 親画像
278
+ int32_t _lineno; // 行番号
279
+
280
+ public: // コンストラクタ
281
+ /**
282
+ * デフォルトコンストラクタ.
283
+ */
284
+ ImageLineData(VALUE image = Qnil, int32_t lineno = 0) : _image(image), _lineno(lineno) {}
285
+
286
+ /**
287
+ * デストラクタ
288
+ */
289
+ ~ImageLineData() {}
290
+
291
+ public: // プロパティメンバ関数
292
+ /**
293
+ * 参照している親画像を返します.
294
+ */
295
+ inline VALUE getImage() const { return this->_image; }
296
+
297
+ /**
298
+ * 参照先の画像を設定します.
299
+ */
300
+ inline void setImage(VALUE image) { this->_image = image; }
301
+
302
+ /**
303
+ * 参照している親画像の内部データへのポインタを返します.
304
+ * 参照画像がnilの場合はNULLを返します.
305
+ */
306
+ inline ImageData* getImageData() const {
307
+ if (NIL_P(this->_image)) {
308
+ return NULL;
309
+ } else {
310
+ return rixmap_unwrap<ImageData>(this->_image);
311
+ }
312
+ }
313
+
314
+ /**
315
+ * 参照先の行番号を返します.
316
+ */
317
+ inline int32_t getLineNumber() const { return this->_lineno; }
318
+
319
+ /**
320
+ * 参照先の行番号を設定します.
321
+ */
322
+ inline void setLineNumber(int32_t lineno) { this->_lineno = lineno; }
323
+
324
+ public: // メンバ関数
325
+ /**
326
+ * スキャンラインの参照が正しいかを返します.
327
+ */
328
+ inline bool isValid() const {
329
+ ImageData* parent = this->getImageData();
330
+ if (parent != NULL && 0 <= this->_lineno && this->_lineno < parent->getHeight()) {
331
+ return true;
332
+ } else {
333
+ return false;
334
+ }
335
+ }
336
+
337
+ /**
338
+ * このスキャンラインの長さを返します.
339
+ * 親画像がnilである等、無効なスキャンラインの場合は0になります.
340
+ */
341
+ inline int32_t getLength() const {
342
+ ImageData* image = this->getImageData();
343
+ if (this->isValid()) {
344
+ return image->getWidth();
345
+ } else {
346
+ return 0;
347
+ }
348
+ }
349
+
350
+ /**
351
+ * GCでのマーク処理を行います.
352
+ */
353
+ inline void gcmark() {
354
+ rb_gc_mark_maybe(this->_image);
355
+ }
356
+
357
+ public: // 演算子オーバーロード
358
+ /**
359
+ * 等値比較演算子.
360
+ */
361
+ inline bool operator==(const ImageLineData& data) {
362
+ return ((this->_image == data._image) && (this->_lineno == data._lineno));
363
+ }
364
+ inline bool operator!=(const ImageLineData& data) { return !((*this) == data); }
365
+ };
366
+ }
367
+
368
+
369
+ //============================================================================//
370
+ // $Id: image.hxx,v c10e98a1e0fa 2014/04/20 08:17:37 chikuchikugonzalez $
371
+ // vim: set sts=4 ts=4 sw=4 expandtab foldmethod=marker: