{"id":30141767,"url":"https://github.com/jamedjo/himg","last_synced_at":"2025-10-08T17:18:09.516Z","repository":{"id":288706918,"uuid":"968979475","full_name":"Jamedjo/himg","owner":"Jamedjo","description":"You give it HTML and get back an image - perfect for dynamic OpenGraph social image previews.","archived":false,"fork":false,"pushed_at":"2025-08-21T23:23:55.000Z","size":552,"stargazers_count":88,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-10-07T20:44:48.853Z","etag":null,"topics":["browserless","image-generation","opengraph","rails","rails-renderer","renderer","ruby-gem"],"latest_commit_sha":null,"homepage":"https://himg.jamedjo.co.uk/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jamedjo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-19T05:38:56.000Z","updated_at":"2025-09-08T16:23:12.000Z","dependencies_parsed_at":"2025-07-30T13:13:56.097Z","dependency_job_id":"f93e56b9-5e37-4ffe-9338-092170413421","html_url":"https://github.com/Jamedjo/himg","commit_stats":null,"previous_names":["jamedjo/himg"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/Jamedjo/himg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jamedjo%2Fhimg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jamedjo%2Fhimg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jamedjo%2Fhimg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jamedjo%2Fhimg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jamedjo","download_url":"https://codeload.github.com/Jamedjo/himg/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jamedjo%2Fhimg/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278981540,"owners_count":26079644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browserless","image-generation","opengraph","rails","rails-renderer","renderer","ruby-gem"],"created_at":"2025-08-11T05:17:47.558Z","updated_at":"2025-10-08T17:18:09.510Z","avatar_url":"https://github.com/Jamedjo.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"logo.svg\" alt=\"Himg\" width=\"200\"\u003e\n  \u003cdiv\u003e\n    \u003cimg src=\"tagline.svg\" alt=\"The Hyper Image Generator\" width=\"600\"\u003e\n  \u003c/div\u003e\n\n  \u003cp\u003eYou give it HTML and it gives back an image!\u003c/p\u003e\n\n  \u003cp\u003eParses HTML/CSS, fetches nested resources, renders an image. No browser, no fuss.\u003c/p\u003e\n\n  \u003cp\u003ePerfect for OpenGraph images - stop losing clicks to boring links by adding a rich image preview that showcases your content.\u003c/p\u003e\n\u003c/div\u003e\n\n![Mockup showing HTML being transformed into a WhatsApp preview](/readme_hero.svg)\n\n## Quickstart\n\n### Command Line\n\n```bash\ngem install himg\n\nhimg screenshot path/to/your.html screenshot.png\nhimg screenshot https://himg.jamedjo.co.uk himg.png --width=1024 --verbose --no-truncate\necho '\u003ch1\u003eHello Image\u003c/h1\u003e' | himg screenshot --stdin output.png\n```\n\n### Ruby\n\n```ruby\npng = Himg.render(\"\u003c!DOCTYPE html\u003e\u003cbody style='background:blue;'\u003e\u003c/body\u003e\")\nFile.open(\"blue.png\", \"wb\"){|f| f.write(png) }\n```\n\n```ruby\npng = Himg.render(\"\u003c!DOCTYPE html\u003e\u003ch1\u003eSnapshot\u003c/h1\u003e\", width: 89, height: 5, truncate: false)\nFile.open(\"dynamic_height.png\", \"wb\"){|f| f.write(png) }\n```\n\n### Rails\n\nSimply add a `show.himg.erb`!\n\n```erb\n\u003cdiv\u003e\u003c%= @username %\u003e\u003c/div\u003e\n```\n\n### OpenGraph Meta Tags\n\nOpenGraph tags let messenger apps and social media sites know to use your generated image as a thumbnail card for your website.\n\n```html\n\u003cmeta property=\"og:title\" content=\"\u003c%= @user.username %\u003e\" /\u003e\n\u003cmeta property=\"og:description\" content=\"\u003c%= @user.tagline %\u003e\" /\u003e\n\u003cmeta property=\"og:image\" content=\"\u003c%= user_url(@user.username, format: :png) %\u003e\" /\u003e\n```\n\n![WhatsApp preview comparison showing plain link vs rich OpenGraph preview](/readme_opengraph_comparison.png)\n\n# Usage\n\nInstall the gem and add to the application's Gemfile by executing:\n\n```bash\nbundle add himg\n```\n\n## Configuration\n\n|Option | Description | Type | Default |\n|-|-|-|-|\n|width | Sets the width of the rendered content. | integer | 720 |\n|height | Sets the desired height of the rendered output. | integer | 405 |\n|truncate | Keeps the image height fixed instead of expanding to include the full page | bool | true |\n|verbose | Enables detailed logging for debugging and profiling. | bool | false |\n|base_url | Where relative paths are relative to for linked resources (stylesheets, images, fonts, etc) | string | nil |\n|disable_fetch | Disables fetching linked resources from disk and network| bool | false |\n|fetch_timeout | Timeout in seconds for fetching resources | float | 10.0 |\n|gpu | Use GPU renderer instead of CPU renderer | bool | false |\n|http_headers | Headers sent when the CLI fetches the SOURCE HTML (CLI only) | hash | nil |\n|stdin | Read HTML content from stdin instead of a file (CLI only) | bool | false |\n\n\n### Passing options to a Rails view template\n\nOptions can be set at a controller level using the `himg_config` helper method:\n```ruby\nclass UsersController \u003c ActionController::Base\n  himg_config(verbose: true)\nend\n```\n\nThese can be overridden at a view level:\n```ruby\nclass UsersController \u003c ActionController::Base\n  def show\n    himg_config(width: params[:w]) if params[:w]\n\n    @user = User.new\n  end\n```\n\n### Rails manual render\n\nIf you prefer you could also use `render himg: \"\u003cdiv\u003eMy Data\u003c/div\u003e\"` instead, but should be careful with untrusted input if constructing HTML manually.\n\nOptions can then be passed directly to the manual render:\n```ruby\nrender himg: '\u003c!DOCTYPE html\u003e', truncate: false\n```\n\nAlternatively you can pass in options which have been set with `himg_config`:\n```ruby\nrender himg: '\u003c!DOCTYPE html\u003e', config: himg_config\n```\n\n### Rails `respond_to`\n\nTo be explicit in the controller you can also use `respond_to` style:\n\n```ruby\nrespond_to do |format|\n  format.html\n  format.himg\nend\n```\n\nYou can also use this combined with a manual render:\n```ruby\nrespond_to do |format|\n  format.html\n  format.himg { render himg: '\u003ch1 style=\"text-align: center;\"\u003eRecent Users\u003c/h1\u003e' }\n  format.png { render himg: '\u003cdiv\u003eFor .png URLs\u003c/div\u003e' }\nend\n```\n\n### Rails caching\n\nYou can cache images to save re-generating them for later requests.\n\nTo serve the cached response you'll need to use `send_data` to send the png data as binary content.\n\n```ruby\nformat.png do\n  cache_key = [\"opengraph-your-resource\", id_or_data].join(\"/\")\n\n  cached_image = Rails.cache.fetch(cache_key, expires_in: 30.days) do\n    render_to_string(template: 'your_resource/show', formats: [:himg])\n  end\n\n  send_data cached_image, type: 'image/png', disposition: 'inline'\nend\n```\n\nYou can also speed up the render time by minimizing resources to fetch over the network, for example installing fonts locally or ensuring background images are read from disk as a file rather than fetched over http.\n\n# Supported HTML and CSS\n\nHimg supports a large subset of the HTML and CSS you'd need to get by, but not all elements or properties are supported.\n\nFor a full list, see our [snapshot of the blitz.is status page](https://github.com/Jamedjo/himg/issues/2).\n\nIf something you'd like supported is missing and is available [upstream on Blitz](https://blitz.is/status), please [open an issue](https://github.com/Jamedjo/himg/issues/new).\n\n|HTML|Status|\n|-|-|\n|`Generic HTML5 elements`|✅ Supported|\n|`\u003cstyle\u003e`|✅ Supported|\n|`\u003clink rel=\"stylesheet\"\u003e`|✅ Supported|\n|`\u003clink rel=\"icon\"\u003e`|❌ Not supported|\n|`\u003cimg src=\"\"\u003e`|✅ Supported|\n|`\u003cimg srcset=\"\"\u003e`|❌ Not supported|\n|`\u003cpicture\u003e`|❌ Not supported|\n|`\u003csvg\u003e`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`\u003ch1\u003e-\u003ch6\u003e`|✅ Supported|\n|`\u003cul\u003e/\u003col\u003e`|✅ Supported|\n|`\u003ci\u003e/\u003cem\u003e`|✅ Supported|\n|`\u003cb\u003e/\u003cstrong\u003e`|✅ Supported|\n|`\u003cu\u003e`|✅ Supported|\n|`\u003ccenter\u003e`|✅ Supported|\n|`\u003cpre\u003e/\u003cblockquote\u003e`|✅ Supported|\n|`\u003ca\u003e`|✅ Supported|\n|`\u003cbr\u003e`|✅ Supported|\n|`\u003chr\u003e`|❌ Not supported|\n|`\u003cdetails\u003e/\u003csummary\u003e`|❌ Not supported|\n|`\u003ctable\u003e`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`Form Controls`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n\n|CSS|Status|\n|-|-|\n|`display:inline, display:block, display:inline-block`|✅ Supported|\n|`display:none`|✅ Supported|\n|`display:flex`|✅ Supported|\n|`display:grid`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`display:table`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`display:contents`|❌ Not supported|\n|`position:relative, position:absolute`|✅ Supported|\n|`position:static, position:fixed, position:sticky`|❌ Not supported|\n|`overflow`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`z-index`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`box-sizing`|✅ Supported|\n|`float`|❌ Not supported|\n|`content (::before / ::after)`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`opacity,  visibility`|✅ Supported|\n|`width, height`|✅ Supported|\n|`min-width, max-width, min-height, max-height`|✅ Supported|\n|`padding, margin, gap`|✅ Supported|\n|`border`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`@font-face, font-size, font-family`|✅ Supported|\n|`font-weight, font-style, font-stretch`|✅ Supported|\n|`font-display, font-variant, font-feature-settings`|❌ Not supported|\n|`color, text-align, line-height, text-decoration`|✅ Supported|\n|`letter-spacing, overlap-wrap, word-wrap, word-break`|✅ Supported|\n|`vertical-align, text-transform, text-overflow`|❌ Not supported|\n|`border`|⚠️ [Partial support](https://github.com/Jamedjo/himg/issues/2)|\n|`background-color, background-image`|✅ Supported|\n|`background-size, background-position`|✅ Supported|\n|`background-repeat, background-clip, background-origin`|✅ Supported|\n|`background-attachment`|❌ Not supported|\n|`box-shadow`|✅ Supported|\n|`filter`|❌ Not supported|\n\n# How it works\n\nNo browser, just basics!\n\nHimg calls through to the amazing [blitz](https://github.com/DioxusLabs/blitz) library, which uses [Stylo](https://github.com/servo/stylo) to parse the CSS, [servo/html5ever](https://github.com/servo/html5ever) to parse the HTML, fetches network resources, builds a scene graph and hands over to [vello](https://github.com/linebender/vello) to render an image.\n\nInteraction between Ruby \u0026 Rust is done with the help of `magnus`, `rb_sys` and lots of glue code from the `oxidize-rb` team.\n\nTo 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.\n\n## CAVEATS\n\n1. This is **pre-alpha** software, don't expect it to work perfectly yet.\n2. Performance needs tuning. Both in the underlying [Blitz](https://github.com/DioxusLabs/blitz) library and how data is passed between Rust and Ruby\n3. Network requests can be made: don't use this library with untrusted inputs. Use `disable_fetch` if you don't need to fetch any resources.\n4. file:// URLs are resolved: this could expose files on your computer. Use `disable_fetch` if you don't need to fetch any resources.\n\n# Development\n\n1. Run `bin/setup` to install dependencies.\n2. Run `rake spec` to run the tests with the default development setup\n3. Run `appraisal rake spec` to run tests against different versions of rails and to confirm that the gem works in a plain ruby environment\n4. Run `bin/console` for an interactive prompt that will allow you to experiment.\n5. Run `RAILS_ENV=development bundle exec spec/dummy/dummy_rails server` to check the dummy app.\n  - http://localhost:3000/users/jamedjo.png will display an opengraph compatible png\n  - http://localhost:3000/users/jamedjo.himg will also render the same png\n  - http://localhost:3000/users/jamedjo will render an HTML page with opengraph meta tags\n6. To install this gem onto your local machine, run `bundle exec rake install`.\n7. To simulate a headless server environment without a GPU, use `WGPU_BACKEND=empty bundle exec rspec`\n8. To profile performance with flamegraphs, run `bin/profile spec/fixtures/profile_test.html`\n\n### Run cargo example directly generate image in Rust\n\n```bash\nbundle exec cargo run --example file\nbundle exec cargo run --example file -- path/to/file.html\n```\n## Releases\n\nTo release a new version:\n1. Run `rake bump:patch` to update the version numbers in `version.rb` and `ext/himg/Cargo.toml`.\n3. Run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/jamedjo/himg.\n\n## License\n\nCopyright (c) 2025 James Edwards-Jones\n\nThis project is dual licenced under both the MIT and Apache 2.0 terms.\n\nSee: [MIT License](https://opensource.org/licenses/MIT) and [APACHE 2.0 License](http://www.apache.org/licenses/LICENSE-2.0)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamedjo%2Fhimg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamedjo%2Fhimg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamedjo%2Fhimg/lists"}