From 9bd3367b35bcc85f74c749cfbab05e9c430ab064 Mon Sep 17 00:00:00 2001 From: Sebastiano Date: Tue, 17 Jan 2023 12:14:09 +0100 Subject: feat: add support for remote images --- lib/axlsx/drawing/pic.rb | 33 ++++++++++++++++++++++++++++----- lib/axlsx/package.rb | 2 +- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/axlsx/drawing/pic.rb b/lib/axlsx/drawing/pic.rb index fb4d01fe..b6d085de 100644 --- a/lib/axlsx/drawing/pic.rb +++ b/lib/axlsx/drawing/pic.rb @@ -7,6 +7,7 @@ module Axlsx # Creates a new Pic(ture) object # @param [Anchor] anchor the anchor that holds this image + # @@option options [Boolean] :remote indicates if image_src is a remote URI # @option options [String] :name # @option options [String] :descr # @option options [String] :image_src @@ -18,6 +19,7 @@ module Axlsx @anchor = anchor @hyperlink = nil @anchor.drawing.worksheet.workbook.images << self + @remote = options[:remote] parse_options options start_at(*options[:start_at]) if options[:start_at] yield self if block_given? @@ -54,6 +56,10 @@ module Axlsx # @return [Integer] attr_reader :opacity + # Flag for remote picture (from URI) + # @return [Boolean] + attr_reader :remote + # sets or updates a hyperlink for this image. # @param [String] v The href value for the hyper link # @option options @see Hyperlink#initialize All options available to the Hyperlink class apply - however href will be overridden with the v parameter value. @@ -71,8 +77,10 @@ module Axlsx def image_src=(v) Axlsx::validate_string(v) - RestrictionValidator.validate 'Pic.image_src', ALLOWED_MIME_TYPES, MimeTypeUtils.get_mime_type(v) - raise ArgumentError, "File does not exist" unless File.exist?(v) + unless remote? + RestrictionValidator.validate 'Pic.image_src', ALLOWED_MIME_TYPES, MimeTypeUtils.get_mime_type(v) + raise ArgumentError, "File does not exist" unless File.exist?(v) + end @image_src = v end @@ -83,10 +91,17 @@ module Axlsx # @see descr def descr=(v) Axlsx::validate_string(v); @descr = v; end + # @see remote + def remote=(v) @remote = v; end + + def remote? + remote == true; + end + # The file name of image_src without any path information # @return [String] def file_name - File.basename(image_src) unless image_src.nil? + File.basename(image_src) unless remote? || image_src.nil? end # returns the extension of image_src without the preceeding '.' @@ -110,7 +125,11 @@ module Axlsx # The relationship object for this pic. # @return [Relationship] def relationship - Relationship.new(self, IMAGE_R, "../#{pn}") + if remote? + Relationship.new(self, IMAGE_R, "#{image_src}", target_mode: :External) + else + Relationship.new(self, IMAGE_R, "../#{pn}") + end end # providing access to the anchor's width attribute @@ -174,7 +193,11 @@ module Axlsx picture_locking.to_xml_string(str) str << '' str << '' - str << ('') + if remote? + str << ('') + else + str << ('') + end if opacity str << "" end diff --git a/lib/axlsx/package.rb b/lib/axlsx/package.rb index 2118d0ea..b61c3de1 100644 --- a/lib/axlsx/package.rb +++ b/lib/axlsx/package.rb @@ -247,7 +247,7 @@ module Axlsx end workbook.images.each do |image| - parts << { :entry => "xl/#{image.pn}", :path => image.image_src } + parts << { :entry => "xl/#{image.pn}", :path => image.image_src } unless image.remote? end if use_shared_strings -- cgit v1.2.3 From f91cf59d7a62643140378e601f0a11a4deb23465 Mon Sep 17 00:00:00 2001 From: Sebastiano Date: Tue, 17 Jan 2023 14:55:35 +0100 Subject: improve validation add test cases --- lib/axlsx/drawing/pic.rb | 7 +++++-- lib/axlsx/util/mime_type_utils.rb | 9 +++++++++ test/drawing/tc_pic.rb | 18 ++++++++++++++++++ test/util/tc_mime_type_utils.rb | 2 ++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/axlsx/drawing/pic.rb b/lib/axlsx/drawing/pic.rb index b6d085de..f2f72cea 100644 --- a/lib/axlsx/drawing/pic.rb +++ b/lib/axlsx/drawing/pic.rb @@ -77,7 +77,10 @@ module Axlsx def image_src=(v) Axlsx::validate_string(v) - unless remote? + if remote? + RegexValidator.validate('Pic.image_src', /\A#{URI::DEFAULT_PARSER.make_regexp}\z/, v) + RestrictionValidator.validate 'Pic.image_src', ALLOWED_MIME_TYPES, MimeTypeUtils.get_mime_type_from_uri(v) + else RestrictionValidator.validate 'Pic.image_src', ALLOWED_MIME_TYPES, MimeTypeUtils.get_mime_type(v) raise ArgumentError, "File does not exist" unless File.exist?(v) end @@ -194,7 +197,7 @@ module Axlsx str << '' str << '' if remote? - str << ('') + str << ('') else str << ('') end diff --git a/lib/axlsx/util/mime_type_utils.rb b/lib/axlsx/util/mime_type_utils.rb index 9ad56630..5a6ad38e 100644 --- a/lib/axlsx/util/mime_type_utils.rb +++ b/lib/axlsx/util/mime_type_utils.rb @@ -1,3 +1,5 @@ +require 'open-uri' + module Axlsx # This module defines some utils related with mime type detection module MimeTypeUtils @@ -7,5 +9,12 @@ module Axlsx def self.get_mime_type(v) Marcel::MimeType.for(Pathname.new(v)) end + + # Detect a file mime type from URI + # @param [String] v URI + # @return [String] File mime type + def self.get_mime_type_from_uri(v) + Marcel::MimeType.for(URI.open(v)) + end end end diff --git a/test/drawing/tc_pic.rb b/test/drawing/tc_pic.rb index 56042de5..aa4d6af7 100644 --- a/test/drawing/tc_pic.rb +++ b/test/drawing/tc_pic.rb @@ -8,7 +8,10 @@ class TestPic < Test::Unit::TestCase @test_img_png = File.dirname(__FILE__) + "/../fixtures/image1.png" @test_img_gif = File.dirname(__FILE__) + "/../fixtures/image1.gif" @test_img_fake = File.dirname(__FILE__) + "/../fixtures/image1_fake.jpg" + @test_img_remote_png = "https://via.placeholder.com/150.png" + @test_img_remote_fake = "invalid_URI" @image = ws.add_image :image_src => @test_img, :hyperlink => 'https://github.com/randym', :tooltip => "What's up doc?", :opacity => 5 + @image_remote = ws.add_image :image_src => @test_img_remote_png, remote: true, :hyperlink => 'https://github.com/randym', :tooltip => "What's up doc?", :opacity => 5 end def test_initialization @@ -17,6 +20,13 @@ class TestPic < Test::Unit::TestCase assert_equal(@image.image_src, @test_img) end + def test_remote_img_initialization + assert_equal(@p.workbook.images[1], @image_remote) + assert_equal(@image_remote.file_name, nil) + assert_equal(@image_remote.image_src, @test_img_remote_png) + end + + def test_anchor_swapping # swap from one cell to two cell when end_at is specified assert(@image.anchor.is_a?(Axlsx::OneCellAnchor)) @@ -76,6 +86,14 @@ class TestPic < Test::Unit::TestCase assert_equal(@image.image_src, @test_img_jpg) end + def test_remote_image_src + assert_raise(ArgumentError) { @image_remote.image_src = @test_img_fake } + assert_raise(ArgumentError) { @image_remote.image_src = @test_img_remote_fake } + assert_nothing_raised { @image_remote.image_src = @test_img_remote_png } + assert_equal(@image_remote.image_src, @test_img_remote_png) + end + + def test_descr assert_raise(ArgumentError) { @image.descr = 49 } assert_nothing_raised { @image.descr = "test" } diff --git a/test/util/tc_mime_type_utils.rb b/test/util/tc_mime_type_utils.rb index cfeec9d3..9d116931 100644 --- a/test/util/tc_mime_type_utils.rb +++ b/test/util/tc_mime_type_utils.rb @@ -2,6 +2,7 @@ require 'tc_helper.rb' class TestMimeTypeUtils < Test::Unit::TestCase def setup @test_img = File.dirname(__FILE__) + "/../fixtures/image1.jpeg" + @test_img_url = "https://via.placeholder.com/150.png" end def teardown @@ -9,5 +10,6 @@ class TestMimeTypeUtils < Test::Unit::TestCase def test_mime_type_utils assert_equal(Axlsx::MimeTypeUtils::get_mime_type(@test_img), 'image/jpeg') + assert_equal(Axlsx::MimeTypeUtils::get_mime_type_from_uri(@test_img_url), 'image/png') end end -- cgit v1.2.3 From 340366e53979f8f1566eca06cdf29e5e1ec6bc1e Mon Sep 17 00:00:00 2001 From: Sebastiano Date: Tue, 17 Jan 2023 15:00:06 +0100 Subject: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c7e81a8..da888bff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG - Change `BorderCreator#initialize` arguments handling - Fix `add_border` to work with singluar cell refs - [PR #196](https://github.com/caxlsx/caxlsx/pull/196) - Fix tab color reassignment + - Add support for remote image source in `Pic` using External Relationship (supported in Excel documents) - **October.21.22**: 3.3.0 - [PR #168](https://github.com/caxlsx/caxlsx/pull/168) - Merge in the gem [`axlsx_styler`](https://github.com/axlsx-styler-gem/axlsx_styler) -- cgit v1.2.3 From 664921094c275b1d5e69077b26394a676bb5e5d7 Mon Sep 17 00:00:00 2001 From: Sebastiano Date: Tue, 17 Jan 2023 15:01:38 +0100 Subject: clean code --- lib/axlsx/drawing/pic.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/axlsx/drawing/pic.rb b/lib/axlsx/drawing/pic.rb index f2f72cea..4e269721 100644 --- a/lib/axlsx/drawing/pic.rb +++ b/lib/axlsx/drawing/pic.rb @@ -7,7 +7,7 @@ module Axlsx # Creates a new Pic(ture) object # @param [Anchor] anchor the anchor that holds this image - # @@option options [Boolean] :remote indicates if image_src is a remote URI + # @option options [Boolean] :remote indicates if image_src is a remote URI # @option options [String] :name # @option options [String] :descr # @option options [String] :image_src -- cgit v1.2.3 From 892b06a1ab832133ac933e58d09acfc24ad24d22 Mon Sep 17 00:00:00 2001 From: Sebastiano Date: Tue, 17 Jan 2023 15:02:54 +0100 Subject: improve tests --- test/drawing/tc_pic.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/drawing/tc_pic.rb b/test/drawing/tc_pic.rb index aa4d6af7..d38d5e9a 100644 --- a/test/drawing/tc_pic.rb +++ b/test/drawing/tc_pic.rb @@ -24,6 +24,7 @@ class TestPic < Test::Unit::TestCase assert_equal(@p.workbook.images[1], @image_remote) assert_equal(@image_remote.file_name, nil) assert_equal(@image_remote.image_src, @test_img_remote_png) + assert_equal(@image_remote.remote?, true) end -- cgit v1.2.3 From c068cd0f3734b8fd34d99a129afa9ce180092d61 Mon Sep 17 00:00:00 2001 From: Sebastiano Date: Sun, 19 Feb 2023 13:43:18 +0100 Subject: refactored code on Pic class --- lib/axlsx/drawing/pic.rb | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/axlsx/drawing/pic.rb b/lib/axlsx/drawing/pic.rb index 4e269721..dda1763c 100644 --- a/lib/axlsx/drawing/pic.rb +++ b/lib/axlsx/drawing/pic.rb @@ -95,10 +95,14 @@ module Axlsx def descr=(v) Axlsx::validate_string(v); @descr = v; end # @see remote - def remote=(v) @remote = v; end + def remote=(v) Axlsx::validate_boolean(v); @remote = v; end def remote? - remote == true; + if remote == 1 || remote.to_s == 'true' + true + else + false + end end # The file name of image_src without any path information @@ -196,11 +200,7 @@ module Axlsx picture_locking.to_xml_string(str) str << '' str << '' - if remote? - str << ('') - else - str << ('') - end + str << relationship_xml_portion if opacity str << "" end @@ -212,6 +212,15 @@ module Axlsx private + # Return correct xml relationship string portion + def relationship_xml_portion + if remote? + ('') + else + ('') + end + end + # Changes the anchor to a one cell anchor. def use_one_cell_anchor return if @anchor.is_a?(OneCellAnchor) -- cgit v1.2.3 From 909419f43ed994b7fc4aa247453f1d309be3dab3 Mon Sep 17 00:00:00 2001 From: Koza Date: Wed, 12 Apr 2023 17:19:48 +0200 Subject: Add extrenal image to the examples --- examples/image_example.md | 1 + examples/images/image_example.png | Bin 53952 -> 53248 bytes 2 files changed, 1 insertion(+) diff --git a/examples/image_example.md b/examples/image_example.md index e434c1b3..f01cfa1b 100644 --- a/examples/image_example.md +++ b/examples/image_example.md @@ -15,6 +15,7 @@ image = File.expand_path('assets/image1.jpeg') wb.add_worksheet(name: 'Image') do |sheet| sheet.add_image(image_src: image, start_at: 'B2', width: 100, height: 100) sheet.add_image(image_src: image, start_at: 'E1', end_at: 'G3') + sheet.add_image(image_src: 'https://via.placeholder.com/150.png', remote: true, start_at: 'E4', end_at: 'G6') end p.serialize 'image_example.xlsx' diff --git a/examples/images/image_example.png b/examples/images/image_example.png index 6d29b7ce..846af4a8 100644 Binary files a/examples/images/image_example.png and b/examples/images/image_example.png differ -- cgit v1.2.3 From 518e74f8769daf67fca461139d3c7229abdb6e60 Mon Sep 17 00:00:00 2001 From: Koza Date: Wed, 12 Apr 2023 17:32:20 +0200 Subject: Rubocop fixes --- lib/axlsx/drawing/pic.rb | 6 +----- test/drawing/tc_pic.rb | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/axlsx/drawing/pic.rb b/lib/axlsx/drawing/pic.rb index dda1763c..e31876bf 100644 --- a/lib/axlsx/drawing/pic.rb +++ b/lib/axlsx/drawing/pic.rb @@ -98,11 +98,7 @@ module Axlsx def remote=(v) Axlsx::validate_boolean(v); @remote = v; end def remote? - if remote == 1 || remote.to_s == 'true' - true - else - false - end + remote == 1 || remote.to_s == 'true' end # The file name of image_src without any path information diff --git a/test/drawing/tc_pic.rb b/test/drawing/tc_pic.rb index d38d5e9a..34f24eb3 100644 --- a/test/drawing/tc_pic.rb +++ b/test/drawing/tc_pic.rb @@ -27,7 +27,6 @@ class TestPic < Test::Unit::TestCase assert_equal(@image_remote.remote?, true) end - def test_anchor_swapping # swap from one cell to two cell when end_at is specified assert(@image.anchor.is_a?(Axlsx::OneCellAnchor)) @@ -94,7 +93,6 @@ class TestPic < Test::Unit::TestCase assert_equal(@image_remote.image_src, @test_img_remote_png) end - def test_descr assert_raise(ArgumentError) { @image.descr = 49 } assert_nothing_raised { @image.descr = "test" } -- cgit v1.2.3