White Space Around Resized Image - swift

I'm trying to Resize Image by preserving aspect ratio.But there is this white space surrounding the resized image.
extension NSImage {
func resizeTo(width: CGFloat, height: CGFloat) -> NSImage {
let ratioX = width / size.width
let ratioY = height / size.height
let ratio = ratioX < ratioY ? ratioX : ratioY
let newHeight = size.height * ratio
let newWidth = size.width * ratio
let canvasSize = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
let img = NSImage(size: canvasSize)
img.lockFocus()
let context = NSGraphicsContext.current()
context?.imageInterpolation = .high
draw(in: NSRect(origin: .zero, size: NSSize(width: newWidth,height: newHeight)), from: NSRect(origin: .zero, size: size) , operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
}
What I'm I doing wrong?

First you are picking the smallest ratio from ratioX and ratioY, but later you create canvas using ratioX (of size width, height * ratioX). I'd say you need to create canvas using newWidth and newHeight.
let canvasSize = CGSize(width: newWidth, height: newHeight)
Additionally, be aware that this script will resize in both directions, i.e. will increase the size of small images.

Related

Unable to change image size in my draw function

In my meme application, I want the user to be able to put text on image. To make this possible I am using UIGraphics. In my scene, I have an image drawn on the background and a text showing on the foreground.
Here is my code for generating the so said image :
func GenerateMemeFrom(image: UIImage, topText: NSString, bottomText: NSString) -> UIImage {
let scale: CGFloat = 4
let size = CGSize(width: UIScreen.main.bounds.size.width * scale, height: UIScreen.main.bounds.size.height * scale)
UIGraphicsBeginImageContext(size)
let textAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.font: UIFont(name: "HelveticaNeue-CondensedBlack", size: 200)!,
NSAttributedString.Key.foregroundColor: UIColor.white,
]
let ratio = UIScreen.main.bounds.size.width / image.size.width
let imageSize = CGSize(width: UIScreen.main.bounds.size.width * scale, height: image.size.height * ratio * scale)
image.draw(in: CGRect(origin: CGPoint.zero, size: imageSize))
let point = CGPoint(x: UIScreen.main.bounds.size.width * scale / 2, y: 100)
let rect = CGRect(origin: point, size: image.size)
topText.draw(in: rect, withAttributes: textAttributes)
let generatedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return generatedImage!
}
Here is what I have on my screen : Image
But whether I put scale equal to 2 or 4, it changes nothing in the application. I want to be able to change size based on screen width. Furthermore, I want the image to be centered. Is there any way to do so ?

How to resize image from library of UIImagePickerController

How to resize image from UIImagePickerController if the length, width, or both of the photos exceed 1500, both the length and width must be reduced to 65%. For example if the size of the photo is 2000x3000 after resizing both parameters should be multiplied by 0.65 and become 1300x1950.
And, if the length and width of the photo does not exceed 1500, the photo should remain unchanged
Please find the code to resize based on max size and scale.
extension UIImage {
func resizeImage(maxSize: CGFloat, scale : CGFloat) -> UIImage {
let size = self.size
if (size.width > maxSize || size.height > maxSize) {
let newSize = CGSize(width: size.width * scale, height: size.height * scale)
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
self.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
return self
}
}
let resizedImage = yourImage.resizeImage(maxSize: 1500, scale: 0.65)

Keep same image quality after converting in swift

I am referring to ZImageCropper for my project to crop an image. However, it reduces the quality of the image during conversion.
I know one of the reasons the quality of image was reduced is due to UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, 1)
I have tried changing it to UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, 0) and UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, UIScreen.main.scale)
I reference my code from Resize and Crop 2 Images affected the original image quality It does help but when I check the quality of the image, it is still reduced. Is there any way to prevent a reduction in image quality?
in iOS 10 and above you can resize any UIImage without quality loss, hope this helps:
func resize(targetSize: CGSize) -> UIImage {
if #available(iOS 10.0, *) {
return UIGraphicsImageRenderer(size: targetSize).image { _ in
self.draw(in: CGRect(origin: .zero, size: targetSize))
}
} else {
return resizeImage(maxSize: targetSize.width)
}
}
func resizeImage(maxSize: CGFloat) -> UIImage {
var newWidth = size.width
var newHeight = size.height
if size.width >= maxSize {
newWidth = min(maxSize, size.width)
newHeight = maxSize * size.height / size.width
} else if size.height >= maxSize {
newHeight = min(maxSize, size.height)
newWidth = maxSize * size.width / size.height
}
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}

Resizing NSImage Shifts its Origin and Producing Wrong Results

I'm using the following code to Resize an Image(Keeping Aspect Ratio).When I try to resize an Image whose size is 2432X3648 Pixels to 1800X2700 Pixels
The output image origin gets shifted.
extension NSImage {
func resizeTo(width: CGFloat, height: CGFloat) -> NSImage {
let ratioX = width / size.width
let ratioY = height / size.height
var ratio = ratioX < ratioY ? ratioX : ratioY
let newHeight = size.height * ratio
let newWidth = size.width * ratio
let canvasSize = CGSize(width: newWidth, height: newHeight)
let img = NSImage(size: canvasSize)
img.lockFocus()
let context = NSGraphicsContext.current()
context?.imageInterpolation = .high
draw(in: NSRect(origin: .zero, size: NSSize(width: newWidth,height: newHeight)), from: NSRect(origin: .zero, size: size) , operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
}
Please see the resized sample image.I have marked the Image.The resizing code seems to work fine in other cases.Please advice..
UPDATE:
#LeoDabus I have used your code and it produces similar result for output size 1084X2086 Pixels.I had to slightly modify your code - only on a single line as it won't compile.The compiler auto suggested it.
NSGraphicsContext.current()?.imageInterpolation = .high
func resizeTo(width: CGFloat, height: CGFloat) -> NSImage {
let ratioX = width / size.width
let ratioY = height / size.height
let ratio = ratioX < ratioY ? ratioX : ratioY
let newHeight = size.height * ratio
let newWidth = size.width * ratio
let canvasSize = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
let img = NSImage(size: canvasSize)
img.lockFocus()
NSGraphicsContext.current()?.imageInterpolation = .high
draw(in: NSRect(origin: CGPoint(x: (canvasSize.width - (size.width * ratio)) / 2, y: (canvasSize.height - (size.height * ratio)) / 2), size: NSSize(width: newWidth,height: newHeight)), from: NSRect(origin: .zero, size: size), operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
What was actually wrong was only the canvas size which should be using the new width and height:
extension NSImage {
func resizedTo(width: CGFloat, height: CGFloat) -> NSImage {
let ratio = min(canvas.width/size.width, canvas.height/size.height)
let canvasSize = NSSize(width: size.width * ratio, height: size.height * ratio)
let img = NSImage(size: canvasSize)
img.lockFocus()
NSGraphicsContext.current?.imageInterpolation = .high
draw(in: NSRect(origin: CGPoint(x: (canvasSize.width - (size.width * ratio)) / 2, y: (canvasSize.height - (size.height * ratio)) / 2), size: canvasSize), from: NSRect(origin: .zero, size: size), operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
}

Resizing an Image by preserving aspect ratio in swift

I have the following extension to resize an image.
extension NSImage {
func resizeImage(width: CGFloat, _ height: CGFloat) -> NSImage {
let img = NSImage(size: CGSize(width:width, height:height))
img.lockFocus()
let ctx = NSGraphicsContext.current()
ctx?.imageInterpolation = .high
self.draw(in: NSMakeRect(0, 0, width, height), from: NSMakeRect(0, 0, size.width, size.height), operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
}
On resizing the aspect ratio is not preserved.
How can I modify the code to preserve aspect ratio?
Please advice.
Update:
This the logic used in C# .I don't know how to do this in swift.
double ratioX = (double) canvasWidth / (double) originalWidth;
double ratioY = (double) canvasHeight / (double) originalHeight;
// use whichever multiplier is smaller
double ratio = ratioX < ratioY ? ratioX : ratioY;
// now we can get the new height and width
int newHeight = Convert.ToInt32(originalHeight * ratio);
int newWidth = Convert.ToInt32(originalWidth * ratio);
// Now calculate the X,Y position of the upper-left corner
// (one of these will always be zero)
int posX = Convert.ToInt32((canvasWidth - (originalWidth * ratio)) / 2);
int posY = Convert.ToInt32((canvasHeight - (originalHeight * ratio)) / 2);
You can change your method signature to make it scale your image using a percentage instead of a size:
extension NSImage {
func resizedTo(width: CGFloat, height: CGFloat) -> NSImage {
let ratioX = width / size.width
let ratioY = height / size.height
let ratio = ratioX < ratioY ? ratioX : ratioY
let canvasSize = NSSize(width: size.width * ratio, height: size.height * ratio)
let img = NSImage(size: canvasSize)
img.lockFocus()
NSGraphicsContext.current?.imageInterpolation = .high
draw(in: NSRect(origin: CGPoint(x: (canvasSize.width - (size.width * ratio)) / 2, y: (canvasSize.height - (size.height * ratio)) / 2), size: canvasSize), from: NSRect(origin: .zero, size: size), operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
func resizedTo(percentage: CGFloat) -> NSImage {
let canvasSize = CGSize(width: size.width * percentage, height: size.height * percentage)
let img = NSImage(size: canvasSize)
img.lockFocus()
NSGraphicsContext.current?.imageInterpolation = .high
draw(in: NSRect(origin: .zero, size: canvasSize), from: NSRect(origin: .zero, size: size), operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
func resizedTo(width: CGFloat) -> NSImage {
let canvasSize = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
let img = NSImage(size: canvasSize)
img.lockFocus()
NSGraphicsContext.current?.imageInterpolation = .high
draw(in: NSRect(origin: .zero, size: canvasSize), from: NSRect(origin: .zero, size: size), operation: .copy, fraction: 1)
img.unlockFocus()
return img
}
}