#image #alpha #blend #blending-modes #imagechops

image-blend

Type-agnostic support for image blending operations (add, multiply, screen, etc) for the image crate. Support for custom blends and utils for alpha channel manipulation.

6 releases

0.1.7 Sep 19, 2024
0.1.6 Sep 19, 2024

#174 in Images

Download history 270/week @ 2024-08-31 70/week @ 2024-09-07 143/week @ 2024-09-14 58/week @ 2024-09-21 11/week @ 2024-09-28

323 downloads per month

MIT/Apache

64KB
833 lines

image-blend

Library to perform blending and alpha channel operations using the image crate

Implementation of support for type-agnostic blending algorithms such as screen, multiply, lighter, etc, for the image crate

Also provide support for getting alpha channnels as grayscale images, setting alpha channels from grayscale images, and transplanting alpha channels directly from one image to another

Type-agnostic: this library will automatically convert between input type when blending two images together.

The only limitation to this is that you cannot blend an Rgb/Rgba image into a Luma image.

Usage:

Syntax is the same when working with Dynamic and Imagebuffer.

Working with dynamic images

Blend two images together

use image::open;
use image_blend::DynamicChops;
use image_blend::pixelops::pixel_mult;

// Load an image
let mut img1_dynamic = open("test_data/1.png").unwrap();

// Load another image
let img2_dynamic = open("test_data/2.png").unwrap();

// Blend the images using the pixel_mult function
img1_dynamic.blend(&img2_dynamic, pixel_mult, true, false).unwrap();
img1_dynamic.save("tests_out/doctest_dynamic_blend_result.png").unwrap();

Get and set the alpha channels

use image::open;
use image_blend::DynamicChops;

// Load an image and get its alpha channel
let img1_dynamic = open("test_data/1.png").unwrap();
let img1_alpha = img1_dynamic.get_alpha().unwrap();
img1_alpha.clone().save("tests_out/doctest_dynamic_getalpha_alpha.png").unwrap();

// Load another image and set its alpha channel to the first image's alpha channel, using the copied alpha channel
let mut img2_dynamic = open("test_data/2.png").unwrap();
img2_dynamic.set_alpha(&img1_alpha).unwrap();
img2_dynamic.save("tests_out/doctest_dynamic_getalpha_result.png").unwrap();

Transplant an alpha channel directly from one image to another

use image::open;
use image_blend::DynamicChops;

// Load an image and get its alpha channel
let img1_dynamic = open("test_data/1.png").unwrap();

// Load another image and set its alpha channel to a copy of the first image's alpha channel.
let mut img2_dynamic = open("test_data/2.png").unwrap();
img2_dynamic.transplant_alpha(&img1_dynamic).unwrap();
img2_dynamic.save("tests_out/doctest_dynamic_transplantalpha_result.png").unwrap();

Working with imagebuffers

Note how in these examples, the image buffers have different types but it doesn't matter as the library handles this.

Blend two images together

use image::open;
use image_blend::BufferBlend;
use image_blend::pixelops::pixel_mult;

// Load an image
let mut img1_dynamic = open("test_data/1.png").unwrap();
let mut img1_buffer = img1_dynamic.as_mut_rgba8().unwrap();

// Load another image
let img2_dynamic = open("test_data/2.png").unwrap();
let img2_buffer = img2_dynamic.to_rgba16();

// Blend the images using the pixel_mult function
img1_buffer.blend(&img2_buffer, pixel_mult, true, false).unwrap();
img1_buffer.save("tests_out/doctest_buffer_blend_result.png").unwrap();

Get and set alpha channels

use image::open;
use image_blend::{BufferGetAlpha, BufferSetAlpha};

// Load an image and get its alpha channel
let img1_dynamic = open("test_data/1.png").unwrap();
let img1_buffer = img1_dynamic.as_rgba8().unwrap();
let img1_alpha = img1_buffer.get_alpha().unwrap();
img1_alpha.clone().save("tests_out/doctest_buffer_getalpha_alpha.png").unwrap();

// Load another image and set its alpha channel to the first image's alpha channel, using the copied alpha channel
let mut img2_dynamic = open("test_data/2.png").unwrap();
let mut img2_buffer = img2_dynamic.to_rgba16();
img2_buffer.set_alpha(&img1_alpha).unwrap();
img2_buffer.save("tests_out/doctest_buffer_getalpha_result.png").unwrap();

Transplant an alpha channel directly from one image to another

use image::open;
use image_blend::{BufferGetAlpha, BufferSetAlpha};

// Load an image and get its alpha channel
let img1_dynamic = open("test_data/1.png").unwrap();
let img1_buffer = img1_dynamic.as_rgba8().unwrap();

// Load another image and set its alpha channel to a copy of the first image's alpha channel.
let mut img2_dynamic = open("test_data/2.png").unwrap();
let mut img2_buffer = img2_dynamic.to_rgba16();
img2_buffer.transplant_alpha(&img1_buffer).unwrap();
img2_buffer.save("tests_out/doctest_buffer_transplantalpha_result.png").unwrap();

Custom blend operations

Using custom blend operations is easy. You just need a function that takes 2 f64s and returns an f64.

The values passed to this function are 0..1 where 0. is the darkest a pixel can be and 1. the brightest. Type conversion and clamping of the return to 0..1 is handled for you.

a is self, b is other.

use image::open;
use image_blend::DynamicChops;

let closest_to_gray = |a: f64, b: f64| {
    let a_diff = (a - 0.5).abs();
    let b_diff = (b - 0.5).abs();
    if a_diff < b_diff {
        a
    } else {
        b
    }
};

// Load an image
let mut img1_dynamic = open("test_data/1.png").unwrap();

// Load another image
let img2_dynamic = open("test_data/2.png").unwrap();

// Blend the images using our custom function
img1_dynamic.blend(&img2_dynamic, closest_to_gray, true, false).unwrap();
img1_dynamic.save("tests_out/doctest_dynamic_custom_result.png").unwrap();

Dependencies

~3.5MB
~69K SLoC