Magick++: Fit image to size - imagemagick

How do I fit an image to an exact size? I don't want to distort the image, I need to fit it on a black background and it needs to be centered whether that's side to side or top to bottom. They're originally large images that I need to get down to 25px wide by 32px high.
Right now I'm simply checking for width and height and figure out which needs to be resized:
InitializeMagick(*argv);
Image img(imgFilename);
// Check image dimensions
if (img.columns() > img.rows()) {
// wide image!
if (img.columns() > 25) {
img.resize(Magick::Geometry("25x"));
}
} else {
// tall image!
if (img.rows() > 32) {
img.resize(Magick::Geometry("x32"));
}
}
I have to believe there's a simpler/better way of doing this while also fitting it to a 25px wide by 32px tall canvas with the image in the center. How do I do that?
By the way, I realize there's a problem with the above code ... if img.columns() == img.rows() it always goes to the second case and sizes the image to 32 high which isn't correct as that will cause img.columns() to also go to 32, which is outside of the required 25 pixels. This is something I'm assuming an image fit would take care of. I just don't know how.

I believe evaluating the image columns & rows might be unnecessary. Magick::Geometry supports additional qualifier like (>) "only resize if image is bigger" and (^) "crop/fill to size". You should be able to use a combination of qualifiers to resize images, if needed, and extent the image to fit.
img.resize(Magick::Geometry("25x32>^"));
img.extent(Magick::Geometry("25x32"),Magick::CenterGravity);
Of course, you may also apply the qualifiers in the extent method. I would suggest experimenting with them using the convert utility, and example documents.

Related

What is the correct approach to show the image without distortion in collection view

I have a very fundamental question hence not posting any code.
OverView
I have a collection view which makes use of custom layout which I have written. All this custom layout does is it applies some maths and finds out the optimal number of cells to place on screen based on screen width and tries to round off the additional pixels using padding. As a result most of my cells size vary when the collection view changes its orientation especially on a device like iPad Pro. What I mean is if the cell size is 300 x 300 in portrait it might become 320 x 300 something like that in landscape. (They are not exact values just trying to give an idea)
Every single cell has imageView in it and image needs to be downloaded from server. I am making use of SDWebImage. Images downloaded are way bigger than my cells and I don't want to load such big images into memory, hence I have decided that I'll be resizing the image once it is downloaded before putting it on to SDWebImageCache.
Issue
Now as my cells sizes are changing based on device orientation, in order to make the image look pixel perfect I'll have to resize the image every time device rotates for each cell. But that will lead to bad performance.
Solutions I have figured out
I'll have to cache two images each one for one orientation in SDWeImageCache but thats again will increase memory footprint of the app.
Find the biggest size cell will get among various orientation and resize the image to that size and then use the same image for all the smaller cell size with image view having its mode set to AspectToFit.
Please suggest me what is the correct approach. I don't need the code, just need idea.
Let me know if this is a bad idea, but potential options.
You could
1) Get the original image size.
Save this.
func resetImage() {
2) Determine if picture width > height
3) If width > height, then you know it is gonna be a longer picture. Determine how long you would like it. Let's say you want the wider pictures about 1/10*Width of a cell
4) Determine the height of the image accordingly. ((1/10)/widthOfCell)*imageHeight
5) If (width > height) imageView.frame = CGRect(0, 0, 1/10*widthCell, height)
6) imageView.contentMode = .ScaleAspectFit, imageView.image = UIImage(named: "awesome")
7) Possibly save imageView.size to use incase another rotation.
This allows you to change just the imageView instead of saving the image data, hopefully removing the white space. Comment and lemme see whatcha think.

UIImageView - anyway to use 2 content modes at the same time?

So in my scenario, I have a square that is (for understanding's sake) 100x100 and need to display an image that is 300x800 inside of it.
What I want to do is be able to have the image scale just as it would with UIViewContentMode.ScaleAspectFill so that the width scales properly to 100.
However, after that, I would like to then "move" the image up to the top of the image instead of it putting it inside the imageView right in the center, basically what UIViewContentMode.Top does. However that doesn't scale it first.
Is there anyway to do this type of behavior with the built in tools? Anyway to add multiple contentModes?
I already had a helper function that I wrote that scaled an image to a specific size passed in, so I just wrote a function that calculated the scaled image that would fit into the smaller square I had similar to the size AspectFill would do, and then I wrote code that would crop it with the rectangle size I needed at (0,0).

Position an UIImageView over another with scaling

Is there a method on UIImageView that tells me the position of its image within its bounds? Say I have an image of a car, like this:
This image is 600x243, and, where the rear wheel should be, there's a hole which is 118,144,74,74 (x,y,w,h).
I want to let the user see different rear wheel options, and I have a few wheel images to choose from (all square, so they are easily scaled to match the hole in the car).
I wanted to place the car image in a UIImageView whose size is arbitrary based on layout, and I wanted to see the whole car at the natural aspect ratio. So I set the image view's content mode to UIViewContentModeScaleAspectFit, and that worked great.
For example, here's the car in an imageView that is 267x200:
I think doing this scaled the image from w=600 to w=267, or, by a factor of 267/600=0.445, and (I think) that means that the height changed from 200 to 200*0.445=89. And I think it's true that the hole was scaled by that factor, too
But I want to add a UIImageView subview to show the wheel, this is where I get confused. I know the image size, I know the imageView size, and I know the hole frame in terms of the original image size. How do I get the hole frame after the image is scaled?
I've tried something like this:
determine the position of the car image in its UIImageView. That's something like:
float ratio=carImage.width/carImageView.frame.size.width; // 0.445
CGFloat yPos=(carImageView.frame.size.height-carImage.height)/2; // there should be a method for this?
determine the scaled frame of the hole:
CGFloat holeX = ratio*118;
CGFloat holeY = yPos + ratio*144;
CGFloat holeEdge = ratio*74;
CGRect holeRect = CGRectMake(holeX,holeY,holeEdge,holeEdge);
But there must be a better way. These calculations (if they are right) are only right for a car image view that is taller than the car. The code needs to be different if the image view is wider.
I think I can work out the logic for a wider view, but it still might be wrong. For example, that yPos calculation. Do the docs say that, for content mode = AspectFit, the image is centered inside the larger dimension? I don't see that any place.
Please tell me there's a better way, or, if not, is it proven that my idea here will work for arbitrary size images, image views, holes?
Thanks.
The easiest solution (by far) is to simply use the same sizes for both the car image and the wheel option images.
Just give the wheel options a transparent padding (easy to do in nearly every graphics editing program), and overlay them over the car with the same frame.
You may increase your asset sizes by a minuscule amount.. but it'll save you one hell of a headache trying to work out positions and sizings, especially as you're scaling the car image.

When iOS shrinks an image, does it clip/pixelate it?

I have 2 relatively small pngs that will be images inside UIButtons.
Once our app is finished, we might want to resize the buttons and make them smaller.
Now, we can easily do this by resizing the button frame; the system automatically re-sizes the images smaller.
Would the system's autoresize cause the image to look ugly after shrinking the image? (i.e., would it clip pixels and make it look less smooth than if I were to shrink it in a photo editor myself?)
Or would it better to make the image the sizes they are intended to be?
It is always best to make the images of correct size from the beginning. All resize-functions will have negative impact on the end result. If you scale it up to a larger image it will be a big different, but even if you scale it down to a smaller it is usually creating visible noise in the image. Let's say that you have a line of one pixel in your image. scale it down to 90% of the original size, this line will just use 90% of a pixel wide and other parts of the images will influence the colors of the same pixels.

Is it possible to resize an image but keep the borders the same on iOS?

I have an image with a fixed border, and I need to be able to change the height of the image from for example 25px to 300px but so that the border on top only makes up the 5px it did originally. Of course the possibility is to keep as many version of the same image in different sizes, as many sizes I have, but that would take up huge amounts of memory, or I could try to rather make up one image of 5 parts, that is upper border, bottom border, left and right borders, and the actual content. This is, however, rather inconvenient
Thanks
You are looking for the UIImage method
-(UIImage *)resizableImageWithCapInsets:
Send this message to your original image and pass UIEdgeInsetsMake(topFixedBorderSize, leftFixedBorderSize, bottomFixedBorderSize, rightFixedBorderSize) and you'll get back a "resizable" image. When you draw the resizable image at a larger size only the pixels not covered by the cap insets will be stretched. The pixels covered by the cap insets on every side will remain fixed on the edge.

Resources