pruim 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +44 -0
- data/Rakefile +49 -0
- data/lib/pruim/bmp.rb +238 -0
- data/lib/pruim/codec.rb +74 -0
- data/lib/pruim/color.rb +34 -0
- data/lib/pruim/image.rb +160 -0
- data/lib/pruim/movie.rb +15 -0
- data/lib/pruim/page.rb +82 -0
- data/lib/pruim/palette.rb +17 -0
- data/lib/pruim/pbm.rb +70 -0
- data/lib/pruim/ppm.rb +76 -0
- data/lib/pruim.rb +10 -0
- data/test/atto.rb +9 -0
- data/test/pruim/test_bmp.rb +90 -0
- data/test/pruim/test_image.rb +34 -0
- data/test/pruim/test_page.rb +15 -0
- data/test/pruim/test_pbm.rb +36 -0
- data/test/pruim/test_ppm.rb +44 -0
- data/test/test_helper.rb +20 -0
- data/test/test_image.rb +47 -0
- metadata +94 -0
data/README
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
+------------------------------------+
|
2
|
+
| Pruim -- a Pure RUby IMage library |
|
3
|
+
+------------------------------------+
|
4
|
+
|
5
|
+
Introduction
|
6
|
+
------------
|
7
|
+
|
8
|
+
Pruim is a Pure RUby IMage library, with the indent of supporting
|
9
|
+
multiple image formats. Currently only supports loading from and
|
10
|
+
saving to PPM files and paletted BMP files. Contributions of
|
11
|
+
other formats are welcome. :)
|
12
|
+
|
13
|
+
Requirements
|
14
|
+
------------
|
15
|
+
|
16
|
+
BinData (gem install bindata) is required. It makes decoding images much easier.
|
17
|
+
Watch and autowatchr for testing.
|
18
|
+
Run watchr test/test.watchr to run the tests.
|
19
|
+
|
20
|
+
|
21
|
+
License
|
22
|
+
-------
|
23
|
+
|
24
|
+
You may use Pruim under the Zlib license:
|
25
|
+
|
26
|
+
Pruim is Copyright (C) 2011 Beoran beoran@rubyforge.org
|
27
|
+
|
28
|
+
This software is provided 'as-is', without any express or implied
|
29
|
+
warranty. In no event will the authors be held liable for any damages
|
30
|
+
arising from the use of this software.
|
31
|
+
|
32
|
+
Permission is granted to anyone to use this software for any purpose,
|
33
|
+
including commercial applications, and to alter it and redistribute it
|
34
|
+
freely, subject to the following restrictions:
|
35
|
+
|
36
|
+
1. The origin of this software must not be misrepresented; you must not
|
37
|
+
claim that you wrote the original software. If you use this software
|
38
|
+
in a product, an acknowledgment in the product documentation would be
|
39
|
+
appreciated but is not required.
|
40
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
41
|
+
misrepresented as being the original software.
|
42
|
+
3. This notice may not be removed or altered from any source distribution.
|
43
|
+
|
44
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/package_task'
|
3
|
+
require 'rake/clean'
|
4
|
+
CLEAN.include("pkg/*.gem")
|
5
|
+
|
6
|
+
|
7
|
+
PRUIM_VERSION = "0.1.0"
|
8
|
+
|
9
|
+
def apply_spec_defaults(s)
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
spec = Gem::Specification.new do |s|
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
s.summary = "Pure Ruby Image Library."
|
16
|
+
s.name = 'pruim'
|
17
|
+
s.version = '0.1.0'
|
18
|
+
s.add_dependency('bindata', '>= 1.0.0')
|
19
|
+
s.add_development_dependency('atto', '>= 0.9.2')
|
20
|
+
s.require_path = 'lib'
|
21
|
+
s.files = ['README', 'Rakefile'] +
|
22
|
+
FileList["lib/pruim.rb", "lib/pruim/*.rb",
|
23
|
+
"test/*.rb" , "test/pruim/*.rb" ].to_a
|
24
|
+
s.description = <<EOF
|
25
|
+
Pruim is a Pure Ruby Image Library. Currently only supports BMP, PPM and PBM
|
26
|
+
formats, but preserves palette ordering on reading and writing.
|
27
|
+
EOF
|
28
|
+
s.author = 'beoran'
|
29
|
+
s.email = 'beoran@rubyforge.org'
|
30
|
+
s.homepage = 'http://github.com/beoran/pruim'
|
31
|
+
s.date = Time.now.strftime '%Y-%m-%d'
|
32
|
+
end
|
33
|
+
|
34
|
+
Gem::PackageTask.new(spec) do |pkg|
|
35
|
+
pkg.need_zip = false
|
36
|
+
pkg.need_tar = false
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
task :test do
|
41
|
+
for file in FileList["test/*.rb" , "test/pruim/*.rb" ] do
|
42
|
+
puts("Running tests for #{file}:")
|
43
|
+
res = system("ruby -I lib #{file}")
|
44
|
+
puts res ? "OK!" : "Failed!"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
task :default => :test
|
49
|
+
|
data/lib/pruim/bmp.rb
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
|
3
|
+
module Pruim
|
4
|
+
class BMP
|
5
|
+
include Codec
|
6
|
+
|
7
|
+
class Header < BinData::Record
|
8
|
+
endian :little
|
9
|
+
string :magic, :length => 2
|
10
|
+
uint32 :filesize
|
11
|
+
uint16 :creator1
|
12
|
+
uint16 :creator2
|
13
|
+
uint32 :bitmap_offset
|
14
|
+
def set(*args)
|
15
|
+
self.magic, self.filesize, self.creator1, self.creator2,
|
16
|
+
self.bitmap_offset = *args
|
17
|
+
self
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class CoreHeader < BinData::Record
|
22
|
+
endian :little
|
23
|
+
uint32 :header_size
|
24
|
+
int32 :width
|
25
|
+
int32 :height
|
26
|
+
uint16 :nplanes
|
27
|
+
uint16 :bitspp
|
28
|
+
def set(*args)
|
29
|
+
self.header_size, self.width, self.height, self.nplanes,
|
30
|
+
self.bitspp = *args
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class ExtraHeader < BinData::Record
|
36
|
+
endian :little
|
37
|
+
# uint32 :header_size
|
38
|
+
# int32 :width
|
39
|
+
# int32 :height
|
40
|
+
# uint16 :nplanes
|
41
|
+
# uint16 :bitspp
|
42
|
+
uint32 :compress_type
|
43
|
+
uint32 :bmp_bytesz
|
44
|
+
int32 :hres
|
45
|
+
int32 :vres
|
46
|
+
uint32 :ncolors
|
47
|
+
uint32 :nimpcolors
|
48
|
+
|
49
|
+
def set(*args)
|
50
|
+
self.compress_type, self.bmp_bytesz, self.hres, self.vres, self.ncolors,
|
51
|
+
self.nimpcolors = *args
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
BI_RGB = 0 #
|
57
|
+
BI_RLE8 = 1 # RLE 8-bit/pixel Can be used only with 8-bit/pixel bitmaps
|
58
|
+
BI_RLE4 = 2 # RLE 4-bit/pixel Can be used only with 4-bit/pixel bitmaps
|
59
|
+
BI_BITFIELDS = 3 # Bit field or Huffman 1D compression for BITMAPCOREHEADER2
|
60
|
+
BI_JPEG = 4 # JPEG or RLE-24 compression for BITMAPCOREHEADER2
|
61
|
+
BI_PNG = 5 # PNG The bitmap contains a PNG image.
|
62
|
+
BITMAPINFOHEADER=40 # Commonly used
|
63
|
+
BITMAPV5HEADER =124# Latest version
|
64
|
+
HEADER_SIZE = 14
|
65
|
+
|
66
|
+
|
67
|
+
class BGRX < BinData::Record
|
68
|
+
uint8 :b
|
69
|
+
uint8 :g
|
70
|
+
uint8 :r
|
71
|
+
uint8 :x
|
72
|
+
def set(b, g, r, x)
|
73
|
+
self.b = b
|
74
|
+
self.g = g
|
75
|
+
self.r = r
|
76
|
+
self.x = x
|
77
|
+
self
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class BGR < BinData::Record
|
82
|
+
uint8 :b
|
83
|
+
uint8 :g
|
84
|
+
uint8 :r
|
85
|
+
|
86
|
+
def set(b, g, r)
|
87
|
+
self.b = b
|
88
|
+
self.g = g
|
89
|
+
self.r = r
|
90
|
+
self
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class ColorTableRGBX < BinData::Record
|
95
|
+
array :type => BGRX
|
96
|
+
end
|
97
|
+
|
98
|
+
def can_decode?(io)
|
99
|
+
header = Header.read(io)
|
100
|
+
io.rewind
|
101
|
+
return header && header.magic == 'BM'
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def read_palette(io, header, core, extra)
|
106
|
+
palette = Pruim::Palette.new
|
107
|
+
ncolors = 2 ** core.bitspp
|
108
|
+
for i in 0..255
|
109
|
+
color = BGRX.read(io)
|
110
|
+
palette.new_rgb(color.r, color.g, color.b)
|
111
|
+
raise "Unexpected end of file whilst reading bmp palette!" if io.eof?
|
112
|
+
end
|
113
|
+
return palette
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def decode_bpp8_rgb(io, header, core, extra, padding)
|
118
|
+
data = []
|
119
|
+
for ypos in (0...core.height)
|
120
|
+
size = core.width + padding
|
121
|
+
# read a line with padding
|
122
|
+
raise "End of file when reading BMP btyes!" if io.eof?
|
123
|
+
str = io.read(size)
|
124
|
+
raise "Short read when reading BMP bytes!" unless str && str.bytesize == size
|
125
|
+
# make an array out of it and drop the padding
|
126
|
+
arr = str.bytes.to_a
|
127
|
+
arr.pop(padding)
|
128
|
+
data = arr + data # prepend data
|
129
|
+
end
|
130
|
+
return data
|
131
|
+
end
|
132
|
+
|
133
|
+
# Calculate padding size
|
134
|
+
def calc_padding(wide, palette = true)
|
135
|
+
bs = palette ? 1 : 3
|
136
|
+
padding = (1 * bs * wide) % 4;
|
137
|
+
padding = 4 - padding if padding != 0
|
138
|
+
return padding
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
def decode_bpp8(io, header, core, extra)
|
143
|
+
# p header, core, extra
|
144
|
+
io.seek(HEADER_SIZE + core.header_size)
|
145
|
+
palette = read_palette(io, header, core, extra)
|
146
|
+
# Skip to the bitmap, gap may be there...
|
147
|
+
io.seek(header.bitmap_offset)
|
148
|
+
# Calculate padding size
|
149
|
+
padding = calc_padding(core.width, true)
|
150
|
+
data = nil
|
151
|
+
case extra.compress_type
|
152
|
+
when BI_RGB
|
153
|
+
data = decode_bpp8_rgb(io, header, core, extra, padding)
|
154
|
+
else
|
155
|
+
return nil
|
156
|
+
end
|
157
|
+
image = Image.new(core.width, core.height, :depth => core.bitspp,
|
158
|
+
:palette => palette, :pages => 1, :data => [data])
|
159
|
+
return image
|
160
|
+
end
|
161
|
+
|
162
|
+
def decode(io)
|
163
|
+
header = Header.read(io)
|
164
|
+
core = CoreHeader.read(io)
|
165
|
+
extra = nil
|
166
|
+
if (core.header_size == BITMAPINFOHEADER)
|
167
|
+
extra = ExtraHeader.read(io)
|
168
|
+
end
|
169
|
+
io.seek(HEADER_SIZE + core.header_size)
|
170
|
+
# skip rest of header that we don't support
|
171
|
+
if core.bitspp == 8
|
172
|
+
return decode_bpp8(io, header, core, extra)
|
173
|
+
end
|
174
|
+
# TODO: real color bitmaps.
|
175
|
+
return nil
|
176
|
+
end
|
177
|
+
|
178
|
+
def encode_palette(image, io)
|
179
|
+
image.palette.each do |color|
|
180
|
+
r, g, b = *Color.to_rgb(color)
|
181
|
+
bgrx = BGRX.new.set(b, g, r, 0)
|
182
|
+
bgrx.write(io)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def encode_bpp8_rgb(image, io, padding)
|
187
|
+
page = image.active
|
188
|
+
ypos = image.h - 1
|
189
|
+
while ypos >= 0
|
190
|
+
row = page.row(ypos)
|
191
|
+
row = row + [0] * padding
|
192
|
+
str = row.pack('C*')
|
193
|
+
io.write(str)
|
194
|
+
ypos -= 1
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
def encode_bpp8(image, io, padding)
|
200
|
+
encode_palette(image, io)
|
201
|
+
encode_bpp8_rgb(image, io, padding)
|
202
|
+
end
|
203
|
+
|
204
|
+
def encode_bpp24(image, io, padding)
|
205
|
+
end
|
206
|
+
|
207
|
+
def encode(image, io)
|
208
|
+
bitcount = (image.palette? ? 8 : 24)
|
209
|
+
bitmap_size = ((image.w * bitcount) / 8) * image.h
|
210
|
+
info_size = BITMAPINFOHEADER
|
211
|
+
# Data for the palette
|
212
|
+
if image.palette?
|
213
|
+
info_size += image.palette.size * 4
|
214
|
+
end
|
215
|
+
total_size = 14 + info_size + bitmap_size
|
216
|
+
# write bmp header info
|
217
|
+
header = Header.new.set('BM', total_size, 0, 0, 14 + info_size)
|
218
|
+
header.write(io)
|
219
|
+
core = CoreHeader.new.set(BITMAPINFOHEADER, image.w, image.h, 1, bitcount)
|
220
|
+
core.write(io)
|
221
|
+
extra = ExtraHeader.new.set(BI_RGB, 0, 0, bitcount, image.palette.size, 0)
|
222
|
+
extra.write(io)
|
223
|
+
# Calculate padding size
|
224
|
+
padding = calc_padding(image.active.w, image.palette?)
|
225
|
+
if image.palette?
|
226
|
+
encode_bpp8(image, io, padding)
|
227
|
+
else
|
228
|
+
encode_bpp24(image, io, padding)
|
229
|
+
end
|
230
|
+
return image
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
|
data/lib/pruim/codec.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module Pruim
|
2
|
+
module Codec
|
3
|
+
|
4
|
+
def self.register(name, klass)
|
5
|
+
@codecs ||= {}
|
6
|
+
@codecs[name] = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
# Returns a codec based on it's short name.
|
10
|
+
def self.for_name(name)
|
11
|
+
return Pruim.const_get(name.upcase)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the codec to use for the given filename, based on the extension
|
15
|
+
def self.for_filename(filename)
|
16
|
+
ext = File.extname(flename) # get filename extension
|
17
|
+
return self.codec_for(name)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns an instance of codec to use for the given filename, based on the
|
21
|
+
# extension of the filename.
|
22
|
+
def self.new_for_filename(filename)
|
23
|
+
codec = for_filename(filename)
|
24
|
+
return codec.new()
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns a new instance of a codec based on it's short name.
|
28
|
+
def self.new_for_name(name)
|
29
|
+
codec = for_name(name)
|
30
|
+
return nil unless codec
|
31
|
+
return codec.new()
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns a codec based on it's short name or on the filename's extension.
|
35
|
+
def self.for_filename_name(filename, codecname = nil)
|
36
|
+
codec = nil
|
37
|
+
return for_name(codecname) if codecname
|
38
|
+
return for_filename(codecname)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns a new instance of a codec based on it's short name or on
|
42
|
+
# the filename's extension.
|
43
|
+
def self.new_for_filename_name(filename, codecname = nil)
|
44
|
+
codec = for_filename_name(filename, codecname)
|
45
|
+
return nil unless codec
|
46
|
+
return codec.new()
|
47
|
+
end
|
48
|
+
|
49
|
+
# Stream should be an StringIO, or otherwise IO compatible object.
|
50
|
+
def decode(io)
|
51
|
+
raise "not implemented"
|
52
|
+
end
|
53
|
+
|
54
|
+
def encode(image, io)
|
55
|
+
raise "not implemented"
|
56
|
+
end
|
57
|
+
|
58
|
+
def can_decode?(io)
|
59
|
+
raise "not implemented"
|
60
|
+
end
|
61
|
+
|
62
|
+
def can_encode?(image)
|
63
|
+
raise "not implemented"
|
64
|
+
end
|
65
|
+
|
66
|
+
def encode_will_degrade?(image)
|
67
|
+
raise "not implemented"
|
68
|
+
end
|
69
|
+
|
70
|
+
def text
|
71
|
+
return "A codec that does nothing."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/pruim/color.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Pruim
|
2
|
+
class Color
|
3
|
+
def self.rgba(r, g, b, a)
|
4
|
+
(a | (b << 8) | (g << 16) | (r << 24))
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.rgb(r, g, b)
|
8
|
+
return rgba(r, g, b, 255)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Cpolors are encoded in abgr
|
12
|
+
def self.to_rgba(color)
|
13
|
+
a = (color) & 255
|
14
|
+
b = (color >> 8) & 255
|
15
|
+
g = (color >> 16) & 255
|
16
|
+
r = (color >> 24) & 255
|
17
|
+
return r, g, b, a
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.to_rgb(color)
|
21
|
+
r, g, b, a = to_rgba(color)
|
22
|
+
return r, g, b
|
23
|
+
end
|
24
|
+
|
25
|
+
BRIGHT_TRESHOLD = 382
|
26
|
+
|
27
|
+
# Returns true if the color is bright (above threshold)
|
28
|
+
# And false if black. Transparency is takeninto account as well.
|
29
|
+
def to_bool(treshold = BRIGHT_TRESHOLD)
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
data/lib/pruim/image.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
module Pruim
|
2
|
+
# An image consists of one or more pages.
|
3
|
+
# Whether a page is a layer, a frame in an animation
|
4
|
+
# or both, is determined by the properties of the page.
|
5
|
+
|
6
|
+
class Image
|
7
|
+
|
8
|
+
attr_reader :w
|
9
|
+
attr_reader :h
|
10
|
+
attr_reader :palette
|
11
|
+
attr_reader :pages
|
12
|
+
# Currently "active" page.
|
13
|
+
attr_reader :active
|
14
|
+
# image mode, may be one of :monochrome, :palette, :grayscale, :rgba
|
15
|
+
attr_reader :mode
|
16
|
+
# Color depth, may be one of 1, 2, 4, 8, 16, 24, 32
|
17
|
+
attr_reader :depth
|
18
|
+
|
19
|
+
# Extra information data hash table.
|
20
|
+
attr_reader :info
|
21
|
+
|
22
|
+
def self.depth_for_colors(ncolors)
|
23
|
+
(Math.log(ncolors) / Math.log(2)).to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
# Sets the comment for this image
|
27
|
+
def comment=(comm)
|
28
|
+
@info[:comment] = comm
|
29
|
+
end
|
30
|
+
|
31
|
+
# gets the comment for this image
|
32
|
+
def comment
|
33
|
+
@info[:comment]
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(w, h, extra = {})
|
37
|
+
@w = w
|
38
|
+
@h = h
|
39
|
+
@info = {}
|
40
|
+
@palette = extra[:palette]
|
41
|
+
@mode = extra[:mode]
|
42
|
+
@mode ||= (@palette ? :palette : :rgba)
|
43
|
+
@palette = Palette.new if !@palette && @mode == :palette
|
44
|
+
@depth = extra[:depth]
|
45
|
+
@depth ||= (@palette ? 8 : 32)
|
46
|
+
@pages = []
|
47
|
+
@ordered = {}
|
48
|
+
@active = nil
|
49
|
+
# Construct many pages.
|
50
|
+
if extra[:pages]
|
51
|
+
data = extra[:data] || []
|
52
|
+
extra[:pages].times { |i| self.new_page(@w, @h, :data => data[i]) }
|
53
|
+
# Construct a single page if data is given nevertheless
|
54
|
+
elsif extra[:data]
|
55
|
+
self.new_page(@w, @h, :data => extra[:data])
|
56
|
+
end
|
57
|
+
# Set comments if any
|
58
|
+
self.comment = extra[:comment]
|
59
|
+
end
|
60
|
+
|
61
|
+
def palette?
|
62
|
+
return !(@palette.nil?)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Sets the page with the given index as active if it exists.
|
66
|
+
def activate(index)
|
67
|
+
@active = @pages[index]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Create a new a page and adds it to this image.
|
71
|
+
# The page is also set as the active page.
|
72
|
+
def new_page(w = nil, h = nil, extra = {})
|
73
|
+
w ||= self.w
|
74
|
+
h ||= self.h
|
75
|
+
page = Page.new(self, w, h, extra)
|
76
|
+
return self.add_page(page)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Adds a page to this image. The page is also set as the active page.
|
80
|
+
def add_page(page)
|
81
|
+
@pages << page
|
82
|
+
@ordered[page.frame] = {} unless @ordered[page.frame]
|
83
|
+
@ordered[page.frame][page.layer] = [] unless @ordered[page.frame][page.layer]
|
84
|
+
@ordered[page.frame][page.layer] << page
|
85
|
+
@active = page
|
86
|
+
return page
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns an array of all pages at the given frame and layer
|
90
|
+
def pages_at(frame = 0, layer = 0)
|
91
|
+
@ordered[frame, layer]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Gets a pixel from the current active page, if any.
|
95
|
+
def getpixel(x, y)
|
96
|
+
@active.getpixel!(x, y)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Sets a pixel to the current active page, if any.
|
100
|
+
def putpixel(x, y, color)
|
101
|
+
@active.putpixel!(x, y, color)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Fills the current active page, if any.
|
105
|
+
def fill(color)
|
106
|
+
@active.fill(color)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Saves the image to the given filename using the given codec
|
110
|
+
# If codec is missig, it's determined from the filename's extension.
|
111
|
+
def save_as(filename, codecname = nil)
|
112
|
+
codec = Codec.new_for_filename_name(filename, codecname)
|
113
|
+
return false unless codec
|
114
|
+
io = File.open(filename, 'wb+')
|
115
|
+
res = codec.encode(self, io)
|
116
|
+
io.close
|
117
|
+
return res
|
118
|
+
end
|
119
|
+
|
120
|
+
# Loads the image from the given filename using the given codec
|
121
|
+
# If codec is missig, it's determined from the filename's extension.
|
122
|
+
def self.load_from(filename, codecname = nil)
|
123
|
+
codec = Codec.new_for_filename_name(filename, codecname)
|
124
|
+
return false unless codec
|
125
|
+
io = File.open(filename, 'rb+')
|
126
|
+
res = nil
|
127
|
+
if codec.can_decode?(io)
|
128
|
+
res = codec.decode(io)
|
129
|
+
else
|
130
|
+
raise "Malformed file #{filename} cannot be decoded as a #{codec} file."
|
131
|
+
end
|
132
|
+
io.close
|
133
|
+
return res
|
134
|
+
end
|
135
|
+
|
136
|
+
# Creates a new rgb color for use with this image.
|
137
|
+
# If the image is palleted, the color is added to the palette and the index
|
138
|
+
# is returned, otherwise the color is returned
|
139
|
+
def new_rgb(r, g, b)
|
140
|
+
if palette?
|
141
|
+
return @palette.new_rgb
|
142
|
+
else
|
143
|
+
return Color.rgb(r, g, b)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Creates a new rgba color for use with this image.
|
148
|
+
# If the image is palleted, the color is added to the palette and the index
|
149
|
+
# is returned, otherwise the color is returned
|
150
|
+
def new_rgba(r, g, b, a)
|
151
|
+
if palette?
|
152
|
+
return @palette.new_rgba
|
153
|
+
else
|
154
|
+
return Color.rgba(r, g, b, a)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
data/lib/pruim/movie.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Pruim
|
2
|
+
class Movie
|
3
|
+
attr_reader :w
|
4
|
+
attr_reader :h
|
5
|
+
attr_reader :frames
|
6
|
+
|
7
|
+
def initialize(w, h, index = 0, nframes = 1, nlayers = 1, data = nil)
|
8
|
+
@w = w
|
9
|
+
@h = h
|
10
|
+
@frames = Array.new(nframes) do | index |
|
11
|
+
Movie.new(self, w, h, index, nlayers, data)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/pruim/page.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Pruim
|
2
|
+
# A Page can represents both a layer and a frame of animation, for
|
3
|
+
# multi-page image formats.
|
4
|
+
# Inside a Page, bitmap data is stored in an array as follows:
|
5
|
+
# For a monochrome image, true and false are stored, where true is "black"
|
6
|
+
# meaning pixel activated, on, say, an LCD screen, and false means white
|
7
|
+
# or pixel not activated.
|
8
|
+
# For :palette mode images, what is stored are palette indexes.
|
9
|
+
# for an RBGA , integers are stored that encode the color in an 8888 bits
|
10
|
+
# ABGR way
|
11
|
+
class Page
|
12
|
+
attr_reader :image
|
13
|
+
attr_reader :w
|
14
|
+
attr_reader :h
|
15
|
+
attr_reader :layer
|
16
|
+
attr_reader :frame
|
17
|
+
attr_reader :x
|
18
|
+
attr_reader :y
|
19
|
+
|
20
|
+
# Extra information data hash table.
|
21
|
+
attr_reader :info
|
22
|
+
|
23
|
+
# Returns a row of pixels with the given y coordinates as an array
|
24
|
+
def row(y)
|
25
|
+
return @data.slice(y * self.w, self.w)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def pixels
|
30
|
+
return @data
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(image, w, h, extra = {})
|
34
|
+
@image = image
|
35
|
+
@info = {}
|
36
|
+
@w = w
|
37
|
+
@h = h
|
38
|
+
@frame = extra[:frame] || 0
|
39
|
+
@layer = extra[:layer] || 0
|
40
|
+
@x = extra[:x] || 0
|
41
|
+
@y = extra[:y] || 0
|
42
|
+
@data = extra[:data]
|
43
|
+
if !@data
|
44
|
+
@data = Array.new(@h * @w, 0)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns true if the coordinates are outside of the limits of this page.
|
49
|
+
def outside?(x, y)
|
50
|
+
return true if (x < 0 ) || (y < 0 )
|
51
|
+
return true if (x >= @w) || (y >= @h)
|
52
|
+
return false
|
53
|
+
end
|
54
|
+
|
55
|
+
# Gets the pixel at coordinates x,y. Returns nil if out of bounds.
|
56
|
+
def getpixel!(x, y)
|
57
|
+
@data[y * @w + x]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Gets the pixel at coordinates x,y. Returns nil if out of bounds.
|
61
|
+
def getpixel(x, y)
|
62
|
+
return getpixel!(x, y)
|
63
|
+
end
|
64
|
+
|
65
|
+
def putpixel!(x, y, color)
|
66
|
+
@data[y * @w + x] = color
|
67
|
+
end
|
68
|
+
|
69
|
+
def putpixel(x, y, color)
|
70
|
+
return nil if outside?(x, y)
|
71
|
+
putpixel!(x, y, color)
|
72
|
+
end
|
73
|
+
|
74
|
+
def fill(color)
|
75
|
+
for i in (0..(@h*@w))
|
76
|
+
@data[i] = color
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pruim
|
2
|
+
class Palette < Array
|
3
|
+
|
4
|
+
# Adds a new RGB color to this palette. Returns the palette index.
|
5
|
+
def new_rgb(r, g, b)
|
6
|
+
self << Pruim::Color.rgb(r, g, b)
|
7
|
+
return self.size - 1
|
8
|
+
end
|
9
|
+
|
10
|
+
# Adds a new RGBA color to this palette. Returns the palette index.
|
11
|
+
def new_rgba(r, g, b, a)
|
12
|
+
self << Pruim::Color.rgba(r, g, b, a)
|
13
|
+
return self.size - 1
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
data/lib/pruim/pbm.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Tiny PBM parser, only works for 2 color (monochrome) pbm's
|
2
|
+
#
|
3
|
+
module Pruim
|
4
|
+
# Tiny PBM parser integrated with Prium codecs.
|
5
|
+
class PBM
|
6
|
+
include Codec
|
7
|
+
Codec.register('pbm', self)
|
8
|
+
|
9
|
+
# Read in a pbm file from an io object.
|
10
|
+
def decode(stream)
|
11
|
+
header = stream.gets
|
12
|
+
lines = []
|
13
|
+
until stream.eof?
|
14
|
+
lines << stream.gets
|
15
|
+
end
|
16
|
+
data = []
|
17
|
+
image = nil
|
18
|
+
page = nil
|
19
|
+
w, h = nil, nil
|
20
|
+
y = 0
|
21
|
+
comment = ''
|
22
|
+
lines.each do |line|
|
23
|
+
if line[0] == '#'
|
24
|
+
comment << line.chomp.sub(/\A#/, '')
|
25
|
+
next
|
26
|
+
end
|
27
|
+
if !w
|
28
|
+
w , h = line.chomp.split(' ').map { |v| v.to_i }
|
29
|
+
next
|
30
|
+
end
|
31
|
+
# Converts 1 to true, rest to false.
|
32
|
+
bits = line.chomp.split('').map { |v| (v == '1') }
|
33
|
+
data += bits
|
34
|
+
end
|
35
|
+
image = Image.new(w, h, :mode => :monochrome, :data => data)
|
36
|
+
image.comment = comment
|
37
|
+
return image
|
38
|
+
end
|
39
|
+
|
40
|
+
def encode(image, stream)
|
41
|
+
stream.puts("P1")
|
42
|
+
stream.puts("##{image.comment}") if image.comment
|
43
|
+
stream.puts("#{image.w} #{image.h}")
|
44
|
+
page = image.pages.first
|
45
|
+
for y in (0...page.h) do
|
46
|
+
for x in (0...page.w) do
|
47
|
+
white = page.getpixel!(x, y)
|
48
|
+
stream.write(white ? '1' : '0')
|
49
|
+
end
|
50
|
+
stream.puts()
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def can_decode?(stream)
|
55
|
+
header = stream.gets
|
56
|
+
stream.rewind
|
57
|
+
return header == "P1\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Can only encode monocrome images.
|
61
|
+
def can_encode?(image)
|
62
|
+
return image.mode == :monochrome
|
63
|
+
end
|
64
|
+
|
65
|
+
# Will only save first page of image.
|
66
|
+
def encode_will_degrade?(image)
|
67
|
+
return (image.pages.size > 1)
|
68
|
+
end
|
69
|
+
end # class PBM
|
70
|
+
end # module Pruim
|
data/lib/pruim/ppm.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Pruim
|
2
|
+
class PPM
|
3
|
+
include Codec
|
4
|
+
Codec.register('ppm', self)
|
5
|
+
|
6
|
+
def decode(stream)
|
7
|
+
header = stream.gets
|
8
|
+
lines = []
|
9
|
+
until stream.eof?
|
10
|
+
lines << stream.gets
|
11
|
+
end
|
12
|
+
image = nil
|
13
|
+
page = nil
|
14
|
+
w, h, d = nil, nil
|
15
|
+
y = 0
|
16
|
+
comment = ''
|
17
|
+
lines.each do |line|
|
18
|
+
if line[0] == '#'
|
19
|
+
comment << line.chomp.sub(/\A#/, '')
|
20
|
+
next
|
21
|
+
end
|
22
|
+
if !image
|
23
|
+
w , h = line.chomp.split(' ').map { |v| v.to_i }
|
24
|
+
image = Image.new(w, h)
|
25
|
+
page = image.new_page(w, h)
|
26
|
+
next
|
27
|
+
end
|
28
|
+
if !d
|
29
|
+
d = line.chomp.to_i
|
30
|
+
next
|
31
|
+
end
|
32
|
+
triplets = line.chomp.split(' ').map { |v| v.to_i }
|
33
|
+
for x in (0...page.w) do
|
34
|
+
r, g, b = triplets.shift(3)
|
35
|
+
color = Color.rgb(r, g, b)
|
36
|
+
page.putpixel(x, y, color)
|
37
|
+
end
|
38
|
+
y += 1
|
39
|
+
end
|
40
|
+
image.comment = comment
|
41
|
+
return image
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def encode(image, stream)
|
46
|
+
stream.puts("P3")
|
47
|
+
stream.puts("##{image.comment}") if image.comment
|
48
|
+
stream.puts("#{image.w} #{image.h}")
|
49
|
+
stream.puts("255")
|
50
|
+
page = image.pages.first
|
51
|
+
for y in (0...page.h) do
|
52
|
+
for x in (0...page.w) do
|
53
|
+
color = page.getpixel!(x, y)
|
54
|
+
r, g, b = Color.to_rgb(color)
|
55
|
+
stream.write(" ") if x > 0
|
56
|
+
stream.write("#{r} #{g} #{b}")
|
57
|
+
end
|
58
|
+
stream.write("\n")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def can_decode?(stream)
|
63
|
+
header = stream.gets
|
64
|
+
stream.rewind
|
65
|
+
return header == "P3\n"
|
66
|
+
end
|
67
|
+
|
68
|
+
def can_encode?(image)
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
|
72
|
+
def encode_will_degrade?(image)
|
73
|
+
return (image.pages.size > 1)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/pruim.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
module Pruim
|
2
|
+
autoload :Color , 'pruim/color'
|
3
|
+
autoload :Codec , 'pruim/codec'
|
4
|
+
autoload :Palette , 'pruim/palette'
|
5
|
+
autoload :Image , 'pruim/image'
|
6
|
+
autoload :Page , 'pruim/page'
|
7
|
+
autoload :PBM , 'pruim/pbm'
|
8
|
+
autoload :PPM , 'pruim/ppm'
|
9
|
+
autoload :BMP , 'pruim/bmp'
|
10
|
+
end
|
data/test/atto.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pruim'
|
3
|
+
|
4
|
+
test_w, test_h = 64, 32
|
5
|
+
bitmap1_w, bitmap1_h = 64, 64
|
6
|
+
|
7
|
+
assert { Pruim }
|
8
|
+
assert { Pruim::BMP }
|
9
|
+
inname = test_file('data', 'bitmap1.bmp')
|
10
|
+
inname2 = test_file('data', 'bitmap_alpha.bmp')
|
11
|
+
outname = test_file('data', 'out1.bmp')
|
12
|
+
outname2= test_file('data', 'out2.bmp')
|
13
|
+
|
14
|
+
codec = Pruim::Codec.for_name('bmp')
|
15
|
+
assert { codec }
|
16
|
+
|
17
|
+
image = Pruim::Image.load_from(inname, :bmp)
|
18
|
+
|
19
|
+
#
|
20
|
+
# fin = File.open(inname, 'r+')
|
21
|
+
# assert { codec.can_decode?(fin) }
|
22
|
+
# image = nil
|
23
|
+
# assert { image = codec.decode(fin) }
|
24
|
+
# fin.close
|
25
|
+
assert { image.w == bitmap1_w }
|
26
|
+
assert { image.h == bitmap1_h }
|
27
|
+
|
28
|
+
image.save_as(outname, :bmp)
|
29
|
+
|
30
|
+
#
|
31
|
+
# fout = File.open(outname, 'w+')
|
32
|
+
# assert { codec.encode(image, fout) }
|
33
|
+
# fout.close
|
34
|
+
|
35
|
+
# system("display #{outname} &")
|
36
|
+
|
37
|
+
|
38
|
+
image2 = Pruim::Image.new(test_w, test_h, :mode => :palette, :pages => 1)
|
39
|
+
assert { image2 }
|
40
|
+
assert { image2.w == test_w }
|
41
|
+
assert { image2.h == test_h }
|
42
|
+
gray = image2.palette.new_rgb(127, 128, 129)
|
43
|
+
red = image2.palette.new_rgb(255, 0, 0)
|
44
|
+
green = image2.palette.new_rgb(0 , 255, 255)
|
45
|
+
blue = image2.palette.new_rgb(0 , 0, 255)
|
46
|
+
p red
|
47
|
+
image2.fill(gray)
|
48
|
+
image2.putpixel(4, 5, red)
|
49
|
+
image2.putpixel(5, 6, green)
|
50
|
+
image2.putpixel(6, 7, blue)
|
51
|
+
assert { image2.getpixel(4, 5) == red }
|
52
|
+
assert { image2.getpixel(5, 6) == green }
|
53
|
+
assert { image2.getpixel(6, 7) == blue }
|
54
|
+
|
55
|
+
image2.save_as(outname2, :bmp)
|
56
|
+
#
|
57
|
+
# fout2 = File.open(outname2, 'w+')
|
58
|
+
# assert { codec.encode(image2, fout2) }
|
59
|
+
# fout2.close
|
60
|
+
assert { system("display #{outname2} &") }
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
#
|
65
|
+
# assert { codec }
|
66
|
+
# assert { codec.encode(image, fout) }
|
67
|
+
# fout.close
|
68
|
+
# # system("eog #{outname} &")
|
69
|
+
# fin = File.open(outname, 'r+')
|
70
|
+
# image2 = nil
|
71
|
+
# assert { image2 = codec.decode(fin) }
|
72
|
+
# fin.close
|
73
|
+
# page2 = image2.active
|
74
|
+
# assert { page2 }
|
75
|
+
# assert { image2.w == test_w }
|
76
|
+
# assert { image2.h == test_h }
|
77
|
+
# assert { page2.w == test_w }
|
78
|
+
# assert { page2.h == test_h }
|
79
|
+
#
|
80
|
+
# assert { page2.getpixel!(1, 1) == green }
|
81
|
+
# assert { page2.getpixel!(10, 10) == blue }
|
82
|
+
# assert { page2.getpixel!(0, 0) == red }
|
83
|
+
#
|
84
|
+
# assert { image2.getpixel(1, 1) == green }
|
85
|
+
# assert { image2.getpixel(10, 10) == blue }
|
86
|
+
# assert { image2.getpixel(0, 0) == red }
|
87
|
+
#
|
88
|
+
|
89
|
+
|
90
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pruim'
|
3
|
+
|
4
|
+
test_w, test_h = 64, 32
|
5
|
+
|
6
|
+
assert { Pruim }
|
7
|
+
assert { Pruim::Image }
|
8
|
+
image = Pruim::Image.new(test_w, test_h, :pages => 1)
|
9
|
+
assert { image }
|
10
|
+
assert { image.w == test_w }
|
11
|
+
assert { image.h == test_h }
|
12
|
+
red = Pruim::Color.rgb(255, 0, 0)
|
13
|
+
green = Pruim::Color.rgb(0 ,255, 255)
|
14
|
+
blue = Pruim::Color.rgb(0 , 0, 255)
|
15
|
+
page = image.active
|
16
|
+
assert { page }
|
17
|
+
assert { page.w == test_w }
|
18
|
+
assert { page.h == test_h }
|
19
|
+
page.fill(red)
|
20
|
+
page.putpixel(1, 1, green)
|
21
|
+
page.putpixel(10, 10, blue)
|
22
|
+
assert { image.getpixel(1, 1) == green }
|
23
|
+
assert { image.getpixel(10, 10) == blue }
|
24
|
+
assert { image.getpixel(0, 0) == red }
|
25
|
+
|
26
|
+
image2 = Pruim::Image.new(2, 3, :data => [ 1, 2, 3, 4, 5, 6])
|
27
|
+
assert { image2 }
|
28
|
+
assert { image2.getpixel(0, 0) == 1 }
|
29
|
+
assert { image2.getpixel(1, 1) == 4 }
|
30
|
+
assert { image2.getpixel(1, 2) == 6 }
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pruim'
|
3
|
+
|
4
|
+
test_w = 2
|
5
|
+
test_h = 3
|
6
|
+
assert { Pruim }
|
7
|
+
assert { Pruim::Page }
|
8
|
+
page = Pruim::Page.new(nil, test_w, test_h, :data => [1, 2, 3, 4, 5, 6] )
|
9
|
+
assert { page }
|
10
|
+
assert { page.w == test_w }
|
11
|
+
assert { page.h == test_h }
|
12
|
+
assert { page.getpixel(0,0) == 1 }
|
13
|
+
assert { page.getpixel(1,2) == 6 }
|
14
|
+
|
15
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pruim'
|
3
|
+
|
4
|
+
test_w, test_h = 16, 16
|
5
|
+
test_comment = "Test PBM file for Pruim."
|
6
|
+
assert { Pruim }
|
7
|
+
assert { Pruim::Image }
|
8
|
+
image = Pruim::Image.new(test_w, test_h, :mode => :monochrome, :pages => 1)
|
9
|
+
page = image.active
|
10
|
+
page.fill(false)
|
11
|
+
page.putpixel(1, 1, true)
|
12
|
+
page.putpixel(10, 10, true)
|
13
|
+
image.comment = test_comment
|
14
|
+
|
15
|
+
outname = test_file("out.pbm")
|
16
|
+
assert { image.save_as(outname, "pbm") }
|
17
|
+
|
18
|
+
image2 = Pruim::Image.load_from(outname, "pbm")
|
19
|
+
#
|
20
|
+
# fin = File.open(outname, 'r+')
|
21
|
+
# image2 = nil
|
22
|
+
# assert { image2 = codec.decode(fin) }
|
23
|
+
# fin.close
|
24
|
+
page2 = image2.active
|
25
|
+
assert { page2 }
|
26
|
+
assert { image2.w == test_w }
|
27
|
+
assert { image2.h == test_h }
|
28
|
+
assert { page2.w == test_w }
|
29
|
+
assert { page2.h == test_h }
|
30
|
+
assert { page2.getpixel!(1, 1) }
|
31
|
+
assert { page2.getpixel!(10, 10) }
|
32
|
+
assert { !(page2.getpixel!(0, 0)) }
|
33
|
+
assert { image2.getpixel(1, 1) }
|
34
|
+
assert { image2.getpixel(10, 10) }
|
35
|
+
assert { !(image2.getpixel(0, 0)) }
|
36
|
+
assert { image2.comment == test_comment }
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pruim'
|
3
|
+
|
4
|
+
test_w, test_h = 64, 32
|
5
|
+
test_comment = "Test PPM file for Pruim."
|
6
|
+
assert { Pruim }
|
7
|
+
assert { Pruim::Image }
|
8
|
+
image = Pruim::Image.new(test_w, test_h, :pages => 1)
|
9
|
+
red = Pruim::Color.rgb(255, 0, 0)
|
10
|
+
green = Pruim::Color.rgb(0 ,255, 255)
|
11
|
+
blue = Pruim::Color.rgb(0 , 0, 255)
|
12
|
+
page = image.active
|
13
|
+
page.fill(red)
|
14
|
+
page.putpixel(1, 1, green)
|
15
|
+
page.putpixel(10, 10, blue)
|
16
|
+
image.comment = test_comment
|
17
|
+
|
18
|
+
outname = test_file("out.ppm")
|
19
|
+
assert { image.save_as(outname, "ppm") }
|
20
|
+
|
21
|
+
image2 = Pruim::Image.load_from(outname, "ppm")
|
22
|
+
#
|
23
|
+
# fin = File.open(outname, 'r+')
|
24
|
+
# image2 = nil
|
25
|
+
# assert { image2 = codec.decode(fin) }
|
26
|
+
# fin.close
|
27
|
+
page2 = image2.active
|
28
|
+
assert { page2 }
|
29
|
+
assert { image2.w == test_w }
|
30
|
+
assert { image2.h == test_h }
|
31
|
+
assert { page2.w == test_w }
|
32
|
+
assert { page2.h == test_h }
|
33
|
+
|
34
|
+
assert { page2.getpixel!(1, 1) == green }
|
35
|
+
assert { page2.getpixel!(10, 10) == blue }
|
36
|
+
assert { page2.getpixel!(0, 0) == red }
|
37
|
+
|
38
|
+
assert { image2.getpixel(1, 1) == green }
|
39
|
+
assert { image2.getpixel(10, 10) == blue }
|
40
|
+
assert { image2.getpixel(0, 0) == red }
|
41
|
+
assert { image2.comment == test_comment }
|
42
|
+
|
43
|
+
|
44
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# require 'nanotest'
|
2
|
+
# require 'redgreen'
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
require 'timeout'
|
6
|
+
|
7
|
+
$: << '.'
|
8
|
+
|
9
|
+
require 'atto'
|
10
|
+
include Atto::Test
|
11
|
+
|
12
|
+
|
13
|
+
def test_file(*fname)
|
14
|
+
return File.join('test', *fname)
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
$: << '../lib'
|
19
|
+
|
20
|
+
|
data/test/test_image.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pruim'
|
3
|
+
|
4
|
+
test_w, test_h = 64, 32
|
5
|
+
|
6
|
+
assert { Pruim }
|
7
|
+
assert { Pruim::Image }
|
8
|
+
image = Pruim::Image.new(test_w, test_h)
|
9
|
+
assert { image }
|
10
|
+
assert { image.w == test_w }
|
11
|
+
assert { image.h == test_h }
|
12
|
+
red = Pruim::Color.rgb(255, 0, 0)
|
13
|
+
green = Pruim::Color.rgb(0 ,255, 255)
|
14
|
+
blue = Pruim::Color.rgb(0 , 0, 255)
|
15
|
+
page = image.new_page(test_w, test_h)
|
16
|
+
assert { page }
|
17
|
+
assert { page.w == test_w }
|
18
|
+
assert { page.h == test_h }
|
19
|
+
page.fill(red)
|
20
|
+
page.putpixel(1, 1, green)
|
21
|
+
page.putpixel(10, 10, blue)
|
22
|
+
outname = test_file("out.ppm")
|
23
|
+
fout = File.open(outname, 'w+')
|
24
|
+
codec = Pruim::Codec.new_codec_for('ppm')
|
25
|
+
assert { codec }
|
26
|
+
assert { codec.encode(image, fout) }
|
27
|
+
fout.close
|
28
|
+
# system("eog #{outname} &")
|
29
|
+
fin = File.open(outname, 'r+')
|
30
|
+
image2 = nil
|
31
|
+
assert { image2 = codec.decode(fin) }
|
32
|
+
fin.close
|
33
|
+
page2 = image2.pages.first
|
34
|
+
assert { page2 }
|
35
|
+
assert { image2.w == test_w }
|
36
|
+
assert { image2.h == test_h }
|
37
|
+
assert { page2.w == test_w }
|
38
|
+
assert { page2.h == test_h }
|
39
|
+
|
40
|
+
assert { page2.getpixel!(1, 1) == green }
|
41
|
+
assert { page2.getpixel!(10, 10) == blue }
|
42
|
+
assert { page2.getpixel!(0, 0) == red }
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pruim
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- beoran
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-12-13 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bindata
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.0.0
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: atto
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.9.2
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
description: " Pruim is a Pure Ruby Image Library. Currently only supports BMP, PPM and PBM\n formats, but preserves palette ordering on reading and writing.\n"
|
38
|
+
email: beoran@rubyforge.org
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- README
|
47
|
+
- Rakefile
|
48
|
+
- lib/pruim.rb
|
49
|
+
- lib/pruim/pbm.rb
|
50
|
+
- lib/pruim/bmp.rb
|
51
|
+
- lib/pruim/ppm.rb
|
52
|
+
- lib/pruim/page.rb
|
53
|
+
- lib/pruim/image.rb
|
54
|
+
- lib/pruim/palette.rb
|
55
|
+
- lib/pruim/codec.rb
|
56
|
+
- lib/pruim/color.rb
|
57
|
+
- lib/pruim/movie.rb
|
58
|
+
- test/test_helper.rb
|
59
|
+
- test/test_image.rb
|
60
|
+
- test/atto.rb
|
61
|
+
- test/pruim/test_bmp.rb
|
62
|
+
- test/pruim/test_image.rb
|
63
|
+
- test/pruim/test_pbm.rb
|
64
|
+
- test/pruim/test_ppm.rb
|
65
|
+
- test/pruim/test_page.rb
|
66
|
+
homepage: http://github.com/beoran/pruim
|
67
|
+
licenses: []
|
68
|
+
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: "0"
|
86
|
+
requirements: []
|
87
|
+
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 1.8.12
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: Pure Ruby Image Library.
|
93
|
+
test_files: []
|
94
|
+
|