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 +0 -1
- data/Gemfile.lock +0 -2
- data/README.md +50 -10
- data/README.md.tpl +15 -1
- data/TODO +6 -0
- data/VERSION +1 -1
- data/lib/zpng.rb +4 -32
- data/lib/zpng/adam7_decoder.rb +8 -1
- data/lib/zpng/chunk.rb +7 -24
- data/lib/zpng/cli.rb +196 -141
- data/lib/zpng/color.rb +85 -30
- data/lib/zpng/hexdump.rb +86 -0
- data/lib/zpng/image.rb +99 -21
- data/lib/zpng/metadata.rb +20 -0
- data/lib/zpng/pixels.rb +25 -0
- data/lib/zpng/scan_line.rb +139 -87
- data/lib/zpng/string_ext.rb +9 -1
- data/lib/zpng/text_chunk.rb +75 -0
- data/samples/itxt.png +0 -0
- data/spec/adam7_spec.rb +24 -0
- data/spec/alpha_spec.rb +28 -0
- data/spec/cli_spec.rb +62 -0
- data/spec/color_spec.rb +12 -2
- data/spec/deinterlace_spec.rb +19 -0
- data/spec/metadata_spec.rb +22 -0
- data/spec/pixel_access_spec.rb +16 -0
- data/spec/pixels_enumerator_spec.rb +34 -0
- data/spec/set_random_pixel_spec.rb +13 -0
- data/spec/spec_helper.rb +1 -22
- data/spec/support/png_suite.rb +43 -0
- data/zpng.gemspec +15 -5
- metadata +16 -19
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -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
|
-
|
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
|
-
-
|
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
|
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,
|
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: )
|
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
|
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
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/zpng.rb
CHANGED
@@ -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
|
-
|
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'
|
data/lib/zpng/adam7_decoder.rb
CHANGED
@@ -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
|
data/lib/zpng/chunk.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
data/lib/zpng/cli.rb
CHANGED
@@ -1,193 +1,248 @@
|
|
1
1
|
require 'zpng'
|
2
2
|
require 'optparse'
|
3
|
-
require 'hexdump'
|
4
3
|
require 'pp'
|
5
4
|
|
6
|
-
|
5
|
+
module ZPNG
|
6
|
+
class CLI
|
7
|
+
include Hexdump
|
7
8
|
|
8
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
35
|
+
opts.on("-m", "--metadata", "Show image metadata, if any (default)"){ @actions << :metadata }
|
40
36
|
|
41
|
-
|
42
|
-
@actions <<
|
43
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
62
|
-
|
76
|
+
|
77
|
+
if (argv = optparser.parse(@argv)).empty?
|
78
|
+
puts optparser.help
|
79
|
+
return
|
63
80
|
end
|
64
|
-
|
65
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
120
|
+
def unpack_imagedata
|
121
|
+
print @img.imagedata
|
122
|
+
end
|
75
123
|
|
76
|
-
|
77
|
-
|
78
|
-
puts
|
79
|
-
|
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
|
-
@
|
82
|
-
@
|
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
|
-
|
133
|
+
def load_file fname
|
134
|
+
@img = Image.load fname
|
135
|
+
end
|
85
136
|
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
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
|
-
|
100
|
-
|
101
|
-
|
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
|
-
|
113
|
-
|
114
|
-
|
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
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
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
|
-
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|