chunky_png 1.3.7 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +35 -0
- data/.standard.yml +16 -0
- data/.yardopts +1 -1
- data/CHANGELOG.rdoc +20 -4
- data/CONTRIBUTING.rdoc +17 -8
- data/Gemfile +12 -4
- data/LICENSE +1 -1
- data/README.md +15 -9
- data/Rakefile +5 -3
- data/benchmarks/decoding_benchmark.rb +17 -17
- data/benchmarks/encoding_benchmark.rb +22 -19
- data/benchmarks/filesize_benchmark.rb +6 -6
- data/bin/rake +29 -0
- data/bin/standardrb +29 -0
- data/chunky_png.gemspec +21 -13
- data/docs/.gitignore +3 -0
- data/docs/CNAME +1 -0
- data/docs/_config.yml +9 -0
- data/docs/_posts/2010-01-14-memory-efficiency-when-using-ruby.md +136 -0
- data/docs/_posts/2010-01-17-ode-to-array-pack-and-string-unpack.md +82 -0
- data/docs/_posts/2014-11-07-the-value-of-a-pure-ruby-library.md +61 -0
- data/docs/index.md +88 -0
- data/lib/chunky_png/canvas/adam7_interlacing.rb +16 -10
- data/lib/chunky_png/canvas/data_url_exporting.rb +3 -3
- data/lib/chunky_png/canvas/data_url_importing.rb +3 -3
- data/lib/chunky_png/canvas/drawing.rb +30 -43
- data/lib/chunky_png/canvas/masking.rb +14 -14
- data/lib/chunky_png/canvas/operations.rb +28 -24
- data/lib/chunky_png/canvas/png_decoding.rb +39 -33
- data/lib/chunky_png/canvas/png_encoding.rb +111 -103
- data/lib/chunky_png/canvas/resampling.rb +27 -32
- data/lib/chunky_png/canvas/stream_exporting.rb +8 -8
- data/lib/chunky_png/canvas/stream_importing.rb +8 -8
- data/lib/chunky_png/canvas.rb +31 -28
- data/lib/chunky_png/chunk.rb +170 -55
- data/lib/chunky_png/color.rb +218 -212
- data/lib/chunky_png/datastream.rb +29 -29
- data/lib/chunky_png/dimension.rb +18 -11
- data/lib/chunky_png/image.rb +11 -11
- data/lib/chunky_png/palette.rb +13 -14
- data/lib/chunky_png/point.rb +27 -26
- data/lib/chunky_png/rmagick.rb +10 -10
- data/lib/chunky_png/vector.rb +28 -29
- data/lib/chunky_png/version.rb +3 -1
- data/lib/chunky_png.rb +49 -43
- data/spec/chunky_png/canvas/adam7_interlacing_spec.rb +20 -21
- data/spec/chunky_png/canvas/data_url_exporting_spec.rb +8 -5
- data/spec/chunky_png/canvas/data_url_importing_spec.rb +5 -6
- data/spec/chunky_png/canvas/drawing_spec.rb +46 -38
- data/spec/chunky_png/canvas/masking_spec.rb +15 -16
- data/spec/chunky_png/canvas/operations_spec.rb +68 -67
- data/spec/chunky_png/canvas/png_decoding_spec.rb +37 -38
- data/spec/chunky_png/canvas/png_encoding_spec.rb +59 -50
- data/spec/chunky_png/canvas/resampling_spec.rb +19 -21
- data/spec/chunky_png/canvas/stream_exporting_spec.rb +47 -27
- data/spec/chunky_png/canvas/stream_importing_spec.rb +10 -11
- data/spec/chunky_png/canvas_spec.rb +63 -52
- data/spec/chunky_png/color_spec.rb +115 -114
- data/spec/chunky_png/datastream_spec.rb +110 -13
- data/spec/chunky_png/dimension_spec.rb +10 -10
- data/spec/chunky_png/image_spec.rb +11 -14
- data/spec/chunky_png/point_spec.rb +21 -23
- data/spec/chunky_png/rmagick_spec.rb +7 -8
- data/spec/chunky_png/vector_spec.rb +21 -17
- data/spec/chunky_png_spec.rb +2 -2
- data/spec/png_suite_spec.rb +35 -40
- data/spec/resources/itxt_chunk.png +0 -0
- data/spec/spec_helper.rb +15 -9
- data/tasks/benchmarks.rake +7 -8
- metadata +65 -25
- data/.travis.yml +0 -16
- data/lib/chunky_png/compatibility.rb +0 -15
@@ -1,13 +1,13 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
1
3
|
module ChunkyPNG
|
2
4
|
class Canvas
|
3
|
-
|
4
5
|
# The ChunkyPNG::Canvas::Masking module defines methods to perform masking
|
5
6
|
# and theming operations on a {ChunkyPNG::Canvas}. The module is included into the Canvas class so all
|
6
7
|
# these methods are available on every canvas.
|
7
8
|
#
|
8
9
|
# @see ChunkyPNG::Canvas
|
9
10
|
module Masking
|
10
|
-
|
11
11
|
# Creates a new image, based on the current image but with a new theme color.
|
12
12
|
#
|
13
13
|
# This method will replace one color in an image with another image. This is done by
|
@@ -21,8 +21,8 @@ module ChunkyPNG
|
|
21
21
|
# @param [Integer] old_theme_color The original theme color in this image.
|
22
22
|
# @param [Integer] new_theme_color The color to replace the old theme color with.
|
23
23
|
# @param [Integer] bg_color The background color on which the theme colored pixels are placed.
|
24
|
-
# @param [Integer] tolerance The tolerance level to use when extracting the mask image. Five is
|
25
|
-
# the default; increase this if the masked image does not extract all the required pixels,
|
24
|
+
# @param [Integer] tolerance The tolerance level to use when extracting the mask image. Five is
|
25
|
+
# the default; increase this if the masked image does not extract all the required pixels,
|
26
26
|
# decrease it if too many pixels get extracted.
|
27
27
|
# @return [ChunkyPNG::Canvas] Returns itself, but with the theme colored pixels changed.
|
28
28
|
# @see #change_theme_color!
|
@@ -30,9 +30,9 @@ module ChunkyPNG
|
|
30
30
|
def change_theme_color!(old_theme_color, new_theme_color, bg_color = ChunkyPNG::Color::WHITE, tolerance = 5)
|
31
31
|
base, mask = extract_mask(old_theme_color, bg_color, tolerance)
|
32
32
|
mask.change_mask_color!(new_theme_color)
|
33
|
-
|
33
|
+
replace!(base.compose!(mask))
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
# Creates a base image and a mask image from an original image that has a particular theme color.
|
37
37
|
# This can be used to easily change a theme color in an image.
|
38
38
|
#
|
@@ -40,16 +40,16 @@ module ChunkyPNG
|
|
40
40
|
# these in a mask image. All the other pixels will be stored in a base image. Both images will be
|
41
41
|
# of the exact same size as the original image. The original image will be left untouched.
|
42
42
|
#
|
43
|
-
# The color of the mask image can be changed with {#change_mask_color!}. This new mask image can
|
44
|
-
# then be composed upon the base image to create an image with a new theme color. A call to
|
43
|
+
# The color of the mask image can be changed with {#change_mask_color!}. This new mask image can
|
44
|
+
# then be composed upon the base image to create an image with a new theme color. A call to
|
45
45
|
# {#change_theme_color!} will perform this in one go.
|
46
46
|
#
|
47
47
|
# @param [Integer] mask_color The current theme color.
|
48
48
|
# @param [Integer] bg_color The background color on which the theme colored pixels are applied.
|
49
|
-
# @param [Integer] tolerance The tolerance level to use when extracting the mask image. Five is
|
50
|
-
# the default; increase this if the masked image does not extract all the required pixels,
|
49
|
+
# @param [Integer] tolerance The tolerance level to use when extracting the mask image. Five is
|
50
|
+
# the default; increase this if the masked image does not extract all the required pixels,
|
51
51
|
# decrease it if too many pixels get extracted.
|
52
|
-
# @return [Array<ChunkyPNG::Canvas, ChunkyPNG::Canvas>] An array with the base canvas and the mask
|
52
|
+
# @return [Array<ChunkyPNG::Canvas, ChunkyPNG::Canvas>] An array with the base canvas and the mask
|
53
53
|
# canvas as elements.
|
54
54
|
# @see #change_theme_color!
|
55
55
|
# @see #change_mask_color!
|
@@ -66,10 +66,10 @@ module ChunkyPNG
|
|
66
66
|
base_pixels << pixel
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
70
|
-
[
|
69
|
+
|
70
|
+
[self.class.new(width, height, base_pixels), self.class.new(width, height, mask_pixels)]
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
# Changes the color of a mask image.
|
74
74
|
#
|
75
75
|
# This method works on a canvas extracted out of another image using the {#extract_mask} method.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
1
3
|
module ChunkyPNG
|
2
4
|
class Canvas
|
3
5
|
# The ChunkyPNG::Canvas::Operations module defines methods to perform
|
@@ -15,8 +17,8 @@ module ChunkyPNG
|
|
15
17
|
# the current instance intact, use {#grayscale} instead.
|
16
18
|
#
|
17
19
|
# @return [ChunkyPNG::Canvas] Returns itself, converted to grayscale.
|
18
|
-
# @see
|
19
|
-
# @see
|
20
|
+
# @see #grayscale
|
21
|
+
# @see ChunkyPNG::Color#to_grayscale
|
20
22
|
def grayscale!
|
21
23
|
pixels.map! { |pixel| ChunkyPNG::Color.to_grayscale(pixel) }
|
22
24
|
self
|
@@ -29,8 +31,8 @@ module ChunkyPNG
|
|
29
31
|
#
|
30
32
|
# @return [ChunkyPNG::Canvas] A copy of the canvas, converted to
|
31
33
|
# grayscale.
|
32
|
-
# @see
|
33
|
-
# @see
|
34
|
+
# @see #grayscale!
|
35
|
+
# @see ChunkyPNG::Color#to_grayscale
|
34
36
|
def grayscale
|
35
37
|
dup.grayscale!
|
36
38
|
end
|
@@ -56,11 +58,14 @@ module ChunkyPNG
|
|
56
58
|
|
57
59
|
for y in 0...other.height do
|
58
60
|
for x in 0...other.width do
|
59
|
-
set_pixel(
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
set_pixel(
|
62
|
+
x + offset_x,
|
63
|
+
y + offset_y,
|
64
|
+
ChunkyPNG::Color.compose(
|
65
|
+
other.get_pixel(x, y),
|
66
|
+
get_pixel(x + offset_x, y + offset_y)
|
67
|
+
)
|
68
|
+
)
|
64
69
|
end
|
65
70
|
end
|
66
71
|
self
|
@@ -169,17 +174,16 @@ module ChunkyPNG
|
|
169
174
|
# coordinates are bigger then the original image.
|
170
175
|
def crop!(x, y, crop_width, crop_height)
|
171
176
|
if crop_width + x > width
|
172
|
-
raise ChunkyPNG::OutOfBounds,
|
177
|
+
raise ChunkyPNG::OutOfBounds, "Original image width is too small!"
|
173
178
|
end
|
174
179
|
if crop_height + y > height
|
175
|
-
raise ChunkyPNG::OutOfBounds,
|
180
|
+
raise ChunkyPNG::OutOfBounds, "Original image height is too small!"
|
176
181
|
end
|
177
182
|
|
178
183
|
if crop_width == width && x == 0
|
179
184
|
# We only need to crop off the top and/or bottom, so we can take a
|
180
185
|
# shortcut.
|
181
|
-
replace_canvas!(crop_width, crop_height,
|
182
|
-
pixels.slice(y * width, width * crop_height))
|
186
|
+
replace_canvas!(crop_width, crop_height, pixels.slice(y * width, width * crop_height))
|
183
187
|
else
|
184
188
|
new_pixels = []
|
185
189
|
for cy in 0...crop_height do
|
@@ -221,8 +225,8 @@ module ChunkyPNG
|
|
221
225
|
self
|
222
226
|
end
|
223
227
|
|
224
|
-
|
225
|
-
|
228
|
+
alias flip! flip_horizontally!
|
229
|
+
alias flip flip_horizontally
|
226
230
|
|
227
231
|
# Flips the image vertically, leaving the original intact.
|
228
232
|
#
|
@@ -253,8 +257,8 @@ module ChunkyPNG
|
|
253
257
|
self
|
254
258
|
end
|
255
259
|
|
256
|
-
|
257
|
-
|
260
|
+
alias mirror! flip_vertically!
|
261
|
+
alias mirror flip_vertically
|
258
262
|
|
259
263
|
# Returns a new canvas instance that is rotated 90 degrees clockwise.
|
260
264
|
#
|
@@ -278,8 +282,8 @@ module ChunkyPNG
|
|
278
282
|
replace_canvas!(height, width, new_pixels)
|
279
283
|
end
|
280
284
|
|
281
|
-
|
282
|
-
|
285
|
+
alias rotate_clockwise rotate_right
|
286
|
+
alias rotate_clockwise! rotate_right!
|
283
287
|
|
284
288
|
# Returns an image that is rotated 90 degrees counter-clockwise.
|
285
289
|
#
|
@@ -305,8 +309,8 @@ module ChunkyPNG
|
|
305
309
|
replace_canvas!(height, width, new_pixels)
|
306
310
|
end
|
307
311
|
|
308
|
-
|
309
|
-
|
312
|
+
alias rotate_counter_clockwise rotate_left
|
313
|
+
alias rotate_counter_clockwise! rotate_left!
|
310
314
|
|
311
315
|
# Rotates the image 180 degrees.
|
312
316
|
#
|
@@ -389,11 +393,11 @@ module ChunkyPNG
|
|
389
393
|
# applied.
|
390
394
|
# @raise [ChunkyPNG::OutOfBounds] when the other image doesn't fit.
|
391
395
|
def check_size_constraints!(other, offset_x, offset_y)
|
392
|
-
if width
|
393
|
-
raise ChunkyPNG::OutOfBounds,
|
396
|
+
if width < other.width + offset_x
|
397
|
+
raise ChunkyPNG::OutOfBounds, "Background image width is too small!"
|
394
398
|
end
|
395
399
|
if height < other.height + offset_y
|
396
|
-
raise ChunkyPNG::OutOfBounds,
|
400
|
+
raise ChunkyPNG::OutOfBounds, "Background image height is too small!"
|
397
401
|
end
|
398
402
|
end
|
399
403
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
1
3
|
module ChunkyPNG
|
2
4
|
class Canvas
|
3
|
-
|
4
5
|
# The PNGDecoding contains methods for decoding PNG datastreams to create a
|
5
6
|
# Canvas object. The datastream can be provided as filename, string or IO
|
6
7
|
# stream.
|
@@ -26,9 +27,8 @@ module ChunkyPNG
|
|
26
27
|
# combined to form the original images.
|
27
28
|
#
|
28
29
|
# @see ChunkyPNG::Canvas::PNGEncoding
|
29
|
-
# @see
|
30
|
+
# @see https://www.w3.org/TR/PNG/ The W3C PNG format specification
|
30
31
|
module PNGDecoding
|
31
|
-
|
32
32
|
# Decodes a Canvas from a PNG encoded string.
|
33
33
|
# @param [String] str The string to read from.
|
34
34
|
# @return [ChunkyPNG::Canvas] The canvas decoded from the PNG encoded string.
|
@@ -36,7 +36,7 @@ module ChunkyPNG
|
|
36
36
|
from_datastream(ChunkyPNG::Datastream.from_blob(str))
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
alias from_string from_blob
|
40
40
|
|
41
41
|
# Decodes a Canvas from a PNG encoded file.
|
42
42
|
# @param [String] filename The file to read from.
|
@@ -52,7 +52,7 @@ module ChunkyPNG
|
|
52
52
|
from_datastream(ChunkyPNG::Datastream.from_io(io))
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
alias from_stream from_io
|
56
56
|
|
57
57
|
# Decodes the Canvas from a PNG datastream instance.
|
58
58
|
# @param [ChunkyPNG::Datastream] ds The datastream to decode.
|
@@ -85,7 +85,7 @@ module ChunkyPNG
|
|
85
85
|
# color mode and interlacing mode.
|
86
86
|
# @param [String] stream The pixelstream to read from.
|
87
87
|
# @param [Integer] width The width of the image.
|
88
|
-
# @param [Integer]
|
88
|
+
# @param [Integer] height The height of the image.
|
89
89
|
# @param [Integer] color_mode The color mode of the encoded pixelstream.
|
90
90
|
# @param [Integer] depth The bit depth of the pixel samples.
|
91
91
|
# @param [Integer] interlace The interlace method of the encoded pixelstream.
|
@@ -96,13 +96,13 @@ module ChunkyPNG
|
|
96
96
|
raise ChunkyPNG::ExpectationFailed, "This palette is not suitable for decoding!" if decoding_palette && !decoding_palette.can_decode?
|
97
97
|
|
98
98
|
image = case interlace
|
99
|
-
when ChunkyPNG::INTERLACING_NONE
|
100
|
-
when ChunkyPNG::INTERLACING_ADAM7
|
99
|
+
when ChunkyPNG::INTERLACING_NONE then decode_png_without_interlacing(stream, width, height, color_mode, depth, decoding_palette)
|
100
|
+
when ChunkyPNG::INTERLACING_ADAM7 then decode_png_with_adam7_interlacing(stream, width, height, color_mode, depth, decoding_palette)
|
101
101
|
else raise ChunkyPNG::NotSupported, "Don't know how the handle interlacing method #{interlace}!"
|
102
102
|
end
|
103
103
|
|
104
104
|
image.pixels.map! { |c| c == transparent_color ? ChunkyPNG::Color::TRANSPARENT : c } if transparent_color
|
105
|
-
|
105
|
+
image
|
106
106
|
end
|
107
107
|
|
108
108
|
protected
|
@@ -147,7 +147,7 @@ module ChunkyPNG
|
|
147
147
|
# the value will be modded by 2 to enforce this.
|
148
148
|
# @return [Integer] The extracted 4bit value (0..15)
|
149
149
|
def decode_png_extract_4bit_value(byte, index)
|
150
|
-
|
150
|
+
index & 0x01 == 0 ? ((byte & 0xf0) >> 4) : (byte & 0x0f)
|
151
151
|
end
|
152
152
|
|
153
153
|
# Extract 2 consecutive bits from a byte.
|
@@ -205,7 +205,6 @@ module ChunkyPNG
|
|
205
205
|
value == 0x01 ? 0xff : 0x00
|
206
206
|
end
|
207
207
|
|
208
|
-
|
209
208
|
# Decodes a scanline of a 1-bit, indexed image into a row of pixels.
|
210
209
|
# @param [String] stream The stream to decode from.
|
211
210
|
# @param [Integer] pos The position in the stream on which the scanline starts (including the filter byte).
|
@@ -259,17 +258,21 @@ module ChunkyPNG
|
|
259
258
|
def decode_png_pixels_from_scanline_truecolor_alpha_16bit(stream, pos, width, _decoding_palette)
|
260
259
|
pixels = []
|
261
260
|
stream.unpack("@#{pos + 1}n#{width * 4}").each_slice(4) do |r, g, b, a|
|
262
|
-
pixels << ChunkyPNG::Color.rgba(
|
263
|
-
|
261
|
+
pixels << ChunkyPNG::Color.rgba(
|
262
|
+
decode_png_resample_16bit_value(r),
|
263
|
+
decode_png_resample_16bit_value(g),
|
264
|
+
decode_png_resample_16bit_value(b),
|
265
|
+
decode_png_resample_16bit_value(a),
|
266
|
+
)
|
264
267
|
end
|
265
|
-
|
268
|
+
pixels
|
266
269
|
end
|
267
270
|
|
268
271
|
# Decodes a scanline of an 8-bit, true color image into a row of pixels.
|
269
272
|
# @params (see #decode_png_pixels_from_scanline_indexed_1bit)
|
270
273
|
# @return (see #decode_png_pixels_from_scanline_indexed_1bit)
|
271
274
|
def decode_png_pixels_from_scanline_truecolor_8bit(stream, pos, width, _decoding_palette)
|
272
|
-
stream.unpack("@#{pos + 1}"
|
275
|
+
stream.unpack("@#{pos + 1}#{"NX" * width}").map { |c| c | 0x000000ff }
|
273
276
|
end
|
274
277
|
|
275
278
|
# Decodes a scanline of a 16-bit, true color image into a row of pixels.
|
@@ -280,7 +283,7 @@ module ChunkyPNG
|
|
280
283
|
stream.unpack("@#{pos + 1}n#{width * 3}").each_slice(3) do |r, g, b|
|
281
284
|
pixels << ChunkyPNG::Color.rgb(decode_png_resample_16bit_value(r), decode_png_resample_16bit_value(g), decode_png_resample_16bit_value(b))
|
282
285
|
end
|
283
|
-
|
286
|
+
pixels
|
284
287
|
end
|
285
288
|
|
286
289
|
# Decodes a scanline of an 8-bit, grayscale image with transparency into a row of pixels.
|
@@ -298,7 +301,7 @@ module ChunkyPNG
|
|
298
301
|
stream.unpack("@#{pos + 1}n#{width * 2}").each_slice(2) do |g, a|
|
299
302
|
pixels << ChunkyPNG::Color.grayscale_alpha(decode_png_resample_16bit_value(g), decode_png_resample_16bit_value(a))
|
300
303
|
end
|
301
|
-
|
304
|
+
pixels
|
302
305
|
end
|
303
306
|
|
304
307
|
# Decodes a scanline of a 1-bit, grayscale image into a row of pixels.
|
@@ -353,12 +356,11 @@ module ChunkyPNG
|
|
353
356
|
# @raise [ChunkyPNG::NotSupported] when the color_mode and/or bit depth is not supported.
|
354
357
|
def decode_png_pixels_from_scanline_method(color_mode, depth)
|
355
358
|
decoder_method = case color_mode
|
356
|
-
when ChunkyPNG::COLOR_TRUECOLOR
|
357
|
-
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA
|
358
|
-
when ChunkyPNG::COLOR_INDEXED
|
359
|
-
when ChunkyPNG::COLOR_GRAYSCALE
|
360
|
-
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA
|
361
|
-
else nil
|
359
|
+
when ChunkyPNG::COLOR_TRUECOLOR then :"decode_png_pixels_from_scanline_truecolor_#{depth}bit"
|
360
|
+
when ChunkyPNG::COLOR_TRUECOLOR_ALPHA then :"decode_png_pixels_from_scanline_truecolor_alpha_#{depth}bit"
|
361
|
+
when ChunkyPNG::COLOR_INDEXED then :"decode_png_pixels_from_scanline_indexed_#{depth}bit"
|
362
|
+
when ChunkyPNG::COLOR_GRAYSCALE then :"decode_png_pixels_from_scanline_grayscale_#{depth}bit"
|
363
|
+
when ChunkyPNG::COLOR_GRAYSCALE_ALPHA then :"decode_png_pixels_from_scanline_grayscale_alpha_#{depth}bit"
|
362
364
|
end
|
363
365
|
|
364
366
|
raise ChunkyPNG::NotSupported, "No decoder found for color mode #{color_mode} and #{depth}-bit depth!" unless respond_to?(decoder_method, true)
|
@@ -379,7 +381,6 @@ module ChunkyPNG
|
|
379
381
|
# @param [ChunkyPNG::Palette] decoding_palette The palette to use to decode colors.
|
380
382
|
# @return (see ChunkyPNG::Canvas::PNGDecoding#decode_png_pixelstream)
|
381
383
|
def decode_png_image_pass(stream, width, height, color_mode, depth, start_pos, decoding_palette)
|
382
|
-
|
383
384
|
pixels = []
|
384
385
|
if width > 0 && height > 0
|
385
386
|
|
@@ -419,11 +420,11 @@ module ChunkyPNG
|
|
419
420
|
# @return [void]
|
420
421
|
def decode_png_str_scanline(stream, pos, prev_pos, line_length, pixel_size)
|
421
422
|
case stream.getbyte(pos)
|
422
|
-
when ChunkyPNG::FILTER_NONE
|
423
|
-
when ChunkyPNG::FILTER_SUB
|
424
|
-
when ChunkyPNG::FILTER_UP
|
425
|
-
when ChunkyPNG::FILTER_AVERAGE
|
426
|
-
when ChunkyPNG::FILTER_PAETH
|
423
|
+
when ChunkyPNG::FILTER_NONE then # rubocop:disable Lint/EmptyWhen # no-op
|
424
|
+
when ChunkyPNG::FILTER_SUB then decode_png_str_scanline_sub(stream, pos, prev_pos, line_length, pixel_size)
|
425
|
+
when ChunkyPNG::FILTER_UP then decode_png_str_scanline_up(stream, pos, prev_pos, line_length, pixel_size)
|
426
|
+
when ChunkyPNG::FILTER_AVERAGE then decode_png_str_scanline_average(stream, pos, prev_pos, line_length, pixel_size)
|
427
|
+
when ChunkyPNG::FILTER_PAETH then decode_png_str_scanline_paeth(stream, pos, prev_pos, line_length, pixel_size)
|
427
428
|
else raise ChunkyPNG::NotSupported, "Unknown filter type: #{stream.getbyte(pos)}!"
|
428
429
|
end
|
429
430
|
end
|
@@ -462,7 +463,7 @@ module ChunkyPNG
|
|
462
463
|
# @return [void]
|
463
464
|
def decode_png_str_scanline_average(stream, pos, prev_pos, line_length, pixel_size)
|
464
465
|
for i in 1..line_length do
|
465
|
-
a =
|
466
|
+
a = i > pixel_size ? stream.getbyte(pos + i - pixel_size) : 0
|
466
467
|
b = prev_pos ? stream.getbyte(prev_pos + i) : 0
|
467
468
|
stream.setbyte(pos + i, (stream.getbyte(pos + i) + ((a + b) >> 1)) & 0xff)
|
468
469
|
end
|
@@ -475,14 +476,19 @@ module ChunkyPNG
|
|
475
476
|
def decode_png_str_scanline_paeth(stream, pos, prev_pos, line_length, pixel_size)
|
476
477
|
for i in 1..line_length do
|
477
478
|
cur_pos = pos + i
|
478
|
-
a =
|
479
|
+
a = i > pixel_size ? stream.getbyte(cur_pos - pixel_size) : 0
|
479
480
|
b = prev_pos ? stream.getbyte(prev_pos + i) : 0
|
480
|
-
c =
|
481
|
+
c = prev_pos && i > pixel_size ? stream.getbyte(prev_pos + i - pixel_size) : 0
|
481
482
|
p = a + b - c
|
482
483
|
pa = (p - a).abs
|
483
484
|
pb = (p - b).abs
|
484
485
|
pc = (p - c).abs
|
485
|
-
pr =
|
486
|
+
pr = if pa <= pb
|
487
|
+
pa <= pc ? a : c
|
488
|
+
else
|
489
|
+
pb <= pc ? b : c
|
490
|
+
end
|
491
|
+
|
486
492
|
stream.setbyte(cur_pos, (stream.getbyte(cur_pos) + pr) & 0xff)
|
487
493
|
end
|
488
494
|
end
|