How to Combine Images in Ruby

How to combine images in Ruby

Try: 'rmagick' gem

require 'rmagick'

image_list = Magick::ImageList.new("image1.png", "image2.png", "image3.png")
image_list.write("combine.png")

You can also refer this SO Question it's similar to yours.

Combining four images to one image for download

As a commentor pointed out, you're looking for RMagick:

https://github.com/rmagick/rmagick

Using the answer from How to combine images in Ruby, and assuming you want a square layout for your new combined image, then try:

require 'rmagick'

image_list = Magick::ImageList.new("image1.png", "image2.png", "image3.png", "image4.png")
image_list.write("combine.png")

This will take the 4 images and combine them into one, created in the same directory as the originals, called combine.png

How do I combine a number of images into a single PDF using ruby?

You can use RMagick's ImageList#write:

If the image format indicated by the filename supports multiple images per file (animated images), write writes all the images in the imagelist to a single file.

Example:

require 'rmagick'

image_list = Magick::ImageList.new("image1.png", "image2.png", "image3.png")
image_list.write("images.pdf")

Combine remote images to one image using ruby-vips

You can read and write URIs in ruby-vips like this:

#!/usr/bin/ruby

require "vips"
require "down"

def new_from_uri(uri)
byte_source = Down.open uri

source = Vips::SourceCustom.new
source.on_read do |length|
puts "reading #{length} bytes from #{uri} ..."
byte_source.read length
end
source.on_seek do |offset, whence|
puts "seeking to #{offset}, #{whence} in #{uri}"
byte_source.seek(offset, whence)
end

return Vips::Image.new_from_source source, "", access: :sequential
end

a = new_from_uri "https://upload.wikimedia.org/wikipedia/commons/a/a6/Big_Ben_Clock_Face.jpg"
b = new_from_uri "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"
out = a.composite b, "over", x: 100, y: 100
out.write_to_file "x.jpg"

If you watch the console output you can see it loading the two source images and interleaving the pixels. It makes this output:

example output

The docs on Vips::Source have more details.

Combine multiple images using vips (ruby-vips8)

ruby-vips8 comes with a complete set of operator overloads, so you can just do arithmetic on images. It also does automatic common-subexpression elimination, so you don't need to be too careful about ordering or grouping, you can just write an equation and it should work well.

In your example:

require 'vips8'

images = Dir["shots/*"].map{ |i| Vips::Image.new_from_file(i) }
sum = images.reduce (:+)
avg = sum / images.length
avg.write_to_file "out.tif"

+-*/ with a constant always makes a float image, so you might want to cast the result down to uchar before saving (or maybe ushort?) or you'll have a HUGE output tiff. You could write:

avg = sum / images.length
avg.cast("uchar").write_to_file "out.tif"

By default, new_from_file opens images for random access. If your sources images are JPG or PNG, this will involve decompressing them entirely to memory (or to a disk temp if they are very large) before processing can start.

In this case, you only need to scan the input images from top to bottom as you write the result, so you can stream the images through your system. Change the new_from_file to be:

images = Dir["shots/*"].map { |i| Vips::Image.new_from_file(i,  :access => "sequential") }

to hint that you will only be using the image pixels sequentially, and you should see a nice drop in memory and CPU use.

PNG is a horribly slow format, I would use tiff if possible.

You could experiment with bandrank This does something like a median filter over a set of images: you give it an array of images and at each pixel position it sorts the images by pixel value and selects the Nth one. It's a very effective way to remove transitory artifacts.

You can use condition.ifthenelse(then, else) to compute more complex functions. For example, to set all pixels greater than their local average equal to the local average, you could write:

(image > image.gaussblur(1)).ifthenelse(image.gaussblur(1), image)

You might be curious how vips will execute the program above. The code:

(images.reduce(:+) / images.length).cast("uchar")

will construct a pipeline of image processing operations: a series of vips_add() to sum the array, then a vips_linear() to do the divide, and finally a vips_cast() to knock it back to uchar.

When you call write_to_file, each core on your machine will be given a copy of the pipeline and they will queue up to process tiles from the source images as they arrive from the decompressor. Each time a line of output tiles is completed, a background thread will use the selected image write library (libtiff in my example) to send those scanlines back to disk.

You should see low memory use and good CPU utilization.

Combine picture and text in HAML

Try this

view file:

%span
= "text".html_safe
= image_tag('/apple-icon-57x57.png')
= "text"

css file:

span img { display: inline; }

Combine multiple image strips into one image with ChunkyPNG

Try this:

newpic = newpic.replace(strips[0], offset_x = 0, offset_y = 0)
newpic.save('name.png') # save when done

With the replace method, you can select any of the strips from your array and lay them down on a canvas according to the offsets. Is that what you had in mind?

Ruby / RMagick rotate and combine images

Before rotating set your background to none:

overlay.background_color = "none"

Other possible methods to use after the rotation:

img.transparent_chroma(low, high, opacity=TransparentOpacity, invert=false)
img.transparent(color, opacity=TransparentOpacity)

so in your case:

overlay.transparent!("white")


Related Topics



Leave a reply



Submit