Browse Source

Merge branch 'ios' of git.kdan.cc:Others/kmpdfkit_demo into ios

# Conflicts:
#	PDFViewer.xcodeproj/project.pbxproj
#	PDFViewer.xcodeproj/project.xcworkspace/xcuserdata/kdan.xcuserdatad/UserInterfaceState.xcuserstate
#	PDFViewer.xcodeproj/project.xcworkspace/xcuserdata/kdanmobile_2.xcuserdatad/UserInterfaceState.xcuserstate
#	PDFViewer.xcodeproj/xcuserdata/kdanmobile_2.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
#	PDFViewer/Controller/CPDFListController.m
#	PDFViewer/Controller/CPDFViewController.m
yangliuhua 2 years ago
parent
commit
2ce7368cbe
38 changed files with 3241 additions and 0 deletions
  1. 48 0
      PDFViewer.xcodeproj/project.pbxproj
  2. BIN
      PDFViewer.xcodeproj/project.xcworkspace/xcuserdata/kdanmobile_2.xcuserdatad/UserInterfaceState.xcuserstate
  3. 36 0
      PDFViewer/Controller/CPDFAddWaterMarkViewController.h
  4. 378 0
      PDFViewer/Controller/CPDFAddWaterMarkViewController.m
  5. 31 0
      PDFViewer/Controller/CPDFBackgroundSettingViewController.h
  6. 417 0
      PDFViewer/Controller/CPDFBackgroundSettingViewController.m
  7. 33 0
      PDFViewer/Controller/CPDFImageViewController.h
  8. 437 0
      PDFViewer/Controller/CPDFImageViewController.m
  9. 32 0
      PDFViewer/Controller/CPDFTextViewController.h
  10. 397 0
      PDFViewer/Controller/CPDFTextViewController.m
  11. 1 0
      PDFViewer/Controller/CPDFViewController.h
  12. 20 0
      PDFViewer/View/CPDFBackgroundPreview.h
  13. 43 0
      PDFViewer/View/CPDFBackgroundPreview.m
  14. 32 0
      PDFViewer/View/CPDFBackgroundSettingView.h
  15. 163 0
      PDFViewer/View/CPDFBackgroundSettingView.m
  16. 22 0
      PDFViewer/View/CPDFBackgroundView.h
  17. 93 0
      PDFViewer/View/CPDFBackgroundView.m
  18. 27 0
      PDFViewer/View/CPDFClipView.h
  19. 30 0
      PDFViewer/View/CPDFClipView.m
  20. 19 0
      PDFViewer/View/CPDFDrawBackgroundView.h
  21. 55 0
      PDFViewer/View/CPDFDrawBackgroundView.m
  22. 18 0
      PDFViewer/View/CPDFDrawImageView.h
  23. 76 0
      PDFViewer/View/CPDFDrawImageView.m
  24. 23 0
      PDFViewer/View/CPDFDrawView.h
  25. 115 0
      PDFViewer/View/CPDFDrawView.m
  26. 18 0
      PDFViewer/View/CPDFEditView.h
  27. 33 0
      PDFViewer/View/CPDFEditView.m
  28. 21 0
      PDFViewer/View/CPDFImagePreview.h
  29. 59 0
      PDFViewer/View/CPDFImagePreview.m
  30. 35 0
      PDFViewer/View/CPDFImageView.h
  31. 156 0
      PDFViewer/View/CPDFImageView.m
  32. 20 0
      PDFViewer/View/CPDFTextPreview.h
  33. 66 0
      PDFViewer/View/CPDFTextPreview.m
  34. 37 0
      PDFViewer/View/CPDFTextView.h
  35. 178 0
      PDFViewer/View/CPDFTextView.m
  36. 21 0
      PDFViewer/View/UIImage+TintColor.h
  37. 51 0
      PDFViewer/View/UIImage+TintColor.m
  38. BIN
      PDFViewer/View/sources/btn_selected.png

+ 48 - 0
PDFViewer.xcodeproj/project.pbxproj

@@ -363,6 +363,12 @@
 				C92BA19929651CA3009954EF /* CPDFBackgroundModel.m */,
 				C95FE7452966F3700038BBF3 /* CPDFHeaderFooterModel.h */,
 				C95FE7462966F37F0038BBF3 /* CPDFHeaderFooterModel.m */,
+				C993B916292B5BC500D8F474 /* CPDFHeaderFooterModel.h */,
+				C993B917292B5BC500D8F474 /* CPDFHeaderFooterModel.m */,
+                    ECD0AC30292B56C90091B6EB /* CPDFDataModel.h */,
+                ECD0AC31292B56C90091B6EB /* CPDFDataModel.m */,
+                C92BA19829651CA3009954EF /* CPDFBackgroundModel.h */,
+                C92BA19929651CA3009954EF /* CPDFBackgroundModel.m */,
 			);
 			path = Model;
 			sourceTree = "<group>";
@@ -378,6 +384,21 @@
 				C97A78822967AF980012BA91 /* Watermark */,
 				C97A787E2967AEB00012BA91 /* Background */,
 				C97A786F2967AC000012BA91 /* HeaderFooter */,
+				C96D13942924DD7E00CC92C7 /* CPDFHeaderFooterAddController.h */,
+				C96D13952924DD7E00CC92C7 /* CPDFHeaderFooterAddController.m */,
+				C993B90A29271FCA00D8F474 /* CPDFBatesAddViewController.h */,
+				C993B90B29271FCA00D8F474 /* CPDFBatesAddViewController.m */,
+				C9B7639B2940B71600D25041 /* CPDFAddViewController.h */,
+				C9B7639C2940B71600D25041 /* CPDFAddViewController.m */,
+				C9B763A22941808500D25041 /* CPDFAddViewControllerHeader.h */,
+                    ECD0AC212928F2A70091B6EB /* CPDFTextViewController.h */,
+                ECD0AC222928F2A70091B6EB /* CPDFTextViewController.m */,
+                ECD0AC242928F2E50091B6EB /* CPDFImageViewController.h */,
+                ECD0AC252928F2E50091B6EB /* CPDFImageViewController.m */,
+                C9638494294ACC240055CCCA /* CPDFAddViewController.h */,
+                C9638495294ACC240055CCCA /* CPDFAddViewController.m */,
+                C986D3F32962857900EBD4DF /* CPDFBackgroundSettingViewController.h */,
+                C986D3F42962857900EBD4DF /* CPDFBackgroundSettingViewController.m */,
 			);
 			path = Controller;
 			sourceTree = "<group>";
@@ -389,6 +410,33 @@
 				C95FE7772966F70B0038BBF3 /* BackgroundView */,
 				C95FE7762966F6AF0038BBF3 /* WatermarkView */,
 				C95FE7752966F65F0038BBF3 /* HeaderFooterView */,
+				ECD0AC1E2928EF030091B6EB /* sources */,
+				ECD0ABED2928ED9A0091B6EB /* CPDFImageView.h */,
+				ECD0ABE82928ED990091B6EB /* CPDFImageView.m */,
+				ECD0ABEB2928ED9A0091B6EB /* CPDFImagePreview.h */,
+				ECD0ABEC2928ED9A0091B6EB /* CPDFImagePreview.m */,
+				ECD0ABEF2928ED9A0091B6EB /* CPDFTextPreview.h */,
+				ECD0ABE52928ED990091B6EB /* CPDFTextPreview.m */,
+				ECD0ABE92928ED990091B6EB /* CPDFTextView.h */,
+				ECD0ABEA2928ED990091B6EB /* CPDFTextView.m */,
+				C96150D0295400B00020F445 /* CPDFDrawView.h */,
+				C96150D1295400B00020F445 /* CPDFDrawView.m */,
+				C96150D329554F660020F445 /* CPDFClipView.h */,
+				C96150D429554F660020F445 /* CPDFClipView.m */,
+				C97E91662959B96C007F6943 /* CPDFEditView.h */,
+				C97E91672959B96C007F6943 /* CPDFEditView.m */,
+				C986D3F6296288C400EBD4DF /* CPDFBackgroundPreview.h */,
+				C986D3F7296288C400EBD4DF /* CPDFBackgroundPreview.m */,
+				C986D3F9296288F700EBD4DF /* CPDFBackgroundView.h */,
+				C986D3FA296288F700EBD4DF /* CPDFBackgroundView.m */,
+				C986D3FC2962A70400EBD4DF /* CPDFBackgroundSettingView.h */,
+				C986D3FD2962A70400EBD4DF /* CPDFBackgroundSettingView.m */,
+				C92BA1922963F806009954EF /* CPDFDrawBackgroundView.h */,
+				C92BA1932963F806009954EF /* CPDFDrawBackgroundView.m */,
+				C92BA1952963F84B009954EF /* CPDFDrawImageView.h */,
+				C92BA1962963F84B009954EF /* CPDFDrawImageView.m */,
+				C92BA18F2963CAB4009954EF /* UIImage+TintColor.h */,
+				C92BA1902963CAB4009954EF /* UIImage+TintColor.m */,
 			);
 			path = View;
 			sourceTree = "<group>";

BIN
PDFViewer.xcodeproj/project.xcworkspace/xcuserdata/kdanmobile_2.xcuserdatad/UserInterfaceState.xcuserstate


+ 36 - 0
PDFViewer/Controller/CPDFAddWaterMarkViewController.h

@@ -0,0 +1,36 @@
+//
+//  CPDFAddViewController.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2022/12/15.
+//  Alter cause : code standards
+
+#import <UIKit/UIKit.h>
+#import <ComPDFKit/ComPDFKit.h>
+#import "CPDFDataModel.h"
+#import "CPDFTextViewController.h"
+#import "CPDFImageViewController.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol WaterMarkModelDataDelegate <NSObject>
+
+- (void)changeTextModel:(CPDFDataModel *)dataModel;
+- (void)deleteTextModel:(CPDFWatermark *)waterMark;
+- (void)changeImageModel:(CPDFDataModel *)dataModel;
+
+@end
+
+@interface CPDFAddWaterMarkViewController : UIViewController
+
+@property (nonatomic,strong) UISegmentedControl *segmentedControl;
+@property (nonatomic,strong) id<WaterMarkModelDataDelegate> delegate;
+@property (nonatomic,strong) CPDFTextViewController *textViewController;
+@property (nonatomic,strong) CPDFImageViewController *imageViewController;
+@property (nonatomic,strong) CPDFDocument *document;
+
+- (instancetype)initWithDocument:(CPDFDocument *)document;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 378 - 0
PDFViewer/Controller/CPDFAddWaterMarkViewController.m

@@ -0,0 +1,378 @@
+//
+//  CPDFAddViewController.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2022/12/15.
+// 
+
+#import "CPDFAddWaterMarkViewController.h"
+#import <ComPDFKit/ComPDFKit.h>
+#import <ComPDFKit/CPDFWatermark.h>
+#import "CPDFViewController.h"
+#import "CPDFTextView.h"
+#import "CPDFTextPreview.h"
+#import "CPDFImageView.h"
+#import "CPDFImagePreview.h"
+#import "CPDFDataModel.h"
+#import "CPDFEditView.h"
+#import "Masonry.h"
+
+@interface CPDFAddWaterMarkViewController () <UITableViewDelegate,UITableViewDataSource>
+
+@property (nonatomic,assign) CGSize imageSize;
+@property (nonatomic,strong) UIImage *image;
+@property (nonatomic,strong) CPDFDataModel *dataModel;
+@property (nonatomic,strong) CPDFEditView *editView;
+@property (nonatomic,strong) NSMutableArray *dataArray;
+
+@end
+
+@implementation CPDFAddWaterMarkViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    
+    UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(onClickedDoneBtn)];
+    
+    UIBarButtonItem *editBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editClick)];
+    UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelClick)];
+    
+    self.navigationItem.rightBarButtonItems = @[doneBtn,editBtn,cancelBtn];
+    
+    [self createView];
+    [self addConstraint];
+}
+
+#pragma mark - Initializers
+
+- (instancetype)initWithDocument:(CPDFDocument *)document {
+    self = [super init];
+    if (self) {
+        _document = document;
+        
+        CPDFPage *pdfPage = [document pageAtIndex:0];
+        CGSize imageSize = [document pageSizeAtIndex:0];
+        _image = [pdfPage thumbnailOfSize:imageSize];
+        _imageSize = _image.size;
+    }
+    return self;
+}
+
+- (void)createView {
+    NSArray *segmentArray = @[@"Text",@"Image"];
+    _segmentedControl = [[UISegmentedControl alloc] initWithItems:segmentArray];
+    
+    [_segmentedControl addTarget:self action:@selector(segmentedAction:) forControlEvents:UIControlEventValueChanged];
+    
+    _segmentedControl.selectedSegmentIndex = 0;
+    
+    [_segmentedControl setBackgroundColor:[UIColor whiteColor]];
+    
+    _textViewController = [[CPDFTextViewController alloc] init];
+    _imageViewController = [[CPDFImageViewController alloc] init];
+    
+    [self addChildViewController:_textViewController];
+    [self addChildViewController:_imageViewController];
+    
+    [self.view addSubview:self.segmentedControl];
+    [self.view addSubview:_textViewController.view];
+    [self.view addSubview:_imageViewController.view];
+    
+    _editView = [[CPDFEditView alloc] init];
+    _editView.editTableView.dataSource = self;
+    _editView.editTableView.delegate = self;
+    
+    [self.view addSubview:_editView];
+    
+    _textViewController.textPreview.documentView.image = self.image;
+    _imageViewController.imagePreview.documentView.image = self.image;
+    _imageViewController.view.hidden = YES;
+}
+
+- (void)addConstraint {
+    
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown || (self.view.frame.size.width > self.view.frame.size.height)) {
+        [self addSideConstraint];
+    } else {
+        [self addNomalConstraint];
+    }
+}
+
+- (void)addSideConstraint {
+    [_segmentedControl mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.view.mas_top).offset(43.6);
+        make.width.equalTo(self.view.mas_width);
+        make.height.equalTo(@(self.view.bounds.size.height / 13));
+    }];
+    
+    [_textViewController.view mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(_segmentedControl.mas_bottom).offset(0);
+        make.width.equalTo(_segmentedControl.mas_width);
+        make.bottom.equalTo(self.view).offset(-34);
+    }];
+    [_imageViewController.view mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(_segmentedControl.mas_bottom).offset(0);
+        make.width.equalTo(_segmentedControl.mas_width);
+        make.bottom.equalTo(self.view).offset(-34);
+    }];
+    
+    [_textViewController.textView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.view.mas_right).offset(-38);
+        make.height.equalTo(@205);
+        make.width.equalTo(@393);
+        make.bottom.equalTo(self.view.mas_bottom).offset(-74);
+    }];
+    [_textViewController.textPreview mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.segmentedControl.mas_bottom).offset(0);
+        make.right.equalTo(_textViewController.textView.mas_left).offset(-5);
+        make.left.equalTo(self.view.mas_left).offset(0);
+        make.bottom.equalTo(self.view.mas_bottom).offset(-34);
+    }];
+    
+    [_imageViewController.imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.view.mas_right).offset(-38);
+        make.height.equalTo(@205);
+        make.width.equalTo(@393);
+        make.bottom.equalTo(self.view.mas_bottom).offset(-74);
+    }];
+    [_imageViewController.imagePreview mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.segmentedControl.mas_bottom).offset(0);
+        make.right.equalTo(_imageViewController.imageView.mas_left).offset(-5);
+        make.left.equalTo(self.view.mas_left).offset(0);
+        make.bottom.equalTo(self.view.mas_bottom).offset(-34);
+    }];
+    
+    [_textViewController.textPreview.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.centerX.equalTo(_textViewController.textPreview.mas_centerX);
+        make.centerY.equalTo(_textViewController.textPreview.mas_centerY);
+        make.width.equalTo(@(_imageSize.width / 10));
+        make.height.equalTo(@(_imageSize.height / 10));
+    }];
+    [_imageViewController.imagePreview.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.centerX.equalTo(_imageViewController.imagePreview.mas_centerX);
+        make.centerY.equalTo(_imageViewController.imagePreview.mas_centerY);
+        make.width.equalTo(@(_imageSize.width / 10));
+        make.height.equalTo(@(_imageSize.height / 10));
+    }];
+}
+
+- (void)addNomalConstraint {
+    [_segmentedControl mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.view.mas_top).offset(83.6);
+        make.width.equalTo(self.view.mas_width);
+        make.height.equalTo(@(self.view.bounds.size.height / 20));
+    }];
+    
+    [_textViewController.view mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(_segmentedControl.mas_bottom).offset(0);
+        make.width.equalTo(_segmentedControl.mas_width);
+        make.bottom.equalTo(self.view).offset(-34);
+    }];
+    [_imageViewController.view mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(_segmentedControl.mas_bottom).offset(0);
+        make.width.equalTo(_segmentedControl.mas_width);
+        make.bottom.equalTo(self.view).offset(-34);
+    }];
+    [_textViewController.textPreview.documentView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.centerX.equalTo(_textViewController.textPreview.mas_centerX);
+        make.centerY.equalTo(_textViewController.textPreview.mas_centerY);
+        make.width.equalTo(@(_imageSize.width / 8));
+        make.height.equalTo(@(_imageSize.height / 8));
+    }];
+    [_imageViewController.imagePreview.documentView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.centerX.equalTo(_imageViewController.imagePreview.mas_centerX);
+        make.centerY.equalTo(_imageViewController.imagePreview.mas_centerY);
+        make.width.equalTo(@(_imageSize.width / 8));
+        make.height.equalTo(@(_imageSize.height / 8));
+    }];
+}
+
+#pragma mark - Accessors
+
+- (NSArray *)dataArray {
+    if (!_dataArray) {
+        _dataArray = [NSMutableArray array];
+    
+        NSArray *waterArray = [_document watermarks];
+        
+        for (NSInteger i = 0; i < waterArray.count; i++) {
+            CPDFWatermark *dataWater = [[CPDFWatermark alloc] init];
+            dataWater = waterArray[i];
+            
+            [_dataArray addObject:dataWater];
+        }
+    }
+    
+    return _dataArray;
+}
+
+#pragma mark - UITableViewDataSource
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return self.dataArray.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    static NSString *path = @"AddWater";
+    
+    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:path];
+    
+    if (!cell) {
+        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:path];
+    }
+    
+    if ([self.dataArray[indexPath.row] text]) {
+        cell.textLabel.text = [self.dataArray[indexPath.row] text];
+    } else {
+        cell.imageView.image = [self.dataArray[indexPath.row] image];
+    }
+    
+    return cell;
+}
+
+#pragma mark - UITableViewDelegate
+
+- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return UITableViewCellEditingStyleDelete;
+}
+
+- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
+    if (editingStyle == UITableViewCellEditingStyleDelete) {
+        [self.delegate deleteTextModel:self.dataArray[indexPath.row]];
+        [self.dataArray removeObjectAtIndex:indexPath.row];
+        
+        [tableView beginUpdates];
+        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
+        [tableView endUpdates];
+    }
+}
+
+- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
+    CPDFWatermark *dataWater = _dataArray[sourceIndexPath.row];
+    [_dataArray removeObject:dataWater];
+    [_dataArray insertObject:dataWater atIndex:destinationIndexPath.row];
+}
+
+#pragma mark - Actons
+
+- (void)onClickedDoneBtn {
+    
+    self.navigationItem.rightBarButtonItem = nil;
+    
+    if (_segmentedControl.selectedSegmentIndex == 0) {
+    
+        _dataModel = self.textViewController.dataModel;
+        [self.delegate changeTextModel:self.dataModel];
+    } else {
+        
+        _dataModel = self.imageViewController.dataModel;
+        [self.delegate changeImageModel:self.dataModel];
+    }
+    
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (void)segmentedAction:(UISegmentedControl *)sender {
+    switch(sender.selectedSegmentIndex) {
+        case 0:
+            _textViewController.view.hidden = NO;
+            _imageViewController.view.hidden = YES;
+            break;
+        case 1:
+            _textViewController.view.hidden = YES;
+            _imageViewController.view.hidden = NO;
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)editClick {
+    if (self.editView.center.x < 50) {
+        [_editView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.left.equalTo(self.view.mas_left);
+            make.top.equalTo(self.textViewController.textPreview.mas_top);
+            make.bottom.equalTo(self.textViewController.textPreview.mas_bottom);
+            make.width.mas_equalTo(200);
+        }];
+        
+        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
+            self.editView.center = CGPointMake(self.editView.center.x + 200, self.editView.center.y);
+        } completion:nil];
+    }
+}
+
+- (void)cancelClick {
+    if (self.editView.center.x > 0) {
+        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
+            self.editView.center = CGPointMake(self.editView.center.x - 200, self.editView.center.y);
+        } completion:nil];
+    }
+}
+
+#pragma mark - Orientation
+
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight) {
+        
+        [_segmentedControl mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(43.6);
+            make.width.equalTo(self.view.mas_width);
+            make.height.equalTo(@(self.view.bounds.size.height / 24));
+        }];
+        
+        if (_imageSize.width > _imageSize.height) {
+            [_textViewController.textPreview.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.centerX.equalTo(_textViewController.textPreview.mas_centerX);
+                make.centerY.equalTo(_textViewController.textPreview.mas_centerY);
+                make.width.equalTo(@(_imageSize.width / 8));
+                make.height.equalTo(@(_imageSize.height / 8));
+            }];
+            [_imageViewController.imagePreview.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.centerX.equalTo(_imageViewController.imagePreview.mas_centerX);
+                make.centerY.equalTo(_imageViewController.imagePreview.mas_centerY);
+                make.width.equalTo(@(_imageSize.width / 8));
+                make.height.equalTo(@(_imageSize.height / 8));
+            }];
+        } else {
+            [_textViewController.textPreview.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.centerX.equalTo(_textViewController.textPreview.mas_centerX);
+                make.centerY.equalTo(_textViewController.textPreview.mas_centerY);
+                make.width.equalTo(@(_imageSize.width / 10));
+                make.height.equalTo(@(_imageSize.height / 10));
+            }];
+            [_imageViewController.imagePreview.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.centerX.equalTo(_imageViewController.imagePreview.mas_centerX);
+                make.centerY.equalTo(_imageViewController.imagePreview.mas_centerY);
+                make.width.equalTo(@(_imageSize.width / 10));
+                make.height.equalTo(@(_imageSize.height / 10));
+            }];
+        }
+        
+    } else if ([UIDevice currentDevice].orientation == UIDeviceOrientationPortrait) {
+        
+        [_segmentedControl mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(83.6);
+            make.width.equalTo(self.view.mas_width);
+            make.height.equalTo(@(852 / 20));
+        }];
+        
+        [_textViewController.textPreview.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.centerX.equalTo(_textViewController.textPreview.mas_centerX);
+            make.centerY.equalTo(_textViewController.textPreview.mas_centerY);
+            make.width.equalTo(@(_imageSize.width / 8));
+            make.height.equalTo(@(_imageSize.height / 8));
+        }];
+        [_imageViewController.imagePreview.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.centerX.equalTo(_imageViewController.imagePreview.mas_centerX);
+            make.centerY.equalTo(_imageViewController.imagePreview.mas_centerY);
+            make.width.equalTo(@(_imageSize.width / 8));
+            make.height.equalTo(@(_imageSize.height / 8));
+        }];
+    }
+}
+
+
+@end

+ 31 - 0
PDFViewer/Controller/CPDFBackgroundSettingViewController.h

@@ -0,0 +1,31 @@
+//
+//  CPDFBackgroundSettingViewController.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/2.
+//
+
+#import <UIKit/UIKit.h>
+#import <ComPDFKit/ComPDFKit.h>
+#import "CPDFBackgroundModel.h"
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol BackgroundDataModelDelegate <NSObject>
+
+- (void)changeBackgroundModel:(CPDFBackgroundModel *)dataModel;
+- (void)deleteBackgroundModel;
+
+@end
+
+@interface CPDFBackgroundSettingViewController : UIViewController
+
+@property (nonatomic,strong) CPDFDocument *document;
+@property (nonatomic,strong) id<BackgroundDataModelDelegate> delegate;
+
+- (instancetype)initWithDocument:(CPDFDocument *)document;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 417 - 0
PDFViewer/Controller/CPDFBackgroundSettingViewController.m

@@ -0,0 +1,417 @@
+//
+//  CPDFBackgroundSettingViewController.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/2.
+//
+
+#import "CPDFBackgroundSettingViewController.h"
+#import "CPDFBackgroundView.h"
+#import "CPDFBackgroundPreview.h"
+#import "CPDFBackgroundSettingView.h"
+#import "CPDFDrawBackgroundView.h"
+#import "CPDFDrawImageView.h"
+#import "Masonry.h"
+
+@interface CPDFBackgroundSettingViewController () <UIImagePickerControllerDelegate,UINavigationControllerDelegate,UITextFieldDelegate>
+
+@property (nonatomic,strong) CPDFBackgroundView *backgroundView;
+@property (nonatomic,strong) CPDFBackgroundPreview *backgroundPreView;
+@property (nonatomic,strong) CPDFBackgroundSettingView *backgroudSettingView;
+@property (nonatomic,strong) CPDFDrawImageView *drawImageView;
+@property (nonatomic,strong) CPDFDrawBackgroundView *drawBackgroundView;
+@property (nonatomic,strong) CPDFBackgroundModel *dataModel;
+@property (nonatomic,assign) CGSize imageSize;
+@property (nonatomic,strong) UIImage *image;
+
+@end
+
+@implementation CPDFBackgroundSettingViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    
+    UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(onClickedDoneBtn)];
+    
+    UIBarButtonItem *editBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editClick)];
+    
+    UIBarButtonItem *deleteBtn = [[UIBarButtonItem alloc] initWithTitle:@"Delete" style:UIBarButtonItemStylePlain target:self action:@selector(deleteClick)];
+    
+    self.navigationItem.rightBarButtonItems = @[doneBtn, editBtn, deleteBtn];
+     
+    [self initDataMoel];
+    [self createView];
+    [self addConstraint];
+    [self addTargets];
+}
+
+#pragma mark - Initializers
+
+- (instancetype)initWithDocument:(CPDFDocument *)document {
+    self = [super init];
+    if (self) {
+        _document = document;
+        
+        CPDFPage *pdfPage = [document pageAtIndex:0];
+        CGSize imageSize = [document pageSizeAtIndex:0];
+        _image = [pdfPage thumbnailOfSize:imageSize];
+        _imageSize = imageSize;
+    }
+    return self;
+}
+
+- (void)createView {
+    _backgroundView = [[CPDFBackgroundView alloc] init];
+    [self.view addSubview:_backgroundView];
+    
+    _backgroundPreView = [[CPDFBackgroundPreview alloc] init];
+    [self.view addSubview:_backgroundPreView];
+    
+    _backgroundPreView.documentView.image = self.image;
+    
+    _drawBackgroundView = [[CPDFDrawBackgroundView alloc] initWithFrame:CGRectMake(0, 40, 393, 598.333)];
+    _drawBackgroundView.dataModel = self.dataModel;
+    [self.backgroundPreView addSubview:_drawBackgroundView];
+    
+    _drawImageView      = [[CPDFDrawImageView alloc] initWithFrame:CGRectMake(0, 40, 393, 598.333)];
+    [_drawImageView setImage:_image];
+    [self.backgroundPreView addSubview:_drawImageView];
+}
+
+- (void)initDataMoel {
+    _dataModel = [[CPDFBackgroundModel alloc] init];
+    _dataModel.backgroundColor = [UIColor whiteColor];
+    _dataModel.backgroudScale = 1.0f;
+    _dataModel.backgroundOpacity = 1.0f;
+    _dataModel.backgroundRotation = 0.0f;
+    _dataModel.verticalSpacing = 0.0f;
+    _dataModel.horizontalSpacing = 0.0f;
+}
+
+- (void)addConstraint {
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown || (self.view.frame.size.width > self.view.frame.size.height)) {
+        [self addSideConstraint];
+    } else {
+        [self addNomalConstraint];
+    }
+}
+
+- (void)addSideConstraint {
+    [_backgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.bottom.equalTo(self.view.mas_bottom).offset(-25);
+        make.left.equalTo(self.view.mas_left);
+        make.right.equalTo(self.view.mas_right);
+        make.height.mas_equalTo(70);
+    }];
+    
+    [_backgroundPreView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.view.mas_top).offset(43.6);
+        make.left.equalTo(self.view.mas_left);
+        make.right.equalTo(self.view.mas_right);
+        make.bottom.equalTo(self.backgroundView.mas_top);
+    }];
+    
+    [_backgroundPreView.documentView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.view.mas_top).offset(43.6);
+        make.bottom.equalTo(self.backgroundPreView.mas_bottom);
+        make.centerX.equalTo(self.backgroundPreView.mas_centerX);
+        make.width.mas_equalTo(233);
+    }];
+    
+    [_drawBackgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.backgroundPreView.documentView.mas_top);
+        make.bottom.equalTo(self.backgroundPreView.documentView.mas_bottom);
+        make.left.equalTo(self.backgroundPreView.documentView.mas_left);
+        make.right.equalTo(self.backgroundPreView.documentView.mas_right);
+    }];
+    [_drawImageView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.backgroundPreView.documentView.mas_top);
+        make.bottom.equalTo(self.backgroundPreView.documentView.mas_bottom);
+        make.left.equalTo(self.backgroundPreView.documentView.mas_left);
+        make.right.equalTo(self.backgroundPreView.documentView.mas_right);
+    }];
+}
+
+- (void)addNomalConstraint {
+    [_backgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.bottom.equalTo(self.view.mas_bottom).offset(-25);
+        make.left.equalTo(self.view.mas_left);
+        make.right.equalTo(self.view.mas_right);
+        make.height.mas_equalTo(70);
+    }];
+    
+    [_backgroundPreView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.view.mas_top).offset(83.6);
+        make.left.equalTo(self.view.mas_left);
+        make.right.equalTo(self.view.mas_right);
+        make.bottom.equalTo(self.backgroundView.mas_top);
+    }];
+    
+    [_backgroundPreView.documentView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.equalTo(self.backgroundPreView.mas_left);
+        make.top.equalTo(self.backgroundPreView.mas_top).offset(40);
+        make.bottom.equalTo(self.backgroundPreView.mas_bottom).offset(-40);
+        make.width.mas_equalTo(393);
+    }];
+}
+
+- (void)addTargets {
+    [_backgroundView.selectBtn addTarget:self action:@selector(onSelectBtnClicked:) forControlEvents:UIControlEventTouchDown];
+    
+    for (NSInteger i = 0; i < _backgroundView.colorArray.count; ++i) {
+        [_backgroundView.colorArray[i] addTarget:self action:@selector(onColorBtnClicked:) forControlEvents:UIControlEventTouchDown];
+    }
+}
+
+#pragma mark - Actions
+
+- (void)onClickedDoneBtn {
+    [self.delegate changeBackgroundModel:self.dataModel];
+    
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (void)editClick {
+    self.backgroundView.selectBtn.enabled = NO;
+    self.navigationItem.rightBarButtonItems.firstObject.enabled = NO;
+    self.navigationItem.rightBarButtonItems.lastObject.enabled = NO;
+    
+    if (!([_backgroudSettingView isDescendantOfView:self.view])) {
+        _backgroudSettingView = [[CPDFBackgroundSettingView alloc] init];
+        
+        _backgroudSettingView.verticalField.delegate = self;
+        _backgroudSettingView.horizontalField.delegate = self;
+        
+        [self.view addSubview:_backgroudSettingView];
+        
+        [_backgroudSettingView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.centerX.equalTo(self.backgroundPreView.mas_centerX);
+            make.centerY.equalTo(self.backgroundPreView.mas_centerY);
+            make.height.mas_equalTo(330);
+            make.width.mas_equalTo(320);
+        }];
+        
+        [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
+            self.backgroudSettingView.center = CGPointMake(self.backgroudSettingView.center.x, self.backgroudSettingView.center.y - 300);
+        } completion:nil];
+        
+        [_backgroudSettingView.pageBtn addTarget:self action:@selector(onSelectPageRange:) forControlEvents:UIControlEventTouchUpInside];
+        [_backgroudSettingView.doneBtn addTarget:self action:@selector(doneClick:) forControlEvents:UIControlEventTouchUpInside];
+        [_backgroudSettingView.cancelBtn addTarget:self action:@selector(cancelClick:) forControlEvents:UIControlEventTouchUpInside];
+        
+        [_backgroudSettingView.opacitySlider addTarget:self action:@selector(onOpacityChanged:) forControlEvents:UIControlEventValueChanged];
+        [_backgroudSettingView.scaleSlider addTarget:self action:@selector(onScaleChanged:) forControlEvents:UIControlEventValueChanged];
+        [_backgroudSettingView.rotationSlider addTarget:self action:@selector(onRotationChanged:) forControlEvents:UIControlEventValueChanged];
+        
+        [_backgroudSettingView.horizontalField addTarget:self action:@selector(horizontalChange:) forControlEvents:UIControlEventEditingDidEnd];
+        [_backgroudSettingView.verticalField addTarget:self action:@selector(verticalChage:) forControlEvents:UIControlEventEditingDidEnd];
+    }
+}
+
+- (void)deleteClick {
+    [self.delegate deleteBackgroundModel];
+    
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+#pragma mark - UI Functions
+
+- (void)onColorBtnClicked:(UIButton *)btn {
+    
+    if (_dataModel.image) {
+        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Select Color Warning" message:@"Sorry,we can't choose color" preferredStyle:UIAlertControllerStyleAlert];
+        
+        [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        }]];
+        [self presentViewController:alertController animated:YES completion:nil];
+    }
+    
+    _dataModel.backgroundColor = btn.backgroundColor;
+    _drawBackgroundView.dataModel = self.dataModel;
+    [_drawBackgroundView setNeedsDisplay];
+    
+//    _backgroundPreView.documentView.image = [_image imageWithTintColor:btn.backgroundColor];
+}
+
+- (void)onSelectBtnClicked:(UIButton *)sender {
+    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
+    imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
+    imagePicker.delegate = self;
+    imagePicker.allowsEditing = YES;
+    [self presentViewController:imagePicker animated:YES completion:nil];
+}
+
+- (void)onSelectPageRange:(UIButton *)btn {
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
+    UIAlertAction *defaultRange = [UIAlertAction actionWithTitle:@"All Pages" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        self.backgroudSettingView.rangeLabel.text = @"Page Range: ALL";
+        }];
+    UIAlertAction *customRange = [UIAlertAction actionWithTitle:@"Custom" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        [self createCustomRangeAlert];
+        }];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
+            
+        }];
+    [alertController addAction:defaultRange];
+    [alertController addAction:customRange];
+    [alertController addAction:cancelAction];
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)createCustomRangeAlert {
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Custom Page Range" message:nil preferredStyle:UIAlertControllerStyleAlert];
+    
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = @"such as:1,3-5,10";
+    }];
+    [alertController addAction:[UIAlertAction actionWithTitle:@"Done" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        
+        self.dataModel.pageString = alertController.textFields.firstObject.text;
+        self.backgroudSettingView.rangeLabel.text = @"Page Range:Custom";
+    }]];
+    [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+    }]];
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)doneClick:(UIButton *)btn {
+    [self btnEnable];
+    _drawBackgroundView.dataModel = self.dataModel;
+    
+    [_drawBackgroundView setNeedsDisplay];
+    [_backgroudSettingView removeFromSuperview];
+}
+
+- (void)cancelClick:(UIButton *)btn {
+    [self btnEnable];
+    [_backgroudSettingView removeFromSuperview];
+}
+
+- (void)onOpacityChanged:(UISlider *)sender {
+    _dataModel.backgroundOpacity = 1 - sender.value;
+}
+
+- (void)onScaleChanged:(UISlider *)sender {
+    _dataModel.backgroudScale = sender.value;
+}
+
+- (void)onRotationChanged:(UISlider *)sender {
+    _dataModel.backgroundRotation = sender.value * 180 / M_PI;
+}
+
+- (void)horizontalChange:(UITextField *)text {
+    _dataModel.horizontalSpacing = [text.text floatValue];
+}
+
+- (void)verticalChage:(UITextField *)text {
+    _dataModel.verticalSpacing = [text.text floatValue];
+}
+
+- (void)btnEnable {
+    self.backgroundView.selectBtn.enabled = YES;
+    self.navigationItem.rightBarButtonItems.firstObject.enabled = YES;
+    self.navigationItem.rightBarButtonItems.lastObject.enabled = YES;
+}
+
+#pragma mark - Orientation
+
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight) {
+        
+        [_backgroundView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.bottom.equalTo(self.view.mas_bottom).offset(-25);
+            make.left.equalTo(self.view.mas_left);
+            make.right.equalTo(self.view.mas_right);
+            make.height.mas_equalTo(70);
+        }];
+        
+        [_backgroundPreView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(43.6);
+            make.left.equalTo(self.view.mas_left);
+            make.right.equalTo(self.view.mas_right);
+            make.bottom.equalTo(self.backgroundView.mas_top);
+        }];
+        
+        [_backgroundPreView.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.backgroundPreView.mas_top);
+            make.bottom.equalTo(self.backgroundPreView.mas_bottom);
+            make.centerX.equalTo(self.backgroundPreView.mas_centerX);
+            make.width.mas_equalTo(233);
+        }];
+        
+        [_drawBackgroundView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.backgroundPreView.documentView.mas_top);
+            make.bottom.equalTo(self.backgroundPreView.documentView.mas_bottom);
+            make.left.equalTo(self.backgroundPreView.documentView.mas_left);
+            make.right.equalTo(self.backgroundPreView.documentView.mas_right);
+        }];
+        [_drawImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.backgroundPreView.documentView.mas_top);
+            make.bottom.equalTo(self.backgroundPreView.documentView.mas_bottom);
+            make.left.equalTo(self.backgroundPreView.documentView.mas_left);
+            make.right.equalTo(self.backgroundPreView.documentView.mas_right);
+        }];
+    } else if ([UIDevice currentDevice].orientation == UIDeviceOrientationPortrait) {
+        
+        [_backgroundView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.bottom.equalTo(self.view.mas_bottom).offset(-25);
+            make.left.equalTo(self.view.mas_left);
+            make.right.equalTo(self.view.mas_right);
+            make.height.mas_equalTo(70);
+        }];
+        
+        [_backgroundPreView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(83.6);
+            make.left.equalTo(self.view.mas_left);
+            make.right.equalTo(self.view.mas_right);
+            make.bottom.equalTo(self.backgroundView.mas_top);
+        }];
+        
+        [_backgroundPreView.documentView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.left.equalTo(self.view.mas_left);
+            make.top.equalTo(self.view.mas_top).offset(123.6);
+            make.bottom.equalTo(self.backgroundPreView.mas_bottom).offset(-40);
+            make.width.mas_equalTo(393);
+        }];
+    }
+    
+    [_drawBackgroundView setNeedsDisplay];
+}
+
+#pragma mark - UIImagePickerControllerDelegate
+
+- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
+    UIImage *image = info[UIImagePickerControllerOriginalImage];
+    CGSize size;
+    size.width = self.backgroundPreView.documentView.frame.size.width;
+    size.height = self.backgroundPreView.documentView.frame.size.height;
+    _dataModel.image = [self imageWithImageSimple:image scaledToSize:_imageSize];
+    [_backgroundPreView.imageView sizeToFit];
+    
+    [picker dismissViewControllerAnimated:YES completion:nil];
+    [_drawBackgroundView setNeedsDisplay];
+}
+
+- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
+    [picker dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (UIImage *)imageWithImageSimple:(UIImage *)image scaledToSize:(CGSize)newSize
+{
+    UIGraphicsBeginImageContext(newSize);
+    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
+    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return newImage;
+}
+
+#pragma mark - UITextFieldDelegate
+
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    [textField resignFirstResponder];
+    
+    return YES;
+}
+
+@end

+ 33 - 0
PDFViewer/Controller/CPDFImageViewController.h

@@ -0,0 +1,33 @@
+//
+//  CPDFImageViewController.h
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/19.
+//
+
+#import <UIKit/UIKit.h>
+
+
+@class CPDFImagePreview;
+@class CPDFImageView;
+@class CPDFDataModel;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFImageViewController : UIViewController
+
+@property (nonatomic,strong) CPDFImagePreview *imagePreview;
+@property (nonatomic,strong) CPDFImageView *imageView;
+@property (nonatomic,strong) CPDFDataModel *dataModel;
+
+- (void)initDataModel;
+- (void)addTargets;
+- (void)addConstraint;
+- (void)createGestureRecognizer;
+- (void)createCustomRangeAlert;
+
+- (UIImage *)imageWithImageSimple:(UIImage *)image scaledToSize:(CGSize)newSize;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 437 - 0
PDFViewer/Controller/CPDFImageViewController.m

@@ -0,0 +1,437 @@
+//
+//  CPDFImageViewController.m
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/19.
+//
+
+#import "CPDFImageViewController.h"
+#import "CPDFImageView.h"
+#import "CPDFImagePreview.h"
+#import "CPDFDataModel.h"
+#import "CPDFDrawView.h"
+#import "CPDFClipView.h"
+#import "Masonry.h"
+
+@interface CPDFImageViewController () <UIImagePickerControllerDelegate,UINavigationControllerDelegate,CPDFClipTextPreviewDelegate,UITextFieldDelegate>
+
+@property (nonatomic,assign) CGRect watermarkFrame;
+
+@property (nonatomic,strong) CPDFDrawView *drawView;
+@property (nonatomic,strong) CPDFClipView *cliView;
+@property (nonatomic,assign) CGAffineTransform transform1;
+@property (nonatomic,assign) CGAffineTransform transform2;
+@property (nonatomic,assign) CGRect normalWatermarkRect;
+@property (nonatomic,strong) UILabel *shadowWaterLabel;
+
+@end
+
+@implementation CPDFImageViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    _imagePreview = [[CPDFImagePreview alloc] init];
+    _imageView = [[CPDFImageView alloc] init];
+    _dataModel = [[CPDFDataModel alloc] init];
+    
+    _imageView.verticalField.delegate = self;
+    _imageView.horizontalField.delegate = self;
+    
+    [self.view addSubview:_imagePreview];
+    [self.view addSubview:_imageView];
+    [self.view setBackgroundColor:UIColor.systemGray5Color];
+    
+    [self initDataModel];
+    [self addConstraint];
+    [self addTargets];
+    [self createGestureRecognizer];
+    
+    _normalWatermarkRect = CGRectMake(97.5, 143.333, 28, 28);
+    _shadowWaterLabel = [[UILabel alloc] initWithFrame:CGRectMake(97.5, 143.333, 28, 28)];
+}
+
+#pragma mark - Orientation
+
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight) {
+        
+        [_imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.right.equalTo(self.view.mas_right).offset(-38);
+            make.left.equalTo(_imagePreview.mas_right).offset(0);
+            make.height.equalTo(@205);
+            make.width.equalTo(@(self.view.bounds.size.width));
+            make.bottom.equalTo(self.view.mas_bottom).offset(-40);
+        }];
+        [_imagePreview mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(0);
+            make.right.equalTo(_imageView.mas_left).offset(-5);
+            make.left.equalTo(self.view.mas_left).offset(0);
+            make.bottom.equalTo(self.view.mas_bottom).offset(0);
+        }];
+    
+        if ([_drawView isDescendantOfView:self.view]) {
+            [_drawView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.top.equalTo(self.view.mas_top).offset(0);
+                make.right.equalTo(_imageView.mas_left).offset(-5);
+                make.left.equalTo(self.view.mas_left).offset(0);
+                make.bottom.equalTo(self.view.mas_bottom).offset(0);
+            }];
+            [_cliView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.top.equalTo(self.view.mas_top).offset(0);
+                make.right.equalTo(_imageView.mas_left).offset(-5);
+                make.left.equalTo(self.view.mas_left).offset(0);
+                make.bottom.equalTo(self.view.mas_bottom).offset(0);
+            }];
+        }
+    } else if ([UIDevice currentDevice].orientation == UIDeviceOrientationPortrait) {
+        [_imagePreview mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(0);
+            make.width.equalTo(self.view.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(-205);
+        }];
+
+        [_imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(_imagePreview.mas_bottom).offset(0);
+            make.width.equalTo(_imagePreview.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(0);
+        }];
+        
+        if ([_drawView isDescendantOfView:self.view]) {
+            [_drawView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.top.equalTo(self.view.mas_top).offset(0);
+                make.width.equalTo(self.view.mas_width);
+                make.bottom.equalTo(self.view.mas_bottom).offset(-205);
+            }];
+            [_cliView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.top.equalTo(self.view.mas_top).offset(0);
+                make.width.equalTo(self.view.mas_width);
+                make.bottom.equalTo(self.view.mas_bottom).offset(-205);
+            }];
+        }
+    }
+    
+    if ([_drawView isDescendantOfView:self.view]) {
+        [_drawView setDocumentViewRect:_imagePreview.documentView.frame];
+        [_drawView setWaterLabelRect:_imagePreview.watermarkView.frame];
+        [_drawView setNeedsDisplay];
+        [_cliView setNeedsDisplay];
+    }
+}
+
+#pragma mark - Initializers
+
+- (void)initDataModel {
+    _dataModel.watermarkOpacity = 1;
+    _dataModel.imagePath = @"btn_selected";
+    _dataModel.image = [UIImage imageNamed:_dataModel.imagePath];
+    _dataModel.watermarkScale = 1;
+    _dataModel.isTile = NO;
+    _dataModel.watermarkRotation = 0;
+    _dataModel.horizontalSpacing = 100;
+    _dataModel.verticalSpacing = 100;
+    
+    _imageView.horizontalField.text = 0;
+    _imageView.verticalField.text = 0;
+    _imageView.horizontalField.enabled = NO;
+    _imageView.verticalField.enabled = NO;
+    _imageView.imageScaleSlider.enabled = YES;
+    _imagePreview.watermarkView.image = [UIImage imageNamed:_dataModel.imagePath];
+}
+
+- (void)addConstraint {
+    [_imagePreview mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(self.view.mas_top).offset(0);
+        make.width.equalTo(self.view.mas_width);
+        make.bottom.equalTo(self.view.mas_bottom).offset(-205);
+    }];
+
+    [_imageView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(_imagePreview.mas_bottom).offset(0);
+        make.width.equalTo(_imagePreview.mas_width);
+        make.bottom.equalTo(self.view.mas_bottom).offset(0);
+    }];
+}
+
+- (void)addTargets {
+    [_imageView.selectBtn addTarget:self action:@selector(onSelectBtnClicked:) forControlEvents:UIControlEventTouchDown];
+    [_imageView.opacitySlider addTarget:self action:@selector(onOpacityChanged:) forControlEvents:UIControlEventValueChanged];
+    [_imageView.imageScaleSlider addTarget:self action:@selector(onImageScaleChanged:) forControlEvents:UIControlEventValueChanged];
+    [_imageView.tileSwitch addTarget:self action:@selector(onTileSwitchChanged:) forControlEvents:UIControlEventValueChanged];
+    [_imageView.pageBtn addTarget:self action:@selector(onSelectPageRange:) forControlEvents:UIControlEventTouchDown];
+    
+    [_imageView.horizontalField addTarget:self action:@selector(horizontalChange:) forControlEvents:UIControlEventEditingDidEnd];
+    [_imageView.verticalField addTarget:self action:@selector(verticalChage:) forControlEvents:UIControlEventEditingDidEnd];
+}
+
+#pragma mark - Gesture
+
+- (void)createGestureRecognizer {
+    [_imagePreview.documentView setUserInteractionEnabled:YES];
+    [_imagePreview.watermarkView setMultipleTouchEnabled:YES];
+    [_imagePreview.watermarkView setUserInteractionEnabled:YES];
+    [_imagePreview.rotationBtn setUserInteractionEnabled:YES];
+    
+    UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panWatermarkView:)];
+    [_imagePreview.watermarkView addGestureRecognizer:panRecognizer];
+    
+    UIPanGestureRecognizer *panRotationBtnRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(rotateWatermarkView:)];
+    [_imagePreview.rotationBtn addGestureRecognizer:panRotationBtnRecognizer];
+}
+
+- (void)rotateWatermarkView:(UIPanGestureRecognizer *)recognizer {
+    CGPoint point = [recognizer translationInView:_imagePreview];
+    CGFloat radian = atan2(point.x + _imagePreview.center.x - _imagePreview.watermarkView.center.x,point.y + _imagePreview.center.y - _imagePreview.watermarkView.center.y);
+    
+    if (self.dataModel.watermarkScale == 1) {
+        _imagePreview.watermarkView.transform = CGAffineTransformMakeRotation(-radian);
+    } else {
+        _imagePreview.watermarkView.transform = CGAffineTransformRotate(self.transform2, -radian);
+    }
+    
+    _transform1 = CGAffineTransformMakeRotation(-radian);
+    _dataModel.watermarkRotation = (-radian) * 180 / M_PI;
+}
+
+- (void)panWatermarkView:(UIPanGestureRecognizer *)recognizer {
+    CGPoint point = [recognizer translationInView:_imagePreview.documentView];
+    CGRect documentFrame = _imagePreview.documentView.frame;
+    documentFrame.origin.x -= _imagePreview.documentView.frame.origin.x;
+    documentFrame.origin.y -= _imagePreview.documentView.frame.origin.y;
+    
+    [_imagePreview.watermarkView setCenter:CGPointMake(_imagePreview.watermarkView.center.x + point.x, _imagePreview.watermarkView.center.y + point.y)];
+    [_imagePreview.rotationBtn setCenter:CGPointMake(_imagePreview.rotationBtn.center.x + point.x, _imagePreview.rotationBtn.center.y + point.y)];
+    
+    if (!CGRectContainsRect(documentFrame,_imagePreview.watermarkView.frame)) {
+        [_imagePreview.watermarkView setCenter:CGPointMake(_imagePreview.watermarkView.center.x - point.x, _imagePreview.watermarkView.center.y - point.y)];
+        [_imagePreview.rotationBtn setCenter:CGPointMake(_imagePreview.rotationBtn.center.x - point.x, _imagePreview.rotationBtn.center.y - point.y)];
+    }
+    
+    _dataModel.tx = _imagePreview.watermarkView.center.x - (_imagePreview.documentView.center.x - _imagePreview.documentView.frame.origin.x);
+    _dataModel.ty = _imagePreview.documentView.center.y - _imagePreview.documentView.frame.origin.y - _imagePreview.watermarkView.center.y;
+    
+    _shadowWaterLabel.center = _imagePreview.watermarkView.center;
+    
+    [recognizer setTranslation:CGPointZero inView:_imagePreview.documentView];
+    
+    _normalWatermarkRect = _shadowWaterLabel.frame;
+}
+
+#pragma mark - UI Functions
+
+- (void)onSelectBtnClicked:(UIButton *)sender {
+    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
+    imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
+    imagePicker.delegate = self;
+    imagePicker.allowsEditing = YES;
+    [self presentViewController:imagePicker animated:YES completion:nil];
+}
+
+- (void)onOpacityChanged:(UISlider *)sender {
+    _imagePreview.watermarkView.alpha =  1 - sender.value;
+    [_dataModel setWatermarkOpacity:1 - sender.value];
+}
+
+/*
+    this had core was deleted:
+ //    _watermarkFrame.size.width = sender.value * [UIImage imageNamed:_dataModel.imagePath].size.width;
+ //    _watermarkFrame.size.height = sender.value * [UIImage imageNamed:_dataModel.imagePath].size.height;
+ //    _watermarkFrame.size.width = sender.value * 33;
+ //    _watermarkFrame.size.height = sender.value * 33;
+ //
+ //    _watermarkFrame.origin.x = _imagePreview.watermarkView.frame.origin.x;
+ //    _watermarkFrame.origin.y = _imagePreview.watermarkView.frame.origin.y;
+ //    _imagePreview.watermarkView.frame = _watermarkFrame;
+ //    _imagePreview.watermarkFrame = _watermarkFrame;
+ */
+
+- (void)onImageScaleChanged:(UISlider *)sender {
+    sender.minimumValue = 0.5;
+    sender.maximumValue = 2;
+    
+    if (self.dataModel.watermarkRotation) {
+        _imagePreview.watermarkView.transform = CGAffineTransformScale(self.transform1, sender.value, sender.value);
+    } else {
+            _imagePreview.watermarkView.transform = CGAffineTransformMakeScale(sender.value, sender.value);
+    }
+
+    _transform2 = CGAffineTransformMakeScale(sender.value, sender.value);
+    _shadowWaterLabel.transform = CGAffineTransformMakeScale(sender.value, sender.value);
+    
+    [_imagePreview.rotationBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(_imagePreview.watermarkView.mas_bottom).offset(-10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@20);
+        make.left.equalTo(_imagePreview.watermarkView.mas_right).offset(-10);
+    }];
+    
+    [_dataModel setWatermarkScale:sender.value];
+    
+    _normalWatermarkRect = _shadowWaterLabel.frame;
+}
+
+- (void)onSelectPageRange:(UIButton *)sender {
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
+    UIAlertAction *defaultRange = [UIAlertAction actionWithTitle:@"All Pages" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        self.imageView.rangeLabel.text = @"Page Range: ALL";
+        }];
+    UIAlertAction *customRange = [UIAlertAction actionWithTitle:@"Custom Page Range" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        [self createCustomRangeAlert];
+        }];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
+            
+        }];
+    [alertController addAction:defaultRange];
+    [alertController addAction:customRange];
+    [alertController addAction:cancelAction];
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)createCustomRangeAlert {
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Custom Page Range" message:nil preferredStyle:UIAlertControllerStyleAlert];
+    
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = @"such as:1,3-5,10";
+    }];
+    [alertController addAction:[UIAlertAction actionWithTitle:@"Done" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        
+        self.dataModel.pageString = alertController.textFields.firstObject.text;
+        self.imageView.rangeLabel.text = @"Page Range:Custom";
+    }]];
+    [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+    }]];
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)onTileSwitchChanged:(UISwitch *) sender {
+    if ([sender isOn]) {
+        _dataModel.isTile = YES;
+        _imageView.horizontalField.enabled = YES;
+        _imageView.verticalField.enabled = YES;
+        _imageView.imageScaleSlider.enabled = NO;
+        
+        _drawView = [[CPDFDrawView alloc] initWithFrame:self.imagePreview.bounds];
+        
+        [_drawView setDataModel:self.dataModel];
+        [_drawView setWaterLabelRect:self.normalWatermarkRect];
+        [_drawView setDocumentViewRect:self.imagePreview.documentView.frame];
+        
+        [self.view addSubview:_drawView];
+        [self.imagePreview bringSubviewToFront:_drawView];
+        
+        _cliView = [[CPDFClipView alloc] initWithFrame:self.imagePreview.bounds];
+        _cliView.delegate = self;
+        [self.view addSubview:_cliView];
+        [self.drawView bringSubviewToFront:_cliView];
+        
+    } else {
+        _dataModel.isTile = NO;
+        _imageView.horizontalField.enabled = NO;
+        _imageView.verticalField.enabled = NO;
+        _imageView.imageScaleSlider.enabled = YES;
+        
+        [self.drawView removeFromSuperview];
+        [self.cliView removeFromSuperview];
+    }
+}
+
+- (void)horizontalChange:(UITextField *)text {
+    [_drawView setHorizontal:[text.text floatValue]];
+    _dataModel.horizontalSpacing = [text.text floatValue];
+    
+    [_drawView setNeedsDisplay];
+}
+
+- (void)verticalChage:(UITextField *)text {
+    [_drawView setVertical:[text.text floatValue]];
+    _dataModel.verticalSpacing = [text.text floatValue];
+    
+    [_drawView setNeedsDisplay];
+}
+
+
+#pragma mark - UIImagePickerControllerDelegate
+
+- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info {
+    UIImage *image = info[UIImagePickerControllerOriginalImage];
+    CGSize size;
+    size.width = image.size.width / 30;
+    size.height = image.size.height / 30;
+    _imagePreview.watermarkView.image = [self imageWithImageSimple:image scaledToSize:size];
+    _dataModel.image = [self imageWithImageSimple:image scaledToSize:size];
+    [_imagePreview.watermarkView sizeToFit];
+    _shadowWaterLabel.frame = _imagePreview.watermarkView.frame;
+    [picker dismissViewControllerAnimated:YES completion:nil];
+    _normalWatermarkRect = _shadowWaterLabel.frame;
+}
+
+- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
+    [picker dismissViewControllerAnimated:YES completion:nil];
+}
+
+- (UIImage *)imageWithImageSimple:(UIImage *)image scaledToSize:(CGSize)newSize
+{
+    UIGraphicsBeginImageContext(newSize);
+    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
+    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    return newImage;
+}
+
+#pragma mark - CPDFClipTextPreviewDelegate
+
+- (void)clipText:(CGContextRef)context {
+    CGContextSetFillColorWithColor(context, [UIColor systemGray5Color].CGColor);
+    CGContextFillRect(context, self.imagePreview.bounds);
+    CGContextClearRect(context, self.imagePreview.documentView.frame);
+}
+
+#pragma mark - UITextFieldDelegate
+
+- (void)textFieldDidBeginEditing:(UITextField *)textField {
+    
+    self.cliView.hidden = YES;
+    self.drawView.hidden = YES;
+    
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown) {
+        
+    } else {
+        [_imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.height.mas_equalTo(205);
+            make.width.equalTo(_imagePreview.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(-300);
+        }];
+        
+        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^ {
+            self.imageView.center = CGPointMake(self.imageView.center.x, self.imageView.center.y - 300);
+        } completion:nil];
+    }
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    [textField resignFirstResponder];
+    
+    self.cliView.hidden = NO;
+    self.drawView.hidden = NO;
+    
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown) {
+        
+    } else {
+        [_imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(_imagePreview.mas_bottom).offset(0);
+            make.width.equalTo(_imagePreview.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(0);
+            make.height.mas_equalTo(205);
+        }];
+        
+        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^ {
+            self.imageView.center = CGPointMake(self.imageView.center.x, self.imageView.center.y + 300);
+        } completion:nil];
+    }
+    
+    return YES;
+}
+
+@end

+ 32 - 0
PDFViewer/Controller/CPDFTextViewController.h

@@ -0,0 +1,32 @@
+//
+//  CPDFTextViewController.h
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/19.
+//
+
+#import <UIKit/UIKit.h>
+#import "CPDFTextPreview.h"
+
+@class CPDFTextPreview;
+@class CPDFTextView;
+@class CPDFDataModel;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFTextViewController : UIViewController 
+
+@property (nonatomic,strong) CPDFTextPreview *textPreview;
+@property (nonatomic,strong) CPDFTextView *textView;
+@property (nonatomic,strong) CPDFDataModel *dataModel;
+@property (nonatomic,strong) UIAlertController *alertController;
+
+- (void)initDataModel;
+- (void)addTargets;
+- (void)addConstraint;
+- (void)createGestureRecognizer;
+- (void)createCustomRangeAlert;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 397 - 0
PDFViewer/Controller/CPDFTextViewController.m

@@ -0,0 +1,397 @@
+//
+//  CPDFTextViewController.m
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/19.
+//
+
+#import "CPDFTextViewController.h"
+#import "CPDFTextView.h"
+#import "CPDFDataModel.h"
+#import "CPDFDrawView.h"
+#import "CPDFClipView.h"
+#import "Masonry.h"
+
+@interface CPDFTextViewController () <CPDFClipTextPreviewDelegate,UITextFieldDelegate>
+
+@property (nonatomic,strong) CPDFDrawView *drawView;
+@property (nonatomic,strong) CPDFClipView *cliView;
+@property (nonatomic,assign) CGRect normalWatermarkRect;
+@property (nonatomic,strong) UILabel *shadowWaterLabel;
+
+@end
+
+@implementation CPDFTextViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    
+    _textPreview = [[CPDFTextPreview alloc] init];
+    _textView = [[CPDFTextView alloc] init];
+    
+    _textView.verticalField.delegate = self;
+    _textView.horizontalField.delegate = self;
+    
+    _dataModel = [[CPDFDataModel alloc] init];
+    _alertController = [UIAlertController alertControllerWithTitle:@"Watermark Content" message:nil preferredStyle:UIAlertControllerStyleAlert];
+    
+    [self.view addSubview:_textPreview];
+    [self.view addSubview:_textView];
+    [self.view setBackgroundColor:UIColor.systemGray5Color];
+    
+    [self addConstraint];
+    [self initDataModel];
+    [self addTargets];
+    [self createGestureRecognizer];
+    
+    _normalWatermarkRect = CGRectMake(69.666, 147.666, 83.666, 20.333);
+    _shadowWaterLabel = [[UILabel alloc] initWithFrame:CGRectMake(69.666, 147.666, 83.666, 20.333)];
+    _shadowWaterLabel.text = _textPreview.watermarkLabel.text;
+}
+
+#pragma mark - Initializers
+
+- (void)initDataModel {
+    _dataModel.textColor = UIColor.blackColor;
+    _dataModel.watermarkOpacity = 1;
+    _dataModel.text = @"Watermark";
+    _dataModel.watermarkScale = 17.0 / 24.0;
+    _dataModel.isTile = NO;
+    _dataModel.watermarkRotation = 0;
+    _dataModel.verticalSpacing = 100;
+    _dataModel.horizontalSpacing = 100;
+    
+    _textPreview.watermarkLabel.text = _dataModel.text;
+    _textView.horizontalField.text = 0;
+    _textView.verticalField.text = 0;
+    _textView.horizontalField.enabled = NO;
+    _textView.verticalField.enabled = NO;
+}
+
+- (void)addConstraint {
+        [_textPreview mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(0);
+            make.width.equalTo(self.view.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(-205);
+        }];
+
+        [_textView mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(_textPreview.mas_bottom).offset(0);
+            make.width.equalTo(_textPreview.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(0);
+        }];
+}
+
+- (void)addTargets {
+    for (NSInteger i = 0; i < _textView.colorArray.count; ++i) {
+        [_textView.colorArray[i] addTarget:self action:@selector(onColorBtnClicked:) forControlEvents:UIControlEventTouchDown];
+    }
+    
+    __block CPDFTextViewController *strongBlock = self;
+    [_alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        
+    }];
+    [_alertController addAction:[UIAlertAction actionWithTitle:@"Done" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        
+        strongBlock.dataModel.text = strongBlock.alertController.textFields.firstObject.text;
+        strongBlock.textPreview.watermarkLabel.text = strongBlock.alertController.textFields.firstObject.text;
+        [strongBlock.textPreview.watermarkLabel sizeToFit];
+        
+    }]];
+    [_alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        strongBlock.alertController.view.hidden = YES;
+    }]];
+    
+    [_textView.opacitySlider addTarget:self action:@selector(onOpacityChanged:) forControlEvents:UIControlEventValueChanged];
+    [_textView.textScaleSlider addTarget:self action:@selector(onTextScaleChanged:) forControlEvents:UIControlEventValueChanged];
+    [_textView.tileSwitch addTarget:self action:@selector(onTileSwitchChanged:) forControlEvents:UIControlEventValueChanged];
+    [_textView.pageBtn addTarget:self action:@selector(onSelectPageRange:) forControlEvents:UIControlEventTouchDown];
+    
+    [_textView.horizontalField addTarget:self action:@selector(horizontalChange:) forControlEvents:UIControlEventEditingDidEnd];
+    [_textView.verticalField addTarget:self action:@selector(verticalChage:) forControlEvents:UIControlEventEditingDidEnd];
+}
+
+#pragma mark - UI Functions
+
+- (void)onColorBtnClicked:(UIButton *)sender {
+    _textPreview.watermarkLabel.textColor = sender.backgroundColor;
+    [_dataModel setTextColor:sender.backgroundColor];
+}
+
+- (void)onOpacityChanged:(UISlider *)sender {
+    _textPreview.watermarkLabel.alpha =  1 - sender.value;
+    [_dataModel setWatermarkOpacity:1 - sender.value];
+}
+
+- (void)onTextScaleChanged:(UISlider *)sender {
+    if (!_dataModel.isTile) {
+        sender.minimumValue = 12;
+        sender.maximumValue = 36;
+        _textPreview.watermarkLabel.font = [_textPreview.watermarkLabel.font fontWithSize:sender.value];
+        _shadowWaterLabel.font = [_textPreview.watermarkLabel.font fontWithSize:sender.value];
+        _shadowWaterLabel.center = _textPreview.watermarkLabel.center;
+        
+        [_textPreview.watermarkLabel sizeToFit];
+        [_shadowWaterLabel sizeToFit];
+        
+        [_dataModel setWatermarkScale:sender.value / 24];
+    }
+    
+    _normalWatermarkRect = _shadowWaterLabel.frame;
+}
+
+- (void)onTileSwitchChanged:(UISwitch *) sender {
+    if ([sender isOn]) {
+        _dataModel.isTile = YES;
+        _textView.horizontalField.enabled = YES;
+        _textView.verticalField.enabled = YES;
+        _textView.textScaleSlider.enabled = NO;
+        
+        _drawView = [[CPDFDrawView alloc] initWithFrame:self.textPreview.bounds];
+        
+        [_drawView setDataModel:self.dataModel];
+        [_drawView setWaterLabelRect:self.normalWatermarkRect];
+        [_drawView setDocumentViewRect:self.textPreview.documentView.frame];
+        
+        [self.view addSubview:_drawView];
+        [self.textPreview bringSubviewToFront:_drawView];
+        
+        _cliView = [[CPDFClipView alloc] initWithFrame:self.textPreview.bounds];
+        _cliView.delegate = self;
+        [self.view addSubview:_cliView];
+        [self.drawView bringSubviewToFront:_cliView];
+        
+    } else {
+        _dataModel.isTile = NO;
+        _textView.horizontalField.enabled = NO;
+        _textView.verticalField.enabled = NO;
+        _textView.textScaleSlider.enabled = YES;
+        
+        [_drawView removeFromSuperview];
+        [_cliView removeFromSuperview];
+    }
+}
+
+- (void)onSelectPageRange:(UIButton *)sender {
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
+    UIAlertAction *defaultRange = [UIAlertAction actionWithTitle:@"All Pages" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        self.textView.rangeLabel.text = @"Page Range: ALL";
+        }];
+    UIAlertAction *customRange = [UIAlertAction actionWithTitle:@"Custom Page Range" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        [self createCustomRangeAlert];
+        }];
+    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
+            
+        }];
+    [alertController addAction:defaultRange];
+    [alertController addAction:customRange];
+    [alertController addAction:cancelAction]; 
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)createCustomRangeAlert {
+    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Custom Page Range" message:nil preferredStyle:UIAlertControllerStyleAlert];
+    
+    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
+        textField.placeholder = @"such as:1,3-5,10";
+    }];
+    [alertController addAction:[UIAlertAction actionWithTitle:@"Done" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+        
+        self.dataModel.pageString = alertController.textFields.firstObject.text;
+        self.textView.rangeLabel.text = @"Page Range:Custom";
+    }]];
+    [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
+    }]];
+    [self presentViewController:alertController animated:YES completion:nil];
+}
+
+- (void)horizontalChange:(UITextField *)text {
+    [_drawView setHorizontal:[text.text floatValue]];
+    _dataModel.horizontalSpacing = [text.text floatValue];
+    [_drawView setNeedsDisplay];
+}
+
+- (void)verticalChage:(UITextField *)text {
+    [_drawView setVertical:[text.text floatValue]];
+    _dataModel.verticalSpacing = [text.text floatValue];
+    [_drawView setNeedsDisplay];
+}
+
+#pragma mark - Gesture
+
+- (void)createGestureRecognizer {
+    [_textPreview.documentView setUserInteractionEnabled:YES];
+    [_textPreview.watermarkLabel setUserInteractionEnabled:YES];
+    [_textPreview.rotationBtn setUserInteractionEnabled:YES];
+      
+    UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapWatermarkLabel:)];
+    [_textPreview.watermarkLabel addGestureRecognizer:tapGestureRecognizer];
+    
+    UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panWatermarkLabel:)];
+    [_textPreview.watermarkLabel addGestureRecognizer:panRecognizer];
+    
+    UIPanGestureRecognizer *panRotationBtnRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(rotationWatermarkLabel:)];
+    [_textPreview.rotationBtn addGestureRecognizer:panRotationBtnRecognizer];
+}
+
+- (void)tapWatermarkLabel:(UITapGestureRecognizer *)recognizer {
+    _alertController.view.hidden = NO;
+    _alertController.textFields.firstObject.text = _textPreview.watermarkLabel.text;
+    [self presentViewController:_alertController animated:true completion:nil];
+}
+
+- (void)panWatermarkLabel:(UIPanGestureRecognizer *)recognizer {
+    CGPoint point = [recognizer translationInView:_textPreview.documentView];
+    CGRect documentFrame = _textPreview.documentView.frame;
+    documentFrame.origin.x -= _textPreview.documentView.frame.origin.x;
+    documentFrame.origin.y -= _textPreview.documentView.frame.origin.y;
+    
+    [_textPreview.watermarkLabel setCenter:CGPointMake(_textPreview.watermarkLabel.center.x + point.x, _textPreview.watermarkLabel.center.y + point.y)];
+    [_textPreview.rotationBtn setCenter:CGPointMake(_textPreview.rotationBtn.center.x + point.x, _textPreview.rotationBtn.center.y + point.y)];
+    
+    if (!CGRectContainsRect(documentFrame,_textPreview.watermarkLabel.frame)) {
+        [_textPreview.watermarkLabel setCenter:CGPointMake(_textPreview.watermarkLabel.center.x - point.x, _textPreview.watermarkLabel.center.y - point.y)];
+        [_textPreview.rotationBtn setCenter:CGPointMake(_textPreview.rotationBtn.center.x - point.x, _textPreview.rotationBtn.center.y - point.y)];
+    }
+    
+    _dataModel.tx = _textPreview.watermarkLabel.center.x - (_textPreview.documentView.center.x - _textPreview.documentView.frame.origin.x);
+    _dataModel.ty = _textPreview.documentView.center.y - _textPreview.documentView.frame.origin.y - _textPreview.watermarkLabel.center.y;
+    [recognizer setTranslation:CGPointZero inView:_textPreview.documentView];
+    _shadowWaterLabel.center = _textPreview.watermarkLabel.center;
+    
+    _normalWatermarkRect = _shadowWaterLabel.frame;
+}
+
+- (void)rotationWatermarkLabel:(UIPanGestureRecognizer *)recognizer {
+    CGPoint point = [recognizer translationInView:_textPreview];
+    CGFloat radian = atan2(point.x + _textPreview.center.x - _textPreview.watermarkLabel.center.x, point.y + _textPreview.center.y - _textPreview.watermarkLabel.center.y);
+    _textPreview.watermarkLabel.transform = CGAffineTransformMakeRotation(-radian);
+    _dataModel.watermarkRotation = (-radian) * 180 / M_PI;
+}
+
+#pragma mark - Orientation
+
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
+    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight) {
+        
+        [_textView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.right.equalTo(self.view.mas_right).offset(-38);
+            make.left.equalTo(_textPreview.mas_right).offset(0);
+            make.height.equalTo(@205);
+            make.width.equalTo(@(self.view.bounds.size.width));
+            make.bottom.equalTo(self.view.mas_bottom).offset(-40);
+        }];
+        [_textPreview mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(0);
+            make.right.equalTo(_textView.mas_left).offset(-5);
+            make.left.equalTo(self.view.mas_left).offset(0);
+            make.bottom.equalTo(self.view.mas_bottom).offset(0);
+        }];
+        
+        if ([_drawView isDescendantOfView:self.view]) {
+            [_drawView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.top.equalTo(self.view.mas_top).offset(0);
+                make.right.equalTo(_textView.mas_left).offset(-5);
+                make.left.equalTo(self.view.mas_left).offset(0);
+                make.bottom.equalTo(self.view.mas_bottom).offset(0);
+            }];
+            [_cliView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.top.equalTo(self.view.mas_top).offset(0);
+                make.right.equalTo(_textView.mas_left).offset(-5);
+                make.left.equalTo(self.view.mas_left).offset(0);
+                make.bottom.equalTo(self.view.mas_bottom).offset(0);
+            }];
+        }
+        
+    } else if ([UIDevice currentDevice].orientation == UIDeviceOrientationPortrait) {
+        [_textPreview mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(self.view.mas_top).offset(0);
+            make.width.equalTo(self.view.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(-205);
+        }];
+        [_textView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(_textPreview.mas_bottom).offset(0);
+            make.width.equalTo(_textPreview.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(0);
+        }];
+        
+        if ([_drawView isDescendantOfView:self.view]) {
+            [_drawView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.top.equalTo(self.view.mas_top).offset(0);
+                make.width.equalTo(self.view.mas_width);
+                make.bottom.equalTo(self.view.mas_bottom).offset(-205);
+            }];
+            [_cliView mas_remakeConstraints:^(MASConstraintMaker *make) {
+                make.top.equalTo(self.view.mas_top).offset(0);
+                make.width.equalTo(self.view.mas_width);
+                make.bottom.equalTo(self.view.mas_bottom).offset(-205);
+            }];
+        }
+    }
+    
+    if ([_drawView isDescendantOfView:self.view]) {
+        [_drawView setDocumentViewRect:_textPreview.documentView.frame];
+        [_drawView setWaterLabelRect:_textPreview.watermarkLabel.frame];
+        [_drawView setNeedsDisplay];
+        [_cliView setNeedsDisplay];
+    }
+}
+
+#pragma mark - CPDFClipTextPreviewDelegate
+
+- (void)clipText:(CGContextRef)context {
+    CGContextSetFillColorWithColor(context, [UIColor systemGray5Color].CGColor);
+    CGContextFillRect(context, self.textPreview.bounds);
+    CGContextClearRect(context, self.textPreview.documentView.frame);
+}
+
+#pragma mark - UITextFieldDelegate
+
+- (void)textFieldDidBeginEditing:(UITextField *)textField {
+    
+    self.cliView.hidden = YES;
+    self.drawView.hidden = YES;
+    
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown) {
+        
+    } else {
+        [_textView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.height.mas_equalTo(205);
+            make.width.equalTo(_textPreview.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(-300);
+        }];
+        
+        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^ {
+            self.textView.center = CGPointMake(self.textView.center.x, self.textView.center.y - 300);
+        } completion:nil];
+    }
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField *)textField {
+    [textField resignFirstResponder];
+    
+    self.cliView.hidden = NO;
+    self.drawView.hidden = NO;
+    
+    if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight || [UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft || [UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown) {
+        
+    } else {
+        [_textView mas_remakeConstraints:^(MASConstraintMaker *make) {
+            make.top.equalTo(_textPreview.mas_bottom).offset(0);
+            make.width.equalTo(_textPreview.mas_width);
+            make.bottom.equalTo(self.view.mas_bottom).offset(0);
+            make.height.mas_equalTo(205);
+        }];
+        
+        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^ {
+            self.textView.center = CGPointMake(self.textView.center.x, self.textView.center.y + 300);
+        } completion:nil];
+    }
+    
+    return YES;
+}
+
+@end

+ 1 - 0
PDFViewer/Controller/CPDFViewController.h

@@ -8,6 +8,7 @@
 #import <UIKit/UIKit.h>
 #import "CPDFHeaderFooterModel.h"
 
+
 NS_ASSUME_NONNULL_BEGIN
 
 @interface CPDFViewController : UIViewController

+ 20 - 0
PDFViewer/View/CPDFBackgroundPreview.h

@@ -0,0 +1,20 @@
+//
+//  CPDFBackgroundPreview.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/2.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFBackgroundPreview : UIView
+
+@property (nonatomic,strong) UIImageView *documentView;
+@property (nonatomic,strong) UIImageView *imageView;
+@property (nonatomic,strong) UIColor *tintColor;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 43 - 0
PDFViewer/View/CPDFBackgroundPreview.m

@@ -0,0 +1,43 @@
+//
+//  CPDFBackgroundPreview.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/2.
+//
+
+#import "CPDFBackgroundPreview.h"
+#import "Masonry.h"
+
+@implementation CPDFBackgroundPreview
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    
+    if (self) {
+        _documentView = [[UIImageView alloc] init];
+        [self addSubview:_documentView];
+        
+        _imageView = [[UIImageView alloc] init];
+        [self addSubview:_imageView];
+        
+        self.backgroundColor = [UIColor systemGray5Color];
+    }
+    
+    return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+    [super drawRect:rect];
+    
+    _imageView.layer.borderColor = UIColor.blueColor.CGColor;
+    _imageView.layer.borderWidth = 1;
+    [_imageView sizeToFit];
+    _imageView.contentMode = UIViewContentModeScaleAspectFit;
+    
+    CGRect frame = _imageView.frame;
+    frame.origin = CGPointMake(_documentView.bounds.size.width / 2 - _imageView.frame.size.width / 2, _documentView.bounds.size.height / 2 - _imageView.frame.size.height / 2);
+    
+    _imageView.frame = frame;
+}
+
+@end

+ 32 - 0
PDFViewer/View/CPDFBackgroundSettingView.h

@@ -0,0 +1,32 @@
+//
+//  CPDFBackgroundSettingView.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/2.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFBackgroundSettingView : UIView
+
+@property (nonatomic,strong) UILabel *titleLabel;
+@property (nonatomic,strong) UISlider *scaleSlider;
+@property (nonatomic,strong) UISlider *opacitySlider;
+@property (nonatomic,strong) UISlider *rotationSlider;
+@property (nonatomic,strong) UILabel *rotationlabel;
+@property (nonatomic,strong) UILabel *textLabel;
+@property (nonatomic,strong) UILabel *opacityLabel;
+@property (nonatomic,strong) UILabel *rangeLabel;
+@property (nonatomic,strong) UITextField *verticalField;
+@property (nonatomic,strong) UITextField *horizontalField;
+@property (nonatomic,strong) UILabel *verticalLabel;
+@property (nonatomic,strong) UILabel *horizontalLabel;
+@property (nonatomic,strong) UIButton *pageBtn;
+@property (nonatomic,strong) UIButton *doneBtn;
+@property (nonatomic,strong) UIButton *cancelBtn;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 163 - 0
PDFViewer/View/CPDFBackgroundSettingView.m

@@ -0,0 +1,163 @@
+//
+//  CPDFBackgroundSettingView.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/2.
+//
+
+#import "CPDFBackgroundSettingView.h"
+#import "Masonry.h"
+
+@implementation CPDFBackgroundSettingView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    if (self) {
+        _opacitySlider = [[UISlider alloc] init];
+        _scaleSlider = [[UISlider alloc] init];
+        _rotationSlider = [[UISlider alloc] init];
+        
+        [self addSubview:_opacitySlider];
+        [self addSubview:_scaleSlider];
+        [self addSubview:_rotationSlider];
+        
+        _rotationlabel = [[UILabel alloc] init];
+        _rangeLabel = [[UILabel alloc] init];
+        _textLabel = [[UILabel alloc] init];
+        _opacityLabel = [[UILabel alloc] init];
+        _titleLabel = [[UILabel alloc] init];
+        
+        [self addSubview:_textLabel];
+        [self addSubview:_opacityLabel];
+        [self addSubview:_rangeLabel];
+        [self addSubview:_rotationlabel];
+        [self addSubview:_titleLabel];
+        
+        _verticalField = [[UITextField alloc] init];
+        _verticalField.borderStyle = UITextBorderStyleRoundedRect;
+        _verticalLabel = [[UILabel alloc] init];
+        _horizontalField = [[UITextField alloc] init];
+        _horizontalField.borderStyle = UITextBorderStyleRoundedRect;
+        _horizontalLabel = [[UILabel alloc] init];
+        _pageBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
+        
+        [self addSubview:_verticalLabel];
+        [self addSubview:_verticalField];
+        [self addSubview:_horizontalField];
+        [self addSubview:_horizontalLabel];
+        [self addSubview:_pageBtn];
+        
+        _doneBtn = [[UIButton alloc] init];
+        _cancelBtn = [[UIButton alloc] init];
+        
+        [self addSubview:_doneBtn];
+        [self addSubview:_cancelBtn];
+        
+        self.backgroundColor = [UIColor systemGray6Color];
+    }
+    
+    return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+    
+    _titleLabel.frame = CGRectMake(5, 5, 180, 50);
+    _rangeLabel.frame = CGRectMake(5, 165, 150, 30);
+    _textLabel.frame = CGRectMake(5, 95, 90, 30);
+    _opacityLabel.frame = CGRectMake(5, 60, 90, 30);
+    _rotationlabel.frame = CGRectMake(5, 130, 90, 30);
+    
+    [self addConstraint];
+    [self assignData];
+}
+
+- (void)addConstraint {
+    [_verticalField mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@80);
+        make.height.equalTo(@30);
+    }];
+    [_verticalLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-95);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@30);
+    }];
+    [_horizontalField mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.equalTo(self.mas_left).offset(25);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@80);
+        make.height.equalTo(@30);
+    }];
+    [_horizontalLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.equalTo(self.mas_left).offset(5);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@30);
+    }];
+    [_scaleSlider mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.left.equalTo(_textLabel.mas_right).offset(0);
+        make.top.equalTo(self.mas_top).offset(95);
+        make.height.equalTo(@30);
+    }];
+    [_opacitySlider mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.left.equalTo(_opacityLabel.mas_right).offset(0);
+        make.top.equalTo(self.mas_top).offset(60);
+        make.height.equalTo(@30);
+    }];
+    [_rotationSlider mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.left.equalTo(_rotationlabel.mas_right).offset(0);
+        make.top.equalTo(_scaleSlider.mas_bottom).offset(5);
+    }];
+    
+    [_pageBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.top.equalTo(self.rotationSlider.mas_bottom).offset(5);
+        make.left.equalTo(_rangeLabel.mas_right);
+        make.height.equalTo(@35);
+    }];
+    
+    [_doneBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.top.equalTo(_horizontalField.mas_bottom).offset(25);
+        make.height.mas_equalTo(30);
+        make.width.mas_equalTo(80);
+    }];
+    
+    [_cancelBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-110);
+        make.top.equalTo(_horizontalField.mas_bottom).offset(25);
+        make.height.mas_equalTo(30);
+        make.width.mas_equalTo(80);
+    }];
+}
+
+- (void)assignData {
+    _rangeLabel.text = @"Page Range";
+    _rangeLabel.font = [UIFont systemFontOfSize:15];
+    _titleLabel.text = @"Background Edit";
+    _rotationlabel.text = @"Rotation";
+    _textLabel.text = @"Scale";
+    _opacityLabel.text = @"Opacity";
+    _verticalLabel.text = @"Y:";
+    _horizontalLabel.text = @"X:";
+    
+    _scaleSlider.minimumValue = 0.2;
+    _scaleSlider.maximumValue = 1;
+    _scaleSlider.value = 1;
+    
+    _rotationSlider.minimumValue = 0;
+    _rotationSlider.maximumValue = M_PI;
+    
+    [_pageBtn setTitle:@"Page Range" forState:UIControlStateNormal];
+    [_doneBtn setTitle:@"Done" forState:UIControlStateNormal];
+    [_doneBtn setTitleColor:UIColor.systemBlueColor forState:UIControlStateNormal];
+    [_cancelBtn setTitle:@"Cancel" forState:UIControlStateNormal];
+    [_cancelBtn setTitleColor:UIColor.systemBlueColor forState:UIControlStateNormal];
+}
+
+@end

+ 22 - 0
PDFViewer/View/CPDFBackgroundView.h

@@ -0,0 +1,22 @@
+//
+//  CPDFBackgroundView.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/2.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFBackgroundView : UIView
+
+@property (nonatomic,strong) UIButton *colorBtn;
+@property (nonatomic,strong) UILabel *colorLabel;
+@property (nonatomic,strong) UIButton *selectBtn;
+@property (nonatomic,strong) UILabel *imageLabel;
+@property (nonatomic,strong) NSMutableArray *colorArray;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 93 - 0
PDFViewer/View/CPDFBackgroundView.m

@@ -0,0 +1,93 @@
+//
+//  CPDFBackgroundView.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/2.
+//
+
+#define KBUTTON_WIDTH 28
+#define KBUTTON_HEIGHT 28
+
+#import "CPDFBackgroundView.h"
+#import "Masonry.h"
+
+@implementation CPDFBackgroundView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    
+    if (self) {
+        _imageLabel = [[UILabel alloc] init];
+        [self addSubview:_imageLabel];
+        
+        _selectBtn = [[UIButton alloc] init];
+        [self addSubview:_selectBtn];
+        
+        _colorLabel = [[UILabel alloc] init];
+        [self addSubview:_colorLabel];
+        
+        _colorArray = [NSMutableArray array];
+        for (NSInteger i = 0; i < 8; ++i) {
+            _colorBtn = [UIButton buttonWithType:UIButtonTypeSystem];
+            [_colorArray addObject:_colorBtn];
+            [self addSubview:_colorBtn];
+        }
+    }
+    
+    return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+    [super drawRect:rect];
+    
+    _colorLabel.frame = CGRectMake(20, 5, 50, 30);
+    _colorLabel.text = @"Color";
+    _imageLabel.frame = CGRectMake(20, 40, 140, 30);
+    _imageLabel.text = @"Image";
+    
+    for (NSInteger i = 0; i < _colorArray.count; i++) {
+        [[[self colorArray][i] layer] setCornerRadius:KBUTTON_WIDTH / 2];
+        [[[self colorArray][i] layer] setMasksToBounds:YES];
+        [[_colorArray[i] layer] setBorderWidth:0.5f];
+        [[_colorArray[i] layer] setBorderColor:UIColor.systemGray4Color.CGColor];
+    }
+    
+    [_colorArray[0] setBackgroundColor:[UIColor redColor]];
+    [_colorArray[1] setBackgroundColor:[UIColor orangeColor]];
+    [_colorArray[2] setBackgroundColor:[UIColor yellowColor]];
+    [_colorArray[3] setBackgroundColor:[UIColor greenColor]];
+    [_colorArray[4] setBackgroundColor:[UIColor blueColor]];
+    [_colorArray[5] setBackgroundColor:[UIColor brownColor]];
+    [_colorArray[6] setBackgroundColor:[UIColor purpleColor]];
+    [_colorArray[7] setBackgroundColor:[UIColor whiteColor]];
+    
+    _selectBtn.layer.borderWidth = 1.0;
+    _selectBtn.layer.borderColor = UIColor.systemGray4Color.CGColor;
+    [_selectBtn setTitle:@"Select Image" forState:UIControlStateNormal];
+    [_selectBtn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
+    _selectBtn.layer.cornerRadius = 7;
+    
+    [self addConstraint];
+}
+ 
+- (void)addConstraint {
+    NSInteger offset = 10;
+    for (NSInteger i = 0; i < _colorArray.count; ++i) {
+        [_colorArray[i] mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.right.equalTo(self.mas_right).offset( - offset);
+            make.top.equalTo(self.mas_top).offset(5);
+            make.width.equalTo(@KBUTTON_WIDTH);
+            make.height.equalTo(@KBUTTON_HEIGHT);
+        }];
+        offset += 40;
+    }
+    
+    [_selectBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-25);
+        make.top.equalTo(self.colorLabel.mas_bottom).offset(5);
+        make.width.mas_equalTo(180);
+        make.height.equalTo(@35);
+    }];
+}
+
+@end

+ 27 - 0
PDFViewer/View/CPDFClipView.h

@@ -0,0 +1,27 @@
+//
+//  CPDFClipView.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2022/12/23.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol CPDFClipTextPreviewDelegate <NSObject>
+
+@required
+
+- (void)clipText:(CGContextRef)context;
+
+@end
+
+
+@interface CPDFClipView : UIView
+
+@property (nonatomic,strong) id<CPDFClipTextPreviewDelegate> delegate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 30 - 0
PDFViewer/View/CPDFClipView.m

@@ -0,0 +1,30 @@
+//
+//  CPDFClipView.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2022/12/23.
+//
+
+#import "CPDFClipView.h"
+
+@implementation CPDFClipView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+    }
+    
+    return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+    [super drawRect:rect];
+    
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    
+    [self.delegate clipText:context];
+}
+
+@end

+ 19 - 0
PDFViewer/View/CPDFDrawBackgroundView.h

@@ -0,0 +1,19 @@
+//
+//  CPDFDrawBackgroundView.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/3.
+//
+
+#import <UIKit/UIKit.h>
+#import "CPDFBackgroundModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFDrawBackgroundView : UIView
+
+@property (nonatomic,strong) CPDFBackgroundModel *dataModel;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 55 - 0
PDFViewer/View/CPDFDrawBackgroundView.m

@@ -0,0 +1,55 @@
+//
+//  CPDFDrawBackgroundView.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/3.
+//
+
+#import "CPDFDrawBackgroundView.h"
+
+@implementation CPDFDrawBackgroundView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    
+    if (self) {
+        self.backgroundColor = [UIColor whiteColor];
+    }
+    
+    return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+    [super drawRect:rect];
+    
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    
+    [self showDraw:context];
+}
+
+- (void)showDraw:(CGContextRef)context {
+    CGContextSetFillColorWithColor(context, self.dataModel.backgroundColor.CGColor);
+    
+    CGContextSetAlpha(context, self.dataModel.backgroundOpacity);
+    
+    CGFloat ctm = (self.dataModel.backgroundRotation * M_PI) / 180;
+    CGFloat centerWidth = self.bounds.size.width / 2;
+    CGFloat centerHeigth = self.bounds.size.height / 2;
+    
+    CGContextTranslateCTM(context, self.dataModel.horizontalSpacing, - self.dataModel.verticalSpacing);
+
+    CGContextTranslateCTM(context, centerWidth, centerHeigth);
+    CGContextRotateCTM(context, ctm);
+    
+    CGContextScaleCTM(context, self.dataModel.backgroudScale, self.dataModel.backgroudScale);
+    if (_dataModel.image) {
+        [_dataModel.image drawInRect:CGRectMake(- centerWidth,  - centerHeigth, self.frame.size.width,self.frame.size.height) blendMode:kCGBlendModeNormal alpha:self.dataModel.backgroundOpacity];
+    } else {
+        CGContextFillRect(context, CGRectMake( - centerWidth, - centerHeigth, self.bounds.size.width, self.bounds.size.height));
+    }
+    
+    CGContextRotateCTM(context, -ctm);
+    CGContextTranslateCTM(context, - centerWidth, - centerHeigth);
+}
+
+@end

+ 18 - 0
PDFViewer/View/CPDFDrawImageView.h

@@ -0,0 +1,18 @@
+//
+//  CPDFDrawImageView.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/3.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFDrawImageView : UIView
+
+@property (nonatomic,strong) UIImage *image;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 76 - 0
PDFViewer/View/CPDFDrawImageView.m

@@ -0,0 +1,76 @@
+//
+//  CPDFDrawImageView.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/3.
+//
+
+#import "CPDFDrawImageView.h"
+
+@implementation CPDFDrawImageView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+    }
+    
+    return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+    CGContextRef context = UIGraphicsGetCurrentContext();
+    
+    [self showDraw:context];
+}
+
+- (void)showDraw:(CGContextRef)context {
+    UIImage *newImage = [self imageToTransparent:_image];
+    
+    [newImage drawInRect:self.bounds blendMode:kCGBlendModeNormal alpha:1.0f];
+}
+
+- (UIImage*) imageToTransparent:(UIImage*) image {
+    const int imageWidth = image.size.width;
+    const int imageHeight = image.size.height;
+    size_t bytesPerRow = imageWidth * 4;
+    uint32_t *rgbImageBuf = (uint32_t *)malloc(bytesPerRow * imageHeight);
+    
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace
+                                                 , kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
+    
+    CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
+    
+    int pixelNum = imageWidth * imageHeight;
+    uint32_t* pCurPtr = rgbImageBuf;
+    for (int i = 0; i < pixelNum; i++, pCurPtr++)
+    {
+        if ((*pCurPtr & 0x65815A00) == 0x65815a00)
+        {
+            uint8_t* ptr = (uint8_t*)pCurPtr;
+            ptr[0] = 0;
+        }
+    }
+
+    CGDataProviderRef dataProvider =CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, ProviderReleaseData);
+    CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight,8, 32, bytesPerRow, colorSpace,
+                                        kCGImageAlphaLast |kCGBitmapByteOrder32Little, dataProvider,
+                                        NULL, true,kCGRenderingIntentDefault);
+    CGDataProviderRelease(dataProvider);
+
+    UIImage* resultUIImage = [UIImage imageWithCGImage:imageRef];
+
+    CGImageRelease(imageRef);
+    CGContextRelease(context);
+    CGColorSpaceRelease(colorSpace);
+
+    return resultUIImage;
+}
+
+ void ProviderReleaseData(void *info, const void *data, size_t size) {
+     free((void *) data);
+}
+
+@end

+ 23 - 0
PDFViewer/View/CPDFDrawView.h

@@ -0,0 +1,23 @@
+//
+//  CPDFDrawView.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2022/12/22.
+//
+
+#import <UIKit/UIKit.h>
+#import "CPDFDataModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFDrawView : UIView
+
+@property (nonatomic,strong) CPDFDataModel *dataModel;
+@property (nonatomic,assign) CGRect waterLabelRect;
+@property (nonatomic,assign) CGRect documentViewRect;
+@property (nonatomic,assign) CGFloat vertical;
+@property (nonatomic,assign) CGFloat horizontal;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 115 - 0
PDFViewer/View/CPDFDrawView.m

@@ -0,0 +1,115 @@
+//
+//  CPDFDrawView.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2022/12/22.
+//
+
+#import "CPDFDrawView.h"
+
+@implementation CPDFDrawView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    
+    if (self) {
+        self.backgroundColor = [UIColor clearColor];
+        
+        _dataModel = [[CPDFDataModel alloc] init];
+        
+        _horizontal = 100;
+        _vertical = 100;
+    }
+    
+    return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+    [super drawRect:rect];
+    
+    CGContextRef context = UIGraphicsGetCurrentContext();
+
+    if (self.dataModel.text) {
+        [self drawText:context];
+    } else if (self.dataModel.image) {
+        [self drawImage:context];
+    }
+    
+}
+
+- (void)drawText:(CGContextRef)context {
+    CGContextSetFillColorWithColor(context, self.dataModel.textColor.CGColor);
+    CGContextSaveGState(context);
+    
+    CGContextSetAlpha(context, self.dataModel.watermarkOpacity);
+    
+    UIFont *font = [UIFont systemFontOfSize:24 * self.dataModel.watermarkScale];
+    NSDictionary *dic = @{NSFontAttributeName:font,NSForegroundColorAttributeName:self.dataModel.textColor};
+    
+    NSInteger wx,wy,height,width;
+    wx = self.waterLabelRect.origin.x + self.documentViewRect.origin.x;
+    wy = self.waterLabelRect.origin.y + self.documentViewRect.origin.y;
+    height = self.waterLabelRect.size.height + _vertical / 2.5;
+    width = self.waterLabelRect.size.width + _horizontal / 2.3;
+
+    NSInteger x,y,a,b;
+    x = self.frame.size.width / width;
+    y = self.frame.size.height / height;
+
+    a = wx % width;
+    b = wy % height;
+    
+    CGFloat ctm = (self.dataModel.watermarkRotation * M_PI) / 180;
+    
+    CGContextTranslateCTM(context, self.center.x,  self.center.y);
+    
+    CGContextRotateCTM(context, ctm);
+
+    for (NSInteger i = 0; i < x; i++) {
+        for (NSInteger j = 0; j < y; j++) {
+            
+            [self.dataModel.text drawInRect:CGRectMake((a + i * width) - self.center.x, b + j * height - self.center.y, width - _horizontal / 2.5, height - _vertical / 2.5) withAttributes:dic];
+        }
+    }
+    
+    CGContextRotateCTM(context, -ctm);
+    CGContextTranslateCTM(context, - self.center.x, - self.center.y);
+}
+
+- (void)drawImage:(CGContextRef)context {
+    CGContextSaveGState(context);
+    
+    CGContextSetAlpha(context, self.dataModel.watermarkOpacity);
+    
+    NSInteger wx,wy,height,width;
+    wx = self.waterLabelRect.origin.x + self.documentViewRect.origin.x;
+    wy = self.waterLabelRect.origin.y + self.documentViewRect.origin.y;
+    height = self.waterLabelRect.size.height + _vertical / 1.8;
+    width = self.waterLabelRect.size.width + _horizontal / 1.8;
+
+    NSInteger x,y,a,b;
+    x = self.frame.size.width / width;
+    y = self.frame.size.height / height;
+
+    a = wx % width;
+    b = wy % height;
+    
+    CGFloat ctm = (self.dataModel.watermarkRotation * M_PI) / 180;
+    
+    CGContextTranslateCTM(context, self.center.x,  self.center.y);
+    
+    CGContextRotateCTM(context, ctm);
+
+    for (NSInteger i = 0; i < x; i++) {
+        for (NSInteger j = 0; j < y; j++) {
+            
+            [self.dataModel.image drawInRect:CGRectMake((a + i * width) - self.center.x, b + j * height - self.center.y, width - _horizontal / 1.8, height - _vertical / 1.8) blendMode:kCGBlendModeNormal alpha:self.dataModel.watermarkOpacity];
+        }
+    }
+    CGContextRotateCTM(context, -ctm);
+    
+    CGContextTranslateCTM(context, - self.center.x, - self.center.y);
+    
+}
+
+@end

+ 18 - 0
PDFViewer/View/CPDFEditView.h

@@ -0,0 +1,18 @@
+//
+//  CPDFEditView.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2022/12/26.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFEditView : UIView
+ 
+@property (nonatomic,strong) UITableView *editTableView;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 33 - 0
PDFViewer/View/CPDFEditView.m

@@ -0,0 +1,33 @@
+//
+//  CPDFEditView.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2022/12/26.
+//
+
+#import "CPDFEditView.h"
+
+@implementation CPDFEditView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    self = [super initWithFrame:frame];
+    
+    if (self) {
+        _editTableView = [[UITableView alloc] initWithFrame:self.bounds style:UITableViewStylePlain];
+        _editTableView.backgroundColor = [UIColor systemGray6Color];
+        _editTableView.rowHeight = 50;
+        _editTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+        _editTableView.tableFooterView = [[UIView alloc] init];
+        [_editTableView setEditing:YES animated:YES];
+        _editTableView.allowsMultipleSelection = NO;
+        _editTableView.allowsSelectionDuringEditing = NO;
+        _editTableView.allowsMultipleSelectionDuringEditing = NO;
+        
+        [self addSubview:_editTableView];
+        
+        self.backgroundColor = [UIColor systemGray6Color];
+    }
+    return self;
+}
+
+@end

+ 21 - 0
PDFViewer/View/CPDFImagePreview.h

@@ -0,0 +1,21 @@
+//
+//  CPDFImagePreview.h
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/18.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFImagePreview : UIView
+
+@property (nonatomic,strong) UIImageView *watermarkView;
+@property (nonatomic,strong) UIButton *rotationBtn;
+@property (nonatomic,strong) UIImageView *documentView;
+@property (nonatomic,assign) CGRect watermarkFrame;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 59 - 0
PDFViewer/View/CPDFImagePreview.m

@@ -0,0 +1,59 @@
+//
+//  CPDFImagePreview.m
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/18.
+//
+
+#import "CPDFImagePreview.h"
+#import "Masonry.h"
+
+BOOL gImagePreviewIsFirstLayout = YES;
+
+@implementation CPDFImagePreview
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    if (self = [super initWithFrame:frame]) {
+        _watermarkView = [[UIImageView alloc] init];
+        _rotationBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        _documentView = [[UIImageView alloc] init];
+
+        [self addSubview:_documentView];
+        [_documentView addSubview:_watermarkView];
+        [_watermarkView addSubview:_rotationBtn];
+    }
+    return self;
+}
+
+#pragma mark - Layout
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    
+    _watermarkView.layer.borderColor = UIColor.blueColor.CGColor;
+    _watermarkView.layer.borderWidth = 1;
+    [_watermarkView sizeToFit];
+    _watermarkView.contentMode = UIViewContentModeScaleAspectFit;
+    
+    CGRect frame = _watermarkView.frame;
+    frame.origin = CGPointMake(_documentView.bounds.size.width / 2 - _watermarkView.frame.size.width / 2, _documentView.bounds.size.height / 2 - _watermarkView.frame.size.height / 2);
+    _watermarkFrame = frame;
+    
+    _watermarkView.frame = _watermarkFrame;
+    
+    [_rotationBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(_watermarkView.mas_bottom).offset(-10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@20);
+        make.left.equalTo(_watermarkView.mas_right).offset(-10);
+    }];
+    
+    _rotationBtn.layer.cornerRadius = 10;
+    _rotationBtn.layer.masksToBounds = YES;
+    _rotationBtn.layer.borderColor = UIColor.blueColor.CGColor;
+    [_rotationBtn setBackgroundImage:[UIImage imageNamed:@"btn_selected"] forState:UIControlStateNormal];
+    
+}
+
+@end

+ 35 - 0
PDFViewer/View/CPDFImageView.h

@@ -0,0 +1,35 @@
+//
+//  CPDFImageView.h
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/16.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFImageView : UIView
+
+@property (nonatomic,strong) UIButton *selectBtn;
+@property (nonatomic,strong) UISlider *imageScaleSlider;
+@property (nonatomic,strong) UISlider *opacitySlider;
+@property (nonatomic,strong) UISwitch *tileSwitch;
+@property (nonatomic,strong) UILabel *rangeLabel;
+@property (nonatomic,strong) UILabel *tileLabel;
+@property (nonatomic,strong) UILabel *sizeLabel;
+@property (nonatomic,strong) UILabel *opacityLabel;
+@property (nonatomic,strong) UITextField *verticalField;
+@property (nonatomic,strong) UITextField *horizontalField;
+@property (nonatomic,strong) UILabel *verticalLabel;
+@property (nonatomic,strong) UILabel *horizontalLabel;
+@property (nonatomic,strong) UILabel *imageLabel;
+@property (nonatomic,strong) UIButton *pageBtn;
+
+- (void)createView;
+- (void)createFrame;
+- (void)assignData;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 156 - 0
PDFViewer/View/CPDFImageView.m

@@ -0,0 +1,156 @@
+//
+//  CPDFImageView.m
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/16.
+//
+
+#import "CPDFImageView.h"
+#import "Masonry.h"
+
+@implementation CPDFImageView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    
+    if (self = [super initWithFrame:frame]) {
+        [self createView];
+        [self assignData];
+    }
+    
+    return self;
+}
+
+#pragma mark - Layout
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    [self createFrame];
+    [self addConstraint];
+}
+
+- (void)createView {
+    
+    _opacitySlider = [[UISlider alloc] init];
+    _imageScaleSlider = [[UISlider alloc] init];
+    _tileSwitch = [[UISwitch alloc] init];
+    _rangeLabel = [[UILabel alloc] init];
+    _tileLabel = [[UILabel alloc] init];
+    _sizeLabel = [[UILabel alloc] init];
+    _opacityLabel = [[UILabel alloc] init];
+    
+    _verticalField = [[UITextField alloc] init];
+    _verticalField.borderStyle = UITextBorderStyleRoundedRect;
+    
+    _verticalLabel = [[UILabel alloc] init];
+    
+    _horizontalField = [[UITextField alloc] init];
+    _horizontalField.borderStyle = UITextBorderStyleRoundedRect;
+    
+    _horizontalLabel = [[UILabel alloc] init];
+    _imageLabel = [[UILabel alloc] init];
+    _selectBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
+    _pageBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
+    
+    [self addSubview:_opacitySlider];
+    [self addSubview:_sizeLabel];
+    [self addSubview:_opacityLabel];
+    [self addSubview:_imageScaleSlider];
+    [self addSubview:_tileSwitch];
+    [self addSubview:_rangeLabel];
+    [self addSubview:_tileLabel];
+    [self addSubview:_verticalLabel];
+    [self addSubview:_verticalField];
+    [self addSubview:_horizontalField];
+    [self addSubview:_horizontalLabel];
+    [self addSubview:_imageLabel];
+    [self addSubview:_selectBtn];
+    [self addSubview:_pageBtn];
+    
+    [self setBackgroundColor:[UIColor whiteColor]];
+    
+}
+
+- (void)createFrame {
+    // y -- 40   height -- 30
+    _tileSwitch.frame = CGRectMake(100, 160, 10, 10);
+    _rangeLabel.frame = CGRectMake(10, 120, 180, 30);
+    _tileLabel.frame = CGRectMake(10, 160, 100, 30);
+    _sizeLabel.frame = CGRectMake(10, 80, 90, 30);
+    _opacityLabel.frame = CGRectMake(10, 40, 90, 30);
+    _imageLabel.frame = CGRectMake(10, 5, 150, 30);
+    
+    _selectBtn.layer.borderWidth = 1.0;
+    _selectBtn.layer.borderColor = UIColor.systemGray4Color.CGColor;
+    [_selectBtn setTitle:@"Select Image" forState:UIControlStateNormal];
+    [_selectBtn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
+    _selectBtn.layer.cornerRadius = 7;
+    
+    _pageBtn.layer.borderWidth = 1.0;
+    _pageBtn.layer.borderColor = UIColor.systemGray4Color.CGColor;
+    [_pageBtn setTitle:@"Page Range" forState:UIControlStateNormal];
+    [_pageBtn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
+    _pageBtn.layer.cornerRadius = 7;
+}
+
+- (void)addConstraint {
+    [_verticalField mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@80);
+        make.height.equalTo(@30);
+    }];
+    [_verticalLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-95);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@30);
+    }];
+    [_horizontalField mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-115);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@80);
+        make.height.equalTo(@30);
+    }];
+    [_horizontalLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-195);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@30);
+    }];
+    [_selectBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.top.equalTo(self.mas_top).offset(2);
+        make.left.equalTo(_horizontalField.mas_left);
+        make.height.equalTo(@35);
+    }];
+    [_imageScaleSlider mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.left.equalTo(_sizeLabel.mas_right).offset(0);
+        make.top.equalTo(self.mas_top).offset(80);
+        make.height.equalTo(@30);
+    }];
+    [_opacitySlider mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.left.equalTo(_opacityLabel.mas_right).offset(0);
+        make.top.equalTo(self.mas_top).offset(40);
+        make.height.equalTo(@30);
+    }];
+    [_pageBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.top.equalTo(self.mas_top).offset(115);
+        make.left.equalTo(_horizontalField.mas_left);
+        make.height.equalTo(@35);
+    }];
+}
+
+- (void)assignData {
+    _rangeLabel.text = @"Page Range";
+    _tileLabel.text = @"Full Screen";
+    _sizeLabel.text = @"Image Size";
+    _opacityLabel.text = @"Opacity";
+    _verticalLabel.text = @"Y:";
+    _horizontalLabel.text = @"X:";
+    _imageLabel.text = @"Image";
+}
+
+@end

+ 20 - 0
PDFViewer/View/CPDFTextPreview.h

@@ -0,0 +1,20 @@
+//
+//  CPDFTextPreview.h
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/18.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFTextPreview : UIView 
+
+@property (nonatomic,strong) UILabel *watermarkLabel;
+@property (nonatomic,strong) UIButton *rotationBtn;
+@property (nonatomic,strong) UIImageView *documentView;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 66 - 0
PDFViewer/View/CPDFTextPreview.m

@@ -0,0 +1,66 @@
+//
+//  CPDFTextPreview.m
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/18.
+//
+
+#import "CPDFTextPreview.h"
+#import "Masonry.h"
+
+BOOL gTextPreviewIsFirstLayout = YES;
+
+@implementation CPDFTextPreview
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+    if (self = [super initWithFrame:frame]) {
+        _watermarkLabel = [[UILabel alloc] init];
+        _rotationBtn = [UIButton buttonWithType:UIButtonTypeCustom];
+        _documentView = [[UIImageView alloc] init];
+        
+        [self addSubview:_documentView];
+        [_documentView addSubview:_watermarkLabel];
+        [_watermarkLabel addSubview:_rotationBtn];
+        
+        self.backgroundColor = [UIColor systemGray5Color];
+    }
+    return self;
+}
+
+#pragma mark - Drawrect
+
+- (void)drawRect:(CGRect)rect {
+    [super drawRect:rect];
+
+    _watermarkLabel.layer.borderWidth = 1;
+    _watermarkLabel.layer.borderColor = UIColor.blueColor.CGColor;
+
+    [_watermarkLabel sizeToFit];
+    
+    /*
+     this have a core was delete:
+         if (gTextPreviewIsFirstLayout) {
+             gTextPreviewIsFirstLayout = NO;
+         }
+     
+     */
+
+    CGRect frame = _watermarkLabel.frame;
+    frame.origin = CGPointMake(_documentView.bounds.size.width / 2 - _watermarkLabel.frame.size.width / 2, _documentView.bounds.size.height / 2 - _watermarkLabel.frame.size.height / 2);
+        _watermarkLabel.frame = frame;
+
+    _rotationBtn.layer.cornerRadius = 10;
+    _rotationBtn.layer.masksToBounds = YES;
+    _rotationBtn.layer.borderColor = UIColor.blueColor.CGColor;
+    [_rotationBtn setBackgroundImage:[UIImage imageNamed:@"btn_selected"] forState:UIControlStateNormal];
+    
+    [_rotationBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.equalTo(_watermarkLabel.mas_bottom).offset(-10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@20);
+        make.left.equalTo(_watermarkLabel.mas_right).offset(-10);
+    }];
+}
+
+@end

+ 37 - 0
PDFViewer/View/CPDFTextView.h

@@ -0,0 +1,37 @@
+//
+//  CPDFTextView.h
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/16.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CPDFTextView : UIView
+
+@property (nonatomic,strong) UIButton *colorBtn;
+@property (nonatomic,strong) UILabel *colorLabel;
+@property (nonatomic,strong) UISlider *textScaleSlider;
+@property (nonatomic,strong) UISlider *opacitySlider;
+@property (nonatomic,strong) UISwitch *tileSwitch;
+@property (nonatomic,strong) UILabel *rangeLabel;
+@property (nonatomic,strong) UILabel *tileLabel;
+@property (nonatomic,strong) UILabel *textLabel;
+@property (nonatomic,strong) UILabel *opacityLabel;
+@property (nonatomic,strong) UITextField *verticalField;
+@property (nonatomic,strong) UITextField *horizontalField;
+@property (nonatomic,strong) UILabel *verticalLabel;
+@property (nonatomic,strong) UILabel *horizontalLabel;
+@property (nonatomic,strong) UIButton *pageBtn;
+
+@property (nonatomic,strong) NSMutableArray *colorArray;
+
+- (void)createView;
+- (void)createFrame;
+- (void)assignData;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 178 - 0
PDFViewer/View/CPDFTextView.m

@@ -0,0 +1,178 @@
+//
+//  CPDFTextView.m
+//  PDFViewer
+//
+//  Created by kdan on 2022/11/16.
+//
+
+#import "CPDFTextView.h"
+#import "Masonry.h"
+
+#define KBUTTON_WIDTH 28
+#define KBUTTON_HEIGHT 28
+
+@implementation CPDFTextView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+    
+    if (self = [super initWithFrame:frame]) {
+        [self createView];
+        [self assignData];
+        self.backgroundColor = [UIColor whiteColor];
+    }
+    
+    return self;
+}
+
+#pragma mark - Layout
+
+- (void)layoutSubviews {
+    [super layoutSubviews];
+    [self createFrame];
+    [self addConstraint];
+}
+
+- (void)createView {
+    
+    _opacitySlider = [[UISlider alloc] init];
+    _textScaleSlider = [[UISlider alloc] init];
+    _tileSwitch = [[UISwitch alloc] init];
+    _rangeLabel = [[UILabel alloc] init];
+    _tileLabel = [[UILabel alloc] init];
+    _textLabel = [[UILabel alloc] init];
+    _opacityLabel = [[UILabel alloc] init];
+    _colorLabel = [[UILabel alloc] init];
+    
+    _verticalField = [[UITextField alloc] init];
+    _verticalField.borderStyle = UITextBorderStyleRoundedRect;
+    
+    _verticalLabel = [[UILabel alloc] init];
+    
+    _horizontalField = [[UITextField alloc] init];
+    _horizontalField.borderStyle = UITextBorderStyleRoundedRect;
+    
+    _horizontalLabel = [[UILabel alloc] init];
+    _pageBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
+    
+    _colorArray = [NSMutableArray array];
+    for (NSInteger i = 0; i < 8; ++i) {
+        _colorBtn = [UIButton buttonWithType:UIButtonTypeSystem];
+        [_colorArray addObject:_colorBtn];
+        [self addSubview:_colorBtn];
+    }
+    
+    
+    [self addSubview:_opacitySlider];
+    [self addSubview:_textLabel];
+    [self addSubview:_opacityLabel];
+    [self addSubview:_textScaleSlider];
+    [self addSubview:_tileSwitch];
+    [self addSubview:_rangeLabel];
+    [self addSubview:_tileLabel];
+    [self addSubview:_verticalLabel];
+    [self addSubview:_verticalField];
+    [self addSubview:_horizontalField];
+    [self addSubview:_horizontalLabel];
+    [self addSubview:_colorLabel];
+    [self addSubview:_pageBtn];
+    
+}
+
+- (void)createFrame {
+    // y -- 40   height -- 30
+    _tileSwitch.frame = CGRectMake(100, 160, 10, 10);
+    _rangeLabel.frame = CGRectMake(10, 120, 180, 30);
+    _tileLabel.frame = CGRectMake(10, 160, 100, 30);
+    _textLabel.frame = CGRectMake(10, 80, 90, 30);
+    _opacityLabel.frame = CGRectMake(10, 40, 90, 30);
+    _colorLabel.frame = CGRectMake(10, 5, 50, 30);
+    
+    for (NSInteger i = 0; i < _colorArray.count; i++) {
+        [[[self colorArray][i] layer] setCornerRadius:KBUTTON_WIDTH / 2];
+        [[[self colorArray][i] layer] setMasksToBounds:YES];
+    }
+    
+    [_colorArray[0] setBackgroundColor:[UIColor redColor]];
+    [_colorArray[1] setBackgroundColor:[UIColor orangeColor]];
+    [_colorArray[2] setBackgroundColor:[UIColor yellowColor]];
+    [_colorArray[3] setBackgroundColor:[UIColor greenColor]];
+    [_colorArray[4] setBackgroundColor:[UIColor blueColor]];
+    [_colorArray[5] setBackgroundColor:[UIColor brownColor]];
+    [_colorArray[6] setBackgroundColor:[UIColor purpleColor]];
+    [_colorArray[7] setBackgroundColor:[UIColor grayColor]];
+    
+    _pageBtn.layer.borderWidth = 1.0;
+    _pageBtn.layer.borderColor = UIColor.systemGray4Color.CGColor;
+    [_pageBtn setTitle:@"Page Range" forState:UIControlStateNormal];
+    [_pageBtn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
+    _pageBtn.layer.cornerRadius = 7;
+}
+
+- (void)addConstraint {
+    [_verticalField mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@80);
+        make.height.equalTo(@30);
+    }];
+    [_verticalLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-95);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@30);
+    }];
+    [_horizontalField mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-115);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@80);
+        make.height.equalTo(@30);
+    }];
+    [_horizontalLabel mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-195);
+        make.top.equalTo(self.pageBtn.mas_bottom).offset(10);
+        make.width.equalTo(@20);
+        make.height.equalTo(@30);
+    }];
+    [_textScaleSlider mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.left.equalTo(_textLabel.mas_right).offset(0);
+        make.top.equalTo(self.mas_top).offset(80);
+        make.height.equalTo(@30);
+    }];
+    [_opacitySlider mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.left.equalTo(_opacityLabel.mas_right).offset(0);
+        make.top.equalTo(self.mas_top).offset(40);
+        make.height.equalTo(@30);
+    }];
+    
+    NSInteger offset = 10;
+    for (NSInteger i = 0; i < _colorArray.count; ++i) {
+        [_colorArray[i] mas_makeConstraints:^(MASConstraintMaker *make) {
+            make.right.equalTo(self.mas_right).offset( - offset);
+            make.top.equalTo(self.mas_top).offset(5);
+            make.width.equalTo(@KBUTTON_WIDTH);
+            make.height.equalTo(@KBUTTON_HEIGHT);
+        }];
+        offset += 40;
+    }
+    
+    [_pageBtn mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.right.equalTo(self.mas_right).offset(-15);
+        make.top.equalTo(self.mas_top).offset(115);
+        make.left.equalTo(_horizontalField.mas_left);
+        make.height.equalTo(@35);
+    }];
+}
+
+- (void)assignData {
+    _rangeLabel.text = @"Page Range";
+    _tileLabel.text = @"Full Screen";
+    _textLabel.text = @"Font Size";
+    _opacityLabel.text = @"Opacity";
+    _verticalLabel.text = @"Y:";
+    _horizontalLabel.text = @"X:";
+    _colorLabel.text = @"Color";
+}
+
+@end

+ 21 - 0
PDFViewer/View/UIImage+TintColor.h

@@ -0,0 +1,21 @@
+//
+//  UIImage+TintColor.h
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/3.
+//
+
+#import <UIKit/UIKit.h>
+#import "CPDFDataModel.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface UIImage (TintColor)
+
+@property (nonatomic,strong) CPDFDataModel *datamodel;
+
+- (UIImage *)imageWithTintColor:(UIColor *)tintColor;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 51 - 0
PDFViewer/View/UIImage+TintColor.m

@@ -0,0 +1,51 @@
+//
+//  UIImage+TintColor.m
+//  PDFViewer
+//
+//  Created by kdanmobile_2 on 2023/1/3.
+//
+
+#import "UIImage+TintColor.h"
+
+@implementation UIImage (TintColor)
+
+- (UIImage *)imageWithTintColor:(UIColor *)tintColor {
+    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
+
+    [tintColor setFill];
+    
+    CGRect bounds = CGRectMake(0, 0, self.size.width, self.size.height);
+    UIRectFill(bounds);
+    
+    [self drawInRect:bounds blendMode:kCGBlendModeDestinationIn alpha:0.3f];
+    
+    [self drawInRect:bounds blendMode:kCGBlendModeOverlay alpha:2.0f];
+    
+    UIImage *tintImage = UIGraphicsGetImageFromCurrentImageContext();
+    UIGraphicsEndImageContext();
+    
+    return tintImage;
+}
+
+- (void)setDatamodel:(CPDFDataModel *)datamodel {
+    self.datamodel = datamodel;
+}
+
+- (CPDFDataModel *)datamodel {
+    return self.datamodel;
+}
+
+- (CGRect)rotateRect:(CGRect)rect {
+    CGAffineTransform tranform_1 = CGAffineTransformMakeTranslation(- self.size.width / 2,  - self.size.height / 2);
+    CGRect rect_1 = CGRectApplyAffineTransform(rect,tranform_1);
+    
+    CGAffineTransform tranform_2 = CGAffineTransformMakeRotation(M_PI / 8);
+    CGRect rect_2 = CGRectApplyAffineTransform(rect_1,tranform_2);
+    
+    CGAffineTransform tranform_3 = CGAffineTransformMakeTranslation(- self.size.width / 2,  - self.size.height / 2);
+    CGRect rect_3 = CGRectApplyAffineTransform(rect_2,tranform_3);
+    
+    return rect_3;
+}
+
+@end

BIN
PDFViewer/View/sources/btn_selected.png