Capturing UIScrollView off screen content - objective-c

I'm working with a UIScrollView which can be used in either orientation and contains a number of subviews:
// in viewDidLoad
mainScrollView = (UIScrollView *)self.view;
mainScrollView.contentSize = CGSizeMake(1024, 1432);
I'm trying to capture a screen shot of the entire scroll view with all its subviews, including what is not currently visible on screen. The following captures only what is visible on screen at the time of capture:
// make screenshot
UIGraphicsBeginImageContext(mainScrollView.bounds.size);
[mainScrollView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// save screenshot in docs dir
NSData *pngData = UIImagePNGRepresentation(screenImg);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
[pngData writeToFile:[documentsDir stringByAppendingPathComponent:#"screen1.png"]
options:NSDataWritingAtomic error:nil];
Adding the following before making the screen shot was the only way I could fine that enabled me to capture the entire scroll view:
// capture off-screen content
mainScrollView.frame = CGRectMake(0, 0, 1024, 1432);
This capture is fine and includes all subviews. The problem is that once I have made the screen shot, my scroll view becomes unresponsive so I can no longer scroll (or pan sideways if in portrait mode). If I rotate the device, the problem seems to rectify itself and I can scroll and pan normally.
I'm sure I'm missing something very simple that is needed to get my scroll view working normally straight after the screen shot is taken.
Any suggestions much appreciated!

The problem is that you are setting the frame size equals to the content size. When the frame size is equals or greater to the content size you can't scroll.
You have to find a way to identify when the screen shot have finished and change the frame size back to the previous size. So:
CGRect oldFrame = mainScrollView.frame;
// do your logic to screenshot
mainScrollView.frame = oldFrame;

Related

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

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.

Why is [UIImage imageNamed] displaying a blue rectangle instead of my image?

I'm trying to use an image for a button in the Nav Bar. It appears to be finding the image, because when I run the app, there is blue rectangle roughly the size of my image centered on where the nav bar button is supposed to be. And when I click it, the action specified for the button happens. But why is the image not displayed? Here's my code:
UIImage *image = [UIImage imageNamed:#"newTweetSmall"];
[self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStyleBordered target:self action:#selector(newTweet)];
I've also tried
UIImage *image = [UIImage imageWithContentsOfFile:#"newTweetSmall"];
But that appears to not be finding the image at all, because there is no big blue rectangle, no button in the Nav Bar at all.
Here's the structure of my project, in case that matters. I've also tried using 'Resources/newTweetSmall' for the path of the image, but that results in no image or button either.
Your code is correct. Try use a png image with alpha channel.
It certainly solve your problem.
If you want to be convinced that your file was loaded to memory check the value in the image variable. If image is loaded this variable cannot be nil.

In iOS6, XCode 4.5, UIScrollView is not Scrolling, despite contentSize being set

I've been banging my head against the wall for the last hour trying to get my scrollView to scroll, but to no avail. In viewDidLoad I have
NSURL *url = [FlickrFetcher urlForPhoto:self.photoData format:FlickrPhotoFormatLarge];
NSData *imageRawData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageRawData];
self.scrollView.delegate = self;
self.imageView.image = image;
self.scrollView.contentSize = image.size;
self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
I have the imageView view mode set to top left.
My UIScrollView was created by selecting my imageView, then Editor -> Embed in -> ScrollView.
Anything else I can check/try?
If you have created your scrollview through nib, and if that nib has autolayout feature then it will not let you scroll.
So go utility window of nib.
Select First tab of utility window.
Remove autolayout and run the application
Checklist:
Is image really downloaded? (so it actaullly has size?)
Is scrollview outlet set?
Is imageView added as a subview of scrollView?
Btw. Don't know if this is just sample code or real but if it's real then it's really bad idea to download data synchronously and even worse idea to do it in viewDidLoad.
I guess it because you have image view embedded in scrollview,so its frame is becoming to imageview's frame. when frame size and content size are equal, scrollview wont scroll. Try setting scrollview's frame pragmatically to some fixed rectangle. ScrollView's contentSize's height and width should be greater then scrollview's frame's height and width. Give it some space to scroll:) In your case , they both are equal I guess.

iOS - Rotating an image or picture

My iOS app downloads some images from the internet and displays them on the screen (iPhone Portrait layout). Some of these images are more wider than taller, and in that case, when the image is presented to the screen, they appear squished (imagine the picture of a widescreen tv shrunk to iPhone's width). What I want to do is that everytime the width of the image is wider than the height of the image, I want to rotate the picture by 90 degrees clockwise (into landscape layout mode), save it on app's documents folder, and then present it on the screen - this way, the picture of the widescreen tv (e.g.) appears 90 degrees rotated but the image aspect ratio is not totally destroyed.
For various complicated reasons, I can't use landscape layout of my app - too many other side effects. So this is code I wrote:
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
CGFloat width = image.size.width;
CGFloat height = image.size.height;
if(width > 1.2*height) {
NSLog(#"rotate the image");
CGImageRef imageRef = [image CGImage];
image = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationLeft];
}
Then I save the image into App's documents folder. Then a new UIViewController opens which reads the image file saved in the documents folder and then opens this image. Problem is, the image doesn't appear rotated at all - just appears the same way as the original - without any rotation. I do know that the above code tries to do what it is supposed to do because I do see NSLog "rotate the image" in the console. But somehow this image doesn't get saved as the rotated image.
So, how should I approach this issue?
EDIT:
Code to save my image:
NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
// Create image name
NSString *path = [#"" stringByAppendingFormat:#"%#%#", #"image", #".png"];
// Create full image path
path = [documentsDirectory stringByAppendingPathComponent:path];
path = [NSString stringWithFormat:#"%#", path];
// Write image to image path
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(image)];
[data1 writeToFile:path atomically:YES];
The following website's solution ultimately worked for me:
http://www.catamount.com/blog/uiimage-extensions-for-cutting-scaling-and-rotating-uiimages/

UILabel scaling with UIScrollView

I have a UIScrollView that displays and Image and it scrolls fine and everything. What I want to do is add a UILabel to the UIScrollView to display the title of the image. I managed to do that, but when I zoom out the UILabel does not zoom with the scroll View and stays in the same place on the screen. How would I make it so the label scales with the scrollView Image? Here is the code I have:
[super viewDidLoad];
// Do any additional setup after loading the view.
self.scrollView.delegate = self;
//This just creates a image from a URL
NSURL * photoURL = [FlickrFetcher urlForPhoto:self.photoCellName format:2];
NSData * photoData = [NSData dataWithContentsOfURL:photoURL];
self.imageView.image = [UIImage imageWithData:photoData];
//Setting up scroll View
self.scrollView.contentSize= self.imageView.image.size;
self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
NSLog(#"Name = %#", [self.photoCellName valueForKeyPath:#"description._content"]);
//Assigning title to the label
self.textLabel.text = [self.photoCellName objectForKey:#"title"];
Make sure label is the subview of your scrollview.
I'm guessing you are providing the UIImageView as the View that will be zoomed by the UIScrollView by implementing the method in the UIScrollViewDelegate.
If not, I'm not sure how your zooming is working then. If you are providing it, you'll have to return a UIView that contains as subviews your UILabel and your UIImageView and you will have to manually apply transformations to the UIView to resize it.
I guess that a similar question was answered in this SO thread, and Dimme (the one that answered it)provided a complete solution with source code, hope it helps!
You should check if you setup autoresizingMask property of your UILabel
self.label.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
You can do it in IB too. Then if you will change the frame of its superview the frame of your label will be updated during - (void)setNeedsLayout handling process
... and DO NOT block the main thread creating images from url in - (void)viewDidLoad!