zpng 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,7 +2,6 @@ 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 'hexdump'
6
5
  gem 'rainbow'
7
6
 
8
7
  # Add dependencies to develop your gem here.
@@ -3,7 +3,6 @@ GEM
3
3
  specs:
4
4
  diff-lcs (1.1.3)
5
5
  git (1.2.5)
6
- hexdump (0.2.3)
7
6
  jeweler (1.8.4)
8
7
  bundler (~> 1.0)
9
8
  git (>= 1.2.5)
@@ -28,7 +27,6 @@ PLATFORMS
28
27
 
29
28
  DEPENDENCIES
30
29
  bundler (>= 1.0.0)
31
- hexdump
32
30
  jeweler (~> 1.8.4)
33
31
  rainbow
34
32
  rspec (>= 2.8.0)
data/README.md CHANGED
@@ -6,52 +6,91 @@ Description
6
6
  -----------
7
7
  A pure ruby PNG file manipulation & validation
8
8
 
9
+ (If you need a high-level PNG creation toolkit - take a look at [SugarPNG](https://github.com/zed-0xff/sugar_png))
10
+
9
11
  Installation
10
12
  ------------
11
13
  gem install zpng
12
14
 
15
+ Comparison
16
+ ----------
17
+ * supports `iTXt` (international text) chunks
18
+ * full support of 16-bit color & alpha depth
19
+ * correct 4bpp image decoding (as of 29-Dec-2012, ChunkyPNG had 1-bit error in 4bpp image decoding)
20
+
13
21
  Usage
14
22
  -----
15
23
 
16
24
  # zpng -h
17
25
 
18
26
  Usage: zpng [options] filename.png
19
- -v, --verbose Run verbosely (can be used multiple times)
20
- -q, --quiet Silent any warnings (can be used multiple times)
21
- -C, --chunks Show file chunks (default)
27
+
22
28
  -i, --info General image info (default)
29
+ -c, --chunk(s) [ID] Show chunks (default) or single chunk by its #
30
+ -m, --metadata Show image metadata, if any (default)
31
+
23
32
  -S, --scanlines Show scanlines info
24
33
  -P, --palette Show palette
25
34
  -E, --extract-chunk ID extract a single chunk
26
35
  -D, --imagedata dump unpacked Image Data (IDAT) chunk(s) to stdout
27
36
 
28
- -c, --crop GEOMETRY crop image, {WIDTH}x{HEIGHT}+{X}+{Y},
37
+ -C, --crop GEOMETRY crop image, {WIDTH}x{HEIGHT}+{X}+{Y},
29
38
  puts results on stdout unless --ascii given
30
39
 
31
40
  -A, --ascii Try to convert image to ASCII (works best with monochrome images)
32
41
  -N, --ansi Try to display image as ANSI colored text
33
42
  -2, --256 Try to display image as 256-colored text
34
43
  -W, --wide Use 2 horizontal characters per one pixel
44
+
45
+ -v, --verbose Run verbosely (can be used multiple times)
46
+ -q, --quiet Silent any warnings (can be used multiple times)
35
47
 
36
48
  ### Info
37
49
 
38
- # zpng --info qr_rgb.png
50
+ # zpng qr_rgb.png
39
51
 
40
- [.] image size 35x35
52
+ [.] image size 35x35, 24bpp, COLOR_RGB
41
53
  [.] uncompressed imagedata size = 3710 bytes
54
+ [.] <Chunk #00 IHDR size= 13, crc=91bb240e, width=35, color=2, interlace=0, depth=8, compression=0, height=35, filter=0> CRC OK
55
+ [.] <Chunk #01 sRGB size= 1, crc=aece1ce9 > CRC OK
56
+ [.] <Chunk #02 IDAT size= 399, crc=59790716 > CRC OK
57
+ [.] <Chunk #03 IEND size= 0, crc=ae426082 > CRC OK
58
+
59
+ ### Info (verbose)
60
+
61
+ # zpng -v qr_rgb.png
62
+
63
+ [.] image size 35x35, 24bpp, COLOR_RGB
64
+ [.] uncompressed imagedata size = 3710 bytes
65
+ 01 ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 |................|
66
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 3678 bytes
67
+
68
+ [.] <Chunk #00 IHDR size= 13, crc=91bb240e, width=35, idx=0, color=2, interlace=0, depth=8, compression=0, height=35, filter=0> CRC OK
69
+ 00 00 00 23 00 00 00 23 08 02 00 00 00 |...#...#..... |
70
+
71
+ [.] <Chunk #01 sRGB size= 1, crc=aece1ce9 > CRC OK
72
+ 00 |. |
73
+
74
+ [.] <Chunk #02 IDAT size= 399, crc=59790716 > CRC OK
75
+ 48 c7 bd 56 41 12 c4 20 08 d3 8e ff ff b2 7b 70 |H..VA.. ......{p|
76
+ 86 d2 24 44 db c3 7a d8 d9 b6 08 18 03 a1 cf 39 |..$D..z........9| + 367 bytes
77
+
78
+ [.] <Chunk #03 IEND size= 0, crc=ae426082 > CRC OK
79
+
80
+ ( add more `-v`'s for even more verbose output)
42
81
 
43
82
  ### Chunks
44
83
 
45
84
  # zpng --chunks qr_aux_chunks.png
46
85
 
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
86
+ [.] <Chunk #00 IHDR size= 13, crc=36a28ef4, width=35, color=0, interlace=0, depth=1, compression=0, height=35, filter=0> CRC OK
48
87
  [.] <Chunk #01 gAMA size= 4, crc=0bfc6105 > CRC OK
49
88
  [.] <Chunk #02 sRGB size= 1, crc=aece1ce9 > CRC OK
50
89
  [.] <Chunk #03 cHRM size= 32, crc=9cba513c > CRC OK
51
90
  [.] <Chunk #04 pHYs size= 9, crc=46c96b3e > CRC OK
52
91
  [.] <Chunk #05 IDAT size= 213, crc=5f3f1ff9 > CRC OK
53
- [.] <Chunk #06 tEXt size= 37, crc=8d62fd1a > CRC OK
54
- [.] <Chunk #07 tEXt size= 37, crc=fc3f45a6 > CRC OK
92
+ [.] <Chunk #06 tEXt size= 37, crc=8d62fd1a, keyword="date:create"> CRC OK
93
+ [.] <Chunk #07 tEXt size= 37, crc=fc3f45a6, keyword="date:modify"> CRC OK
55
94
  [.] <Chunk #08 IEND size= 0, crc=ae426082 > CRC OK
56
95
 
57
96
  ### ASCII
@@ -141,7 +180,8 @@ source image: ![qr_rgb.png](https://github.com/zed-0xff/zpng/raw/master/samples/
141
180
  # zpng --palette qr_plte_bw.png
142
181
 
143
182
  <Chunk #02 PLTE size= 6, crc=55c2d37e >
144
- 00000000 ff ff ff 00 00 00 |......|
183
+ color #0: ff ff ff |...|
184
+ color #1: 00 00 00 |...|
145
185
 
146
186
 
147
187
  ## Image manipulation
@@ -6,10 +6,18 @@ Description
6
6
  -----------
7
7
  A pure ruby PNG file manipulation & validation
8
8
 
9
+ (If you need a high-level PNG creation toolkit - take a look at [SugarPNG](https://github.com/zed-0xff/sugar_png))
10
+
9
11
  Installation
10
12
  ------------
11
13
  gem install zpng
12
14
 
15
+ Comparison
16
+ ----------
17
+ * supports `iTXt` (international text) chunks
18
+ * full support of 16-bit color & alpha depth
19
+ * correct 4bpp image decoding (as of 29-Dec-2012, ChunkyPNG had 1-bit error in 4bpp image decoding)
20
+
13
21
  Usage
14
22
  -----
15
23
 
@@ -17,7 +25,13 @@ Usage
17
25
 
18
26
  ### Info
19
27
 
20
- % zpng --info qr_rgb.png
28
+ % zpng qr_rgb.png
29
+
30
+ ### Info (verbose)
31
+
32
+ % zpng -v qr_rgb.png
33
+
34
+ ( add more `-v`'s for even more verbose output)
21
35
 
22
36
  ### Chunks
23
37
 
data/TODO CHANGED
@@ -5,6 +5,12 @@ ways to hide info in PNG:
5
5
  * data after IEND
6
6
  * TEXT chunks
7
7
  * zTXT chunks
8
+ * comp_method
8
9
  * IDAT:
9
10
  * data after last scanline
10
11
  * last bits in scanline when bpp%8 != 0
12
+ * PLTE:
13
+ * raw letters
14
+ * stegano
15
+ * custom chunks
16
+ * crc
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.2.1
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env ruby
2
1
  require 'zlib'
3
2
  require 'stringio'
4
3
 
@@ -9,36 +8,9 @@ require 'zpng/color'
9
8
  require 'zpng/block'
10
9
  require 'zpng/scan_line'
11
10
  require 'zpng/chunk'
11
+ require 'zpng/text_chunk'
12
12
  require 'zpng/image'
13
13
  require 'zpng/adam7_decoder'
14
-
15
- # see alse http://github.com/wvanbergen/chunky_png/
16
-
17
- if $0 == __FILE__
18
- if ARGV.size == 0
19
- puts "gimme a png filename!"
20
- else
21
- img = ZPNG::Image.new(ARGV[0])
22
- img.dump
23
- puts "[.] image size #{img.width}x#{img.height}"
24
- puts "[.] uncompressed imagedata size=#{img.imagedata.size}"
25
- puts "[.] palette =#{img.palette}"
26
- # puts "[.] imagedata: #{img.imagedata[0..30].split('').map{|x| sprintf("%02X",x.ord)}.join(' ')}"
27
-
28
- require 'hexdump'
29
- #Hexdump.dump(img.imagedata, :width => 6)
30
- require 'pp'
31
- pp img.scanlines[0..5]
32
- # puts Hexdump.dump(img.imagedata[0,60])
33
- # img.scanlines.each do |l|
34
- # puts l.to_s
35
- # end
36
- puts img.to_s
37
- img[1,0]= ZPNG::Color.new(0,0,0)
38
- puts img.to_s
39
- File.open 'export.png','wb' do |f|
40
- f << img.export
41
- end
42
- end
43
- end
44
-
14
+ require 'zpng/hexdump'
15
+ require 'zpng/metadata'
16
+ require 'zpng/pixels'
@@ -18,7 +18,7 @@ module ZPNG
18
18
  @scanlines_count = 0
19
19
  # two leading zeroes added specially for convert_coords() code readability
20
20
  @pass_starts = [0,0] + @widths.map(&:size).map{ |x| @scanlines_count+=x }
21
- @widths.flatten!
21
+ @widths.flatten! # yahoo! :))
22
22
  end
23
23
 
24
24
  # scanline width in pixels
@@ -67,5 +67,12 @@ module ZPNG
67
67
  raise "invalid coords"
68
68
  end
69
69
  end
70
+
71
+ # is the specified scanline is a first scanline in the pass?
72
+ # When the image is interlaced, each pass of the interlace pattern is
73
+ # treated as an independent image for filtering purposes
74
+ def pass_start? idx
75
+ @pass_starts.include?(idx)
76
+ end
70
77
  end
71
78
  end
@@ -54,7 +54,7 @@ module ZPNG
54
54
  @data || ''
55
55
  end
56
56
 
57
- def inspect
57
+ def inspect verbosity = 10
58
58
  size = @size ? sprintf("%6d",@size) : sprintf("%6s","???")
59
59
  crc = @crc ? sprintf("%08x",@crc) : sprintf("%8s","???")
60
60
  type = @type.to_s.gsub(/[^0-9a-z]/i){ |x| sprintf("\\x%02X",x.ord) }
@@ -180,10 +180,11 @@ module ZPNG
180
180
  (@color & ALPHA_USED) != 0
181
181
  end
182
182
 
183
- def inspect
183
+ def inspect verbosity = 10
184
+ vars = instance_variables - [:@type, :@crc, :@data, :@size]
185
+ vars -= [:@idx] if verbosity <= 0
184
186
  super.sub(/ *>$/,'') + ", " +
185
- (instance_variables-[:@type, :@crc, :@data, :@size]).
186
- map{ |var| "#{var.to_s.tr('@','')}=#{instance_variable_get(var)}" }.
187
+ vars.map{ |var| "#{var.to_s.tr('@','')}=#{instance_variable_get(var)}" }.
187
188
  join(", ") + ">"
188
189
  end
189
190
  end
@@ -214,7 +215,7 @@ module ZPNG
214
215
  end
215
216
 
216
217
  def add color
217
- raise "palette full, cannot add color #{ncolors}" if ncolors >= max_colors
218
+ raise "palette full (#{ncolors}), cannot add #{color.inspect}" if ncolors >= max_colors
218
219
  idx = ncolors
219
220
  self[idx] = color
220
221
  idx
@@ -228,25 +229,7 @@ module ZPNG
228
229
 
229
230
  class IDAT < Chunk; end
230
231
  class IEND < Chunk; end
232
+ class TRNS < Chunk; end
231
233
 
232
- class ZTXT < Chunk
233
- attr_accessor :keyword, :comp_method, :text
234
- def initialize *args
235
- super
236
- @keyword,@comp_method,@text = data.unpack('Z*Ca*')
237
- if @text
238
- @text = Zlib::Inflate.inflate(@text)
239
- end
240
- end
241
- def inspect
242
- super.sub(/ *>$/,'') + ", " +
243
- (instance_variables-[:@type, :@crc, :@data, :@size]).
244
- map do |var|
245
- t = instance_variable_get(var).to_s
246
- t = t[0..10] + "..." if t.size > 10
247
- "#{var.to_s.tr('@','')}=#{t}"
248
- end.join(", ") + ">"
249
- end
250
- end
251
234
  end
252
235
  end
@@ -1,193 +1,248 @@
1
1
  require 'zpng'
2
2
  require 'optparse'
3
- require 'hexdump'
4
3
  require 'pp'
5
4
 
6
- class ZPNG::CLI
5
+ module ZPNG
6
+ class CLI
7
+ include Hexdump
7
8
 
8
- ACTIONS = {
9
- 'chunks' => 'Show file chunks (default)',
10
- %w'i info' => 'General image info (default)',
11
- 'scanlines' => 'Show scanlines info',
12
- 'palette' => 'Show palette'
13
- }
14
- DEFAULT_ACTIONS = %w'info chunks'
9
+ DEFAULT_ACTIONS = %w'info metadata chunks'
15
10
 
16
- def initialize argv = ARGV
17
- @argv = argv
18
- end
19
-
20
- def run
21
- @actions = []
22
- @options = { :verbose => 0 }
23
- optparser = OptionParser.new do |opts|
24
- opts.banner = "Usage: zpng [options] filename.png"
11
+ def initialize argv = ARGV
12
+ # hack #1: allow --chunk as well as --chunks
13
+ @argv = argv.map{ |x| x.sub(/^--chunks?/,'--chunk(s)') }
25
14
 
26
- opts.on "-v", "--verbose", "Run verbosely (can be used multiple times)" do |v|
27
- @options[:verbose] += 1
28
- end
29
- opts.on "-q", "--quiet", "Silent any warnings (can be used multiple times)" do |v|
30
- @options[:verbose] -= 1
15
+ # hack #2: allow --chunk(s) followed by a non-number, like "zpng --chunks fname.png"
16
+ @argv.each_cons(2) do |a,b|
17
+ if a == "--chunk(s)" && b !~ /^\d+$/
18
+ a<<"=-1"
19
+ end
31
20
  end
21
+ end
32
22
 
33
- ACTIONS.each do |t,desc|
34
- if t.is_a?(Array)
35
- opts.on *[ "-#{t[0]}", "--#{t[1]}", desc, eval("lambda{ |_| @actions << :#{t[1]} }") ]
36
- else
37
- opts.on *[ "-#{t[0].upcase}", "--#{t}", desc, eval("lambda{ |_| @actions << :#{t} }") ]
23
+ def run
24
+ @actions = []
25
+ @options = { :verbose => 0 }
26
+ optparser = OptionParser.new do |opts|
27
+ opts.banner = "Usage: zpng [options] filename.png"
28
+ opts.separator ""
29
+
30
+ opts.on("-i", "--info", "General image info (default)"){ @actions << :info }
31
+ opts.on("-c", "--chunk(s) [ID]", Integer, "Show chunks (default) or single chunk by its #") do |id|
32
+ id = nil if id == -1
33
+ @actions << [:chunks, id]
38
34
  end
39
- end
35
+ opts.on("-m", "--metadata", "Show image metadata, if any (default)"){ @actions << :metadata }
40
36
 
41
- opts.on "-E", "--extract-chunk ID", "extract a single chunk" do |id|
42
- @actions << [:extract_chunk, id.to_i]
43
- end
44
- opts.on "-D", "--imagedata", "dump unpacked Image Data (IDAT) chunk(s) to stdout" do
45
- @actions << :unpack_imagedata
46
- end
37
+ opts.separator ""
38
+ opts.on("-S", "--scanlines", "Show scanlines info"){ @actions << :scanlines }
39
+ opts.on("-P", "--palette", "Show palette"){ @actions << :palette }
47
40
 
48
- opts.separator ""
49
- opts.on "-c", "--crop GEOMETRY", "crop image, {WIDTH}x{HEIGHT}+{X}+{Y},",
50
- "puts results on stdout unless --ascii given" do |x|
51
- @actions << [:crop, x]
52
- end
41
+ opts.on "-E", "--extract-chunk ID", Integer, "extract a single chunk" do |id|
42
+ @actions << [:extract_chunk, id]
43
+ end
44
+ opts.on "-D", "--imagedata", "dump unpacked Image Data (IDAT) chunk(s) to stdout" do
45
+ @actions << :unpack_imagedata
46
+ end
53
47
 
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
48
+ opts.separator ""
49
+ opts.on "-C", "--crop GEOMETRY", "crop image, {WIDTH}x{HEIGHT}+{X}+{Y},",
50
+ "puts results on stdout unless --ascii given" do |x|
51
+ @actions << [:crop, x]
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
67
+
68
+ opts.separator ""
69
+ opts.on "-v", "--verbose", "Run verbosely (can be used multiple times)" do |v|
70
+ @options[:verbose] += 1
71
+ end
72
+ opts.on "-q", "--quiet", "Silent any warnings (can be used multiple times)" do |v|
73
+ @options[:verbose] -= 1
74
+ end
60
75
  end
61
- opts.on "-2", '--256', 'Try to display image as 256-colored text' do
62
- @actions << :ansi256
76
+
77
+ if (argv = optparser.parse(@argv)).empty?
78
+ puts optparser.help
79
+ return
63
80
  end
64
- opts.on "-W", '--wide', 'Use 2 horizontal characters per one pixel' do
65
- @options[:wide] = true
81
+
82
+ @actions = DEFAULT_ACTIONS if @actions.empty?
83
+
84
+ argv.each_with_index do |fname,idx|
85
+ if argv.size > 1 && @options[:verbose] >= 0
86
+ puts if idx > 0
87
+ puts "[.] #{fname}".color(:green)
88
+ end
89
+ @file_idx = idx
90
+ @file_name = fname
91
+
92
+ @zpng = load_file fname
93
+
94
+ @actions.each do |action|
95
+ if action.is_a?(Array)
96
+ self.send(*action) if self.respond_to?(action.first)
97
+ else
98
+ self.send(action) if self.respond_to?(action)
99
+ end
100
+ end
66
101
  end
102
+ rescue Errno::EPIPE
103
+ # output interrupt, f.ex. when piping output to a 'head' command
104
+ # prevents a 'Broken pipe - <STDOUT> (Errno::EPIPE)' message
67
105
  end
68
106
 
69
- if (argv = optparser.parse(@argv)).empty?
70
- puts optparser.help
71
- return
107
+ def extract_chunk id
108
+ @img.chunks.each do |chunk|
109
+ if chunk.idx == id
110
+ case chunk
111
+ when Chunk::ZTXT
112
+ print chunk.text
113
+ else
114
+ print chunk.data
115
+ end
116
+ end
117
+ end
72
118
  end
73
119
 
74
- @actions = DEFAULT_ACTIONS if @actions.empty?
120
+ def unpack_imagedata
121
+ print @img.imagedata
122
+ end
75
123
 
76
- argv.each_with_index do |fname,idx|
77
- if argv.size > 1 && @options[:verbose] >= 0
78
- puts if idx > 0
79
- puts "[.] #{fname}".color(:green)
124
+ def crop geometry
125
+ unless geometry =~ /\A(\d+)x(\d+)\+(\d+)\+(\d+)\Z/i
126
+ STDERR.puts "[!] invalid geometry #{geometry.inspect}, must be WxH+X+Y, like 100x100+10+10"
127
+ exit 1
80
128
  end
81
- @file_idx = idx
82
- @file_name = fname
129
+ @img.crop! :width => $1.to_i, :height => $2.to_i, :x => $3.to_i, :y => $4.to_i
130
+ print @img.export unless @actions.include?(:ascii)
131
+ end
83
132
 
84
- @zpng = load_file fname
133
+ def load_file fname
134
+ @img = Image.load fname
135
+ end
85
136
 
86
- @actions.each do |action|
87
- if action.is_a?(Array)
88
- self.send(*action) if self.respond_to?(action.first)
137
+ def metadata
138
+ return if @img.metadata.empty?
139
+ puts "[.] metadata:"
140
+ @img.metadata.each do |k,v,h|
141
+ if h.keys.sort == [:keyword, :text]
142
+ v.gsub!(/[\n\r]+/, "\n"+" "*18)
143
+ printf " %-11s : %s\n", k, v.gray
89
144
  else
90
- self.send(action) if self.respond_to?(action)
145
+ printf " %s (%s: %s):", k, h[:language], h[:translated_keyword]
146
+ v.gsub!(/[\n\r]+/, "\n"+" "*18)
147
+ printf "\n%s%s\n", " "*18, v.gray
91
148
  end
92
149
  end
150
+ puts
93
151
  end
94
- rescue Errno::EPIPE
95
- # output interrupt, f.ex. when piping output to a 'head' command
96
- # prevents a 'Broken pipe - <STDOUT> (Errno::EPIPE)' message
97
- end
98
152
 
99
- def extract_chunk id
100
- @img.chunks.each do |chunk|
101
- if chunk.idx == id
102
- case chunk
103
- when ZPNG::Chunk::ZTXT
104
- print chunk.text
105
- else
106
- print chunk.data
107
- end
153
+ def info
154
+ color = %w'COLOR_GRAYSCALE COLOR_RGB COLOR_INDEXED COLOR_GRAY_ALPHA COLOR_RGBA'.find do |k|
155
+ @img.hdr.color == ZPNG.const_get(k)
108
156
  end
157
+ puts "[.] image size #{@img.width || '?'}x#{@img.height || '?'}, #{@img.bpp}bpp, #{color}"
158
+ puts "[.] palette = #{@img.palette}" if @img.palette
159
+ puts "[.] uncompressed imagedata size = #{@img.imagedata.size} bytes"
160
+ _conditional_hexdump @img.imagedata, 3
109
161
  end
110
- end
111
162
 
112
- def unpack_imagedata
113
- print @img.imagedata
114
- end
163
+ def _conditional_hexdump data, v2 = 2
164
+ if @options[:verbose] <= 0
165
+ # do nothing
166
+ elsif @options[:verbose] < v2
167
+ sz = 0x20
168
+ print Hexdump.dump(data[0,sz],
169
+ :show_offset => false,
170
+ :tail => data.size > sz ? " + #{data.size-sz} bytes\n" : "\n"
171
+ ){ |row| row.insert(0," ") }.gray
172
+ puts
115
173
 
116
- def crop geometry
117
- unless geometry =~ /\A(\d+)x(\d+)\+(\d+)\+(\d+)\Z/i
118
- STDERR.puts "[!] invalid geometry #{geometry.inspect}, must be WxH+X+Y, like 100x100+10+10"
119
- exit 1
174
+ elsif @options[:verbose] >= v2
175
+ print Hexdump.dump(data){ |row| row.insert(0," ") }.gray
176
+ puts
177
+ end
120
178
  end
121
- @img.crop! :width => $1.to_i, :height => $2.to_i, :x => $3.to_i, :y => $4.to_i
122
- print @img.export unless @actions.include?(:ascii)
123
- end
124
-
125
- def load_file fname
126
- @img = ZPNG::Image.new fname
127
- end
128
-
129
- def info
130
- puts "[.] image size #{@img.width || '?'}x#{@img.height || '?'}, bpp=#{@img.bpp}"
131
- puts "[.] uncompressed imagedata size = #{@img.imagedata.size} bytes"
132
- puts "[.] palette = #{@img.palette}" if @img.palette
133
- end
134
179
 
135
- def chunks
136
- @img.dump
137
- end
180
+ def chunks idx=nil
181
+ @img.chunks.each do |chunk|
182
+ next if idx && chunk.idx != idx
183
+ colored_type = chunk.type.magenta
184
+ colored_crc = chunk.crc_ok? ? 'CRC OK'.green : 'CRC ERROR'.red
185
+ puts "[.] #{chunk.inspect(@options[:verbose]).sub(chunk.type, colored_type)} #{colored_crc}"
138
186
 
139
- def ascii
140
- @img.height.times do |y|
141
- @img.width.times do |x|
142
- c = @img[x,y].to_ascii
143
- c *= 2 if @options[:wide]
144
- print c
187
+ _conditional_hexdump(chunk.data) unless chunk.size == 0
145
188
  end
146
- puts
147
189
  end
148
- end
149
190
 
150
- def ansi
151
- spc = @options[:wide] ? " " : " "
152
- @img.height.times do |y|
153
- @img.width.times do |x|
154
- print spc.background(@img[x,y].to_ansi)
191
+ def ascii
192
+ @img.height.times do |y|
193
+ @img.width.times do |x|
194
+ c = @img[x,y].to_ascii
195
+ c *= 2 if @options[:wide]
196
+ print c
197
+ end
198
+ puts
155
199
  end
156
- puts
157
200
  end
158
- end
159
201
 
160
- def ansi256
161
- require 'rainbow'
162
- spc = @options[:wide] ? " " : " "
163
- @img.height.times do |y|
164
- @img.width.times do |x|
165
- print spc.background(@img[x,y].to_html)
202
+ def ansi
203
+ spc = @options[:wide] ? " " : " "
204
+ @img.height.times do |y|
205
+ @img.width.times do |x|
206
+ print spc.background(@img[x,y].to_ansi)
207
+ end
208
+ puts
166
209
  end
167
- puts
168
210
  end
169
- end
170
211
 
171
- def 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)
212
+ def ansi256
213
+ require 'rainbow'
214
+ spc = @options[:wide] ? " " : " "
215
+ @img.height.times do |y|
216
+ @img.width.times do |x|
217
+ print spc.background(@img[x,y].to_html)
218
+ end
182
219
  puts
183
220
  end
184
221
  end
185
- end
186
222
 
187
- def palette
188
- if @img.palette
189
- pp @img.palette
190
- Hexdump.dump @img.palette.data, :width => 6*3
223
+ def scanlines
224
+ @img.scanlines.each do |sl|
225
+ p sl
226
+ case @options[:verbose]
227
+ when 1
228
+ hexdump(sl.raw_data)
229
+ when 2
230
+ hexdump(sl.decoded_bytes)
231
+ when 3..999
232
+ hexdump(sl.raw_data)
233
+ hexdump(sl.decoded_bytes)
234
+ puts
235
+ end
236
+ end
237
+ end
238
+
239
+ def palette
240
+ if @img.palette
241
+ pp @img.palette
242
+ hexdump(@img.palette.data, :width => 3, :show_offset => false) do |row, offset|
243
+ row.insert(0," color %4s: " % "##{(offset/3)}")
244
+ end
245
+ end
191
246
  end
192
247
  end
193
248
  end