zpng 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -23,7 +23,7 @@ Usage
23
23
  -S, --scanlines Show scanlines info
24
24
  -P, --palette Show palette
25
25
  -E, --extract-chunk ID extract a single chunk
26
- -U, --unpack-imagedata unpack Image Data (IDAT) chunk(s), output to stdout
26
+ -D, --imagedata dump unpacked Image Data (IDAT) chunk(s) to stdout
27
27
 
28
28
  -c, --crop GEOMETRY crop image, {WIDTH}x{HEIGHT}+{X}+{Y},
29
29
  puts results on stdout unless --ascii given
@@ -44,7 +44,7 @@ Usage
44
44
 
45
45
  # zpng --chunks qr_aux_chunks.png
46
46
 
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
47
+ [.] <Chunk #00 IHDR size= 13, crc=36a28ef4, width=35, height=35, depth=1, color=0, compression=0, filter=0, interlace=0, idx=0> CRC OK
48
48
  [.] <Chunk #01 gAMA size= 4, crc=0bfc6105 > CRC OK
49
49
  [.] <Chunk #02 sRGB size= 1, crc=aece1ce9 > CRC OK
50
50
  [.] <Chunk #03 cHRM size= 32, crc=9cba513c > CRC OK
@@ -60,80 +60,81 @@ source image: ![qr_rgb.png](https://github.com/zed-0xff/zpng/raw/master/samples/
60
60
 
61
61
  # zpng --ascii --wide qr_rgb.png
62
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
- ############## ## ## #### ## #### ## #### ##
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
+ @@ @@ @@ @@@@ @@ @@ @@@@@@ @@ @@@@@@ @@@@@@
97
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
97
98
 
98
99
  ### Scanlines
99
100
 
100
101
  # zpng --scanlines qr_rgb.png
101
102
 
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>]
103
+ #<ZPNG::ScanLine idx=0 offset=0 size=106 bpp=24 filter=1>
104
+ #<ZPNG::ScanLine idx=1 offset=106 size=106 bpp=24 filter=4>
105
+ #<ZPNG::ScanLine idx=2 offset=212 size=106 bpp=24 filter=4>
106
+ #<ZPNG::ScanLine idx=3 offset=318 size=106 bpp=24 filter=4>
107
+ #<ZPNG::ScanLine idx=4 offset=424 size=106 bpp=24 filter=2>
108
+ #<ZPNG::ScanLine idx=5 offset=530 size=106 bpp=24 filter=2>
109
+ #<ZPNG::ScanLine idx=6 offset=636 size=106 bpp=24 filter=4>
110
+ #<ZPNG::ScanLine idx=7 offset=742 size=106 bpp=24 filter=0>
111
+ #<ZPNG::ScanLine idx=8 offset=848 size=106 bpp=24 filter=1>
112
+ #<ZPNG::ScanLine idx=9 offset=954 size=106 bpp=24 filter=0>
113
+ #<ZPNG::ScanLine idx=10 offset=1060 size=106 bpp=24 filter=0>
114
+ #<ZPNG::ScanLine idx=11 offset=1166 size=106 bpp=24 filter=0>
115
+ #<ZPNG::ScanLine idx=12 offset=1272 size=106 bpp=24 filter=1>
116
+ #<ZPNG::ScanLine idx=13 offset=1378 size=106 bpp=24 filter=2>
117
+ #<ZPNG::ScanLine idx=14 offset=1484 size=106 bpp=24 filter=4>
118
+ #<ZPNG::ScanLine idx=15 offset=1590 size=106 bpp=24 filter=0>
119
+ #<ZPNG::ScanLine idx=16 offset=1696 size=106 bpp=24 filter=4>
120
+ #<ZPNG::ScanLine idx=17 offset=1802 size=106 bpp=24 filter=0>
121
+ #<ZPNG::ScanLine idx=18 offset=1908 size=106 bpp=24 filter=4>
122
+ #<ZPNG::ScanLine idx=19 offset=2014 size=106 bpp=24 filter=4>
123
+ #<ZPNG::ScanLine idx=20 offset=2120 size=106 bpp=24 filter=0>
124
+ #<ZPNG::ScanLine idx=21 offset=2226 size=106 bpp=24 filter=1>
125
+ #<ZPNG::ScanLine idx=22 offset=2332 size=106 bpp=24 filter=2>
126
+ #<ZPNG::ScanLine idx=23 offset=2438 size=106 bpp=24 filter=0>
127
+ #<ZPNG::ScanLine idx=24 offset=2544 size=106 bpp=24 filter=2>
128
+ #<ZPNG::ScanLine idx=25 offset=2650 size=106 bpp=24 filter=1>
129
+ #<ZPNG::ScanLine idx=26 offset=2756 size=106 bpp=24 filter=1>
130
+ #<ZPNG::ScanLine idx=27 offset=2862 size=106 bpp=24 filter=4>
131
+ #<ZPNG::ScanLine idx=28 offset=2968 size=106 bpp=24 filter=4>
132
+ #<ZPNG::ScanLine idx=29 offset=3074 size=106 bpp=24 filter=4>
133
+ #<ZPNG::ScanLine idx=30 offset=3180 size=106 bpp=24 filter=4>
134
+ #<ZPNG::ScanLine idx=31 offset=3286 size=106 bpp=24 filter=2>
135
+ #<ZPNG::ScanLine idx=32 offset=3392 size=106 bpp=24 filter=4>
136
+ #<ZPNG::ScanLine idx=33 offset=3498 size=106 bpp=24 filter=4>
137
+ #<ZPNG::ScanLine idx=34 offset=3604 size=106 bpp=24 filter=1>
137
138
 
138
139
  ### Palette
139
140
 
data/TODO ADDED
@@ -0,0 +1,10 @@
1
+ ways to hide info in PNG:
2
+ * IHDR: longer than 13 bytes
3
+ * IEND:
4
+ * longer than 0 bytes
5
+ * data after IEND
6
+ * TEXT chunks
7
+ * zTXT chunks
8
+ * IDAT:
9
+ * data after last scanline
10
+ * last bits in scanline when bpp%8 != 0
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
data/lib/zpng.rb CHANGED
@@ -3,6 +3,7 @@ require 'zlib'
3
3
  require 'stringio'
4
4
 
5
5
  require 'zpng/string_ext'
6
+ require 'zpng/deep_copyable'
6
7
 
7
8
  require 'zpng/color'
8
9
  require 'zpng/block'
@@ -1,21 +1,29 @@
1
1
  module ZPNG
2
2
  class Adam7Decoder
3
3
  attr_accessor :image
4
+ attr_reader :scanlines_count
4
5
 
5
- def initialize image
6
- @image = image
6
+ # http://en.wikipedia.org/wiki/Adam7_algorithm#Passes
7
+ def initialize img
8
+ @image = img
9
+ @widths = [
10
+ [(img.width/8.0).ceil] * (img.height/8.0).ceil, # pass1
11
+ [((img.width-4)/8.0).ceil] * (img.height/8.0).ceil, # pass2
12
+ [(img.width/4.0).ceil] * ((img.height-4)/8.0).ceil, # pass3
13
+ [((img.width-2)/4.0).ceil] * (img.height/4.0).ceil, # pass4
14
+ [(img.width/2.0).ceil] * ((img.height-2)/4.0).ceil, # pass5
15
+ [((img.width-1)/2.0).ceil] * (img.height/2.0).ceil, # pass6
16
+ [img.width] * ((img.height-1)/2.0).ceil # pass7
17
+ ].map{ |x| x == [0] ? [] : x }
18
+ @scanlines_count = 0
19
+ # two leading zeroes added specially for convert_coords() code readability
20
+ @pass_starts = [0,0] + @widths.map(&:size).map{ |x| @scanlines_count+=x }
21
+ @widths.flatten!
7
22
  end
8
23
 
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
24
  # scanline width in pixels
16
25
  def scanline_width idx
17
- #image.width/8*(2**(idx/2))
18
- WIDTHS[idx*8/image.height]*(image.width/8)
26
+ @widths[idx]
19
27
  end
20
28
 
21
29
  # scanline size in bytes, INCLUDING leading filter byte
@@ -36,25 +44,25 @@ module ZPNG
36
44
 
37
45
  if y%2 == 1
38
46
  # 7th pass: last height/2 full scanlines
39
- [x, y/2 + image.height*11/8]
47
+ [x, y/2 + @pass_starts[7]]
40
48
  elsif x%2 == 1 && y%2 == 0
41
49
  # 6th pass
42
- [x/2, y/2 + image.height*7/8]
50
+ [x/2, y/2 + @pass_starts[6]]
43
51
  elsif x%8 == 0 && y%8 == 0
44
- # 1st pass
52
+ # 1st pass, starts at 0
45
53
  [x/8, y/8]
46
54
  elsif x%8 == 4 && y%8 == 0
47
55
  # 2nd pass
48
- [x/8, y/8 + image.height/8]
56
+ [x/8, y/8 + @pass_starts[2]]
49
57
  elsif x%4 == 0 && y%8 == 4
50
58
  # 3rd pass
51
- [x/4, y/8 + image.height*2/8]
59
+ [x/4, y/8 + @pass_starts[3]]
52
60
  elsif x%4 == 2 && y%4 == 0
53
61
  # 4th pass
54
- [x/4, y/4 + image.height*3/8]
62
+ [x/4, y/4 + @pass_starts[4]]
55
63
  elsif x%2 == 0 && y%4 == 2
56
64
  # 5th pass
57
- [x/2, y/4 + image.height*5/8]
65
+ [x/2, y/4 + @pass_starts[5]]
58
66
  else
59
67
  raise "invalid coords"
60
68
  end
data/lib/zpng/chunk.rb CHANGED
@@ -2,6 +2,8 @@ module ZPNG
2
2
  class Chunk
3
3
  attr_accessor :size, :type, :data, :crc, :idx
4
4
 
5
+ include DeepCopyable
6
+
5
7
  def self.from_stream io
6
8
  size, type = io.read(8).unpack('Na4')
7
9
  io.seek(-8,IO::SEEK_CUR)
data/lib/zpng/cli.rb CHANGED
@@ -41,7 +41,7 @@ class ZPNG::CLI
41
41
  opts.on "-E", "--extract-chunk ID", "extract a single chunk" do |id|
42
42
  @actions << [:extract_chunk, id.to_i]
43
43
  end
44
- opts.on "-U", "--unpack-imagedata", "unpack Image Data (IDAT) chunk(s), output to stdout" do
44
+ opts.on "-D", "--imagedata", "dump unpacked Image Data (IDAT) chunk(s) to stdout" do
45
45
  @actions << :unpack_imagedata
46
46
  end
47
47
 
@@ -74,7 +74,10 @@ class ZPNG::CLI
74
74
  @actions = DEFAULT_ACTIONS if @actions.empty?
75
75
 
76
76
  argv.each_with_index do |fname,idx|
77
- @need_fname_header = (argv.size > 1)
77
+ if argv.size > 1 && @options[:verbose] >= 0
78
+ puts if idx > 0
79
+ puts "[.] #{fname}".color(:green)
80
+ end
78
81
  @file_idx = idx
79
82
  @file_name = fname
80
83
 
@@ -124,7 +127,7 @@ class ZPNG::CLI
124
127
  end
125
128
 
126
129
  def info
127
- puts "[.] image size #{@img.width || '?'}x#{@img.height || '?'}"
130
+ puts "[.] image size #{@img.width || '?'}x#{@img.height || '?'}, bpp=#{@img.bpp}"
128
131
  puts "[.] uncompressed imagedata size = #{@img.imagedata.size} bytes"
129
132
  puts "[.] palette = #{@img.palette}" if @img.palette
130
133
  end
@@ -148,7 +151,7 @@ class ZPNG::CLI
148
151
  spc = @options[:wide] ? " " : " "
149
152
  @img.height.times do |y|
150
153
  @img.width.times do |x|
151
- print spc.background(@img[x,y].closest_ansi_color)
154
+ print spc.background(@img[x,y].to_ansi)
152
155
  end
153
156
  puts
154
157
  end
@@ -159,14 +162,26 @@ class ZPNG::CLI
159
162
  spc = @options[:wide] ? " " : " "
160
163
  @img.height.times do |y|
161
164
  @img.width.times do |x|
162
- print spc.background(@img[x,y].to_s)
165
+ print spc.background(@img[x,y].to_html)
163
166
  end
164
167
  puts
165
168
  end
166
169
  end
167
170
 
168
171
  def scanlines
169
- pp @img.scanlines
172
+ @img.scanlines.each do |sl|
173
+ p sl
174
+ case @options[:verbose]
175
+ when 1
176
+ Hexdump.dump(sl.raw_data)
177
+ when 2
178
+ Hexdump.dump(sl.decoded_bytes)
179
+ when 3..999
180
+ Hexdump.dump(sl.raw_data)
181
+ Hexdump.dump(sl.decoded_bytes)
182
+ puts
183
+ end
184
+ end
170
185
  end
171
186
 
172
187
  def palette
data/lib/zpng/color.rb CHANGED
@@ -1,28 +1,54 @@
1
1
  module ZPNG
2
- class Color < Struct.new(:r,:g,:b,:a)
2
+ class Color
3
+ attr_accessor :r, :g, :b, :a
4
+ attr_accessor :depth, :alpha_depth
3
5
 
4
- def initialize *args
5
- super
6
- self.a ||= 0xff
6
+ include DeepCopyable
7
+
8
+ def initialize *a
9
+ h = a.last.is_a?(Hash) ? a.pop : {}
10
+ @r,@g,@b,@a = *a
11
+
12
+ # default ALPHA = 0xff - opaque
13
+ @a ||= h[:alpha] || 0xff
14
+
15
+ # default sample depth for r,g,b and alpha = 8 bits
16
+ @depth = h[:depth] || 8
17
+ @alpha_depth = h[:alpha_depth] || @depth
7
18
  end
8
19
 
9
20
  alias :alpha :a
10
- def alpha= v; self.a = v; end
21
+ def alpha= a; @a=a; end
11
22
 
12
- BLACK = Color.new(0 , 0, 0, 255)
13
- WHITE = Color.new(255,255,255, 255)
23
+ BLACK = Color.new(0 , 0, 0)
24
+ WHITE = Color.new(255,255,255)
14
25
 
15
- RED = Color.new(255, 0, 0, 255)
16
- GREEN = Color.new(0 ,255, 0, 255)
17
- BLUE = Color.new(0 , 0,255, 255)
26
+ RED = Color.new(255, 0, 0)
27
+ GREEN = Color.new(0 ,255, 0)
28
+ BLUE = Color.new(0 , 0,255)
18
29
 
19
- YELLOW= Color.new(255,255, 0, 255)
20
- CYAN = Color.new( 0,255,255, 255)
30
+ YELLOW= Color.new(255,255, 0)
31
+ CYAN = Color.new( 0,255,255)
21
32
  PURPLE= MAGENTA =
22
- Color.new(255, 0,255, 255)
33
+ Color.new(255, 0,255)
23
34
 
24
35
  ANSI_COLORS = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
25
36
 
37
+ #ASCII_MAP = %q_ .`,-:;~"!<+*^(LJ=?vctsxj12FuoCeyPSah5wVmXA4G9$OR0MQNW#&%@_
38
+ #ASCII_MAP = %q_ .`,-:;~"!<+*^=VXMQNW#&%@_
39
+ #ASCII_MAP = %q_ .,:"!*=7FZVXM#%@_
40
+
41
+ # see misc/gen_ascii_map.rb
42
+ ASCII_MAP =
43
+ [" '''''''```,,",
44
+ ",,---:::::;;;;~~\"\"\"\"",
45
+ "\"!!!!!!<++*^^^(((LLJ",
46
+ "=??vvv]ts[j1122FFuoo",
47
+ "CeyyPEah55333VVmmXA4",
48
+ "G9$666666RRRRRR00MQQ",
49
+ "NNW####&&&&&%%%%%%%%",
50
+ "@@@@@@@"].join
51
+
26
52
  # euclidian distance - http://en.wikipedia.org/wiki/Euclidean_distance
27
53
  def euclidian other_color
28
54
  r = (self.r.to_i - other_color.r.to_i)**2
@@ -31,12 +57,6 @@ module ZPNG
31
57
  Math.sqrt r
32
58
  end
33
59
 
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
39
-
40
60
  def white?
41
61
  r == 0xff && g == 0xff && b == 0xff
42
62
  end
@@ -53,42 +73,79 @@ module ZPNG
53
73
  (r+g+b)/3
54
74
  end
55
75
 
56
- def self.from_grayscale value, alpha = nil
57
- Color.new value,value,value, alpha
76
+ def self.from_grayscale value, alpha_or_hash = nil
77
+ Color.new value,value,value, alpha_or_hash
58
78
  end
59
79
 
60
80
  def to_s
61
81
  "%02X%02X%02X" % [r,g,b]
62
82
  end
63
83
 
84
+ ########################################################
85
+
64
86
  # try to convert to pseudographics
65
- def to_ascii h={}
66
- white = h[:white] || ' '
67
- black = h[:black] || '#'
68
- unknown = h[:unknown] || '?'
87
+ def to_ascii map=ASCII_MAP
88
+ #p self
89
+ map[self.to_grayscale*(map.size-1)/(2**@depth-1), 1]
90
+ end
91
+
92
+ def to_ansi
93
+ return to_depth(8).to_ansi if depth != 8
94
+ a = ANSI_COLORS.map{|c| self.class.const_get(c.to_s.upcase) }
95
+ a.map!{ |c| self.euclidian(c) }
96
+ ANSI_COLORS[a.index(a.min)]
97
+ end
69
98
 
70
- self.white?? white : (self.black?? black : unknown)
99
+ def to_css
100
+ return to_depth(8).to_css if depth != 8
101
+ "#%02X%02X%02X" % [r,g,b]
71
102
  end
103
+ alias :to_html :to_css
104
+
105
+ ########################################################
72
106
 
73
107
  def to_i
74
108
  ((a||0) << 24) + ((r||0) << 16) + ((g||0) << 8) + (b||0)
75
109
  end
76
110
 
77
- def inspect
78
- if r && g && b && a
79
- "#<ZPNG::Color #%02x%02x%02x a=%d>" % [r,g,b,a]
111
+ # change bit depth, return new Color
112
+ def to_depth new_depth
113
+ c = Color.new :depth => new_depth
114
+ if new_depth > self.depth
115
+ %w'r g b'.each do |part|
116
+ color = self.send(part)
117
+ if color%2 == 0
118
+ color <<= (new_depth-self.depth)
119
+ else
120
+ (new_depth-self.depth).times{ color = color*2 + 1 }
121
+ end
122
+ c.send("#{part}=", color)
123
+ end
80
124
  else
81
- rs = r ? "%02x" % r : "??"
82
- gs = g ? "%02x" % g : "??"
83
- bs = b ? "%02x" % b : "??"
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]
125
+ # new_depth < self.depth
126
+ %w'r g b'.each do |part|
127
+ c.send("#{part}=", self.send(part)>>(self.depth-new_depth))
90
128
  end
91
129
  end
130
+ c
131
+ end
132
+
133
+ def inspect
134
+ s = "#<ZPNG::Color"
135
+ if depth == 16
136
+ s << " r=" + (r ? "%04x" % r : "????")
137
+ s << " g=" + (g ? "%04x" % g : "????")
138
+ s << " b=" + (b ? "%04x" % b : "????")
139
+ else
140
+ s << " #"
141
+ s << (r ? "%02x" % r : "??")
142
+ s << (g ? "%02x" % g : "??")
143
+ s << (b ? "%02x" % b : "??")
144
+ end
145
+ s << " a=#{a}" if a && alpha_depth != 0
146
+ s << " depth=#{depth}" if depth != 8
147
+ s << " alpha_depth=#{alpha_depth}" if alpha_depth != 8 && alpha_depth != 0
148
+ s << ">"
92
149
  end
93
150
  end
94
151
  end
@@ -0,0 +1,7 @@
1
+ module ZPNG
2
+ module DeepCopyable
3
+ def deep_copy
4
+ Marshal.load(Marshal.dump(self))
5
+ end
6
+ end
7
+ end
data/lib/zpng/image.rb CHANGED
@@ -3,6 +3,8 @@ module ZPNG
3
3
  attr_accessor :data, :header, :chunks, :scanlines, :imagedata, :palette
4
4
  alias :hdr :header
5
5
 
6
+ include DeepCopyable
7
+
6
8
  PNG_HDR = "\x89PNG\x0d\x0a\x1a\x0a"
7
9
 
8
10
  def initialize x
@@ -124,6 +126,10 @@ module ZPNG
124
126
  @header && @header.interlace != 0
125
127
  end
126
128
 
129
+ def alpha_used?
130
+ @header && @header.alpha_used?
131
+ end
132
+
127
133
  def imagedata
128
134
  @imagedata ||=
129
135
  begin
@@ -165,12 +171,12 @@ module ZPNG
165
171
  end
166
172
  end
167
173
 
168
- def to_s h={}
174
+ def to_ascii *args
169
175
  if scanlines.any?
170
176
  if interlaced?
171
- height.times.map{ |y| width.times.map{ |x| self[x,y].to_ascii(h) }.join }.join("\n")
177
+ height.times.map{ |y| width.times.map{ |x| self[x,y].to_ascii(*args) }.join }.join("\n")
172
178
  else
173
- scanlines.map{ |l| l.to_s(h) }.join("\n")
179
+ scanlines.map{ |l| l.to_ascii(*args) }.join("\n")
174
180
  end
175
181
  else
176
182
  super()
@@ -244,8 +250,40 @@ module ZPNG
244
250
 
245
251
  # returns new image
246
252
  def crop params
253
+ decode_all_scanlines
247
254
  # deep copy first, then crop!
248
- Marshal.load(Marshal.dump(self)).crop!(params)
255
+ deep_copy.crop!(params)
256
+ end
257
+
258
+ def each_pixel &block
259
+ height.times do |y|
260
+ width.times do |x|
261
+ yield(self[x,y], x, y)
262
+ end
263
+ end
264
+ end
265
+
266
+ # returns new deinterlaced image if deinterlaced
267
+ # OR returns self if no need to deinterlace
268
+ def deinterlace
269
+ return self unless interlaced?
270
+ require 'pp'
271
+ pp chunks
272
+
273
+ # copy all but 'interlace' header params
274
+ h = Hash[*%w'width height depth color compression filter'.map{ |k| [k.to_sym, hdr.send(k)] }.flatten]
275
+ new_img = Image.new h
276
+ chunks.each do |chunk|
277
+ next if chunk.is_a?(Chunk::IHDR)
278
+ next if chunk.is_a?(Chunk::IDAT)
279
+ next if chunk.is_a?(Chunk::IEND)
280
+ new_img.chunks << chunk.deep_copy
281
+ end
282
+ each_pixel do |c,x,y|
283
+ new_img[x,y] = c
284
+ end
285
+ p new_img.scanlines
286
+ new_img
249
287
  end
250
288
  end
251
289
  end
@@ -21,6 +21,7 @@ module ZPNG
21
21
  if @image.new?
22
22
  @decoded_bytes = "\x00" * (size-1)
23
23
  @filter = FILTER_NONE
24
+ @offset = idx*size
24
25
  else
25
26
  @offset =
26
27
  if image.interlaced?
@@ -33,7 +34,6 @@ module ZPNG
33
34
  else
34
35
  STDERR.puts "[!] #{self.class}: ##@idx: no data at pos 0, scanline dropped".red
35
36
  end
36
- @offset += 1
37
37
  end
38
38
  end
39
39
 
@@ -67,9 +67,9 @@ module ZPNG
67
67
  end
68
68
  end
69
69
 
70
- def to_s h={}
70
+ def to_ascii *args
71
71
  @image.width.times.map do |i|
72
- decode_pixel(i).to_ascii(h)
72
+ decode_pixel(i).to_ascii(*args)
73
73
  end.join
74
74
  end
75
75
 
@@ -142,27 +142,39 @@ module ZPNG
142
142
  when 8
143
143
  [raw.ord, nil]
144
144
  when 16
145
- raw.unpack 'C2'
145
+ if image.alpha_used?
146
+ raw.unpack 'C2'
147
+ else
148
+ # 16-bit grayscale
149
+ raw.unpack 'n'
150
+ end
146
151
  when 24
147
152
  # RGB
148
153
  return Color.new(*raw.unpack('C3'))
149
154
  when 32
150
- # RGBA
151
- return Color.new(*raw.unpack('C4'))
155
+ if image.grayscale? && image.alpha_used?
156
+ # 16-bit grayscale + 16-bit alpha
157
+ raw.unpack 'n2'
158
+ else
159
+ # RGBA
160
+ return Color.new(*raw.unpack('C4'))
161
+ end
162
+ when 48
163
+ # RGB 16 bits per sample
164
+ return Color.new(*raw.unpack('n3'), :depth => 16)
165
+ when 64
166
+ # RGB 16 bits per sample + 16-bit alpha
167
+ return Color.new(*raw.unpack('n4'), :depth => 16, :alpha_depth => 16)
152
168
  else
153
169
  raise "unexpected bpp #{@bpp}"
154
170
  end
155
171
 
156
172
  if image.grayscale?
157
- if [1,2,4].include?(@bpp)
158
- #color should be extended to a 8-bit range
159
- if color%2 == 0
160
- color <<= (8-@bpp)
161
- else
162
- (8-@bpp).times{ color = color*2 + 1 }
163
- end
164
- end
165
- Color.from_grayscale(color, alpha)
173
+ Color.from_grayscale(color,
174
+ :alpha => alpha,
175
+ :depth => image.hdr.depth,
176
+ :alpha_depth => image.alpha_used? ? image.hdr.depth : 0
177
+ )
166
178
  elsif image.palette
167
179
  color = image.palette[color]
168
180
  color.alpha = alpha
@@ -173,17 +185,14 @@ module ZPNG
173
185
  end
174
186
 
175
187
  def decoded_bytes
176
- raise if caller.size > 50
188
+ #raise if caller.size > 50
177
189
  @decoded_bytes ||=
178
190
  begin
179
191
  # number of bytes per complete pixel, rounding up to one
180
192
  bpp1 = (@bpp/8.0).ceil
181
193
 
182
- # bytes in one scanline
183
- nbytes = (image.width*@bpp/8.0).ceil
184
-
185
194
  s = ''
186
- nbytes.times do |i|
195
+ (size-1).times do |i|
187
196
  b0 = (i-bpp1) >= 0 ? s[i-bpp1] : nil
188
197
  s[i] = decode_byte(i, b0, bpp1)
189
198
  end
@@ -197,9 +206,13 @@ module ZPNG
197
206
  true
198
207
  end
199
208
 
209
+ def raw_data
210
+ @offset ? @image.imagedata[@offset, size] : ''
211
+ end
212
+
200
213
  private
201
214
  def decode_byte x, b0, bpp1
202
- raw = @image.imagedata[@offset+x]
215
+ raw = @image.imagedata[@offset+x+1]
203
216
 
204
217
  unless raw
205
218
  STDERR.puts "[!] #{self.class}: ##@idx: no data at pos #{x}".red
data/misc/chars.png ADDED
Binary file
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ $: << "../lib"
3
+ require 'zpng'
4
+
5
+ h = Hash.new{ |k,v| k[v] = "" }
6
+ a = []
7
+
8
+ big_img = ZPNG::Image.load("chars.png").deinterlace
9
+
10
+ (big_img.width/13).times do |idx|
11
+ img = big_img.crop(:x=>idx*13, :y=>0, :width=>13, :height =>big_img.height)
12
+ s = img.to_ascii(' ##')
13
+ puts s
14
+
15
+ c = (idx+32).chr
16
+ next if c == "_"
17
+ n = s.count('#')
18
+ h[n] << c
19
+ a[n] ||= ''
20
+ a[n] << c
21
+ end
22
+
23
+ puts "[.] step1 results:"
24
+ p a
25
+ while a.index(nil)
26
+ prevset = false
27
+ 0.upto(a.size-1) do |i|
28
+ c = a[i]
29
+ a[i] = c[0] if c && c.size > 1
30
+ if !c && a[i-1] && !prevset
31
+ a[i] = a[i-1]
32
+ prevset = true
33
+ else
34
+ prevset = false
35
+ end
36
+ end
37
+ (a.size-1).downto(0) do |i|
38
+ c = a[i]
39
+ a[i] = c[0] if c && c.size > 1
40
+ if !c && a[i+1] && !prevset
41
+ a[i] = a[i+1]
42
+ prevset = true
43
+ else
44
+ prevset = false
45
+ end
46
+ end
47
+ end
48
+ puts "[.] normalized:"
49
+ p a
50
+ puts
51
+
52
+ h.keys.sort.each do |n|
53
+ printf "[.] %3d: %s\n", n, h[n]
54
+ end
55
+ puts
56
+
57
+ require 'pp'
58
+ puts "[.] final array:"
59
+ puts "a = ["
60
+ a.each_slice(20).map(&:join).each do |slice|
61
+ puts " #{slice.inspect},"
62
+ end
63
+ puts "].join"
@@ -0,0 +1,61 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe ZPNG::Adam7Decoder do
4
+ describe "scanline_width" do
5
+ {
6
+ "8x8" => [1,1,2,2,2],
7
+ "8x16" => [1,1,1,1,2],
8
+ "16x8" => [2,2,4,4,4],
9
+ "16x16"=> [2,2,2,2,4],
10
+ "8x9" => [1,1,1,1,2,2],
11
+ "9x8" => [2,1,3,2,2,5],
12
+ "9x9" => [2,2,1,1,3,2]
13
+ }.each do |dims, slw|
14
+ it "should be right for #{dims} image" do
15
+ w,h = dims.split('x').map(&:to_i)
16
+ img = stub(:width => w, :height => h)
17
+ adam7 = ZPNG::Adam7Decoder.new(img)
18
+ slw.size.times.map{ |i| adam7.scanline_width(i) }.should == slw
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "scanlines_count" do
24
+ {
25
+ "8x8" => 15,
26
+ "8x16" => 30,
27
+ "16x8" => 15,
28
+ "16x16"=> 30,
29
+ "8x9" => 19,
30
+ "9x8" => 15,
31
+ "9x9" => 19,
32
+ "1x1" => 1,
33
+ }.each do |dims, n|
34
+ it "should be right for #{dims} image" do
35
+ w,h = dims.split('x').map(&:to_i)
36
+ img = stub(:width => w, :height => h)
37
+ adam7 = ZPNG::Adam7Decoder.new(img)
38
+ adam7.scanlines_count.should == n
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "@pass_starts" do
44
+ {
45
+ "8x8" => [0, 0, 1, 2, 3, 5, 7, 11, 15],
46
+ "8x16" => [0, 0, 2, 4, 6, 10, 14, 22, 30],
47
+ "16x8" => [0, 0, 1, 2, 3, 5, 7, 11, 15],
48
+ "16x16"=> [0, 0, 2, 4, 6, 10, 14, 22, 30],
49
+ "8x9" => [0, 0, 2, 4, 5, 8, 10, 15, 19],
50
+ "9x8" => [0, 0, 1, 2, 3, 5, 7, 11, 15],
51
+ "9x9" => [0, 0, 2, 4, 5, 8, 10, 15, 19]
52
+ }.each do |dims, pst|
53
+ it "should be right for #{dims} image" do
54
+ w,h = dims.split('x').map(&:to_i)
55
+ img = stub(:width => w, :height => h)
56
+ adam7 = ZPNG::Adam7Decoder.new(img)
57
+ adam7.instance_variable_get("@pass_starts").should == pst
58
+ end
59
+ end
60
+ end
61
+ end
data/spec/ascii_spec.rb CHANGED
@@ -45,7 +45,7 @@ describe "ZPNG png2ascii" do
45
45
  Dir[File.join(SAMPLES_DIR,'qr_*.png')].each do |fname|
46
46
  describe fname do
47
47
  it "generates a nice ascii img" do
48
- ZPNG::Image.new(fname).to_s(:white => '.', :black => '#').strip.should == ASCII_QR.strip
48
+ ZPNG::Image.new(fname).to_ascii('#.').strip.should == ASCII_QR.strip
49
49
  end
50
50
  end
51
51
  end
data/spec/color_spec.rb CHANGED
@@ -5,7 +5,36 @@ describe ZPNG::Color do
5
5
  ZPNG::Color::ANSI_COLORS.each do |color_sym|
6
6
  it "finds closest color for #{color_sym}" do
7
7
  color = ZPNG::Color.const_get(color_sym.to_s.upcase)
8
- color.closest_ansi_color.should == color_sym
8
+ color.to_ansi.should == color_sym
9
+ end
10
+ end
11
+
12
+ describe "to_depth" do
13
+ it "decreases color depth" do
14
+ c = ZPNG::Color.new 0x10, 0x20, 0x30
15
+ c = c.to_depth(4)
16
+ c.depth.should == 4
17
+ c.r.should == 1
18
+ c.g.should == 2
19
+ c.b.should == 3
20
+ end
21
+
22
+ it "increases color depth" do
23
+ c = ZPNG::Color.new 0,2,3, :depth => 4
24
+ c = c.to_depth(8)
25
+ c.depth.should == 8
26
+ c.r.should == 0
27
+ c.g.should == 0x20
28
+ c.b.should == 0x3f
29
+ end
30
+
31
+ it "keeps color depth" do
32
+ c = ZPNG::Color.new 0x11, 0x22, 0x33
33
+ c = c.to_depth(8)
34
+ c.depth.should == 8
35
+ c.r.should == 0x11
36
+ c.g.should == 0x22
37
+ c.b.should == 0x33
9
38
  end
10
39
  end
11
40
  end
@@ -12,7 +12,7 @@ describe Image do
12
12
  describe "new( :bpp => #{bpp}, :color => #{color} )" do
13
13
  subject(:img){ _new_img(bpp,color) }
14
14
  it("should export"){ img.export.should start_with(Image::PNG_HDR) }
15
- it("should to_s") { img.to_s.strip.split("\n").size.should == 8 }
15
+ it("should to_ascii") { img.to_ascii.split("\n").size.should == 8 }
16
16
 
17
17
  subject{ img.hdr }
18
18
  its(:depth) { should == bpp }
@@ -24,7 +24,7 @@ describe Image do
24
24
  describe "new( :bpp => 16, :color => false )" do
25
25
  subject(:img){ _new_img(16,false) }
26
26
  it("should export"){ img.export.should start_with(Image::PNG_HDR) }
27
- it("should to_s") { img.to_s.strip.split("\n").size.should == 8 }
27
+ it("should to_ascii") { img.to_ascii.split("\n").size.should == 8 }
28
28
 
29
29
  subject{ img.hdr }
30
30
  its(:depth) { should == 8 } # 8 bits per color + 8 per alpha = 16 bpp
@@ -39,7 +39,7 @@ describe Image do
39
39
  describe "new( :bpp => 24, :color => false )" do
40
40
  subject(:img){ _new_img(24,false) }
41
41
  it("should export"){ img.export.should start_with(Image::PNG_HDR) }
42
- it("should to_s") { img.to_s.strip.split("\n").size.should == 8 }
42
+ it("should to_ascii") { img.to_ascii.split("\n").size.should == 8 }
43
43
 
44
44
  subject{ img.hdr }
45
45
  its(:depth) { should == 8 } # each channel depth = 8
@@ -49,7 +49,7 @@ describe Image do
49
49
  describe "new( :bpp => 24, :color => true )" do
50
50
  subject(:img){ _new_img(24,true) }
51
51
  it("should export"){ img.export.should start_with(Image::PNG_HDR) }
52
- it("should to_s") { img.to_s.strip.split("\n").size.should == 8 }
52
+ it("should to_ascii") { img.to_ascii.split("\n").size.should == 8 }
53
53
 
54
54
  subject{ img.hdr }
55
55
  its(:depth) { should == 8 } # each channel depth = 8
@@ -59,7 +59,7 @@ describe Image do
59
59
  describe "new( :bpp => 32, :color => false )" do
60
60
  subject(:img){ _new_img(32,false) }
61
61
  it("should export"){ img.export.should start_with(Image::PNG_HDR) }
62
- it("should to_s") { img.to_s.strip.split("\n").size.should == 8 }
62
+ it("should to_ascii") { img.to_ascii.split("\n").size.should == 8 }
63
63
 
64
64
  subject{ img.hdr }
65
65
  its(:depth) { should == 8 } # each channel depth = 8
@@ -69,7 +69,7 @@ describe Image do
69
69
  describe "new( :bpp => 32, :color => true )" do
70
70
  subject(:img){ _new_img(32,true) }
71
71
  it("should export"){ img.export.should start_with(Image::PNG_HDR) }
72
- it("should to_s") { img.to_s.strip.split("\n").size.should == 8 }
72
+ it("should to_ascii") { img.to_ascii.split("\n").size.should == 8 }
73
73
 
74
74
  subject{ img.hdr }
75
75
  its(:depth) { should == 8 } # each channel depth = 8
data/spec/crop_spec.rb CHANGED
@@ -69,24 +69,24 @@ describe Image do
69
69
 
70
70
  it "should extract left square" do
71
71
  img.crop! :x => 1, :y => 1, :width => 7, :height => 7
72
- img.to_s(:white => '.', :black => '#').strip.should == QR_SQUARE.strip
72
+ img.to_ascii('#.').strip.should == QR_SQUARE.strip
73
73
  end
74
74
 
75
75
  it "should extract right square" do
76
76
  img.crop! :x => 27, :y => 1, :width => 7, :height => 7
77
- img.to_s(:white => '.', :black => '#').strip.should == QR_SQUARE.strip
77
+ img.to_ascii('#.').strip.should == QR_SQUARE.strip
78
78
  end
79
79
 
80
80
  it "should extract bottom square" do
81
81
  img.crop! :x => 1, :y => 27, :width => 7, :height => 7
82
- img.to_s(:white => '.', :black => '#').strip.should == QR_SQUARE.strip
82
+ img.to_ascii('#.').strip.should == QR_SQUARE.strip
83
83
  end
84
84
 
85
85
  it "keeps whole original image if crop is larger than image" do
86
86
  img2 = img.crop :x => 0, :y => 0, :width => 7000, :height => 7000
87
87
  img2.width.should == img.width
88
88
  img2.height.should == img.height
89
- img2.to_s.should == img.to_s
89
+ img2.to_ascii.should == img.to_ascii
90
90
  end
91
91
  end
92
92
  end
data/spec/modify_spec.rb CHANGED
@@ -49,7 +49,7 @@ describe "ZPNG modify" do
49
49
  img.width.times do |x|
50
50
  img[x,0] = (x%2==0) ? ZPNG::Color::WHITE : ZPNG::Color::BLACK
51
51
  end
52
- img.to_s(:white => '.', :black => '#').strip.should == ASCII_MODIFIED_QR.strip
52
+ img.to_ascii('#.').strip.should == ASCII_MODIFIED_QR.strip
53
53
  end
54
54
  end
55
55
  end
@@ -29,7 +29,7 @@ describe Image do
29
29
 
30
30
  s = '#'*16
31
31
  s[x] = ' '
32
- img.to_s.should == s
32
+ img.to_ascii('# ').should == s
33
33
 
34
34
  # fname = "out-#{x}-#{bpp}-#{color}.png"
35
35
  # img.save fname
data/zpng.gemspec CHANGED
@@ -5,17 +5,18 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "zpng"
8
- s.version = "0.1.2"
8
+ s.version = "0.2.0"
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-21"
12
+ s.date = "2012-12-23"
13
13
  s.email = "zed.0xff@gmail.com"
14
14
  s.executables = ["zpng"]
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
17
  "README.md",
18
- "README.md.tpl"
18
+ "README.md.tpl",
19
+ "TODO"
19
20
  ]
20
21
  s.files = [
21
22
  ".document",
@@ -26,6 +27,7 @@ Gem::Specification.new do |s|
26
27
  "README.md",
27
28
  "README.md.tpl",
28
29
  "Rakefile",
30
+ "TODO",
29
31
  "VERSION",
30
32
  "bin/zpng",
31
33
  "lib/zpng.rb",
@@ -34,9 +36,12 @@ Gem::Specification.new do |s|
34
36
  "lib/zpng/chunk.rb",
35
37
  "lib/zpng/cli.rb",
36
38
  "lib/zpng/color.rb",
39
+ "lib/zpng/deep_copyable.rb",
37
40
  "lib/zpng/image.rb",
38
41
  "lib/zpng/scan_line.rb",
39
42
  "lib/zpng/string_ext.rb",
43
+ "misc/chars.png",
44
+ "misc/gen_ascii_map.rb",
40
45
  "samples/captcha_4bpp.png",
41
46
  "samples/modify.rb",
42
47
  "samples/qr_aux_chunks.png",
@@ -47,6 +52,7 @@ Gem::Specification.new do |s|
47
52
  "samples/qr_plte_bw.png",
48
53
  "samples/qr_rgb.png",
49
54
  "samples/qr_rgba.png",
55
+ "spec/adam7_spec.rb",
50
56
  "spec/ascii_spec.rb",
51
57
  "spec/color_spec.rb",
52
58
  "spec/create_image_spec.rb",
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: zpng
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.2
5
+ version: 0.2.0
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-21 00:00:00.000000000 Z
12
+ date: 2012-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  prerelease: false
@@ -100,6 +100,7 @@ extra_rdoc_files:
100
100
  - LICENSE.txt
101
101
  - README.md
102
102
  - README.md.tpl
103
+ - TODO
103
104
  files:
104
105
  - .document
105
106
  - .rspec
@@ -109,6 +110,7 @@ files:
109
110
  - README.md
110
111
  - README.md.tpl
111
112
  - Rakefile
113
+ - TODO
112
114
  - VERSION
113
115
  - bin/zpng
114
116
  - lib/zpng.rb
@@ -117,9 +119,12 @@ files:
117
119
  - lib/zpng/chunk.rb
118
120
  - lib/zpng/cli.rb
119
121
  - lib/zpng/color.rb
122
+ - lib/zpng/deep_copyable.rb
120
123
  - lib/zpng/image.rb
121
124
  - lib/zpng/scan_line.rb
122
125
  - lib/zpng/string_ext.rb
126
+ - misc/chars.png
127
+ - misc/gen_ascii_map.rb
123
128
  - samples/captcha_4bpp.png
124
129
  - samples/modify.rb
125
130
  - samples/qr_aux_chunks.png
@@ -130,6 +135,7 @@ files:
130
135
  - samples/qr_plte_bw.png
131
136
  - samples/qr_rgb.png
132
137
  - samples/qr_rgba.png
138
+ - spec/adam7_spec.rb
133
139
  - spec/ascii_spec.rb
134
140
  - spec/color_spec.rb
135
141
  - spec/create_image_spec.rb
@@ -154,7 +160,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
154
160
  version: '0'
155
161
  segments:
156
162
  - 0
157
- hash: -657082677898355514
163
+ hash: -93398394471482814
158
164
  none: false
159
165
  required_rubygems_version: !ruby/object:Gem::Requirement
160
166
  requirements: