How to blend a color with an image and make the image transparent?

Hello!

I am unsure where to start with a MWE, but suppose I want to take an image and do the following operations:

  1. ‘Multiply’ it with a color (let’s say blue) so that a picture of a sunset gets a bluish tint
  2. Make the image transparent, how do I control the opacity of the image function?

Kind regards

I don’t think you can currently modify the opacity of an image
A workaround I have used though is overlaying it with a filled box (this works both for “decreasing the opacity” - i.e. overlaying a semi-transparent white box - and for “mixing a color” - i.e. a semi-transparent box fill with another color)

Do you happen to have a simple example of that you can share? :)

A very hacky way of doing it:

#let overlay(img, color) = context {
  let m = measure(img)
  stack(
    img,
    move(
      dy: -m.height,
      box(width: m.width, height: m.height, fill: color)
    )
  )
}
#overlay(my-image, red.transparentize(50%))

I’d be very interested to see if someone else can come up with a better solution

Two things I can note here:

  • If the image is larger than the container it is placed in, it is resized automatically to fit. However, this is by default not reflected in the measured size, as measuring happens on an unbounded canvas. I would recommend using the layout function and passing the bounds in measure.

  • By using place, you can simplify this quite a bit, as you can set the alignment to the top left of the parent block (here the layout element), so that you don’t need to move the box manually.

Other than that, the idea is the exact same :)

#let overlay(img, color) = layout(bounds => {
  let size = measure(img, ..bounds)
  img
  place(top + left, block(..size, fill: color))
})
1 Like

I thought it would probably involve the layout function but I didn’t know about passing the bounds to measure
Thanks for the explanation :+1:

When looking for similar functionality i came accross this question and later on a package that seems to do what you were looking for.

Transparancy is not supported by Typst directly, but the package grayness supports parsing of images and performing operations on the image.
One of the operations is transparent image.

I created this example:

#import "@preview/grayness:0.2.0": *

#let data = read("nadine-e-ZPP-zP8HYG0-unsplash.jpg", encoding:none)
#transparent-image(data,alpha:75%)

#block(fill:gradient.linear(red, blue, angle: 45deg).sharp(2),inset:1cm, transparent-image(data,alpha:75%)) 

Photo by Nadine E on Unsplash.

That results is the following:

Note that the plugin can become slow on bigger images, but transparancy is possible.