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
Related
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.
So I am building a meme app that lets you create your own memes by changing the text of two labels.
General Layout
The app consists of an ImageView across the whole scene with contentMode aspectFit. So some pictures are resized when picked.
Taking a screenshot with blank spaces above and below
When I take a screenshot of the image via the following code I get the correct result. However, the resulting image has blank spaces above and below.
private func generateMemedImage() -> UIImage {
//self.navigationController?.setNavigationBarHidden(true, animated: false)
// toolBar.isHidden = true
// Render view to an image
// Parameter 0.0 is required, so the generated image is not blurry.
UIGraphicsBeginImageContextWithOptions(view.frame.size, false, 0.0)
view.drawHierarchy(in: view.frame, afterScreenUpdates: true)
var memedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
//self.navigationController?.setNavigationBarHidden(false, animated: false)
//toolBar.isHidden = false
return memedImage
}
Result with above code
So to automatically position the labels I have introduced a rectangle containingImageHelperView(illustrated in red below) which is basically a view that is added on top of all other views. (In reality the view is transparent)
Now I want to take a screenshot of only the red area.
private func generateMemedImage() -> UIImage {
//self.navigationController?.setNavigationBarHidden(true, animated: false)
// toolBar.isHidden = true
// Render view to an image
// Parameter 0.0 is required, so the generated image is not blurry.
UIGraphicsBeginImageContextWithOptions(containingImageHelperView!.frame.size, false, 0.0)
view.drawHierarchy(in: containingImageHelperView!.frame, afterScreenUpdates: true)
var memedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
//self.navigationController?.setNavigationBarHidden(false, animated: false)
//toolBar.isHidden = false
return memedImage
}
However, I get weird results. On emulator I just get a blank (white) picture and on a real device I get something like this (the red circle was only added for privacy purposes):
Notice, that the resulting screenshots have the correct size. But they do not show the contents as expected.
I hope I was clear enough. Please help!
If it helps to understand the whole project clearer, you can take a look at it here: https://github.com/Shanakor/MemeMe
I have a tableview which one of it's cells at the bottom have a button which has to take a screenshot of the whole screen and the whole content of the table view.
I manage to screenshot at it with the following code
#objc func shareReceipt(sender:UIButton){
self.receiptVC.tableView.setContentOffset(CGPoint.zero, animated: true)
let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(receiptVC.tableView.contentSize
, false, scale);
layer.render(in: UIGraphicsGetCurrentContext()!)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(screenshot!, nil, nil, nil)
}
The Problem I'm having is that when the screenshot is taken, the tableview is showing the last cells (with the share button).
I believe that happens because when I execute
self.receiptVC.tableView.setContentOffset(CGPoint.zero, animated: true)
the UI is not updated on time for when I screenshot at it.
My question is... what can I do to update de UI (set table view to top) and then screenshot it?
So I have a UIImageView with some text overlayed on the top and bottom. I want to get a screenshot so I have a new image with the text overlayed on it. This is the code I was working with but I am unable to take a screenshot of the my UIImageView object properly.
func generateImage() -> UIImage
{
// Render view to an image
UIGraphicsBeginImageContext(self.view.frame.size)
view.drawViewHierarchyInRect(self.imageView.frame,
afterScreenUpdates: true)
let memeImage: UIImage =
UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return memeImage
}
Alternatively, I have also tried the code below, though the image saved is the right size/area of the screen, it ends up with blurry version of what I took a screenshot of:
UIGraphicsBeginImageContext(self.imageView.frame.size)
let context = UIGraphicsGetCurrentContext()
imageView.layer.renderInContext(context!) // tried drawInContext but it didn't work at all
let memeImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return memeImage
First, using UIGraphicsBeginImageContextWithOptions will allow you to adjust the scale factor to suit your screen size. Second, passing in the view you want to capture will ensure that you are working with the correct view/subviews.
func generateImage(currentView: UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(currentView.frame.size, true, 0.0)
currentView.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let memeImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//UIImageWriteToSavedPhotosAlbum(memeImage, nil, nil, nil)
return memeImage
}
I am creating a vertical scrolling game in SpriteKit and I would like to take a screenshot of the entire game scene once the game ends including the parts that have scrolled off screen. So far I am only able to capture the part of the screen that is visible using the following:
let bounds = self.scene!.view?.bounds
UIGraphicsBeginImageContextWithOptions(bounds!.size, true, UIScreen.mainScreen().scale)
self.scene?.view!.drawViewHierarchyInRect(bounds!, afterScreenUpdates: true)
screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Is it possible to get the entire scene?
Thanks.
I was seeing your code and I don't see any problem at all; in fact I tested it (made it a function) and it works perfectly .
func getScreenshot(scene: SKScene) -> UIImage {
let bounds = self.scene!.view?.bounds
UIGraphicsBeginImageContextWithOptions(bounds!.size, true, UIScreen.mainScreen().scale)
self.scene?.view!.drawViewHierarchyInRect(bounds!, afterScreenUpdates: true)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return screenshot;
}
I've tested it myself as it is and works; hope it helps :)