Printing subview image to PDF in iOS
I am attempting to take a fingerpainted signature from the iPad's touch screen, print it to PDF, and then email the resulting PDF to a preset address. I have a UIView subclass written that adds lines between the current drag event's location to the last drag event's location, as shown below. I have had no troubles implementing the emailing portion. The subclass's declaration:
#import <UIKit/UIKit.h>
@interface SignatureView : UIView {
UIImageView *drawImage;
@public
UIImage *cachedSignature;
}
@property (nonatomic, retain) UIImage* cachedSignature;
-(void) clearView;
@end
And implementation:
#import "SignatureView.h"
@implementation SignatureView
Boolean drawSignature=FALSE;
float oldTouchX=-1;
float oldTouchY=-1;
float nowTouchX=-1;
float nowTouchY=-1;
@synthesize cachedSignature;
//UIImage *cachedSignature=nil;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
}
return self;
if (cachedSignature==nil){
if(UIGraphicsBeginImageContextWithOptions!=NULL){
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
}els开发者_如何学Goe{
UIGraphicsBeginImageContext(self.frame.size);
}
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
cachedSignature = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
- (void)drawRect:(CGRect)rect {
//get image of current state of signature field
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
cachedSignature = UIGraphicsGetImageFromCurrentImageContext();
//draw cached signature onto signature field, no matter what.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0,0,302,90),cachedSignature.CGImage);
if(oldTouchX>0 && oldTouchY>0 && nowTouchX>0 && nowTouchY>0){
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetLineWidth(context, 2);
//make change to signature field
CGContextMoveToPoint(context, oldTouchX, oldTouchY);
CGContextAddLineToPoint(context, nowTouchX, nowTouchY);
CGContextStrokePath(context);
}
}
-(void) clearView{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetGrayFillColor(context, 0.75, 1.0);
CGContextFillRect(context, CGRectMake(0,0,800,600));
CGContextFlush(context);
cachedSignature = UIGraphicsGetImageFromCurrentImageContext();
[self setNeedsDisplay];
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint location=[[touches anyObject] locationInView:self];
oldTouchX=nowTouchX;
oldTouchY=nowTouchY;
nowTouchX=location.x;
nowTouchY=location.y;
[self setNeedsDisplay];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint location=[[touches anyObject] locationInView:self];
oldTouchX=nowTouchX;
oldTouchY=nowTouchY;
nowTouchX=location.x;
nowTouchY=location.y;
[self setNeedsDisplay];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
oldTouchX=-1;
oldTouchY=-1;
nowTouchX=-1;
nowTouchY=-1;
}
- (void)dealloc {
[super dealloc];
}
@end
I am, however, having trouble printing the signature to a PDF. As I understand the above code, it should keep a copy of the signature before the last move was made as a UIImage named cachedSignature, accessible to all. However, when I try to write it to a PDF context with the following:
UIGraphicsBeginPDFContextToFile(fileName, CGRectZero, nil);
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
UIImage* background=[[UIImage alloc] initWithContentsOfFile:backgroundPath];
// Create the PDF context using the default page size of 612 x 792.
// Mark the beginning of a new page.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0.0, 792);
CGContextScaleCTM(context, 1.0, -1.0);
//CGContextDrawImage(context, CGRectMake(0,0,612,790),background.CGImage);
//draw signature images
UIImage *y=clientSignatureView.cachedSignature;
CGContextDrawImage(context, CGRectMake(450, 653, 600, 75), y.CGImage);
//CGContextDrawImage(context, CGRectMake(75, 75, 300, 300), techSignatureView.cachedSignature.CGImage);
CGContextTranslateCTM(context, 0.0, 792);
CGContextScaleCTM(context, 1.0, -1.0);
It fails. In this instance 'techSignatureView' and 'clientSignatureView' are instances of the custom UIView as defined above, connected to outlets in the same parent UIView as is running this code.
I don't know what's going wrong. I've taken out the call to print the background image, in case they were being printed 'behind' it, with no results. Using the debugger to inspect 'y' in the above code reveals that it has nil protocol entries and nil method entries; so I suspect it's not being accessed properly - beyond that, I'm clueless and don't know how to proceed.
First of all, your cachedSignature probably doesn't exist anymore when you try to draw it, because it's autoreleased. Use the property setter when you assign it, so instead of cachedSignature = foo
write self.cachedSignature = foo
.
Also, UIGraphicsGetImageFromCurrentImageContext
only works for image contexts, you cannot use this in drawRect:
with the current context. The drawRect:
method takes care of drawing your view to the screen, you cannot create an image from the same context, you have to use UIGraphicsBeginImageContext
to create a new context that you draw the image into. The drawRect:
method is not the best place for that anyway, because performance will likely be bad if you render the image every time a touch moves. Instead, I'd suggest to render the signature to the image in your touchesEnded:withEvent:
implementation.
精彩评论