views:

3476

answers:

6

I am developing an iPhone app for creating images using built in graphics and user defined text.

I want to be able to have my app, with built in graphics and user defined text, which can then be sent as a single image (much like a screenshot) to the email app to be emailed.

Is there a way to do this without taking a screenshot, leaving the app, going into the Photos app, selecting the screenshot, and emailing it from there?

Ultimately I would like to be able to have a button in my app that the user could tap, and the whole screen would be captured and sent directly to the mail app.

Any pointers gratefully accepted!

A: 

I have no idea if this will work, but you can try creating a bitmap-backed graphics context, then getting your root view's Core Animation layer and calling its -renderInContext: method. That might do it, but I've never tried it.

Perhaps, though, you should consider a different approach. Is it just that you've written a bunch of custom drawing code that's visible on screen and you want to be able to draw into a file or memory buffer too? If so, perhaps you should factor that drawing code out of your view and into a separate object that your view simply uses. That would allow you to very easily draw it both ways.

Brent Royal-Gordon
+3  A: 

To expand upon Brent's answer, the following code will grab a screenshot and save it out to the Documents directory as a PNG called screenshot.png:

UIWindow *screenWindow = [[UIApplication sharedApplication] keyWindow];

UIGraphicsBeginImageContext(screenWindow.frame.size);
[screenWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

NSData *screenshotPNG = UIImagePNGRepresentation(screenshot);

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSError *error = nil;
[screenshotPNG writeToFile:[documentsDirectory stringByAppendingPathComponent:@"screenshot.png"] options:NSAtomicWrite error:&error];

This is a little crude, as it will leave a blank spot near the top of the screen for the title bar, and doesn't appear to grab the content from CAEAGLLayers.

Also, I don't believe you can use the standard mailto:// URL construction, followed by openURL, to send MIME-encoded attachments. Maybe the 3.0 SDK fixes this, but I've yet to play with it. You may need to use something like sksmtpmessage to send the message directly from within your application.

Brad Larson
I bet if you looped through UIApplication's windows array and rendered them all (instead of only the keyWindow), the status bar would be drawn.
benzado
+3  A: 

There's also the private API UIGetScreenImage. It is used like so:

CGImageRef UIGetScreenImage();
@interface UIImage (ScreenImage)
+ (UIImage *)imageWithScreenContents;
@end

@implementation UIImage (ScreenImage)
+ (UIImage *)imageWithScreenContents
{
    CGImageRef cgScreen = UIGetScreenImage();
    if (cgScreen) {
     UIImage *result = [UIImage imageWithCGImage:cgScreen];
     CGImageRelease(cgScreen);
     return result;
    }
    return nil;
}
@end

This function may be combined with UIImagePNGRepresentation to produce a PNG.

rpetrich
I'm not sure if this used to work, but ti doesn't work now.
Dimitris
It still works, but only on-device (not in simulator) and Apple will definitely reject it.
rpetrich
A: 

skpsmtpmessage is great. If fact, it's so good, I went and cloned it and added sample project on github. The sample GUI below adds a few bells and whistles, like a progress bar and some other goodies, but it basically maintains the core skpsmtpmessage code.

http://github.com/kailoa/iphone-smtp/tree/master

Kailoa Kadano
+1  A: 

In OS 3.0, you can use MFMailComposeViewController:

MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker addAttachmentData:screenshotPNG mimeType:@"image/png" fileName:@"PNGfromMyApp"];
David Maymudes
+1  A: 

Apple is now allowing applications to use the;

CGImageRef UIGetScreenImage(void);

function. Although you must remember that it returns a retained CGImageRef and you'll have to manage your memory accordingly.

They also say that, "...a future release of iPhone OS may provide a public API equivalent of this functionality. At such time, all applications using UIGetScreenImage() will be required to adopt the public API."

Alasdair Allan