Vips - add text on top of image, after resize in Ruby

1.1k Views Asked by At

I'm using Vips to resize images via Shrine, hoping it's possible to use the Vips library to merge a layer of text on top of the image.

ImageProcessing::Vips.source(image).resize_to_fill!(width, height)

This code works great, how can I add a layer of text after resize_to_fill?

The goal is to write 'Hello world' in white text, with a CSS text-shadow in the center of the image.

I've tried writing something like this, but I'm only getting errors so far:

Vips\Image::text('Hello world!', ['font' => 'sans 120', 'width' => $image->width - 100]);
1

There are 1 best solutions below

0
On BEST ANSWER

Your example looks like PHP -- in Ruby you'd write something like:

text = Vips::Image.text 'Hello world!', font: 'sans 120', width: image.width - 100

I made a demo for you:

#!/usr/bin/ruby

require "vips"

image = Vips::Image.new_from_file ARGV[0], access: :sequential

text_colour = [255, 128, 128]
shadow_colour = [128, 255, 128]
h_shadow = 2
v_shadow = 5
blur_radius = 10

# position to render the top-left of the text
text_left = 100
text_top = 200

# render some text ... this will make a one-band uchar image, with 0 
# for black, 255 for white and intermediate values for anti-aliasing
text_mask = Vips::Image.text "Hello world!", dpi: 300

# we need to enlarge the text mask before we blur so that the soft edges 
# don't get clipped
shadow_mask = text_mask.embed(blur_radius, blur_radius,
                              text_mask.width + 2 * blur_radius,
                              text_mask.height + 2 * blur_radius)

# gaussblur() takes sigma as a parameter -- approximate as radius / 2
shadow_mask = shadow_mask.gaussblur(blur_radius / 2) if blur_radius > 0.1

# make an RGB image the size of the text mask with each pixel set to the
# constant, then attach the text mask as the alpha
rgb = text_mask.new_from_image(text_colour).copy(interpretation: "srgb")
text = rgb.bandjoin(text_mask)

rgb = shadow_mask.new_from_image(shadow_colour).copy(interpretation: "srgb")
shadow = rgb.bandjoin(shadow_mask)

# composite the three layers together
image = image.composite([shadow, text], "over",            
                        x: [text_left + h_shadow, text_left],
                        y: [text_top + v_shadow, text_top]) 

image.write_to_file ARGV[1]

Run like this:

$ ./try319.rb ~/pics/PNG_transparency_demonstration_1.png x.png

To make:

enter image description here