I am attempting to stack multiple PNG images with transparency on top of each other. These are pixel art images for game characters and should work similar to “dressing” a paper doll. The pixels in my images are either fully transparent or fully opaque, there is no “partial” transparency going on.
I’m more or less porting code from a JavaScript canvas to a Phoenix Controller generating the image on the fly.
defmodule RenderCharacterController do
use Web, :controller
def get(conn, params) do
result_image = Image.new!(832, 1344, color: [0, 0, 0, 0])
gender = Map.get(params, "gender", "male")
layers = [
Image.open!("priv/static/lpc/body/#{gender}/light.png"),
Image.open!("priv/static/lpc/head/#{gender}/light.png"),
Image.open!("priv/static/lpc/hair/buzzcut/adult/blue.png"),
Image.open!("priv/static/lpc/torso/longsleeve/#{gender}/red.png")
]
result_image = Enum.reduce(layers, result_image, & Image.Draw.image!(&2, &1, 0, 0, mode: :VIPS_COMBINE_MODE_ADD))
binary = Image.write!(result_image, :memory, suffix: ".png", minimize_file_size: true)
conn
|> put_resp_content_type("image/png")
|> send_resp(200, binary)
end
end
The result is however not what I expected. I’m sadly not allowed to upload images, so please bare with to imgur. You can also see them all at once: Imgur: The magic of the Internet
- Combining
body
and head `works fine, these images have no overlap: Imgur: The magic of the Internet - For reference, this is the red shirt that should be overlayed: Imgur: The magic of the Internet
- For reference, this is blue hair that should be overlayed: Imgur: The magic of the Internet
- The result has however very white colours and the body shines through: Imgur: The magic of the Internet
So clearly :VIPS_COMBINE_MODE_ADD
is not the correct way to blend / draw transparent images on top of each other like a JavaScript Canvas would do. The only other mode is however :VIPS_COMBINE_MODE_SET
and this ignores transparency and completely hides the first image behind the second image. I would require something along the line of :VIPS_COMBINE_MODE_SET_UNLESS_FULLY_TRANSPARENT
.
Does anyone have an idea how to stack images like this using the Image library? Or any other library for that matter.