html2img-client 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f26b9fea9182f0ceb819242d093a8deaf5d661e3d25c3ff20f90286120c7b52d
4
+ data.tar.gz: 41691473ff4cc2ad5d17cb27ef5cf43b7500b08bc2acb4ad5ad913d9fa0600d3
5
+ SHA512:
6
+ metadata.gz: fc292634a6b4cb762ca9f475187e6d3c9059983a486181926e3c98bf35a287296d16969cb8b9831e0bab741c9b3792c69a802d6edc51a81aa966e7298477e364
7
+ data.tar.gz: cc605647b58582a4182335d2412474a23b9fbdbcb3c8a2938bc74cc2ee5e1e2034d372e777c3a6ecf8ad109ac1a5b0344e7555cbfca359c38d93703dea4b3107
data/CHANGELOG.md ADDED
@@ -0,0 +1,34 @@
1
+ # Changelog
2
+
3
+ All notable changes to `html2img-client` are documented here. This project
4
+ follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and the
5
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] - 2026-08-16
10
+
11
+ Initial release of the official Ruby client for the
12
+ [HTML to Image API](https://html2img.com).
13
+
14
+ ### Added
15
+
16
+ - `Html2img::Client` with `#html`, `#screenshot` and `#template`.
17
+ - `Html2img.configure` for process-wide defaults, plus module-level shortcuts
18
+ (`Html2img.html`, `.screenshot`, `.template`, `.download`, `.save`).
19
+ - `Html2img::RenderResponse`, a frozen value object covering both the
20
+ synchronous and the async acceptance envelopes, with `#processing?`, `#pdf?`
21
+ and the full `#raw` payload.
22
+ - PDF output through `format: "pdf"`, including `scale_to_fit`, via the
23
+ [HTML to PDF API](https://html2img.com/html-to-pdf/).
24
+ - `#download` and `#save` for keeping a copy of a render.
25
+ - Typed error hierarchy rooted at `Html2img::Error`, mapped from the API's
26
+ status codes and `code` field.
27
+ - Local validation of every render option, so a typo or an out-of-range value
28
+ raises an `ArgumentError` before a credit is spent.
29
+ - Pluggable transports: the default is built on Net::HTTP, and any object
30
+ responding to `#call` can replace it.
31
+ - An `html2img` executable with `test`, `html`, `screenshot` and `template`.
32
+
33
+ [Unreleased]: https://github.com/html2img/html2img-ruby/compare/v1.0.0...HEAD
34
+ [1.0.0]: https://github.com/html2img/html2img-ruby/releases/tag/v1.0.0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 html2img
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,472 @@
1
+ [![html2img — HTML to image API, rendered in real Chrome](https://html2img.com/og-image.png)](https://html2img.com)
2
+
3
+ # html2img for Ruby
4
+
5
+ [![Gem Version](https://img.shields.io/gem/v/html2img-client)](https://rubygems.org/gems/html2img-client)
6
+ [![Downloads](https://img.shields.io/gem/dt/html2img-client)](https://rubygems.org/gems/html2img-client)
7
+ [![Ruby](https://img.shields.io/badge/ruby-3.1%20%7C%203.2%20%7C%203.3%20%7C%203.4%20%7C%204.0-CC342D)](https://www.ruby-lang.org)
8
+ [![License](https://img.shields.io/github/license/html2img/html2img-ruby)](LICENSE)
9
+
10
+ The official Ruby client for the [HTML to Image API](https://html2img.com) at html2img.com. Turn HTML and CSS into images, capture screenshots of live URLs, render named templates, and export A4 PDFs, all returning a typed response object.
11
+
12
+ Every render runs in real Chrome, so flexbox, grid, custom properties, web fonts and inline JavaScript behave exactly as they do in the browser. The gem has **zero runtime dependencies** — it is built on Net::HTTP from the standard library — and works anywhere Ruby does: Rails and Sinatra apps, Sidekiq and Active Job workers, rake tasks and one-off scripts. The full API reference lives in the [documentation](https://html2img.com/docs), with a Ruby guide at [html2img.com/docs/usage/ruby](https://html2img.com/docs/usage/ruby).
13
+
14
+ Three things this gem does, each with its own worked guide:
15
+
16
+ - **[HTML to Image API](https://html2img.com/)** — render a document you control into a PNG.
17
+ - **[Screenshot API](https://html2img.com/screenshot-api/)** — capture any public URL, full page or cropped to one element.
18
+ - **[HTML to PDF API](https://html2img.com/html-to-pdf/)** — the same markup as a vector A4 PDF with selectable text.
19
+
20
+ ## Contents
21
+
22
+ - [What you can build](#what-you-can-build)
23
+ - [Requirements](#requirements)
24
+ - [Installation](#installation)
25
+ - [Quick start](#quick-start)
26
+ - [Configuration](#configuration)
27
+ - [Usage](#usage)
28
+ - [Render HTML](#render-html)
29
+ - [Capture a screenshot](#capture-a-screenshot)
30
+ - [Generate a PDF](#generate-a-pdf)
31
+ - [Render a template](#render-a-template)
32
+ - [Saving renders](#saving-renders)
33
+ - [Rails](#rails)
34
+ - [Background jobs](#background-jobs)
35
+ - [Render options](#render-options)
36
+ - [The response](#the-response)
37
+ - [Asynchronous delivery](#asynchronous-delivery)
38
+ - [Error handling](#error-handling)
39
+ - [Custom transports](#custom-transports)
40
+ - [Command line](#command-line)
41
+ - [Verifying your setup](#verifying-your-setup)
42
+ - [Other languages and frameworks](#other-languages-and-frameworks)
43
+ - [Development](#development)
44
+ - [Links](#links)
45
+
46
+ ## What you can build
47
+
48
+ - **Open Graph and social images**, generated per page or post. See the [Open Graph image template](https://html2img.com/templates/open-graph-image) and [Twitter/X post template](https://html2img.com/templates/twitter-post).
49
+ - **Business documents** such as [invoices](https://html2img.com/templates/invoice-image), [receipts](https://html2img.com/templates/receipt-image), [event tickets](https://html2img.com/templates/event-ticket) and [certificates](https://html2img.com/templates/certificate-of-completion) — as PNGs, or as PDFs through the [HTML to PDF API](https://html2img.com/html-to-pdf/).
50
+ - **Developer assets** such as [code screenshots](https://html2img.com/templates/code-screenshot) and [GitHub social previews](https://html2img.com/templates/github-social-preview).
51
+ - **URL screenshots** through the [Screenshot API](https://html2img.com/screenshot-api/), full page or cropped to a single element, with CSS injection to hide cookie banners and chat widgets before capture.
52
+
53
+ Browse the [full template library](https://html2img.com/templates), or try the no-signup [browser tools](https://html2img.com/tools) to see the output before you write any code.
54
+
55
+ ## Requirements
56
+
57
+ - Ruby 3.1 or newer (tested on 3.1, 3.2, 3.3, 3.4 and 4.0)
58
+ - An html2img API key, issued per account from your [dashboard](https://app.html2img.com/register)
59
+
60
+ Every account starts with 50 free credits and no card is needed to get started. Free-tier renders are hosted for seven days; on any paid [plan](https://html2img.com/pricing) they are hosted permanently, including everything you rendered before upgrading.
61
+
62
+ > **Keep your API key on the server.** This client is designed for server-side use. Shipping your key in client-side code would let anyone spend your credits.
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ bundle add html2img-client
68
+ ```
69
+
70
+ Or in your `Gemfile`:
71
+
72
+ ```ruby
73
+ gem "html2img-client"
74
+ ```
75
+
76
+ The gem is named `html2img-client`; the namespace is `Html2img`:
77
+
78
+ ```ruby
79
+ require "html2img/client"
80
+ ```
81
+
82
+ Bundler requires the gem for you in a Rails app, so the `require` is only needed in plain scripts.
83
+
84
+ Set your API key in the environment. The client reads it automatically:
85
+
86
+ ```dotenv
87
+ HTML2IMG_API_KEY=your-api-key
88
+ ```
89
+
90
+ See the [authentication docs](https://html2img.com/docs/authentication) for issuing and rotating keys, and the [getting started guide](https://html2img.com/docs/getting-started) for a tour of the API.
91
+
92
+ ## Quick start
93
+
94
+ ```ruby
95
+ require "html2img/client"
96
+
97
+ client = Html2img::Client.new # reads HTML2IMG_API_KEY from the environment
98
+
99
+ response = client.html(
100
+ "<h1 style='font: 700 64px system-ui'>Hello from Ruby</h1>",
101
+ width: 1200,
102
+ height: 630,
103
+ dpi: 2
104
+ )
105
+
106
+ puts response.url # => "https://i.html2img.com/abc123def456.png"
107
+ ```
108
+
109
+ ## Configuration
110
+
111
+ Pass configuration when you build a client:
112
+
113
+ ```ruby
114
+ client = Html2img::Client.new(
115
+ api_key: "your-api-key", # default: ENV["HTML2IMG_API_KEY"]
116
+ base_url: "https://app.html2img.com", # default: ENV["HTML2IMG_BASE_URI"], then this
117
+ timeout: 35 # seconds
118
+ )
119
+ ```
120
+
121
+ Or configure the process once and use the module-level shortcuts, which is usually what you want in an application:
122
+
123
+ ```ruby
124
+ # config/initializers/html2img.rb
125
+ Html2img.configure do |config|
126
+ config.api_key = ENV.fetch("HTML2IMG_API_KEY")
127
+ config.timeout = 45
128
+ end
129
+
130
+ Html2img.html(document, width: 1200, height: 630)
131
+ Html2img.screenshot("https://example.com")
132
+ Html2img.template("invoice-image", number: 1042)
133
+ ```
134
+
135
+ | Variable | Default | Purpose |
136
+ | ------------------- | -------------------------- | ---------------------------------------------------------- |
137
+ | `HTML2IMG_API_KEY` | none | Your key, sent as the `X-API-Key` header on every request. |
138
+ | `HTML2IMG_BASE_URI` | `https://app.html2img.com` | API base URL. You rarely need to change this. |
139
+
140
+ The default timeout of 35 seconds sits just over the 30 second synchronous render budget. For captures likely to exceed it, pass a `webhook_url` on the request rather than raising the timeout — see [asynchronous delivery](#asynchronous-delivery).
141
+
142
+ A client is cheap to build and safe to share between threads, so a memoised one is fine.
143
+
144
+ ## Usage
145
+
146
+ Every render method returns an `Html2img::RenderResponse`. Options are keyword arguments, validated locally before anything is sent.
147
+
148
+ ### Render HTML
149
+
150
+ `POST /api/html`. Send a complete HTML document and get back an image of the rendered result. Inline your CSS in a `<style>` block, or reference remote stylesheets and web fonts with `<link>` tags in the document head. This is the [HTML to Image API](https://html2img.com/); see the [`html` parameter docs](https://html2img.com/docs/parameters/html).
151
+
152
+ ```ruby
153
+ response = client.html(
154
+ document, # a complete HTML document
155
+ css: "body { background: #0f172a; color: #fff; }", # injected after load
156
+ width: 1200,
157
+ height: 630,
158
+ dpi: 2 # retina
159
+ )
160
+
161
+ response.url # => "https://i.html2img.com/abc123def456.png"
162
+ ```
163
+
164
+ ### Capture a screenshot
165
+
166
+ `POST /api/screenshot`. Fetch a public URL in real Chrome and capture it. Use `selector` to crop to a single element, and `css` to hide cookie banners or chat widgets before the capture. This is the [Screenshot API](https://html2img.com/screenshot-api/); see the [`url` parameter docs](https://html2img.com/docs/parameters/url) and the [`selector` docs](https://html2img.com/docs/parameters/selector).
167
+
168
+ ```ruby
169
+ response = client.screenshot(
170
+ "https://example.com",
171
+ width: 1200,
172
+ height: 630,
173
+ selector: "#hero",
174
+ css: ".cookie-banner, .intercom-launcher { display: none !important; }",
175
+ dpi: 2
176
+ )
177
+ ```
178
+
179
+ Full-page captures grow to the whole scroll length of the document:
180
+
181
+ ```ruby
182
+ client.screenshot("https://example.com/pricing", fullpage: true)
183
+ ```
184
+
185
+ ### Generate a PDF
186
+
187
+ Pass `format: "pdf"` on either render and the result comes back as an A4 portrait vector PDF instead of a PNG: text stays selectable and searchable, web fonts are embedded, and long content paginates automatically. The API ignores `width`, `height`, `dpi`, `fullpage` and `selector` in PDF mode, and the response URL points at a `.pdf` file. One credit, the same as an image. This is the [HTML to PDF API](https://html2img.com/html-to-pdf/); see the [`format` parameter docs](https://html2img.com/docs/parameters/format).
188
+
189
+ ```ruby
190
+ response = client.html(invoice_html, format: "pdf")
191
+
192
+ # Wide content, such as a data table, can be scaled down to the page width
193
+ response = client.html(report_html, format: "pdf", scale_to_fit: true)
194
+
195
+ client.save(response, "invoices/#{invoice.number}.pdf")
196
+ ```
197
+
198
+ ### Render a template
199
+
200
+ `POST /api/v1/templates/{slug}`. Render one of the built-in [templates](https://html2img.com/templates) from a data payload, with no markup of your own. The data is validated server-side per template. Templates output PNG only.
201
+
202
+ ```ruby
203
+ response = client.template("invoice-image", number: 1042, amount: "£240.00", due_date: "2026-07-01")
204
+
205
+ # A hash works too, when your data is already one
206
+ response = client.template("invoice-image", invoice.as_json)
207
+ ```
208
+
209
+ ## Saving renders
210
+
211
+ The API returns the CDN URL of the render rather than the raw bytes, so you can cache and re-serve it from your own infrastructure. When you would rather keep a copy, `download` gives you the bytes and `save` writes them to a path, creating parent directories as needed:
212
+
213
+ ```ruby
214
+ response = client.html(document, width: 1200, height: 630)
215
+
216
+ bytes = client.download(response) # => String (binary)
217
+ path = client.save(response, "og/post-42.png") # => "og/post-42.png"
218
+ ```
219
+
220
+ Both accept a URL string as well as a response, so you can re-download an earlier render:
221
+
222
+ ```ruby
223
+ client.save("https://i.html2img.com/abc123.png", "thumbnails/abc123.png")
224
+ ```
225
+
226
+ To store somewhere else, hand the bytes to whatever you already use — for example Active Storage:
227
+
228
+ ```ruby
229
+ post.og_image.attach(
230
+ io: StringIO.new(client.download(response)),
231
+ filename: "og-#{post.id}.png",
232
+ content_type: "image/png"
233
+ )
234
+ ```
235
+
236
+ ## Rails
237
+
238
+ Render an Action View template into the image, so the card lives with the rest of your views:
239
+
240
+ ```ruby
241
+ class OgImage
242
+ def self.for(post)
243
+ html = ApplicationController.render(
244
+ template: "og_images/post",
245
+ layout: false,
246
+ assigns: { post: post }
247
+ )
248
+
249
+ Html2img.html(html, width: 1200, height: 630, dpi: 2).url
250
+ end
251
+ end
252
+ ```
253
+
254
+ Then output it in your layout:
255
+
256
+ ```erb
257
+ <meta property="og:image" content="<%= @post.og_image_url %>">
258
+ ```
259
+
260
+ Configure the client once in an initializer, as shown in [configuration](#configuration).
261
+
262
+ ## Background jobs
263
+
264
+ Renders are a natural fit for a background job, especially full-page captures:
265
+
266
+ ```ruby
267
+ class GenerateOgImageJob < ApplicationJob
268
+ queue_as :default
269
+
270
+ retry_on Html2img::ServerError, Html2img::ConnectionError, wait: :polynomially_longer, attempts: 3
271
+ discard_on Html2img::ValidationError
272
+
273
+ def perform(post)
274
+ response = Html2img.html(OgImage.html_for(post), width: 1200, height: 630)
275
+
276
+ post.update!(og_image_url: response.url)
277
+ end
278
+ end
279
+ ```
280
+
281
+ Retrying a `ServerError` or a `ConnectionError` is worthwhile; retrying a `ValidationError` is not, since the same request will fail the same way. For very large captures, prefer [asynchronous delivery](#asynchronous-delivery) over a long-running job.
282
+
283
+ ## Render options
284
+
285
+ Both renders accept the following. Any option you leave out is omitted from the request, so the server applies its own default. The complete reference is in the [parameter docs](https://html2img.com/docs/parameters).
286
+
287
+ | Option | Type | Docs |
288
+ | ------------------- | --------------- | --------------------------------------------------------------------------------------- |
289
+ | `css` | String | [css](https://html2img.com/docs/parameters/css) |
290
+ | `width` | Integer | [dimensions](https://html2img.com/docs/parameters/dimensions) (1 to 5000) |
291
+ | `height` | Integer | [dimensions](https://html2img.com/docs/parameters/dimensions) (ignored when `fullpage`) |
292
+ | `fullpage` | Boolean | [fullpage](https://html2img.com/docs/parameters/fullpage) |
293
+ | `dpi` | Integer | [dpi](https://html2img.com/docs/parameters/dpi) (1 to 4, use 2 for retina) |
294
+ | `webhook_url` | String | [webhook_url](https://html2img.com/docs/parameters/webhook-url) |
295
+ | `ms_delay` | Integer | [ms_delay](https://html2img.com/docs/parameters/ms_delay) (1 to 5000) |
296
+ | `wait_for_selector` | String | [wait_for_selector](https://html2img.com/docs/parameters/wait_for_selector) |
297
+ | `format` | String / Symbol | [format](https://html2img.com/docs/parameters/format): `"png"` (default) or `"pdf"` |
298
+ | `scale_to_fit` | Boolean | PDF only. Scale wide content down to the page width instead of clipping it. |
299
+
300
+ `screenshot` also accepts [`selector`](https://html2img.com/docs/parameters/selector) to crop the capture to a single element. `html` does not, since you control the markup.
301
+
302
+ Options are checked locally before a request is sent, so a typo or an out-of-range value raises an `ArgumentError` immediately rather than spending a credit on a rejected render:
303
+
304
+ ```ruby
305
+ client.html(document, widht: 1200)
306
+ # => ArgumentError: Unknown option(s): widht. Valid options are: css, dpi, format, ...
307
+
308
+ client.html(document, width: 9000)
309
+ # => ArgumentError: The width must be between 1 and 5000, got 9000.
310
+ ```
311
+
312
+ Custom fonts are loaded by referencing them with `<link>` tags in your HTML document head, or by linking a web font from the page you capture. Everything referenced by your markup is fetched by the renderer over the public internet, so `localhost` URLs will not resolve.
313
+
314
+ ## The response
315
+
316
+ Every render returns a frozen `Html2img::RenderResponse`:
317
+
318
+ ```ruby
319
+ response.success? # => true
320
+ response.id # => "abc123", the render id
321
+ response.url # => "https://i.html2img.com/abc123.png"
322
+ response.expires_at # => ISO 8601 String, or nil on paid plans
323
+ response.credits_remaining # => Integer, credits left after this call
324
+ response.status # => "processing" for async jobs
325
+ response.message # => String or nil
326
+ response.template # => the template slug, when applicable
327
+ response.processing? # => false
328
+ response.pdf? # => false
329
+ response.raw # => the full decoded JSON payload
330
+ ```
331
+
332
+ `to_s` is the URL, so a response drops straight into string interpolation or a view.
333
+
334
+ ## Asynchronous delivery
335
+
336
+ Synchronous requests have a 30 second budget. For captures likely to exceed it, pass a `webhook_url`. The API responds immediately with `status: "processing"` and no URL, then POSTs the final URL to your endpoint once rendering finishes. See the [`webhook_url` docs](https://html2img.com/docs/parameters/webhook-url).
337
+
338
+ ```ruby
339
+ response = client.screenshot(
340
+ "https://example.com/long-report",
341
+ fullpage: true,
342
+ webhook_url: hooks_html2img_url
343
+ )
344
+
345
+ if response.processing?
346
+ # the final URL will arrive at your webhook, not on this response
347
+ end
348
+ ```
349
+
350
+ ## Error handling
351
+
352
+ Every request-time failure raises an `Html2img::Error` or one of its subclasses. Rescue that single type to handle any error, or rescue a specific subclass. No raw Net::HTTP exception escapes the gem. Invalid arguments are reported before any request is sent, as a plain `ArgumentError`.
353
+
354
+ ```ruby
355
+ begin
356
+ response = client.html(document)
357
+ rescue Html2img::ValidationError => e
358
+ # 400 or 422: inspect the per-field messages
359
+ e.details.each { |field, messages| logger.warn("#{field}: #{messages.join(', ')}") }
360
+ rescue Html2img::InsufficientCreditsError => e
361
+ logger.error("Out of credits: #{e.credits_remaining}")
362
+ rescue Html2img::Error => e
363
+ e.status_code # => Integer or nil
364
+ e.error_code # => String or nil, the API "code" field
365
+ e.payload # => Hash, the decoded body
366
+ end
367
+ ```
368
+
369
+ | Exception | When |
370
+ | ---------------------------------- | --------------------------------------------------------------- |
371
+ | `Html2img::AuthenticationError` | 401, missing or invalid API key. |
372
+ | `Html2img::InsufficientCreditsError`| 402, no credits remaining. Exposes `credits_remaining`. |
373
+ | `Html2img::NotSubscribedError` | 403, no active subscription. |
374
+ | `Html2img::NotFoundError` | 404, for example an unknown template slug. |
375
+ | `Html2img::ValidationError` | 400 or 422, with `details` per field. |
376
+ | `Html2img::RateLimitError` | 429, rate or quota exceeded. Exposes `retry_after`. |
377
+ | `Html2img::TimeoutError` | 408 or 504, or the local timeout elapsed. |
378
+ | `Html2img::ServerError` | 5xx, an unexpected renderer error. |
379
+ | `Html2img::ConnectionError` | the request never reached a response. |
380
+ | `Html2img::Error` | base type for all of the above. |
381
+
382
+ Retries are left to you, so that a retry policy fits your application rather than the other way round. A 5xx or a `ConnectionError` is worth retrying; a 4xx is not.
383
+
384
+ ## Custom transports
385
+
386
+ All HTTP goes through a single object responding to `#call`, which is the seam for retry middleware, proxies, connection pooling and tests. The default is `Html2img::Transport`, built on Net::HTTP. To use Faraday instead:
387
+
388
+ ```ruby
389
+ class FaradayTransport
390
+ def initialize(connection) = @connection = connection
391
+
392
+ def call(method:, url:, headers:, body:, timeout:)
393
+ response = @connection.run_request(method.downcase.to_sym, url, body, headers) do |request|
394
+ request.options.timeout = timeout
395
+ end
396
+
397
+ [response.status, response.body.to_s]
398
+ end
399
+ end
400
+
401
+ client = Html2img::Client.new(transport: FaradayTransport.new(Faraday.new))
402
+ ```
403
+
404
+ The client still sends the `X-API-Key`, `Accept` and `Content-Type` headers on every request, and still maps every status onto the same typed errors.
405
+
406
+ In tests, a transport is the simplest way to avoid the network entirely:
407
+
408
+ ```ruby
409
+ transport = ->(**) { [200, '{"success": true, "url": "https://i.html2img.com/test.png"}'] }
410
+ client = Html2img::Client.new(api_key: "test", transport: transport)
411
+
412
+ expect(client.html("<h1>Hi</h1>").url).to eq("https://i.html2img.com/test.png")
413
+ ```
414
+
415
+ ## Command line
416
+
417
+ Installing the gem also installs an `html2img` executable:
418
+
419
+ ```bash
420
+ html2img test # verify your setup
421
+ html2img html card.html --width 1200 --height 630 -o card.png
422
+ html2img html - --format pdf -o report.pdf < report.html # read stdin
423
+ html2img screenshot https://example.com --fullpage -o shot.png
424
+ html2img screenshot https://example.com --selector "#hero" -o hero.png
425
+ html2img template invoice-image --data '{"number": 1042}'
426
+ ```
427
+
428
+ Every command prints the resulting URL, and `--out/-o` also saves the render locally. Run `html2img --help` for the full list.
429
+
430
+ ## Verifying your setup
431
+
432
+ Confirm your key and configuration by rendering a small test image:
433
+
434
+ ```bash
435
+ html2img test
436
+ ```
437
+
438
+ It prints the resulting image URL and your remaining credits, or a clear error if the key is missing or rejected. The check uses one credit. There is also a [testing guide](https://html2img.com/docs/testing) for the API itself.
439
+
440
+ ## Other languages and frameworks
441
+
442
+ The same API has worked guides and official packages for
443
+ [Python](https://github.com/html2img/html2img-python),
444
+ [Django](https://github.com/html2img/html2img-django),
445
+ [PHP](https://html2img.com/docs/usage/php),
446
+ [Laravel](https://html2img.com/docs/usage/laravel),
447
+ [Ruby on Rails](https://html2img.com/docs/usage/rails),
448
+ [JavaScript and Node.js](https://html2img.com/docs/usage/javascript),
449
+ [React](https://html2img.com/docs/usage/react),
450
+ [Vue](https://html2img.com/docs/usage/vue),
451
+ [WordPress](https://html2img.com/docs/usage/wordpress) and
452
+ [Statamic](https://html2img.com/docs/usage/statamic).
453
+
454
+ ## Development
455
+
456
+ ```bash
457
+ bundle install
458
+
459
+ bundle exec rspec # specs, no network and no credits spent
460
+ bundle exec rubocop # lint
461
+ bundle exec rake # both
462
+ ```
463
+
464
+ Publishing to RubyGems is covered in [PUBLISHING.md](PUBLISHING.md).
465
+
466
+ ## Links
467
+
468
+ [HTML to Image API](https://html2img.com) · [Screenshot API](https://html2img.com/screenshot-api/) · [HTML to PDF API](https://html2img.com/html-to-pdf/) · [Documentation](https://html2img.com/docs) · [Ruby guide](https://html2img.com/docs/usage/ruby) · [Templates](https://html2img.com/templates) · [Tools](https://html2img.com/tools) · [Features](https://html2img.com/features) · [Comparisons](https://html2img.com/compare) · [Articles](https://html2img.com/articles) · [Pricing](https://html2img.com/pricing)
469
+
470
+ ## Licence
471
+
472
+ MIT. See [LICENSE](LICENSE).
data/exe/html2img ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "html2img/cli"
5
+
6
+ exit(Html2img::CLI.run(ARGV))