forked from vfr/Reader
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPDFViewTiled.m
More file actions
348 lines (259 loc) · 9.11 KB
/
PDFViewTiled.m
File metadata and controls
348 lines (259 loc) · 9.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
//
// PDFViewTiled.m
// Reader
//
// Created by Julius Oklamcak on 2010-09-01.
// Copyright © 2010-2011 Julius Oklamcak. All rights reserved.
//
// This work is being made available under a Creative Commons Attribution license:
// «http://creativecommons.org/licenses/by/3.0/»
// You are free to use this work and any derivatives of this work in personal and/or
// commercial products and projects as long as the above copyright is maintained and
// the original author is attributed.
//
#import "PDFViewTiled.h"
#import "PDFTiledLayer.h"
#import "CGPDFDocument.h"
@implementation PDFViewTiled
#pragma mark Properties
@synthesize pageCount = _pageCount;
@synthesize currentPage = _currentPage;
#pragma mark PDFViewTiled class methods
+ (Class)layerClass
{
return [PDFTiledLayer class];
}
#pragma mark PDFViewTiled instance methods
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
self.autoresizesSubviews = NO;
self.userInteractionEnabled = NO;
self.contentMode = UIViewContentModeScaleAspectFit; // For proper view rotation handling
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; // N.B.
self.autoresizingMask |= UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
self.autoresizingMask |= UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (id)initWithURL:(NSURL *)fileURL page:(NSInteger)page password:(NSString *)password frame:(CGRect)frame
{
if ((self = [self initWithFrame:frame]))
{
if (fileURL != nil) // Check for non-nil file URL
{
_fileURL = [fileURL copy]; // Keep a copy of the file URL
_password = [password copy]; // Keep a copy of the password
_PDFDocRef = CGPDFDocumentCreateX((CFURLRef)_fileURL, _password);
if (_PDFDocRef != NULL) // Check for non-NULL CGPDFDocumentRef
{
if (page < 1) page = 1; // Check the lower page bounds
NSInteger count = CGPDFDocumentGetNumberOfPages(_PDFDocRef);
if (page > count) page = count; // Check the upper page bounds
_PDFPageRef = CGPDFDocumentGetPage(_PDFDocRef, page);
if (_PDFPageRef != NULL) // Check for non-NULL CGPDFPageRef
{
CGPDFPageRetain(_PDFPageRef); // Retain the PDF page
_currentPage = page; // Set the current page number
_pageCount = count; // Set the total page count
}
else // Error out with a diagnostic
{
CGPDFDocumentRelease(_PDFDocRef), _PDFDocRef = NULL;
NSAssert(NO, @"CGPDFPageRef == NULL");
}
}
else // Error out with a diagnostic
{
NSAssert(NO, @"CGPDFDocumentRef == NULL");
}
}
else // Error out with a diagnostic
{
NSAssert(NO, @"fileURL == nil");
}
}
return self;
}
- (BOOL)changeFileURL:(NSURL *)fileURL page:(NSInteger)page password:(NSString *)password
{
BOOL status = NO; // Default flag
if (fileURL != nil) // Check for non-nil file URL
{
CGPDFPageRef newPDFPageRef = NULL;
CGPDFDocumentRef newPDFDocRef = NULL;
newPDFDocRef = CGPDFDocumentCreateX((CFURLRef)fileURL, password);
if (newPDFDocRef != NULL) // Check for non-NULL CGPDFDocumentRef
{
if (page < 1) page = 1; // Check the lower page bounds
NSInteger count = CGPDFDocumentGetNumberOfPages(newPDFDocRef);
if (page > count) page = count; // Check the upper page bounds
newPDFPageRef = CGPDFDocumentGetPage(newPDFDocRef, page);
if (newPDFPageRef != NULL) // Check for non-NULL CGPDFPageRef
{
CGPDFPageRetain(newPDFPageRef); // Retain the PDF page
@synchronized(self) // Block the CATiledLayer thread
{
CGPDFPageRelease(_PDFPageRef); _PDFPageRef = newPDFPageRef;
CGPDFDocumentRelease(_PDFDocRef); _PDFDocRef = newPDFDocRef;
self.layer.contents = nil; // Clear CATiledLayer tile cache
[self.layer setNeedsDisplay]; // Flag the layer for redraw
}
[_password release]; _password = [password copy]; // Keep a copy
[_fileURL release]; _fileURL = [fileURL copy]; // Keep a copy
_currentPage = page; // Set the current page number
_pageCount = count; // Set the total page count
status = YES; // Happiness is success
}
else // Error out with a diagnostic
{
CGPDFDocumentRelease(newPDFDocRef), newPDFDocRef = NULL;
NSAssert(NO, @"CGPDFPageRef == NULL");
}
}
else // Error out with a diagnostic
{
NSAssert(NO, @"CGPDFDocumentRef == NULL");
}
}
else // Error out with a diagnostic
{
NSAssert(NO, @"fileURL == nil");
}
return status;
}
- (void)gotoPage:(NSInteger)page
{
if (_PDFDocRef != NULL)
{
if (page < 1) // Check lower page bounds
page = 1;
else
if (page > _pageCount) // Check upper page bounds
page = _pageCount;
if (page != _currentPage) // Only if page numbers differ
{
_currentPage = 0; // Clear the current page number
@synchronized(self) // Block CATiledLayer thread
{
CGPDFPageRelease(_PDFPageRef), _PDFPageRef = NULL;
CGPDFDocumentRelease(_PDFDocRef), _PDFDocRef = NULL;
_PDFDocRef = CGPDFDocumentCreateX((CFURLRef)_fileURL, _password);
if (_PDFDocRef != NULL) // Check for non-NULL CGPDFDocumentRef
{
_PDFPageRef = CGPDFDocumentGetPage(_PDFDocRef, page);
if (_PDFPageRef != NULL) // Check for non-NULL CGPDFPageRef
{
CGPDFPageRetain(_PDFPageRef); // Retain the PDF page
//self.layer.contents = nil; // Clear CATiledLayer tile cache
[self.layer setNeedsDisplay]; // Flag the layer for redraw
_currentPage = page; // Set the current page number
}
else // Error out with a diagnostic
{
CGPDFDocumentRelease(_PDFDocRef), _PDFDocRef = NULL;
NSAssert(NO, @"CGPDFPageRef == NULL");
}
}
else // Error out with a diagnostic
{
NSAssert(NO, @"CGPDFDocumentRef == NULL");
}
}
}
}
}
- (CGSize)currentPageSize
{
CGSize pageSize = CGSizeZero; // Error default size
if (_PDFDocRef != NULL) // Check for non-NULL CGPDFDocumentRef
{
CGRect cropBoxRect = CGPDFPageGetBoxRect(_PDFPageRef, kCGPDFCropBox);
CGRect mediaBoxRect = CGPDFPageGetBoxRect(_PDFPageRef, kCGPDFMediaBox);
CGRect effectiveRect = CGRectIntersection(cropBoxRect, mediaBoxRect);
NSInteger degrees = CGPDFPageGetRotationAngle(_PDFPageRef);
if (degrees == 0) // Check for page rotation
{
pageSize = effectiveRect.size;
}
else // Rotate the effective rect so many degrees
{
CGFloat radians = (degrees * M_PI / 180.0);
CGAffineTransform rotation = CGAffineTransformMakeRotation(radians);
CGRect rotatedRect = CGRectApplyAffineTransform(effectiveRect, rotation);
pageSize = rotatedRect.size;
}
}
return pageSize;
}
- (void)decrementPage
{
if (_PDFDocRef != NULL)
{
[self gotoPage:(_currentPage - 1)];
}
}
- (void)incrementPage
{
if (_PDFDocRef != NULL)
{
[self gotoPage:(_currentPage + 1)];
}
}
- (void)dealloc
{
@synchronized(self) // Block any other threads
{
CGPDFPageRelease(_PDFPageRef), _PDFPageRef = NULL;
CGPDFDocumentRelease(_PDFDocRef), _PDFDocRef = NULL;
}
[_fileURL release]; [_password release];
[super dealloc];
}
#pragma mark CATiledLayer delegate methods
- (void)drawLayer:(CATiledLayer *)layer inContext:(CGContextRef)context
{
CGPDFPageRef drawPDFPageRef = NULL;
CGPDFDocumentRef drawPDFDocRef = NULL;
@synchronized(self) // Block any other threads
{
drawPDFDocRef = CGPDFDocumentRetain(_PDFDocRef);
drawPDFPageRef = CGPDFPageRetain(_PDFPageRef);
}
CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // White
CGContextFillRect(context, CGContextGetClipBoundingBox(context));
if (drawPDFPageRef != NULL) // Render the page into the context
{
CGFloat boundsHeight = self.bounds.size.height;
if (CGPDFPageGetRotationAngle(drawPDFPageRef) == 0)
{
CGFloat boundsWidth = self.bounds.size.width; // View width
CGRect cropBoxRect = CGPDFPageGetBoxRect(drawPDFPageRef, kCGPDFCropBox);
CGRect mediaBoxRect = CGPDFPageGetBoxRect(drawPDFPageRef, kCGPDFMediaBox);
CGRect effectiveRect = CGRectIntersection(cropBoxRect, mediaBoxRect);
CGFloat effectiveWidth = effectiveRect.size.width;
CGFloat effectiveHeight = effectiveRect.size.height;
CGFloat widthScale = (boundsWidth / effectiveWidth);
CGFloat heightScale = (boundsHeight / effectiveHeight);
CGFloat scale = (widthScale < heightScale) ? widthScale : heightScale;
CGFloat x_offset = ((boundsWidth - (effectiveWidth * scale)) / 2.0f);
CGFloat y_offset = ((boundsHeight - (effectiveHeight * scale)) / 2.0f);
y_offset = (boundsHeight - y_offset); // Co-ordinate system adjust
CGFloat x_translate = (x_offset - effectiveRect.origin.x);
CGFloat y_translate = (y_offset + effectiveRect.origin.y);
CGContextTranslateCTM(context, x_translate, y_translate);
CGContextScaleCTM(context, scale, -scale); // Mirror Y
}
else // Use CGPDFPageGetDrawingTransform for pages with rotation (AKA kludge)
{
CGContextTranslateCTM(context, 0.0f, boundsHeight); CGContextScaleCTM(context, 1.0f, -1.0f);
CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(drawPDFPageRef, kCGPDFCropBox, self.bounds, 0, true));
}
CGContextDrawPDFPage(context, drawPDFPageRef);
}
CGPDFPageRelease(drawPDFPageRef); // Cleanup
CGPDFDocumentRelease(drawPDFDocRef);
}
@end