Compositing/flattening images in Rails with Paperclip - ruby-on-rails

I'm building a Rails application where a user can upload an image which is automatically cropped to a certain size, then they can choose an overlay which is exactly the same size as the cropped image.
What I want to do is composite or flatten the two images and save it as a single image - I've looked at the Image Magick documentation, but I can't see how to apply the example they give:
composite -gravity center smile.gif rose: rose-over.png
to work with Paperclip.
Also, the example references two specific images, but I'm wondering how I can pass in a variable (the user uploaded image) instead?

I believe you want to use a paperclip processor.
Here is the high level description:
https://github.com/thoughtbot/paperclip#custom-attachment-processors
Here is a gist example of using composite (recommended here https://github.com/thoughtbot/paperclip/issues/978):
https://gist.github.com/708077

Related

Overlaying multiple PNG images of different sizes on a canvas using ImageMagick

I want to overlay multiple PNG images of different sizes on a transparent canvas using ImageMagick. First I create a transparent canvas of some fixed size, say like
convert -size 1500x1000 canvas:transparent PNG32:canvas.png
Then I loop over my images in order to add each image to the canvas
convert canvas.png nthimage.png -gravity Center -geometry xResxYres+xcoord+ycoord -composite canvas.png
This works fine, but I may overlay as many as 10 pictures and I do this for thousands of n-tuples of images, so a faster solution would be appreciated. So my question: Can I also do this in one step instead of creating the canvas first and then adding a single image at a time?
Edit: I use ImageMagick 7.0.11-13 on macOS 10.15.7. I run ImageMagick from within a python script, so a file containing a list of input files can be generated if needed. For concreteness, say my input files are file_1.png up to file_n.png with sizes A1xB1 up to AnxBn and should be placed at coordinates +X1+Y1 up to +Xn+Yn with respect to the center of the canvas and the output file is output.png and should have size 1500x1000.
I really wouldn't recommend shelling out subprocesses from Python to call ImageMagick thousands of times. You'll just end up including too much process creation overhead per image, which is pointless if you are already running Python which can do the image processing "in house".
I would suggest you use PIL, or OpenCV directly from Python, and as your Mac is certainly multi-core, I would suggest you use multi-processing too since the task of doing thousands of images is trivially parallelisable.
As you haven't really given any indication of what your tuples actually look like, nor how to determine the output filename, I can only point you to methods 7 & 8 in this answer.
Your processing function for each image will want to create a new transparent image then open and paste other images with:
from PIL import Image
canvas = Image.new('RGBA', SOMETHING)
for overlay in overlays:
im = Image.open(overlay)
canvas.paste(im, (SOMEWHERE))
canvas.save(something)
Documentation here.

How do I extract a common part of multiple images and put it as a single transparent PNG

Similar to this “Diff” an image using ImageMagick but lets say I have 2+ images of different sizes. Say from a game with multiple screenshots and I just want to extract the "coins" image so I detect it in a tool like Sikuli which accepts a transparent PNG and ignores the transparent areas.
I am thinking it is something with the compare tool to create a mask for one of the images then apply the mask using magick/convert to extract the final PNG.
Say I have three images where each are slightly off...
I want to somehow extract the following from the three images.
Note I am not really requiring a full imagemagick solution. I am thinking that the alignment best be done with another tool like Gimp, but I am not sure how to even create a "difference layer" that I can shift around so I can align the images.

Is it possible for Paperclip to generate a new image (with no source)?

I'm building an image based off of user input -- the background will either be an image or a color, and then a few other images may or may not be composed on top.
Checking through the paperclip docs, it mentions that you can use ImageMagik to post-process images, and that post-processing will never fire if it doesnt already have an image.
If I am able to make the imagemagik scripts to compose/color/resize an image, is there a way for it to generate the image, or will I need to include some sort of hackish pixel to upload (and then postprocess in to the image I want)?
ImageMagick can generate a starting image for you, consisting of a simple rectangle filled with a single color. For example, this will generate a 150x100 red image:
convert -size 150x100 xc:"#ff0000" starting_image.png
I would try the following:
Have a default image in my app's assets folder
If the model to be saved has no attachment then I would assign it the one mentioned above: a_model.image = File.open('...')
Then, upon save of the a_model the post-processing should take place normally

Dragonfly Imagemagick rotate, than crop than resize

I am using a jQuery plugin that allows basic image manipulation: cropping, rotating, zooming, etc.
I am able to rotate the image:
image = photo.image.rotate(wrapper.rotate)
I am able to crop the image
image.thumb("#{wrapper.width}x#{wrapper.height}+#{wrapper.x}+#{wrapper.y}")
However, I can't figure out a way to resize the image after cropping it. Basically, I want to run:
image.thumb("300x200!")
once more.
I understand that image.thumb() returns a Dragonfly job, is it possible to preform another process after cropping it?
Some context on why I want to do this: The user can pan over a specific area of the image which will than be visible in a 300x200px container. Most of the time, the image is way larger than 300x200px, so I want to re-size it after cropping it to reduce the filesize.
instead of trying to do it with the given methods, just use .convert and pass the normal image magic arguments as one lone string e.g
image.convert("-gravity center -crop '#{wrapper.width}x#{wrapper.height}+#{wrapper.x}+#{wrapper.y}' -resize '300x200!'")

Creating map flags with ImageMagick

I have a requirement where I need to create a map flag based on a users avatar:
The users avatar can be any size and aspect ratio. The problem I'm having is getting the image to compose correctly, allowing me to get the transparency around the marker in order to support the tick at the bottom.
How can I do this?
It transpires that this is fairly straightforward with the correct approach.
First you need TWO overlay images. One of these is the size of the result image and is transparent everywhere for except where you want the avatar to show. The second is a simple transparent PNG of the surround on the image.
Then, this seems to work:
composite avatar.jpg -thumbnail 61x68^ -gravity center map_marker.png mask.png output.png

Resources