tl;dr: How can I use RMagick to rotate an image at a given point.
I created a website which allows user to manipulate 2 images online and composite these images on the server side to a single image.
I use regular css transform: rotate()
for rotation on the client side.
On the server side I'm rotating the image using RMagick's rotate!
method but the results differ from the web version.
(Presumably because of an origin issue (e.g. at which point of the image the rotation takes place)).
The web version rotates at the center of the image (transform-origin: 50% 50%
). Unfortunately RMagick doesn't by default.
I read through the RMagick docs and found affine_transform
which accepts a matrix and transforms the image. Is this the right method to use, if so how? I tried passing the css-matrix to that function but it doesn't work.
Somewhere in the RMagick documentation I read that Magick::Image#rotate
accepts 3 parameters (degree, originX, originY)
but my version says that it only accepts 2 parameters (and actually requires the second parameter to be a string...).
My code:
require 'rmagick'
include Magick
@label = Label.last
image = @label.image
json = @label.processing
image.background_color = "none"
image.resize!(json["size"]["width"], json["size"]["height"])
# how can I set the rotation origin to the center of the image?
image.rotate!(json["rotation"].to_i)
overlay.composite!(image, json["position"]["x"], json["position"]["y"],
Magick::OverCompositeOp)
overlay.write("output5.png")
The output I'm currently getting is this. The blue square is actually image
in the code. The heart is overlay
.
My desired output looks like this: (Ignore background, border and controls)
If I don't use rotation at all, both images are identically. That's why I assume it's an rotation issue. Both images are equally in width and height.
edit: Apparently only Magick::RVG::Image
accepts the originX & originY parameters I mentioned above. Still not able to transform the current image into a RVG Image. It might solve the issue if I can transform my Magick::Image into Magick::RVG::Image.
Okay I've found a solution for this problem. I have to use RVG which is a module to create vector graphics. The #rotate(degree, originX, originY) method is defined in the RVG::Image class so I had to wrap my Magick::Image object with:
require 'rvg/rvg'
image = RVG::Image.new(magick_image, width, height, x, y)
canvas = RVG.new(width, height)
canvas.use image
overlay.composite!(canvas.draw, ...)
Writing this on mobile, I will add a detailed answer asap.