From bdb78ce76a524f9eb05a0375c1d91c7a8ec3734e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 3 Nov 2014 19:54:10 +0100 Subject: [PATCH] FEATURE: consider SVG as an image when authorized --- .../javascripts/discourse/lib/utilities.js | 4 +-- app/models/optimized_image.rb | 11 ++++++-- app/models/upload.rb | 25 ++++++++++++----- spec/fixtures/images/image.svg | 3 +++ spec/models/upload_spec.rb | 27 ++++++++++++++++++- 5 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 spec/fixtures/images/image.svg diff --git a/app/assets/javascripts/discourse/lib/utilities.js b/app/assets/javascripts/discourse/lib/utilities.js index 3ee9f2a9817..2835ac843e7 100644 --- a/app/assets/javascripts/discourse/lib/utilities.js +++ b/app/assets/javascripts/discourse/lib/utilities.js @@ -269,7 +269,7 @@ Discourse.Utilities = { @param {String} path The path **/ isAnImage: function(path) { - return (/\.(png|jpg|jpeg|gif|bmp|tif|tiff)$/i).test(path); + return (/\.(png|jpg|jpeg|gif|bmp|tif|tiff|svg|webp)$/i).test(path); }, /** @@ -279,7 +279,7 @@ Discourse.Utilities = { **/ allowsAttachments: function() { return Discourse.Utilities.authorizesAllExtensions() || - !(/((png|jpg|jpeg|gif|bmp|tif|tiff)(,\s)?)+$/i).test(Discourse.Utilities.authorizedExtensions()); + !(/((png|jpg|jpeg|gif|bmp|tif|tiff|svg|webp)(,\s)?)+$/i).test(Discourse.Utilities.authorizedExtensions()); }, displayErrorForUpload: function(data) { diff --git a/app/models/optimized_image.rb b/app/models/optimized_image.rb index 5f5ecb645d5..7c7c42f53c1 100644 --- a/app/models/optimized_image.rb +++ b/app/models/optimized_image.rb @@ -31,9 +31,16 @@ class OptimizedImage < ActiveRecord::Base extension = File.extname(original_path) temp_file = Tempfile.new(["discourse-thumbnail", extension]) temp_path = temp_file.path - original_path += "[0]" unless opts[:allow_animation] - if resize(original_path, temp_path, width, height) + if extension =~ /\.svg$/i + FileUtils.cp(original_path, temp_path) + resized = true + else + original_path << "[0]" unless opts[:allow_animation] + resized = resize(original_path, temp_path, width, height) + end + + if resized thumbnail = OptimizedImage.create!( upload_id: upload.id, sha1: Digest::SHA1.file(temp_path).hexdigest, diff --git a/app/models/upload.rb b/app/models/upload.rb index 8b6455769ac..d9a5437df45 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -75,13 +75,24 @@ class Upload < ActiveRecord::Base # deal with width & height for images if FileHelper.is_image?(filename) begin - # fix orientation first - Upload.fix_image_orientation(file.path) - # retrieve image info - image_info = FastImage.new(file, raise_on_failure: true) - # compute image aspect ratio - upload.width, upload.height = ImageSizer.resize(*image_info.size) - # make sure we're at the beginning of the file (FastImage moves the pointer) + if filename =~ /\.svg$/i + svg = Nokogiri::XML(file).at_css("svg") + width, height = svg["width"].to_i, svg["height"].to_i + if width == 0 || height == 0 + upload.errors.add(:base, I18n.t("upload.images.size_not_found")) + else + upload.width, upload.height = ImageSizer.resize(width, height) + end + else + # fix orientation first + Upload.fix_image_orientation(file.path) + # retrieve image info + image_info = FastImage.new(file, raise_on_failure: true) + # compute image aspect ratio + upload.width, upload.height = ImageSizer.resize(*image_info.size) + end + # make sure we're at the beginning of the file + # (FastImage and Nokogiri move the pointer) file.rewind rescue FastImage::ImageFetchFailure upload.errors.add(:base, I18n.t("upload.images.fetch_failure")) diff --git a/spec/fixtures/images/image.svg b/spec/fixtures/images/image.svg new file mode 100644 index 00000000000..b95c0f4a79e --- /dev/null +++ b/spec/fixtures/images/image.svg @@ -0,0 +1,3 @@ + + Discourse + diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb index d55b0df42a0..573d53191a0 100644 --- a/spec/models/upload_spec.rb +++ b/spec/models/upload_spec.rb @@ -15,11 +15,15 @@ describe Upload do let(:user_id) { 1 } let(:url) { "http://domain.com" } - let(:image) { file_from_fixtures("logo.png") } let(:image_filename) { "logo.png" } + let(:image) { file_from_fixtures(image_filename) } let(:image_filesize) { File.size(image) } let(:image_sha1) { Digest::SHA1.file(image).hexdigest } + let(:image_svg_filename) { "image.svg" } + let(:image_svg) { file_from_fixtures(image_svg_filename) } + let(:image_svg_filesize) { File.size(image_svg) } + let(:attachment_path) { __FILE__ } let(:attachment) { File.new(attachment_path) } let(:attachment_filename) { File.basename(attachment_path) } @@ -96,6 +100,27 @@ describe Upload do upload.url.should == url end + context "when svg is authorized" do + + before { SiteSetting.stubs(:authorized_extensions).returns("svg") } + + it "consider SVG as an image" do + store = {} + Discourse.expects(:store).returns(store) + store.expects(:store_upload).returns(url) + + upload = Upload.create_for(user_id, image_svg, image_svg_filename, image_svg_filesize) + + upload.user_id.should == user_id + upload.original_filename.should == image_svg_filename + upload.filesize.should == image_svg_filesize + upload.width.should == 100 + upload.height.should == 50 + upload.url.should == url + end + + end + end context ".get_from_url" do