Code to make screenshot of an entire UITableView doesn't work anymore in iOS 13 - objective-c

I used the code below for years to be able to capture a screenshot of an UITableView (including hidden rows) and save it to the user's phone gallery or share it.
Since they updated to iOS 13 it doesn't work anymore, it captures only the visible part of the table leaving it blank on the bottom part.
-(UIImage *)imageFromCurrentTable
{
CGRect frame = self.tableView.frame;
frame.size.height = self.tableView.contentSize.height;
self.tableView.frame = frame;
UIGraphicsBeginImageContext(self.tableView.bounds.size);
[self.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
return [UIImage imageWithData:data];
}
What changed in iOS 13? How this code can be updated? (the code is Obj-C but I will accept also swift answers!)

I have faced this issue. Due to cell Reuse, UIGraphicsGetImageFromCurrentImageContext cannot produce full UITableView structure.
One Way [Not Efficient Way]:
In cellForRowAtIndexPath, we can able to get which UITableViewCell using. Store that cell in [Int: UITableViewCell].
Get screenshot from UITableViewCell.contentView.
Add that screenshot's image as subview to UIView one by one.
Now, UIView having UITableView's contentView as Images.
Get screenshot from UIView.

Related

Get UIImage from UIImageView with masked subviews

Through Face Detection, I want to blur eyes and mouth of a person. So I have a imageView that contains 3 subviews (2 per eye and the mouth). Each one of these subviews were masked with a PNG shape (with background clear) for avoiding to show rectangle.
My imageView in screen remain so: http://screencast.com/t/ak4SkNXM0I
And I want to obtain the image for storing in another place, so I've tried this:
CGSize size = [imageView bounds].size;
UIGraphicsBeginImageContext(size);
[[imageView layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
But finalImage is an image like this:
http://screencast.com/t/eDlvGqqY
My subViews (eyes and mouth) are not masked as above.
Any idea?
Thanks.
Edit:
I have to use library compatible with ios6
You can check the new API added to iOS7. Try one of the following methods:
snapshotViewAfterScreenUpdates:
resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets: for resizable image
drawViewHierarchyInRect:afterScreenUpdates:

cell.imageView.image and indentationLevel on iOS 7

How to make a distance between the image and the text closer?
In ios 6 the same code displays normally, but in the new version of the distance increased.
I do everything by standard methods
[cell.textLabel setText: .....
// cell.indentationLevel = 0; // this is for test
UIImage * img = [UIImage imageNamed: # "image10.png"];
             NSData * imageData = UIImagePNGRepresentation (img);
            cell.imageView.image = [UIImage imageWithData: imageData];
attached image
https://www.dropbox.com/s/lt119xgozvzzstd/image01.png
If I remember correctly, the indentation level only affects the text. So when you're changing the indentation level/width you are in fact changing the distance between the imageView and the textLabel.
I tested this an unfortunately you can't make the indentationWidth negative. Thus you will need to subclass the UITableViewCell and set it up with your own views (I would suggest doing that in the Storyboard, with autolayout and make the indentation into a NSLayoutConstraint so that you have a property on your cell indentationConstant, for example which you can change). I have done this for a slightly different purposes, I needed to indent the whole contentView. No way around subclassing and creating custom views in Storyboard, sorry. (I am not even going to suggest some terrible hacks of accessing the subviews and modifying their frame, everything is autolayout today).

Can't get a screenshot of UIView to be displayed inside UIImageView

Here's my code to get the screenshot of the view:
if (NULL != UIGraphicsBeginImageContextWithOptions){
UIGraphicsBeginImageContextWithOptions(pagedScrollView.frame.size, NO, [[UIScreen mainScreen] scale]);
}else{
UIGraphicsBeginImageContext(pagedScrollView.frame.size);
}
[pagedScrollView.layer renderInContext:UIGraphicsGetCurrentContext()];
screenshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView = [[UIImageView alloc] initWithImage:screenshotImage];
imageView.frame = CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y, imageView.frame.size.width, imageView.frame.size.height);
imageView.backgroundColor = [UIColor greenColor];
[self.view addSubview:imageView];
I'm 100% sure I have the right frame and the right view - the size of UIImageView say about it - but the thing is I can't get my UIImage to be displayed on the UIImageView.
The UIImageView is added on the view and I see a green region on it - but no image inside it, what can be wrong?
I'm using iOS 6 and ARC.
Well, I just tested your code running on my view controller's view and the capture and display worked fine. This leads me to believe that pagedScrollView is probably nil, or has a zero frame.
Either way, you'll be creating an image from a blank context and then passing it to your image view resulting in there not being any visible image.
It turns out I've been taking a screenshot of a long UIScrollView and I was always taking its first page - it had a lot of pages in it and sometimes the layer had nothing in it. It also turns out that UIImage was never released and the memory can effectively store dozens of them.

Screenshot a separate UIView (not self.view)

Basically I want to screenshot a UIView which is called CustomViewLayout, which belongs to MyClass. MyClass's view is assigned to NormalView. Therefore if I call self.view it will reference NormalView. I have made a property viewCustom which is an outlet for CustomViewLayout. Anyways, I want to screenshot CustomViewLayout, I have tried this:
UIGraphicsBeginImageContextWithOptions(self.viewCustom.bounds.size, self.viewCustom.opaque, 0.0);
[self.viewCustom.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
That image is then displayed/attached inside an In-App Mail (MFMailComposeViewController). And it doesn't work, it shows a blue box with a question mark inside, which I presume means the image is not readable. I know there is nothing wrong with my In-App Mail image attachment code because if I change my screenshot code to screenshot self.view like below:
UIGraphicsBeginImageContextWithOptions(self.viewCustom.bounds.size, self.viewCustom.opaque, 0.0);
[self.viewCustom.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
Then it works fine. So what should I do to screenshot my other view?
Thanks for the help!
The solution was just easily to load the different nib name from MyClass and then reload it back later.
Easy!

Blending a UITableViewCell with a background

I have a dilemma I can't seem to solve. I have a UITableView populated by custom UITableViewCells and I need the background of each cell to be blended (like Photoshop multiply) with the background image (the background image is part of the UIView behind the UITableView).
I've found several ways to do the blend (and it does somewhat work). The blending function I'm using is:
- (UIImage *)blendOverlay:(UIImage *)topImage withBaseImage:(UIImage *)baseImage toSize:(CGFloat)imageSize
{
UIGraphicsBeginImageContext(CGSizeMake(imageSize, imageSize));
[baseImage drawInRect:CGRectMake(0.0, 0.0, imageSize, imageSize)];
[topImage drawInRect:CGRectMake(0.0, 0.0, imageSize, imageSize) blendMode:kCGBlendModeMulitply alpha:0.5];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
which is from http://www.cocoabuilder.com/archive/cocoa/280142-uiimageview-display-as-multiply.html.
Basically what I do now is chop out the piece of the background I'm over by getting the cell's frame and creating a new image which is the piece of the background in that frame. However, in order for the effect to work, it essentially needs to recalculate and update every frame (much like an alpha effect). Oh, and I tried just setting a timer to 1/60 seconds and calling
[tableView reloadData];
But that just slowed everything down and the redraws never actually occurred. Any help is much appreciated, I've been googling for nearly 3 hours to avail.
Oh, and for posterity purposes, I chop the background image like so:
CGRect r = [tableView rectForRowAtIndexPath:indexPath];
CGRect r2 = [tableView convertRect:r toView:self.view];
CGImageRef imageRef = CGImageCreateWithImageInRect([m_background.image CGImage], r2);
// Get the image by calling [UIImage imageWithCGImage:imageRef]
CGImageRelease(imageRef);
Thanks!
The problem is that a UITableView doesn't call the drawRect: method of the each individual UITabelViewCell while moving the rows. It seems to cache the view at the start of the table movement, and use that image for moving the whole table. Therefore the custom UITableViewCell has no opportunity to update the background image to show the movement of the blended backgrounds.
The one possible way I can see to animate the background image blending as the table cells move is to subclass UITableView and override drawRect: in that subclass.