Dragonfly/imagemagick resize and crop and maybe add white padding - ruby

With dragonfly I can do the following:
image.thumb('300x300#')
Which will resize the image, maintaining aspect ratio and cropping it centrally (effectively chopping off the ends of the longest edge).
However, if the image has an edge smaller than 300px, then it is scaled upwards. What I would prefer is that in this case the image is not resized, but instead white padding is added where necessary.
So basically, if both edges are 300px or over I want the normal behaviour from 300x300#, but if any edge is smaller than 300px, then the image is not resized at all, but still cropped to 300x300 with whitespace added where necessary.
Is this possible with either of Dragonfly's built in processors (#thumb or #convert? Or do I need to build my own processor? If so, what sort of imagemagick commands do I need to be looking at?

Best solution would be to create a white canvas image that is 300x300 then composite your image, centered, on top of the canvas image. Then crop it with center gravity (centered). This would yield a 300x300 image with a white canvas on any vertical or horizontal edges that had a dimension smaller than 300.
** For this solution you may need to install the RMagick gem, as I do not believe Dragonfly has extended the ImageMagick operations that you will need.
This is how I would approach it:
#Set file path first and load a white image called canvas that is 300x300 into Imagmagik
canvas_file_path = "#{Rails.root}/app/assets/images/canvas.png"
canvas_image = Magick::Image.read(canvas_file_path).first
#Then perform the compositing operation. This overlays your image on top of the canvas, center gravity ensures that your image is centered on the canvas.
canvas_image.composite!(<YOUR IMAGE>, CenterGravity, Magick::OverCompositeOp)
#then write the file to a temporary file path so you can do something with it
temporary_file_path = "#{Rails.root}/tmp/#{#model.id}"
canvas_image.write(temporary_file_path)
Be sure to add the require statement in your file, pay close attention to the capitalization, it is RMagick not Rmagick
require "RMagick"
For reference here is the ImageMagick example from the documentation to perform the compositing operation that you will need
composite -gravity center smile.gif rose: rose-over.png
Rmagick Documentation on how to composite images - http://www.imagemagick.org/RMagick/doc/image1.html#composite
Rmagick Gem - https://github.com/rmagick/rmagick
ImageMagick reference to compositing - http://www.imagemagick.org/script/composite.php

I have a habit of answering my own questions of SO...
The following can be done with Dragonfly:
def thumb_url
if image.width < 300 || image.height < 300
image.convert('-background white -gravity center -extent 300x300').url
else
image.thumb('300x300#').url
end
end

Related

No-crop canvas increase to 2:1 aspect ratio with ImageMagick

I am in a situation where I have a set of images with variable width and height and I need to ensure that those images comply with an aspect ratio of 2:1.
The only assumption I can make is that those images have an aspect ratio greater than 2 so I need to expand the canvas.
With ImageMagick I can do this:
magick input.jpg -background black -gravity north -extent 2:1 output.jpg
But this crops instead of adding canvas as desired. Is there an option to avoid cropping, i.e. force image padding? Remember I do not know the image resolution beforehand.
Of course with a more complex script I can extract the image dimensions and compute the desired resolution but I am trying to keep things simple if possible.
P.S.: The images comes from a laser scanner and are going to be used in a 360 panorama viewer hence the need to meet an aspect ration without cropping.
With ImageMagick v7 you can do some inline calculations that will adjust the results of the -extent operation to pad any size input to a 2:1 ratio. See this command as an example...
magick input.png -gravity center -extent "%[fx:max(w,h*2)]x%[fx:max(w/2,h)]" result.png
That will pad any extra space with black. Add -background <somecolor> before the extent operation to change the padding color.

How to keep sprite border the same size when scaling sprite in Unity?

I've created an image in Photoshop to be used as a sprite in Unity and everything works fine while the sprite is scaled at X: 1; Y: 1.
The problem starts when I scale the image up as the border of the image stretches out with the rest of the image. Is there any way to scale an image from its centre or to ignore the image's border when it's scaled?
Here's the example now that I am able to show it:
The rectangle on top is the original image without being scaled up or down and the rectangle on the bottom is scaled at X:5, Y:0.5 but the borders are stretched.
I think that the borders are stretched because it's part of the image and when it's being scaled, the image (including the borders) is just being stretched.
Is there any way to stretch the sprite image but by ignoring the borders?
Are you trying to scale the image and keep the original ratio?
If so, here are the steps:
Hope this helps. Please let me know if you were trying to do something else.
You can use a sliced sprite. The center of the image is scaled to fit the control rectangle but the borders maintain their sizes regardless of the scaling. Check out the Unity doc here: Unity - Manual: Image

Ruby: how to crop and resize image from center

I am trying to resize an image and crop it from the center. i.e. if the resolution is 1024x512 and I want to resize by 256x256 I would resize the smallest side to 256 and maintain aspect ratio, i.e. resize the image to 512x256 and then I want to crop the 256x256 square from the centre.
I have seen solutions with paperclip but only for Rails, but I'm not sure how to do this in just a regular script.
Any ideas?
Thanks
You can use,
Magick::ImageList.crop!(CenterGravity,256,256)
More options

Find the edges of image and crop it in MATLAB

I have a RGB image. I have scanned the image. So the image occupies a small portion of an A4 size sheet.
I want to find the border of the image and crop it. I could use edge detection operators like 'Sobel' etc, but they detect all the edges present in the image. All I want is the border of the image. Also many of the edge detection functions including 'bwboundaries' work only with binary or grayscale images. My image is RGB.
I tried using 'imcrop', but this is more of interactive cropping. I am keen on doing this automatically.
Uploading a test image:
Since this is an rgb image, there will be apparent color in the gray areas, but there should be none in the white ones. You can make use of this to find the image, then you can get the bounding box.
img = imread('http://i.stack.imgur.com/dEawA.jpg');
%# instead of "==" you can check for similarity within a tolerance
tt=img(:,:,1)==img(:,:,2) & img(:,:,2) == img(:,:,3);
%# invert tt so that it's 1 where there is signal
tt = ~tt;
%# clean up some of the smaller artifacts
tto = imopen(~tt,strel('square',100));
%# get the areas and bounding box of the areas above threshold
%# as an additional criterion, you could also use excentricity
%# or you could simply remove the bottom 100 rows of the scan
stats = regionprops(tto,'BoundingBox','Area');
area = cat(1,stats.Area);
[~,maxAreaIdx] = max(Area);
bb = round(stats(maxAreaIdx).BoundingBox);
%# note that regionprops switches x and y (it's a long story)
croppedImage = img(bb(2):bb(2)+bb(4),bb(1):bb(1)+bb(3),:);
There is a bit of a border left due to rotation. You can use the mask tto above to set all non-image pixels to NaN before cropping, or you can use imrotate to fix your image.
You can try to detect the corners of your image using e.g. the Harris-Detector (corner in Matlab). Set the maximum number of corners to detect to 4. Then use the positions of the corners in imcrop. If you would post an image I could give you more specific hints. Your image being RGB shouldn't be a problem, just convert it to grayscale.
You can try using bwlabel http://www.mathworks.com/help/toolbox/images/ref/bwlabel.html (along with find, as noted in the help page) to get the indices of the image and use those to crop the original.
You'll first need to convert the original image to binary using im2bw http://www.mathworks.com/help/toolbox/images/ref/im2bw.html.

Cropping an image with a focus area (face) using ImageMagick

I'm struggling to find the right approach to resize and crop and image, with a focus area. In my case the focus area is a face detected in the image, and I need to make sure that this area is visible in the cropped version.
I have focus area given by eg. face_height, face_width, face_center_x and face_center_y. These values are percentages of dimensions of the original image.
What I want to do, is getting a eg. 60x60 thumbnail. The normal approach would be to resize so either height or width of the image is equal 60px and then crop a 60x60 from center, like this:
mogrify -resize 60x -gravity 'Center' -crop 60x60 image.jpg
What approach can be taken focus my crop around a given area instead?
I'm thinking of a solution that includes several paths:
If the face area is bigger than the wanted thumbnail, resize the image just enough to make the whole face visible in 60x60 pixels, then crop
If the face area is smaller than the wanted thumbnail, then crop "expand" my face area until my wanted thumb can fit inside the area. Then crop. I guess I need to make sure that this doesn't exceed the bounds of the original image.
Is there a smarter approach? Can you try make some example code?
Thanks!
I'd first do the arithmetic in script or program, then feed exact coordinates to ImageMagick.
The arithmetic steps:
It'll be easier to operate with exact pixel values than percentages, so convert face_height, face_width, face_center_x and face_center_y to pixel values.
You'll want rectangular thumbnail, so pick the longest side and operate with that:
longest_side = max(face_height, face_width)
Now you can calculate top left point for your crop:
crop_x = face_center_x - longest_side / 2
crop_y = face_center_y - longest_side / 2
If any of the four crop corners fall outside your picture dimensions, adjust for that:
crop_x and crop_y should both be >= 0
crop_x + longest_side should be less than image width
crop_y + longest_side should be less than image height
Having calculated these, ImageMagick call gets quite straightforward:
mogrify -crop {longest_side}x{longest_side}+{crop_x}+{crop_y} -resize 60x60 image.jpg

Resources