chunky_png 0.9.2 → 0.10.0
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.lock +1 -1
- data/benchmarks/decoding_benchmark.rb +8 -4
- data/benchmarks/encoding_benchmark.rb +3 -1
- data/benchmarks/filesize_benchmark.rb +30 -0
- data/chunky_png.gemspec +4 -4
- data/lib/chunky_png.rb +11 -1
- data/lib/chunky_png/canvas.rb +19 -2
- data/lib/chunky_png/canvas/drawing.rb +2 -2
- data/lib/chunky_png/canvas/operations.rb +1 -1
- data/lib/chunky_png/canvas/png_decoding.rb +85 -94
- data/lib/chunky_png/canvas/png_encoding.rb +120 -132
- data/lib/chunky_png/canvas/stream_importing.rb +2 -2
- data/spec/chunky_png/canvas/png_decoding_spec.rb +27 -29
- data/spec/chunky_png/canvas/png_encoding_spec.rb +103 -22
- data/spec/resources/pixelstream_best_compression.png +0 -0
- data/spec/resources/pixelstream_fast_rgba.png +0 -0
- data/tasks/github-gem.rake +24 -36
- metadata +87 -73
data/Gemfile.lock
CHANGED
@@ -16,9 +16,11 @@ def image_data(name)
|
|
16
16
|
data
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
no_filtering_stream = image_data('pixelstream_fast_rgba.png')
|
20
|
+
up_filtering_stream = image_data('pixelstream_reference.png')
|
21
|
+
paeth_filtering_stream = image_data('pixelstream_best_compression.png')
|
22
|
+
rgba_pixelstream = image_data('pixelstream.rgba')
|
23
|
+
rgb_pixelstream = image_data('pixelstream.rgb')
|
22
24
|
|
23
25
|
n = (ENV['N'] || '5').to_i
|
24
26
|
|
@@ -28,7 +30,9 @@ puts "---------------------------------------------"
|
|
28
30
|
puts
|
29
31
|
|
30
32
|
Benchmark.bmbm do |x|
|
31
|
-
x.report('
|
33
|
+
x.report('PNG - no filtering') { n.times { ChunkyPNG::Image.from_blob(no_filtering_stream) } }
|
34
|
+
x.report('PNG - UP filtering') { n.times { ChunkyPNG::Image.from_blob(up_filtering_stream) } }
|
35
|
+
x.report('PNG - PAETH filtering') { n.times { ChunkyPNG::Image.from_blob(paeth_filtering_stream) } }
|
32
36
|
x.report('From RGBA pixelstream') { n.times { ChunkyPNG::Image.from_rgba_stream(240, 180, rgba_pixelstream) } }
|
33
37
|
x.report('From RGB pixelstream') { n.times { ChunkyPNG::Image.from_rgb_stream(240, 180, rgb_pixelstream) } }
|
34
38
|
end
|
@@ -21,11 +21,13 @@ puts "---------------------------------------------"
|
|
21
21
|
puts
|
22
22
|
|
23
23
|
Benchmark.bmbm do |x|
|
24
|
-
x.report('
|
24
|
+
x.report('Autodetect (indexed)') { n.times { image.to_blob } }
|
25
25
|
|
26
26
|
# Presets
|
27
|
+
x.report(':no_compression') { n.times { image.to_blob(:no_compression) } }
|
27
28
|
x.report(':fast_rgba') { n.times { image.to_blob(:fast_rgba) } }
|
28
29
|
x.report(':fast_rgb') { n.times { image.to_blob(:fast_rgb) } }
|
30
|
+
x.report(':good_compression') { n.times { image.to_blob(:good_compression) } }
|
29
31
|
x.report(':best_compression') { n.times { image.to_blob(:best_compression) } }
|
30
32
|
|
31
33
|
# Some options
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
require 'benchmark'
|
7
|
+
require 'chunky_png'
|
8
|
+
|
9
|
+
files = ['pixelstream_reference.png', 'operations.png', 'gray_10x10.png', 'clock_stubbed.png']
|
10
|
+
|
11
|
+
def encode_png(image, constraints = {})
|
12
|
+
filesize = nil
|
13
|
+
time = Benchmark.realtime { filesize = image.to_blob(constraints).bytesize }
|
14
|
+
[filesize, time]
|
15
|
+
end
|
16
|
+
|
17
|
+
files.each do |file|
|
18
|
+
filename = File.join(File.dirname(__FILE__), '..', 'spec', 'resources', file)
|
19
|
+
image = ChunkyPNG::Canvas.from_file(filename)
|
20
|
+
|
21
|
+
puts "#{file}: #{image.width}x#{image.height} - #{image.palette.size} colors"
|
22
|
+
puts "------------------------------------------------"
|
23
|
+
puts "<default> : %8d bytes in %0.4fs" % encode_png(image)
|
24
|
+
puts ":no_compression : %8d bytes in %0.4fs" % encode_png(image, :no_compression)
|
25
|
+
puts ":fast_rgba : %8d bytes in %0.4fs" % encode_png(image, :fast_rgba)
|
26
|
+
puts ":fast_rgb : %8d bytes in %0.4fs" % encode_png(image, :fast_rgb)
|
27
|
+
puts ":good_compression : %8d bytes in %0.4fs" % encode_png(image, :good_compression)
|
28
|
+
puts ":best_compression : %8d bytes in %0.4fs" % encode_png(image, :best_compression)
|
29
|
+
puts
|
30
|
+
end
|
data/chunky_png.gemspec
CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
|
4
4
|
# Do not change the version and date fields by hand. This will be done
|
5
5
|
# automatically by the gem release script.
|
6
|
-
s.version = "0.
|
7
|
-
s.date = "2010-
|
6
|
+
s.version = "0.10.0"
|
7
|
+
s.date = "2010-10-04"
|
8
8
|
|
9
9
|
s.summary = "Pure ruby library for read/write, chunk-level access to PNG files"
|
10
10
|
s.description = <<-EOT
|
@@ -34,6 +34,6 @@ Gem::Specification.new do |s|
|
|
34
34
|
|
35
35
|
# Do not change the files and test_files fields by hand. This will be done
|
36
36
|
# automatically by the gem release script.
|
37
|
-
s.files = %w(
|
38
|
-
s.test_files = %w(spec/chunky_png/canvas/adam7_interlacing_spec.rb spec/chunky_png/canvas/
|
37
|
+
s.files = %w(.gitignore BENCHMARKS.rdoc Gemfile Gemfile.lock LICENSE README.rdoc Rakefile benchmarks/decoding_benchmark.rb benchmarks/encoding_benchmark.rb benchmarks/filesize_benchmark.rb chunky_png.gemspec lib/chunky_png.rb lib/chunky_png/canvas.rb lib/chunky_png/canvas/adam7_interlacing.rb lib/chunky_png/canvas/drawing.rb lib/chunky_png/canvas/operations.rb lib/chunky_png/canvas/png_decoding.rb lib/chunky_png/canvas/png_encoding.rb lib/chunky_png/canvas/stream_exporting.rb lib/chunky_png/canvas/stream_importing.rb lib/chunky_png/chunk.rb lib/chunky_png/color.rb lib/chunky_png/datastream.rb lib/chunky_png/image.rb lib/chunky_png/palette.rb lib/chunky_png/rmagick.rb spec/chunky_png/canvas/adam7_interlacing_spec.rb spec/chunky_png/canvas/drawing_spec.rb spec/chunky_png/canvas/operations_spec.rb spec/chunky_png/canvas/png_decoding_spec.rb spec/chunky_png/canvas/png_encoding_spec.rb spec/chunky_png/canvas_spec.rb spec/chunky_png/color_spec.rb spec/chunky_png/datastream_spec.rb spec/chunky_png/image_spec.rb spec/chunky_png/rmagick_spec.rb spec/chunky_png_spec.rb spec/resources/16x16_interlaced.png spec/resources/16x16_non_interlaced.png spec/resources/adam7.png spec/resources/clock.png spec/resources/clock_base.png spec/resources/clock_flip_horizontally.png spec/resources/clock_flip_vertically.png spec/resources/clock_mask.png spec/resources/clock_mask_updated.png spec/resources/clock_rotate_180.png spec/resources/clock_rotate_left.png spec/resources/clock_rotate_right.png spec/resources/clock_stubbed.png spec/resources/clock_updated.png spec/resources/composited.png spec/resources/cropped.png spec/resources/damaged_chunk.png spec/resources/damaged_signature.png spec/resources/gray_10x10.png spec/resources/gray_10x10_grayscale.png spec/resources/gray_10x10_grayscale_alpha.png spec/resources/gray_10x10_indexed.png spec/resources/gray_10x10_truecolor.png spec/resources/gray_10x10_truecolor_alpha.png spec/resources/indexed_4bit.png spec/resources/lines.png spec/resources/operations.png spec/resources/pixelstream.rgb spec/resources/pixelstream.rgba spec/resources/pixelstream_best_compression.png spec/resources/pixelstream_fast_rgba.png spec/resources/pixelstream_reference.png spec/resources/rect.png spec/resources/replaced.png spec/resources/text_chunk.png spec/resources/transparent_gray_10x10.png spec/resources/ztxt_chunk.png spec/spec_helper.rb tasks/benchmarks.rake tasks/github-gem.rake)
|
38
|
+
s.test_files = %w(spec/chunky_png/canvas/adam7_interlacing_spec.rb spec/chunky_png/canvas/drawing_spec.rb spec/chunky_png/canvas/operations_spec.rb spec/chunky_png/canvas/png_decoding_spec.rb spec/chunky_png/canvas/png_encoding_spec.rb spec/chunky_png/canvas_spec.rb spec/chunky_png/color_spec.rb spec/chunky_png/datastream_spec.rb spec/chunky_png/image_spec.rb spec/chunky_png/rmagick_spec.rb spec/chunky_png_spec.rb)
|
39
39
|
end
|
data/lib/chunky_png.rb
CHANGED
@@ -27,7 +27,7 @@ module ChunkyPNG
|
|
27
27
|
|
28
28
|
# The current version of ChunkyPNG. This value will be updated automatically
|
29
29
|
# by them gem:release rake task.
|
30
|
-
VERSION = "0.
|
30
|
+
VERSION = "0.10.0"
|
31
31
|
|
32
32
|
###################################################
|
33
33
|
# PNG international standard defined constants
|
@@ -80,4 +80,14 @@ module ChunkyPNG
|
|
80
80
|
# Exception that is raised if an expectation fails.
|
81
81
|
class OutOfBounds < ChunkyPNG::ExpectationFailed
|
82
82
|
end
|
83
|
+
|
84
|
+
EXTRA_BYTE = (RUBY_VERSION.to_f < 1.9) ? "\0" : "\0".force_encoding('ASCII-8BIT')
|
85
|
+
end
|
86
|
+
|
87
|
+
if RUBY_VERSION.to_f < 1.9
|
88
|
+
class String
|
89
|
+
alias_method :getbyte, :[]
|
90
|
+
alias_method :setbyte, :[]=
|
91
|
+
alias_method :bytesize, :size
|
92
|
+
end
|
83
93
|
end
|
data/lib/chunky_png/canvas.rb
CHANGED
@@ -97,20 +97,37 @@ module ChunkyPNG
|
|
97
97
|
# @param [Integer] x The x-coordinate of the pixel (column)
|
98
98
|
# @param [Integer] y The y-coordinate of the pixel (row)
|
99
99
|
# @param [ChunkyPNG::Color] pixel The new pixel for the provided coordinates.
|
100
|
+
# @return [Integer] the new pixel value, i.e. <tt>color</tt>.
|
101
|
+
# @raise [ChunkyPNG::OutOfBounds] when the coordinates are outside of the image's dimensions.
|
100
102
|
def []=(x, y, color)
|
101
103
|
assert_xy!(x, y)
|
102
104
|
@pixels[y * width + x] = color
|
103
105
|
end
|
104
106
|
|
107
|
+
# Replaces a single pixel in this canvas, without bounds checking.
|
108
|
+
# @param (see #[]=)
|
109
|
+
# @return [Integer] the new pixel value, i.e. <tt>color</tt>.
|
110
|
+
def set_pixel(x, y, color)
|
111
|
+
@pixels[y * width + x] = color
|
112
|
+
end
|
113
|
+
|
105
114
|
# Returns a single pixel from this canvas.
|
106
115
|
# @param [Integer] x The x-coordinate of the pixel (column)
|
107
116
|
# @param [Integer] y The y-coordinate of the pixel (row)
|
108
117
|
# @return [ChunkyPNG::Color] The current pixel at the provided coordinates.
|
118
|
+
# @raise [ChunkyPNG::OutOfBounds] when the coordinates are outside of the image's dimensions.
|
109
119
|
def [](x, y)
|
110
120
|
assert_xy!(x, y)
|
111
121
|
@pixels[y * width + x]
|
112
122
|
end
|
113
123
|
|
124
|
+
# Returns a single pixel from this canvas, without checking bounds.
|
125
|
+
# @param (see #[])
|
126
|
+
# @return [ChunkyPNG::Color] The current pixel at the provided coordinates.
|
127
|
+
def get_pixel(x, y)
|
128
|
+
@pixels[y * width + x]
|
129
|
+
end
|
130
|
+
|
114
131
|
# Returns an extracted row as vector of pixels
|
115
132
|
# @param [Integer] y The 0-based row index
|
116
133
|
# @return [Array<Integer>] The vector of pixels in the requested row
|
@@ -124,7 +141,7 @@ module ChunkyPNG
|
|
124
141
|
# @return [Array<Integer>] The vector of pixels in the requested column.
|
125
142
|
def column(x)
|
126
143
|
assert_x!(x)
|
127
|
-
(0...height).inject([]) { |pixels, y| pixels <<
|
144
|
+
(0...height).inject([]) { |pixels, y| pixels << get_pixel(x, y) }
|
128
145
|
end
|
129
146
|
|
130
147
|
# Replaces a row of pixels on this canvas.
|
@@ -141,7 +158,7 @@ module ChunkyPNG
|
|
141
158
|
def replace_column!(x, vector)
|
142
159
|
assert_x!(x) && assert_height!(vector.length)
|
143
160
|
for y in 0...height do
|
144
|
-
|
161
|
+
set_pixel(x, y, vector[y])
|
145
162
|
end
|
146
163
|
end
|
147
164
|
|
@@ -5,7 +5,7 @@ module ChunkyPNG
|
|
5
5
|
|
6
6
|
# Sets a point on the canvas by composing a pixel with its background color.
|
7
7
|
def point(x, y, color)
|
8
|
-
|
8
|
+
set_pixel(x, y, ChunkyPNG::Color.compose(color, get_pixel(x, y)))
|
9
9
|
end
|
10
10
|
|
11
11
|
# Draws an anti-aliased line using Xiaolin Wu's algorithm.
|
@@ -63,7 +63,7 @@ module ChunkyPNG
|
|
63
63
|
return self
|
64
64
|
end
|
65
65
|
|
66
|
-
|
66
|
+
alias_method :line, :line_xiaolin_wu
|
67
67
|
|
68
68
|
def rect(x0, y0, x1, y1, line_color, fill_color = ChunkyPNG::COLOR::TRANSPARENT)
|
69
69
|
|
@@ -29,7 +29,7 @@ module ChunkyPNG
|
|
29
29
|
|
30
30
|
for y in 0...other.height do
|
31
31
|
for x in 0...other.width do
|
32
|
-
|
32
|
+
set_pixel(x + offset_x, y + offset_y, ChunkyPNG::Color.compose(other.get_pixel(x, y), get_pixel(x + offset_x, y + offset_y)))
|
33
33
|
end
|
34
34
|
end
|
35
35
|
self
|
@@ -14,12 +14,12 @@ module ChunkyPNG
|
|
14
14
|
# * Based on the color mode, width and height of the original image, which
|
15
15
|
# is read from the PNG header (IHDR chunk), the amount of bytes
|
16
16
|
# per line is determined.
|
17
|
-
# * For every line of pixels in the
|
18
|
-
#
|
17
|
+
# * For every line of pixels in the encoded image, the original byte values
|
18
|
+
# are restored by unapplying the milter method for that line.
|
19
19
|
# * The read bytes are unfiltered given by the filter function specified by
|
20
20
|
# the first byte of the line.
|
21
|
-
# * The unfiltered
|
22
|
-
# * All lines combined form the original image.
|
21
|
+
# * The unfiltered pixelstream are is into colored pixels, using the color mode.
|
22
|
+
# * All lines combined to form the original image.
|
23
23
|
#
|
24
24
|
# For interlaced images, the original image was split into 7 subimages.
|
25
25
|
# These images get decoded just like the process above (from step 3), and get
|
@@ -41,7 +41,7 @@ module ChunkyPNG
|
|
41
41
|
from_datastream(ChunkyPNG::Datastream.from_blob(str))
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
alias_method :from_string, :from_blob
|
45
45
|
|
46
46
|
# Decodes a Canvas from a PNG encoded file.
|
47
47
|
# @param [String] filename The file to read from.
|
@@ -57,6 +57,8 @@ module ChunkyPNG
|
|
57
57
|
from_datastream(ChunkyPNG::Datastream.from_io(io))
|
58
58
|
end
|
59
59
|
|
60
|
+
alias_method :from_stream, :from_io
|
61
|
+
|
60
62
|
# Decodes the Canvas from a PNG datastream instance.
|
61
63
|
# @param [ChunkyPNG::Datastream] ds The datastream to decode.
|
62
64
|
# @return [ChunkyPNG::Canvas] The canvas decoded from the PNG datastream.
|
@@ -86,8 +88,8 @@ module ChunkyPNG
|
|
86
88
|
raise ChunkyPNG::ExpectationFailed, "This palette is not suitable for decoding!" if decoding_palette && !decoding_palette.can_decode?
|
87
89
|
|
88
90
|
return case interlace
|
89
|
-
when ChunkyPNG::INTERLACING_NONE
|
90
|
-
when ChunkyPNG::INTERLACING_ADAM7
|
91
|
+
when ChunkyPNG::INTERLACING_NONE; decode_png_without_interlacing(stream, width, height, color_mode)
|
92
|
+
when ChunkyPNG::INTERLACING_ADAM7; decode_png_with_adam7_interlacing(stream, width, height, color_mode)
|
91
93
|
else raise ChunkyPNG::NotSupported, "Don't know how the handle interlacing method #{interlace}!"
|
92
94
|
end
|
93
95
|
end
|
@@ -138,14 +140,14 @@ module ChunkyPNG
|
|
138
140
|
# @param [Integer] start_pos The position in the pixel stream to start reading.
|
139
141
|
# @return (see ChunkyPNG::Canvas::PNGDecoding#decode_png_pixelstream)
|
140
142
|
def decode_png_image_pass(stream, width, height, color_mode, start_pos = 0)
|
141
|
-
|
143
|
+
stream << ChunkyPNG::EXTRA_BYTE if color_mode == ChunkyPNG::COLOR_TRUECOLOR
|
142
144
|
pixel_size = Color.bytesize(color_mode)
|
143
145
|
pixel_decoder = case color_mode
|
144
|
-
when ChunkyPNG::COLOR_TRUECOLOR
|
145
|
-
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA
|
146
|
-
when ChunkyPNG::COLOR_INDEXED
|
147
|
-
when ChunkyPNG::COLOR_GRAYSCALE
|
148
|
-
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA
|
146
|
+
when ChunkyPNG::COLOR_TRUECOLOR; lambda { |s, pos| s.unpack("@#{pos + 1}" << ('NX' * width)).map { |c| c | 0x000000ff } }
|
147
|
+
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA; lambda { |s, pos| s.unpack("@#{pos + 1}N#{width}") }
|
148
|
+
when ChunkyPNG::COLOR_INDEXED; lambda { |s, pos| (1..width).map { |i| decoding_palette[s.getbyte(pos + i)] } }
|
149
|
+
when ChunkyPNG::COLOR_GRAYSCALE; lambda { |s, pos| (1..width).map { |i| ChunkyPNG::Color.grayscale(s.getbyte(pos + i)) } }
|
150
|
+
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA; lambda { |s, pos| (0...width).map { |i| ChunkyPNG::Color.grayscale_alpha(s.getbyte(pos + (i * 2) + 1), s.getbyte(pos + (i * 2) + 2)) } }
|
149
151
|
else raise ChunkyPNG::NotSupported, "No suitable pixel decoder found for color mode #{color_mode}!"
|
150
152
|
end
|
151
153
|
|
@@ -155,114 +157,103 @@ module ChunkyPNG
|
|
155
157
|
raise ChunkyPNG::ExpectationFailed, "Invalid stream length!" unless stream.length - start_pos >= width * height * pixel_size + height
|
156
158
|
|
157
159
|
decoded_bytes = Array.new(width * pixel_size, 0)
|
158
|
-
|
160
|
+
line_length = width * pixel_size
|
161
|
+
pos, prev_pos = start_pos, nil
|
159
162
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
bytes = stream.unpack("@#{position}CC#{line_length}")
|
164
|
-
filter = bytes.shift
|
165
|
-
decoded_bytes = decode_png_scanline(filter, bytes, decoded_bytes, pixel_size)
|
163
|
+
for line_no in 0...height do
|
164
|
+
decode_png_str_scanline(stream, pos, prev_pos, line_length, pixel_size)
|
165
|
+
pixels += pixel_decoder.call(stream, pos)
|
166
166
|
|
167
|
-
|
168
|
-
|
167
|
+
prev_pos = pos
|
168
|
+
pos += line_length + 1
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
172
172
|
new(width, height, pixels)
|
173
173
|
end
|
174
174
|
|
175
|
-
# Decodes
|
176
|
-
# to return the original bytes of the image.
|
175
|
+
# Decodes a scanline if it was encoded using filtering.
|
177
176
|
#
|
178
|
-
#
|
179
|
-
#
|
177
|
+
# It will extract the filtering method from the first byte of the scanline, and uses the
|
178
|
+
# method to change the subsequent bytes to unfiltered values. This will modify the pixelstream.
|
180
179
|
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
# @param [
|
184
|
-
#
|
185
|
-
# @param [Integer]
|
186
|
-
#
|
187
|
-
# @
|
188
|
-
#
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
180
|
+
# The bytes of the scanline can then be used to construct pixels, based on the color mode..
|
181
|
+
#
|
182
|
+
# @param [String] stream The pixelstream to undo the filtering in.
|
183
|
+
# @param [Integer] pos The starting position of the scanline to decode.
|
184
|
+
# @param [Integer, nil] prev_pos The starting position of the previously decoded scanline, or <tt>nil</tt>
|
185
|
+
# if this is the first scanline of the image.
|
186
|
+
# @param [Integer] line_length The number of bytes in the scanline, discounting the filter method byte.
|
187
|
+
# @param [Integer] pixel_size The number of bytes used per pixel, based on the color mode.
|
188
|
+
# @return [nil]
|
189
|
+
def decode_png_str_scanline(stream, pos, prev_pos, line_length, pixel_size)
|
190
|
+
case stream.getbyte(pos)
|
191
|
+
when ChunkyPNG::FILTER_NONE; # noop
|
192
|
+
when ChunkyPNG::FILTER_SUB; decode_png_str_scanline_sub( stream, pos, prev_pos, line_length, pixel_size)
|
193
|
+
when ChunkyPNG::FILTER_UP; decode_png_str_scanline_up( stream, pos, prev_pos, line_length, pixel_size)
|
194
|
+
when ChunkyPNG::FILTER_AVERAGE; decode_png_str_scanline_average( stream, pos, prev_pos, line_length, pixel_size)
|
195
|
+
when ChunkyPNG::FILTER_PAETH; decode_png_str_scanline_paeth( stream, pos, prev_pos, line_length, pixel_size)
|
196
|
+
else raise ChunkyPNG::NotSupported, "Unknown filter type: #{stream.getbyte(pos)}!"
|
197
197
|
end
|
198
198
|
end
|
199
199
|
|
200
|
-
#
|
201
|
-
# @
|
202
|
-
# @
|
203
|
-
|
204
|
-
|
205
|
-
# @see ChunkyPNG::Canvas::PNGDecoding#decode_png_scanline
|
206
|
-
def decode_png_scanline_none(bytes, previous_bytes, pixelsize = 3)
|
207
|
-
bytes
|
200
|
+
# Decodes a scanline that wasn't encoded using filtering. This is a no-op.
|
201
|
+
# @params (see #decode_png_str_scanline)
|
202
|
+
# @return [nil]
|
203
|
+
def decode_png_str_scanline_sub_none(stream, pos, prev_pos, line_length, pixel_size)
|
204
|
+
# noop - this method shouldn't get called.
|
208
205
|
end
|
209
206
|
|
210
|
-
#
|
211
|
-
#
|
212
|
-
# @
|
213
|
-
# @
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
bytes
|
207
|
+
# Decodes a scanline in a pxielstream that was encoded using SUB filtering.
|
208
|
+
# This will chnage the pixelstream to have unfiltered values.
|
209
|
+
# @params (see #decode_png_str_scanline)
|
210
|
+
# @return [nil]
|
211
|
+
def decode_png_str_scanline_sub(stream, pos, prev_pos, line_length, pixel_size)
|
212
|
+
for i in 1..line_length do
|
213
|
+
stream.setbyte(pos + i, (stream.getbyte(pos + i) + (i > pixel_size ? stream.getbyte(pos + i - pixel_size) : 0)) & 0xff)
|
214
|
+
end
|
219
215
|
end
|
220
216
|
|
221
|
-
#
|
222
|
-
#
|
223
|
-
# @
|
224
|
-
# @
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
217
|
+
# Decodes a scanline in a pxielstream that was encoded using UP filtering.
|
218
|
+
# This will chnage the pixelstream to have unfiltered values.
|
219
|
+
# @params (see #decode_png_str_scanline)
|
220
|
+
# @return [nil]
|
221
|
+
def decode_png_str_scanline_up(stream, pos, prev_pos, line_length, pixel_size)
|
222
|
+
for i in 1..line_length do
|
223
|
+
up = prev_pos ? stream.getbyte(prev_pos + i) : 0
|
224
|
+
stream.setbyte(pos + i, (stream.getbyte(pos + i) + up) & 0xff)
|
225
|
+
end
|
230
226
|
end
|
231
227
|
|
232
|
-
#
|
233
|
-
#
|
234
|
-
# @
|
235
|
-
# @
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
b = previous_bytes[i]
|
242
|
-
bytes[i] = (byte + ((a + b) >> 1)) % 256
|
228
|
+
# Decodes a scanline in a pxielstream that was encoded using AVERAGE filtering.
|
229
|
+
# This will chnage the pixelstream to have unfiltered values.
|
230
|
+
# @params (see #decode_png_str_scanline)
|
231
|
+
# @return [nil]
|
232
|
+
def decode_png_str_scanline_average(stream, pos, prev_pos, line_length, pixel_size)
|
233
|
+
for i in 1..line_length do
|
234
|
+
a = (i > pixel_size) ? stream.getbyte(pos + i - pixel_size) : 0
|
235
|
+
b = prev_pos ? stream.getbyte(prev_pos + i) : 0
|
236
|
+
stream.setbyte(pos + i, (stream.getbyte(pos + i) + ((a + b) >> 1)) & 0xff)
|
243
237
|
end
|
244
|
-
bytes
|
245
238
|
end
|
246
239
|
|
247
|
-
#
|
248
|
-
#
|
249
|
-
# @
|
250
|
-
# @
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
c = (i >= pixelsize) ? previous_bytes[i - pixelsize] : 0
|
240
|
+
# Decodes a scanline in a pxielstream that was encoded using PAETH filtering.
|
241
|
+
# This will chnage the pixelstream to have unfiltered values.
|
242
|
+
# @params (see #decode_png_str_scanline)
|
243
|
+
# @return [nil]
|
244
|
+
def decode_png_str_scanline_paeth(stream, pos, prev_pos, line_length, pixel_size)
|
245
|
+
for i in 1..line_length do
|
246
|
+
cur_pos = pos + i
|
247
|
+
a = (i > pixel_size) ? stream.getbyte(cur_pos - pixel_size) : 0
|
248
|
+
b = prev_pos ? stream.getbyte(prev_pos + i) : 0
|
249
|
+
c = (prev_pos && i > pixel_size) ? stream.getbyte(prev_pos + i - pixel_size) : 0
|
258
250
|
p = a + b - c
|
259
251
|
pa = (p - a).abs
|
260
252
|
pb = (p - b).abs
|
261
253
|
pc = (p - c).abs
|
262
|
-
pr = (pa <= pb
|
263
|
-
|
254
|
+
pr = (pa <= pb) ? (pa <= pc ? a : c) : (pb <= pc ? b : c)
|
255
|
+
stream.setbyte(cur_pos, (stream.getbyte(cur_pos) + pr) & 0xff)
|
264
256
|
end
|
265
|
-
bytes
|
266
257
|
end
|
267
258
|
end
|
268
259
|
end
|