I have an application where by I take a picture and then go on to present this image in a different UIViewController. However, the resulting UIImage appears to expand beyond the bounds at which I set the UIImageView. The content mode is 'Aspect fill'
After taking the picture, the following method is called:
CaptureImageViewController:
func presentCapturedImage(image: CGImage, observationObj: VNRectangleObservation) -> Void {
print("HERE!")
let prevVC = storyboard?.instantiateViewController(withIdentifier: "prevcrop") as! PreviewCropViewController
prevVC.cgImg = image
prevVC.uiImageEXIF = uiImageEXIF
prevVC.ObserObj = observationObj
DispatchQueue.main.async {
self.present(prevVC, animated: true, completion: nil)
}
}
PresentingViewController calls the following in its viewDidLoad():
#IBOutlet weak var imgPreViewOutlet: UIImageView!
guard
let img = self.cgImg,
let imgEXIF = self.uiImageEXIF else{return}
let uiImage = UIImage.init(cgImage: img)
self.imgPreViewOutlet.image = uiImage
The UIViewController that I use to present the image:
The Constraints of the lower UIView holding the UIButton:
The constraints of the UIImageView:
The resulting view - you can see the image covers almostall of the crop button:
Beware when using aspectFill in UIImageViews. If clipsToBounds is not true, the image will probably extend outside the frame.
This happens as the image is scaled in such a way to fully fill the image view frame. If the proportions of the image and frame aren't exactly identical, the image will extend outside the frame.
Related
I added a UIImageView on an ImageView, so i want to take screenshot of these two imageviews so that they look like one, any other recommendation is also appreciated.
I made a button that helped me take a screen shot, I have added x-axis and y axis,
func takeScreenshot(_ shouldSave: Bool = true) -> UIImage {
var screenshotImage :UIImage?
let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(CGSize(width: 20, height: 104), false, scale);
guard let context = UIGraphicsGetCurrentContext() else {return screenshotImage ?? UIImage(imageLiteralResourceName: "loading")}
layer.render(in:context)
screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let image = screenshotImage, shouldSave {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
return screenshotImage ?? UIImage(named: "loading")!
}
I expect that the screenshot taken, takes the screenshot of the imageview. Screenshot is attached,enter image description here
Put those two image views inside a UIView, constraint them all properly. Then take a screenshot of that UIView. Follow this for screenshot:
How to take screenshot of a UIView in swift?
I believe you're trying to say
You have 2 UIImageViews with different Images and then you want to take a screenshot of those 2 UIImageViews to make 1 image.
If that's the case, the easiest way to do solve it is to wrap those 2 UIImageViews inside a UIView. Then convert that UIView into UIImage. So you can have the Screenshot of those 2 UIImageViews in one.
In case you need code to convert UIView to UIImage:
extension UIView {
func toImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
I'm not sure if this the solution to your problem.
This question already has answers here:
Cropping image with Swift and put it on center position
(15 answers)
Closed 3 years ago.
I am looking to crop a rectangle segment of a screen shot. I am currently getting back no images when i perform the screen shot and subsequent crop. Below is a image of what i would like to crop (the rectangular grid) and my code
The solution presented in : Cropping image with Swift and put it on center position
is not applicable as I am trying to perform a crop of a screenshot, not crop an existing image. Cropping an image as presented in the above solution does not work for rotated UIImageView.
Code:
private func takeScreenShotCrop(cropGridRect: CGRect) -> UIImage?{
let cropGridOrigin = CGPoint.init(x: cropGridRect.origin.x, y: cropGridRect.origin.y)
let cropGridSize = CGSize.init(width: cropGridRect.width, height: cropGridRect.height)
let cropZoneRect = CGRect.init(origin: cropGridOrigin, size: cropGridSize)
UIGraphicsBeginImageContext(cropGridSize)
view.drawHierarchy(in: cropZoneRect, afterScreenUpdates: true)
guard let croppedIm: UIImage = UIGraphicsGetImageFromCurrentImageContext() else{return nil}
UIGraphicsEndImageContext()
return croppedIm
}
Your question is a bit too general perhaps since you gave no data about your hierarchy. I will expect that there is a view (UIView or it's subclass) which has a certain transform that includes rotation (will call it imageView from now on). I will expect there is a view that shows that grid (will call it panel from now on). I will expect that imageView and panel have some common superview parent (they don't need to exactly be same superview, they just need to be in the same window hierarchy).
You can convert frames in relation from one and another. It is a bit of a pain due to transformations but generally you could write something like the following:
func screenshotView(_ viewToScreenshot: UIView, croppedBy cropView: UIView) -> UIImage? {
guard let originalScreenshot: UIImage = {
UIGraphicsBeginImageContext(viewToScreenshot.bounds.size)
viewToScreenshot.drawHierarchy(in: viewToScreenshot.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}() else { return nil }
let panel = UIView(frame: cropView.bounds)
let imageView = UIImageView(frame: viewToScreenshot.bounds)
imageView.image = originalScreenshot
let viewOriginalTransform = viewToScreenshot.transform
viewToScreenshot.transform = .identity
imageView.frame = viewToScreenshot.convert(viewToScreenshot.bounds, to: cropView)
viewToScreenshot.transform = viewOriginalTransform
panel.addSubview(imageView)
imageView.transform = viewOriginalTransform
UIGraphicsBeginImageContext(panel.bounds.size)
panel.drawHierarchy(in: panel.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
And the usage in your case is then
let image = screenshotView(imageView, croppedBy: panel)
So what we do is first grab the screenshot of your image view. This will not crop it nor will it rotate it. It is just an internal snapshot of your view. This may be skipped and just the image is used IF the imageView is in fact UIImageView and the image is presented as it is (no effects like rounded corners).
The snapshot is then placed into a newly created panel and it's frame adjusted depending on the frame relation between the two views. We create a new snapshot from newly generated panel which is the result we are looking for.
To create "the image view" optimization you can simply add a single line:
guard let originalScreenshot: UIImage = {
if let image = (viewToScreenshot as? UIImageView)?.image { return image }
UIGraphicsBeginImageContext(viewToScreenshot.bounds.size)
viewToScreenshot.drawHierarchy(in: viewToScreenshot.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}() else { return nil }
I'm trying to recreate something like this, where I pull the user's image, and then overlay the "Change" label on top- but I can't seem to figure out how.
(I also want to have some sort of action associated with this label (eg, segue to new page))
My issue: I cannot seem to figure out how to overlay the text label but still keep the image round and have the bottom part of the image have that opaque label.
Code+Details: I have a custom UIView, which contains an Imageview- When I want to add an image I call the following code:
self.userProfilePic.addImage((userImg).roundImage(), factorin: 0.95)
Within the custom view, this is how the image is added:
func addImage(imagein: UIImage, factorin:Float)
{
let img = imagein
imageScalingFactor = factorin
if imageView == nil
{
imageView = UIImageView(image: img)
imageView?.contentMode = .ScaleAspectFit
self.addSubview(imageView!)
self.sendSubviewToBack(imageView!)
imageView!.image = img
}
}
This is my code for the image rounding (which I do not want to touch):
extension UIImage
{
func roundImage() -> UIImage
{
let newImage = self.copy() as! UIImage
let cornerRadius = self.size.height/2
UIGraphicsBeginImageContextWithOptions(self.size, false, 1.0)
let bounds = CGRect(origin: CGPointZero, size: self.size)
UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).addClip()
newImage.drawInRect(bounds)
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return finalImage
}
}
Any help would be appreciated!
Try something like this view hierarchy
UIView
!
!--UIImageView
!--UIButton
so you take 'UIView', inside that first add the UIImageView than on the lower portion of the image view add a UIButton. Now set the clipToBounds to yes. Now set the desire corner radius of this parent view's layer as following
parentView.layer.cornerRadius = parentVirew.frame.size.width;
Remember you have to make the parent view of square size, means the height & width should be the same, for getting the circular masking. Adjust the button position a bit. You will definetly get the result.
I found this pattern on pttrns.com. How can I make the Navigation Bar line curvy like this in Swift?
You can just create a blank navigationBar and use the background of the ViewController to create this effect. For example, create the image with this curvy on the top and set the image as ViewController. Create an UIView that cover the entire ViewController and in you class set
var mainScreenSize : CGSize = UIScreen.mainScreen().bounds.size // Getting main screen size of iPhone
#IBOutlet weak var viewBG: UIView!
let imageObbj:UIImage! = self.imageResize(UIImage(named: "YourImage")!, sizeChange: CGSizeMake(mainScreenSize.width, mainScreenSize.height))
self.viewBG.backgroundColor = UIColor(patternImage: image)
EDIT:
Use this function to set the image size to screen size. I change my code above as well.
func imageResize (imageObj:UIImage, sizeChange:CGSize)-> UIImage{
let hasAlpha = false
let scale: CGFloat = 0.0 // Automatically use scale factor of main screen
UIGraphicsBeginImageContextWithOptions(sizeChange, !hasAlpha, scale)
imageObj.drawInRect(CGRect(origin: CGPointZero, size: sizeChange))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
return scaledImage
}
You can't. You have to create your own custom view controller that behaves like a navigation bar for that example.
I have an app that allows a user to add a photo to their photo and save it kind of like a sticker app. I have it set up to take a screen shot right now but the problem I am facing is that it takes a screenshot of the entire UIView so there is a lot of white space and the UIButtons are visible in the final saved photo in the camera roll.
How do I take a screen shot that crops out the white space from the app?
Here's what I have right now...
UIGraphicsBeginImageContextWithOptions(UIScreen.mainScreen().bounds.size, false, 0);
self.view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
var image: UIImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
self.savedImageAlert()
self.dismissViewControllerAnimated(true, completion: nil)
I have played around with making the bounds equal to the UIImageview called userImageView but that made my photo distorted and still had a lot of white space just at the top of the photo instead of the top and the bottom.
I am new to Swift and have a hard time with the CG/UIGraphics stuff so any help would be really appreciated...I've spent hours researching this and have been getting more and more confused!
NOTE/UPDATE: I have changed my code to the following:
// I defined myView outside of both functions so that I could reference myView in both the function and the IBAction function
let myView = UIView()
func imageWithView(myView:UIView)->UIImage{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
view.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
#IBAction func mergeAndSaveImage(sender: AnyObject) {
let newImage = imageWithView(myView)
UIImageWriteToSavedPhotosAlbum(newImage, nil, nil, nil)
self.savedImageAlert()
self.dismissViewControllerAnimated(true, completion: nil)
In my storyboard I set up a new UIView, renamed it and dragged my two UIImageViews underneath it in the document outline.
I am still not able to get this to work, when I save the image it saves the entire screen with white space and UIbuttons.
First, I don't want the image with the Detroit notebook to be so small, on the storyboard it's much bigger but when I run the app it gets small in the uiview.
Second, the code just saves an image of the entire screen...I only want the UIView that contains the two uiimages to be saved as an image.
Here's what it saves as....
Here's what the code saves...
If you could manage to add a photo inside some UIView then this method can help you. You just have to pass the UIView here and for that particular UIView only it will return an UIImage object. It will not take other screen area but just the UIView which you will be passing as a parameter.
So the hierarchy will be like this. There will be a UIImageView within a UIView and all the other things required for your sticker will be there in your same UIView which will be passed in the below method in order to retrieve only the specific bounded UIImage.
That UIImage can easily be saved or retrieved anywhere.
//function to convert the given UIView into an UIImage
func imageWithView(view:UIView)->UIImage{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
view.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
and later on You can save only that image where ever you want.
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
EDIT:On button click perform this:
#IBAction func buttonAction(sender: AnyObject) {
// you will get an UIImage object
let image = imageWithView(yourCustomView)
//Then save your image
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
Here is the screenshot