App crashs in drawViewHierarchyInRect - objective-c

My app is used large images (5MB) to markup. But app is getting crashed without any error messages.
Below is the code I used
UIGraphicsBeginImageContext(CGSizeMake(_drawingUV.drawingImgView.image.size.width, _drawingUV.drawingImgView.image.size.height));
{
CGContextRef context = UIGraphicsGetCurrentContext();
if ([_drawingUV.drawingImgView respondsToSelector:#selector(drawViewHierarchyInRect:afterScreenUpdates:)])
{
[_drawingUV.drawingImgView drawViewHierarchyInRect:_drawingUV.drawingImgView.bounds afterScreenUpdates:YES];
}
else
{
[_drawingUV.drawingImgView.layer renderInContext:context];
}
screenShot = UIGraphicsGetImageFromCurrentImageContext();
}
UIGraphicsEndImageContext();
I have tried all possibilities to find a solution last two days. But could not.
This function is used below UI objects.
main view has view and inside that it has UIScrollView and inside that UIScrollView has UIImageView. So I need to get screenshoto this UIImageView. I use these views to scroll and markup the the image view.
Any idea for this crash?

I use this all the time without issue:
- (UIImage *)screenshot {
UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow];
UIGraphicsBeginImageContextWithOptions(mainWindow.bounds.size, NO, 1.0);
[mainWindow drawViewHierarchyInRect:mainWindow.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}

Related

Performance issue when try to make rounded UIImage (using mask)

I've developed method which make from rect UIImage to rounded. The problem is that it decrease performance if do that operation for 10 different images in a row. Images have resolution 120x120
- (UIImage *)roundedImage:(UIImage*)anOriginalImage radius:(CGFloat)aRadius
{
UIImage *result = nil;
if (anOriginalImage != nil) {
UIGraphicsBeginImageContextWithOptions(anOriginalImage.size, NO, 0);
[[UIBezierPath bezierPathWithRoundedRect:(CGRect){CGPointZero, anOriginalImage.size}
cornerRadius:aRadius] addClip];
[anOriginalImage drawInRect:(CGRect){CGPointZero, anOriginalImage.size}];
result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
return result;
}
How to fix that?
Import the QuartzCore framework to get access to the .cornerRadius property of your UIView or UIImageView.
#import <QuartzCore/QuartzCore.h>
Also manually add it to your project's Frameworks folder.
Add this method to your view controller or wherever you need it:
-(void)setRoundedView:(UIImageView *)roundedView toDiameter:(float)newSize;
{
CGPoint saveCenter = roundedView.center;
CGRect newFrame = CGRectMake(roundedView.frame.origin.x, roundedView.frame.origin.y, newSize, newSize);
roundedView.frame = newFrame;
roundedView.layer.cornerRadius = newSize / 2.0;
roundedView.center = saveCenter;
}
To use it, just pass it a UIImageView and a diameter. This example assumes you have a UIImageView named "circ" added as a subview to your view. It should have a backgroundColor set so you can see it.
[self setRoundedView:circ toDiameter:100.0];
This just handles UIImageViews but you can generalize it to any UIView.

Creating retina screenshot programmatically resulting in non retina image

I am trying to take a retina screenshot programmatically and I have tried every approach found online, but I was not able to get the screenshot to be retina.
I understand the following private API:
UIGetScreenImage();
cannot be used as Apple will reject your app. However, this method returns exactly what I need (640x960 screenshot of the screen).
I have tried this method on my iPhone 4 as well as the iPhone 4 simulator on retina hardware, but the resulting image is always 320x480.
-(UIImage *)captureView
{
AppDelegate *appdelegate = [[UIApplication sharedApplication]delegate];
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(appdelegate.window.bounds.size, NO, 0.0);
else
UIGraphicsBeginImageContext(appdelegate.window.bounds.size);
[appdelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSLog(#"SIZE: %#", NSStringFromCGSize(image.size));
NSLog(#"scale: %f", [UIScreen mainScreen].scale);
return image;
}
I have also tried the Apple recommended way:
- (UIImage*)screenshot
{
// Create a graphics context with the target size
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
CGSize imageSize = [[UIScreen mainScreen] bounds].size;
if (NULL != UIGraphicsBeginImageContextWithOptions)
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
else
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
// Iterate over every window from back to front
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
if (![window respondsToSelector:#selector(screen)] || [window screen] == [UIScreen mainScreen])
{
// -renderInContext: renders in the coordinate space of the layer,
// so we must first apply the layer's geometry to the graphics context
CGContextSaveGState(context);
// Center the context around the window's anchor point
CGContextTranslateCTM(context, [window center].x, [window center].y);
// Apply the window's transform about the anchor point
CGContextConcatCTM(context, [window transform]);
// Offset by the portion of the bounds left of and above the anchor point
CGContextTranslateCTM(context,
-[window bounds].size.width * [[window layer] anchorPoint].x,
-[window bounds].size.height * [[window layer] anchorPoint].y);
// Render the layer hierarchy to the current context
[[window layer] renderInContext:context];
// Restore the context
CGContextRestoreGState(context);
}
}
// Retrieve the screenshot image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSLog(#"Size: %#", NSStringFromCGSize(image.size));
return image;
}
But it also returns a non retina image:
2012-12-23 19:57:45.205 PostCard[3351:707] size: {320, 480}
Is there something obvious I'm missing? How come there methods that are suppose to take retina screenshot return me non retina screenshots?
Thanks in advance!
I don't see anything wrong in your code. Apart from image.size, have you tried logging image.scale? Is it 1 or 2? If it's 2, it is actually a retina image.
UIImage.scale represents the scale of the image. So an image with UIImage.size being 320×480 and UIImage.scale being 2 has an actual size of 640×960. From Apple's doc:
If you multiply the logical size of the image (stored in the size property) by the value in this property, you get the dimensions of the image in pixels.
It's the same idea as when you load an image into a UIImage with the #2x modifier. For example:
a.png (100×80) => size=100×80 scale=1
b#2x.png (200×160) => size=100×80 scale=2

Screenshot/Snapshot from mapView stores a blank Map

I want to take a screenshot of a MapView and save to photos
This is the used source:
- (IBAction)screenshot:(id)sender {
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(mapView.frame.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(mapView.frame.size);
[mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);
}
The action is successful, but the photo looks like this here
MapView Screenshot
I do not know what is wrong. I've already tried some codes. All with the same result. If I make a screenshot of the entire view, the map also looks like the picture above.
Does anyone have any idea or can help me?
EDIT:
- (UIImage*) ImageFromMapView
{
UIGraphicsBeginImageContext(self.frame.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
//[[[yourmapView.layer sublayers] objectAtIndex:1] renderInContext:UIGraphicsGetCurrentContext()]; try this upper fails
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Try using UIGraphicsBeginImageContextWithOptions instead of UIGraphicsBeginImageContext:
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
Note: Starting from iOS 4, UIGraphicsBeginImageContextWithOptions allows you to provide with a scale factor. A scale factor of zero sets it to the scale factor of the device's main screen. This enables you to get the sharpest, highest-resolustion snapshot of the display, including a Retina Display.

Programmatically take screenshots on iOS from anywhere

I am currently using this code to capture the screen:
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(keyWindow.bounds.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(keyWindow.bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[keyWindow.layer renderInContext:context];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
It works fine from the Springboard but in an opened application, there is no image created. The key window and [UIScreen mainScreen] should work from anywhere or should they not?
Do I have to get more specific and somehow use the specific window that the current app is using?
It may be a silly answer, but are you sure that the view is loaded when you try to capture the key window?
HOpe this helps.
This is for Jailbroken iOS only:
// fwd declare a private function
UIKIT_EXTERN CGImageRef UIGetScreenImage();
// grab screen image from framebuffer.
// this grabs everything: status bar included
CGImageRef ref = UIGetScreenImage();
// create a UIImage out of CoreGraphics object
// at this point img contains your screenshot
UIImage* img = [UIImage imageWithCGImage:ref];
// release temp object
CGImageRelease(ref);

UITableViewCell's imageView fit to 40x40

I use the same big images in a tableView and detailView.
Need to make imageView filled in 40x40 when an imags is showed in tableView, but stretched on a half of a screen. I played with several properties but have no positive result:
[cell.imageView setBounds:CGRectMake(0, 0, 50, 50)];
[cell.imageView setClipsToBounds:NO];
[cell.imageView setFrame:CGRectMake(0, 0, 50, 50)];
[cell.imageView setContentMode:UIViewContentModeScaleAspectFill];
I am using SDK 3.0 with build in "Cell Objects in Predefined Styles".
I put Ben's code as an extension in my NS-Extensions file so that I can tell any image to make a thumbnail of itself, as in:
UIImage *bigImage = [UIImage imageNamed:#"yourImage.png"];
UIImage *thumb = [bigImage makeThumbnailOfSize:CGSizeMake(50,50)];
Here is .h file:
#interface UIImage (PhoenixMaster)
- (UIImage *) makeThumbnailOfSize:(CGSize)size;
#end
and then in the NS-Extensions.m file:
#implementation UIImage (PhoenixMaster)
- (UIImage *) makeThumbnailOfSize:(CGSize)size
{
UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale);
// draw scaled image into thumbnail context
[self drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *newThumbnail = UIGraphicsGetImageFromCurrentImageContext();
// pop the context
UIGraphicsEndImageContext();
if(newThumbnail == nil)
NSLog(#"could not scale image");
return newThumbnail;
}
#end
I cache a thumbnail version since using large images scaled down on the fly uses too much memory.
Here's my thumbnail code:
- (UIImage *)thumbnailOfSize:(CGSize)size {
if( self.previewThumbnail )
return self.previewThumbnail; // returned cached thumbnail
UIGraphicsBeginImageContext(size);
// draw scaled image into thumbnail context
[self.preview drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *newThumbnail = UIGraphicsGetImageFromCurrentImageContext();
// pop the context
UIGraphicsEndImageContext();
if(newThumbnail == nil)
NSLog(#"could not scale image");
self.previewThumbnail = newThumbnail;
return self.previewThumbnail;
}
Just make sure you properly clear the cached thumbnail if you change your original image (self.preview in my case).
I have mine wrapped in a UIView and use this code:
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
(self is the wrapper UIView, with the dimensions I want - I use AsyncImageView).
I thought Ben Lachman's suggestion of generating thumbnails in advance rather than on the fly was smart, so I adapted his code so it could handle a whole array and to make it more portable (no hard-coded property names).
- (NSArray *)arrayOfThumbnailsOfSize:(CGSize)size fromArray:(NSArray*)original {
NSMutableArray *temp = [NSMutableArray arrayWithCapacity:[original count]];
for(UIImage *image in original){
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0,0,size.width,size.height)];
UIImage *thumb = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[temp addObject:thumb];
}
return [NSArray arrayWithArray:temp];
}
you might be able to use this?
yourTableViewController.rowImage = [UIImage imageNamed:#"yourImage.png"];
and/or
cell.image = yourTableViewController.rowImage;
and if your images are already 40x40 then you shouldn't have to worry about setting bounds and stuff... but, i'm also new to this, so, i wouldn't know, haven't played around with Table View row/cell images much
hope this helps.
I was able to make this work using interface builder and a tableviewcell. You can set the "Mode" properties for an image view to "Aspect Fit". I'm not sure how to do this programatically.
Try setting UIImageView.autoresizesSubviews and/or UIImageView.contentStretch.