Resize an image to specific ratio without enlarging it - image

I need to generate new dimensions for an image to match a ratio of a given width and height ...but without increasing the size of the original.
The concept seems oh so simple yet I can't seem to join the dots.
Also, for code samples the language is PHP.
Update:
This is what I have so far:
http://codepad.org/fTdCNhQf
This is the output I need:
Example Image • (can't embed yet)

Since enlarging is not an option, your only options are cropping and extending.
Try this: let's say your image is W*H, and the desired aspect ratio of width to height is R.
Using the width and the aspect ratio, calculate the target height TH = W/R
Using the height and the aspect ratio, calculate the target width TW = H*R
Calculate area changes aH = ABS(TH-H)*W and aW = ABS(TW-W)*H
if aH is less than aW, use target width; pad or crop the image horizontally based on the sign of TH-H
Otherwise, use target height; pad or crop the image vertically based on the sigh of TW-W
Here is a quick example:
Target R: 5/6
Image: W=200, H= 300;
TH = 200/5*6 = 240
TW = 300*5/6 = 250
aH = 60*200=12000
aW = 50*300=15000
Resulting action: since aH is less than aW, crop image vertically to 240

Are you using something like ImageMagick libraries to generate an image or do you just need to generate the new dimensions based on a known ratio? Also, do you need to discover the ratio from the existing image?
This may be useful then:
http://www.zedwood.com/article/119/php-resize-an-image-with-gd

Related

Calculate Object Size for Different Screens

I'm writing an app in Appcelerator that will be running different mobile screens. So, there will be many screen sizes and ratios.
Let me simply ask like this; I have an image object and I want it to protect its ratio on different screens.
How can I calculate the width & height of this object for different screens?
Object Sizes in 1920 X 1080 screen is 885 X 109.
(For example) What should be the sizes of 812 X 375(iPhone X size) screen?
Thanks in advance.
You can use
Alloy.Globals.WIDTH = (OS_ANDROID) ? Ti.Platform.displayCaps.platformWidth / Ti.Platform.displayCaps.logicalDensityFactor : Ti.Platform.displayCaps.platformWidth;
Alloy.Globals.HEIGHT = (OS_ANDROID) ? Ti.Platform.displayCaps.platformHeight / Ti.Platform.displayCaps.logicalDensityFactor : Ti.Platform.displayCaps.platformHeight;
to get the proper device size.
But I'm not sure if I understand the question. You don't need to do anything special about the aspect ration of your image on different devices. You can use Ti.UI.SIZE on width or height and a fixed value on the other property to keep the aspect ratio. E.g. if you image should always be 300dp width set the height to Ti.UI.SIZE.
If you want to adjust the image width to the device screen width but keep a left/right margin you can use
image.width = Ti.UI.FILL;
image.left = 10;
image.right = 10;
imahe.height = Ti.UI.SIZE;
For other calculations you can use the Alloy.Globals.WIDTH or Alloy.Globals.WIDTH from above (put it into alloy.js) and multiply it by the image ratio to get the other side.

zoom an image to fit a screen horizontally - algorithm

This is a general question regarding an algorithm to zoom an image to fit the width of a screen, there are some givens and some constraints. We can assume we are using Java but this question is more mathematical that language dependent.
First of all, the image loads and fits into the dimensions of the screen vertically first, not horizontally.
We can get the dimensions of the screen and the dimensions of the image with methods, but we cannot set the dimensions of either (We only have getters not setters).
imageWidth = image.getWidth(); //integer
imageHeight = image.getHeight(); //integer
screenWidth = screen.getWidth(); //integer
screenHeight = screen.getHeight(); //integer
The only method to resize the image is by setting scale (zooming essentially).
image.setScale(some float); // optionally image.setZoom(integer);
What I would like to know is how to calculate the scale (zoom) level for some l x h image so that it fits a L x H screen horizontally?
All you have to do to make the Image fill your screen is scale along the x axis:
scaling_factor = screen.getWidth()/image.getWidth()
image.setScale(zoom_factor);
The formula is very intuitive:
The image height is irrelevant. The scaling you desire would be the same for a landscape and vertical image, as long as the width of both images are the same
When the image's width increases, your scaling factor decreases
When your screen size increses, the scaling factor increases.

Image scaling inside a canvas

Let's assume we have a container with the size of 500 x 300 (w x h).
Inside this container we have a canvas with the same size, but with a different reference system inside it, with the size of 700 x 1000.
When I put an image of 700 x 1000 in this canvas it will obviously appear distorted, because the canvas occupies the entire 500 x 300 pixels of its parent container - even if inside it is still 700 x 1000.
Now, I am trying to figure out a formula to scale the image in the interlal reference system so the image doesn't appear distorted then loaded in the canvas.
Can anybody help?
First of all, if you have w = 700, h = 1000, i.e. w_container / w_canvas = 5/7 != h_container / h_canvas = 3/10, you will not be able to load you image not being distorted and taking entire space of the container. I just can tell you how to resize your image properly.
To save the width-height ratio of your image (equals 7/10, I think this is what you mean under "distorted image") you should calculate how your image's ratio rescales after putting the image on the canvas.
canvas_ratio(7/10) * x = container_ratio(5/3), hence x = 50/21. So if your image has the ratio y, then it will become y*x = y*50/21.
So you should just resize your image before putting it on the canvas such a way that after multiplying this ratio by x it would be 7/10 (the ratio when your image looks perfect). We have an equation y*50/21 = 7/10, hence y = 147/500. That's the ratio your image should have!
For example, you can make image size 294x1000, and after putting it to the canvas it will have height of 300 pixels in your container's coordinate system and 294*(500/700) = 210 pixel width (unfortunately, not 500). Hope this will be useful information for you.
Good luck!

Algorithm for cropping image to specific ratio

I need an algorithm that given an image's width, height and a target ratio will calculate the number of pixels to be shaved from the image's sides to get to that ratio, that has the smallest change in the image's area.
How might one implement such an algorithm?
Edit
Sorry for the inconsistency in my original question; I have revised my it.
Bring the ratio into reduced form, so that gcd(ratio_width, ratio_height) = 1.
Calculate floor(width / ratio_width) and floor(height / ratio_height). Your factor is the minimum of these two.
Multiply ratio_width and ratio_height by that factor to obtain the new image dimensions.
Shave the difference.
To minimize the change in area, you want to find the largest rectangle of the desired aspect ratio that will fit inside the original image bounds.
So, if the original image is too wide, then make the final image's height = original height, and shave off the extra width.
If the original image is too tall, make the final image's width = original width, and shave off the extra height.
Note: This assumes that you are not allowed to increase the width or height beyond the original dimensions. If that is not the case, the algorithm would be:
Constraint 1: x_final * y_final = x_initial * y_initial
Contraint 2: x_final / y_final = r
The solution is:
x_final = sqrt(r*x_initial*y_initial)
y_final = sqrt(x_initial*y_initial/r)

RMagick: scale and resize image for thumbnail

I want to resize/scale an image. The originals have not the same dimensions like 300x200 or 512x600. I want to resize the image to 100x100 but DONT crop anything from the image or change ratio. Ideally the image will be first scale the long edge to 100 (aspect ratio) and then fill up the smaller edge with white.
.---------.
|- - - - -|
| IMAGE |
|- - - - -|
'---------'
I dont use Paperclip or Rails, just RMagick.
I've done it with merging the resized image with a new 100x100 image. That's for sure not the best way but it works:
img = Magick::Image.read("file.png").first
target = Magick::Image.new(100, 100) do
self.background_color = 'white'
end
img.resize_to_fit!(100, 100)
target.composite(img, Magick::CenterGravity, Magick::CopyCompositeOp).write("file-small.png)
After playing with it for a while I got Fu86's composite trick to work like so:
img = Image.read("some_file").first().resize_to_fit!(width, height)
target = Image.new(width, height) do
self.background_color = 'white'
end
target.composite(img, CenterGravity, AtopCompositeOp).write("some_new_file")
AtopCompositeOp seems to work better than CopyCompositeOp, which turned part of my background black for some reason.
image = Magick::Image.read("filename").first
resized = image.resize_to_fit(width, height) # will maintain aspect ratio, so one of the resized dimensions may be less than the specified dimensions
resized.background_color = "#FFFFFF" # without a default, background color will vary based on the border of your original image
x = (resized.columns - width) / 2 # calculate necessary translation to center image on background
y = (resized.rows - height) / 2
resized = resized.extent(width, height, x, y) # 'extent' fills out the resized image if necessary, with the background color, to match the full requested dimensions. the x and y parameters calculated in the previous step center the image on the background.
resized.write("new_filename")
Note: on heroku, which as of this posting uses imagemagick 6.5.7-8, I needed to multiply the x and y translations by -1 (and send positive numbers). Version 6.8.0-10 expects negative numbers.
It seems you want to use change_geometry...

Resources