Why is my screenshot not displaying current view? - swift

When I take a screenshot to share the current view of my device (iPhone), it only takes the upper part of it, and when I scroll down to the bottom (of my tableview at runtime), the screenshot is blank as if not capturing the current view on the device - I hope I am explaining alright there.
Am I missing anything?
func captureScreen() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, false, 0);
self.view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let image:UIImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image
}

Change your code to the following :
func captureScreen() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.view.frame.size, false, 0);
self.view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let image:UIImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image
}
Note the change from bound to frame in your code. The last argument in UIGraphicsBeginImageContextWithOptions has to do with the scale. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen
Learn more about it here

Related

Rotate downloaded (image.png) before/after saving?

I’m trying to rotate a downloaded image that comes in PNG format with a 4:3 ratio that’s landscape.
I need the image rotated by 90 degrees so it’s portrait with the same dimensions.
I tried the .transform function which worked to start with but doesn’t anymore after adding a scrollView with a lot of settings to allow it to zoom and pan, Id rather not go down the route of editing the srollView content as it took a long time to get all the constrains to work properly to allow free zoom and pan.
After downloading my image I save it to app file. Then it’s loaded for display in another function.
Is it possible to rotate the downloaded file whilst saving so it can be retrieved in the correct way?
I found this in another post which I believe would work with the downloaded image, how can I change the orientation for my need?
func normalizedImage() -> UIImage
{
if (self.imageOrientation == UIImageOrientation.Up) {
return self;
}
UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale);
let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
self.drawInRect(rect)
let normalizedImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return normalizedImage;
}
If you display the UIImage in an image view you can try modifying the orientation.
It is basically the same UIImage but with a flag that is interpreted by UIImageView to rotate the image display.
let rotated = UIImage(cgImage: image.cgImage!, scale: 1, orientation: .right)
If you really want to save a new image to disk, you will need to actually redraw the image. Some info is already available here : How to Rotate a UIImage 90 degrees?

controll the size of image assigned to the background by ui colorpattern

I assign an image to the background so the user can draw on it but the image always is not in the right size it takes like 1/3 of it and assigns it to the image view
the only way to bypass this is to make a canvas exactly the size of the image assigned like in PICSART app,
does any one knows how to do this?
mainimageview.backgroundColor = UIColor(patternImage: "draw")
`
You can write your own method to resize the image you want at the time of assigning background color. Pass your image and size you want
func imageWithImage(image:UIImage?, newSize:CGFloat)->UIImage?
{
let size = CGSizeMake(newSize, newSize)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
image?.drawInRect(CGRectMake(0, 0, size.width, size.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}

Image clipping with path (scaling issue)

The app I am using for testing puposes is able to take a picture and save it as a PNG file. The next time the app is launched, it checks if a file is present and if it is, the image stored inside the file is used as the background view of the app. Up to this point all is OK.
I decided to add a clipping mask to this app and this where things go wrong.
The clipping itself works, but for some mysterious reason the clipped image gets expanded. If someone could tell me what I am doing wrong that would be very helpful.
Here is the relevant code (I can provide more information if ever needed):
if let videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo) {
stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection) {
(imageDataSampleBuffer, error) -> Void in
if error == nil {
var localImage = UIImage(fromSampleBuffer: imageDataSampleBuffer)
var imageSize = CGSize(width: UIScreen.mainScreen().bounds.height * UIScreen.mainScreen().scale,
height: UIScreen.mainScreen().bounds.width * UIScreen.mainScreen().scale)
localImage = resizeImage(localImage!, toSize: imageSize)
imageSize = CGSize(width: imageSize.height, height: imageSize.width)
UIGraphicsBeginImageContext(imageSize)
CGContextRotateCTM (UIGraphicsGetCurrentContext(), CGFloat(M_PI_2))
localImage!.drawAtPoint(CGPoint(x: 0.0, y: -imageSize.width))
localImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Clipping code:
localImage = maskImage(localImage!,
path: UIBezierPath(CGPath: CGPathCreateWithEllipseInRect(UIScreen.mainScreen().bounds, nil)))
if let data = UIImagePNGRepresentation(localImage!) {
data.writeToFile(self.bmpFilePath, atomically: true)
}
} else {print("Error on taking a picture:\n\(error)")}
}
}
The maskImage function is this (taken from iOS UIImage clip to paths and translated to Swift) :
func maskImage(originalImage :UIImage, path:UIBezierPath) -> UIImage {
UIGraphicsBeginImageContextWithOptions(originalImage.size, false, 0);
path.addClip()
originalImage.drawAtPoint(CGPointZero)
let maskedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return maskedImage;
}
When the lines:
localImage = maskImage(localImage!,
path: UIBezierPath(CGPath: CGPathCreateWithEllipseInRect(UIScreen.mainScreen().bounds, nil)))
are commented out, I see what I expect.
Thaking the picture below and having it as background when relaunching the app.
But when they are present(not commented out), I get the background hereafter when relaunching the app (of course taking the same picture at start):
If things worked as they should the mouse should appear inside the elliptic clip with the same size as in the first picture (not magnified as it is now).

Capture visible portion of UIScrollView and subview

I have zoomable image in a UIScrollview. Once the image is scrolled to the user's liking, the scrollview is locked. A UITextField can then be edited, and is (currently) added to the UIImageView. The context of the image is captured and saved.
Without scrolling, this works fine, however, the context is based on the frame of the UIImageView. How can it capture the visible portion of the screen instead, leaving out the navigation bar and toolbar? The function used to save the image is below.
#IBAction func saveButtonPressed(sender: AnyObject) {
let newImage = imageStore.createImage(textLabelBottom.text, imageName: "image1") { () -> UIImage in
// Can't add the textLabel to imageView because its size changes
self.imageView.addSubview(self.textLabelBottom)
UIGraphicsBeginImageContextWithOptions(self.imageView.frame.size, false, 0.0)
let ctx = UIGraphicsGetCurrentContext()
self.imageView.layer.renderInContext(ctx)
self.imageToSave = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return self.imageToSave
}
imageStore.saveImage(newImage)
self.showActivityViewController()
}
I wan't to save the visible portion of the image based on its position in the scrollview with the textLabel in a static spot. The code currently adds textLabel to the same point in the image regardless of zoom, with the saved image either very small or very large based on the UIScrollView.
Update: I changed the code to the following:
#IBAction func saveButtonPressed(sender: AnyObject) {
let newImage = imageStore.createImage(textLabelBottom.text, imageName: "image1") { () -> UIImage in
// Can't add the textLabel to imageView because its size changes
self.imageView.addSubview(self.textLabelBottom)
UIGraphicsBeginImageContextWithOptions(self.imageScrollView.bounds.size, false, UIScreen.mainScreen().scale)
let ctx = UIGraphicsGetCurrentContext()
let offset: CGPoint = self.imageScrollView.contentOffset
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -offset.x, -offset.y)
self.imageScrollView.layer.renderInContext(ctx)
self.imageToSave = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return self.imageToSave
}
imageStore.saveImage(newImage)
self.showActivityViewController()
}
This works properly, but the text field is obviously out of place. Do I add it to a specific CGPoint within the context?
Update 2:
It's my understanding that CGContextTranslateCTM changes the coordinate system to that of the layer you're working on. In this case, the new {0, 0} would be at the offset of the scrollview. When I want to place my textfield into the context, though, it doesn't show up in the right place (offscreen). Trying something like this:
#IBAction func saveButtonPressed(sender: AnyObject) {
let newImage = imageStore.createImage(textLabelBottom.text, imageName: "image1") { () -> UIImage in
// Can't add the textLabel to imageView because its size changes
self.imageView.addSubview(self.textLabelBottom)
UIGraphicsBeginImageContextWithOptions(self.imageScrollView.bounds.size, false, UIScreen.mainScreen().scale)
let ctx = UIGraphicsGetCurrentContext()
let offset: CGPoint = self.imageScrollView.contentOffset
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -offset.x, -offset.y)
self.imageScrollView.layer.renderInContext(ctx)
//Move to the correct point and render
CGContextMoveToPoint(ctx, /*point1*/, /*point2*/)
self.textLabelBottom.layer.renderInContext(ctx)
self.imageToSave = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return self.imageToSave
}
imageStore.saveImage(newImage)
self.showActivityViewController()
}
What else do I need to do to the context to do this properly?

Create bitmap of UITextView's entire content

I'm trying to get a bitmap of a UITextView's content. I'm able to get a bitmap of the UITextView's content that is currently on the screen with:
UIGraphicsBeginImageContext(myTextView.bounds.size);
[myTextView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
myImageView.image=resultingImage;
UIGraphicsEndImageContext();
But I want a bitmap of ALL the content, not just the content visible on the screen. Is this possible? Note that I don't want only the text of the UITextView, I want a bitmap of the content itself. I searched around and found how do do this in Android, with getDrawingCache, but couldn't find anything for objective c.
One way to do this is to make a copy of the UITextView and then resize the copy to it's content size (as long as the content size is bigger than the frame size).
In Swift it looks like this:
func imageFromTextView(textView: UITextView) -> UIImage {
// Make a copy of the textView first so that it can be resized
// without affecting the original.
let textViewCopy = UITextView(frame: textView.frame)
textViewCopy.attributedText = textView.attributedText
// resize if the contentView is larger than the frame
if textViewCopy.contentSize.height > textViewCopy.frame.height {
textViewCopy.frame = CGRect(origin: CGPointZero, size: textViewCopy.contentSize)
}
// draw the text view to an image
UIGraphicsBeginImageContextWithOptions(textViewCopy.bounds.size, false, UIScreen.mainScreen().scale)
textViewCopy.drawViewHierarchyInRect(textViewCopy.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
This allows you to get an image of all of the content, even the part that in not visible without scrolling.
Notes
My somewhat more general answer is here.
The textViewCopy is only a copy of the frame and the attributed text. That should be enough to get a full image. However, if for some reason a more exact copy is needed, then one could do the following: (explanation)
let tempArchive = NSKeyedArchiver.archivedDataWithRootObject(textView)
let textViewCopy = NSKeyedUnarchiver.unarchiveObjectWithData(tempArchive) as! UITextView