Draw image of viewcontroller by UIGraphicsBeginImageContextWithOptions giving not completely loaded one - ios

I am making a image collage app.
After collage the image, I'm trying to draw a output image from ViewController and upload to a site.
UIGraphicsBeginImageContextWithOptions(self.viewDFrame.bounds.size, NO, 0.0f);
[self.viewDFrame.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Sometime it can output a completely loaded viewcontroller but mostly it output not completely loaded one like this - with frame only.
This is actual output image and preview image that i wanted to get

I am using this code to generate single image. Swift 3.0 version
UIGraphicsBeginImageContextWithOptions(CGRect("Frame To get in context"), false, 0.0);
self.view.drawHierarchy(in: CGRect( "Frame Of View" ), afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
If you have any container view where you add frame and images.
self.viewContainer.drawHierarchy(in: CGRect( "Frame Of container view" ), afterScreenUpdates: true)
If you want to render image without showing view on screen and frame sizes are fix then refer this question link.
How to merge two UIImages?
var bottomImage = UIImage(named: "bottom.png")
var topImage = UIImage(named: "top.png")
var size = CGSize(width: 300, height: 300)
UIGraphicsBeginImageContext(size)
let areaSize = CGRect(x: 0, y: 0, width: size.width, height: size.height)
bottomImage!.drawInRect(areaSize)
topImage!.drawInRect(areaSize, blendMode: kCGBlendModeNormal, alpha: 0.8)
var newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

I finally find out that i set Image using requestImageForAsset, this method is asynchronous so that the the renderInContext not wait for the image to be loaded. I set options.synchronous = YES; for PHImageRequestOptions and the image is loaded before rendering.

Related

Adding Text View to Image on iPhone X "squeezes" image on output

I currently having a block of code that is trying to add a text view on top of an image, with the ultimate goal to save down the new image with the overlaid text. Here is the code to do that:
class func addText(label: UITextView,imageSize: CGSize, image: UIImage) -> UIImage {
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(CGSize(width: imageSize.width, height: imageSize.height), false, scale)
let currentView = UIView.init(frame: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
let currentImage = UIImageView.init(image: image)
currentImage.frame = CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height)
currentView.addSubview(currentImage)
currentView.addSubview(label)
currentView.layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
And it is called like below (The image is just a standard 1920x1080 image taken by the phone's camera):
self.imageToEdit.image = UIImage.addText(label: textView, imageSize: UIScreen.main.bounds.size, image: self.imageToEdit.image!)
This works great when I test when an iPhone 6s, but when I test on an iPhone X, it "squeezes" the sides of the image so faces and other features become skinnier on the image that is returned by addText.
I have a hunch it is due to the image being extended up through the notch of the iPhone X which is causing some type of scaling/aspect fill, but I'm not sure where to begin looking.
Does anyone know how to stop the "squeezing" from happening in iPhone X (I am also guessing this is happening in all the other iPhone models that have a notch)
Thanks.
Just figured it out!
I needed to included this line:
currentImage.contentMode = .scaleAspectFill
in my addText func.
Because I was returning a new UIImageView I needed to make sure it had the same content mode as the original view.

Frame and Image in specific aspect Ratio

I created empty gray UIImage, using below code
let size = CGSize(width: 212, height: 332)
UIGraphicsBeginImageContextWithOptions(size, true, 0)
UIColor.gray.setFill()
UIRectFill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
let backgroundImage2: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
It shows output as
Now I need to put UIImage on specific area in this UIImage. as shown in below Image. Say top, left, right should be 30 pixels, and bottom more than that, say 200 pixels. maintaining inner image aspect ratio.
Use two image views (either UIImageView or GLKView), making the "image" a subview of the "gray background" view. After positioning the "image" correctly, merge the two images into one.
Here's an extension to UIView that I use:
extension UIView {
public func createImage() -> UIImage {
UIGraphicsBeginImageContextWithOptions(
CGSize(width: self.frame.width, height: self.frame.height), true, 1)
self.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}

Partial Screenshot with Swift 3

I would like to make partial screenshot in my project.
However, I tried the output screenshot is not good that I want to be.
Here is my code.
let size = CGSize(width: 398, height: 300)
UIGraphicsBeginImageContextWithOptions(size, false, 0);
view.layer.render(in: UIGraphicsGetCurrentContext()!)
var sourceImage = UIGraphicsGetImageFromCurrentImageContext()
sourceImage?.draw(at: CGPoint(x: 0, y: 0))
var cropimage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(cropimage!,nil,nil,nil)
I would like to save only white View. If I set width and height, the output image is small and does not get completely.
Anyone help me please?
extend UIView and capture an image of that white view
// Untested
import UIKit
extension UIView {
func capture() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.frame.size, self.opaque, UIScreen.mainScreen().scale)
self.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
usage:
let whiteImage = myWhiteView.capture()

Rendering image with textview

I am placing a textview on a image. With following code:
var previewImageView=UIImageView()
self.previewImageView.frame = CGRect(x:0, y:0, width:UIScreen.mainScreen().bounds.width, height:UIScreen.mainScreen().bounds.height)
self.view.addSubview(self.previewImageView)
textField = UITextView(frame: CGRect(x: 0, y: self.view.bounds.height/2 - 50, width: self.view.bounds.width, height: 36))
textField.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
self.view.addSubview(textField)
It works well. But I want to render this image with textview. Then I will save it to gallery.
How can I do this?
Edit:
I tried following code but it is only rendering image not textview:
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(inImage.size)
//Put the image into a rectangle as large as the original image.
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
// Creating a point within the space that is as bit as the image.
var rect: CGRect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
//Now Draw the text into an image.
drawText.drawRect(rect)
// Create a new image out of the images we have created
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
// End the context now that we have the image we need
UIGraphicsEndImageContext()
//And pass it back up to the caller.
return newImage
You can render whole view into an UIImage using CGGraphicsContext. Here is an example of the code:
func imageWithView(view: UIView!) -> UIImage! {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0)
view.layer.renderInContext(UIGraphicsGetCurrentContext())
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
When you pass scale = 0.0 it will take a scale of your screen.
An example of usage:
let image = imageWithView(view)
Code to save image:
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
More information about UIGraphicsContext and image saving can be found here.
Update:
If you want to render only specific views, then you should use CALayer, renderInContext. When you use renderInContext it does not know views.frame and draws at (0:0) in coordinate system, so you should use CGContextTranslateCTM to move coordinate system.
To render only these two views you can do:
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(context, previewImageView.frame.origin.x, previewImageView.frame.origin.y)
previewImageView.layer.renderInContext(context)
CGContextTranslateCTM(context, textField.frame.origin.x - previewImageView.frame.origin.x, textField.frame.origin.y - previewImageView.frame.origin.y)
textField.layer.renderInContext(context)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Please set opaque true/false as you need. When I was testing in playground I was using not opaque views.
Update 2:
Code which should work in all scenarios:
func imageFromViews(views: [UIView]!, contextSize: CGSize!) -> UIImage {
UIGraphicsBeginImageContextWithOptions(contextSize, false, 0.0)
let context = UIGraphicsGetCurrentContext()
for view in views {
CGContextTranslateCTM(context, view.frame.origin.x, view.frame.origin.y)
view.layer.renderInContext(UIGraphicsGetCurrentContext())
CGContextTranslateCTM(context, -view.frame.origin.x, -view.frame.origin.y)
}
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}

merging images from two imageviews into a single image in iOS

I have two imageviews view1 and view2 having image1 and image2 respectively. view1 is bigger than view2.
It is oriented such that view2 is located inside view1. view2 is draggable as well.
How could i write a code to merge these two images in imageviews to a single image?
You can merge two images using UIGraphicsBeginImageContext. Here is a small function written with Swift 2.1.1 which takes two images and creates a single image.
func mergeImages (forgroundImage : UIImage, backgroundImage : UIImage) {
let bottomImage = forgroundImage
let topImage = backgroundImage
let size = backgroundImage.size
UIGraphicsBeginImageContext(size)
let areaSize = CGRect(x: 0, y: 0, width: size.width, height: size.height)
bottomImage.drawInRect(areaSize)
topImage.drawInRect(areaSize, blendMode: .Normal, alpha: 1.0)
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
resultImageView.image = newImage
UIGraphicsEndImageContext()
}
You can call it like
mergeImages(yourImageViewOne.image!, backgroundImage: yourImageViewTwo.image!) // Call to mege images
And here is a link for further exploring.

Resources