Swift 3 - How to take a screenshot of specific UITableView row - ios

I need to have a screenshot of a specific UITableView row and remove/add content to the cell before the screenshot.
For example: the cell contains only a text and a share button. On share button click, I want the app to generate an image with the text and my app logo on the top (without the share button).
What is the best approach to do this? and how?
Thanks in advance.

#Nirav already gave you a hint in the comment section with this post:
How to take screenshot of portion of UIView?
So, you have now to get the Rect of the cell in the superview, so i made a sample action method:
#IBOutlet var snapImageView: UIImageView!
#IBAction func snapshotrow(_ sender: Any) {
//get the cell
if let cell = myTable.cellForRow(at: IndexPath(row: 0, section: 0)) as? MyCustomCellClass {
//hide button
cell.shareButton.isHidden = true
let rectOfCellInTableView = myTable.rectForRow(at: IndexPath(row: 0, section: 0))
let rectOfCellInSuperview = myTable.convert(rectOfCellInTableView, to: myTable.superview)
snapImageView.image = self.view.snapshot(of: rectOfCellInSuperview)
let finalImage = saveImage(rowImage: snapImageView.image)
//test final image
snapViewImage.image = finalImage
}
}
func saveImage(rowImage: UIImage) -> UIImage {
let bottomImage = rowImage
let topImage = UIImage(named: "myLogo")!
let newSize = CGSize.init(width: 41, height: 41) // set this to what you need
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
bottomImage.draw(in: CGRect(origin: .zero, size: newSize))
topImage.draw(in: CGRect(origin: .zero, size: newSize))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
and I was able to get the snapshot of the 0th cell of my table view and assigned it to the snapImageView.
Now the last step is to save the image to the camera roll, there are lots of related post out there in SO.
Source: Get Cell position in UITableview
Adding logo and hiding share button: Saving an image on top of another image in Swift

Related

Take a screenshot with background image - iOS

I want to take a screenshot. In this screenshot, I want the text and image in it. However, I am having an issue because when I take a screenshot, I only see the text but not the image.
I think the problem is that clearContainerView only contains the text but not the image. I can't put the image inside of clearContainerView because I want the image to stretch the entire screen... and I want the text centered between the title and tab bar (as shown with green square above).
My code and pictures are below:
This is my current layout in Storyboard:
This is what I want a screenshot of:
This is the screenshot that I get:
This is my code:
#IBOutlet weak var clearContainerView: UIView!
#IBAction func takeScreenshotTapped(_ sender: UIButton) {
let screenshot = clearContainerView.screenshot()
print(screenshot)
}
extension UIView {
func screenshot() -> UIImage {
let image = UIGraphicsImageRenderer(size: bounds.size).image { _ in
drawHierarchy(in: CGRect(origin: .zero, size: bounds.size), afterScreenUpdates: true)
}
return image
}
}
Any suggestions on how to do this?
You can use the following method on your controller view to get the portion of clearContainerView which will be a snapshot view. Then you can use that view object and take a screenshot of it.
resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets:
You have to pass the rect which will is your clearContainerView frame. You can pass zero insets in case you don't want any stretchable content. It return a view object which will contain your imageView portion + your complete clearContainerView. Then you can use the returned view and take its screen shot.
I tried with the following.
My original view.
The screenshot
Use this extension.
//USAGE
let image = self.view.snapshot(of:self.<your view>.frame)
Here "your view" should be the base view from the hierarchy or your can simply use
let image = self.view.snapshot(of:self.view.frame)
Extension
// UIView screenshot
extension UIView {
/// Create snapshot
///
/// - parameter rect: The `CGRect` of the portion of the view to return. If `nil` (or omitted),
/// return snapshot of the whole view.
///
/// - returns: Returns `UIImage` of the specified portion of the view.
func snapshot(of rect: CGRect? = nil) -> UIImage? {
// snapshot entire view
UIGraphicsBeginImageContextWithOptions(bounds.size, false, 0.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)
}
}
Main Code:
let frame = containerView.frame
let x: CGFloat = 0
let y = frame.minY.pointsToPixel()
let width = frame.width.pointsToPixel()
let height = frame.height.pointsToPixel()
let rect = CGRect(x: x, y: y, width: width, height: height)
let image = cropImage(image: view.screenshot(), toRect: rect)
extension UIView {
func screenshot() -> UIImage {
let image = UIGraphicsImageRenderer(size: bounds.size).image { _ in
drawHierarchy(in: CGRect(origin: .zero, size: bounds.size), afterScreenUpdates: true)
}
return image
}
}
public extension CGFloat {
func pointsToPixel() -> CGFloat {
return self * UIScreen.main.scale
}
}
output:
After Screenshot:
What I've done: take a screenshot of the whole view with your method and then crop the image by converting CGPoints to pixels.
You can use the code given below to capture the screenshot. It will capture the whole window not the particular view. But take care of one thing that if you don't want your "Title", "Button" and "Tab Bar" in the screenshot then you need to hide them before the UIGraphicsBeginImageContextWithOptions and show them again after UIGraphicsEndImageContext.
func takeScreenshot() -> UIImage? {
var screenshotImage: UIImage?
let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
// Hide your title label, button and tab bar here
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, scale);
guard let context = UIGraphicsGetCurrentContext() else {return nil}
layer.render(in:context)
screenshotImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// Unhide your title label, button and tab bar here
return screenshotImage
}
#IBAction func takeScreenshotTapped(_ sender: UIButton) {
let screenshot = takeScreenshot()
print(screenshot)
}
Everything is fine. I have made a demo for your expected output.
You just need to change your view hierarchy like this:
As pr you say the image if outside of clearContainerView
Code
class VC: UIViewController {
#IBOutlet weak var mainVw: UIView!
#IBOutlet weak var clearContainerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func takeImage(_ sender: Any) {
if let VC_1 = self.storyboard?.instantiateViewController(withIdentifier: "VC1") as? VC1{
VC_1.img = mainVw.screenshot()
self.present(VC_1, animated: false, completion: nil)
}
}
}
Output :
Try this!
Helper Function
struct UIGraphicsDrawImageHelper {
static func drawImage(from image: UIImageView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(image.bounds.size, image.isOpaque, 0.0)
image.drawHierarchy(in: image.bounds, afterScreenUpdates: false)
let renderImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return renderImage
}
}
calling it
guard let image = UIGraphicsDrawImageHelper.drawImage(from: qrcodeImageView) else { return }
ImageView (Clear Container View) is the view that you want to snapshot your screen. you can change it to uiview or whatever is view.
Hope this help.

Change the size of UIImageView in a UITableViewCell

I am a newbie in Swift And Xcode.
Is there any clean way to change UIImageView Size placed inside a UITableViewCell?
This is my TableView, I want to align left label correctly
Replace
cell.imageView!.image = image
with
cell.imageView?.image = image.scaleImage(toSize: CGSize(width: 40, height: 40))
Add this UIImageView extension to the project.
extension UIImage {
func scaleImage(toSize newSize: CGSize) -> UIImage? {
var newImage: UIImage?
let newRect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height).integral
UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
if let context = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage {
context.interpolationQuality = .high
let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: newSize.height)
context.concatenate(flipVertical)
context.draw(cgImage, in: newRect)
if let img = context.makeImage() {
newImage = UIImage(cgImage: img)
}
UIGraphicsEndImageContext()
}
return newImage
}
}
Reason for the error in your code is UITableViewCell is assigning the various size for UIImageView based on the image size inside it. In addition to I've adjusted the image to specific size so that it can fit to imageView content in UITableViewCell.
Note:
Please don't post the screenshots of the code as it does not help to others to copy it from the question and which attracts -ve voting as well. However, you can post the screenshots for XIBs, Storyboards and for Simulation errors.
You could use a stack view or a view with proportianal constraint to the relavite view in your cell xib. In this way the portion of the flag will be always the same.
Otherwise, if you want to do it quickly, you can contraint the leading of the label to the cell view and not with the flag. It's a litte bit dirtier but it should work.
Fix the width of the UIImageView and set its contentMode to .scaleAspectFit.
myImageView.safeAreaLayoutGuide.widthAnchor.constraint(equalToConstant: 50).isActive = true
myImageView.contentMode = .scaleAspectFit
myImageView.clipsToBounds = true
However, if you are using the storyboard, you can set these properties there itself.

Delay with CollectionView Did Select

I'm getting a second long delay when selecting my collectionview cell. Here is my current code for collection view did select:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = PopUpCellViewController(nibName: "PopUpCellViewController", bundle: nil)
self.navigationController?.pushViewController(vc, animated: true)
print("called")
let cell = collectionView.cellForItem(at: indexPath) as! AnnotatedPhotoCell
sourceCell = cell
vc.picture = resizeImage(image: cell.imageView.image!, targetSize: CGSize(width: (view.bounds.width - 45),height: 0))
vc.comment = cell.commentLabel
var image = UIImage(named: "back_button_thick")
image = image?.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
self.navigationController?.navigationBar.backIndicatorImage = image
self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = image
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: " ", style: UIBarButtonItemStyle.plain, target: nil, action: nil)
}
func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / image.size.width
// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
I am using a UIViewControllerAnimatedTransitioning. I am confident that there is no delay with my UIViewControllerAnimatedTransitioning. There seems to be an issue with my CollectionView Did select function. If switch my code in my didSelect function for a print statement, there is no longera delay.
I have two solutions:
1: PROBABLY NOT: I'm guessing that it's giving an annoying delay because it's taking a while for your app to run the code to get the nib file, and change all those things while it shouldn't.
2: PROBABLY: Perhaps running it on a real device will help. Xcode always has bugs, so don't worry. :)

UIImageView not resizing

I'm using Swift 3.0 with Xcode 8 and I'm having some problems with image resizing. Here is the code where i set my UIImage frame.
open func setData(_ data: Any?, image: String) {
self.textLabel?.font = UIFont.boldSystemFont(ofSize: 10)
self.textLabel?.textColor = UIColor(hex: "000000")
if let menuText = data as? String {
self.textLabel?.text = menuText
}
self.imageView?.contentMode = UIViewContentMode.scaleToFill
self.imageView?.frame = CGRect(x: 12, y: 8, width: 10, height: 10)
self.imageView?.image = UIImage(named: image)
self.imageView?.clipsToBounds = true
}
And here is where I call my function inside my tableView. I don't have any problem with setting the image, but ONLY with resize. When i use smaller images, the image is smaller, when i use bigger images, the image gets bigger, it doesnt resize.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = BaseTableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: BaseTableViewCell.identifier)
cell.setData(menus[indexPath.row], image: images[indexPath.row])
return cell
}
I have solved it by using this resize function to resize my image and then place in the ImageView
func imageResize(image:UIImage,imageSize:CGSize)->UIImage
{
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0.0)
[image .draw(in: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))]
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
return newImage!
}
If you are using default image view of uitableview cell than you won't be able to resize it. Some default constraints are already there.
You have two options :
create a subclass of uitableview cell and use your own image view (don't create the outlet with name imageView, try something else).
Resize the image using https://stackoverflow.com/a/45100626/5383852

How to resize an UIImageView (swift)

I'm a beginner with swift and I can't get the resize of a UIImageView working.
Here is my current layout :
What I want is to resize the images to occupy half the screen's width (2 images per row).
Here is my storyboard :
Here is the function drawing the collection view inside my controller :
func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell! {
var cell : MenuInspirationCellView = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as MenuInspirationCellView
cell.imageView.layer.borderWidth = 2
cell.imageView.layer.borderColor = UIColor.yellowColor().CGColor
//This is my first approach trying to modify the frame :
cell.imageView.frame = CGRectMake(0,0, self.view.bounds.width / 2,v120)
var cellImage : UIImage = UIImage(data: NSData(contentsOfURL: NSURL(string: images[indexPath.row])))
cell.imageView.image = cellImage;
//This is my second approach (based on http://www.snip2code.com/Snippet/89236/Resize-Image-in-iOS-Swift) :
// to resize an image to dimension 52x52
//var newSize:CGSize = CGSize(width: 52,height: 52)
//let rect = CGRectMake(0,0, newSize.width, newSize.height)
//UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
// image is a variable of type UIImage
//cellImage.drawInRect(rect)
//let newImage = UIGraphicsGetImageFromCurrentImageContext()
//UIGraphicsEndImageContext()
// resized image is stored in constant newImage
//cell.imageView.image = newImage;
//This is my thrid approach (based on https://gist.github.com/hcatlin/180e81cd961573e3c54d, of course i added his functions but I don't show them here for the sake of readability) :
//cell.imageView.image = self.RBSquareImageTo(cellImage, size: CGSize(width: 80, height: 80))
return cell
}
Any leads to sort this out ?
SWIFT:
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()
UIGraphicsEndImageContext() // !!!
return scaledImage
}
The sizes of your cells are decided by your UICollectionViewLayout object, which is a UICollectionViewFlowLayout in your case. If you want all of your cells to be the same size, you can configure the properties on the layout itself; itemSize and minimumInterimSpacing will do the trick. Alternatively, if you want your cells to be different sizes, say depending on the image each contains or whatever, you needs your collection view delegate to implement the UICollectionViewDelegateFlowLayout method:
optional func collectionView(collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, sizeForItemAtIndexPath indexPath: NSIndexPath!) -> CGSize
returning the size you want for each cell.
Following this tutorials you can resize UIImage, In that tutorial described fully .. Image Resize in swift ios8
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
}
Here you can also see many tutorials about Swift language Visit Here iPhone & iPad Application Development Help World

Resources