htmlcsstoimage-api 0.1.4 → 0.3.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -1
  3. data/README.md +180 -10
  4. data/htmlcsstoimage.gemspec +4 -2
  5. data/lib/htmlcsstoimage/client.rb +36 -0
  6. data/lib/htmlcsstoimage/images.rb +173 -0
  7. data/lib/htmlcsstoimage/signed_urls.rb +130 -0
  8. data/lib/htmlcsstoimage/templates.rb +99 -0
  9. data/lib/htmlcsstoimage/version.rb +2 -1
  10. data/lib/htmlcsstoimage.rb +7 -151
  11. metadata +23 -29
  12. data/cassettes/HTMLCSSToImage/_create_image/accepts_additional_params.yml +0 -66
  13. data/cassettes/HTMLCSSToImage/_create_image/creates_an_image.yml +0 -64
  14. data/cassettes/HTMLCSSToImage/_create_template/creates_a_new_template.yml +0 -62
  15. data/cassettes/HTMLCSSToImage/_delete_image/deletes_an_image.yml +0 -60
  16. data/cassettes/HTMLCSSToImage/_templates/retrieves_templates.yml +0 -110
  17. data/cassettes/HTMLCSSToImage/_url_to_image/accepts_additional_params.yml +0 -64
  18. data/cassettes/HTMLCSSToImage/_url_to_image/creates_an_image_from_a_url.yml +0 -64
  19. data/docs/HTMLCSSToImage/ApiResponse.html +0 -124
  20. data/docs/HTMLCSSToImage.html +0 -1340
  21. data/docs/_config.yml +0 -1
  22. data/docs/_index.html +0 -122
  23. data/docs/class_list.html +0 -51
  24. data/docs/css/common.css +0 -1
  25. data/docs/css/full_list.css +0 -58
  26. data/docs/css/style.css +0 -496
  27. data/docs/file.README.html +0 -187
  28. data/docs/file_list.html +0 -56
  29. data/docs/frames.html +0 -17
  30. data/docs/index.html +0 -187
  31. data/docs/js/app.js +0 -314
  32. data/docs/js/full_list.js +0 -216
  33. data/docs/js/jquery.js +0 -4
  34. data/docs/method_list.html +0 -107
  35. data/docs/top-level-namespace.html +0 -110
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c33bcd3c7a212ce188b7016c5910a5053f801005a2eb93d367b2cc2722a98aee
4
- data.tar.gz: de1d090df2591e9c37b2a60b9331b83cb700c106e971782d2bce16345086e6cc
3
+ metadata.gz: 38df32b2223110a9e3a096a56984fa3f3bb4ec963193c9cf4cea7f078e9026c3
4
+ data.tar.gz: 28bdef1535be738ebc2ddbbab194f7ac51cd0fc416edb071c623d6efdc320cc8
5
5
  SHA512:
6
- metadata.gz: eaebdc8ab7326430a86bbca299376e94cf890ba4f7e4bceaf2b7aa7e4ef18d974ce3223defba69015dcccfaf78bc1ed2aa101069d626f36130d53b55f5633f83
7
- data.tar.gz: 490e852085597ab9c65bf6c9a812853f3585a5c4c9ec0a26a0a816dba86d64e3db436249ff6bcf77d360c770828728685ca2d0a3392b8f6c3a8dade3ec092d1d
6
+ metadata.gz: 84a023aaaab14f26092d3f6da4d1d41edec173462488287bbbb7a951bf861cfe73590009e8342c5c77fe85cbfb917045d2ebb8833d3d0cb5a263dad2b3369d00
7
+ data.tar.gz: bf9e8f408a9c622bf5f17c91c45ac4834379e4b354379afe98c6f6ba5eda01e89316ce62fe4203fdcb39ed90ac5840d5b92ebc2d9c36440a126a915580f4be20
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- htmlcsstoimage-api (0.1.3)
4
+ htmlcsstoimage-api (0.3.0)
5
5
  addressable (> 2.5.0)
6
6
  httparty (> 0.10)
7
7
 
@@ -56,6 +56,7 @@ GEM
56
56
  addressable (>= 2.8.0)
57
57
  crack (>= 0.3.2)
58
58
  hashdiff (>= 0.4.0, < 2.0.0)
59
+ yard (0.9.45)
59
60
 
60
61
  PLATFORMS
61
62
  ruby
@@ -69,6 +70,7 @@ DEPENDENCIES
69
70
  rspec (~> 3.0)
70
71
  vcr
71
72
  webmock
73
+ yard (~> 0.9)
72
74
 
73
75
  BUNDLED WITH
74
76
  2.5.23
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Ruby client for the [HTML/CSS to Image API](https://htmlcsstoimage.com).
6
6
 
7
- Generate png, jpg or webp images with Ruby. Renders exactly like Google Chrome.
7
+ Generate PNG, JPG, WebP, or PDF files with Ruby. Renders exactly like Google Chrome.
8
8
 
9
9
  ## Installation
10
10
 
@@ -42,12 +42,14 @@ client = HTMLCSSToImage.new
42
42
  ```
43
43
 
44
44
  ### Create an image
45
+
45
46
  Generate an image from HTML/CSS. Returns a URL to the image.
46
47
 
47
48
  ```ruby
48
49
  image = client.create_image("<div>Hello, world</div>",
49
50
  css: "div { background-color: red; font-family: Roboto; }",
50
- google_fonts: "Roboto")
51
+ google_fonts: "Roboto",
52
+ format: "webp")
51
53
 
52
54
  image
53
55
  => #<HTMLCSSToImage::ApiResponse url="https://hcti.io/v1/image/254b444c-dd82-4cc1-94ef-aa4b3a6870a6", id="254b444c-dd82-4cc1-94ef-aa4b3a6870a6">
@@ -56,20 +58,164 @@ image.url
56
58
  ```
57
59
 
58
60
  ### Delete an image
61
+
59
62
  Delete an existing image. Removes the image from HCTI servers and clears the CDN.
60
63
 
61
64
  ```ruby
62
65
  client.delete_image("254b444c-dd82-4cc1-94ef-aa4b3a6870a6")
63
66
  ```
64
67
 
68
+ Delete several images in one request:
69
+
70
+ ```ruby
71
+ client.delete_image_batch([
72
+ "254b444c-dd82-4cc1-94ef-aa4b3a6870a6",
73
+ "60ab90f0-c019-4d0d-a234-cc39e1f2226e"
74
+ ])
75
+ ```
76
+
65
77
  ### URL to image
78
+
66
79
  Generate a screenshot of any public URL.
67
80
 
68
81
  ```ruby
69
82
  image = client.url_to_image("https://github.com", viewport_width: 800, viewport_height: 1200)
70
83
  ```
71
84
 
85
+ ### Create a PDF
86
+
87
+ Select PDF output with `format: "pdf"`; use `pdf_options` to configure its layout:
88
+
89
+ ```ruby
90
+ pdf = client.create_image(
91
+ "<h1>Quarterly report</h1>",
92
+ format: "pdf",
93
+ pdf_options: {
94
+ print_background: true,
95
+ margins: ["20px", "20px", "20px", "20px"]
96
+ }
97
+ )
98
+ ```
99
+
100
+ ### Create a batch of images
101
+
102
+ Create several HTML/CSS or URL images in one API request. Each variation inherits
103
+ values from `default_options` and can override them.
104
+
105
+ ```ruby
106
+ images = client.create_image_batch(
107
+ [
108
+ { html: "<h1>First</h1>", format: "jpg" },
109
+ { html: "<h1>Second</h1>", transparent_background: true }
110
+ ],
111
+ { viewport_width: 1200, format: "webp" }
112
+ )
113
+ ```
114
+
115
+ ## Signed URLs
116
+
117
+ Signed URLs let another application, browser, or service render an image on
118
+ demand without exposing your API key. Generating a signed URL does not make an
119
+ API request; the image is created when the resulting URL is requested.
120
+
121
+ Both signed URL methods return an `HTMLCSSToImage::ApiResponse`. Use `.url` to
122
+ retrieve the URL:
123
+
124
+ ```ruby
125
+ signed_image = client.generate_create_and_render_url("https://example.com")
126
+ signed_image.url
127
+ # => "https://hcti.io/v1/image/create-and-render/user-id/..."
128
+ ```
129
+
130
+ Generate signed URLs in trusted server-side code. The API key is used to create
131
+ the HMAC signature and should never be exposed to a browser or end user. Query
132
+ parameters are covered by that signature, so modifying them after generation
133
+ invalidates the URL. Remember that the URL and its query values remain visible
134
+ to anyone who receives it.
135
+
136
+ [Learn more about create-and-render and signed URLs](https://docs.htmlcsstoimage.com/getting-started/create-and-render/).
137
+
138
+ ### Sign a URL screenshot
139
+
140
+ Use `generate_create_and_render_url` when you want HCTI to capture a public
141
+ webpage each time the signed URL is requested. Pass the target URL first,
142
+ followed by the same screenshot options accepted by `url_to_image`.
143
+
144
+ ```ruby
145
+ signed_image = client.generate_create_and_render_url(
146
+ "https://example.com/dashboard",
147
+ css: ".navigation { display: none; }",
148
+ headers: { "X-Preview-Mode" => "enabled" },
149
+ additional_header_origins: ["https://api.example.com"],
150
+ include_headers_on_subrequests: true,
151
+ identify_as_hcti: true,
152
+ format: "webp",
153
+ viewport_width: 1200,
154
+ viewport_height: 630,
155
+ transparent_background: false
156
+ )
157
+
158
+ signed_image.url
159
+ # => "https://hcti.io/v1/image/create-and-render/user-id/..."
160
+ ```
161
+
162
+ `pdf_options` is not supported by the create-and-render endpoint and
163
+ `dedupe_duration_s` only applies to standard POST requests, so both are omitted
164
+ when generating this URL. Other boolean options set to `false` are omitted,
165
+ except `transparent_background`, where both `true` and `false` are meaningful.
166
+ Custom headers are encoded in the URL and must not contain long-lived secrets.
167
+
168
+ ### Sign a templated image
169
+
170
+ Use `generate_templated_image_url` to substitute values into a saved template
171
+ when the signed URL is requested. Pass `template_version` to pin the URL to a
172
+ specific version; omit it to use the latest template version.
173
+
174
+ ```ruby
175
+ signed_image = client.generate_templated_image_url(
176
+ "t-56c64be5-5861-4148-acec-aaaca452027f",
177
+ {
178
+ title: "Hello, world!",
179
+ customer: {
180
+ name: "Ada",
181
+ plan: "Pro"
182
+ }
183
+ },
184
+ template_version: 1596829374001,
185
+ format: "webp"
186
+ )
187
+
188
+ signed_image.url
189
+ # => "https://hcti.io/v1/image/t-56c64be5-.../signed-token?template_version=...&customer=...&title=..."
190
+ ```
191
+
192
+ Hashes and arrays in `template_values` are serialized as JSON. Values set to
193
+ `nil` are omitted from the signed query string.
194
+
195
+ #### Changed in 0.2.0: template URL signatures
196
+
197
+ Ruby client 0.1.x URL-decoded the query string before generating its HMAC.
198
+ Version 0.2.0 instead signs the encoded query string exactly as it appears in
199
+ the generated URL, as required by the current API.
200
+
201
+ This means regenerating a template URL with the same inputs produces a
202
+ different token after upgrading from 0.1.x. Previously generated URLs are not
203
+ modified and continue to work.
204
+
205
+ `create_image_from_template` remains available as a compatibility proxy:
206
+
207
+ ```ruby
208
+ signed_image = client.create_image_from_template(
209
+ "t-56c64be5-5861-4148-acec-aaaca452027f",
210
+ { title: "Hello, world!" }
211
+ )
212
+ ```
213
+
214
+ Its legacy third argument was previously ignored. It remains unsupported except
215
+ for `template_version`; other keys in that argument are ignored.
216
+
72
217
  ## Templates
218
+
73
219
  A template allows you to define HTML that includes variables to be substituted at the time of image creation. [Learn more about templates](https://docs.htmlcsstoimage.com/getting-started/templates/).
74
220
 
75
221
  ```ruby
@@ -77,22 +223,45 @@ template = client.create_template("<div>{{title}}</div>")
77
223
  # => #<HTMLCSSToImage::ApiResponse template_id="t-56c64be5-5861-4148-acec-aaaca452027f", template_version=1596829374001>
78
224
 
79
225
  # Get templates
80
- all_templates = client.templates
81
-
82
- # Create a signed URL for a templated image
83
- image = client.create_image_from_template(template.template_id, { title: "Hello, world!" })
84
- # => #<HTMLCSSToImage::ApiResponse url="https://hcti.io/v1/image/t-56c64be5-5861-4148-acec-aaaca452027f/3aaa814dd998b302cc62b3550ddb35e8b9117c5ecea286da904eced0a3f44d9e?title=Hello%2C%20world%21">
85
-
86
- image.url
87
- # => "https://hcti.io/v1/image/t-56c64be5-5861-4148-acec-aaaca452027f/3aaa814dd998b302cc62b3550ddb35e8b9117c5ecea286da904eced0a3f44d9e?title=Hello%2C%20world%21"
226
+ all_templates = client.list_templates(count: 25)
227
+
228
+ # Get versions of one template
229
+ versions = client.list_template_versions(template.template_id, count: 25)
230
+
231
+ # Create a new version
232
+ version = client.create_template_version(
233
+ template.template_id,
234
+ "<div class='updated'>{{title}}</div>"
235
+ )
236
+
237
+ # Create a templated image with an API request
238
+ created_image = client.create_templated_image(
239
+ template.template_id,
240
+ { title: "Hello, world!" },
241
+ template_version: version.template_version,
242
+ format: "webp"
243
+ )
88
244
  ```
89
245
 
246
+ For signed, on-demand template images, see “Sign a templated image” in the
247
+ Signed URLs section above. `templates` remains available as a compatibility
248
+ alias for `list_templates`.
249
+
90
250
  ### Additional methods
251
+
91
252
  See the [ruby-client docs for all of the available methods](https://htmlcsstoimage.github.io/ruby-client/HTMLCSSToImage.html).
92
253
 
93
254
  ## Available parameters
255
+
94
256
  For detailed information on all the available parameters, visit the docs: https://docs.htmlcsstoimage.com/getting-started/using-the-api/
95
257
 
258
+ The client passes supported API parameters through as JSON. Recent additions
259
+ include `dedupe_duration_s`, `storage_destination_id`,
260
+ `transparent_background`, `format`, `proxy_id`, `jumbo_max_width`, `jumbo_max_height`,
261
+ and, for URL screenshots, `headers`, `additional_header_origins`,
262
+ `include_headers_on_subrequests`, `identify_as_hcti`, and
263
+ `block_consent_banners`.
264
+
96
265
  ## Development
97
266
 
98
267
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -102,6 +271,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
102
271
  To generate the Yard docs, run `yard doc -o docs` and commit the changes.
103
272
 
104
273
  ## Support
274
+
105
275
  For help with the API, you can also contact `support@htmlcsstoimage.com`.
106
276
 
107
277
  ## Contributing
@@ -10,14 +10,15 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["support@htmlcsstoimage.com"]
11
11
 
12
12
  spec.summary = %q{Ruby client for the HTML/CSS to Image API.}
13
- spec.description = %q{Ruby client for the HTML/CSS to Image API. Generate a png, jpg or webp images with Ruby. Renders exactly like Google Chrome. }
13
+ spec.description = %q{Ruby client for the HTML/CSS to Image API. Generate PNG, JPG, WebP, or PDF files with Ruby. Renders exactly like Google Chrome. }
14
14
  spec.homepage = "https://docs.htmlcsstoimage.com/example-code/ruby"
15
15
  spec.license = "MIT"
16
+ spec.required_ruby_version = ">= 2.7.0"
16
17
 
17
18
  # Specify which files should be added to the gem when it is released.
18
19
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
20
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|doc)/}) }
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|doc|docs|cassettes)/}) }
21
22
  end
22
23
  spec.bindir = "exe"
23
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -32,4 +33,5 @@ Gem::Specification.new do |spec|
32
33
  spec.add_development_dependency "pry-byebug"
33
34
  spec.add_development_dependency "vcr"
34
35
  spec.add_development_dependency "webmock"
36
+ spec.add_development_dependency "yard", "~> 0.9"
35
37
  end
@@ -0,0 +1,36 @@
1
+ # Client for creating images and managing templates with HTML/CSS to Image.
2
+ class HTMLCSSToImage
3
+ include HTTParty
4
+
5
+ base_uri "https://hcti.io"
6
+ headers "Content-Type" => "application/json"
7
+ format :json
8
+
9
+ # A structured API response with attribute-style access to JSON fields.
10
+ class ApiResponse < OpenStruct
11
+ end
12
+
13
+ parser(
14
+ proc do |body, format|
15
+ case format
16
+ when :json
17
+ JSON.parse(body, object_class: ApiResponse)
18
+ else
19
+ body
20
+ end
21
+ end
22
+ )
23
+
24
+ # Creates an instance of HTMLCSSToImage with API credentials.
25
+ # If credentials are not provided, the client uses the `HCTI_USER_ID`
26
+ # and `HCTI_API_KEY` environment variables.
27
+ #
28
+ # @see https://htmlcsstoimage.com/dashboard
29
+ #
30
+ # @param user_id [String] the user ID for the account
31
+ # @param api_key [String] the API key for the account
32
+ # @return [HTMLCSSToImage] an instance of the API client
33
+ def initialize(user_id: ENV["HCTI_USER_ID"], api_key: ENV["HCTI_API_KEY"])
34
+ @auth = { username: user_id, password: api_key }
35
+ end
36
+ end
@@ -0,0 +1,173 @@
1
+ class HTMLCSSToImage
2
+ # Converts HTML/CSS to an image with the API.
3
+ #
4
+ # @see https://docs.htmlcsstoimage.com/getting-started/using-the-api
5
+ #
6
+ # @param html [String] HTML to render, as a snippet or an entire webpage
7
+ # @param params [Hash] image creation options
8
+ # @option params [String] :format The format used in the initially returned URL: `png`, `jpg`, `webp`, or `pdf`. This does not change the stored image definition or prevent rendering another supported format later.
9
+ # @option params [String] :css The CSS for your image.
10
+ # @option params [Numeric] :device_scale The pixel ratio for the screenshot. Minimum: `0.1`, Maximum: `3`.
11
+ # @option params [String] :google_fonts Google Fonts to load. Separate multiple fonts with `|`.
12
+ # @option params [Integer] :max_wait_ms The maximum time to wait before taking the screenshot. Minimum: `500`, Maximum: `10000`.
13
+ # @option params [Integer] :ms_delay Extra time in milliseconds to wait before taking the screenshot. Maximum: `10000`.
14
+ # @option params [Boolean] :render_when_ready Wait until `ScreenshotReady()` is called from JavaScript before taking the screenshot.
15
+ # @option params [String] :selector A CSS selector for the element to capture.
16
+ # @option params [Integer] :viewport_height The Chrome viewport height. Both viewport dimensions must be set if using either.
17
+ # @option params [Integer] :viewport_width The Chrome viewport width. Both viewport dimensions must be set if using either.
18
+ # @option params [Hash] :pdf_options Options for generating a PDF, including page size, margins, scale, and background printing.
19
+ # @option params [Boolean] :disable_twemoji Disable the Twemoji fallback and use native emoji fonts.
20
+ # @option params [Boolean] :max_render_once Ensure the image is only rendered and saved once.
21
+ # @option params [Integer] :dedupe_duration_s Reuse an identical image created within this many seconds. Only supported for single-image POST requests.
22
+ # @option params [String] :color_scheme Render using the `light` or `dark` browser color scheme.
23
+ # @option params [String] :timezone The browser timezone as an IANA timezone identifier, such as `America/New_York`.
24
+ # @option params [Boolean] :viewport_mobile Whether to honor the page's mobile viewport behavior.
25
+ # @option params [Boolean] :viewport_landscape Whether to render the viewport in landscape mode.
26
+ # @option params [Boolean] :viewport_touch Whether the viewport supports touch events.
27
+ # @option params [String] :media_type Render using `print` or `screen` media.
28
+ # @option params [String] :proxy_id The ID of an organization proxy to use for the render.
29
+ # @option params [String] :storage_destination_id The ID of an organization storage destination for the rendered image.
30
+ # @option params [Integer] :jumbo_max_height Maximum output height in jumbo mode. Requires `jumbo_max_width`.
31
+ # @option params [Integer] :jumbo_max_width Maximum output width in jumbo mode. Requires `jumbo_max_height`.
32
+ # @option params [Boolean] :transparent_background Whether to render the image with a transparent background.
33
+ # @return [HTMLCSSToImage::ApiResponse] image details, including `.url`
34
+ def create_image(html, params = {})
35
+ body = { html: html }.merge(params).to_json
36
+ options = { basic_auth: @auth, body: body, query: { includeId: true } }
37
+
38
+ self.class.post("/v1/image", options)
39
+ end
40
+
41
+ # Generates a screenshot of a public URL.
42
+ #
43
+ # @see https://docs.htmlcsstoimage.com/getting-started/url-to-image/
44
+ #
45
+ # @param url [String] the fully qualified URL to capture
46
+ # @param params [Hash] image creation options
47
+ # @option params [String] :format The format used in the initially returned URL: `png`, `jpg`, `webp`, or `pdf`. This does not change the stored image definition or prevent rendering another supported format later.
48
+ # @option params [String] :css CSS to inject into the webpage.
49
+ # @option params [Numeric] :device_scale The pixel ratio for the screenshot. Minimum: `0.1`, Maximum: `3`.
50
+ # @option params [Boolean] :full_screen Take a screenshot of the entire scrollable page.
51
+ # @option params [Integer] :max_wait_ms The maximum time to wait before taking the screenshot. Minimum: `500`, Maximum: `10000`.
52
+ # @option params [Integer] :ms_delay Extra time in milliseconds to wait before taking the screenshot. Maximum: `10000`.
53
+ # @option params [Boolean] :render_when_ready Wait until `ScreenshotReady()` is called from JavaScript before taking the screenshot.
54
+ # @option params [String] :selector A CSS selector for the element to capture.
55
+ # @option params [Integer] :viewport_height The Chrome viewport height. Both viewport dimensions must be set if using either.
56
+ # @option params [Integer] :viewport_width The Chrome viewport width. Both viewport dimensions must be set if using either.
57
+ # @option params [Hash] :pdf_options Options for generating a PDF, including page size, margins, scale, and background printing.
58
+ # @option params [Boolean] :disable_twemoji Disable the Twemoji fallback and use native emoji fonts.
59
+ # @option params [Boolean] :max_render_once Ensure the image is only rendered and saved once.
60
+ # @option params [Integer] :dedupe_duration_s Reuse an identical image created within this many seconds. Only supported for single-image POST requests.
61
+ # @option params [String] :color_scheme Render using the `light` or `dark` browser color scheme.
62
+ # @option params [String] :timezone The browser timezone as an IANA timezone identifier, such as `America/New_York`.
63
+ # @option params [Boolean] :block_consent_banners Attempt to block cookie and consent banners.
64
+ # @option params [Hash{String => String}] :headers Custom HTTP headers to send to allowed origins.
65
+ # @option params [Array<String>] :additional_header_origins Additional exact origins allowed to receive custom headers.
66
+ # @option params [Boolean] :include_headers_on_subrequests Send custom headers on subrequests to allowed origins.
67
+ # @option params [Boolean] :identify_as_hcti Add `X-HCTI-SCREENSHOT: 1` to the top-level page request.
68
+ # @option params [Boolean] :viewport_mobile Whether to honor the page's mobile viewport behavior.
69
+ # @option params [Boolean] :viewport_landscape Whether to render the viewport in landscape mode.
70
+ # @option params [Boolean] :viewport_touch Whether the viewport supports touch events.
71
+ # @option params [String] :media_type Render using `print` or `screen` media.
72
+ # @option params [String] :proxy_id The ID of an organization proxy to use for the render.
73
+ # @option params [String] :storage_destination_id The ID of an organization storage destination for the rendered image.
74
+ # @option params [Integer] :jumbo_max_height Maximum output height in jumbo mode. Requires `jumbo_max_width`.
75
+ # @option params [Integer] :jumbo_max_width Maximum output width in jumbo mode. Requires `jumbo_max_height`.
76
+ # @option params [Boolean] :transparent_background Whether to render the image with a transparent background.
77
+ # @return [HTMLCSSToImage::ApiResponse] image details, including `.url`
78
+ def url_to_image(url, params = {})
79
+ body = { url: url }.merge(params).to_json
80
+ options = { basic_auth: @auth, body: body, query: { includeId: true } }
81
+
82
+ self.class.post("/v1/image", options)
83
+ end
84
+
85
+ # Creates an image from a saved template with an API request.
86
+ #
87
+ # @see https://docs.htmlcsstoimage.com/getting-started/templates/
88
+ #
89
+ # @param template_id [String] the saved template ID
90
+ # @param template_values [Hash] values to substitute into the template
91
+ # @param template_version [Integer, nil] a specific template version, or the latest when omitted
92
+ # @param format [String, nil] the format used in the initially returned URL: `png`, `jpg`, `webp`, or `pdf`; does not change the stored image definition
93
+ # @param keyword_values [Hash] template values passed as Ruby keyword arguments
94
+ # @return [HTMLCSSToImage::ApiResponse] image details, including `.url`
95
+ def create_templated_image(
96
+ template_id,
97
+ template_values = {},
98
+ template_version: nil,
99
+ format: nil,
100
+ **keyword_values
101
+ )
102
+ template_values = template_values.merge(keyword_values)
103
+ body = {
104
+ template_id: template_id,
105
+ template_values: template_values
106
+ }
107
+ body[:template_version] = template_version unless template_version.nil?
108
+ body[:format] = format unless format.nil?
109
+
110
+ self.class.post(
111
+ "/v1/image",
112
+ basic_auth: @auth,
113
+ body: body.to_json,
114
+ query: { includeId: true }
115
+ )
116
+ end
117
+
118
+ # Creates several HTML/CSS or URL images in one API request.
119
+ #
120
+ # Templates are not supported in batch requests.
121
+ #
122
+ # @see https://docs.htmlcsstoimage.com/getting-started/using-the-api
123
+ #
124
+ # @param variations [Array<Hash>] per-image values
125
+ # @param default_options [Hash, nil] shared values inherited by each variation; `format` may be `png`, `jpg`, `webp`, or `pdf` and only changes initially returned URL extensions
126
+ # @return [HTMLCSSToImage::ApiResponse] batch response with images available at `.images`
127
+ def create_image_batch(variations, default_options = nil)
128
+ return ApiResponse.new(images: []) if variations.empty?
129
+
130
+ body = { variations: variations }
131
+ body[:default_options] = default_options unless default_options.nil?
132
+
133
+ self.class.post(
134
+ "/v1/image/batch",
135
+ basic_auth: @auth,
136
+ body: body.to_json
137
+ )
138
+ end
139
+
140
+ # Deletes an image.
141
+ #
142
+ # @see https://docs.htmlcsstoimage.com/getting-started/using-the-api
143
+ #
144
+ # @param image_id [String] the ID of the image to delete
145
+ # @return [Boolean, HTMLCSSToImage::ApiResponse] true on success, or the API response on failure
146
+ def delete_image(image_id)
147
+ response = self.class.delete("/v1/image/#{image_id}", basic_auth: @auth)
148
+
149
+ return true if response.success?
150
+
151
+ response
152
+ end
153
+
154
+ # Deletes multiple images in one request.
155
+ #
156
+ # @see https://docs.htmlcsstoimage.com/getting-started/using-the-api
157
+ #
158
+ # @param image_ids [Array<String>] IDs of the images to delete
159
+ # @return [Boolean, HTMLCSSToImage::ApiResponse] true on success, or the API response on failure
160
+ def delete_image_batch(image_ids)
161
+ return true if image_ids.empty?
162
+
163
+ response = self.class.delete(
164
+ "/v1/image/batch",
165
+ basic_auth: @auth,
166
+ body: { ids: image_ids }.to_json
167
+ )
168
+
169
+ return true if response.success?
170
+
171
+ response
172
+ end
173
+ end
@@ -0,0 +1,130 @@
1
+ class HTMLCSSToImage
2
+ # Generates a signed URL for rendering an image from a saved template.
3
+ #
4
+ # This method makes no network requests. Hashes and arrays in
5
+ # `template_values` are encoded as JSON before the query string is signed.
6
+ #
7
+ # @see https://docs.htmlcsstoimage.com/getting-started/create-and-render/
8
+ #
9
+ # @param template_id [String] the saved template ID
10
+ # @param template_values [Hash] values to substitute into the template
11
+ # @param template_version [Integer, nil] a specific template version, or the latest when omitted
12
+ # @param format [String, nil] output format appended to the signed URL path: `png`, `jpg`, `webp`, or `pdf`
13
+ # @param keyword_values [Hash] template values passed as Ruby keyword arguments
14
+ # @return [HTMLCSSToImage::ApiResponse] signed URL available at `.url`
15
+ def generate_templated_image_url(
16
+ template_id,
17
+ template_values = {},
18
+ template_version: nil,
19
+ format: nil,
20
+ **keyword_values
21
+ )
22
+ template_values = template_values.merge(keyword_values)
23
+ pairs = []
24
+ pairs << ["template_version", template_version.to_s] unless template_version.nil?
25
+
26
+ template_values.sort_by { |key, _value| key.to_s }.each do |key, value|
27
+ next if value.nil?
28
+
29
+ pairs << [key.to_s, signed_value(value)]
30
+ end
31
+
32
+ query = Addressable::URI.form_encode(pairs)
33
+ token = generate_hmac_token(query)
34
+ separator = query.empty? ? "" : "?"
35
+ format_path = format.nil? ? "" : "/#{format}"
36
+
37
+ ApiResponse.new(
38
+ url: "https://hcti.io/v1/image/#{template_id}/#{token}#{format_path}#{separator}#{query}"
39
+ )
40
+ end
41
+
42
+ # Compatibility proxy for {#generate_templated_image_url}.
43
+ #
44
+ # The third positional hash was accepted by previous versions but was not
45
+ # used. Its `template_version` value is now honored when present.
46
+ #
47
+ # @deprecated Use {#generate_templated_image_url} instead.
48
+ # @param template_id [String] the saved template ID
49
+ # @param template_values [Hash] values to substitute into the template
50
+ # @param params [Hash] legacy options; only `template_version` is used
51
+ # @param template_version [Integer, nil] a specific template version
52
+ # @param format [String, nil] output format appended to the signed URL path: `png`, `jpg`, `webp`, or `pdf`
53
+ # @param keyword_values [Hash] template values passed as Ruby keyword arguments
54
+ # @return [HTMLCSSToImage::ApiResponse] signed URL available at `.url`
55
+ def create_image_from_template(
56
+ template_id,
57
+ template_values = {},
58
+ params = {},
59
+ template_version: nil,
60
+ format: nil,
61
+ **keyword_values
62
+ )
63
+ params ||= {}
64
+ template_values = template_values.merge(keyword_values)
65
+ legacy_version =
66
+ if params.is_a?(Hash)
67
+ params[:template_version] || params["template_version"]
68
+ end
69
+
70
+ options = { template_version: template_version || legacy_version }
71
+ options[:format] = format unless format.nil?
72
+
73
+ generate_templated_image_url(template_id, template_values, **options)
74
+ end
75
+
76
+ # Generates a signed create-and-render URL for a URL screenshot.
77
+ #
78
+ # This method makes no network requests. PDF options are omitted because the
79
+ # create-and-render endpoint does not support them. `dedupe_duration_s` is
80
+ # omitted because deduplication applies only to standard POST requests. False
81
+ # boolean values are omitted except for `transparent_background`, where both
82
+ # values are meaningful.
83
+ #
84
+ # @see https://docs.htmlcsstoimage.com/getting-started/create-and-render/
85
+ #
86
+ # @param url [String] the fully qualified URL to capture
87
+ # @param params [Hash] URL screenshot options; `format` may be `png`, `jpg`, `webp`, or `pdf` and is appended to the signed URL path instead of the query string
88
+ # @return [HTMLCSSToImage::ApiResponse] signed URL available at `.url`
89
+ def generate_create_and_render_url(url, params = {})
90
+ pairs = [["url", url.to_s]]
91
+ format = params[:format] || params["format"]
92
+
93
+ params
94
+ .reject do |key, _value|
95
+ %w[url format pdf_options dedupe_duration_s].include?(key.to_s)
96
+ end
97
+ .sort_by { |key, _value| key.to_s }
98
+ .each do |key, value|
99
+ next if value.nil?
100
+ next if value == false && key.to_s != "transparent_background"
101
+
102
+ case key.to_s
103
+ when "headers"
104
+ value.each { |name, header_value| pairs << ["headers", "#{name}:#{header_value}"] }
105
+ when "additional_header_origins"
106
+ value.each { |origin| pairs << ["additional_header_origins", origin.to_s] }
107
+ else
108
+ pairs << [key.to_s, signed_value(value)]
109
+ end
110
+ end
111
+
112
+ query = Addressable::URI.form_encode(pairs)
113
+ token = generate_hmac_token(query)
114
+ format_path = format.nil? ? "" : "/#{format}"
115
+
116
+ ApiResponse.new(
117
+ url: "https://hcti.io/v1/image/create-and-render/#{@auth[:username]}/#{token}#{format_path}?#{query}"
118
+ )
119
+ end
120
+
121
+ private
122
+
123
+ def generate_hmac_token(query)
124
+ OpenSSL::HMAC.hexdigest("sha256", @auth[:password], query)
125
+ end
126
+
127
+ def signed_value(value)
128
+ value.is_a?(Array) || value.is_a?(Hash) ? JSON.generate(value) : value.to_s
129
+ end
130
+ end