rixmap 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 74d87da8ef09dd6ee5469552b8baa9a576cb4da1
4
+ data.tar.gz: 24e2a21db530cdddf6a65e99feb1656e5b745eb0
5
+ SHA512:
6
+ metadata.gz: 2f70fb1617536f2dbb4b010e46608b0c8189ac4277a212002d6a5fd8f2255534784262dc3d5427775f3f369a5e3b734af774abe62fe49df75f49d4fccd9333fa
7
+ data.tar.gz: b893adf73dd5fd5e550da4f6526e56322c75935acadeace954b80c04848272c3086f81999896a0222893120ffe31564f6826312648b91dd09ca227b8de071d69
data/LICENSE.txt ADDED
@@ -0,0 +1,38 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2014 TANAKA Kenichi <chikuchikugonzalez@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+
24
+ 以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフト
25
+ ウェア」)の複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無
26
+ 償で許可します。これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒
27
+ 布、サブライセンス、および/または販売する権利、およびソフトウェアを提供する相
28
+ 手に同じことを許可する権利も無制限に含まれます。
29
+
30
+ 上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分
31
+ に記載するものとします。
32
+
33
+ ソフトウェアは「現状のまま」で、明示であるか暗黙であるかを問わず、何らの保証も
34
+ なく提供されます。ここでいう保証とは、商品性、特定の目的への適合性、および権利
35
+ 非侵害についての保証も含みますが、それに限定されるものではありません。 作者ま
36
+ たは著作権者は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起
37
+ 因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切
38
+ の請求、損害、その他の義務について何らの責任も負わないものとします。
data/README.markdown ADDED
@@ -0,0 +1,74 @@
1
+ # Rixmap is A Pixel-Map Imaging Library for Ruby - Ruby用Pix-Map画像ライブラリ -
2
+ **Rixmap**とは、Ruby用の簡易画像読み書きライブラリです.
3
+
4
+ ## Rixmapについて
5
+ ピクセルで構成された画像データを読み込んだり書き込んだりできる簡易ライブラリです.
6
+ 画像処理をするなら[RMagick](http://rmagick.rubyforge.org/)を使ったほうが幸せになれると思います \(マテ
7
+
8
+ ### なんで作ったの?
9
+ 作者は基本的に Windows ユーザなわけですが、RMagickのインストールがすこぶる面倒だったということがありまして。
10
+ 作者曰く
11
+
12
+ > 8bit PCXを読み込んでbmpにしたいだけなのに面倒だよこれ(´・ω・\`)
13
+
14
+ ということでした。探してもいいのがないので作るか、っていうのが動機です。
15
+
16
+ ## 特徴のようなもの
17
+ * ほかのライブラリをなるべく使わない方向での実装
18
+ * `NArray`とかを使ってた時期もあったけどやめました
19
+ * 基本的に **Windows** 用です
20
+
21
+ ## ライセンスについて
22
+ MITライセンスとします. (LICENSE.txtに条文書いておきました)
23
+
24
+ ## 作者
25
+ _タナカ ケンイチ (TANAKA Kenichi) aka チクチーク・ゴンザレス (chikuchikugonzalez)_
26
+
27
+ ### 連絡先
28
+ #### E-mail
29
+ * mailto:chikuchikugonzalez@gmail.com
30
+ * mailto:chiku2gonzalez@live.jp
31
+
32
+ #### Twitter
33
+ * [ちくちく(・∀・)ごんざれす on Twitter](https://twitter.com/chiku2gonzalez)
34
+
35
+ ### 活動場所
36
+ * [chikuchikugonzalezの雑記帳](http://chiku2gonzalez.hatenablog.com/)
37
+
38
+ ## 参考資料
39
+ ### Windows Bitmap
40
+ * [Bitmaps (Windows)](http://msdn.microsoft.com/en-us/library/dd183377%28v=vs.85%29.aspx)
41
+ * [Microsoft RLE](http://wiki.multimedia.cx/index.php?title=Microsoft_RLE)
42
+ * [Bitmapファイルフォーマット](http://www.umekkii.jp/data/computer/file_format/bitmap.cgi)
43
+ * [BMPファイル仕様 - ルーチェ's Homepage](http://www.ruche-home.net/program/bmp)
44
+
45
+ ### PC Paintbrush File Format (PCX)
46
+ * [PCX File Format Summary](http://www.fileformat.info/format/pcx/egff.htm)
47
+ * [file-format-pcx](http://www.daubnet.com/en/file-format-pcx)
48
+
49
+ ### X PixMap (XPM)
50
+ * [X PixMap - Wikipedia](http://en.wikipedia.org/wiki/X_PixMap "英語版Wikipedia情報")
51
+ * [XPM - Wikipedia](http://ja.wikipedia.org/wiki/XPM "日本語版Wikipedia情報")
52
+ * [XPM File Format Summary](http://www.fileformat.info/format/xpm/egff.htm)
53
+
54
+ ### Portable Network Graphics (PNG)
55
+ * [Portable Network Graphics(PNG)仕様 第2版 日本語訳](http://www.milk-island.net/document/png/)
56
+ * [PNGファイルフォーマット](http://www14.ocn.ne.jp/~setsuki/ext/png.htm)
57
+ * [Portable Network Graphics - Wikipedia](https://ja.wikipedia.org/wiki/Portable_Network_Graphics)
58
+ * [PNG画像を自力で読む](http://kanow.jp/programming/png-loader.xhtml)
59
+ * [PNGについて](http://homepage2.nifty.com/sophia0/png.html)
60
+
61
+ ### アフィン変換
62
+ * [線形代数入門](http://kagennotuki.sakura.ne.jp/la/la.html)
63
+ * [2x2行列と3x3行列と4x4行列の逆行列の公式](http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/tech23.html)
64
+ * [イメージングソリューション](http://imagingsolution.net/)
65
+ * [アフィン変換 イメージングソリューション](http://imagingsolution.net/imaging/affine-transformation/)
66
+ * [画素の補間 イメージングソリューション](http://imagingsolution.net/imaging/interpolation/)
67
+
68
+ ### その他
69
+ * [std::vectorへ配列をコピーする方法](http://stackoverflow.com/questions/259297/how-do-you-copy-the-contents-of-an-array-to-a-stdvector-in-c-without-looping)
70
+ * [mapをsort](http://d.hatena.ne.jp/graighle/20080510/1210438595)
71
+ * [クラスをSTLコンテナにいれると恐ろしい事が起こるぞ!](http://isoparametric.net/entry/20091210/1260408984)
72
+
73
+
74
+ <!-- vim: set sts=4 ts=4 sw=4 expandtab filetype=markdown: -->
data/Rakefile ADDED
@@ -0,0 +1,156 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'rbconfig'
3
+ require 'rake/clean'
4
+ begin
5
+ require 'rubygems'
6
+ require 'rubygems/package_task'
7
+ rescue LoadError => e
8
+ $stderr.puts "LoadError: Can't load rubygems."
9
+ end
10
+ begin
11
+ require 'yard'
12
+ require 'yard/rake/yardoc_task'
13
+ rescue LoadError => e
14
+ $stderr.puts "LoadError: Can't load yard."
15
+ end
16
+ begin
17
+ require 'rspec/core/rake_task'
18
+ rescue LoadError => e
19
+ $stderr.puts "Loaderror: Can't load RSpec"
20
+ end
21
+ Encoding.default_external = 'utf-8'
22
+
23
+ #------------------------------------------------------------------------------#
24
+ # C拡張ビルドルール
25
+ #------------------------------------------------------------------------------#
26
+ # ビルドターゲット定義
27
+ EXTS = {
28
+ 'rixmap' => {
29
+ :mkmf => 'src/extconf.rb',
30
+ :deps => FileList["src/*.{cxx,hxx}"] + FileList["src/rixmap/*.{hxx,cxx}"] + FileList["src/chollas/*.{hxx,cxx}"],
31
+ :dll => "src/rixmap.#{RbConfig::CONFIG['DLEXT']}",
32
+ :ext => "lib/#{RUBY_PLATFORM}/rixmap.#{RbConfig::CONFIG['DLEXT']}"
33
+ }
34
+ }
35
+
36
+ # makeコマンドチェック
37
+ if /(mswin)/ =~ RUBY_PLATFORM
38
+ # MS-Windows
39
+ MAKE = %w[nmake].find do |make|
40
+ begin
41
+ `#{make} /help`
42
+ $? == 0
43
+ rescue
44
+ # nmakeが失敗した (無視)
45
+ end
46
+ end
47
+ else
48
+ # MinGW / Cygwin / Linux / Mac / etc..
49
+ MAKE = ENV['MAKE'] || %w[make gmake].find do |make|
50
+ begin
51
+ `#{make} -v`
52
+ $? == 0
53
+ rescue
54
+ # makeツールが失敗 (無視)
55
+ end
56
+ end
57
+ end
58
+
59
+ # ビルドルール定義
60
+ if defined?(MAKE)
61
+ CLEAN.include(FileList["src/**/*.{so,bundle,dll,#{RbConfig::CONFIG['DLEXT']},o,obj,pdb,lib,exp,def}"])
62
+ CLOBBER.include(FileList["lib/**/*.{so,bundle,dll,#{RbConfig::CONFIG['DLEXT']}}"])
63
+ CLOBBER.include(FileList["src/**/{Makefile}"])
64
+
65
+ namespace :build do
66
+ EXTS.each do |name, config|
67
+ distroot = File.dirname(config[:ext])
68
+ makeroot = File.dirname(config[:mkmf])
69
+ makeconf = File.basename(config[:mkmf])
70
+ makefile = "#{makeroot}/Makefile"
71
+
72
+ # ディレクトリ依存関係
73
+ directory distroot
74
+
75
+ # 拡張ライブラリビルド
76
+ file config[:dll] => [config[:mkmf]] + config[:deps] do |t|
77
+ cd makeroot do
78
+ ruby makeconf
79
+ sh MAKE
80
+ end
81
+ end
82
+
83
+ # 拡張インストール
84
+ file config[:ext] => [distroot, config[:dll], config[:mkmf]] do |t|
85
+ cp config[:dll], config[:ext]
86
+ end
87
+
88
+ # 基本タスク
89
+ desc "Build #{name}"
90
+ task name => config[:ext]
91
+ end
92
+ end
93
+
94
+ # 総合タスク
95
+ desc "Build ALL C-Extension Libraries"
96
+ task :build => EXTS.keys.collect {|name| "build:#{name}"}
97
+ end
98
+
99
+ #------------------------------------------------------------------------------#
100
+ # Yardによるドキュメント生成タスク
101
+ #------------------------------------------------------------------------------#
102
+ if defined?(YARD::Rake::YardocTask)
103
+ YARD::Rake::YardocTask.new do |yd|
104
+ yd.files = FileList['src/**/*.{c,cpp,cxx}']
105
+ yd.files += FileList['lib/**/*.rb']
106
+ yd.options << '--markup=markdown'
107
+ yd.options << '--private'
108
+ yd.options << '--readme=README.markdown'
109
+ yd.options << '--charset=utf-8'
110
+ yd.options << '--output-dir=doc'
111
+ yd.options << '--no-cache'
112
+ #yd.options << '--debug'
113
+ #yd.options << '--single-db'
114
+ #yd.options << '--one-file'
115
+ end
116
+
117
+ desc "Remove YARD Documentation"
118
+ task "clobber_yard" do |t|
119
+ remove_dir "doc"
120
+ end
121
+ else
122
+ # yardocないお(´・ω・`)
123
+ end
124
+
125
+ #------------------------------------------------------------------------------#
126
+ # Gem Package作成ルール
127
+ #------------------------------------------------------------------------------#
128
+ if defined?(Gem::PackageTask)
129
+ spec = eval(File.read('rixmap.gemspec'), TOPLEVEL_BINDING)
130
+ Gem::PackageTask.new(spec) do |pkg|
131
+ pkg.need_zip = true
132
+ pkg.need_tar = true
133
+ end
134
+ else
135
+ # gem作れないお(´;ω;`)
136
+ end
137
+
138
+ #------------------------------------------------------------------------------#
139
+ # RSpec実行ルール
140
+ #------------------------------------------------------------------------------#
141
+ if defined?(RSpec::Core::RakeTask)
142
+ RSpec::Core::RakeTask.new() do |rspec|
143
+ rspec.verbose = true
144
+ rspec.rspec_opts = "-fs --warnings --backtrace --profile"
145
+ if RbConfig::CONFIG['MAJOR'].to_i >= 2
146
+ rspec.rspec_opts += " --color"
147
+ end
148
+ end
149
+ else
150
+ # RSpecないな(´・ω・`)
151
+ end
152
+
153
+
154
+ #==============================================================================#
155
+ # $Id: Rakefile,v 431aac54543a 2014/04/20 15:12:27 chikuchikugonzalez $
156
+ # vim: set sts=2 ts=2 sw=2 expandtab:
@@ -0,0 +1,326 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ #
4
+ module Rixmap
5
+ module Format
6
+
7
+ # Windows Bitmapフォーマット対応実装モジュール.
8
+ module BMP
9
+
10
+ # BMPファイルシグネチャ
11
+ FILE_SIGNATURE = 'BM'
12
+
13
+ # @see http://msdn.microsoft.com/en-us/library/cc250415.aspx
14
+ class CompressionType
15
+ # 無圧縮BMP
16
+ RGB = 0x00
17
+
18
+ # 8bit用ランレングス圧縮
19
+ RLE8 = 0x01
20
+
21
+ # 4bit用ランレングス圧縮
22
+ RLE4 = 0x02
23
+
24
+ # ビットフィールド圧縮.
25
+ # 16bitや32bitで使われることがある.
26
+ BITFIELDS = 0x03
27
+
28
+ # JPEG圧縮
29
+ JPEG = 0x04
30
+
31
+ # PNG圧縮
32
+ PNG = 0x05
33
+ end
34
+
35
+ # # @see http://msdn.microsoft.com/en-us/library/cc250396.aspx
36
+ # # @see http://msdn.microsoft.com/en-us/library/cc250410.aspx
37
+ # class ColorSpaceType
38
+ # CALIBRATED_RGB = 0x00000000
39
+ # SRGB = 0x73524742 # "sRGB"
40
+ # WINDOWS_COLOR_SPACE = 0x57696E20 # "Win "
41
+ #
42
+ # # V5 extended
43
+ # PROFILE_LINKED = 0x4C494E4B # "LINK"
44
+ # PROFILE_EMBEDDED = 0x4D424544 #"MBED"
45
+ # end
46
+ #
47
+ # # @see http://msdn.microsoft.com/en-us/library/cc250392.aspx
48
+ # class GamutMappingIntentType
49
+ # GM_ABS_COLORIMETRIC = 0x00000008
50
+ # GM_BUSINESS = 0x00000001
51
+ # GM_GRAPHICS = 0x00000002
52
+ # GM_IMAGES = 0x00000004
53
+ # end
54
+ #
55
+ # # @see http://msdn.microsoft.com/en-us/library/windows/desktop/dd371828%28v=vs.85%29.aspx
56
+ # CIEXYZ = Struct.new('CIEXYZ', :x, :y, :z)
57
+ #
58
+ # # @see http://msdn.microsoft.com/en-us/library/windows/desktop/dd371833%28v=vs.85%29.aspx
59
+ # CIEXYZTriple = Struct.new('CIEXYZTriple', :red, :green, :blue)
60
+ #
61
+ # # ビットマスク
62
+ # class Mask
63
+ # attr_accessor :red
64
+ # attr_accessor :green
65
+ # attr_accessor :blue
66
+ # attr_accessor :alpha
67
+ # end
68
+ #
69
+ # # ガンマ値
70
+ # class Gamma
71
+ # attr_accessor :red
72
+ # attr_accessor :green
73
+ # attr_accessor :blue
74
+ # end
75
+
76
+ # ファイルヘッダ構造体
77
+ #
78
+ # @see http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374%28v=vs.85%29.aspx
79
+ BMPFileHeader = Struct.new('BMPFileHeader', :type, :size, :reserved, :offset)
80
+
81
+ # 情報ヘッダ構造体
82
+ #
83
+ # @see http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376%28v=vs.85%29.aspx
84
+ BMPInfoHeader = Struct.new('BMPInfoHeader', :size, :width, :height, :planes, :bit_count, :compression, :image_size, :ppm_x, :ppm_y, :used_color_count, :important_color_count)
85
+
86
+ # BMP入出力処理実装.
87
+ #
88
+ # TODO V4対応
89
+ # TODO V5対応
90
+ # TODO OS/2対応
91
+ class BMPImageIO < Rixmap::ImageIO::BaseImageIO
92
+ # ファイルヘッダテンプレート.
93
+ FILEHEADER_TEMPLATE = "a2LLL"
94
+ #INFOHEADER_TEMPLATE = "LllSSLLllLL"
95
+
96
+ # 情報ヘッダテンプレート (v3用)
97
+ INFOHEADER_TEMPLATE = "LllSSLLllLL"
98
+
99
+ # ファイルヘッダサイズ
100
+ FILEHEADER_SIZE = 14
101
+
102
+ # 情報ヘッダサイズ (v3用)
103
+ INFOHEADER_SIZE = 40
104
+
105
+ # 画像データの先頭から読み込める画像データかどうかを調べます.
106
+ #
107
+ # @return [Boolean] BMPとして読み込めるならtrue
108
+ def self.readable?(magic)
109
+ return magic[0..1] == 'BM'
110
+ end
111
+
112
+ # BMP形式で書き込める画像かどうかを返します.
113
+ #
114
+ # 全種類書き込めるけど、グレースケール形式はインデックス形式に変換されます.
115
+ #
116
+ # @return [Boolean] 常にtrue
117
+ def self.writable?(image)
118
+ if image.kind_of?(Rixmap::Image)
119
+ return true
120
+ else
121
+ return false
122
+ end
123
+ end
124
+
125
+ # BMP形式として画像をエンコードします.
126
+ #
127
+ # @param [Rixmap::Image] image 対象画像
128
+ # @param [Hash] options オプションパラメータ
129
+ # @return [String] エンコードされた画像のバイト列
130
+ def encode(image, options={})
131
+ # ヘッダ
132
+ bf = BMPFileHeader.new('BM', 0, 0, 0)
133
+ bi = BMPInfoHeader.new(INFOHEADER_SIZE, 0, 0, 1, 0, 0, 0, 3780, 3780, 0, 0)
134
+
135
+ # 基本情報
136
+ bi.width = image.width
137
+ bi.height = image.height
138
+ bi.bit_count = image.mode.depth
139
+ bi.compression = CompressionType::RGB
140
+
141
+ # データ部品
142
+ bytes_per_line = ((image.width * image.mode.depth + 31) / 32) * 4
143
+ palbuf = ''
144
+ palbuf.force_encoding(Encoding::ASCII_8BIT)
145
+ pixbuf = ''
146
+ pixbuf.force_encoding(Encoding::ASCII_8BIT)
147
+
148
+ # 画像形式で分岐
149
+ case image.mode
150
+ when Rixmap::INDEXED
151
+ bi.used_color_count = image.palette.size
152
+ bi.important_color_count = image.palette.size
153
+ palbuf = image.palette.to_s('BGRA')
154
+ padding_size = bytes_per_line - image.width
155
+ padding_bytes = "\x00" * padding_size
156
+ (image.height - 1).downto(0) do |h|
157
+ line = image[h].to_s('P')
158
+ pixbuf.concat(line)
159
+ pixbuf.concat(padding_bytes)
160
+ end
161
+
162
+ when Rixmap::GRAYSCALE
163
+ # 疑似パレットデータ
164
+ graypal = Rixmap::Palette.new(256)
165
+ 256.times do |i|
166
+ graypal[i] = [i, i, i, 255]
167
+ end
168
+ palbuf = graypal.to_s('BGRA')
169
+
170
+ # ピクセルデータ
171
+ padding_size = bytes_per_line - image.width
172
+ padding_bytes = "\x00" * padding_size
173
+ (image.height - 1).downto(0) do |h|
174
+ line = image[h].to_s('L')
175
+ pixbuf.concat(line)
176
+ pixbuf.concat(padding_bytes)
177
+ end
178
+ when Rixmap::GRAYALPHA
179
+ bytes_per_line = ((image.width * 32 + 31) / 32) * 4
180
+ bi.bit_count = 32
181
+
182
+ # RGBA扱いにする
183
+ padding_size = bytes_per_line - (image.width * 4)
184
+ padding_bytes = "\x00" * padding_size
185
+ (image.height - 1).downto(0) do |h|
186
+ line = image[h].to_s('LLLA')
187
+ pixbuf.concat(line)
188
+ pixbuf.concat(padding_bytes)
189
+ end
190
+ when Rixmap::RGB
191
+ padding_size = bytes_per_line - (image.width * 3)
192
+ padding_bytes = "\x00" * padding_size
193
+ (image.height - 1).downto(0) do |h|
194
+ line = image[h].to_s('BGR')
195
+ pixbuf.concat(line)
196
+ pixbuf.concat(padding_bytes)
197
+ end
198
+ when Rixmap::RGBA
199
+ padding_size = bytes_per_line - (image.width * 4)
200
+ padding_bytes = "\x00" * padding_size
201
+ (image.height - 1).downto(0) do |h|
202
+ line = image[h].to_s('BGRA')
203
+ pixbuf.concat(line)
204
+ pixbuf.concat(padding_bytes)
205
+ end
206
+ else
207
+ raise "Unsupported Image Mode: #{image.mode}"
208
+ end
209
+
210
+ # ヘッダを調整
211
+ bf.offset = FILEHEADER_SIZE + INFOHEADER_SIZE + palbuf.bytesize
212
+ bi.image_size = pixbuf.bytesize
213
+ bf.size = bf.offset + bi.image_size
214
+
215
+ # パック
216
+ bfbytes = bf.to_a.pack(FILEHEADER_TEMPLATE)
217
+ bibytes = bi.to_a.pack(INFOHEADER_TEMPLATE)
218
+
219
+ # 結合
220
+ imgbytes = bfbytes.clone
221
+ imgbytes.concat(bibytes)
222
+ imgbytes.concat(palbuf)
223
+ imgbytes.concat(pixbuf)
224
+ return imgbytes
225
+ end
226
+
227
+ # バイト列をBMPとして復元します.
228
+ #
229
+ # @param [String] data BMP形式画像のバイト列データ
230
+ # @param [Hash] options オプションパラメータ
231
+ # @return [Rixmap::Image] 復元された画像オブジェクト
232
+ def decode(data, options={})
233
+ unless data[0..1] == 'BM'
234
+ raise ArgumentError.new("InvalidSignature detected. Input is not BMP Image Data.")
235
+ end
236
+
237
+ # ヘッダ構造体
238
+ bf = BMPFileHeader.new
239
+ bi = BMPInfoHeader.new
240
+
241
+ # ファイルヘッダの復元
242
+ bfbytes = data.byteslice(0...FILEHEADER_SIZE)
243
+ bf.type, bf.size, bf.reserved, bf.offset = bfbytes.unpack(FILEHEADER_TEMPLATE)
244
+
245
+ # 情報ヘッダの復元
246
+ bi.size = data.byteslice(FILEHEADER_SIZE, 4).unpack('L')[0]
247
+ if bi.size < INFOHEADER_SIZE
248
+ raise NotImplementedError.new("Unsupported Info-Header Size: #{bi.size}")
249
+ end
250
+ bitemplate = INFOHEADER_TEMPLATE.clone
251
+ if bi.size > 40
252
+ bitemplate.concat("x#{INFOHEADER_SIZE - bi.size}")
253
+ end
254
+ bibytes = data.byteslice(FILEHEADER_SIZE, bi.size)
255
+ _, bi.width, bi.height, bi.planes, bi.bit_count, bi.compression, bi.image_size, bi.ppm_x, bi.ppm_y, bi.used_color_count, bi.important_color_count = bibytes.unpack(bitemplate)
256
+
257
+ # 画像を復元
258
+ image = nil
259
+ pixoffset = if bf.offset > 0
260
+ bf.offset
261
+ else
262
+ FILEHEADER_SIZE + bi.size + bi.used_color_count * 4
263
+ end
264
+ pixbytes = data.byteslice(pixoffset..-1)
265
+ bytes_per_line = ((bi.width * bi.bit_count + 31) / 32) * 4
266
+
267
+ case bi.bit_count
268
+ when 8
269
+ image = Rixmap::Image.new(Rixmap::INDEXED, bi.width, bi.height)
270
+
271
+ # パレットを復元
272
+ ncolors = bi.used_color_count
273
+ palbytes = data.byteslice((FILEHEADER_SIZE + bi.size), (ncolors * 4))
274
+ palbytes.unpack('C*').each_slice(4).each_with_index do |c, i|
275
+ break if i >= image.palette.size
276
+ image.palette[i] = [c[2], c[1], c[0], c[3]]
277
+ end
278
+
279
+ # ピクセルを復元
280
+ bi.height.times do |h|
281
+ line_no = (bi.height - 1) - h
282
+ line_data = pixbytes.byteslice((h * bytes_per_line)...((h + 1) * bytes_per_line))
283
+ image[line_no].palette = line_data
284
+ end
285
+ when 24
286
+ image = Rixmap::Image.new(Rixmap::RGB, bi.width, bi.height)
287
+
288
+ # ピクセルを復元
289
+ bi.height.times do |h|
290
+ line_no = (bi.height - 1) - h
291
+ line_data = pixbytes.byteslice((h * bytes_per_line)...((h + 1) * bytes_per_line))
292
+ line_data.unpack('C*').each_slice(3).each_with_index do |c, i|
293
+ break if i >= bi.width
294
+ image[i, line_no] = [c[2], c[1], c[0]]
295
+ end
296
+ end
297
+ when 32
298
+ image = Rixmap::Image.new(Rixmap::RGBA, bi.width, bi.height)
299
+
300
+ # ピクセルを復元
301
+ bi.height.times do |h|
302
+ line_no = (bi.height - 1) - h
303
+ line_data = pixbytes.byteslice((h * bytes_per_line)...((h + 1) * bytes_per_line))
304
+ line_data.unpack('C*').each_slice(4).each_with_index do |c, i|
305
+ break if i >= bi.width
306
+ image[i, line_no] = [c[2], c[1], c[0], c[3]]
307
+ end
308
+ end
309
+ else
310
+ raise NotImplementedError.new("Unsupported Bit-Count: #{bi.bit_count}")
311
+ end
312
+
313
+ return image
314
+ end
315
+ end
316
+
317
+ Rixmap::ImageIO.register(:BMP, BMPImageIO, [".bmp"])
318
+ end
319
+
320
+ end
321
+ end
322
+
323
+
324
+ #==============================================================================#
325
+ # $Id: bmp.rb,v 57b1fb2cd6a6 2014/04/20 12:21:27 chikuchikugonzalez $
326
+ # vim: set sts=2 ts=2 sw=2 expandtab: