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
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:
|