How to save a UIImage to Parse - swift

I've taken an image and converted it to the jpeg format as such
let jpgImage = UIImageJPEGRepresentation(image1, 0.5)
Next I want to upload this image to Parse as a object part of a PFUser. When ever I try this I get the error
[Error]: The object is too large -- should be less than 128 kB
I don't know how to fix this error and just sign up the user. Thanks for any help or advice!

Objects are limited to 128kb as the error states, if your image is larger than that as it is you can choose to shrink it by using the function below.
func ResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
let heightRatio = targetSize.height / image.size.height
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSizeMake(size.width * heightRatio, size.height * heightRatio)
} else {
newSize = CGSizeMake(size.width * widthRatio, size.height * widthRatio)
}
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
Use of the above function, you can resize your image as dynamics
dimension.Here as above code resize image of 200*200. By calling the
below function.
self.ResizeImage(UIImage(named: "yourImageName")!, targetSize: CGSizeMake(200.0, 200.0))
Source code from here.
So start by checking the image size by:
let sizeOfImage = image?.size
if let image = image {
let sizeOfImage = image.size
// Check the size here and resize if needed
}

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
}

UIGraphicsImageRenderer producing Larger file size for Smaller image?

I am resizing an image and in doing so I find that the reduced image produces a larger file than the original. This for the same image.
func imageResizedForSMS() -> UIImage? {
guard let image = self.image else {print("No image to resize");return nil}
let maxDimension:CGFloat = 1280
guard max(image.size.width,image.size.height) > maxDimension else {print("Original image within proper sizing");return image}
let scaleRatio = min(image.size.width,image.size.height) / max(image.size.width,image.size.height)
let scaledTarget = maxDimension * scaleRatio
let targetSize = CGSize(width: image.size.width >= image.size.height ? maxDimension : scaledTarget, height: image.size.height >= image.size.width ? maxDimension : scaledTarget)
let renderer = UIGraphicsImageRenderer(size: targetSize)
let scaledImage = renderer.image { _ in
image.draw(in: CGRect(origin: .zero, size: targetSize))
}
let imageData = scaledImage.jpegData(compressionQuality: 1.0)
let imageSize = imageData?.count ?? 0
print("Size of resized image = \(Double(imageSize) / 1000.0) KB")
let imageData2 = image.jpegData(compressionQuality: 1.0)
let imageSize2 = imageData2?.count ?? 0
print("Size of original image = \(Double(imageSize2) / 1000.0) KB")
return scaledImage
}
The original image dimensions are 4032X3024 and the resized dimensions are 1280X960. However, the resized file size is 11733.6 KB while the original file size is 7088.8 KB
From the debugger log:
Size of resized image = 11733.636 KB
Size of original image = 7088.865 KB
Printing description of image:
<UIImage:0x283978b40 anonymous {4032, 3024} renderingMode=automatic>
Printing description of scaledImage:
<UIImage:0x28394d320 anonymous {1280, 960} renderingMode=automatic>
How is that a reduction in image dimensions is producing a much larger file size?
As usual I figure it out shortly after posting the question no matter how much time was spent prior to posting....
The issue appears to be the display scale. If I set a trait with a displayScale of 1 and then use the code above, the file size is indeed much reduced. It drops from the previous 11733KB to 1474KB which is much smaller than the original of 7088KB
The updated portion of the code above that fixes this issue:
let format = UIGraphicsImageRendererFormat(for: UITraitCollection(displayScale: 1))
let renderer = UIGraphicsImageRenderer(size: targetSize, format: format)
let scaledImage = renderer.image { _ in
image.draw(in: CGRect(origin: .zero, size: targetSize))
}

Creating thumbnail -> ugly quality (Swift - preparingThumbnail)

This is how I create a thumbnail from Data:
let image = UIImage(data: data)!
.preparingThumbnail(of: .init(width: size, height: size))!
try image.pngData()!.write(to: url)
The data variable contains the original image. That looks good, but I want to create thumbnails from lists.
The size variable holds a value which is the same height as my Image in SwiftUI. The problem is, it looks horrible:
Thumbnail:
Original:
The 'thumbnail' is the same size as the image above, it really looks that bad on the device, it is not stretched out. What is the correct way to create a thumbnail of the same quality in iOS 15.0>?
Have you tried to consider the aspect ratio as well instead of just the size? Pass in the data (your let image = UIImage(data: data)! and see if that works)
func resizeImageWithAspect(image: UIImage,scaledToMaxWidth width:CGFloat,maxHeight height :CGFloat)->UIImage? {
let oldWidth = image.size.width;
let oldHeight = image.size.height;
let scaledBy = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
let newHeight = oldHeight * scaledBy;
let newWidth = oldWidth * scaledBy;
let newSize = CGSize(width: newWidth, height: newHeight)
UIGraphicsBeginImageContextWithOptions(newSize,false,UIScreen.main.scale);
image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height));
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage
}

How to take a snapshot from UIImage of a UIImageView that is scaleAspectFit mode?

I have an image in a UIImageView:
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = .red
because of .scaleAspectFit the image view has some red borders and thats OK:
User can added some UIView like label or images over the imageView.
In final step I used the following code to save edited image and user can share it or save it to photo library:
private func generateImage() -> UIImage? {
var finalImage: UIImage?
UIGraphicsBeginImageContextWithOptions(CGSize(width: imageView.frame.size.width, height: imageView.frame.size.height), true, 0)
imageView.drawHierarchy(in: CGRect(x: 0, y: 0, width: imageView.frame.size.width, height: imageView.frame.size.height), afterScreenUpdates: true)
finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
The problem is that the finalImage still has the red borders from imageView.
You can get CGRect of the UIImage displayed in the UIImageView in AspectFit content mode. Please create extension of UIImageView like this,
extension UIImageView {
var contentClippingRect: CGRect {
guard let image = image else { return bounds }
guard contentMode == .scaleAspectFit else { return bounds }
guard image.size.width > 0 && image.size.height > 0 else { return bounds }
let scale: CGFloat
if image.size.width > image.size.height {
scale = bounds.width / image.size.width
} else {
scale = bounds.height / image.size.height
}
let size = CGSize(width: image.size.width * scale, height: image.size.height * scale)
let x = (bounds.width - size.width) / 2.0
let y = (bounds.height - size.height) / 2.0
return CGRect(x: x, y: y, width: size.width, height: size.height)
}
}
You can now use imageView.contentClippingRect to read how read the position and size of the image inside.
You have to do minor changes in your method, call your function with appropriate bounds as contentClippingRect.
Let me know in case of any queries.
UPDATE
Please try this UIImageView+Extension, this might help you. It is in Objective-C code, convert it in Swift.
You can try this as well,
let image = #imageLiteral(resourceName: "Cat03")
let x: CGRect = AVMakeRect(aspectRatio: image.size, insideRect: imageView1.frame)
print(x)
Above code gives you size perfectly.

Resize UIImage by keeping Aspect ratio and width

I seen in many posts for resizing the image by keeping aspect ratio. These functions uses the fixed points(Width and Height) for RECT while resizing. But in my project, I need to resize the view based on the Width alone, Height should be taken automatically based on the aspect ratio.
anyone help me to achieve this.
The method of Srikar works very well, if you know both height and width of your new Size.
If you for example know only the width you want to scale to and don't care about the height you first have to calculate the scale factor of the height.
+(UIImage*)imageWithImage: (UIImage*) sourceImage scaledToWidth: (float) i_width
{
float oldWidth = sourceImage.size.width;
float scaleFactor = i_width / oldWidth;
float newHeight = sourceImage.size.height * scaleFactor;
float newWidth = oldWidth * scaleFactor;
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
[sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
If you don't happen to know if the image will be portrait or landscape (e.g user takes pic with camera), I created another method that takes max width and height parameters.
Lets say you have a UIImage *myLargeImage which is a 4:3 ratio.
UIImage *myResizedImage = [ImageUtilities imageWithImage:myLargeImage
scaledToMaxWidth:1024
maxHeight:1024];
The resized UIImage will be 1024x768 if landscape; 768x1024 if portrait. This method will also generate higher res images for retina display.
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
} else {
UIGraphicsBeginImageContext(size);
}
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
+ (UIImage *)imageWithImage:(UIImage *)image scaledToMaxWidth:(CGFloat)width maxHeight:(CGFloat)height {
CGFloat oldWidth = image.size.width;
CGFloat oldHeight = image.size.height;
CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
CGFloat newHeight = oldHeight * scaleFactor;
CGFloat newWidth = oldWidth * scaleFactor;
CGSize newSize = CGSizeMake(newWidth, newHeight);
return [ImageUtilities imageWithImage:image scaledToSize:newSize];
}
Best answer Maverick 1st's correctly translated to Swift (working with latest swift 3):
func imageWithImage (sourceImage:UIImage, scaledToWidth: CGFloat) -> UIImage {
let oldWidth = sourceImage.size.width
let scaleFactor = scaledToWidth / oldWidth
let newHeight = sourceImage.size.height * scaleFactor
let newWidth = oldWidth * scaleFactor
UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
sourceImage.draw(in: CGRect(x:0, y:0, width:newWidth, height:newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
thanks #Maverick1st the algorithm, I implemented it to Swift, in my case height is the input parameter
class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
let scale = newHeight / image.size.height
let newWidth = image.size.width * scale
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
This method is a category on UIImage. Does scale to fit in few lines of code using AVFoundation.
Don't forget to import #import <AVFoundation/AVFoundation.h>.
#implementation UIImage (Helper)
- (UIImage *)imageScaledToFitToSize:(CGSize)size
{
CGRect scaledRect = AVMakeRectWithAspectRatioInsideRect(self.size, CGRectMake(0, 0, size.width, size.height));
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
[self drawInRect:scaledRect];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
#end
Swift 5 version of aspect-fit-to-height, based on answer by #János
Uses the modern UIGraphicsImageRenderer API, so a valid UIImage is guaranteed to return.
extension UIImage
{
/// Given a required height, returns a (rasterised) copy
/// of the image, aspect-fitted to that height.
func aspectFittedToHeight(_ newHeight: CGFloat) -> UIImage
{
let scale = newHeight / self.size.height
let newWidth = self.size.width * scale
let newSize = CGSize(width: newWidth, height: newHeight)
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image { _ in
self.draw(in: CGRect(origin: .zero, size: newSize))
}
}
}
You can use this in conjunction with a (vector-based) PDF image asset, to preserve quality at any render size.
The simplest way is to set the frame of your UIImageView and set the contentMode to one of the resizing options.
The code goes like this - This can be used as an utility method -
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Just import AVFoundation and use AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)
Well, we have few good answers here for resizing image, but I just modify as per my need. hope this help someone like me.
My Requirement was
If image width is more than 1920, resize it with 1920 width and maintaining height with original aspect ratio.
If image height is more than 1080, resize it with 1080 height and maintaining width with original aspect ratio.
if (originalImage.size.width > 1920)
{
CGSize newSize;
newSize.width = 1920;
newSize.height = (1920 * originalImage.size.height) / originalImage.size.width;
originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];
}
if (originalImage.size.height > 1080)
{
CGSize newSize;
newSize.width = (1080 * originalImage.size.width) / originalImage.size.height;
newSize.height = 1080;
originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];
}
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
{
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Thanks to #Srikar Appal , for resizing I have used his method.
You may like to check this as well for resize calculation.
Programmatically:
imageView.contentMode = UIViewContentModeScaleAspectFit;
Storyboard:
If somebody needs this solution in Swift 5:
private func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
let scale = newHeight / image.size.height
let newWidth = image.size.width * scale
UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
image.draw(in:CGRect(x:0, y:0, width:newWidth, height:newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
To improve on Ryan's answer:
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
CGFloat oldWidth = image.size.width;
CGFloat oldHeight = image.size.height;
//You may need to take some retina adjustments into consideration here
CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
return [UIImage imageWithCGImage:image.CGImage scale:scaleFactor orientation:UIImageOrientationUp];
}
Ryan's Solution #Ryan
in swift code
use:
func imageWithSize(image: UIImage,size: CGSize)->UIImage{
if UIScreen.mainScreen().respondsToSelector("scale"){
UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.mainScreen().scale);
}
else
{
UIGraphicsBeginImageContext(size);
}
image.drawInRect(CGRectMake(0, 0, size.width, size.height));
var newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
//Summon this function VVV
func resizeImageWithAspect(image: UIImage,scaledToMaxWidth width:CGFloat,maxHeight height :CGFloat)->UIImage
{
let oldWidth = image.size.width;
let oldHeight = image.size.height;
let scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
let newHeight = oldHeight * scaleFactor;
let newWidth = oldWidth * scaleFactor;
let newSize = CGSizeMake(newWidth, newHeight);
return imageWithSize(image, size: newSize);
}
extension UIImage {
/// Returns a image that fills in newSize
func resizedImage(newSize: CGSize) -> UIImage? {
guard size != newSize else { return self }
let hasAlpha = false
let scale: CGFloat = 0.0
UIGraphicsBeginImageContextWithOptions(newSize, !hasAlpha, scale)
draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
/// Returns a resized image that fits in rectSize, keeping it's aspect ratio
/// Note that the new image size is not rectSize, but within it.
func resizedImageWithinRect(rectSize: CGSize) -> UIImage? {
let widthFactor = size.width / rectSize.width
let heightFactor = size.height / rectSize.height
var resizeFactor = widthFactor
if size.height > size.width {
resizeFactor = heightFactor
}
let newSize = CGSize(width: size.width / resizeFactor, height: size.height / resizeFactor)
let resized = resizedImage(newSize: newSize)
return resized
}
}
When scale is set to 0.0, the scale factor of the main screen is used, which for Retina displays is 2.0 or higher (3.0 on the iPhone 6 Plus).
In Swift 3 there are some changes.
Here is an extension to UIImage:
public extension UIImage {
public func resize(height: CGFloat) -> UIImage? {
let scale = height / self.size.height
let width = self.size.width * scale
UIGraphicsBeginImageContext(CGSize(width: width, height: height))
self.draw(in: CGRect(x:0, y:0, width:width, height:height))
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
}
Calculates the best height of the image for available width.
import Foundation
public extension UIImage {
public func height(forWidth width: CGFloat) -> CGFloat {
let boundingRect = CGRect(
x: 0,
y: 0,
width: width,
height: CGFloat(MAXFLOAT)
)
let rect = AVMakeRect(
aspectRatio: size,
insideRect: boundingRect
)
return rect.size.height
}
}
Zeeshan Tufail and Womble answers in Swift 5 with small improvements.
Here we have extension with 2 functions to scale image to maxLength of any dimension and jpeg compression.
extension UIImage {
func aspectFittedToMaxLengthData(maxLength: CGFloat, compressionQuality: CGFloat) -> Data {
let scale = maxLength / max(self.size.height, self.size.width)
let format = UIGraphicsImageRendererFormat()
format.scale = scale
let renderer = UIGraphicsImageRenderer(size: self.size, format: format)
return renderer.jpegData(withCompressionQuality: compressionQuality) { context in
self.draw(in: CGRect(origin: .zero, size: self.size))
}
}
func aspectFittedToMaxLengthImage(maxLength: CGFloat, compressionQuality: CGFloat) -> UIImage? {
let newImageData = aspectFittedToMaxLengthData(maxLength: maxLength, compressionQuality: compressionQuality)
return UIImage(data: newImageData)
}
}
This one was perfect for me. Keeps aspect ratio and takes a maxLength. Width or Height will not be more than maxLength
-(UIImage*)imageWithImage: (UIImage*) sourceImage maxLength: (float) maxLength
{
CGFloat scaleFactor = maxLength / MAX(sourceImage.size.width, sourceImage.size.height);
float newHeight = sourceImage.size.height * scaleFactor;
float newWidth = sourceImage.size.width * scaleFactor;
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
[sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
I have solved it in a much simpler way
UIImage *placeholder = [UIImage imageNamed:#"OriginalImage.png"];
self.yourImageview.image = [UIImage imageWithCGImage:[placeholder CGImage] scale:(placeholder.scale * 1.5)
orientation:(placeholder.imageOrientation)];
multiplier of the scale will define the scalling of the image,more the multiplier smaller the image. so You can check what fits your screen.
Or you can also get the multiplire by dividing imagewidth/screenwidth.