summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKoza <[email protected]>2023-04-12 17:33:59 +0200
committerKoza <[email protected]>2023-04-12 17:33:59 +0200
commit2d714298a462a1482bd8e12fbb2efb74d6acee5f (patch)
treec377925f9f0ea9106d3c7d808130863c11a6ce63
parente548f377932207130cec4ac257a3907385d547d5 (diff)
parent518e74f8769daf67fca461139d3c7229abdb6e60 (diff)
downloadcaxlsx-2d714298a462a1482bd8e12fbb2efb74d6acee5f.tar.gz
caxlsx-2d714298a462a1482bd8e12fbb2efb74d6acee5f.zip
Merge branch 'feature/remote_images_support'
-rw-r--r--CHANGELOG.md1
-rw-r--r--examples/image_example.md1
-rw-r--r--examples/images/image_example.pngbin53952 -> 53248 bytes
-rw-r--r--lib/axlsx/drawing/pic.rb41
-rw-r--r--lib/axlsx/package.rb2
-rw-r--r--lib/axlsx/util/mime_type_utils.rb9
-rw-r--r--test/drawing/tc_pic.rb17
-rw-r--r--test/util/tc_mime_type_utils.rb2
8 files changed, 67 insertions, 6 deletions
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)
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
--- a/examples/images/image_example.png
+++ b/examples/images/image_example.png
Binary files differ
diff --git a/lib/axlsx/drawing/pic.rb b/lib/axlsx/drawing/pic.rb
index fb4d01fe..e31876bf 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,13 @@ 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)
+ 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
@image_src = v
end
@@ -83,10 +94,17 @@ module Axlsx
# @see descr
def descr=(v) Axlsx::validate_string(v); @descr = v; end
+ # @see remote
+ def remote=(v) Axlsx::validate_boolean(v); @remote = v; end
+
+ def remote?
+ remote == 1 || remote.to_s == '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 +128,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 +196,7 @@ module Axlsx
picture_locking.to_xml_string(str)
str << '</xdr:cNvPicPr></xdr:nvPicPr>'
str << '<xdr:blipFill>'
- str << ('<a:blip xmlns:r ="' << XML_NS_R << '" r:embed="' << relationship.Id << '">')
+ str << relationship_xml_portion
if opacity
str << "<a:alphaModFix amt=\"#{opacity}\"/>"
end
@@ -186,6 +208,15 @@ module Axlsx
private
+ # Return correct xml relationship string portion
+ def relationship_xml_portion
+ if remote?
+ ('<a:blip xmlns:r ="' << XML_NS_R << '" r:link="' << relationship.Id << '">')
+ else
+ ('<a:blip xmlns:r ="' << XML_NS_R << '" r:embed="' << relationship.Id << '">')
+ end
+ end
+
# Changes the anchor to a one cell anchor.
def use_one_cell_anchor
return if @anchor.is_a?(OneCellAnchor)
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
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..34f24eb3 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)
+ 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))
@@ -76,6 +86,13 @@ 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