zpng 0.2.0 → 0.2.1

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/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