pruim 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.
- 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
|
+
|