diff --git a/ILPDFKit/Controller/PDFViewController.m b/ILPDFKit/Controller/PDFViewController.m index 8b10026..4d6cd92 100755 --- a/ILPDFKit/Controller/PDFViewController.m +++ b/ILPDFKit/Controller/PDFViewController.m @@ -137,7 +137,15 @@ -(void)loadPDFView self.view.frame = CGRectMake(0,self.view.frame.origin.y,frm.size.width,frm.size.height-self.view.frame.origin.y); CGPoint margins = [self getMargins]; NSArray* additionViews = [_document.forms createWidgetAnnotationViewsForSuperviewWithWidth:frm.size.width Margin:margins.x HMargin:margins.y]; - _pdfView = [[PDFView alloc] initWithFrame:self.view.bounds DataOrPath:pass AdditionViews:additionViews]; + + //Fetch annotations for the page.. + NSMutableArray *annotations=[[NSMutableArray alloc] init]; + for(PDFPage *page in _document.pages){ + [annotations addObjectsFromArray:[page showAnnotationsForPageWithWidth:frm.size.width XMargin:margins.x YMargin:margins.y]]; + } + + _pdfView = [[PDFView alloc] initWithFrame:self.view.bounds DataOrPath:pass AdditionViews:additionViews Annotations:annotations]; + [self.view addSubview:_pdfView]; } diff --git a/ILPDFKit/Model/PDFPage.h b/ILPDFKit/Model/PDFPage.h index 7dfd952..1d636c3 100755 --- a/ILPDFKit/Model/PDFPage.h +++ b/ILPDFKit/Model/PDFPage.h @@ -13,6 +13,7 @@ PDFPage consists of the data representing the page info. */ +@class PDFDocument; @class PDFDictionary; @interface PDFPage : NSObject @@ -89,4 +90,13 @@ */ @property(nonatomic,readonly) PDFDictionary* resources; +/** The reference of the actual PDFDocument object + */ +@property(nonatomic, assign) PDFDocument *document; + + +/** Show annotations for the page.. + */ +-(NSMutableArray *)showAnnotationsForPageWithWidth:(CGFloat)vwidth XMargin:(CGFloat)xmargin YMargin:(CGFloat)ymargin; + @end diff --git a/ILPDFKit/Model/PDFPage.m b/ILPDFKit/Model/PDFPage.m index 5c1c27c..e026f55 100755 --- a/ILPDFKit/Model/PDFPage.m +++ b/ILPDFKit/Model/PDFPage.m @@ -3,7 +3,8 @@ #import "PDFPage.h" #import "PDFDictionary.h" - +#import "PDFAnnotation.h" +#import "PDFDocument.h" @interface PDFPage() @@ -135,4 +136,174 @@ -(CGRect)rotateBox:(CGRect)box return ret; } +#pragma mark - Annotations + +-(NSMutableArray *)showAnnotationsForPageWithWidth:(CGFloat)vwidth XMargin:(CGFloat)xmargin YMargin:(CGFloat)ymargin{ + + CGPDFPageRef pPage=self.page; + + NSMutableArray* pdfAnnots = [[NSMutableArray alloc] init]; + + CGPDFDictionaryRef pageDictionary = CGPDFPageGetDictionary(pPage); + CGPDFArrayRef outputArray; + if(!CGPDFDictionaryGetArray(pageDictionary, "Annots", &outputArray)) { + return nil; + } + else{ + int arrayCount = CGPDFArrayGetCount( outputArray ); + for( int j = 0; j < arrayCount; ++j ) { + CGPDFObjectRef aDictObj; + if(!CGPDFArrayGetObject(outputArray, j, &aDictObj)) { + break; + } + + CGPDFDictionaryRef annotDict; + if(!CGPDFObjectGetValue(aDictObj, kCGPDFObjectTypeDictionary, &annotDict)) { + break; + } + + const char *annotationType; + CGPDFDictionaryGetName(annotDict, "Subtype", &annotationType); + + NSString* type = [NSString stringWithUTF8String:annotationType]; + + BOOL freeTextCustomAnotToShow=YES; + CGPDFDictionaryRef apDict; + if(CGPDFDictionaryGetDictionary(annotDict, "AP", &apDict)){ + int count = CGPDFDictionaryGetCount(apDict); + if(count>0 && [type isEqualToString:FREE_TEXT_ANNOTATION]) + freeTextCustomAnotToShow=NO; + } + + CGPDFArrayRef rectArray; + if(!CGPDFDictionaryGetArray(annotDict, "Rect", &rectArray)) { + break; + } + + int arrayCount = CGPDFArrayGetCount( rectArray ); + CGPDFReal coords[4]; + for( int k = 0; k < arrayCount; ++k ) { + CGPDFObjectRef rectObj; + if(!CGPDFArrayGetObject(rectArray, k, &rectObj)) { + break; + } + + CGPDFReal coord; + if(!CGPDFObjectGetValue(rectObj, kCGPDFObjectTypeReal, &coord)) { + break; + } + + coords[k] = coord; + } + + CGRect rect = CGRectMake(coords[0],coords[1],coords[2],coords[3]); + + UIColor *annotColor = [UIColor blackColor]; + CGPDFArrayRef colorArray; + if(CGPDFDictionaryGetArray(annotDict, "C", &colorArray)) { + int cArrayCount = CGPDFArrayGetCount( colorArray ); + CGPDFReal colors[3]; + for( int k = 0; k < cArrayCount; ++k ) { + CGPDFObjectRef colorObj; + if(!CGPDFArrayGetObject(colorArray, k, &colorObj)) { + break; + } + CGPDFReal color; + if(!CGPDFObjectGetValue(colorObj, kCGPDFObjectTypeReal, &color)) { + break; + } + colors[k] = color; + } + annotColor=[UIColor colorWithRed:colors[0] green:colors[1] blue:colors[2] alpha:1]; + + } + rect.size.width -= rect.origin.x; + rect.size.height -= rect.origin.y; + + //to show the annotation on the right position a +5 is needed. It may + //be needed because the content inset Top of the ResizableTextView is set + //to -5 ?Dont know why this effects the y value of the frame? + rect.origin.y +=5; + CGRect cropBox=[self cropBox]; + CGFloat width = cropBox.size.width; + CGFloat maxWidth = width; + for(PDFPage* pg in self.document.pages) + { + if([pg cropBox].size.width > maxWidth)maxWidth = [pg cropBox].size.width; + } + + CGFloat hmargin = ((maxWidth-width)/2)*((vwidth-2*xmargin)/maxWidth)+xmargin; + + + + CGFloat height = cropBox.size.height; + CGRect correctedFrame = CGRectMake(rect.origin.x-cropBox.origin.x, height-rect.origin.y-rect.size.height-cropBox.origin.y, rect.size.width, rect.size.height); + + CGFloat realWidth = vwidth-2*hmargin; + + CGFloat factor = realWidth/width; + + CGFloat pageOffset = 0; + + for(NSUInteger c = 0; c < self.pageNumber-1;c++) + { + PDFPage* pg = [self.document.pages objectAtIndex:c]; + CGFloat iwidth = [pg cropBox].size.width; + CGFloat ihmargin = ((maxWidth-iwidth)/2)*((vwidth-2*xmargin)/maxWidth)+xmargin; + CGFloat iheight = [pg cropBox].size.height; + CGFloat irealWidth = vwidth-2*ihmargin; + CGFloat ifactor = irealWidth/iwidth; + pageOffset+= iheight*ifactor+ymargin; + } + + + CGRect pageRect = CGRectIntegral(CGRectMake(correctedFrame.origin.x*factor+hmargin, correctedFrame.origin.y*factor+ymargin, correctedFrame.size.width*factor, correctedFrame.size.height*factor)); + + + + CGRect uiBaseRect = CGRectIntegral(CGRectMake(pageRect.origin.x, pageRect.origin.y+pageOffset, pageRect.size.width, pageRect.size.height)); + + + PDFAnnotation *annotation = [[PDFAnnotation alloc] initWithPDFDictionary:annotDict andType:type]; + + + CGSize strSize=[annotation.textString sizeWithFont:annotation.font]; + + if(uiBaseRect.size.width + +/** + The identifier for FreeText annotations + */ +#define FREE_TEXT_ANNOTATION @"FreeText" + +@interface PDFAnnotation : NSObject +/** + Defines the type of the annotation. In this version only FreeText is supported + */ +@property(nonatomic,retain) NSString * annotationType; + +/** + Defines the font of a FreeText annotation. + */ +@property(nonatomic,retain) UIFont * font; + +/** + The text of a FreeText annotation + */ +@property(nonatomic,retain) NSString * textString; + +/** + The view showing the annoatation. + */ +@property(nonatomic,retain) UIView * annotationView; + +/** + The text color of a FreeText annotation + */ +@property(nonatomic,retain) UIColor* textColor; + +/** + The alignment of a the text in a FreeText annotation + */ +@property UITextAlignment textAlignment; + +/** + The border Width of a Square or FreeText annotation. If the FreeText + annotation is without border this value should be 0 + */ +@property CGFloat borderWidth; + +/** + Initializes an PDFAnnotation with a specified PDF dictionary containing + the annotation properties and a specified type + @param annotDict The CGPDFDictionaryRef containing the annotation properties + @param type The annotation type + @return The newly initialized PDFAnnotation + */ +-(id)initWithPDFDictionary:(CGPDFDictionaryRef)annotDict andType:(NSString*)type; +@end diff --git a/ILPDFKit/View/PDFAnnotation.m b/ILPDFKit/View/PDFAnnotation.m new file mode 100644 index 0000000..8039460 --- /dev/null +++ b/ILPDFKit/View/PDFAnnotation.m @@ -0,0 +1,111 @@ +// +// PDFAnnotation.m +// ILPDFKitSample +// +// Created by Ved Prakash on 6/10/14. +// Copyright (c) 2014 Iwe Labs. All rights reserved. +// + +#import "PDFAnnotation.h" + +@implementation PDFAnnotation +@synthesize annotationType,font,textString; +@synthesize textColor; +@synthesize textAlignment; +@synthesize borderWidth; + + +-(id)initWithPDFDictionary:(CGPDFDictionaryRef)annotDict andType:(NSString *)type{ + self=[super init]; + self.annotationType = type; + + if ([type isEqualToString:FREE_TEXT_ANNOTATION]){ + + CGPDFStringRef fontTypeRef; + if(CGPDFDictionaryGetString(annotDict, "DA", &fontTypeRef)) { + NSString* fontType = (__bridge NSString *)CGPDFStringCopyTextString(fontTypeRef); + NSArray *firstWords = [fontType componentsSeparatedByString:@" "]; + NSString *tempStr = [firstWords objectAtIndex:0]; + fontType = [tempStr substringFromIndex:1]; + + tempStr=[firstWords objectAtIndex:1]; + NSInteger fontSize = [tempStr intValue]; + int rgIndex=0;//Color + for(NSString *val in firstWords){ + if([[val lowercaseString] isEqualToString:@"rg"]){ + //Colors will be defined in 3 indexes less than rg index + break; + } + rgIndex++; + } + if (rgIndex>0 && rgIndex>4) { + CGFloat red = [[firstWords objectAtIndex:rgIndex-3] floatValue]; + CGFloat green = [[firstWords objectAtIndex:rgIndex-2] floatValue]; + CGFloat blue = [[firstWords objectAtIndex:rgIndex-1] floatValue]; + self.textColor = [UIColor colorWithRed:red green:green blue:blue alpha:1]; + } + else{ + self.textColor = [UIColor blackColor]; + } + self.font = [UIFont fontWithName:fontType size:fontSize]; + } + else{ + textColor=[UIColor blackColor]; + self.font = [UIFont fontWithName:@"Helvetica" size:12]; + } + CGPDFInteger textAlignmentRef; + if (CGPDFDictionaryGetInteger(annotDict, "Q", &textAlignmentRef)) { + switch (textAlignmentRef) { + case 1: + self.textAlignment = UITextAlignmentCenter; + break; + case 2: + self.textAlignment = UITextAlignmentRight; + break; + + default: + self.textAlignment = UITextAlignmentLeft; + break; + } + } + else self.textAlignment = UITextAlignmentLeft; + + CGPDFStringRef textStringRef; + if(CGPDFDictionaryGetString(annotDict, "Contents", &textStringRef)) { + self.textString = (__bridge NSString *)CGPDFStringCopyTextString(textStringRef); + } + + } + CGPDFArrayRef borderArray; + if (CGPDFDictionaryGetArray(annotDict, "Border",&borderArray)){ + int cArrayCount = CGPDFArrayGetCount( borderArray ); + for( int k = 0; k < cArrayCount; ++k ) { + CGPDFObjectRef borderObj; + if(!CGPDFArrayGetObject(borderArray, k, &borderObj)) { + break; + } + CGPDFReal border; + if(!CGPDFObjectGetValue(borderObj, kCGPDFObjectTypeReal, &border)) { + break; + } + + if (k==2) { + self.borderWidth = border; + } + } + } + else{ + self.borderWidth = 1; + } + + CGPDFDictionaryRef borderStyleDict; + if (CGPDFDictionaryGetDictionary(annotDict, "BS",&borderStyleDict)){ + CGPDFReal borderStyleWidth; + if(CGPDFDictionaryGetNumber(borderStyleDict, "W", &borderStyleWidth)){ + self.borderWidth = borderStyleWidth; + } + } + + return self; +} +@end diff --git a/ILPDFKit/View/PDFView.h b/ILPDFKit/View/PDFView.h index 78c1b79..23e3a53 100755 --- a/ILPDFKit/View/PDFView.h +++ b/ILPDFKit/View/PDFView.h @@ -41,6 +41,17 @@ -(id)initWithFrame:(CGRect)frame DataOrPath:(id)dataOrPath AdditionViews:(NSArray*)widgetAnnotationViews; +/** Creates a new instance of PDFView. + + @param frame Frame of the view. + @param dataOrPath Either NSData for PDF data or NSString for a PDF file path. + @param widgetAnnotationViews NSArray of instances of PDFWidgetAnnotationalElementView to be added to the pdfView scrollView. + @param annotations NSArray instances of Text Annotations to be added to the pdfView scrollView + @return A new instance of PDFView. + */ +- (id)initWithFrame:(CGRect)frame DataOrPath:(id)dataOrPath AdditionViews:(NSArray*)widgetAnnotationViews Annotations:(NSArray *)annotations; + + /**--------------------------------------------------------------------------------------- * @name Adding and Removing Additions * --------------------------------------------------------------------------------------- diff --git a/ILPDFKit/View/PDFView.m b/ILPDFKit/View/PDFView.m index a6b310f..c7cdafc 100755 --- a/ILPDFKit/View/PDFView.m +++ b/ILPDFKit/View/PDFView.m @@ -6,7 +6,7 @@ #import "PDFWidgetAnnotationView.h" #import "PDFFormButtonField.h" #import "PDF.h" - +#import "PDFAnnotation.h" @interface PDFView() @@ -71,6 +71,63 @@ - (id)initWithFrame:(CGRect)frame DataOrPath:(id)dataOrPath AdditionViews:(NSArr } +- (id)initWithFrame:(CGRect)frame DataOrPath:(id)dataOrPath AdditionViews:(NSArray*)widgetAnnotationViews Annotations:(NSArray *)annotations +{ + self = [super initWithFrame:frame]; + if (self) + { + CGRect contentFrame = CGRectMake(0, 0, frame.size.width, frame.size.height); + _pdfView = [[UIWebView alloc] initWithFrame:contentFrame]; + _pdfView.scalesPageToFit = YES; + _pdfView.scrollView.delegate = self; + _pdfView.scrollView.bouncesZoom = NO; + _pdfView.delegate = self; + _pdfView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin; + self.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin; + + [self addSubview:_pdfView]; + [_pdfView.scrollView setZoomScale:1]; + [_pdfView.scrollView setContentOffset:CGPointZero]; + + //This allows us to prevent the keyboard from obscuring text fields near the botton of the document. + [_pdfView.scrollView setContentInset:UIEdgeInsetsMake(0, 0, frame.size.height/2, 0)]; + + _pdfWidgetAnnotationViews = [[NSMutableArray alloc] initWithArray:widgetAnnotationViews]; + + for(PDFWidgetAnnotationView* element in _pdfWidgetAnnotationViews) + { + element.alpha = 0; + element.parentView = self; + [_pdfView.scrollView addSubview:element]; + + if([element isKindOfClass:[PDFFormButtonField class]]) + { + [(PDFFormButtonField*)element setButtonSuperview]; + } + } + + //Adding annotations + for(PDFAnnotation *annotation in annotations){ + [_pdfView.scrollView addSubview:annotation.annotationView]; + } + + if([dataOrPath isKindOfClass:[NSString class]]) + { + [_pdfView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:dataOrPath]]]; + } + else if([dataOrPath isKindOfClass:[NSData class]]) + { + [_pdfView loadData:dataOrPath MIMEType:@"application/pdf" textEncodingName:@"NSASCIIStringEncoding" baseURL:nil]; + } + + UITapGestureRecognizer* tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:nil action:NULL]; + [self addGestureRecognizer:tapGestureRecognizer]; + tapGestureRecognizer.delegate = self; + } + return self; +} + + -(void)addPDFWidgetAnnotationView:(PDFWidgetAnnotationView*)viewToAdd { [_pdfWidgetAnnotationViews addObject:viewToAdd]; diff --git a/ILPDFKitSample/ILPDFKitSample.xcodeproj/project.pbxproj b/ILPDFKitSample/ILPDFKitSample.xcodeproj/project.pbxproj index 872c395..862b797 100644 --- a/ILPDFKitSample/ILPDFKitSample.xcodeproj/project.pbxproj +++ b/ILPDFKitSample/ILPDFKitSample.xcodeproj/project.pbxproj @@ -35,6 +35,8 @@ 67AB6D9418C52131005E8D36 /* PDFFormTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 67AB6D7F18C52131005E8D36 /* PDFFormTextField.m */; }; 67AB6D9518C52131005E8D36 /* PDFView.m in Sources */ = {isa = PBXBuildFile; fileRef = 67AB6D8118C52131005E8D36 /* PDFView.m */; }; 67AB6D9618C52131005E8D36 /* PDFWidgetAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 67AB6D8318C52131005E8D36 /* PDFWidgetAnnotationView.m */; }; + 84A9C9741947105F00959F6B /* PDFAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 84A9C9731947105F00959F6B /* PDFAnnotation.m */; }; + 84A9C976194713B000959F6B /* testC.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 84A9C975194713B000959F6B /* testC.pdf */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -90,6 +92,9 @@ 67AB6D8118C52131005E8D36 /* PDFView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PDFView.m; sourceTree = ""; }; 67AB6D8218C52131005E8D36 /* PDFWidgetAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PDFWidgetAnnotationView.h; sourceTree = ""; }; 67AB6D8318C52131005E8D36 /* PDFWidgetAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PDFWidgetAnnotationView.m; sourceTree = ""; }; + 84A9C9721947105F00959F6B /* PDFAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PDFAnnotation.h; sourceTree = ""; }; + 84A9C9731947105F00959F6B /* PDFAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PDFAnnotation.m; sourceTree = ""; }; + 84A9C975194713B000959F6B /* testC.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = testC.pdf; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -148,6 +153,7 @@ 67AB6D2218C5189F005E8D36 /* Supporting Files */ = { isa = PBXGroup; children = ( + 84A9C975194713B000959F6B /* testC.pdf */, 67AB6D4A18C518FD005E8D36 /* testA.pdf */, 67AB6D4B18C518FD005E8D36 /* testB.pdf */, 67AB6D2318C5189F005E8D36 /* ILPDFKitSample-Info.plist */, @@ -233,6 +239,8 @@ 67AB6D8118C52131005E8D36 /* PDFView.m */, 67AB6D8218C52131005E8D36 /* PDFWidgetAnnotationView.h */, 67AB6D8318C52131005E8D36 /* PDFWidgetAnnotationView.m */, + 84A9C9721947105F00959F6B /* PDFAnnotation.h */, + 84A9C9731947105F00959F6B /* PDFAnnotation.m */, ); path = View; sourceTree = ""; @@ -290,6 +298,7 @@ buildActionMask = 2147483647; files = ( 67AB6D2618C5189F005E8D36 /* InfoPlist.strings in Resources */, + 84A9C976194713B000959F6B /* testC.pdf in Resources */, 67AB6D2E18C5189F005E8D36 /* Images.xcassets in Resources */, 67AB6D4C18C518FD005E8D36 /* testA.pdf in Resources */, 67AB6D4D18C518FD005E8D36 /* testB.pdf in Resources */, @@ -308,6 +317,7 @@ 67AB6D8A18C52131005E8D36 /* PDFFormAction.m in Sources */, 67AB6D8C18C52131005E8D36 /* PDFObject.m in Sources */, 67AB6D8918C52131005E8D36 /* PDFForm.m in Sources */, + 84A9C9741947105F00959F6B /* PDFAnnotation.m in Sources */, 67AB6D9518C52131005E8D36 /* PDFView.m in Sources */, 67AB6D9018C52131005E8D36 /* PDFUtility.m in Sources */, 67AB6D8E18C52131005E8D36 /* PDFStream.m in Sources */, diff --git a/ILPDFKitSample/ILPDFKitSample/ILAppDelegate.m b/ILPDFKitSample/ILPDFKitSample/ILAppDelegate.m index 82c35db..ac536c2 100644 --- a/ILPDFKitSample/ILPDFKitSample/ILAppDelegate.m +++ b/ILPDFKitSample/ILPDFKitSample/ILAppDelegate.m @@ -30,7 +30,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( } else { - _pdfViewController = [[PDFViewController alloc] initWithResource:@"testA.pdf"]; + _pdfViewController = [[PDFViewController alloc] initWithResource:@"testC.pdf"]; } _pdfViewController.title = @"Sample PDF"; diff --git a/ILPDFKitSample/ILPDFKitSample/ILPDFKitSample-Prefix.pch b/ILPDFKitSample/ILPDFKitSample/ILPDFKitSample-Prefix.pch index ff395d2..d527941 100644 --- a/ILPDFKitSample/ILPDFKitSample/ILPDFKitSample-Prefix.pch +++ b/ILPDFKitSample/ILPDFKitSample/ILPDFKitSample-Prefix.pch @@ -15,3 +15,11 @@ #import #import #endif + +#ifdef __IPHONE_6_0 // iOS6 and later +# define UITextAlignmentCenter NSTextAlignmentCenter +# define UITextAlignmentLeft NSTextAlignmentLeft +# define UITextAlignmentRight NSTextAlignmentRight +# define UILineBreakModeTailTruncation NSLineBreakByTruncatingTail +# define UILineBreakModeMiddleTruncation NSLineBreakByTruncatingMiddle +#endif \ No newline at end of file diff --git a/ILPDFKitSample/ILPDFKitSample/testC.pdf b/ILPDFKitSample/ILPDFKitSample/testC.pdf new file mode 100644 index 0000000..81b1d3a Binary files /dev/null and b/ILPDFKitSample/ILPDFKitSample/testC.pdf differ