sirv-image 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/sirv_client.rb +282 -0
- metadata +63 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: d6c538246d67f50f35c56a61bd2ef2d14e28630d44c3253589e48a5cca03d776
|
|
4
|
+
data.tar.gz: f1c701e3610a77fc660161454647a2c382b640fa7d75da2b6dfe923fea146b9e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7cfc5e4b1bee19c6b8e958d7731f13fb9adb76b83113d3ecc755069667deda87085a4ca5e2900d2d62de9cd911e185e6bbe0a593af5c349d7049051c6aefcb78
|
|
7
|
+
data.tar.gz: 847db3c1eafd0ee31b1aa3d59ff238aa0baa720581fcf234f621d533789a47ff9877a15a84faeceae51b17d2e4bfb1e713bd8a89db24889f428dd05b8a5aac8f
|
data/lib/sirv_client.rb
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi"
|
|
4
|
+
|
|
5
|
+
module Sirv
|
|
6
|
+
# SDK for building Sirv URLs and HTML tags for images, spins, videos, 3D models, and galleries.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# sirv = Sirv::SirvClient.new(domain: 'demo.sirv.com', defaults: { q: 80 })
|
|
10
|
+
# url = sirv.url('/image.jpg', w: 300, format: 'webp')
|
|
11
|
+
# html = sirv.image('/photo.jpg', alt: 'A photo')
|
|
12
|
+
#
|
|
13
|
+
class SirvClient
|
|
14
|
+
# Create a SirvClient instance.
|
|
15
|
+
#
|
|
16
|
+
# @param domain [String] Sirv domain (e.g. 'demo.sirv.com')
|
|
17
|
+
# @param defaults [Hash] Default query parameters merged into every URL
|
|
18
|
+
# @raise [ArgumentError] if domain is not provided
|
|
19
|
+
def initialize(domain:, defaults: {})
|
|
20
|
+
raise ArgumentError, "domain is required" if domain.nil? || domain.empty?
|
|
21
|
+
|
|
22
|
+
@domain = domain.gsub(%r{/+\z}, "")
|
|
23
|
+
@defaults = defaults
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Build a full Sirv URL.
|
|
27
|
+
#
|
|
28
|
+
# @param path [String] Asset path (e.g. '/image.jpg')
|
|
29
|
+
# @param params [Hash] Transformation parameters (nested hashes are flattened to dot-notation)
|
|
30
|
+
# @return [String]
|
|
31
|
+
def url(path, params = {})
|
|
32
|
+
normalized = path.start_with?("/") ? path : "/#{path}"
|
|
33
|
+
"https://#{@domain}#{normalized}#{build_query(params)}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Generate a srcset string for responsive images.
|
|
37
|
+
#
|
|
38
|
+
# Supports three modes:
|
|
39
|
+
# - Explicit widths: `widths: [320, 640, 960]`
|
|
40
|
+
# - Auto-range: `min_width: 200, max_width: 2000, tolerance: 0.15`
|
|
41
|
+
# - Device pixel ratios: `device_pixel_ratios: [1, 2, 3]` with variable quality
|
|
42
|
+
#
|
|
43
|
+
# @param path [String] Image path
|
|
44
|
+
# @param params [Hash] Transformation parameters
|
|
45
|
+
# @param widths [Array<Integer>, nil] Explicit list of widths
|
|
46
|
+
# @param min_width [Integer, nil] Minimum width for auto-generation
|
|
47
|
+
# @param max_width [Integer, nil] Maximum width for auto-generation
|
|
48
|
+
# @param tolerance [Float] Tolerance for auto-generating widths (0-1)
|
|
49
|
+
# @param device_pixel_ratios [Array<Numeric>, nil] DPR values (e.g. [1, 2, 3])
|
|
50
|
+
# @return [String]
|
|
51
|
+
def src_set(path, params = {}, widths: nil, min_width: nil, max_width: nil, tolerance: 0.15, device_pixel_ratios: nil)
|
|
52
|
+
if widths
|
|
53
|
+
return widths
|
|
54
|
+
.map { |w| "#{url(path, params.merge(w: w))} #{w}w" }
|
|
55
|
+
.join(", ")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if min_width && max_width
|
|
59
|
+
generated = generate_widths(min_width, max_width, tolerance)
|
|
60
|
+
return generated
|
|
61
|
+
.map { |w| "#{url(path, params.merge(w: w))} #{w}w" }
|
|
62
|
+
.join(", ")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if device_pixel_ratios
|
|
66
|
+
base_q = params[:q] || params["q"] || @defaults[:q] || @defaults["q"] || 80
|
|
67
|
+
return device_pixel_ratios
|
|
68
|
+
.map do |dpr|
|
|
69
|
+
q = dpr_quality(base_q, dpr)
|
|
70
|
+
dpr_params = params.merge(q: q)
|
|
71
|
+
dpr_params[:w] = params[:w] * dpr if params[:w]
|
|
72
|
+
dpr_params[:h] = params[:h] * dpr if params[:h]
|
|
73
|
+
"#{url(path, dpr_params)} #{dpr}x"
|
|
74
|
+
end
|
|
75
|
+
.join(", ")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
""
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Generate an <img> tag for a Sirv image.
|
|
82
|
+
#
|
|
83
|
+
# @param path [String] Image path
|
|
84
|
+
# @param transform [Hash, nil] Transformation parameters for the URL
|
|
85
|
+
# @param viewer [Hash, nil] Viewer options for data-options attribute
|
|
86
|
+
# @param alt [String, nil] Alt text
|
|
87
|
+
# @param class_name [String, nil] Additional CSS class(es)
|
|
88
|
+
# @return [String]
|
|
89
|
+
def image(path, transform: nil, viewer: nil, alt: nil, class_name: nil)
|
|
90
|
+
src = url(path, transform || {})
|
|
91
|
+
cls = class_name ? "Sirv #{class_name}" : "Sirv"
|
|
92
|
+
html = "<img class=\"#{cls}\" data-src=\"#{escape_attr(src)}\""
|
|
93
|
+
html += " alt=\"#{escape_attr(alt)}\"" unless alt.nil?
|
|
94
|
+
html += " data-options=\"#{escape_attr(serialize_viewer_options(viewer))}\"" if viewer
|
|
95
|
+
html += ">"
|
|
96
|
+
html
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Generate a <div> tag for a Sirv zoom viewer.
|
|
100
|
+
#
|
|
101
|
+
# @param path [String] Image path
|
|
102
|
+
# @param transform [Hash, nil] Transformation parameters
|
|
103
|
+
# @param viewer [Hash, nil] Viewer options
|
|
104
|
+
# @param class_name [String, nil] Additional CSS class(es)
|
|
105
|
+
# @return [String]
|
|
106
|
+
def zoom(path, transform: nil, viewer: nil, class_name: nil)
|
|
107
|
+
viewer_div(path, "zoom", transform: transform, viewer: viewer, class_name: class_name)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Generate a <div> tag for a Sirv spin viewer.
|
|
111
|
+
#
|
|
112
|
+
# @param path [String] Path to .spin file
|
|
113
|
+
# @param transform [Hash, nil] Transformation parameters
|
|
114
|
+
# @param viewer [Hash, nil] Viewer options
|
|
115
|
+
# @param class_name [String, nil] Additional CSS class(es)
|
|
116
|
+
# @return [String]
|
|
117
|
+
def spin(path, transform: nil, viewer: nil, class_name: nil)
|
|
118
|
+
viewer_div(path, nil, transform: transform, viewer: viewer, class_name: class_name)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Generate a <div> tag for a Sirv video.
|
|
122
|
+
#
|
|
123
|
+
# @param path [String] Video path
|
|
124
|
+
# @param transform [Hash, nil] Transformation parameters
|
|
125
|
+
# @param viewer [Hash, nil] Viewer options
|
|
126
|
+
# @param class_name [String, nil] Additional CSS class(es)
|
|
127
|
+
# @return [String]
|
|
128
|
+
def video(path, transform: nil, viewer: nil, class_name: nil)
|
|
129
|
+
viewer_div(path, nil, transform: transform, viewer: viewer, class_name: class_name)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Generate a <div> tag for a Sirv 3D model viewer.
|
|
133
|
+
#
|
|
134
|
+
# @param path [String] Path to .glb file
|
|
135
|
+
# @param transform [Hash, nil] Transformation parameters
|
|
136
|
+
# @param viewer [Hash, nil] Viewer options
|
|
137
|
+
# @param class_name [String, nil] Additional CSS class(es)
|
|
138
|
+
# @return [String]
|
|
139
|
+
def model(path, transform: nil, viewer: nil, class_name: nil)
|
|
140
|
+
viewer_div(path, nil, transform: transform, viewer: viewer, class_name: class_name)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Generate a gallery container with multiple assets.
|
|
144
|
+
#
|
|
145
|
+
# @param items [Array<Hash>] Gallery items, each with:
|
|
146
|
+
# - :src [String] Asset path
|
|
147
|
+
# - :type [String, nil] Asset type override (e.g. 'zoom', 'spin')
|
|
148
|
+
# - :transform [Hash, nil] Per-item transformation params
|
|
149
|
+
# - :viewer [Hash, nil] Per-item viewer options
|
|
150
|
+
# @param viewer [Hash, nil] Gallery-level viewer options
|
|
151
|
+
# @param class_name [String, nil] Additional CSS class(es) for the gallery container
|
|
152
|
+
# @return [String]
|
|
153
|
+
def gallery(items, viewer: nil, class_name: nil)
|
|
154
|
+
cls = class_name ? "Sirv #{class_name}" : "Sirv"
|
|
155
|
+
html = "<div class=\"#{cls}\""
|
|
156
|
+
html += " data-options=\"#{escape_attr(serialize_viewer_options(viewer))}\"" if viewer
|
|
157
|
+
html += ">"
|
|
158
|
+
|
|
159
|
+
items.each do |item|
|
|
160
|
+
src = url(item[:src], item[:transform] || {})
|
|
161
|
+
child = "<div data-src=\"#{escape_attr(src)}\""
|
|
162
|
+
child += " data-type=\"#{item[:type]}\"" if item[:type]
|
|
163
|
+
child += " data-options=\"#{escape_attr(serialize_viewer_options(item[:viewer]))}\"" if item[:viewer]
|
|
164
|
+
child += "></div>"
|
|
165
|
+
html += child
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
html += "</div>"
|
|
169
|
+
html
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Generate a <script> tag to load Sirv JS.
|
|
173
|
+
#
|
|
174
|
+
# @param modules [Array<String>, nil] Specific modules to load (e.g. ['spin', 'zoom'])
|
|
175
|
+
# @param async [Boolean] Whether to add async attribute (default: true)
|
|
176
|
+
# @return [String]
|
|
177
|
+
def script_tag(modules: nil, async: true)
|
|
178
|
+
filename = "sirv"
|
|
179
|
+
if modules && !modules.empty?
|
|
180
|
+
filename = "sirv.#{modules.join(".")}"
|
|
181
|
+
end
|
|
182
|
+
html = "<script src=\"https://scripts.sirv.com/sirvjs/v3/#{filename}.js\""
|
|
183
|
+
html += " async" if async
|
|
184
|
+
html += "></script>"
|
|
185
|
+
html
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
private
|
|
189
|
+
|
|
190
|
+
# Flatten a nested hash into dot-notation key-value pairs.
|
|
191
|
+
#
|
|
192
|
+
# @param obj [Hash]
|
|
193
|
+
# @param prefix [String]
|
|
194
|
+
# @return [Array<Array(String, String)>]
|
|
195
|
+
def flatten_params(obj, prefix = "")
|
|
196
|
+
entries = []
|
|
197
|
+
obj.each do |key, value|
|
|
198
|
+
full_key = prefix.empty? ? key.to_s : "#{prefix}.#{key}"
|
|
199
|
+
if value.is_a?(Hash)
|
|
200
|
+
entries.concat(flatten_params(value, full_key))
|
|
201
|
+
elsif !value.nil?
|
|
202
|
+
entries << [full_key, value.to_s]
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
entries
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Build a query string from merged defaults + params.
|
|
209
|
+
#
|
|
210
|
+
# @param params [Hash]
|
|
211
|
+
# @return [String]
|
|
212
|
+
def build_query(params = {})
|
|
213
|
+
merged = @defaults.merge(params)
|
|
214
|
+
entries = flatten_params(merged)
|
|
215
|
+
return "" if entries.empty?
|
|
216
|
+
|
|
217
|
+
"?" + entries.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }.join("&")
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Calculate quality for a given DPR.
|
|
221
|
+
#
|
|
222
|
+
# @param base_q [Numeric] Base quality at 1x
|
|
223
|
+
# @param dpr [Numeric] Device pixel ratio
|
|
224
|
+
# @return [Integer]
|
|
225
|
+
def dpr_quality(base_q, dpr)
|
|
226
|
+
return base_q if dpr <= 1
|
|
227
|
+
|
|
228
|
+
(base_q * (0.75**(dpr - 1))).round
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Generate widths between min and max using a tolerance step.
|
|
232
|
+
#
|
|
233
|
+
# @param min [Numeric]
|
|
234
|
+
# @param max [Numeric]
|
|
235
|
+
# @param tolerance [Float]
|
|
236
|
+
# @return [Array<Integer>]
|
|
237
|
+
def generate_widths(min, max, tolerance)
|
|
238
|
+
widths = []
|
|
239
|
+
current = min.to_f
|
|
240
|
+
while current < max
|
|
241
|
+
widths << current.round
|
|
242
|
+
current *= 1 + tolerance * 2
|
|
243
|
+
end
|
|
244
|
+
widths << max.round
|
|
245
|
+
widths
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Serialize viewer options to semicolon-separated format.
|
|
249
|
+
#
|
|
250
|
+
# @param opts [Hash]
|
|
251
|
+
# @return [String]
|
|
252
|
+
def serialize_viewer_options(opts)
|
|
253
|
+
opts.map { |k, v| "#{k}:#{v}" }.join(";")
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Escape HTML attribute values.
|
|
257
|
+
#
|
|
258
|
+
# @param str [String]
|
|
259
|
+
# @return [String]
|
|
260
|
+
def escape_attr(str)
|
|
261
|
+
str.gsub("&", "&").gsub('"', """).gsub("<", "<").gsub(">", ">")
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Internal helper to generate viewer div tags.
|
|
265
|
+
#
|
|
266
|
+
# @param path [String]
|
|
267
|
+
# @param type [String, nil] data-type value (e.g. 'zoom'), or nil to omit
|
|
268
|
+
# @param transform [Hash, nil]
|
|
269
|
+
# @param viewer [Hash, nil]
|
|
270
|
+
# @param class_name [String, nil]
|
|
271
|
+
# @return [String]
|
|
272
|
+
def viewer_div(path, type, transform: nil, viewer: nil, class_name: nil)
|
|
273
|
+
src = url(path, transform || {})
|
|
274
|
+
cls = class_name ? "Sirv #{class_name}" : "Sirv"
|
|
275
|
+
html = "<div class=\"#{cls}\" data-src=\"#{escape_attr(src)}\""
|
|
276
|
+
html += " data-type=\"#{type}\"" if type
|
|
277
|
+
html += " data-options=\"#{escape_attr(serialize_viewer_options(viewer))}\"" if viewer
|
|
278
|
+
html += "></div>"
|
|
279
|
+
html
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: sirv-image
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Sirv
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-25 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rspec
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.0'
|
|
27
|
+
description: Official Ruby SDK for the Sirv dynamic imaging API. This SDK provides
|
|
28
|
+
a simple way to request any modified image (dimensions, format, quality, sharpen,
|
|
29
|
+
crop, watermark etc.) using the 100+ image transformation options in Sirv's image
|
|
30
|
+
optimization service.
|
|
31
|
+
email:
|
|
32
|
+
- support@sirv.com
|
|
33
|
+
executables: []
|
|
34
|
+
extensions: []
|
|
35
|
+
extra_rdoc_files: []
|
|
36
|
+
files:
|
|
37
|
+
- lib/sirv_client.rb
|
|
38
|
+
homepage: https://sirv.github.io/sirv-image-ruby/
|
|
39
|
+
licenses:
|
|
40
|
+
- MIT
|
|
41
|
+
metadata:
|
|
42
|
+
source_code_uri: https://github.com/sirv/sirv-image-ruby
|
|
43
|
+
bug_tracker_uri: https://github.com/sirv/sirv-image-ruby/issues
|
|
44
|
+
post_install_message:
|
|
45
|
+
rdoc_options: []
|
|
46
|
+
require_paths:
|
|
47
|
+
- lib
|
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: 2.6.0
|
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '0'
|
|
58
|
+
requirements: []
|
|
59
|
+
rubygems_version: 3.0.3.1
|
|
60
|
+
signing_key:
|
|
61
|
+
specification_version: 4
|
|
62
|
+
summary: Sirv image transformation Ruby SDK
|
|
63
|
+
test_files: []
|