{"id":15432428,"url":"https://github.com/noesya/kamifusen","last_synced_at":"2026-01-18T02:51:05.441Z","repository":{"id":42490279,"uuid":"368494817","full_name":"noesya/kamifusen","owner":"noesya","description":"Images in Ruby on Rails, as lightweight as possible","archived":false,"fork":false,"pushed_at":"2024-07-11T04:41:41.000Z","size":760,"stargazers_count":14,"open_issues_count":4,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-20T10:54:33.845Z","etag":null,"topics":["image","image-processing","responsive","ruby-on-rails","rubygem","webp"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/kamifusen","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/noesya.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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}},"created_at":"2021-05-18T10:51:09.000Z","updated_at":"2025-03-09T21:24:24.000Z","dependencies_parsed_at":"2024-11-17T01:05:46.917Z","dependency_job_id":"8bfb4fa6-288f-424f-891d-1589b6a10921","html_url":"https://github.com/noesya/kamifusen","commit_stats":{"total_commits":96,"total_committers":6,"mean_commits":16.0,"dds":"0.32291666666666663","last_synced_commit":"de59ea7cfd65388d18efad81604a0618cc18363f"},"previous_names":["sebousan/kamifusen"],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noesya%2Fkamifusen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noesya%2Fkamifusen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noesya%2Fkamifusen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/noesya%2Fkamifusen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/noesya","download_url":"https://codeload.github.com/noesya/kamifusen/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250432436,"owners_count":21429670,"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","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":["image","image-processing","responsive","ruby-on-rails","rubygem","webp"],"created_at":"2024-10-01T18:26:32.247Z","updated_at":"2025-10-08T18:21:00.342Z","avatar_url":"https://github.com/noesya.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kamifūsen\n\nImages in Ruby on Rails, as lightweight as possible!\n\n\n![Kamifūsen in Yamagata](image.jpg?raw=true)\n\n## Installation\n\nActive Storage must be properly installed, with a solution set for the background jobs (we use Delayed Job).\n- https://edgeguides.rubyonrails.org/active_storage_overview.html\n- https://edgeguides.rubyonrails.org/active_job_basics.html#job-execution\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'kamifusen'\n```\n\nAnd then execute:\n\n    $ bundle install\n\nOr install it yourself as:\n\n    $ gem install kamifusen\n\n## Usage\n\nSimply use `kamifusen_tag` instead of `image_tag` in your rails views.\n\nIn the views, use (where object is an active record model, and image is an active storage attachment):\n\n```erb\n\u003c%= kamifusen_tag object.image, alt: 'A nice image' %\u003e\n```\n\nIf you want to disable webp, in config/initializers/kamifusen.rb:\n\n```ruby\nKamifusen.with_webp = false\n```\n\nIf you render kamifusen tags inside a sanitized text, please make sure you allow these tags and attributes in `config/application.yml`:\n\n```ruby\nconfig.action_view.sanitized_allowed_tags = ['picture', 'source', 'img']\nconfig.action_view.sanitized_allowed_attributes = ['src', 'type', 'srcset', 'width', 'height', 'alt', 'sizes', 'loading', 'decoding']\n```\n\nYou can use the cache for the fragment, by setting\n```erb\n\u003c%= kamifusen_tag object.image, alt: 'A nice image', cached: true %\u003e\n```\n\n## What's the problem?\n\n### The initial situation\n\nWhen you use an image in a website, the basic code is:\n```html\n\u003cimg src=\"image.jpg\" alt=\"A nice image\"\u003e\n```\n\nwhich in rails can be generated with (assuming the image is an active storage blob):\n```erb\n\u003c%= image_tag object.image, alt: 'A nice image' %\u003e\n```\n\nIf the image is a 5 mo jpg file, 3500px width by 5000px height, then your page is very heavy, which is bad for the user and bad for the environment.\n\nThere are many things to do to improve the weight and the experience, as we'll now see.\n\n### Ways to optimize\n\n#### 1. Resize the image server side\n\nIf the screen you use is a mobile with a 375px wide screen, retina, then the image should be resized server side to a maximum of 750px. Ideally, if the image in the page is shown at 200px wide, then it should be resized to a 400px width. The technology used to manage that is the srcset.\n\nThe sizes are managed like:\n\n```html\n\u003cimg srcset=\"image-320w.jpg 320w,\n             image-480w.jpg 480w,\n             image-800w.jpg 800w\"\n     sizes=\"(max-width: 320px) 280px,\n            (max-width: 480px) 440px,\n            800px\"\n     src=\"image-800w.jpg\" alt=\"A nice image\"\u003e\n```\n\nAnd the retina like:\n\n```html\n\u003cimg srcset=\"image-320w.jpg,\n             image-480w.jpg 1.5x,\n             image-640w.jpg 2x\"\n     src=\"image-640w.jpg\" alt=\"A nice image\"\u003e\n ```\n\n#### 2. Remove any metadata (EXIF...) and optimize compression (tinyfy)\n\nImages can contain interesting metadata, which are heavy and useless in a standard web context. The technology used is imagemagick, through active storage.\n\n#### 3. Provide more efficient formats (webp, AVIF)\n\nWebp and AVIF are more efficient formats than jpg and png. They allow better compression with lower quality, but are not compatible with all browsers. The technology used is picture, allowing multiple sources to be defined and letting the browser choose the one it can handle.\n\n```html\n\u003cpicture\u003e\n  \u003csource type=\"image/avif\" srcset=\"image.avif\"\u003e\n  \u003csource type=\"image/webp\" srcset=\"image.webp\"\u003e\n  \u003cimg src=\"image.jpg\" alt=\"A nice image\"\u003e\n\u003c/picture\u003e\n```\n\n#### 4. Load and decode asynchronously  \n\n```\n\u003cimg decoding=\"async\" … /\u003e\n```\n\n### The final situation\n\nhttps://noesya.github.io/kamifusen/\n\nThe new helper is:\n\n```erb\n\u003c%= kamifusen_tag object.image, alt: 'A nice image' %\u003e\n```\n\nIt generates a code like:\n\n```html\n\u003cpicture\u003e\n  \u003csource srcset=\"image-800w.avif, image-1600w.avif 2x\" type=\"image/avif\"  media=\"(min-width: 800px)\"\u003e\n  \u003csource srcset=\"image-400w.avif, image-800w.avif 2x\"  type=\"image/avif\"  media=\"(min-width: 400px)\"\u003e\n  \u003csource srcset=\"image-800w.webp, image-1600w.webp 2x\" type=\"image/webp\"  media=\"(min-width: 800px)\"\u003e\n  \u003csource srcset=\"image-400w.webp, image-800w.webp 2x\"  type=\"image/webp\"  media=\"(min-width: 400px)\"\u003e\n  \u003csource srcset=\"image-800w.jpg, image-1600w.jpg 2x\"   type=\"image/jpg\"   media=\"(min-width: 800px)\"\u003e\n  \u003csource srcset=\"image-400w.jpg, image-800w.jpg 2x\"    type=\"image/jpg\"   media=\"(min-width: 400px)\"\u003e\n  \u003cimg src=\"image-800.jpg\" alt=\"A nice image\" srcset=\"image-800.jpg, image-1600.jpg 2x\" loading=\"lazy\"\u003e\n\u003c/picture\u003e\n```\n\n### Parameters\n\nYou can set different parameters : \n\n```\n    class: \"img_class\",\n    alt: \"alt\",\n    height: height,\n    width: width,\n    sizes: sizes,\n    active_storage_direct_url: direct_url,\n    async: async\n```\n\nExample of sizes parameter : \n\n```\nsizes: {\n    '(max-width: 576px)': '315px',\n    '(max-width: 991px)': '210px',\n    '(max-width: 1199px)': '290px',\n    '(max-width: 1439px)': '350px',\n    '(min-width: 1440px)': '420px'\n}\n```\n\n## References\n\n- https://developer.mozilla.org/fr/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images\n- https://cloudfour.com/thinks/responsive-images-101-definitions/\n- https://www.industrialempathy.com/posts/image-optimizations/\n- https://github.com/google/eleventy-high-performance-blog/blob/60902bfdaf764f5b16b2af62cf10f63e0e74efbc/README.md#images\n- http://rbuchberger.github.io/jekyll_picture_tag/\n- https://vitobotta.com/2020/09/24/resize-and-optimise-images-on-upload-with-activestorage/\n- https://www.filamentgroup.com/lab/load-css-simpler/\n- https://mattwilcox.net/web-development/keeping-srcset-and-sizes-under-control\n- https://developers.google.com/web/fundamentals/design-and-ux/responsive/images?hl=fr\n- https://www.smashingmagazine.com/2014/05/responsive-images-done-right-guide-picture-srcset/\n- https://web.dev/use-srcset-to-automatically-choose-the-right-image/\n- https://web.dev/use-imagemin-to-compress-images/\n- https://code.luasoftware.com/tutorials/bootstrap/responsive-image-with-srcset-using-bootstrap-breakpoints/\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then 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/noesya/kamifusen. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/kamifusen/blob/master/CODE_OF_CONDUCT.md).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the Kamifusen project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/kamifusen/blob/master/CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoesya%2Fkamifusen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoesya%2Fkamifusen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoesya%2Fkamifusen/lists"}