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.
- checksums.yaml +7 -0
- data/LICENSE.txt +38 -0
- data/README.markdown +74 -0
- data/Rakefile +156 -0
- data/lib/rixmap/format/bmp.rb +326 -0
- data/lib/rixmap/format/pcx.rb +438 -0
- data/lib/rixmap/format/png/chunk.rb +239 -0
- data/lib/rixmap/format/png/imageio.rb +288 -0
- data/lib/rixmap/format/png.rb +78 -0
- data/lib/rixmap/format/xpm.rb +446 -0
- data/lib/rixmap/format.rb +10 -0
- data/lib/rixmap/version.rb +26 -0
- data/lib/rixmap.rb +24 -0
- data/spec/binary_spec.rb +12 -0
- data/spec/color_spec.rb +76 -0
- data/spec/image_spec.rb +297 -0
- data/spec/mode_spec.rb +71 -0
- data/spec/palette_spec.rb +77 -0
- data/src/chollas/LICENSE.txt +38 -0
- data/src/chollas/README.md +23 -0
- data/src/chollas/alloc.hxx +62 -0
- data/src/chollas/endian.hxx +42 -0
- data/src/chollas/raser.hxx +113 -0
- data/src/chollas/utilities.hxx +58 -0
- data/src/extconf.rb +47 -0
- data/src/rixmap/binary.hxx +19 -0
- data/src/rixmap/channel.hxx +42 -0
- data/src/rixmap/color.hxx +222 -0
- data/src/rixmap/common.hxx +58 -0
- data/src/rixmap/image.hxx +371 -0
- data/src/rixmap/mode.hxx +351 -0
- data/src/rixmap/palette.hxx +220 -0
- data/src/rixmap.hxx +19 -0
- data/src/rixmapcore.cxx +3209 -0
- data/src/rixmapcore.hxx +27 -0
- data/src/rixmapio.cxx +652 -0
- data/src/rixmapio.hxx +25 -0
- data/src/rixmapmain.cxx +24 -0
- data/test/test_bmp.rb +139 -0
- data/test/test_pcx.rb +172 -0
- data/test/test_png.rb +136 -0
- data/test/test_xpm.rb +73 -0
- metadata +128 -0
@@ -0,0 +1,438 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
#
|
4
|
+
module Rixmap
|
5
|
+
module Format
|
6
|
+
|
7
|
+
# PCX画像形式用入出力実装モジュール.
|
8
|
+
module PCX
|
9
|
+
|
10
|
+
# PCXファイルシグネチャバイト
|
11
|
+
FILE_SIGNATURE = 0x0A
|
12
|
+
|
13
|
+
# パレットセパレータバイト
|
14
|
+
PALETTE_SEPARATOR = 0x0C
|
15
|
+
|
16
|
+
# Version 2.5 with fixed EGA Palette information
|
17
|
+
FORMAT_VERSION_25 = 0x00
|
18
|
+
|
19
|
+
# Version 2.8 with modifiable EGA palette information
|
20
|
+
FORMAT_VERSION_28_PLT = 0x02
|
21
|
+
|
22
|
+
# Version 2.8 without palette information
|
23
|
+
FORMAT_VERSION_28_NOPLT = 0x03
|
24
|
+
|
25
|
+
# PC Paintbrush for Windows
|
26
|
+
FORMAT_VERSION_PC_WINDOWS = 0x04
|
27
|
+
|
28
|
+
# Version 3.0
|
29
|
+
FORMAT_VERSION_30 = 0x05
|
30
|
+
|
31
|
+
# RGB or パレット形式定数
|
32
|
+
COLORTYPE_NORMAL = 0x01
|
33
|
+
|
34
|
+
# グレースケール形式
|
35
|
+
COLORTYPE_GRAYSCALE = 0x02
|
36
|
+
|
37
|
+
# 無圧縮形式
|
38
|
+
ENCODINGTYPE_NONE = 0x00
|
39
|
+
|
40
|
+
# RLE圧縮
|
41
|
+
ENCODINGTYPE_RLE = 0x01
|
42
|
+
|
43
|
+
# PCXファイルヘッダ.
|
44
|
+
class PCXFileHeader
|
45
|
+
attr_accessor :magic
|
46
|
+
attr_accessor :version
|
47
|
+
attr_accessor :encoding
|
48
|
+
attr_accessor :bit_width
|
49
|
+
|
50
|
+
attr_accessor :left
|
51
|
+
attr_accessor :top
|
52
|
+
attr_accessor :right
|
53
|
+
attr_accessor :bottom
|
54
|
+
|
55
|
+
attr_accessor :dpi_x
|
56
|
+
attr_accessor :dpi_y
|
57
|
+
|
58
|
+
attr_accessor :palette
|
59
|
+
|
60
|
+
attr_accessor :bit_planes
|
61
|
+
attr_accessor :line_width
|
62
|
+
attr_accessor :colortype
|
63
|
+
|
64
|
+
attr_accessor :screen_x
|
65
|
+
attr_accessor :screen_y
|
66
|
+
|
67
|
+
def initialize()
|
68
|
+
@magic = FILE_SIGNATURE
|
69
|
+
@version = FORMAT_VERSION_30
|
70
|
+
@encoding = ENCODINGTYPE_RLE
|
71
|
+
@bit_width = nil
|
72
|
+
@left = nil
|
73
|
+
@top = nil
|
74
|
+
@right = nil
|
75
|
+
@bottom = nil
|
76
|
+
@dpi_x = 72
|
77
|
+
@dpi_y = 72
|
78
|
+
@palette = "\x00" * 48
|
79
|
+
@bit_planes = nil
|
80
|
+
@line_width = nil
|
81
|
+
@colortype = COLORTYPE_NORMAL
|
82
|
+
@screen_x = 0
|
83
|
+
@screen_y = 0
|
84
|
+
|
85
|
+
# packデータ
|
86
|
+
@template = "CCCCssssssa48xCSSssx54"
|
87
|
+
end
|
88
|
+
|
89
|
+
def unpack(data)
|
90
|
+
@magic, @version, @encoding, @bit_width, @left, @top, @right, @bottom, @dpi_x, @dpi_y, @palette, @bit_planes, @line_width, @colortype, @screen_x, @screen_y = data.unpack(@template)
|
91
|
+
end
|
92
|
+
|
93
|
+
def pack()
|
94
|
+
return [@magic, @version, @encoding, @bit_width, @left, @top, @right, @bottom, @dpi_x, @dpi_y, @palette, @bit_planes, @line_width, @colortype, @screen_x, @screen_y].pack(@template)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# RLEエンコーダ
|
99
|
+
class RLE
|
100
|
+
# パケットを構築します.
|
101
|
+
#
|
102
|
+
# @param [Integer] byte バイトデータ
|
103
|
+
# @param [Integer] count バイトデータの数
|
104
|
+
# @return [Array<Integer>] パケットデータ
|
105
|
+
def pack(byte, count)
|
106
|
+
cnt = count / 0x3F
|
107
|
+
rem = count % 0x3F
|
108
|
+
packed = [0xFF, byte] * cnt
|
109
|
+
if rem > 0
|
110
|
+
if byte < 0xC0 && rem == 1
|
111
|
+
packed.concat([byte])
|
112
|
+
else
|
113
|
+
packed.concat([0xC0 | rem, byte])
|
114
|
+
end
|
115
|
+
end
|
116
|
+
return packed
|
117
|
+
end
|
118
|
+
|
119
|
+
# バイト列をRLEによって圧縮します.
|
120
|
+
#
|
121
|
+
# @param [Array<Integer>] bytes バイト列
|
122
|
+
# @return [Array<Integer>] 圧縮されたバイト列
|
123
|
+
def encode(bytes)
|
124
|
+
return [] if bytes.empty?
|
125
|
+
data = []
|
126
|
+
byte0 = bytes[0]
|
127
|
+
count = 1
|
128
|
+
(1...bytes.size).each do |i|
|
129
|
+
byte = bytes[i]
|
130
|
+
if byte0 == byte
|
131
|
+
count += 1
|
132
|
+
else
|
133
|
+
data.concat(self.pack(byte0, count))
|
134
|
+
byte0 = byte
|
135
|
+
count = 1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
if count > 0
|
139
|
+
data.concat(self.pack(byte0, count))
|
140
|
+
end
|
141
|
+
return data
|
142
|
+
end
|
143
|
+
|
144
|
+
# バイト列をRLEとして復元します.
|
145
|
+
#
|
146
|
+
# @param [Array<Integer>] bytes バイト列データ
|
147
|
+
# @param [Integer] total 最大復元バイト長
|
148
|
+
# @return [Array] 復元されたバイト列データ (整数配列) と、入力バイト列のどこまでを解析したかのオフセット
|
149
|
+
# @example 例えばこんな感じになります (データは適当)
|
150
|
+
# bytes = [0, 0, 0, 0, 0, ...]
|
151
|
+
# data, offset = rle.decode(bytes, 5)
|
152
|
+
# p data #=> [0, 0, 0, 0, 0]
|
153
|
+
# p offset #=> 3
|
154
|
+
def decode(bytes, total)
|
155
|
+
data = []
|
156
|
+
offset = 0
|
157
|
+
length = bytes.length
|
158
|
+
count = 0
|
159
|
+
|
160
|
+
while offset < length && count < total
|
161
|
+
byte0 = bytes[offset]
|
162
|
+
offset += 1
|
163
|
+
if byte0 >= 0xC0 # RLEパケット
|
164
|
+
cnt = byte0 & 0x3F
|
165
|
+
byte1 = bytes[offset]
|
166
|
+
offset += 1
|
167
|
+
data.concat([byte1] * cnt)
|
168
|
+
count += cnt
|
169
|
+
else # 生データ
|
170
|
+
data.push(byte0); count += 1
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
return [data, offset]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# PCX画像入出力処理実装.
|
179
|
+
class PCXImageIO < Rixmap::ImageIO::BaseImageIO
|
180
|
+
# 指定データがPCXとして読み込めるデータかどうかを調べます.
|
181
|
+
#
|
182
|
+
# @param [String] magic 画像の先頭データ
|
183
|
+
# @return [Boolean] PCXとして読み込める場合はtrue
|
184
|
+
def self.readable?(magic)
|
185
|
+
return magic[0].ord == FILE_SIGNATURE && magic[1].ord == FORMAT_VERSION_30
|
186
|
+
end
|
187
|
+
|
188
|
+
# 指定画像がPCXとして書き込めるかどうかを判定します.
|
189
|
+
#
|
190
|
+
# 実は透明度付のPCX画像はサポートしてなかったりします.
|
191
|
+
# 書き込み処理は実行できますが、その場合は透明度を無視して
|
192
|
+
# 書き込むようになってます.
|
193
|
+
#
|
194
|
+
# @param [Rixmap::Image] image 調べる画像
|
195
|
+
# @return [Boolean] PCXとして書き込める場合はtrue
|
196
|
+
def self.writable?(image)
|
197
|
+
if image.has_alpha?
|
198
|
+
return false
|
199
|
+
else
|
200
|
+
return true
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# PCX入出力オブジェクトを初期化します.
|
205
|
+
#
|
206
|
+
# @param [Hash] options オプションパラメータ
|
207
|
+
# @option options [Boolean] :compression 圧縮するかどうか (Default: true)
|
208
|
+
def initialize(options={})
|
209
|
+
super(options)
|
210
|
+
|
211
|
+
@compression = true unless defined?(@compression)
|
212
|
+
end
|
213
|
+
|
214
|
+
# PCX形式として画像をエンコードします.
|
215
|
+
#
|
216
|
+
# @param [Rixmap::Image] image 対象画像
|
217
|
+
# @param [Hash] options オプションパラメータ
|
218
|
+
# @option options [Boolean] :compression 圧縮するかどうか (Defalt: true)
|
219
|
+
# @return [String] 画像データバイト列
|
220
|
+
def encode(image, options={})
|
221
|
+
# 圧縮フラグを取得
|
222
|
+
compression = if options[:compression].nil?
|
223
|
+
@compression
|
224
|
+
else
|
225
|
+
options[:compression]
|
226
|
+
end
|
227
|
+
|
228
|
+
# ヘッダを構築 (共通部分)
|
229
|
+
header = PCXFileHeader.new
|
230
|
+
header.left = 0
|
231
|
+
header.top = 0
|
232
|
+
header.right = image.width - 1
|
233
|
+
header.bottom = image.height - 1
|
234
|
+
header.encoding = if compression
|
235
|
+
ENCODINGTYPE_RLE
|
236
|
+
else
|
237
|
+
ENCODINGTYPE_NONE
|
238
|
+
end
|
239
|
+
header.line_width = image.width
|
240
|
+
header.bit_width = 8
|
241
|
+
|
242
|
+
# ピクセルデータ置場
|
243
|
+
pixels = Array.new
|
244
|
+
|
245
|
+
# エンコーダ
|
246
|
+
rle = RLE.new
|
247
|
+
|
248
|
+
# 各形式での処理
|
249
|
+
if image.indexed? # インデックスカラー形式
|
250
|
+
header.colortype = COLORTYPE_NORMAL
|
251
|
+
header.bit_planes = 1
|
252
|
+
|
253
|
+
# ピクセルの結合
|
254
|
+
if compression
|
255
|
+
# RLE
|
256
|
+
image.each_line do |line|
|
257
|
+
pixels.concat(rle.encode(line.palette))
|
258
|
+
end
|
259
|
+
else
|
260
|
+
# 無圧縮ピクセルデータ
|
261
|
+
image.each_line do |line|
|
262
|
+
pixels.concat(line.palette)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
elsif image.grayscale? # グレースケール形式
|
266
|
+
header.colortype = COLORTYPE_GRAYSCALE
|
267
|
+
|
268
|
+
# 透明度は無視
|
269
|
+
header.bit_planes = 1
|
270
|
+
|
271
|
+
# ピクセルの結合
|
272
|
+
if compression
|
273
|
+
# RLE
|
274
|
+
image.each_line do |line|
|
275
|
+
pixels.concat(rle.encode(line.luminance))
|
276
|
+
end
|
277
|
+
else
|
278
|
+
# 無圧縮
|
279
|
+
image.each_line do |line|
|
280
|
+
pixels.concat(line.luminance)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
elsif image.rgb? # RGBカラー形式
|
284
|
+
header.colortype = COLORTYPE_NORMAL
|
285
|
+
|
286
|
+
# 透明度は無視
|
287
|
+
header.bit_planes = 3
|
288
|
+
|
289
|
+
# ピクセルの結合
|
290
|
+
if compression
|
291
|
+
# RLE
|
292
|
+
image.each_line do |line|
|
293
|
+
pixels.concat(rle.encode(line.red))
|
294
|
+
pixels.concat(rle.encode(line.green))
|
295
|
+
pixels.concat(rle.encode(line.blue))
|
296
|
+
end
|
297
|
+
else
|
298
|
+
# 無圧縮
|
299
|
+
image.each_line do |line|
|
300
|
+
pixels.concat(line.red)
|
301
|
+
pixels.concat(line.green)
|
302
|
+
pixels.concat(line.blue)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# 結合
|
308
|
+
data = header.pack() + pixels.pack('C*')
|
309
|
+
if image.indexed? && !image.palette.nil?
|
310
|
+
data.concat("\x0C")
|
311
|
+
data.concat(image.palette.to_s('RGB'))
|
312
|
+
end
|
313
|
+
|
314
|
+
return data
|
315
|
+
end
|
316
|
+
|
317
|
+
# バイト列をPCXデータとして復元します.
|
318
|
+
#
|
319
|
+
# @param [String] data バイト列
|
320
|
+
# @param [Hash] options オプションパラメータ (現在未実装)
|
321
|
+
# @return [Rixmap::Image] 復元された画像
|
322
|
+
def decode(data, options={})
|
323
|
+
header_data = data.byteslice(0, 128)
|
324
|
+
image_data = data.byteslice(128, (data.bytesize - 128)).unpack('C*')
|
325
|
+
|
326
|
+
# ヘッダを再構築
|
327
|
+
header = PCXFileHeader.new
|
328
|
+
header.unpack(header_data)
|
329
|
+
|
330
|
+
# ヘッダを確認
|
331
|
+
unless header.magic == FILE_SIGNATURE
|
332
|
+
raise ArgumentError.new("Input data is not PCX image data")
|
333
|
+
end
|
334
|
+
unless header.version == FORMAT_VERSION_30
|
335
|
+
raise NotImplementedError.new("Currently supported only PCX Version 3.0, yet")
|
336
|
+
end
|
337
|
+
unless header.encoding == ENCODINGTYPE_NONE || header.encoding == ENCODINGTYPE_RLE
|
338
|
+
raise ArgumentError.new("Unknown encoding-type: #{header.encoding}")
|
339
|
+
end
|
340
|
+
unless header.colortype == COLORTYPE_NORMAL || header.colortype == COLORTYPE_GRAYSCALE
|
341
|
+
raise ArgumentError.new("Unknown color-type: #{header.colortype}")
|
342
|
+
end
|
343
|
+
unless header.bit_width == 8
|
344
|
+
raise NotImplementedError.new("Currently supported only 8-bit image")
|
345
|
+
end
|
346
|
+
if header.bit_planes < 1
|
347
|
+
raise ArgumentError.new("Input image has no pixel data")
|
348
|
+
end
|
349
|
+
|
350
|
+
# 画像を復元
|
351
|
+
image = nil
|
352
|
+
imwidth = header.right - header.left + 1
|
353
|
+
imheight = header.bottom - header.top + 1
|
354
|
+
total_bytes = header.line_width * header.bit_planes * imheight
|
355
|
+
|
356
|
+
# ピクセルデータを復元
|
357
|
+
pixels = nil
|
358
|
+
pixel_end_offset = nil
|
359
|
+
if header.encoding == ENCODINGTYPE_RLE
|
360
|
+
rle = RLE.new
|
361
|
+
pixels, pixel_end_offset = rle.decode(image_data, total_bytes)
|
362
|
+
else
|
363
|
+
pixels = image_data.slice(0, total_bytes)
|
364
|
+
pixel_end_offset = total_bytes
|
365
|
+
end
|
366
|
+
|
367
|
+
# まずはカラータイプで分岐
|
368
|
+
if header.colortype == COLORTYPE_GRAYSCALE # グレースケール
|
369
|
+
image = Rixmap::Image.new(Rixmap::GRAYSCALE, imwidth, imheight)
|
370
|
+
if header.bit_planes > 1 # 輝度値 + 謎プレーン
|
371
|
+
pixels.each_slice(header.line_width * header.bit_planes).each_with_index do |line, i|
|
372
|
+
break if i >= imheight
|
373
|
+
image[h].luminance = line.slice(0, imwidth)
|
374
|
+
end
|
375
|
+
else # 輝度値
|
376
|
+
pixels.each_slice(header.line_width).each_with_index do |line, i|
|
377
|
+
break if i >= imheight
|
378
|
+
image[i].luminance = line
|
379
|
+
end
|
380
|
+
end
|
381
|
+
else # カラー形式
|
382
|
+
if header.bit_planes > 3 # RGB + 謎プレーン
|
383
|
+
image = Rixmap::Image.new(Rixmap::RGB, imwidth, imheight)
|
384
|
+
roffset = 0
|
385
|
+
goffset = header.line_width
|
386
|
+
boffset = header.line_width * 2
|
387
|
+
pixels.each_slice(header.line_width * header.bit_planes).each_with_index do |line, i|
|
388
|
+
break if i >= imheight
|
389
|
+
image[i].red = line.slice(roffset, imwidth)
|
390
|
+
image[i].green = line.slice(goffset, imwidth)
|
391
|
+
image[i].blue = line.slice(boffset, imwidth)
|
392
|
+
end
|
393
|
+
elsif header.bit_planes == 3 # RGB
|
394
|
+
image = Rixmap::Image.new(Rixmap::RGB, imwidth, imheight)
|
395
|
+
roffset = 0
|
396
|
+
goffset = header.line_width
|
397
|
+
boffset = header.line_width * 2
|
398
|
+
pixels.each_slice(header.line_width * 3).each_with_index do |line, i|
|
399
|
+
break if i >= imheight
|
400
|
+
image[i].red = line.slice(roffset, imwidth)
|
401
|
+
image[i].green = line.slice(goffset, imwidth)
|
402
|
+
image[i].blue = line.slice(boffset, imwidth)
|
403
|
+
end
|
404
|
+
elsif header.bit_planes == 1 # INDEXED
|
405
|
+
image = Rixmap::Image.new(Rixmap::INDEXED, imwidth, imheight)
|
406
|
+
pixels.each_slice(header.line_width).each_with_index do |line, i|
|
407
|
+
break if i >= image.height
|
408
|
+
image[i].palette = line
|
409
|
+
end
|
410
|
+
|
411
|
+
if pixel_end_offset < image_data.length && image_data[pixel_end_offset] == PALETTE_SEPARATOR && !image.palette.nil?
|
412
|
+
# パレットある
|
413
|
+
palette_data = image_data.slice(pixel_end_offset + 1, (image_data.length - (pixel_end_offset + 1)))
|
414
|
+
palette = image.palette
|
415
|
+
palette_data.each_slice(3).each_with_index do |color, i|
|
416
|
+
break if i >= palette.size
|
417
|
+
palette[i] = color
|
418
|
+
end
|
419
|
+
end
|
420
|
+
else # !?
|
421
|
+
raise RuntimeError.new("Illegal bit-planes #{header.bit_planes}")
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
return image
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
Rixmap::ImageIO.register(:PCX, PCXImageIO, [".pcx"])
|
430
|
+
end
|
431
|
+
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
|
436
|
+
#==============================================================================#
|
437
|
+
# $Id: pcx.rb,v 57b1fb2cd6a6 2014/04/20 12:21:27 chikuchikugonzalez $
|
438
|
+
# vim: set sts=2 ts=2 sw=2 expandtab:
|
@@ -0,0 +1,239 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
#
|
4
|
+
module Rixmap
|
5
|
+
module Format
|
6
|
+
module PNG
|
7
|
+
|
8
|
+
# PNGチャンクデータモジュール
|
9
|
+
module Chunk
|
10
|
+
|
11
|
+
# チャンクタイプ名と実装クラスの対応を登録します.
|
12
|
+
#
|
13
|
+
# @param [String] name チャンクタイプ名
|
14
|
+
# @param [Class] klass チャンク実装クラス
|
15
|
+
# @return [void]
|
16
|
+
def self.set(name, klass)
|
17
|
+
unless defined?(@chunks)
|
18
|
+
@chunks = Hash.new
|
19
|
+
end
|
20
|
+
@chunks[name] = klass
|
21
|
+
end
|
22
|
+
|
23
|
+
# チャンクタイプ名からその実装クラスを取得します.
|
24
|
+
#
|
25
|
+
# @param [String] name チャンクタイプ名
|
26
|
+
# @return [Class,nil] チャンク実装クラス. 未登録の場合はnil
|
27
|
+
def self.get(name)
|
28
|
+
unless defined?(@chunks)
|
29
|
+
@chunks = Hash.new
|
30
|
+
end
|
31
|
+
return @chunks[name]
|
32
|
+
end
|
33
|
+
|
34
|
+
# PNGチャンクベースクラス
|
35
|
+
class BaseChunk
|
36
|
+
# チャンクを初期化します.
|
37
|
+
#
|
38
|
+
# @param [String] type チャンクタイプ
|
39
|
+
# @param [String] data チャンクデータ
|
40
|
+
def initialize(type, data = nil)
|
41
|
+
@type = type
|
42
|
+
@data = nil
|
43
|
+
|
44
|
+
self.data = data unless data.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
# チャンクタイプを返します.
|
48
|
+
#
|
49
|
+
# @return [String] チャンクタイプ
|
50
|
+
def type()
|
51
|
+
return @type
|
52
|
+
end
|
53
|
+
|
54
|
+
# チャンクデータを返します.
|
55
|
+
#
|
56
|
+
# @return [String] チャンクデータ
|
57
|
+
def data()
|
58
|
+
self.pack()
|
59
|
+
return @data
|
60
|
+
end
|
61
|
+
|
62
|
+
# チャンクデータを更新します.
|
63
|
+
#
|
64
|
+
# @param [String] data チャンクデータ
|
65
|
+
def data=(data)
|
66
|
+
@data = data
|
67
|
+
self.unpack()
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# 補助チャンクかどうかを返します.
|
72
|
+
#
|
73
|
+
# @return [Boolean] 補助チャンクならtrue
|
74
|
+
def optional?()
|
75
|
+
return (@type[0].ord & 0x20) != 0
|
76
|
+
end
|
77
|
+
|
78
|
+
# プライベートチャンクかどうかを返します.
|
79
|
+
#
|
80
|
+
# @return [Boolean] プライベートチャンクならtrue
|
81
|
+
def private?()
|
82
|
+
return (@type[1].ord & 0x20) != 0
|
83
|
+
end
|
84
|
+
|
85
|
+
# 標準チャンクかどうかを返します.
|
86
|
+
#
|
87
|
+
# @return [Boolean] 標準チャンクならtrue
|
88
|
+
def standard?()
|
89
|
+
return (@type[2].ord & 0x20) == 0
|
90
|
+
end
|
91
|
+
|
92
|
+
# コピー安全なチャンクかどうかを返します.
|
93
|
+
#
|
94
|
+
# @return [Boolean] コピー安全なチャンクならtrue
|
95
|
+
def copysafe?()
|
96
|
+
return (@type[3].ord & 0x20) != 0
|
97
|
+
end
|
98
|
+
|
99
|
+
# データ取得前の、データ構築処理を行います.
|
100
|
+
#
|
101
|
+
# #data から呼び出されます
|
102
|
+
def pack()
|
103
|
+
end
|
104
|
+
protected :pack
|
105
|
+
|
106
|
+
# データ更新後の、内部プロパティ更新処理を行います.
|
107
|
+
def unpack()
|
108
|
+
end
|
109
|
+
protected :unpack
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
# IHDRイメージヘッダチャンク.
|
114
|
+
class IHDRChunk < BaseChunk
|
115
|
+
# IHDRチャンクタイプ
|
116
|
+
TYPE = "IHDR"
|
117
|
+
|
118
|
+
# pack用IHDRデータレイアウト
|
119
|
+
LAYOUT = "N2C5"
|
120
|
+
|
121
|
+
attr_accessor :width
|
122
|
+
attr_accessor :height
|
123
|
+
attr_accessor :depth
|
124
|
+
attr_accessor :colortype
|
125
|
+
attr_accessor :compress
|
126
|
+
attr_accessor :filter
|
127
|
+
attr_accessor :interlace
|
128
|
+
|
129
|
+
def initialize(width = 0, height = 0, depth = 0,
|
130
|
+
colortype = COLORTYPE_TRUECOLOR,
|
131
|
+
compress = COMPRESSION_DEFLATE,
|
132
|
+
filter = FILTER_ADAPTIVE,
|
133
|
+
interlace = INTERLACE_NONE)
|
134
|
+
@width = width
|
135
|
+
@height = height
|
136
|
+
@depth = depth
|
137
|
+
@colortype = colortype
|
138
|
+
@compress = compress
|
139
|
+
@filter = filter
|
140
|
+
@interlace = interlace
|
141
|
+
|
142
|
+
super(IHDRChunk::TYPE)
|
143
|
+
end
|
144
|
+
|
145
|
+
def pack()
|
146
|
+
@data = [@width, @height, @depth, @colortype, @compress, @filter, @interlace].pack(IHDRChunk::LAYOUT)
|
147
|
+
end
|
148
|
+
protected :pack
|
149
|
+
|
150
|
+
def unpack()
|
151
|
+
@width, @height, @depth, @colortype, @compress, @filter, @interlace = @data.unpack(IHDRChunk::LAYOUT)
|
152
|
+
end
|
153
|
+
protected :unpack
|
154
|
+
|
155
|
+
# チャンクリストへ登録
|
156
|
+
Chunk.set(self::TYPE, self)
|
157
|
+
end
|
158
|
+
|
159
|
+
# PLTパレットチャンク
|
160
|
+
class PLTEChunk < BaseChunk
|
161
|
+
# PLTEチャンクタイプ
|
162
|
+
TYPE = 'PLTE'
|
163
|
+
|
164
|
+
# pack用PLTEチャンクデータレイアウト
|
165
|
+
LAYOUT = 'C*'
|
166
|
+
|
167
|
+
def initialize()
|
168
|
+
@colors = []
|
169
|
+
super(PLTEChunk::TYPE)
|
170
|
+
end
|
171
|
+
|
172
|
+
# 指定番号のカラーデータ (3バイト) を取得します.
|
173
|
+
#
|
174
|
+
# データオフセットではなく、3バイトごとに区切られたカラーのオフセットであることに注意.
|
175
|
+
#
|
176
|
+
# @param [Integer] offset カラー番号
|
177
|
+
# @return [Array] RGBカラーデータ
|
178
|
+
def [](offset)
|
179
|
+
return @colors[offset * 3, 3]
|
180
|
+
end
|
181
|
+
|
182
|
+
# 指定番号のカラーデータを更新します.
|
183
|
+
#
|
184
|
+
# @param [Integer] offset カラー番号
|
185
|
+
# @param [Array] rgb カラーデータ
|
186
|
+
def []=(offset, rgb)
|
187
|
+
@colors[offset * 3, 3] = rgb
|
188
|
+
end
|
189
|
+
|
190
|
+
def pack()
|
191
|
+
@data = @colors.pack(PLTEChunk::LAYOUT)
|
192
|
+
end
|
193
|
+
protected :pack
|
194
|
+
|
195
|
+
def unpack()
|
196
|
+
@colors = @data.unpack(PLTEChunk::LAYOUT)
|
197
|
+
end
|
198
|
+
protected :unpack
|
199
|
+
|
200
|
+
# チャンクリストへ登録
|
201
|
+
Chunk.set(self::TYPE, self)
|
202
|
+
end
|
203
|
+
|
204
|
+
# IDATイメージデータチャンク
|
205
|
+
class IDATChunk < BaseChunk
|
206
|
+
# IDATチャンクタイプ
|
207
|
+
TYPE = 'IDAT'
|
208
|
+
|
209
|
+
def initialize()
|
210
|
+
super(IDATChunk::TYPE)
|
211
|
+
end
|
212
|
+
|
213
|
+
# チャンクリストへ登録
|
214
|
+
Chunk.set(self::TYPE, self)
|
215
|
+
end
|
216
|
+
|
217
|
+
# IENDイメージトレーラチャンク
|
218
|
+
class IENDChunk < BaseChunk
|
219
|
+
# IENDチャンクタイプ
|
220
|
+
TYPE = 'IEND'
|
221
|
+
|
222
|
+
def initialize()
|
223
|
+
super(IENDChunk::TYPE, '')
|
224
|
+
end
|
225
|
+
|
226
|
+
# チャンクリストへ登録
|
227
|
+
Chunk.set(self::TYPE, self)
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
|
237
|
+
#==============================================================================#
|
238
|
+
# $Id: chunk.rb,v 57b1fb2cd6a6 2014/04/20 12:21:27 chikuchikugonzalez $
|
239
|
+
# vim: set sts=2 ts=2 sw=2 expandtab:
|