adding image to called function from another class in swift - swift

I have started working with swift recently. I have a function to resize the image in one swift file and I wanted to call it in another swift file. Here is the function which was added in class UIImage:
public extension UIImage{
class func scalePreservingAspectRatio(targetSize: CGSize) -> UIImage {
let uimageview = UIImage()
let widthRatio = targetSize.width / uimageview.size.width
let heightRatio = targetSize.height / uimageview.size.height
let scaleFactor = min(widthRatio, heightRatio)
let scaledImageSize = CGSize(
width: uimageview.size.width * scaleFactor,
height: uimageview.size.height * scaleFactor
)
let renderer = UIGraphicsImageRenderer(
size: scaledImageSize
)
let scaledImage = renderer.image { _ in
uimageview.draw(in: CGRect(
origin: .zero,
size: scaledImageSize
))
}
return scaledImage
}
}
so when I want to call this function in another file to resize "myimage", I think I should write like this:
let image = UIImage(named: "myimage")
let targetSize = CGSize(width: 100, height: 100)
let scaledImage = image.UIImage.scalePreservingAspectRatio(targetSize: targetSize)
but by adding 'image' before UIImage.scalePreservingAspectRatio(), it does not recognize the function and it shows an error: Value of type 'UIImage?' has no member 'UIImage'. So I don't know how I can use my image for this function in another file.

If you want to call it on UIImage, it needs to be put into an extension:
extension UIImage {
func scalePreservingAspectRatio(targetSize: CGSize) -> UIImage {
...
}
}
You also probably want it to be able to access the image that you call it on, so remove class from the function declaration. Then you can call it like:
image.scalePreservingAspectRatio(targetSize: size)
Then update the code to use self instead of creating a new source image:
func scalePreservingAspectRatio(targetSize: CGSize) -> UIImage {
let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height
let scaleFactor = min(widthRatio, heightRatio)
let scaledImageSize = CGSize(
width: size.width * scaleFactor,
height: size.height * scaleFactor
)
let renderer = UIGraphicsImageRenderer(
size: scaledImageSize
)
let scaledImage = renderer.image { _ in
self.draw(in: CGRect(
origin: .zero,
size: scaledImageSize
))
}
return scaledImage
}

Related

How to crop a image 3:4 ? Swift

I tried to look up the answer on the Internet and did not find it, maybe I typed my query wrong on the Internet.
Can you tell me how to crop a 3:4 photo? I can't find the function to crop it. Please share?
You can use this function to crop your image in any AspectRatio (e.g 3:4). You have to pass your Image and desired AspectRatio as a parameter to the function and it will return you the Cropped Image.
func crop(image: UIImage, to aspectRatio: CGFloat) -> UIImage {
let originalAspectRatio = image.size.height/image.size.width
var newImagesize = image.size
if originalAspectRatio > aspectRatio {
newImagesize.height = image.size.width * aspectRatio
} else if originalAspectRatio < aspectRatio {
newImagesize.width = image.size.height / aspectRatio
} else {
return image
}
let center = CGPoint(x: image.size.width/2, y: image.size.height/2)
let origin = CGPoint(x: center.x - newImagesize.width/2, y: center.y - newImagesize.height/2)
let cgCroppedImage = image.cgImage!.cropping(to: CGRect(origin: origin, size: CGSize(width: newImagesize.width, height: newImagesize.height)))!
let croppedImage = UIImage(cgImage: cgCroppedImage, scale: image.scale, orientation: image.imageOrientation)
return croppedImage
}
Usage:
let croppedImage = crop(image: "ImageName", to: 3/4)
Use the following function. For more details read this.
func cropImage(_ inputImage: UIImage, toRect cropRect: CGRect, viewWidth: CGFloat, viewHeight: CGFloat) -> UIImage?
{
let imageViewScale = max(inputImage.size.width / viewWidth,
inputImage.size.height / viewHeight)
// Scale cropRect to handle images larger than shown-on-screen size
let cropZone = CGRect(x:cropRect.origin.x * imageViewScale,
y:cropRect.origin.y * imageViewScale,
width:cropRect.size.width * imageViewScale,
height:cropRect.size.height * imageViewScale)
// Perform cropping in Core Graphics
guard let cutImageRef: CGImage = inputImage.cgImage?.cropping(to:cropZone)
else {
return nil
}
// Return image to UIImage
let croppedImage: UIImage = UIImage(cgImage: cutImageRef)
return croppedImage
}

Add transparent padding around NSImage

I need to add some transparent padding around an NSImage.I referred this SO post Placing an NSImage on a transparent canvas in Swift
It was pointing to the the Github code https://gist.github.com/MaciejGad/11d8469b218817290ee77012edb46608 where it mentions of tweaking the resizeWhileMaintainingAspectRatioToSize method. I tried what the post has suggested but swift seems to miss the NSImage.copy method with the NSrect as parameter.So wrote the below extension method with my limited knowledge
func addPadding() -> NSImage? {
let newSize: NSSize
let widthRatio = size.width / self.size.width
let heightRatio = size.height / self.size.height
if widthRatio > heightRatio {
newSize = NSSize(width: floor(self.size.width * widthRatio), height: floor(self.size.height * widthRatio))
} else {
newSize = NSSize(width: floor(self.size.width * heightRatio), height: floor(self.size.height * heightRatio))
}
let img = NSImage(size: newSize)
let frame = NSRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
// Set the drawing context and make sure to remove the focus before returning.
img.lockFocus()
defer { img.unlockFocus() }
let representation = self.bestRepresentation(for: frame, context: nil, hints: nil)
// Draw the new image
if representation!.draw(in: frame) {
return img
}
// Return nil in case something went wrong.
return nil
}
But this does nothing to add padding to the image.
You can do it with this code:
extension NSImage {
var pixelSize: NSSize {
if let rep = self.representations.first {
let size = NSSize(
width: rep.pixelsWide,
height: rep.pixelsHigh
)
return size
}
return NSSize(width: 0, height: 0)
}
func withPadding(percent: Int) -> NSImage {
let originalSize = self.pixelSize
let newHeight = originalSize.height - originalSize.height * CGFloat(percent) / 100
let newWidth = originalSize.width - originalSize.width * CGFloat(percent) / 100
let sizeWithPadding = NSSize(
width: newWidth,
height: newHeight
)
guard let representation = NSBitmapImageRep(
bitmapDataPlanes: nil,
pixelsWide: Int(originalSize.width),
pixelsHigh: Int(originalSize.height),
bitsPerSample: 8,
samplesPerPixel: 4,
hasAlpha: true,
isPlanar: false,
colorSpaceName: .calibratedRGB,
bytesPerRow: 0,
bitsPerPixel: 0
)
else {
return self
}
representation.size = originalSize
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGraphicsContext.init(bitmapImageRep: representation)
let xPoint = (originalSize.width - newWidth) / 2
let yPoint = (originalSize.height - newHeight) / 2
self.draw(
in: NSRect(
x: xPoint,
y: yPoint,
width: sizeWithPadding.width,
height: sizeWithPadding.height
),
from: .zero,
operation: .copy,
fraction: 1.0
)
NSGraphicsContext.restoreGraphicsState()
let newImage = NSImage(size: originalSize)
newImage.addRepresentation(representation)
return newImage
}
}

How to convert pixel dimension to CG Size in Swift?

I have large images uploaded by users in Swift and I need to resize them all to 100x100px to create thumbnails to store in my server. So far I have found that this resizes an image given a CGSize:
func resizedImage(image: UIImage, size: CGSize) -> UIImage? {
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.image { (context) in
image.draw(in: CGRect(origin: .zero, size: size))
}
}
Is there any way to create a CGSize knowing that my target size is strictly 100x100px?
Got this to work:
extension UIImage {
func resizedImage(pixelSize: (width: Int, height: Int)) -> UIImage? {
var size = CGSize(width: CGFloat(pixelSize.width) / UIScreen.main.scale, height: CGFloat(pixelSize.height) / UIScreen.main.scale)
let rect = AVMakeRect(aspectRatio: self.size, insideRect: CGRect(x:0, y:0, width: size.width, height: size.height))
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.image { (context) in
self.draw(in: rect)
}
}
}
You should initialize your render based on the user device scale and multiply its width and height instead of dividing it:
extension UIImage {
func aspectFitScaled(to size: CGSize) -> UIImage {
let format = imageRendererFormat
format.opaque = false
format.scale = UIScreen.main.scale
let isLandscape = self.size.width > self.size.height
let ratio = isLandscape ? size.width / self.size.width : size.height / self.size.height
let drawSize = self.size.scaled(by: ratio)
let x = (size.width - drawSize.width) / 2
let y = (size.height - drawSize.height) / 2
let origin = CGPoint(x: x, y: y)
return UIGraphicsImageRenderer(size: size, format: format).image { _ in
draw(in: CGRect(origin: origin, size: drawSize))
}
}
}
usage:
class ViewController: UIViewController {
// imageView frame is 200 x 200
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// original image size is (719.0, 808.0)
let image = UIImage(data: try! Data(contentsOf: URL(string: "https://i.stack.imgur.com/Xs4RX.jpg")!))!
imageView.backgroundColor = .gray
let ivImage = image.aspectFitScaled(to: imageView.frame.size)
imageView.image = ivImage
print("ivImage.size", ivImage.size) // (200.0, 200.0)
print("ivImage.scale", ivImage.scale) // screen scale 3.0 iPhone 8 Plus
// lets check the real image dimension
let data = ivImage.jpegData(compressionQuality: 1)!
let savedSize = UIImage(data: data)!.size
print("savedSize", savedSize) // savedSize (600.0, 600.0)
}
}

White Border around Resized Image

I'm using the following code to resize an image.But i keep getting a white border at the bottom
func resize(withSize targetSize: NSSize) -> NSImage? {
let size=NSSize(width: floor((targetSize.width/(NSScreen.main?.backingScaleFactor)!)), height:floor( (targetSize.height/(NSScreen.main?.backingScaleFactor)!)))
let frame = NSRect(x: 0, y: 0, width: floor(size.width), height: floor(size.height))
guard let representation = self.bestRepresentation(for: frame, context: nil,hints: nil) else {
return nil
}
let image = NSImage(size: size, flipped: false, drawingHandler: { (_) -> Bool in
return representation.draw(in: frame)
})
return image
}
I have tried using floor function to round off the values.But still the same issue.
extension NSImage {
func resize(withSize targetSize: NSSize) -> NSImage? {
let ratioX = targetSize.width / size.width / (NSScreen.main?.backingScaleFactor ?? 1)
let ratioY = targetSize.height / size.height / (NSScreen.main?.backingScaleFactor ?? 1)
let ratio = ratioX < ratioY ? ratioX : ratioY
let canvasSize = NSSize(width: size.width * ratio, height: size.height * ratio)
let frame = NSRect(origin: .zero, size: canvasSize)
guard let representation = bestRepresentation(for: frame, context: nil, hints: nil)
else { return nil }
return NSImage(size: canvasSize, flipped: false) { _ in representation.draw(in: frame) }
}
}
let image = NSImage(contentsOf: URL(string: "http://i.stack.imgur.com/Xs4RX.jpg")!)!
let resized = image.resize(withSize: .init(width: 400, height: 300)) // w 267 h 300
If you would like to take into account the screen scale just remove the division by (NSScreen.main?.backingScaleFactor ?? 1) from the method when calculating ratioX and ratioY

Resize UIImage Keep Image Quality in Swift

I have created an image from UIView using UIGraphicsGetCurrentContext. It's work fine but when I resized that image to larger size its be blurred with bad quality. Can it possibility to keep quality when resize? I have tried many ways but not work.
- code image:
func image(with view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
context.setAllowsAntialiasing(true)
context.setShouldAntialias(true)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
return nil
}
code I have used to resize, this extension of UIImage
func resizedImage(newSize: CGSize) -> UIImage {
// Guard newSize is different
guard self.size != newSize else { return self }
let aspect_ratio = self.size.width / self.size.height
var image_w = newSize.height * aspect_ratio
let finalSize = CGSize(width: image_w, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(finalSize, false, 0.0)
self.draw(in: CGRect(x: 0, y: 0, width: (CGFloat)(finalSize.width), height: (CGFloat)(newSize.height)))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
and the example image:image
Thanks
Try this:
extension UIImage {
func resizeImage(targetSize: CGSize) -> UIImage {
let size = self.size
let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height
let newSize = widthRatio > heightRatio ? CGSize(width: size.width * heightRatio, height: size.height * heightRatio) : CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
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!
}
}