{"id":14992234,"url":"https://github.com/jay3332/ril","last_synced_at":"2025-04-09T18:18:17.435Z","repository":{"id":49306410,"uuid":"517200884","full_name":"jay3332/ril","owner":"jay3332","description":"Rust Imaging Library: A high-level imaging crate for Rust.","archived":false,"fork":false,"pushed_at":"2024-04-05T14:10:52.000Z","size":117069,"stargazers_count":70,"open_issues_count":13,"forks_count":8,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-04-25T23:03:48.237Z","etag":null,"topics":["gif","graphics","image","image-manipulation","image-processing","images","jpeg","png","ril","rust"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/ril","language":"Rust","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/jay3332.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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}},"created_at":"2022-07-24T01:32:57.000Z","updated_at":"2024-06-09T02:26:36.267Z","dependencies_parsed_at":"2023-02-18T13:30:40.335Z","dependency_job_id":"bf981749-5f0f-4906-b030-880125fc3c89","html_url":"https://github.com/jay3332/ril","commit_stats":{"total_commits":239,"total_committers":5,"mean_commits":47.8,"dds":0.301255230125523,"last_synced_commit":"d2575fbac7d524239813f3df8d56cfb1ad6e4647"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jay3332%2Fril","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jay3332%2Fril/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jay3332%2Fril/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jay3332%2Fril/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jay3332","download_url":"https://codeload.github.com/jay3332/ril/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248085326,"owners_count":21045139,"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":["gif","graphics","image","image-manipulation","image-processing","images","jpeg","png","ril","rust"],"created_at":"2024-09-24T15:00:53.092Z","updated_at":"2025-04-09T18:18:17.414Z","avatar_url":"https://github.com/jay3332.png","language":"Rust","funding_links":[],"categories":["Image and Video Processing"],"sub_categories":[],"readme":"\u003ch1 align=\"center\" id=\"ril\"\u003e\n  \u003ca href=\"https://jay3332.tech/projects/ril\"\u003eril\u003c/a\u003e\n\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n  \u003csup\u003e\n    \u003cb\u003eR\u003c/b\u003eust \u003cb\u003eI\u003c/b\u003emaging \u003cb\u003eL\u003c/b\u003eibrary: A performant and high-level Rust imaging crate.\n    \u003cbr\u003e\n    \u003ca href=\"https://docs.rs/ril\"\u003e\u003cb\u003eDocumentation\u003c/b\u003e\u003c/a\u003e •\n    \u003ca href=\"https://crates.io/crates/ril\"\u003e\u003cb\u003eCrates.io\u003c/b\u003e\u003c/a\u003e •\n    \u003ca href=\"https://discord.gg/FqtZ6akWpd\"\u003e\u003cb\u003eDiscord\u003c/b\u003e\u003c/a\u003e\n  \u003c/sup\u003e\n\u003c/p\u003e\n\n## ril v0.10 has been published to crates.io!\nThis is the biggest release since the beginning of ril and includes a lot of breaking changes.\n\n### Notable Additions:\n- Major refactor of `Encoder` trait\n- Support for lazy image sequence encoding\n- Tile resize\n- Radial and conic gradients\n\n### [See the changelog](https://github.com/jay3332/ril/blob/main/CHANGELOG.md) for more information.\n\n## What's this?\nRIL (Rust Imaging Library) is a Rust crate designed to provide an easy-to-use, high-level interface\naround image processing in Rust. Image and animation processing has never been\nthis easy before, and it's hard to find a good crate for it.\n\nRIL was designed not only for static single-frame images in mind, but also for\nanimated images such as GIFs or APNGs that have multiple frames. RIL provides a\nstreamlined API for this.\n\nEven better, benchmarks prove that RIL, even with its high-level interface, is as\nperformant and usually even faster than leading imaging crates such as `image-rs`. See\n[benchmarks](#benchmarks) for more information.\n\n## Features\n- Support for encoding from/decoding to a wide range of image formats\n- Variety of image processing and manipulation operations, including drawing\n- Robust support for animated images such as GIFs via FrameIterator and ImageSequence\n  - See [Animated Image Support](#animated-image-support) for more information.\n- Robust and performant support for fonts and text rendering\n  - See [Rendering Text](#rendering-text) for more information.\n- A streamlined front-facing interface\n\n## Support\n⚠ This crate is a work in progress\n\nBy the first stable release, we plan to support the following image encodings:\n\n| Encoding Format | Current Status    |\n|-----------------|-------------------|\n| PNG/APNG        | Supported         |\n| JPEG            | Supported         |\n| GIF             | Supported         |\n| WebP            | Supported         |\n| BMP             | Not yet supported |\n| TIFF            | Not yet supported |\n\nAdditionally, we also plan to support the following pixel formats:\n\n| Pixel Format                           | Current Status              |\n|----------------------------------------|-----------------------------|\n| RGB8                                   | Supported as `Rgb`          |\n| RGBA8                                  | Supported as `Rgba`         |\n| L8 (grayscale)                         | Supported as `L`            |\n| LA8 (grayscale + alpha)                | Not yet supported           |\n| 1 (single-bit pixel, equivalent to L1) | Supported as `BitPixel`     |\n| Indexed RGB8 (palette)                 | Supported as `PalettedRgb`  |\n| Indexed RGBA8 (palette)                | Supported as `PalettedRgba` |\n\n16-bit pixel formats are currently downscaled to 8-bits. We do plan to\nhave actual support 16-bit pixel formats in the future.\n\n## Requirements\nMSRV (Minimum Supported Rust Version) is v1.61.0.\n\n## Installation\nAdd the following to your `Cargo.toml` dependencies:\n```toml\nril = { version = \"0\", features = [\"all\"] }\n```\n\nOr, you can run `cargo add ril --features=all` if you have Rust 1.62.0 or newer.\n\nThe above enables all features. See [Cargo Features](#cargo-features) for more information on how you can\ntune these features to reduce dependencies.\n\n### Linking errors on Windows\nIf you get errors regarding `link.exe` on Windows, this is because `libwebp` has problems linking with Windows for now.\n\nThis will be resolved when WebP encoders/decoders are rewritten in pure Rust. For now, you can use switch out the\n`all` feature with `all-pure`:\n\n```toml\nril = { version = \"0\", features = [\"all-pure\"] }\n```\n\nThis will hopefully resolve the linking errors, at the cost of not having WebP support.\n\n## Benchmarks\n\n### Decode GIF + Invert each frame + Encode GIF (600x600, 77 frames)\nPerformed locally (10-cores) ([Source](https://github.com/jay3332/ril/blob/main/benches/invert_comparison.rs))\n\n| Benchmark                                     | Time (average of runs in 10 seconds, lower is better) |\n|-----------------------------------------------|-------------------------------------------------------|\n| ril (combinator)                              | 902.54 ms                                             |\n| ril (for-loop)                                | 922.08 ms                                             |\n| ril (low-level hardcoded GIF en/decoder)      | 902.28 ms                                             |\n| image-rs (low-level hardcoded GIF en/decoder) | 940.42 ms                                             |\n| Python, wand (ImageMagick)                    | 1049.09 ms                                            |\n\n### Rasterize and render text (Inter font, 20px, 1715 glyphs)\nPerformed locally (10-cores) ([Source](https://github.com/jay3332/ril/blob/main/benches/text_comparison.rs))\n\n| Benchmark                                     | Time (average of runs in 10 seconds, lower is better) |\n|-----------------------------------------------|-------------------------------------------------------|\n| ril (combinator)                              | 1.5317 ms                                             |\n| image-rs + imageproc                          | 2.4332 ms                                             |\n\n## Cargo Features\nRIL currently depends on a few dependencies for certain features - especially for various image encodings.\nBy default RIL comes with no encoding dependencies but with the `text` and `resize` dependencies, which give you text\nand resizing capabilities respectively.\n\nYou can use the `all` feature to enable all features, including encoding features. This enables the widest range of\nimage format support, but adds a lot of dependencies you may not need.\n\nFor every image encoding that requires a dependency, a corresponding feature can be enabled for it:\n\n| Encoding     | Feature | Dependencies                   | Default? |\n|--------------|---------|--------------------------------|----------|\n| PNG and APNG | `png`   | `png`                          | no       |\n| JPEG         | `jpeg`  | `jpeg-decoder`, `jpeg-encoder` | no       |\n| GIF          | `gif`   | `gif`                          | no       |\n| WebP         | `webp`  | `libwebp-sys2`                 | no       |\n\nOther features:\n\n| Description                                                                            | Feature      | Dependencies        | Default? |\n|----------------------------------------------------------------------------------------|--------------|---------------------|----------|\n| Font/Text Rendering                                                                    | `text`       | `fontdue`           | yes      |\n| Image Resizing                                                                         | `resize`     | `fast_image_resize` | yes      |\n| Color Quantization (using NeuQuant)                                                    | `quantize`   | `color_quant`       | yes      |\n| Gradients                                                                              | `gradient`   | `colorgrad`         | yes      |\n| Enable all features,\u003cbr/\u003e including all encoding features (excludes `nightly` feature) | `all`        |                     | no       |\n\n### WebP Support limitations\nWebP support uses `libwebp`, which is a native library. This means that if you try to use the `webp` feature\nwhen compiling to a WebAssembly target, it might fail. We plan on making a pure-Rust port of `libwebp` in the future.\n\nFor ease of use, the `all-pure` feature is provided, which is the equivalent of `all` minus the `webp` feature.\n\n## Examples\n\n#### Open an image, invert it, and then save it:\n```rust\nuse ril::prelude::*;\n\nfn main() -\u003e ril::Result\u003c()\u003e {\n    let image = !Image::open(\"sample.png\")?; // notice the `!` operator\n    image.save_inferred(\"inverted.png\")?;\n    \n    Ok(())\n}\n```\n\nor, why not use method chaining?\n```rust\nImage::open(\"sample.png\")?\n    .not()  // std::ops::Not trait\n    .save_inferred(\"inverted.png\")?;\n```\n\n#### Create a new black image, open the sample image, and paste it on top of the black image:\n```rust\nlet image = Image::new(600, 600, Rgb::black());\nimage.paste(100, 100, Image::open(\"sample.png\")?);\nimage.save_inferred(\"sample_on_black.png\")?;\n```\n\nyou can still use method chaining, but this accesses a lower level interface:\n```rust\nlet image = Image::new(600, 600, Rgb::black())\n    .with(\u0026Paste::new(Image::open(\"sample.png\")?).with_position(100, 100))\n    .save_inferred(\"sample_on_black.png\")?;\n```\n\n#### Open an image and mask it to a circle:\n```rust\nlet image = Image::\u003cRgba\u003e::open(\"sample.png\")?;\nlet (width, height) = image.dimensions();\n\nlet ellipse = \n    Ellipse::from_bounding_box(0, 0, width, height).with_fill(L(255));\n\nlet mask = Image::new(width, height, L(0));\nmask.draw(\u0026ellipse);\n\nimage.mask_alpha(\u0026mask);\nimage.save_inferred(\"sample_circle.png\")?;\n```\n\n### Animated Image Support\nRIL supports high-level encoding, decoding, and processing of animated images of any format,\nsuch as GIF or APNGs.\n\nAnimated images can be lazily decoded. This means you can process the frames of an animated image\none by one as each frame is decoded. This can lead to huge performance and memory gains when compared to \ndecoding all frames at once, processing those frames individually, and then encoding the image back to a file.\n\nFor lazy animated image decoding, the `FrameIterator` trait is used as a high-level iterator interface\nto iterate through all frames of an animated image, lazily. These implement `Iterator\u003cItem = Frame\u003c_\u003e\u003e`.\n\nFor times when you need to collect all frames of an image, `ImageSequence` is used as a high-level\ninterface around a sequence of images. This can hold extra metadata about the animation such as loop count.\n\n#### Open an animated image and invert each frame as they are decoded, then saving them:\n\n```rust\nlet mut output = ImageSequence::\u003cRgba\u003e::new();\n\n// ImageSequence::open is lazy\nfor frame in ImageSequence::\u003cRgba\u003e::open(\"sample.gif\")? {\n    let frame = frame?;\n    frame.invert();\n    output.push(frame);\n\n    // or...\n    output.push_frame(!frame?);\n}\n\noutput.save_inferred(\"inverted.gif\")?;\n```\n\n#### Or, how about we encode each frame immediately without storing them in memory?\n```rust\nlet mut stream = ImageSequence::\u003cRgba\u003e::open(\"sample.gif\")?;\n\n// Use the first frame to initialize the encoder\nlet mut output = File::create(\"inverted.gif\")?;\nlet first_frame = stream.next().unwrap()?;\nlet mut encoder = GifEncoder::new(\u0026mut output, \u0026first_frame)?;\n\n// Then, write the first frame into the GIF\nencoder.add_frame(\u0026first_frame)?;\n\n// Now, invert each frame and write it into the GIF\nfor frame in stream {\n    encoder.add_frame(\u0026!frame?)?;\n}\n```\n\n#### Open an animated image and save each frame into a separate PNG image as they are decoded:\n```rust\nImageSequence::\u003cRgba\u003e::open(\"sample.gif\")?\n    .enumerate()\n    .for_each(|(idx, frame)| {\n        frame\n            .unwrap()\n            .save_inferred(format!(\"frames/{}.png\", idx))\n            .unwrap();\n    });\n```\n\nAdditionally, `Frame`s house `Image`s, but they are not `Image`s themselves. However, `Frame`s are able\nto dereference into `Image`s, so calling image methods on frames will seem transparent.\n\n### Rendering Text\nRIL provides a streamlined interface for rendering text.\n\nThere are two ways to render text: with a `TextSegment` or with a `TextLayout`. A `TextSegment`\nis faster and more lightweight than a `TextLayout` (and it's cloneable, unlike `TextLayout`), but\nlacks many of the features of a `TextLayout`.\n\nA `TextSegment` supports only one font and either represents a segment in a `TextLayout`, or it can\nbe directly rendered more efficiently than a `TextLayout`. You should only use `TextLayout` if you \nneed what `TextSegment` can't provide.\n\n`TextLayout`s support anchor-style text-alignment, and can be used to render text with multiple fonts\nand styles, such as different sizes or colors. It also provides the ability to grab the dimensions\nof the text before rendering such as width and height. `TextSegment` cannot do this.\n\n#### Render text with a `TextSegment`:\n```rust\nlet mut image = Image::new(512, 256, Rgb::black());\n// Open the font at the given path. You can try using `Font::from_bytes` along with the `include_bytes!` macro\n// since fonts can usually be statically loaded.\nlet font = Font::open(\n    \"Arial.ttf\",\n    // Do note that the following is a specified optimal size\n    // and not a fixed size for the font. It specifies what size\n    // to optimize rasterizing for. You do not have to load the same\n    // font multiple times for different sizes.\n    36.0,\n)?;\n\nlet text = TextSegment::new(\u0026font, \"Hello, world\", Rgb::white())\n    .with_position(20, 20);\n\nimage.draw(\u0026text);\nimage.save_inferred(\"text.png\")?;\n```\n\n#### Render text in the center of the image with a `TextLayout`:\n```rust\nlet mut image = Image::new(512, 256, Rgb::black());\nlet font = Font::open(\"Arial.ttf\", 36.0)?;\nlet bold = Font::open(\"Arial Bold.ttf\", 36.0)?;\n\nlet (x, y) = image.center();\nlet layout = TextLayout::new()\n    .centered() // Shorthand for centering horizontally and vertically\n    .with_wrap(WrapStyle::Word) // RIL supports word wrapping\n    .with_width(image.width()) // This is the width to wrap text at. Only required if you want to wrap text.\n    .with_position(x, y) // Position the anchor (which is the center) at the center of the image\n    .with_segment(\u0026TextSegment::new(\u0026font, \"Here is some \", Rgb::white()))\n    .with_segment(\u0026TextSegment::new(\u0026bold, \"bold \", Rgb::white()))\n    .with_segment(\u0026TextSegment::new(\u0026font, \"text.\", Rgb::white()));\n\nimage.draw(\u0026layout);\n```\n\n## Contributing\nSee [CONTRIBUTING.md](https://github.com/jay3332/ril/blob/main/CONTRIBUTING.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjay3332%2Fril","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjay3332%2Fril","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjay3332%2Fril/lists"}