Crop Image so It Becomes Full Screen like Snapchat - swift

If you upload a picture to Snapchat (that isn't already full screen), it will zoom in and crop the photo so that it becomes full screen. I am able to do this in my ImageView using autoresizing masks, but I need to be able to save the image in this cropped state and I can't figure out how to do it.
This is how I am able to display the image (selected from camera roll) in the image view how I want it
let imgView = UIImageView(image: image)
imgView.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleBottomMargin, .flexibleRightMargin, .flexibleLeftMargin, .flexibleTopMargin]
imgView.contentMode = .scaleAspectFill
imgView.clipsToBounds = true
imgView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
self.view.addSubview(imgView)
This turns a non-full screen photo and displays it full screen with the propping zoom/crop. How can I now save the photo as a full screen photo?

you can capture an image from given views.
func image(with view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
view.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
return nil
}
let img = image(with: YourImageView)

Related

How to crop to the center square of a UIImage

All the stack overflow posts about this are very dated (at least 5 years old). I have images that are loaded remotely via AWS cloudfront and have aspect ratios similar to the aspect ratio of a phone screen. I need to get this images to squares, without stretching the image. I'd like to just crop them to the center square of the image. I've tried the below code, but specifying the content mode as .scaleAspectFill (which should just 'zoom' to the center square so it fits the UIImageView's frame) doesn't work:
let view = UIView()
let imageView = UIImageView()
imageView.load(url: url)
imageView.contentMode = .scaleAspectFill
imageView.frame = CGRect(x: 0, y: 0, width: 70, height: 70)
view.addSubview(imageView)
return view
The load function looks like this:
extension UIImageView {
func load(url: URL) {
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
}
}
}
}
}
}

Swift ImageCropper returns an image outside of the specified "window"

I am making an app that has a UIWebView along with a button on a single view controller. When the button is clicked, an image (of the UIWebView) is captured using UIGraphicsContext.
This part works great! But when the button is clicked, after capturing the image, it displays the image as a subview on the same view, and I have been trying to use an ImageCropper Library that draws a CGRect in another subview over the UIImageView on the screen with a submit button. The rectangle itself can be resized (dragging the corners/edges) and moved around the view.
When the submit button is clicked, another subview is displayed in the top left hand portion of screen and display the image that was cropped (after clicking submit button) The idea is to only capture what is inside the rectangle. I am able to get the code working but the image captured is of the same image but not a section that is inside the CGRect.
I have 3 images that show how it works and shows the image that is cropped incorrectly.enter image description here . Shot 1 . Shot 2
Shot 3. I believe my problems lies within the size of image captured and the size of the image with the crop rect are not equal and that is why it is distorting it.
Does anyone know what might be the cause? Sorry for the long winded question but any help would be greatly appreciated!
Here is my code below:
ViewController.swift:
class ViewController: UIViewController {
#IBOutlet var webView: UIWebView!
#IBOutlet var imageView: UIImageView!
override func viewDidLoad() {
imageView.isHidden = true
let aString = URL(string: "https://www.kshuntfishcamp.com/home.page")
webView.loadRequest(URLRequest(url: aString!))
super.viewDidLoad()
}
#IBAction func takePhotoPressed(_ sender: UIButton) {
UIGraphicsBeginImageContextWithOptions(webView.bounds.size, false, 0.0)
if let aContext = UIGraphicsGetCurrentContext(){
webView.layer.render(in: aContext)
}
let capturedImage:UIImage? = UIGraphicsGetImageFromCurrentImageContext()
imageView = UIImageView(frame: CGRect(x: 22, y: 123, width: 330, height: 330))
let image = capturedImage
imageView.image = image
imageView.contentMode = UIViewContentMode.scaleAspectFill
imageView.clipsToBounds = true
imageView.isHidden = true
webView.isHidden = true
let editView = EditImageView(frame: self.view.frame)
let image2 = capturedImage!
editView.initWithImage(image: image2)
let croppedImage = editView.getCroppedImage()
self.view.addSubview(editView)
self.view.backgroundColor = UIColor.clear
UIImageWriteToSavedPhotosAlbum(croppedImage, nil, nil, nil)
}
EditImageView.swift - source (https://github.com/Thanatos-L/LyEditImageView)-only including parts that seem relevant to solving the problem
func initWithImage(image:UIImage){
imageView = UIImageView(frame: CGRect(x: 22, y: 123, width: 330, height: 330))
imageView.tag = IMAGE_VIEW_TAG;
self.addSubview(self.imageView)
imageView.isUserInteractionEnabled = true;
imageView.image = image
imageView.frame = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
let frame = AVMakeRect(aspectRatio: imageView.frame.size, insideRect: self.frame);
imageView.frame = frame
originImageViewFrame = frame
NSLog("initWithImage %#", NSStringFromCGRect(originImageViewFrame))
imageZoomScale = 1.0
commitInit()
}
private func cropImage() {
let rect = self.convert(cropView.frame, to: imageView)
let imageSize = imageView.image?.size
let ratio = originImageViewFrame.size.width / (imageSize?.width)!
let zoomedRect = CGRect(x: rect.origin.x / ratio, y: rect.origin.y / ratio, width: rect.size.width / ratio, height: rect.size.height / ratio)
let croppedImage = cropImage(image: imageView.image!, toRect: zoomedRect)
var view: UIImageView? = self.viewWithTag(1301) as? UIImageView
if view == nil {
view = UIImageView()
}
view?.frame = CGRect(x: 0, y: 0, width: croppedImage.size.width , height: croppedImage.size.height)
view?.image = croppedImage
view?.tag = 1301
self.addSubview(view!)
}

WKWebView Swift - Make screenshot of website without the fixed menu bar

I'm using Xcode Swift 3 and WKWebView to display the websites. Then I try to screen capture the website using the following code that I've found from the Internet. There are some websites that come with a fixed menu bar either at the top or bottom of the website. Hence, as I scroll the website, the menu bar does not move with the browser and is fixed on the screen. The problem is this fixed menu bar of the website appears on my screenshot. Is there a way to make a screenshot without the fixed menu bar? Thanks in advance for your help.
func snapshot(of rect: CGRect? = nil) -> UIImage? {
// snapshot entire view
UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
drawHierarchy(in: bounds, afterScreenUpdates: true)
let wholeImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// if no `rect` provided, return image of whole view
guard let image = wholeImage, let rect = rect else { return wholeImage }
// otherwise, grab specified `rect` of image
let scale = image.scale
let scaledRect = CGRect(x: rect.origin.x * scale, y: rect.origin.y * scale, width: rect.size.width * scale, height: rect.size.height * scale)
guard let cgImage = image.cgImage?.cropping(to: scaledRect) else { return nil }
return UIImage(cgImage: cgImage, scale: scale, orientation: .up)
}

Image shown in imageView loses aspect ratio and becomes squished when saved to camera roll

I'm making an image app that can put simple frames over images loaded into the imageView and save them as a new image for practice, because I'm very new to swift and trying to learn. These screenshots show the frame hidden because the problem is with the image loaded behind the frame.
My rep isn't high enough to post images but the specific issue is: Image shown in imageView loses aspect ratio and becomes squished widthwise when saved to camera roll.
I have my imageView's constraints set to maintain a specific aspect ratio with any sized device so it grows and shrinks accordingly. I also have it's content mode set to aspect fill via IB.
The aspect fill works exactly how I'd expect until I save the image. When I hit save the image inside the image view instantly squishes width wise and loses its aspect ratio.
I import the image to the imageView with this:
func importPicture() {
let picker = UIImagePickerController()
picker.allowsEditing = true
picker.delegate = self
present(picker, animated: true)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else { return }
dismiss(animated: true)
currentImage = image
unchangedImage = image
self.imageView.image = currentImage
}
Then I draw:
func drawImagesAndText() {
let renderer = UIGraphicsImageRenderer(size: CGSize(width: imageView.bounds.size.width, height: imageView.bounds.size.height))
img = renderer.image { ctx in
let bgImage = currentImage
bgImage?.draw(in: CGRect(x: 0, y: 0, width: imageView.bounds.size.width, height: imageView.bounds.size.height))
let frame = UIImage(named: "5x4frame")
frame?.draw(in: CGRect(x: 0, y: 0, width: imageView.bounds.size.width, height: imageView.bounds.size.height))
}
imageView.image = img
}
This was the only way I could think to do it to allow the image to be drawn while also having the image view dynamic.
this is the save function I'm using, I have this function tied to a "save button's" outlet from IB.
UIImageWriteToSavedPhotosAlbum(img, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
thanks for any and all advice

Extra white space when get visible content of UIScrollView

There is a UIImageView inside a UIScrollView which user can scale it down and up and then save it:
The area under the navigation bar and top of the tab bar is UIScrollView frame.
When user hits Done, image will be save in camera roll. It's what saved there (Photos App):
I have no idea what is this empty space in the saved image.
It's my code to save the image:
UIGraphicsBeginImageContextWithOptions(scrollView.frame.size, false, 0.0)
let rect = CGRectMake(0, scrollView.frame.origin.y, scrollView.frame.size.width, scrollView.frame.size.height)
self.view.drawViewHierarchyInRect(rect, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
let imageData = UIImageJPEGRepresentation(image, 1)
let compressedJPGImage = UIImage(data: imageData!)
UIImageWriteToSavedPhotosAlbum(compressedJPGImage!, nil, nil, nil)
What I want to save is exactly the visible region of UIScrollView.
I had to use CGContextTranslateCTM() to translate the rectangle:
let screenRect: CGRect = scrollView.bounds
UIGraphicsBeginImageContext(screenRect.size)
let ctx: CGContextRef = UIGraphicsGetCurrentContext()!
CGContextTranslateCTM(ctx,0,-scrollView.frame.origin.y)
UIColor.blackColor().set()
CGContextFillRect(ctx, screenRect)
view.layer.renderInContext(ctx)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()