himg 0.0.4 → 0.0.5
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/Cargo.lock +1 -1
- data/README.md +51 -6
- data/ext/himg/Cargo.toml +1 -1
- data/ext/himg/examples/file.rs +4 -3
- data/ext/himg/src/html_to_image.rs +3 -1
- data/ext/himg/src/lib.rs +5 -2
- data/ext/himg/src/options.rs +1 -0
- data/ext/himg/src/renderer.rs +7 -3
- data/lib/himg/railtie/controller_config.rb +31 -0
- data/lib/himg/railtie/template_handler.rb +2 -2
- data/lib/himg/railtie.rb +13 -2
- data/lib/himg/version.rb +1 -1
- data/lib/himg.rb +3 -2
- data/sig/himg.rbs +11 -3
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bd4c145135ae494ac36cefa1aade53d31d5314e54ce582126c76484115815f7
|
4
|
+
data.tar.gz: f631474fc095ea589af509e8c27e0386efb102868b225bad5be708d10e0b682a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c666c9444a47522f1843e34c3c065ee06e15d2995a5cbe0a537ab17acb96bfdb08414735c5c468ea47609169739f37bda38c4e74a745f12b643c45a1eaa1ded8
|
7
|
+
data.tar.gz: e629137b2de381bf1ed7f5cf5d6caa694372172056e9f1c7c80d6d879011641162ecf486863e51147349133ef1a2e189c13b13406d19bbd0971c9f3d9926d810
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.0.5] - 2025-04-22
|
4
|
+
|
5
|
+
- Can configure `render himg: ""` with options including `width:`, `height:`,
|
6
|
+
`truncate:` and `verbose:`.
|
7
|
+
- Can use `himg_config` helper methods at controller level and action level
|
8
|
+
to set `@_himg_config`, which can then be passed to the renderer with
|
9
|
+
`render himg: "<!DOCTYPE html>", config: himg_config` as an alternative to
|
10
|
+
specifying config options individually to `ActionController::Rendering#render`.
|
11
|
+
- `himg_config` helpers can also be used to control the configuration of
|
12
|
+
template based default render, when not calling render manually within the
|
13
|
+
controller. This works because the template handler can access `@_himg_config`.
|
14
|
+
- Can use string width / height with Himg.render
|
15
|
+
- Disable detailed log timings by default. Can re-enable with verbose: true.
|
16
|
+
There is still some logging from blitz-net#fetch for http requests and for
|
17
|
+
blitz-html::DocumentHtmlParser#finish on unexpected tokens.
|
18
|
+
|
3
19
|
## [0.0.4] - 2025-04-22
|
4
20
|
|
5
21
|
- Allow `width`, `height` and `truncate` to be passed to the render function.
|
data/Cargo.lock
CHANGED
data/README.md
CHANGED
@@ -16,7 +16,6 @@ In Rails this will mean you can process user.himg.erb to display an image includ
|
|
16
16
|
4. Network requests can be made: don't use this library with untrusted inputs.
|
17
17
|
5. file:// URLs are resolved: this could expose files on your computer.
|
18
18
|
6. Native extensions are not yet being published for different os/arch
|
19
|
-
7. Verbose logging is hardcoded
|
20
19
|
|
21
20
|
## Installation
|
22
21
|
|
@@ -37,11 +36,13 @@ gem install himg
|
|
37
36
|
### Ruby
|
38
37
|
|
39
38
|
```ruby
|
40
|
-
png = Himg.render("
|
39
|
+
png = Himg.render("<!DOCTYPE html><body style='background:blue;'></body>")
|
40
|
+
File.open("blue.png", "wb"){|f| f.write(png) }
|
41
41
|
```
|
42
42
|
|
43
43
|
```ruby
|
44
|
-
png = Himg.render("
|
44
|
+
png = Himg.render("<!DOCTYPE html><h1>Snapshot</h1>", width: 89, height: 5, truncate: false)
|
45
|
+
File.open("dynamic_height.png", "wb"){|f| f.write(png) }
|
45
46
|
```
|
46
47
|
|
47
48
|
### Rails
|
@@ -62,13 +63,46 @@ Once you've added a view template for your resource, you can use it to generate
|
|
62
63
|
<meta property="og:image" content="<%= user_url(@user.username, format: :png) %>" />
|
63
64
|
```
|
64
65
|
|
65
|
-
###
|
66
|
+
### Configuration Options
|
66
67
|
|
67
|
-
|
68
|
+
Options: `width`, `height`, `verbose`, `truncate`.
|
69
|
+
|
70
|
+
### Passing options to a Rails view template
|
71
|
+
|
72
|
+
Options can be set at a controller level using the `himg_config` helper method:
|
73
|
+
```ruby
|
74
|
+
class UsersController < ActionController::Base
|
75
|
+
himg_config(verbose: true)
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
These can be overridden at a view level:
|
80
|
+
```ruby
|
81
|
+
class UsersController < ActionController::Base
|
82
|
+
def show
|
83
|
+
himg_config(width: params[:w]) if params[:w]
|
84
|
+
|
85
|
+
@user = User.new
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
### Rails manual render
|
68
90
|
|
69
91
|
If you prefer you could also use `render himg: "<div>My Data</div>"` instead, but should be careful with untrusted input if constructing HTML manually.
|
70
92
|
|
71
|
-
|
93
|
+
Options can then be passed directly to the manual render:
|
94
|
+
```ruby
|
95
|
+
render himg: '<!DOCTYPE html>', truncate: false
|
96
|
+
```
|
97
|
+
|
98
|
+
Alternatively you can pass in options which have been set with `himg_config`:
|
99
|
+
```ruby
|
100
|
+
render himg: '<!DOCTYPE html>', config: himg_config
|
101
|
+
```
|
102
|
+
|
103
|
+
### Rails `respond_to`
|
104
|
+
|
105
|
+
To be explicit in the controller you can also use `respond_to` style:
|
72
106
|
|
73
107
|
```ruby
|
74
108
|
respond_to do |format|
|
@@ -77,6 +111,7 @@ respond_to do |format|
|
|
77
111
|
end
|
78
112
|
```
|
79
113
|
|
114
|
+
You can also use this combined with a manual render:
|
80
115
|
```ruby
|
81
116
|
respond_to do |format|
|
82
117
|
format.html
|
@@ -85,6 +120,16 @@ respond_to do |format|
|
|
85
120
|
end
|
86
121
|
```
|
87
122
|
|
123
|
+
### How it works
|
124
|
+
|
125
|
+
No browser, just basics!
|
126
|
+
|
127
|
+
Himg calls through to the amazing blitz library, which uses Stylo to parse the CSS, servo/html5ever to parse the HTML, fetches network resources, builds a scene graph and hands over to vello to render an image.
|
128
|
+
|
129
|
+
Interaction between Ruby & Rust is done with the help of `magnus`, `rb_sys` and lots of glue code from the `oxidize-rb` team.
|
130
|
+
|
131
|
+
To play nicely with Rails a template handler is registered, which Rails' `default_render` method automatically calls when the corresponding view is found. This can be `show.himg` for a static image, or `show.himg.erb` to use variables from the controller. Additionally a Renderer is available with `render himg: 'content'` in case a view template is not needed.
|
132
|
+
|
88
133
|
### Run directly from the command line to output an image
|
89
134
|
|
90
135
|
```bash
|
data/ext/himg/Cargo.toml
CHANGED
data/ext/himg/examples/file.rs
CHANGED
@@ -21,7 +21,7 @@ async fn main() {
|
|
21
21
|
|
22
22
|
// Fetch HTML from path
|
23
23
|
let html = std::fs::read_to_string(&path_string).unwrap();
|
24
|
-
logger.log("
|
24
|
+
logger.log("Read HTML");
|
25
25
|
|
26
26
|
// Configure viewport dimensions
|
27
27
|
let options = Options {
|
@@ -31,20 +31,21 @@ async fn main() {
|
|
31
31
|
hidpi_scale: 1.0,
|
32
32
|
},
|
33
33
|
truncate: false,
|
34
|
+
verbose: true,
|
34
35
|
color_scheme: ColorScheme::Light,
|
35
36
|
allow_net_requests: true, //TODO: Implement using this
|
36
37
|
};
|
37
38
|
|
38
39
|
// Render to Image
|
39
40
|
let base_url = format!("file://{}", path_string.clone());
|
40
|
-
let
|
41
|
+
let render_output = html_to_image(&html, Some(base_url), options, &mut logger).await;
|
41
42
|
|
42
43
|
// Determine output path, and open a file at that path.
|
43
44
|
let out_path = compute_filename(&path_string);
|
44
45
|
let mut file = File::create(&out_path).unwrap();
|
45
46
|
|
46
47
|
// Encode buffer as PNG and write it to a file
|
47
|
-
write_png(&mut file, &buffer,
|
48
|
+
write_png(&mut file, &render_output.buffer, render_output.image_size.scaled_width(), render_output.image_size.scaled_height()).unwrap();
|
48
49
|
logger.log("Wrote out png");
|
49
50
|
|
50
51
|
logger.log_total_time("\nDone");
|
@@ -76,7 +76,9 @@ pub async fn html_to_image(
|
|
76
76
|
};
|
77
77
|
logger.log("Calculated render dimensions from document");
|
78
78
|
|
79
|
-
|
79
|
+
if options.verbose {
|
80
|
+
println!("Screenshot is ({}x{})",render_size.scaled_width(), render_size.scaled_height());
|
81
|
+
}
|
80
82
|
|
81
83
|
// Render document to RGBA buffer
|
82
84
|
let buffer = render_to_buffer(
|
data/ext/himg/src/lib.rs
CHANGED
@@ -6,9 +6,11 @@ pub mod writer;
|
|
6
6
|
pub mod logger;
|
7
7
|
|
8
8
|
pub use renderer::render_blocking;
|
9
|
+
pub use image_size::ImageSize;
|
10
|
+
pub use options::Options;
|
11
|
+
pub use html_to_image::html_to_image;
|
12
|
+
pub use writer::write_png;
|
9
13
|
|
10
|
-
use crate::image_size::ImageSize;
|
11
|
-
use crate::options::Options;
|
12
14
|
use blitz_traits::ColorScheme;
|
13
15
|
use magnus::{function, prelude::*, ExceptionClass, Error, Ruby, RString, RHash};
|
14
16
|
|
@@ -28,6 +30,7 @@ impl Options {
|
|
28
30
|
hidpi_scale: 1.0,
|
29
31
|
},
|
30
32
|
truncate: Self::get_option(hash, "truncate", true)?,
|
33
|
+
verbose: Self::get_option(hash, "verbose", false)?,
|
31
34
|
color_scheme: ColorScheme::Light,
|
32
35
|
allow_net_requests: true, //TODO: Implement using this
|
33
36
|
};
|
data/ext/himg/src/options.rs
CHANGED
data/ext/himg/src/renderer.rs
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
use crate::html_to_image::html_to_image;
|
2
2
|
use crate::options::Options;
|
3
3
|
use crate::writer::write_png;
|
4
|
-
use crate::logger::{TimedLogger};
|
4
|
+
use crate::logger::{Logger, NullLogger, TimedLogger};
|
5
5
|
|
6
6
|
pub fn render_blocking(html: String, options: Options) -> Result<Vec<u8>, std::io::Error> {
|
7
7
|
let runtime = tokio::runtime::Runtime::new()?;
|
@@ -11,12 +11,16 @@ pub fn render_blocking(html: String, options: Options) -> Result<Vec<u8>, std::i
|
|
11
11
|
|
12
12
|
// render_to_bytes, render_to_string, render_to_file, render_to_io
|
13
13
|
pub async fn render(html: String, options: Options) -> Result<Vec<u8>, std::io::Error> {
|
14
|
-
let mut logger =
|
14
|
+
let mut logger: Box<dyn Logger> = if options.verbose {
|
15
|
+
Box::new(TimedLogger::init())
|
16
|
+
} else {
|
17
|
+
Box::new(NullLogger{})
|
18
|
+
};
|
15
19
|
|
16
20
|
// Render to Image
|
17
21
|
//let base_url = format!("file://{}", path_string.clone());
|
18
22
|
let base_url = None;
|
19
|
-
let render_output = html_to_image(&html, base_url, options, &mut logger).await;
|
23
|
+
let render_output = html_to_image(&html, base_url, options, &mut *logger).await;
|
20
24
|
|
21
25
|
// Determine output path, and open a file at that path.
|
22
26
|
let mut output_buffer: Vec<u8> = Vec::new();
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Himg
|
2
|
+
class Railtie
|
3
|
+
module ControllerConfig
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before_action :_apply_himg_config
|
8
|
+
end
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
def himg_config(options = {})
|
12
|
+
@_himg_global_config ||= {}
|
13
|
+
@_himg_global_config.merge!(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def _himg_global_config
|
17
|
+
@_himg_global_config&.dup || {}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def himg_config(options = {})
|
22
|
+
@_himg_config.merge!(options)
|
23
|
+
@_himg_config
|
24
|
+
end
|
25
|
+
|
26
|
+
def _apply_himg_config
|
27
|
+
@_himg_config = self.class._himg_global_config
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -4,7 +4,7 @@ module Himg
|
|
4
4
|
class TemplateHandler
|
5
5
|
def self.call(_template, source)
|
6
6
|
<<-CODE
|
7
|
-
Himg.render(#{source.inspect})
|
7
|
+
Himg.render(#{source.inspect}, **@_himg_config)
|
8
8
|
CODE
|
9
9
|
end
|
10
10
|
end
|
@@ -21,7 +21,7 @@ module Himg
|
|
21
21
|
output = begin
|
22
22
|
#{preprocessed_view_code}
|
23
23
|
end
|
24
|
-
Himg.render(output)
|
24
|
+
Himg.render(output, **@_himg_config)
|
25
25
|
CODE
|
26
26
|
end
|
27
27
|
end
|
data/lib/himg/railtie.rb
CHANGED
@@ -29,10 +29,21 @@ module Himg
|
|
29
29
|
end
|
30
30
|
|
31
31
|
initializer "himg.controller_renderer" do
|
32
|
-
ActionController::Renderers.add :himg do |obj,
|
33
|
-
|
32
|
+
ActionController::Renderers.add :himg do |obj, options = {}|
|
33
|
+
configured_options = options[:config] || {}
|
34
|
+
direct_options = options.symbolize_keys.slice(*Himg::RENDER_OPTIONS)
|
35
|
+
merged_options = configured_options.merge(direct_options)
|
36
|
+
|
37
|
+
png_data = Himg.render(obj, **merged_options)
|
34
38
|
send_data png_data, type: "image/png", disposition: "inline"
|
35
39
|
end
|
36
40
|
end
|
41
|
+
|
42
|
+
initializer 'himg.controller_config' do
|
43
|
+
require "himg/railtie/controller_config"
|
44
|
+
ActiveSupport.on_load(:action_controller) do
|
45
|
+
include Himg::Railtie::ControllerConfig
|
46
|
+
end
|
47
|
+
end
|
37
48
|
end
|
38
49
|
end
|
data/lib/himg/version.rb
CHANGED
data/lib/himg.rb
CHANGED
@@ -16,9 +16,10 @@ end
|
|
16
16
|
#
|
17
17
|
# Converts HTML to an Image for a minimal subset of HTML and CSS
|
18
18
|
module Himg
|
19
|
+
RENDER_OPTIONS = %i[width height truncate verbose].freeze
|
19
20
|
class Error < StandardError; end
|
20
21
|
|
21
|
-
def self.render(html, width: 720, height: 405, truncate: true)
|
22
|
-
render_to_string(html, "width" => width, "height" => height, "truncate" => truncate)
|
22
|
+
def self.render(html, width: 720, height: 405, truncate: true, verbose: false)
|
23
|
+
render_to_string(html, "width" => width.to_i, "height" => height.to_i, "truncate" => truncate, "verbose" => verbose)
|
23
24
|
end
|
24
25
|
end
|
data/sig/himg.rbs
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
module Himg
|
2
2
|
VERSION: String
|
3
3
|
|
4
|
-
class
|
5
|
-
def initialize: (Integer width, Integer height) -> void
|
6
|
-
def render: (String html) -> String
|
4
|
+
class Error < StandardError
|
7
5
|
end
|
6
|
+
|
7
|
+
def self.render: (
|
8
|
+
String html,
|
9
|
+
?width: Integer,
|
10
|
+
?height: Integer,
|
11
|
+
?truncate: bool,
|
12
|
+
?verbose: bool
|
13
|
+
) -> String
|
14
|
+
|
15
|
+
def self.render_to_string: (String html, Hash[string, untyped] options) -> String
|
8
16
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: himg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Edwards-Jones
|
@@ -196,6 +196,7 @@ files:
|
|
196
196
|
- gemfiles/rails_8.gemfile.lock
|
197
197
|
- lib/himg.rb
|
198
198
|
- lib/himg/railtie.rb
|
199
|
+
- lib/himg/railtie/controller_config.rb
|
199
200
|
- lib/himg/railtie/template_handler.rb
|
200
201
|
- lib/himg/version.rb
|
201
202
|
- sig/himg.rbs
|