zpng 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/README.md +78 -73
- data/README.md.tpl +1 -1
- data/Rakefile +1 -2
- data/VERSION +1 -1
- data/lib/zpng/adam7_decoder.rb +63 -0
- data/lib/zpng/cli.rb +44 -2
- data/lib/zpng/color.rb +43 -4
- data/lib/zpng/image.rb +23 -8
- data/lib/zpng/scan_line.rb +23 -14
- data/lib/zpng/string_ext.rb +11 -0
- data/lib/zpng.rb +3 -1
- data/spec/color_spec.rb +11 -0
- data/spec/spec_helper.rb +29 -3
- data/zpng.gemspec +8 -5
- metadata +8 -5
data/Gemfile
CHANGED
@@ -2,8 +2,8 @@ source "http://rubygems.org"
|
|
2
2
|
# Add dependencies required to use your gem here.
|
3
3
|
# Example:
|
4
4
|
# gem "activesupport", ">= 2.3.5"
|
5
|
-
gem 'colorize'
|
6
5
|
gem 'hexdump'
|
6
|
+
gem 'rainbow'
|
7
7
|
|
8
8
|
# Add dependencies to develop your gem here.
|
9
9
|
# Include everything needed to run rake, tests, features, etc.
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
colorize (0.5.8)
|
5
4
|
diff-lcs (1.1.3)
|
6
5
|
git (1.2.5)
|
7
6
|
hexdump (0.2.3)
|
@@ -11,6 +10,7 @@ GEM
|
|
11
10
|
rake
|
12
11
|
rdoc
|
13
12
|
json (1.7.5)
|
13
|
+
rainbow (1.1.4)
|
14
14
|
rake (10.0.2)
|
15
15
|
rdoc (3.12)
|
16
16
|
json (~> 1.4)
|
@@ -28,7 +28,7 @@ PLATFORMS
|
|
28
28
|
|
29
29
|
DEPENDENCIES
|
30
30
|
bundler (>= 1.0.0)
|
31
|
-
colorize
|
32
31
|
hexdump
|
33
32
|
jeweler (~> 1.8.4)
|
33
|
+
rainbow
|
34
34
|
rspec (>= 2.8.0)
|
data/README.md
CHANGED
@@ -20,13 +20,18 @@ Usage
|
|
20
20
|
-q, --quiet Silent any warnings (can be used multiple times)
|
21
21
|
-C, --chunks Show file chunks (default)
|
22
22
|
-i, --info General image info (default)
|
23
|
-
-A, --ascii Try to display image as ASCII (works best with monochrome images)
|
24
23
|
-S, --scanlines Show scanlines info
|
25
24
|
-P, --palette Show palette
|
26
25
|
-E, --extract-chunk ID extract a single chunk
|
27
26
|
-U, --unpack-imagedata unpack Image Data (IDAT) chunk(s), output to stdout
|
27
|
+
|
28
28
|
-c, --crop GEOMETRY crop image, {WIDTH}x{HEIGHT}+{X}+{Y},
|
29
29
|
puts results on stdout unless --ascii given
|
30
|
+
|
31
|
+
-A, --ascii Try to convert image to ASCII (works best with monochrome images)
|
32
|
+
-N, --ansi Try to display image as ANSI colored text
|
33
|
+
-2, --256 Try to display image as 256-colored text
|
34
|
+
-W, --wide Use 2 horizontal characters per one pixel
|
30
35
|
|
31
36
|
### Info
|
32
37
|
|
@@ -39,7 +44,7 @@ Usage
|
|
39
44
|
|
40
45
|
# zpng --chunks qr_aux_chunks.png
|
41
46
|
|
42
|
-
[.] <Chunk #00 IHDR size= 13, crc=36a28ef4,
|
47
|
+
[.] <Chunk #00 IHDR size= 13, crc=36a28ef4, idx=0, interlace=0, filter=0, compression=0, height=35, width=35, depth=1, color=0> CRC OK
|
43
48
|
[.] <Chunk #01 gAMA size= 4, crc=0bfc6105 > CRC OK
|
44
49
|
[.] <Chunk #02 sRGB size= 1, crc=aece1ce9 > CRC OK
|
45
50
|
[.] <Chunk #03 cHRM size= 32, crc=9cba513c > CRC OK
|
@@ -53,82 +58,82 @@ Usage
|
|
53
58
|
|
54
59
|
source image: ![qr_rgb.png](https://github.com/zed-0xff/zpng/raw/master/samples/qr_rgb.png)
|
55
60
|
|
56
|
-
# zpng --ascii qr_rgb.png
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
61
|
+
# zpng --ascii --wide qr_rgb.png
|
62
|
+
|
63
|
+
|
64
|
+
############## #### #### ## #### ##############
|
65
|
+
## ## #### ## #### ## ##
|
66
|
+
## ###### ## ## ########## ## ## #### ## ###### ##
|
67
|
+
## ###### ## #### ## ## ######## #### ## ###### ##
|
68
|
+
## ###### ## ######## ## ## ######## ## ###### ##
|
69
|
+
## ## ## ## ## ########## ## ##
|
70
|
+
############## ## ## ## ## ## ## ## ## ## ##############
|
71
|
+
## ## #### #### ####
|
72
|
+
######## ## ## #### ## #### #### ###### ##
|
73
|
+
## #### #### #### ## #### ## ###### ####
|
74
|
+
## ###### #### #### ## #### #### ## ###### ##
|
75
|
+
###### ## ########## ## ## #### ## ##
|
76
|
+
#### #### ## ## ## ## ######## #### ####
|
77
|
+
## ## #### #### ## ## ###### #### ####
|
78
|
+
## ############ #### ## ## ########## ##############
|
79
|
+
## ######## ###### #### ## #### ## #### ##
|
80
|
+
#### #### ###### #### ## #### ################
|
81
|
+
## ###### #### #### ################## ##
|
82
|
+
######## ########## #### #### ## ## ## ##
|
83
|
+
#### ## ## ## ## ########## ## ## #### ##
|
84
|
+
############ ########## ## ## #### ##
|
85
|
+
###### ## ######## ## ###### ## ######
|
86
|
+
###### ######## ######## ## ## ############## ####
|
87
|
+
## ## #### #### ## #### ## #### ############ ##
|
88
|
+
## ############## ## #### #### ########## ##
|
89
|
+
## ###### ## #### #### ## ##
|
90
|
+
############## ## ## #### ###### ## ##
|
91
|
+
## ## ###### ## ## ############ ###### ##
|
92
|
+
## ###### ## ## ######## ## ################
|
93
|
+
## ###### ## ###### ## ######## ## ## ##
|
94
|
+
## ###### ## ###### ########## ## #### ## ##
|
95
|
+
## ## ######## #### #### ###### ##
|
96
|
+
############## ## ## #### ## #### ## #### ##
|
92
97
|
|
93
98
|
### Scanlines
|
94
99
|
|
95
100
|
# zpng --scanlines qr_rgb.png
|
96
101
|
|
97
|
-
[#<ZPNG::ScanLine idx=0
|
98
|
-
#<ZPNG::ScanLine idx=1
|
99
|
-
#<ZPNG::ScanLine idx=2
|
100
|
-
#<ZPNG::ScanLine idx=3
|
101
|
-
#<ZPNG::ScanLine idx=4
|
102
|
-
#<ZPNG::ScanLine idx=5
|
103
|
-
#<ZPNG::ScanLine idx=6
|
104
|
-
#<ZPNG::ScanLine idx=7
|
105
|
-
#<ZPNG::ScanLine idx=8
|
106
|
-
#<ZPNG::ScanLine idx=9
|
107
|
-
#<ZPNG::ScanLine idx=10
|
108
|
-
#<ZPNG::ScanLine idx=11
|
109
|
-
#<ZPNG::ScanLine idx=12
|
110
|
-
#<ZPNG::ScanLine idx=13
|
111
|
-
#<ZPNG::ScanLine idx=14
|
112
|
-
#<ZPNG::ScanLine idx=15
|
113
|
-
#<ZPNG::ScanLine idx=16
|
114
|
-
#<ZPNG::ScanLine idx=17
|
115
|
-
#<ZPNG::ScanLine idx=18
|
116
|
-
#<ZPNG::ScanLine idx=19
|
117
|
-
#<ZPNG::ScanLine idx=20
|
118
|
-
#<ZPNG::ScanLine idx=21
|
119
|
-
#<ZPNG::ScanLine idx=22
|
120
|
-
#<ZPNG::ScanLine idx=23
|
121
|
-
#<ZPNG::ScanLine idx=24
|
122
|
-
#<ZPNG::ScanLine idx=25
|
123
|
-
#<ZPNG::ScanLine idx=26
|
124
|
-
#<ZPNG::ScanLine idx=27
|
125
|
-
#<ZPNG::ScanLine idx=28
|
126
|
-
#<ZPNG::ScanLine idx=29
|
127
|
-
#<ZPNG::ScanLine idx=30
|
128
|
-
#<ZPNG::ScanLine idx=31
|
129
|
-
#<ZPNG::ScanLine idx=32
|
130
|
-
#<ZPNG::ScanLine idx=33
|
131
|
-
#<ZPNG::ScanLine idx=34
|
102
|
+
[#<ZPNG::ScanLine idx=0 offset=1 size=106 bpp=24 filter=1>,
|
103
|
+
#<ZPNG::ScanLine idx=1 offset=107 size=106 bpp=24 filter=4>,
|
104
|
+
#<ZPNG::ScanLine idx=2 offset=213 size=106 bpp=24 filter=4>,
|
105
|
+
#<ZPNG::ScanLine idx=3 offset=319 size=106 bpp=24 filter=4>,
|
106
|
+
#<ZPNG::ScanLine idx=4 offset=425 size=106 bpp=24 filter=2>,
|
107
|
+
#<ZPNG::ScanLine idx=5 offset=531 size=106 bpp=24 filter=2>,
|
108
|
+
#<ZPNG::ScanLine idx=6 offset=637 size=106 bpp=24 filter=4>,
|
109
|
+
#<ZPNG::ScanLine idx=7 offset=743 size=106 bpp=24 filter=0>,
|
110
|
+
#<ZPNG::ScanLine idx=8 offset=849 size=106 bpp=24 filter=1>,
|
111
|
+
#<ZPNG::ScanLine idx=9 offset=955 size=106 bpp=24 filter=0>,
|
112
|
+
#<ZPNG::ScanLine idx=10 offset=1061 size=106 bpp=24 filter=0>,
|
113
|
+
#<ZPNG::ScanLine idx=11 offset=1167 size=106 bpp=24 filter=0>,
|
114
|
+
#<ZPNG::ScanLine idx=12 offset=1273 size=106 bpp=24 filter=1>,
|
115
|
+
#<ZPNG::ScanLine idx=13 offset=1379 size=106 bpp=24 filter=2>,
|
116
|
+
#<ZPNG::ScanLine idx=14 offset=1485 size=106 bpp=24 filter=4>,
|
117
|
+
#<ZPNG::ScanLine idx=15 offset=1591 size=106 bpp=24 filter=0>,
|
118
|
+
#<ZPNG::ScanLine idx=16 offset=1697 size=106 bpp=24 filter=4>,
|
119
|
+
#<ZPNG::ScanLine idx=17 offset=1803 size=106 bpp=24 filter=0>,
|
120
|
+
#<ZPNG::ScanLine idx=18 offset=1909 size=106 bpp=24 filter=4>,
|
121
|
+
#<ZPNG::ScanLine idx=19 offset=2015 size=106 bpp=24 filter=4>,
|
122
|
+
#<ZPNG::ScanLine idx=20 offset=2121 size=106 bpp=24 filter=0>,
|
123
|
+
#<ZPNG::ScanLine idx=21 offset=2227 size=106 bpp=24 filter=1>,
|
124
|
+
#<ZPNG::ScanLine idx=22 offset=2333 size=106 bpp=24 filter=2>,
|
125
|
+
#<ZPNG::ScanLine idx=23 offset=2439 size=106 bpp=24 filter=0>,
|
126
|
+
#<ZPNG::ScanLine idx=24 offset=2545 size=106 bpp=24 filter=2>,
|
127
|
+
#<ZPNG::ScanLine idx=25 offset=2651 size=106 bpp=24 filter=1>,
|
128
|
+
#<ZPNG::ScanLine idx=26 offset=2757 size=106 bpp=24 filter=1>,
|
129
|
+
#<ZPNG::ScanLine idx=27 offset=2863 size=106 bpp=24 filter=4>,
|
130
|
+
#<ZPNG::ScanLine idx=28 offset=2969 size=106 bpp=24 filter=4>,
|
131
|
+
#<ZPNG::ScanLine idx=29 offset=3075 size=106 bpp=24 filter=4>,
|
132
|
+
#<ZPNG::ScanLine idx=30 offset=3181 size=106 bpp=24 filter=4>,
|
133
|
+
#<ZPNG::ScanLine idx=31 offset=3287 size=106 bpp=24 filter=2>,
|
134
|
+
#<ZPNG::ScanLine idx=32 offset=3393 size=106 bpp=24 filter=4>,
|
135
|
+
#<ZPNG::ScanLine idx=33 offset=3499 size=106 bpp=24 filter=4>,
|
136
|
+
#<ZPNG::ScanLine idx=34 offset=3605 size=106 bpp=24 filter=1>]
|
132
137
|
|
133
138
|
### Palette
|
134
139
|
|
data/README.md.tpl
CHANGED
data/Rakefile
CHANGED
@@ -86,8 +86,7 @@ Rake::Task[:console].clear
|
|
86
86
|
# from /usr/local/lib64/ruby/gems/1.9.1/gems/jeweler-1.8.4/lib/jeweler/tasks.rb
|
87
87
|
desc "Start IRB with all runtime dependencies loaded"
|
88
88
|
task :console, [:script] do |t,args|
|
89
|
-
|
90
|
-
dirs = ['ext', 'lib'].select { |dir| File.directory?(dir) }
|
89
|
+
dirs = ['./ext', './lib'].select { |dir| File.directory?(dir) }
|
91
90
|
|
92
91
|
original_load_path = $LOAD_PATH
|
93
92
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module ZPNG
|
2
|
+
class Adam7Decoder
|
3
|
+
attr_accessor :image
|
4
|
+
|
5
|
+
def initialize image
|
6
|
+
@image = image
|
7
|
+
end
|
8
|
+
|
9
|
+
def scanlines_count
|
10
|
+
(15*image.height/8.0).ceil
|
11
|
+
end
|
12
|
+
|
13
|
+
WIDTHS = [1,1,2,2,2,4,4,4,4,4,4,8,8,8,8]
|
14
|
+
|
15
|
+
# scanline width in pixels
|
16
|
+
def scanline_width idx
|
17
|
+
#image.width/8*(2**(idx/2))
|
18
|
+
WIDTHS[idx*8/image.height]*(image.width/8)
|
19
|
+
end
|
20
|
+
|
21
|
+
# scanline size in bytes, INCLUDING leading filter byte
|
22
|
+
def scanline_size idx
|
23
|
+
(scanline_width(idx) * image.bpp / 8.0).ceil + 1
|
24
|
+
end
|
25
|
+
|
26
|
+
# scanline offset in imagedata
|
27
|
+
def scanline_offset idx
|
28
|
+
#TODO: optimize
|
29
|
+
(0...idx).map{ |x| scanline_size(x) }.inject(&:+) || 0
|
30
|
+
end
|
31
|
+
|
32
|
+
# convert "flat" coords in scanline number & pos in scanline
|
33
|
+
def convert_coords x,y
|
34
|
+
# optimizing this into one switch/case statement gives
|
35
|
+
# about 1-2% speed increase (ruby 1.9.3p286)
|
36
|
+
|
37
|
+
if y%2 == 1
|
38
|
+
# 7th pass: last height/2 full scanlines
|
39
|
+
[x, y/2 + image.height*11/8]
|
40
|
+
elsif x%2 == 1 && y%2 == 0
|
41
|
+
# 6th pass
|
42
|
+
[x/2, y/2 + image.height*7/8]
|
43
|
+
elsif x%8 == 0 && y%8 == 0
|
44
|
+
# 1st pass
|
45
|
+
[x/8, y/8]
|
46
|
+
elsif x%8 == 4 && y%8 == 0
|
47
|
+
# 2nd pass
|
48
|
+
[x/8, y/8 + image.height/8]
|
49
|
+
elsif x%4 == 0 && y%8 == 4
|
50
|
+
# 3rd pass
|
51
|
+
[x/4, y/8 + image.height*2/8]
|
52
|
+
elsif x%4 == 2 && y%4 == 0
|
53
|
+
# 4th pass
|
54
|
+
[x/4, y/4 + image.height*3/8]
|
55
|
+
elsif x%2 == 0 && y%4 == 2
|
56
|
+
# 5th pass
|
57
|
+
[x/2, y/4 + image.height*5/8]
|
58
|
+
else
|
59
|
+
raise "invalid coords"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/zpng/cli.rb
CHANGED
@@ -8,7 +8,6 @@ class ZPNG::CLI
|
|
8
8
|
ACTIONS = {
|
9
9
|
'chunks' => 'Show file chunks (default)',
|
10
10
|
%w'i info' => 'General image info (default)',
|
11
|
-
'ascii' => 'Try to display image as ASCII (works best with monochrome images)',
|
12
11
|
'scanlines' => 'Show scanlines info',
|
13
12
|
'palette' => 'Show palette'
|
14
13
|
}
|
@@ -46,10 +45,25 @@ class ZPNG::CLI
|
|
46
45
|
@actions << :unpack_imagedata
|
47
46
|
end
|
48
47
|
|
48
|
+
opts.separator ""
|
49
49
|
opts.on "-c", "--crop GEOMETRY", "crop image, {WIDTH}x{HEIGHT}+{X}+{Y},",
|
50
50
|
"puts results on stdout unless --ascii given" do |x|
|
51
51
|
@actions << [:crop, x]
|
52
52
|
end
|
53
|
+
|
54
|
+
opts.separator ""
|
55
|
+
opts.on "-A", '--ascii', 'Try to convert image to ASCII (works best with monochrome images)' do
|
56
|
+
@actions << :ascii
|
57
|
+
end
|
58
|
+
opts.on "-N", '--ansi', 'Try to display image as ANSI colored text' do
|
59
|
+
@actions << :ansi
|
60
|
+
end
|
61
|
+
opts.on "-2", '--256', 'Try to display image as 256-colored text' do
|
62
|
+
@actions << :ansi256
|
63
|
+
end
|
64
|
+
opts.on "-W", '--wide', 'Use 2 horizontal characters per one pixel' do
|
65
|
+
@options[:wide] = true
|
66
|
+
end
|
53
67
|
end
|
54
68
|
|
55
69
|
if (argv = optparser.parse(@argv)).empty?
|
@@ -120,7 +134,35 @@ class ZPNG::CLI
|
|
120
134
|
end
|
121
135
|
|
122
136
|
def ascii
|
123
|
-
|
137
|
+
@img.height.times do |y|
|
138
|
+
@img.width.times do |x|
|
139
|
+
c = @img[x,y].to_ascii
|
140
|
+
c *= 2 if @options[:wide]
|
141
|
+
print c
|
142
|
+
end
|
143
|
+
puts
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def ansi
|
148
|
+
spc = @options[:wide] ? " " : " "
|
149
|
+
@img.height.times do |y|
|
150
|
+
@img.width.times do |x|
|
151
|
+
print spc.background(@img[x,y].closest_ansi_color)
|
152
|
+
end
|
153
|
+
puts
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def ansi256
|
158
|
+
require 'rainbow'
|
159
|
+
spc = @options[:wide] ? " " : " "
|
160
|
+
@img.height.times do |y|
|
161
|
+
@img.width.times do |x|
|
162
|
+
print spc.background(@img[x,y].to_s)
|
163
|
+
end
|
164
|
+
puts
|
165
|
+
end
|
124
166
|
end
|
125
167
|
|
126
168
|
def scanlines
|
data/lib/zpng/color.rb
CHANGED
@@ -9,8 +9,33 @@ module ZPNG
|
|
9
9
|
alias :alpha :a
|
10
10
|
def alpha= v; self.a = v; end
|
11
11
|
|
12
|
-
BLACK = Color.new(0,0,0,
|
13
|
-
WHITE = Color.new(
|
12
|
+
BLACK = Color.new(0 , 0, 0, 255)
|
13
|
+
WHITE = Color.new(255,255,255, 255)
|
14
|
+
|
15
|
+
RED = Color.new(255, 0, 0, 255)
|
16
|
+
GREEN = Color.new(0 ,255, 0, 255)
|
17
|
+
BLUE = Color.new(0 , 0,255, 255)
|
18
|
+
|
19
|
+
YELLOW= Color.new(255,255, 0, 255)
|
20
|
+
CYAN = Color.new( 0,255,255, 255)
|
21
|
+
PURPLE= MAGENTA =
|
22
|
+
Color.new(255, 0,255, 255)
|
23
|
+
|
24
|
+
ANSI_COLORS = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
|
25
|
+
|
26
|
+
# euclidian distance - http://en.wikipedia.org/wiki/Euclidean_distance
|
27
|
+
def euclidian other_color
|
28
|
+
r = (self.r.to_i - other_color.r.to_i)**2
|
29
|
+
r += (self.g.to_i - other_color.g.to_i)**2
|
30
|
+
r += (self.b.to_i - other_color.b.to_i)**2
|
31
|
+
Math.sqrt r
|
32
|
+
end
|
33
|
+
|
34
|
+
def closest_ansi_color
|
35
|
+
a = ANSI_COLORS.map{|c| self.class.const_get(c.to_s.upcase) }
|
36
|
+
a.map!{ |c| self.euclidian(c) }
|
37
|
+
ANSI_COLORS[a.index(a.min)]
|
38
|
+
end
|
14
39
|
|
15
40
|
def white?
|
16
41
|
r == 0xff && g == 0xff && b == 0xff
|
@@ -36,6 +61,15 @@ module ZPNG
|
|
36
61
|
"%02X%02X%02X" % [r,g,b]
|
37
62
|
end
|
38
63
|
|
64
|
+
# try to convert to pseudographics
|
65
|
+
def to_ascii h={}
|
66
|
+
white = h[:white] || ' '
|
67
|
+
black = h[:black] || '#'
|
68
|
+
unknown = h[:unknown] || '?'
|
69
|
+
|
70
|
+
self.white?? white : (self.black?? black : unknown)
|
71
|
+
end
|
72
|
+
|
39
73
|
def to_i
|
40
74
|
((a||0) << 24) + ((r||0) << 16) + ((g||0) << 8) + (b||0)
|
41
75
|
end
|
@@ -47,8 +81,13 @@ module ZPNG
|
|
47
81
|
rs = r ? "%02x" % r : "??"
|
48
82
|
gs = g ? "%02x" % g : "??"
|
49
83
|
bs = b ? "%02x" % b : "??"
|
50
|
-
|
51
|
-
|
84
|
+
if a
|
85
|
+
# alpha is non-NULL
|
86
|
+
"#<ZPNG::Color #%s%s%s a=%d>" % [rs,gs,bs,a]
|
87
|
+
else
|
88
|
+
# alpha is NULL
|
89
|
+
"#<ZPNG::Color #%s%s%s>" % [rs,gs,bs]
|
90
|
+
end
|
52
91
|
end
|
53
92
|
end
|
54
93
|
end
|
data/lib/zpng/image.rb
CHANGED
@@ -22,6 +22,10 @@ module ZPNG
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
def adam7
|
26
|
+
@adam7 ||= Adam7Decoder.new(self)
|
27
|
+
end
|
28
|
+
|
25
29
|
# load image from file
|
26
30
|
def self.load fname
|
27
31
|
open(fname,"rb") do |f|
|
@@ -49,7 +53,7 @@ module ZPNG
|
|
49
53
|
@chunks << (@header = Chunk::IHDR.new(h))
|
50
54
|
if @header.palette_used?
|
51
55
|
@chunks << (@palette = Chunk::PLTE.new)
|
52
|
-
@palette[0] = h[:bg] || Color::BLACK # add default bg color
|
56
|
+
@palette[0] = h[:background] || h[:bg] || Color::BLACK # add default bg color
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
@@ -98,6 +102,10 @@ module ZPNG
|
|
98
102
|
end
|
99
103
|
end
|
100
104
|
|
105
|
+
def bpp
|
106
|
+
@header && @header.bpp
|
107
|
+
end
|
108
|
+
|
101
109
|
def width
|
102
110
|
@header && @header.width
|
103
111
|
end
|
@@ -110,25 +118,27 @@ module ZPNG
|
|
110
118
|
@header && @header.grayscale?
|
111
119
|
end
|
112
120
|
|
121
|
+
def interlaced?
|
122
|
+
@header && @header.interlace != 0
|
123
|
+
end
|
124
|
+
|
113
125
|
def imagedata
|
114
126
|
@imagedata ||=
|
115
127
|
begin
|
116
|
-
|
117
|
-
raise "only non-interlaced mode is supported for imagedata" if @header.interlace != 0
|
118
|
-
else
|
119
|
-
puts "[?] no image header, assuming non-interlaced RGB".yellow
|
120
|
-
end
|
128
|
+
puts "[?] no image header, assuming non-interlaced RGB".yellow unless @header
|
121
129
|
data = @chunks.find_all{ |c| c.is_a?(Chunk::IDAT) }.map(&:data).join
|
122
130
|
(data && data.size > 0) ? Zlib::Inflate.inflate(data) : ''
|
123
131
|
end
|
124
132
|
end
|
125
133
|
|
126
134
|
def [] x, y
|
135
|
+
x,y = adam7.convert_coords(x,y) if interlaced?
|
127
136
|
scanlines[y][x]
|
128
137
|
end
|
129
138
|
|
130
139
|
def []= x, y, newpixel
|
131
140
|
decode_all_scanlines
|
141
|
+
x,y = adam7.convert_coords(x,y) if interlaced?
|
132
142
|
scanlines[y][x] = newpixel
|
133
143
|
end
|
134
144
|
|
@@ -144,7 +154,8 @@ module ZPNG
|
|
144
154
|
@scanlines ||=
|
145
155
|
begin
|
146
156
|
r = []
|
147
|
-
height.to_i
|
157
|
+
n = interlaced? ? adam7.scanlines_count : height.to_i
|
158
|
+
n.times do |i|
|
148
159
|
r << ScanLine.new(self,i)
|
149
160
|
end
|
150
161
|
r.delete_if(&:bad?)
|
@@ -154,7 +165,11 @@ module ZPNG
|
|
154
165
|
|
155
166
|
def to_s h={}
|
156
167
|
if scanlines.any?
|
157
|
-
|
168
|
+
if interlaced?
|
169
|
+
height.times.map{ |y| width.times.map{ |x| self[x,y].to_ascii(h) }.join }.join("\n")
|
170
|
+
else
|
171
|
+
scanlines.map{ |l| l.to_s(h) }.join("\n")
|
172
|
+
end
|
158
173
|
else
|
159
174
|
super()
|
160
175
|
end
|
data/lib/zpng/scan_line.rb
CHANGED
@@ -7,7 +7,7 @@ module ZPNG
|
|
7
7
|
FILTER_AVERAGE = 3
|
8
8
|
FILTER_PAETH = 4
|
9
9
|
|
10
|
-
attr_accessor :image, :idx, :filter, :offset
|
10
|
+
attr_accessor :image, :idx, :filter, :offset, :bpp
|
11
11
|
|
12
12
|
def initialize image, idx
|
13
13
|
@image,@idx = image,idx
|
@@ -22,7 +22,12 @@ module ZPNG
|
|
22
22
|
@decoded_bytes = "\x00" * (size-1)
|
23
23
|
@filter = FILTER_NONE
|
24
24
|
else
|
25
|
-
@offset =
|
25
|
+
@offset =
|
26
|
+
if image.interlaced?
|
27
|
+
image.adam7.scanline_offset(idx)
|
28
|
+
else
|
29
|
+
idx*size
|
30
|
+
end
|
26
31
|
if @filter = image.imagedata[@offset]
|
27
32
|
@filter = @filter.ord
|
28
33
|
else
|
@@ -39,28 +44,32 @@ module ZPNG
|
|
39
44
|
|
40
45
|
# total scanline size in bytes, INCLUDING leading 'filter' byte
|
41
46
|
def size
|
47
|
+
w =
|
48
|
+
if image.interlaced?
|
49
|
+
image.adam7.scanline_width(idx)
|
50
|
+
else
|
51
|
+
image.width
|
52
|
+
end
|
42
53
|
if @BPP
|
43
|
-
|
54
|
+
w*@BPP+1
|
44
55
|
else
|
45
|
-
(
|
56
|
+
(w*@bpp/8.0+1).ceil
|
46
57
|
end
|
47
58
|
end
|
48
59
|
|
49
60
|
def inspect
|
50
|
-
|
51
|
-
|
52
|
-
|
61
|
+
if image.interlaced?
|
62
|
+
"#<ZPNG::ScanLine idx=%-2d offset=%-3d width=%-2d size=%-2d bpp=%d filter=%d>" %
|
63
|
+
[idx, offset, image.adam7.scanline_width(idx), size, bpp, filter]
|
64
|
+
else
|
65
|
+
"#<ZPNG::ScanLine idx=%-2d offset=%-3d size=%-2d bpp=%d filter=%d>" %
|
66
|
+
[idx, offset, size, bpp, filter]
|
67
|
+
end
|
53
68
|
end
|
54
69
|
|
55
70
|
def to_s h={}
|
56
|
-
white = h[:white] || ' '
|
57
|
-
black = h[:black] || '#'
|
58
|
-
unknown = h[:unknown] || '?'
|
59
|
-
|
60
71
|
@image.width.times.map do |i|
|
61
|
-
|
62
|
-
# printf "[d] %08x %s %s\n", px.to_i, px.inspect, px.to_s unless px.black?
|
63
|
-
px.white?? white : (px.black?? black : unknown)
|
72
|
+
decode_pixel(i).to_ascii(h)
|
64
73
|
end.join
|
65
74
|
end
|
66
75
|
|
data/lib/zpng.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'zlib'
|
3
3
|
require 'stringio'
|
4
|
-
|
4
|
+
|
5
|
+
require 'zpng/string_ext'
|
5
6
|
|
6
7
|
require 'zpng/color'
|
7
8
|
require 'zpng/block'
|
8
9
|
require 'zpng/scan_line'
|
9
10
|
require 'zpng/chunk'
|
10
11
|
require 'zpng/image'
|
12
|
+
require 'zpng/adam7_decoder'
|
11
13
|
|
12
14
|
# see alse http://github.com/wvanbergen/chunky_png/
|
13
15
|
|
data/spec/color_spec.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe ZPNG::Color do
|
4
|
+
|
5
|
+
ZPNG::Color::ANSI_COLORS.each do |color_sym|
|
6
|
+
it "finds closest color for #{color_sym}" do
|
7
|
+
color = ZPNG::Color.const_get(color_sym.to_s.upcase)
|
8
|
+
color.closest_ansi_color.should == color_sym
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -7,9 +7,6 @@ require 'zpng'
|
|
7
7
|
# in ./support/ and its subdirectories.
|
8
8
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
9
|
|
10
|
-
RSpec.configure do |config|
|
11
|
-
end
|
12
|
-
|
13
10
|
SAMPLES_DIR = File.join(
|
14
11
|
File.dirname(
|
15
12
|
File.dirname(
|
@@ -22,3 +19,32 @@ SAMPLES =
|
|
22
19
|
else
|
23
20
|
Dir[File.join(SAMPLES_DIR,'qr_*.png')]
|
24
21
|
end
|
22
|
+
|
23
|
+
PNG_SUITE_URL = "http://www.schaik.com/pngsuite/PngSuite-2011apr25.tgz"
|
24
|
+
|
25
|
+
def get_png_suite
|
26
|
+
dir = File.join(SAMPLES_DIR, "png_suite")
|
27
|
+
if Dir.exist?(dir)
|
28
|
+
if Dir[File.join(dir, "*.png")].size > 100
|
29
|
+
# already fetched and unpacked
|
30
|
+
return
|
31
|
+
end
|
32
|
+
else
|
33
|
+
Dir.mkdir(dir)
|
34
|
+
end
|
35
|
+
require 'open-uri'
|
36
|
+
puts "[.] fetching PNG test-suite from #{PNG_SUITE_URL} .. "
|
37
|
+
data = open(PNG_SUITE_URL).read
|
38
|
+
|
39
|
+
fname = File.join(dir, "png_suite.tgz")
|
40
|
+
File.open(fname, "wb"){ |f| f<<data }
|
41
|
+
puts "[.] unpacking .. "
|
42
|
+
system "tar", "xzf", fname, "-C", dir
|
43
|
+
end
|
44
|
+
|
45
|
+
RSpec.configure do |config|
|
46
|
+
config.before :suite do
|
47
|
+
get_png_suite
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/zpng.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "zpng"
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andrey \"Zed\" Zaikin"]
|
12
|
-
s.date = "2012-12-
|
12
|
+
s.date = "2012-12-21"
|
13
13
|
s.email = "zed.0xff@gmail.com"
|
14
14
|
s.executables = ["zpng"]
|
15
15
|
s.extra_rdoc_files = [
|
@@ -29,12 +29,14 @@ Gem::Specification.new do |s|
|
|
29
29
|
"VERSION",
|
30
30
|
"bin/zpng",
|
31
31
|
"lib/zpng.rb",
|
32
|
+
"lib/zpng/adam7_decoder.rb",
|
32
33
|
"lib/zpng/block.rb",
|
33
34
|
"lib/zpng/chunk.rb",
|
34
35
|
"lib/zpng/cli.rb",
|
35
36
|
"lib/zpng/color.rb",
|
36
37
|
"lib/zpng/image.rb",
|
37
38
|
"lib/zpng/scan_line.rb",
|
39
|
+
"lib/zpng/string_ext.rb",
|
38
40
|
"samples/captcha_4bpp.png",
|
39
41
|
"samples/modify.rb",
|
40
42
|
"samples/qr_aux_chunks.png",
|
@@ -46,6 +48,7 @@ Gem::Specification.new do |s|
|
|
46
48
|
"samples/qr_rgb.png",
|
47
49
|
"samples/qr_rgba.png",
|
48
50
|
"spec/ascii_spec.rb",
|
51
|
+
"spec/color_spec.rb",
|
49
52
|
"spec/create_image_spec.rb",
|
50
53
|
"spec/crop_spec.rb",
|
51
54
|
"spec/image_spec.rb",
|
@@ -65,21 +68,21 @@ Gem::Specification.new do |s|
|
|
65
68
|
s.specification_version = 3
|
66
69
|
|
67
70
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
68
|
-
s.add_runtime_dependency(%q<colorize>, [">= 0"])
|
69
71
|
s.add_runtime_dependency(%q<hexdump>, [">= 0"])
|
72
|
+
s.add_runtime_dependency(%q<rainbow>, [">= 0"])
|
70
73
|
s.add_development_dependency(%q<rspec>, [">= 2.8.0"])
|
71
74
|
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
72
75
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
73
76
|
else
|
74
|
-
s.add_dependency(%q<colorize>, [">= 0"])
|
75
77
|
s.add_dependency(%q<hexdump>, [">= 0"])
|
78
|
+
s.add_dependency(%q<rainbow>, [">= 0"])
|
76
79
|
s.add_dependency(%q<rspec>, [">= 2.8.0"])
|
77
80
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
78
81
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
79
82
|
end
|
80
83
|
else
|
81
|
-
s.add_dependency(%q<colorize>, [">= 0"])
|
82
84
|
s.add_dependency(%q<hexdump>, [">= 0"])
|
85
|
+
s.add_dependency(%q<rainbow>, [">= 0"])
|
83
86
|
s.add_dependency(%q<rspec>, [">= 2.8.0"])
|
84
87
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
85
88
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
metadata
CHANGED
@@ -2,19 +2,19 @@
|
|
2
2
|
name: zpng
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Andrey "Zed" Zaikin
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
prerelease: false
|
16
16
|
type: :runtime
|
17
|
-
name:
|
17
|
+
name: hexdump
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
prerelease: false
|
32
32
|
type: :runtime
|
33
|
-
name:
|
33
|
+
name: rainbow
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
35
35
|
requirements:
|
36
36
|
- - ! '>='
|
@@ -112,12 +112,14 @@ files:
|
|
112
112
|
- VERSION
|
113
113
|
- bin/zpng
|
114
114
|
- lib/zpng.rb
|
115
|
+
- lib/zpng/adam7_decoder.rb
|
115
116
|
- lib/zpng/block.rb
|
116
117
|
- lib/zpng/chunk.rb
|
117
118
|
- lib/zpng/cli.rb
|
118
119
|
- lib/zpng/color.rb
|
119
120
|
- lib/zpng/image.rb
|
120
121
|
- lib/zpng/scan_line.rb
|
122
|
+
- lib/zpng/string_ext.rb
|
121
123
|
- samples/captcha_4bpp.png
|
122
124
|
- samples/modify.rb
|
123
125
|
- samples/qr_aux_chunks.png
|
@@ -129,6 +131,7 @@ files:
|
|
129
131
|
- samples/qr_rgb.png
|
130
132
|
- samples/qr_rgba.png
|
131
133
|
- spec/ascii_spec.rb
|
134
|
+
- spec/color_spec.rb
|
132
135
|
- spec/create_image_spec.rb
|
133
136
|
- spec/crop_spec.rb
|
134
137
|
- spec/image_spec.rb
|
@@ -151,7 +154,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
151
154
|
version: '0'
|
152
155
|
segments:
|
153
156
|
- 0
|
154
|
-
hash:
|
157
|
+
hash: 2879730800431969805
|
155
158
|
none: false
|
156
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
160
|
requirements:
|