Compare commits

...

13 Commits

Author SHA1 Message Date
Stephen Sykes
6266b26b87 Add test for meta after mdat for heic 2023-09-28 17:28:33 +03:00
Stephen Sykes
02d70df8c1
Merge pull request #145 from ClearlyClaire/fixes/HEIC-meta-after-mdat
Handle large-size ISO_BMFF boxes and meta-after-mdat
2023-09-28 17:25:31 +03:00
Stephen Sykes
1fcc6c89ea
Merge pull request #144 from c960657/animated-gif
Add animated? support for png images
2023-09-28 16:47:31 +03:00
Stephen Sykes
71469cb64f Fix missing stringio require 2023-09-28 16:19:19 +03:00
Stephen Sykes
edf9558114 Update test paths for working ones 2023-09-28 16:18:59 +03:00
Stephen Sykes
c69d230098 Fix workflow for older rubies 2023-09-28 15:21:10 +03:00
Stephen Sykes
d515546a1d
Merge pull request #142 from dokioco/large-svg-header
Handle SVG files that have extra cruft at the start
2023-09-28 15:13:00 +03:00
Stephen Sykes
23989af8f9
Merge pull request #146 from nishidayuya/fix_cve_2012_2027_test_data
Fix CVE-2012-2027 vulnerability on test data
2023-09-28 15:04:21 +03:00
Yuya.Nishida
2d546f4520 run: git cococo docker run -it --rm -v ./test/fixtures:/data alpine:3.18.3 sh -eux -c 'apk add --no-cache imagemagick && convert /data/test2.tiff /tmp/fixed-test2.tiff && mv /tmp/fixed-test2.tiff /data/test2.tiff' 2023-08-10 11:58:42 +09:00
Claire
7c49d67439 Handle large-size ISO_BMFF boxes and meta-after-mdat
Fixes #140
2023-08-07 14:12:59 +02:00
Christian Schmidt
fb319cda6e unpack1 is not supported on Ruby < 2.4 2023-08-06 21:55:00 +02:00
Christian Schmidt
3fdd1767f5 Add parse_animated_for_png 2023-08-03 23:36:50 +02:00
Alan Harper
7056a4b6c9 Handle SVG files that have extra cruft at the start 2023-05-29 12:31:35 +10:00
7 changed files with 103 additions and 33 deletions

View File

@ -9,9 +9,6 @@ jobs:
fail-fast: false
matrix:
ruby:
- '2.0'
- '2.1'
- '2.2'
- '2.3'
- '2.4'
- '2.5'
@ -27,3 +24,20 @@ jobs:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- run: bundle exec rake
test_old_ruby:
name: Test (Ruby ${{ matrix.ruby }})
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
ruby:
- '2.0'
- '2.1'
- '2.2'
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- run: bundle exec rake

View File

@ -35,17 +35,17 @@
# === Examples
# require 'fastimage'
#
# FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
# => [266, 56]
# FastImage.type("http://stephensykes.com/images/pngimage")
# FastImage.size("https://switchstep.com/images/ios.gif")
# => [196, 283]
# FastImage.type("http://switchstep.com/images/ss_logo.png")
# => :png
# FastImage.type("/some/local/file.gif")
# => :gif
# File.open("/some/local/file.gif", "r") {|io| FastImage.type(io)}
# => :gif
# FastImage.new("http://stephensykes.com/images/pngimage").content_length
# => 432
# FastImage.new("http://stephensykes.com/images/ExifOrientation3.jpg").orientation
# FastImage.new("http://switchstep.com/images/ss_logo.png").content_length
# => 4679
# FastImage.new("http://switchstep.com/images/ExifOrientation3.jpg").orientation
# => 3
#
# === References
@ -61,6 +61,7 @@ require 'pathname'
require 'zlib'
require 'base64'
require 'uri'
require 'stringio'
require_relative 'fastimage/version'
# see http://stackoverflow.com/questions/5208851/i/41048816#41048816
@ -109,27 +110,27 @@ class FastImage
#
# require 'fastimage'
#
# FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
# => [266, 56]
# FastImage.size("http://stephensykes.com/images/pngimage")
# => [16, 16]
# FastImage.size("http://farm4.static.flickr.com/3023/3047236863_9dce98b836.jpg")
# => [500, 375]
# FastImage.size("http://www-ece.rice.edu/~wakin/images/lena512.bmp")
# FastImage.size("https://switchstep.com/images/ios.gif")
# => [196, 283]
# FastImage.size("http://switchstep.com/images/ss_logo.png")
# => [300, 300]
# FastImage.size("https://upload.wikimedia.org/wikipedia/commons/0/09/Jpeg_thumb_artifacts_test.jpg")
# => [1280, 800]
# FastImage.size("https://eeweb.engineering.nyu.edu/~yao/EL5123/image/lena_gray.bmp")
# => [512, 512]
# FastImage.size("test/fixtures/test.jpg")
# => [882, 470]
# FastImage.size("http://pennysmalls.com/does_not_exist")
# FastImage.size("http://switchstep.com/does_not_exist")
# => nil
# FastImage.size("http://pennysmalls.com/does_not_exist", :raise_on_failure=>true)
# FastImage.size("http://switchstep.com/does_not_exist", :raise_on_failure=>true)
# => raises FastImage::ImageFetchFailure
# FastImage.size("http://stephensykes.com/favicon.ico", :raise_on_failure=>true)
# FastImage.size("http://switchstep.com/images/favicon.ico", :raise_on_failure=>true)
# => [16, 16]
# FastImage.size("http://stephensykes.com/images/squareBlue.icns", :raise_on_failure=>true)
# FastImage.size("http://switchstep.com/foo.ics", :raise_on_failure=>true)
# => raises FastImage::UnknownImageType
# FastImage.size("http://stephensykes.com/favicon.ico", :raise_on_failure=>true, :timeout=>0.01)
# FastImage.size("http://switchstep.com/images/favicon.ico", :raise_on_failure=>true, :timeout=>0.01)
# => raises FastImage::ImageFetchFailure
# FastImage.size("http://stephensykes.com/images/faulty.jpg", :raise_on_failure=>true)
# FastImage.size("http://switchstep.com/images/faulty.jpg", :raise_on_failure=>true)
# => raises FastImage::SizeNotFound
#
# === Supported options
@ -155,17 +156,17 @@ class FastImage
#
# require 'fastimage'
#
# FastImage.type("http://stephensykes.com/images/ss.com_x.gif")
# FastImage.type("https://switchstep.com/images/ios.gif")
# => :gif
# FastImage.type("http://stephensykes.com/images/pngimage")
# FastImage.type("http://switchstep.com/images/ss_logo.png")
# => :png
# FastImage.type("http://farm4.static.flickr.com/3023/3047236863_9dce98b836.jpg")
# FastImage.type("https://upload.wikimedia.org/wikipedia/commons/0/09/Jpeg_thumb_artifacts_test.jpg")
# => :jpeg
# FastImage.type("http://www-ece.rice.edu/~wakin/images/lena512.bmp")
# FastImage.type("https://eeweb.engineering.nyu.edu/~yao/EL5123/image/lena_gray.bmp")
# => :bmp
# FastImage.type("test/fixtures/test.jpg")
# => :jpeg
# FastImage.type("http://stephensykes.com/does_not_exist")
# FastImage.type("http://switchstep.com/does_not_exist")
# => nil
# File.open("/some/local/file.gif", "r") {|io| FastImage.type(io)}
# => :gif
@ -435,7 +436,7 @@ class FastImage
def parse_animated
@type = parse_type unless @type
%i(gif webp avif).include?(@type) ? send("parse_animated_for_#{@type}") : nil
%i(gif png webp avif).include?(@type) ? send("parse_animated_for_#{@type}") : nil
end
def fetch_using_base64(uri)
@ -569,9 +570,9 @@ class FastImage
when /\s\s|\s<|<[?!]/, 0xef.chr + 0xbb.chr
# Peek 10 more chars each time, and if end of file is reached just raise
# unknown. We assume the <svg tag cannot be within 10 chars of the end of
# the file, and is within the first 250 chars.
# the file, and is within the first 1000 chars.
begin
:svg if (1..25).detect {|n| @stream.peek(10 * n).include?("<svg")}
:svg if (1..100).detect {|n| @stream.peek(10 * n).include?("<svg")}
rescue FiberError
nil
end
@ -649,9 +650,9 @@ class FastImage
when "ispe"
handle_ispe_box(box_size, index)
when "mdat"
throw :finish
@stream.skip(box_size)
else
@stream.read(box_size)
@stream.skip(box_size)
end
index += 1
@ -729,6 +730,7 @@ class FastImage
def read_box_header!
size = read_uint32!
type = @stream.read(4)
size = read_uint64! - 8 if size == 1
[type, size - 8]
end
@ -743,6 +745,10 @@ class FastImage
def read_uint32!
@stream.read(4).unpack("N")[0]
end
def read_uint64!
@stream.read(8).unpack("Q>")[0]
end
end
def parse_size_for_avif
@ -1095,6 +1101,25 @@ class FastImage
gif.animated?
end
def parse_animated_for_png
# Signature (8) + IHDR chunk (4 + 4 + 13 + 4)
@stream.read(33)
loop do
length = @stream.read(4).unpack("L>")[0]
type = @stream.read(4)
case type
when "acTL"
return true
when "IDAT"
return false
end
@stream.skip(length + 4)
end
end
def parse_animated_for_webp
vp8 = @stream.read(16)[12..15]
_len = @stream.read(4).unpack("V")

BIN
test/fixtures/animated.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Binary file not shown.

26
test/fixtures/test7.svg vendored Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
<!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/">
<!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
<!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
<!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
<!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/">
<!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
<!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
]>
<svg version="1.1" id="Layer_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100"
style="enable-background:new 0 0 113.4 113.4;" xml:space="preserve">
<switch>
<g i:extraneous="self">
<g>
<g>
<circle cx="50" cy="50" r="20" fill="red" />
</g>
</g>
</g>
</switch>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -15,6 +15,7 @@ GoodFixtures = {
"test_v5header.bmp"=>[:bmp, [40, 27]],
"test.gif"=>[:gif, [17, 32]],
"animated.gif"=>[:gif, [400, 400]],
"animated.png"=>[:png, [100, 100]],
"animated_without_gct.gif"=>[:gif, [859, 478]],
"test.jpg"=>[:jpeg, [882, 470]],
"test.png"=>[:png, [30, 20]],
@ -41,6 +42,7 @@ GoodFixtures = {
"test3.svg" => [:svg, [255, 48]],
"test4.svg" => [:svg, [271, 271]],
"test5.svg" => [:svg, [255, 48]],
"test7.svg" => [:svg, [100, 100]],
"orient_6.jpg"=>[:jpeg, [1250,2500]],
"heic/test.heic"=>[:heic, [700,476]],
"heic/heic-empty.heic"=>[:heic, [3992,2992]],
@ -50,6 +52,7 @@ GoodFixtures = {
"heic/heic-single.heic"=>[:heif,[1440,960]],
"heic/heic-collection.heic"=>[:heif,[1440,960]],
"heic/inverted.heic"=>[:heic,[3024, 4032]],
"heic/test-meta-after-mdat.heic"=>[:heic,[4000, 3000]],
"test6.svg" => [:svg, [450, 450]],
"avif/hato.avif" => [:avif, [3082, 2048]],
"avif/fox.avif" => [:avif, [1204, 799]],
@ -122,9 +125,11 @@ class FastImageTest < Test::Unit::TestCase
end
def test_should_report_animated_correctly
assert_equal nil, FastImage.animated?(TestUrl + "test.png")
assert_equal nil, FastImage.animated?(TestUrl + "test.jpg")
assert_equal false, FastImage.animated?(TestUrl + "test.png")
assert_equal false, FastImage.animated?(TestUrl + "test.gif")
assert_equal true, FastImage.animated?(TestUrl + "animated.gif")
assert_equal true, FastImage.animated?(TestUrl + "animated.png")
assert_equal true, FastImage.animated?(TestUrl + "animated_without_gct.gif")
assert_equal false, FastImage.animated?(TestUrl + "webp_vp8x.webp")
assert_equal true, FastImage.animated?(TestUrl + "webp_animated.webp")