I tried to take screenshot of expandable uitableview, I tried to take a screenshot of uitableview but I was not able do that , then I changed tableview frame size to tableview content size. After taking screenshot I changed frame size to old frame size. Now the problem is that I am having expandable section in table view. I'm able to take screenshot of unexpanded table view cell in my screenshot. I need to take the screenshot of unexpanded table view cell content too.
by using this category file u can take the screen shot what ever visible in the screen....
#interface UIImage (MyImage)
+ (UIImage*)imageFromView:(UIView*)view;
+ (UIImage*)imageFromView:(UIView*)view scaledToSize:(CGSize)newSize;
+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize;
+ (void)beginImageContextWithSize:(CGSize)size;
+ (UIImage *)croppedImage:(UIImage *)myImage :(CGRect)bounds;
#end
#import "UIImage+MyImage.h"
#implementation UIImage (MyImage)
+ (void)beginImageContextWithSize:(CGSize)size
{
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
if ([[UIScreen mainScreen] scale] == 2.0) {
UIGraphicsBeginImageContextWithOptions(size, YES, 2.0);
} else {
UIGraphicsBeginImageContext(size);
}
} else {
UIGraphicsBeginImageContext(size);
}
}
+ (void)endImageContext
{
UIGraphicsEndImageContext();
}
+ (UIImage*)imageFromView:(UIView*)view
{
[self beginImageContextWithSize:[view bounds].size];
BOOL hidden = [view isHidden];
[view setHidden:NO];
[[view layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
[self endImageContext];
[view setHidden:hidden];
return image;
}
+ (UIImage*)imageFromView:(UIView*)view scaledToSize:(CGSize)newSize
{
UIImage *image = [self imageFromView:view];
if ([view bounds].size.width != newSize.width ||
[view bounds].size.height != newSize.height) {
image = [self imageWithImage:image scaledToSize:newSize];
}
return image;
}
+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{
[self beginImageContextWithSize:newSize];
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
[self endImageContext];
return newImage;
}
+ (UIImage *)croppedImage:(UIImage *)myImage :(CGRect)bounds {
CGImageRef imageRef = CGImageCreateWithImageInRect(myImage.CGImage, bounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGSize asd = croppedImage.size;
return croppedImage;
}
#end
the method call will be....
yourImageView.image= [UIImage imageFromView:(UIView*)yourTableViewInstance ]
try this....
Related
I am using method to convert UIView to UIImage and its doing a great job when UIView (to be converted to UIImage) is already present/displayed. But my requirement is to convert UIView to UIImage without displaying UIView. Unfortunately, this code is failing in this case and I am stuck. Any help will be appreciated.
I am using the following method:
+ (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [[UIScreen mainScreen] scale]);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
Your code is likely failing because you're not laying out the subviews of your view (which is done automatically when you add a view as a subview). Try something like the method I wrote below:
+ (UIImage *)imageFromView:(UIView *)view sized:(CGSize)size
{
// layout the view
view.frame = CGRectMake(0, 0, size.width, size.height);
[view setNeedsLayout];
[view layoutIfNeeded];
// render the image
UIGraphicsBeginImageContextWithOptions(size, view.opaque, 0.0f);
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return renderedImage;
}
Assuming you have already got a working view, this code should work to convert the UIView to a UIImage (I'm using it to convert a gradient into an image and display the image onto a UIProgressView.
Swift:
let renderer = UIGraphicsImageRenderer(size: gradientView.bounds.size)
let image = renderer.image { ctx in
gradientView.drawHierarchy(in: gradientView.bounds, afterScreenUpdates: true)
}
Objective C:
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:gradientView.bounds.size];
UIImage *gradientImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
[gradientView drawViewHierarchyInRect:gradientView.bounds afterScreenUpdates:true];
}];
_progressView.progressImage = gradientImage;
The above code should allow you to convert any UIView to a UIImage. You should ideally be running it in the viewWillAppear (as at this point the view controller will have the correct layout sizes). If you have any problems getting this to work you can have a look at these example projects that I made for a guide on this very topic! Objective C, Swift.
Hide all subviews, and then snapshot UIview to UIImage should work, see code below
+ (UIImage *)custom_snapshotScreenInView:(UIView *)contentView
{
if (!contentView) {
return nil;
}
CGSize size = contentView.bounds.size;
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
CGRect rect = contentView.bounds;
[contentView drawViewHierarchyInRect:rect afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
return image;
}
+ (UIImage *)custom_snapshotScreenWithoutSubviews:(UIView *)contentView
{
// save hidden view's hash
NSMutableArray *hideViewsHashs = [[NSMutableArray alloc]initWithCapacity:contentView.subviews.count];
for (UIView *subview in contentView.subviews) {
if (subview.hidden == NO) {
[hideViewsHashs addObject:#(subview.hash)];
NSLog(#"Dikey:video:snap:hash = %#", #(subview.hash));
}
subview.hidden = YES;
}
// view to image
UIImage *image = [UIImage custom_snapshotScreenInView:contentView];
// restore
for (UIView *subview in contentView.subviews) {
if ([hideViewsHashs containsObject:#(subview.hash)]) {
subview.hidden = NO;
NSLog(#"Dikey:video:snap:restore:hash = %#", #(subview.hash));
}
}
// finish
return image;
}
Im currently taking screenshot of a UIScrollView as a part of app functionality. but i want to take the screenshot including additional height from the bottom. (UIScrollView+UIImageView)
This is how im taking UIScrollView screenshot now.
UIGraphicsBeginImageContextWithOptions(ScrollView.bounds.size, true, UIScreen.mainScreen().scale)
let offset = ScrollView.contentOffset
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), -offset.x, -offset.y)
ScrollView.layer.renderInContext(UIGraphicsGetCurrentContext())
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
You can implement this:
+ (UIImage *) imageWithView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0f);
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
UIImage * snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return snapshotImage;
}
where your view parameter should be a content view.
Or you can take 2 shots, one of the ScrollView and another from the ImageView and merge in one:
- (UIImage*)imageByCombiningImage:(UIImage*)firstImage withImage:(UIImage*)secondImage {
UIImage *image = nil;
CGSize newImageSize = CGSizeMake(MAX(firstImage.size.width, secondImage.size.width), MAX(firstImage.size.height, secondImage.size.height));
if (UIGraphicsBeginImageContextWithOptions != NULL) {
UIGraphicsBeginImageContextWithOptions(newImageSize, NO, [[UIScreen mainScreen] scale]);
} else {
UIGraphicsBeginImageContext(newImageSize);
}
[firstImage drawAtPoint:CGPointMake(roundf((newImageSize.width-firstImage.size.width)/2),
roundf((newImageSize.height-firstImage.size.height)/2))];
[secondImage drawAtPoint:CGPointMake(roundf((newImageSize.width-secondImage.size.width)/2),
roundf((newImageSize.height-secondImage.size.height)/2))];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
I want to take a screenshot of a UIView (the view would contain a signature) and save it to a local file in the application files, so that the image can be called up at a later point to be displayed in something like a UIImageView. Below is the code behind the signature UIView.
#import "NISignatureViewQuartz.h"
#import <QuartzCore/QuartzCore.h>
#implementation NISignatureViewQuartz
UIBezierPath *path;
- (void)commonInit
{
path = [UIBezierPath bezierPath];
// Capture touches
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1;
[self addGestureRecognizer:pan];
// Erase with long press
[self addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(erase)]];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) [self commonInit];
return self;
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) [self commonInit];
return self;
}
- (void)erase
{
path = [UIBezierPath bezierPath];
[self setNeedsDisplay];
}
- (void)pan:(UIPanGestureRecognizer *)pan {
CGPoint currentPoint = [pan locationInView:self];
if (pan.state == UIGestureRecognizerStateBegan) {
[path moveToPoint:currentPoint];
} else if (pan.state == UIGestureRecognizerStateChanged)
[path addLineToPoint:currentPoint];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
[[UIColor blackColor] setStroke];
[path stroke];
}
#end
How would I go about doing this?
You want to render the view's layer into a graphics context. It's very straightforward. In your NISignatureViewQuartz class you can add this method:
- (UIImage *)snapshot {
UIGraphicsBeginImageContext(self.frame.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
I wrote an useful helper class, to take and manage screenshot:
#implementation MGImageHelper
/* Get the screenshot of an UIView (so take just UIKit elements and not OpenGL or AVFoundation stuff. */
+ (UIImage *)getScreenshotFromView:(UIView *)captureView
{
CGRect rect = [captureView bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[captureView.layer renderInContext:context];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return capturedImage;
}
/* Get the screenshot of a determinate rect of an UIView, and scale it to the size that you want. */
+ (UIImage *)getScreenshotFromView:(UIView *)captureView withRect:(CGRect)captureRect andScaleToSize:(CGSize)newSize
{
UIImage *image = [[self class] getScreenshotFromView:captureView];
image = [[self class] cropImage:image withRect:captureRect];
image = [[self class] scaleImage:image toSize:newSize];
return image;
}
/* Get the screenshot of the screen (useful when you have UIKit elements and OpenGL or AVFoundation stuff */
+ (UIImage *)screenshotFromScreen
{
CGImageRef UIGetScreenImage(void);
CGImageRef screen = UIGetScreenImage();
UIImage* screenImage = [UIImage imageWithCGImage:screen];
CGImageRelease(screen);
return screenImage;
}
/* Get the screenshot of a determinate rect of the screen, and scale it to the size that you want. */
+ (UIImage *)getScreenshotFromScreenWithRect:(CGRect)captureRect andScaleToSize:(CGSize)newSize
{
UIImage *image = [[self class] screenshotFromScreen];
image = [[self class] cropImage:image withRect:captureRect];
image = [[self class] scaleImage:image toSize:newSize];
return image;
}
/* Methods used from methods above but also usable in singular */
+ (UIImage *)cropImage:(UIImage *)image withRect:(CGRect)rect
{
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], rect);
UIImage *cropedImage = [UIImage imageWithCGImage:imageRef];
return cropedImage;
}
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
{
UIGraphicsBeginImageContextWithOptions(newSize, YES, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
#end
You can use UIView method available starting from iOS 7, designed specifically for that:
- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates;
e.g.
UIGraphicsBeginImageContext(self.bounds.size);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I am trying to add image to cell, it works, but the scaling is not really working, the image is scaled to some size, and stay in that size, numbers i enter to the scale function don't change a thing .(image is auto scale to some constant size)
NSURL *url = [NSURL URLWithString:icon];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *logo=[UIImage imageWithData:data scale:4];
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = 10.0;
cell.imageView.image=logo;
Implement this method and use it:
/*! Returns a UIImage which is resized image of the image provided.
#param image
The image to be resized.
#param size
The size of the image to be resized.
*/
+ (UIImage*)resizeImage:(UIImage *)image imageSize:(CGSize)size {
CGFloat imageWidth = image.size.width;
CGFloat imageHeight = image.size.height;
CGFloat requiredWidth = (imageWidth * size.height) / imageHeight;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(requiredWidth, size.height), NO, [UIScreen mainScreen].scale);
[image drawInRect:CGRectMake(0, 0, requiredWidth, size.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
//here is the scaled image which has been changed to the size specified
UIGraphicsEndImageContext();
return newImage;
}
Just write your masking function inside the custom cell class method declared as below.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
[self.imageView.layer setCornerRadius:10.0];
self.imageView.layer.masksToBounds = YES;
}
Use this function to scale the images as per your requirement.
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
float theScaleFactor = 0.0f;
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
if ([[UIScreen mainScreen] scale] == 2.0) {
theScaleFactor = 2.0f;
} else {
theScaleFactor = 0.0f;
}
} else {
theScaleFactor = 0.0f;
}
UIGraphicsBeginImageContextWithOptions(newSize, NO, theScaleFactor);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Hope this will help you.
This is my code:
What am I doing wrong?? I simply want to take a screenshot of an MKMapView displaying a given Location. Taking the screenshot and placing it in an UIImage works fine, but the MKMapView looks really wierd, as if it hasn't been rendered. What's wrong?
if(PageControllerMain.currentPage == 0) {
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(MainPage1MapContainer.bounds.size, MainPage1MapContainer.opaque, 0.0);
}
else {
UIGraphicsBeginImageContext(self.view.bounds.size);
}
UIGraphicsBeginImageContextWithOptions(MainPage1MapContainer.bounds.size, MainPage1MapContainer.opaque, 0.0);
[MainPage1MapContainer.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:#"MapImagePage1.png" atomically:YES];
OverallMainMapContainer.image = image;
}