PDFPageEditViewController.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. //
  2. // PDFPageEditViewController.m
  3. // PDFReader
  4. //
  5. // Copyright © 2014-2022 PDF Technologies, Inc. All Rights Reserved.
  6. //
  7. // The PDF Reader Sample applications are licensed with a modified BSD license.
  8. // Please see License for details. This notice may not be removed from this file.
  9. //
  10. #import "PDFPageEditViewController.h"
  11. #import "PDFPageEditCell.h"
  12. #import <MessageUI/MFMailComposeViewController.h>
  13. #import "PDFPageEditAddViewController.h"
  14. @interface PDFPageEditViewController () <UICollectionViewDelegate,UICollectionViewDataSource>
  15. @property (nonatomic,assign) IBOutlet UICollectionView *collectionView;
  16. @property (nonatomic,assign) IBOutlet UIToolbar *toolbar;
  17. @property (nonatomic,retain) NSMutableArray *pages;
  18. @end
  19. @implementation PDFPageEditViewController
  20. #pragma mark - Init Methods
  21. - (instancetype)init {
  22. if (self = [super init]) {
  23. }
  24. return self;
  25. }
  26. - (void)dealloc {
  27. [_pages release];
  28. [super dealloc];
  29. }
  30. #pragma mark - UIViewController Methods
  31. - (void)viewDidLoad {
  32. [super viewDidLoad];
  33. // Do any additional setup after loading the view.
  34. [self setEditing:NO animated:NO];
  35. self.pages = [NSMutableArray array];
  36. NSURL *documentURL = [self.pdfViewController.pdfView.document documentURL];
  37. CGPDFDocumentRef documentRef = CGPDFDocumentCreateWithURL((CFURLRef)documentURL);
  38. if ([self.pdfViewController.pdfView.document password]) {
  39. CGPDFDocumentUnlockWithPassword(documentRef, [[self.pdfViewController.pdfView.document password] UTF8String]);
  40. }
  41. NSInteger pagesCount = CGPDFDocumentGetNumberOfPages(documentRef);
  42. for (int i = 0; i < pagesCount; i++) {
  43. CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, i+1);
  44. PDFEditPage *page = [[PDFEditPage alloc] initWithPageRef:pageRef];
  45. [self.pages addObject:page];
  46. [page release];
  47. }
  48. CGPDFDocumentRelease(documentRef);
  49. [self.collectionView registerClass:[PDFPageEditCell class] forCellWithReuseIdentifier:@"PDFPageEditCell"];
  50. self.collectionView.alwaysBounceVertical = YES;
  51. UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)];
  52. [self.collectionView addGestureRecognizer:longGesture];
  53. [longGesture release];
  54. }
  55. - (void)viewWillAppear:(BOOL)animated {
  56. [super viewWillAppear:animated];
  57. NSInteger pageIndex = [self.pdfViewController.pdfView currentPageIndex];
  58. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:pageIndex inSection:0];
  59. [self.collectionView selectItemAtIndexPath:indexPath
  60. animated:NO
  61. scrollPosition:UICollectionViewScrollPositionCenteredVertically];
  62. }
  63. - (void)viewDidAppear:(BOOL)animated {
  64. [super viewDidAppear:animated];
  65. NSInteger pageIndex = [self.pdfViewController.pdfView currentPageIndex];
  66. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:pageIndex inSection:0];
  67. [self.collectionView scrollToItemAtIndexPath:indexPath
  68. atScrollPosition:UICollectionViewScrollPositionCenteredVertically
  69. animated:YES];
  70. }
  71. - (void)updateTitle {
  72. if (self.isEditing) {
  73. NSInteger count = [self.collectionView indexPathsForSelectedItems].count;
  74. self.title = [NSString stringWithFormat:@"%@ %ld",NSLocalizedString(@"Selected:", nil), (long)count];
  75. } else {
  76. self.title = nil;
  77. }
  78. }
  79. - (void)reloadDataVisibleCells {
  80. for (PDFPageEditCell *cell in [self.collectionView visibleCells]) {
  81. NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
  82. cell.textLabel.text = [NSString stringWithFormat:@"%@",@(indexPath.item+1)];
  83. }
  84. }
  85. #pragma mark - Button Actions
  86. - (void)setEditing:(BOOL)editing animated:(BOOL)animated {
  87. [super setEditing:editing animated:animated];
  88. if (editing) {
  89. self.collectionView.allowsMultipleSelection = YES;
  90. UIBarButtonItem *selectAllItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"selectall.png"] style:UIBarButtonItemStylePlain target:self action:@selector(buttonItemClicked_SelectAll:)];
  91. if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
  92. NSMutableArray *items = [NSMutableArray array];
  93. [self.toolbar.items enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(UIBarButtonItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  94. if (obj.target) {
  95. [items addObject:obj];
  96. }
  97. }];
  98. [items addObject:selectAllItem];
  99. [self.navigationItem setRightBarButtonItems:items animated:animated];
  100. } else {
  101. [UIView animateWithDuration:animated ? 0.3 : 0.0 animations:^{
  102. self.toolbar.alpha = 1.0;
  103. }];
  104. [self.navigationItem setLeftBarButtonItems:@[selectAllItem] animated:animated];
  105. UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(buttonItemClicked_Done:)];
  106. [self.navigationItem setRightBarButtonItems:@[doneItem] animated:animated];
  107. [doneItem release];
  108. }
  109. [selectAllItem release];
  110. } else {
  111. self.collectionView.allowsMultipleSelection = NO;
  112. [UIView animateWithDuration:animated ? 0.3 : 0.0 animations:^{
  113. self.toolbar.alpha = 0.0;
  114. }];
  115. UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(buttonItemClicked_Done:)];
  116. [self.navigationItem setLeftBarButtonItems:@[doneItem] animated:animated];
  117. [doneItem release];
  118. UIBarButtonItem *editItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(buttonItemClicked_Edit:)];
  119. [self.navigationItem setRightBarButtonItems:@[editItem] animated:animated];
  120. [editItem release];
  121. }
  122. [self updateTitle];
  123. }
  124. - (void)buttonItemClicked_Done:(id)sender {
  125. if (self.isEditing) {
  126. [self setEditing:NO animated:YES];
  127. } else {
  128. [self dismissViewControllerAnimated:YES completion:^{
  129. [self.pdfViewController.pdfView.document writeToURL:self.pdfViewController.pdfView.document.documentURL];
  130. [self.pdfViewController loadDocumentWithFilePath:self.pdfViewController.filePath completion:nil];
  131. }];
  132. }
  133. }
  134. - (void)buttonItemClicked_Edit:(id)sender {
  135. [self setEditing:YES animated:YES];
  136. }
  137. - (void)buttonItemClicked_SelectAll:(id)sender {
  138. BOOL isSelectAll = NO;
  139. if ([self.collectionView indexPathsForSelectedItems].count != [self.collectionView numberOfItemsInSection:0]) {
  140. isSelectAll = YES;
  141. }
  142. for (int i=0; i<[self.collectionView numberOfItemsInSection:0]; i++) {
  143. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
  144. if (isSelectAll) {
  145. [self.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone];
  146. } else {
  147. [self.collectionView deselectItemAtIndexPath:indexPath animated:YES];
  148. }
  149. }
  150. [self updateTitle];
  151. }
  152. - (IBAction)buttonItemClicked_Add:(id)sender {
  153. PDFPageEditAddViewController *vc = [[PDFPageEditAddViewController alloc] init];
  154. vc.callback = ^(PDFEditPage *page) {
  155. NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.pdfViewController.pdfView.currentPageIndex+1
  156. inSection:0];
  157. [self.pages insertObject:page atIndex:indexPath.item];
  158. [self.collectionView insertItemsAtIndexPaths:@[indexPath]];
  159. if (page.imagePath) {
  160. [self.pdfViewController.pdfView.document insertPage:page.size withImage:page.imagePath atIndex:indexPath.item];
  161. } else {
  162. [self.pdfViewController.pdfView.document insertPage:page.size atIndex:indexPath.item];
  163. }
  164. [self reloadDataVisibleCells];
  165. };
  166. [vc showViewController:self inBarButtonItem:sender];
  167. [vc release];
  168. }
  169. - (IBAction)buttonItemClicked_Extract:(id)sender {
  170. NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
  171. NSString *fileName = self.pdfViewController.pdfView.document.documentURL.lastPathComponent.stringByDeletingPathExtension;
  172. NSString *filePath = [NSString stringWithFormat:@"%@/%@_Pages.pdf",path,fileName];
  173. NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
  174. for (NSIndexPath *indexPath in [self.collectionView indexPathsForSelectedItems]) {
  175. [indexSet addIndex:indexPath.item];
  176. }
  177. CPDFDocument *document = [[[CPDFDocument alloc] init] autorelease];
  178. [document importPages:indexSet fromDocument:self.pdfViewController.pdfView.document atIndex:0];
  179. [document writeToURL:[NSURL fileURLWithPath:filePath]];
  180. NSString *message = [NSString stringWithFormat:NSLocalizedString(@"This file has been saved in:'Documents/'", nil)];
  181. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
  182. style:UIAlertActionStyleCancel
  183. handler:nil];
  184. UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Successfully!", nil)
  185. message:message
  186. preferredStyle:UIAlertControllerStyleAlert];
  187. [alert addAction:cancelAction];
  188. [self presentViewController:alert animated:YES completion:nil];
  189. }
  190. - (IBAction)buttonItemClicked_Rotate:(id)sender {
  191. NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
  192. for (NSIndexPath *indexPath in [self.collectionView indexPathsForSelectedItems]) {
  193. PDFPageEditCell *cell = (PDFPageEditCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
  194. PDFEditPage *page = [self.pages objectAtIndex:indexPath.item];
  195. page.rotation += 90;
  196. if (page.rotation == 360) {
  197. page.rotation = 0;
  198. }
  199. cell.page = page;
  200. [indexSet addIndex:indexPath.item];
  201. CPDFPage *pPage = [self.pdfViewController.pdfView.document pageAtIndex:indexPath.item];
  202. pPage.rotation += 90;
  203. }
  204. }
  205. - (IBAction)buttonItemClicked_Mail:(id)sender {
  206. NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
  207. NSString *fileName = self.pdfViewController.pdfView.document.documentURL.lastPathComponent.stringByDeletingPathExtension;
  208. NSString *filePath = [NSString stringWithFormat:@"%@/%@_Pages.pdf",path,fileName];
  209. NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
  210. for (NSIndexPath *indexPath in [self.collectionView indexPathsForSelectedItems]) {
  211. [indexSet addIndex:indexPath.item];
  212. }
  213. CPDFDocument *document = [[[CPDFDocument alloc] init] autorelease];
  214. [document importPages:indexSet fromDocument:self.pdfViewController.pdfView.document atIndex:0];
  215. [document writeToURL:[NSURL fileURLWithPath:filePath]];
  216. MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
  217. vc.mailComposeDelegate = (id)self;
  218. [vc addAttachmentData:[NSData dataWithContentsOfFile:filePath]
  219. mimeType:[NSString stringWithFormat:@"application/%@",[filePath pathExtension]]
  220. fileName:[filePath lastPathComponent]];
  221. [self presentViewController:vc animated:YES completion:nil];
  222. [vc release];
  223. }
  224. - (IBAction)buttonItemClicked_Delete:(id)sender {
  225. NSInteger selectedCount = [self.collectionView indexPathsForSelectedItems].count;
  226. NSInteger totalCount = [self.collectionView numberOfItemsInSection:0];
  227. if (selectedCount == totalCount) {
  228. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
  229. style:UIAlertActionStyleCancel
  230. handler:nil];
  231. UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Warning", nil)
  232. message:NSLocalizedString(@"Can not delete all pages.", nil)
  233. preferredStyle:UIAlertControllerStyleAlert];
  234. [alert addAction:cancelAction];
  235. [self presentViewController:alert animated:YES completion:nil];
  236. return;
  237. }
  238. NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
  239. for (NSIndexPath *indexPath in [self.collectionView indexPathsForSelectedItems]) {
  240. [indexSet addIndex:indexPath.item];
  241. }
  242. [self.pages removeObjectsAtIndexes:indexSet];
  243. [self.collectionView deleteItemsAtIndexPaths:[self.collectionView indexPathsForSelectedItems]];
  244. [self.pdfViewController.pdfView.document removePageAtIndexSet:indexSet];
  245. [self reloadDataVisibleCells];
  246. }
  247. #pragma mark - UICollectionViewDelegateFlowLayout
  248. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
  249. NSInteger count = 4;
  250. UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)collectionViewLayout;
  251. CGFloat width = MIN(self.view.bounds.size.width, self.view.bounds.size.height);
  252. width -= (count-1)*flowLayout.minimumInteritemSpacing;
  253. width -= flowLayout.sectionInset.left;
  254. width -= flowLayout.sectionInset.right;
  255. width /= count;
  256. return CGSizeMake(width, width+18);
  257. }
  258. #pragma mark - UICollectionViewDataSource
  259. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  260. return self.pages.count;
  261. }
  262. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  263. PDFPageEditCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PDFPageEditCell" forIndexPath:indexPath];
  264. cell.backgroundColor = [UIColor clearColor];
  265. cell.page = self.pages[indexPath.item];
  266. cell.textLabel.text = [NSString stringWithFormat:@"%@",@(indexPath.item+1)];
  267. return cell;
  268. }
  269. #pragma mark - UICollectionViewDelegate
  270. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  271. [self updateTitle];
  272. if (!self.isEditing) {
  273. [self dismissViewControllerAnimated:YES completion:^{
  274. [self.pdfViewController.pdfView.document writeToURL:self.pdfViewController.pdfView.document.documentURL];
  275. [self.pdfViewController loadDocumentWithFilePath:self.pdfViewController.filePath completion:^(BOOL result) {
  276. if (result) {
  277. [self.pdfViewController.pdfView goToPageIndex:indexPath.item animated:NO];
  278. }
  279. }];
  280. }];
  281. }
  282. }
  283. - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
  284. [self updateTitle];
  285. }
  286. #pragma mark - UICollectionView Draggable
  287. - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath {
  288. return YES;
  289. }
  290. - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath {
  291. if (sourceIndexPath.item != destinationIndexPath.item) {
  292. CPDFPage *page = [[self.pages objectAtIndex:sourceIndexPath.item] retain];
  293. [self.pages removeObject:page];
  294. [self.pages insertObject:page atIndex:destinationIndexPath.item];
  295. [page release];
  296. [self.pdfViewController.pdfView.document movePageAtIndex:sourceIndexPath.item withPageAtIndex:destinationIndexPath.item];
  297. [self reloadDataVisibleCells];
  298. }
  299. }
  300. - (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture {
  301. switch (longGesture.state) {
  302. case UIGestureRecognizerStateBegan:
  303. {
  304. NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[longGesture locationInView:self.collectionView]];
  305. if (indexPath == nil) {
  306. break;
  307. }
  308. [self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath];
  309. [UIView animateWithDuration:0.2 animations:^{
  310. [self.collectionView updateInteractiveMovementTargetPosition:[longGesture locationInView:self.collectionView]];
  311. }];
  312. }
  313. break;
  314. case UIGestureRecognizerStateChanged:
  315. {
  316. [self.collectionView updateInteractiveMovementTargetPosition:[longGesture locationInView:self.collectionView]];
  317. }
  318. break;
  319. case UIGestureRecognizerStateEnded:
  320. {
  321. [self.collectionView endInteractiveMovement];
  322. }
  323. break;
  324. default:
  325. {
  326. [self.collectionView cancelInteractiveMovement];
  327. }
  328. break;
  329. }
  330. }
  331. #pragma mark - MFMailComposeViewControllerDelegate
  332. - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(nullable NSError *)error {
  333. [controller dismissViewControllerAnimated:YES completion:nil];
  334. }
  335. @end