├── CZHSyntheticImages.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ └── chengzhaohua.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ └── chengzhaohua.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ └── xcschememanagement.plist
├── CZHSyntheticImages
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ ├── 1.imageset
│ │ ├── 1.jpg
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── share_play.imageset
│ │ ├── Contents.json
│ │ └── icon_play@3x.png
├── Base.lproj
│ └── LaunchScreen.storyboard
├── CZHImagePickerBaseController.h
├── CZHImagePickerBaseController.m
├── CZHNavigationController.h
├── CZHNavigationController.m
├── CZHShareLocalViewController.h
├── CZHShareLocalViewController.m
├── CZHShowSyntheticImageView.h
├── CZHShowSyntheticImageView.m
├── CZHSyntheticLocalImageController.h
├── CZHSyntheticLocalImageController.m
├── CZHSyntheticNetworkImageController.h
├── CZHSyntheticNetworkImageController.m
├── CZHTabBarController.h
├── CZHTabBarController.m
├── CZHTipsView.h
├── CZHTipsView.m
├── Header.h
├── Info.plist
├── NSString+CZHSizeExtension.h
├── NSString+CZHSizeExtension.m
├── TZImagePickerController
│ ├── NSBundle+TZImagePicker.h
│ ├── NSBundle+TZImagePicker.m
│ ├── TZAssetCell.h
│ ├── TZAssetCell.m
│ ├── TZAssetModel.h
│ ├── TZAssetModel.m
│ ├── TZGifPhotoPreviewController.h
│ ├── TZGifPhotoPreviewController.m
│ ├── TZImageCropManager.h
│ ├── TZImageCropManager.m
│ ├── TZImageManager.h
│ ├── TZImageManager.m
│ ├── TZImagePickerController.bundle
│ │ ├── MMVideoPreviewPlay@2x.png
│ │ ├── MMVideoPreviewPlayHL@2x.png
│ │ ├── Root.plist
│ │ ├── VideoSendIcon@2x.png
│ │ ├── en.lproj
│ │ │ └── Localizable.strings
│ │ ├── navi_back@2x.png
│ │ ├── photo_def_photoPickerVc@2x.png
│ │ ├── photo_def_previewVc@2x.png
│ │ ├── photo_number_icon@2x.png
│ │ ├── photo_original_def@2x.png
│ │ ├── photo_original_sel@2x.png
│ │ ├── photo_sel_photoPickerVc@2x.png
│ │ ├── photo_sel_previewVc@2x.png
│ │ ├── preview_number_icon@2x.png
│ │ ├── preview_original_def@2x.png
│ │ ├── takePicture@2x.png
│ │ ├── vi.lproj
│ │ │ └── Localizable.strings
│ │ ├── zh-Hans.lproj
│ │ │ └── Localizable.strings
│ │ └── zh-Hant.lproj
│ │ │ └── Localizable.strings
│ ├── TZImagePickerController.h
│ ├── TZImagePickerController.m
│ ├── TZLocationManager.h
│ ├── TZLocationManager.m
│ ├── TZPhotoPickerController.h
│ ├── TZPhotoPickerController.m
│ ├── TZPhotoPreviewCell.h
│ ├── TZPhotoPreviewCell.m
│ ├── TZPhotoPreviewController.h
│ ├── TZPhotoPreviewController.m
│ ├── TZProgressView.h
│ ├── TZProgressView.m
│ ├── TZVideoPlayerController.h
│ ├── TZVideoPlayerController.m
│ ├── UIView+Layout.h
│ └── UIView+Layout.m
├── UIImage+CZHExtension.h
├── UIImage+CZHExtension.m
├── UILabel+CZHExtension.h
├── UILabel+CZHExtension.m
├── UIView+CZHExtension.h
├── UIView+CZHExtension.m
└── main.m
├── CZHSyntheticImagesTests
├── CZHSyntheticImagesTests.m
└── Info.plist
├── CZHSyntheticImagesUITests
├── CZHSyntheticImagesUITests.m
└── Info.plist
└── README.md
/CZHSyntheticImages.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CZHSyntheticImages.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CZHSyntheticImages.xcodeproj/project.xcworkspace/xcuserdata/chengzhaohua.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages.xcodeproj/project.xcworkspace/xcuserdata/chengzhaohua.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/CZHSyntheticImages.xcodeproj/xcuserdata/chengzhaohua.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/CZHSyntheticImages.xcodeproj/xcuserdata/chengzhaohua.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | CZHSyntheticImages.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (strong, nonatomic) UIWindow *window;
15 |
16 |
17 | @end
18 |
19 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "CZHTabBarController.h"
11 | #import "UIImage+CZHExtension.h"
12 | #import "CZHShowSyntheticImageView.h"
13 | @interface AppDelegate ()
14 |
15 | @end
16 |
17 | @implementation AppDelegate
18 |
19 |
20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
21 |
22 |
23 | self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
24 |
25 | self.window.backgroundColor = [UIColor whiteColor];
26 |
27 | self.window.rootViewController = [[CZHTabBarController alloc] init];
28 |
29 | [self.window makeKeyAndVisible];
30 |
31 | //监听截图通知
32 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDidTakeScreenshot:) name:UIApplicationUserDidTakeScreenshotNotification object:nil];
33 |
34 | return YES;
35 | }
36 |
37 | - (void)userDidTakeScreenshot:(NSNotification *)noti {
38 |
39 | NSLog(@"检测到截屏");
40 | //
41 | UIImage *image = [UIImage czh_generateScreenShotImage];
42 |
43 | [CZHShowSyntheticImageView czh_showSyntheticImageViewWithImage:image isScreenShot:YES];
44 |
45 | }
46 |
47 |
48 |
49 |
50 |
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/Assets.xcassets/1.imageset/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/Assets.xcassets/1.imageset/1.jpg
--------------------------------------------------------------------------------
/CZHSyntheticImages/Assets.xcassets/1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "1.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/CZHSyntheticImages/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/CZHSyntheticImages/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/CZHSyntheticImages/Assets.xcassets/share_play.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "icon_play@3x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/CZHSyntheticImages/Assets.xcassets/share_play.imageset/icon_play@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/Assets.xcassets/share_play.imageset/icon_play@3x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHImagePickerBaseController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CZHImagePickerBaseController.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CZHImagePickerBaseController : UIViewController
12 |
13 |
14 | ///打开相册,选择图片回调
15 | - (void)showImagePickerControllerWithSuccessHandler:(void(^)(UIImage *image))successHandler;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHImagePickerBaseController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHImagePickerBaseController.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "CZHImagePickerBaseController.h"
10 | #import "TZImagePickerController.h"
11 | #import
12 | #import
13 | #import "TZImageManager.h"
14 | #import "TZVideoPlayerController.h"
15 | #import "TZPhotoPreviewController.h"
16 | #import "TZGifPhotoPreviewController.h"
17 | #import "TZLocationManager.h"
18 |
19 | #define MAX_COLUMN_NUMBER 4 ///PICKER每行展示的数量
20 | #define MAX_IMAGES_COUNT 1 ///每次选择最大数量
21 |
22 | @interface CZHImagePickerBaseController ()
23 |
24 | @property (strong, nonatomic) CLLocation *location;
25 |
26 | @property (nonatomic, strong) UIImagePickerController *imagePickerVc;
27 | ///选择的图片
28 | @property (nonatomic, strong) NSMutableArray *selectedPhotos;
29 | ///选择的asset
30 | @property (nonatomic, strong) NSMutableArray *selectedAssets;
31 | ///<#注释#>
32 | @property (nonatomic, copy) void (^successHandler)(UIImage *image);
33 |
34 | @end
35 |
36 | @implementation CZHImagePickerBaseController
37 |
38 |
39 | #pragma clang diagnostic push
40 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
41 |
42 |
43 |
44 |
45 |
46 | - (NSMutableArray *)selectedPhotos {
47 | if (!_selectedPhotos) {
48 | _selectedPhotos = [NSMutableArray array];
49 | }
50 | return _selectedPhotos;
51 | }
52 |
53 | - (NSMutableArray *)selectedAssets {
54 | if (!_selectedAssets) {
55 | _selectedAssets = [NSMutableArray array];
56 | }
57 | return _selectedAssets;
58 | }
59 |
60 |
61 |
62 | - (void)viewDidLoad {
63 | [super viewDidLoad];
64 |
65 | }
66 |
67 | - (void)showImagePickerControllerWithSuccessHandler:(void (^)(UIImage *))successHandler {
68 |
69 | self.successHandler = successHandler;
70 |
71 | TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 columnNumber:MAX_COLUMN_NUMBER delegate:self pushPhotoPickerVc:YES];
72 | imagePickerVc.isSelectOriginalPhoto = YES;
73 | imagePickerVc.allowTakePicture = NO; // 在内部显示拍照按钮
74 |
75 | // 3. 设置是否可以选择视频/图片/原图
76 | imagePickerVc.allowPickingVideo = NO;
77 | imagePickerVc.allowPickingImage = YES;
78 | imagePickerVc.allowPickingOriginalPhoto = YES;
79 | imagePickerVc.allowPickingGif = NO;
80 | imagePickerVc.allowPickingMultipleVideo = NO; // 是否可以多选视频
81 |
82 | imagePickerVc.statusBarStyle = UIStatusBarStyleLightContent;
83 |
84 | imagePickerVc.allowCrop = NO;
85 | imagePickerVc.needCircleCrop = NO;
86 |
87 | [self presentViewController:imagePickerVc animated:YES completion:nil];
88 | }
89 |
90 | - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
91 | if ([picker isKindOfClass:[UIImagePickerController class]]) {
92 | [picker dismissViewControllerAnimated:YES completion:nil];
93 | }
94 | }
95 |
96 |
97 | #pragma mark - TZImagePickerControllerDelegate
98 |
99 | /// User click cancel button
100 | /// 用户点击了取消
101 | - (void)tz_imagePickerControllerDidCancel:(TZImagePickerController *)picker {
102 | // CZHLog(@"cancel");
103 | }
104 |
105 |
106 |
107 | /**
108 | * 普通图片
109 | */
110 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray *)infos {
111 |
112 | _selectedPhotos = [NSMutableArray arrayWithArray:photos];
113 | _selectedAssets = [NSMutableArray arrayWithArray:assets];
114 |
115 | if (self.successHandler) {
116 | self.successHandler(photos.firstObject);
117 | }
118 | }
119 |
120 |
121 | @end
122 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHNavigationController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CZHNavigationController.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CZHNavigationController : UINavigationController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHNavigationController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHNavigationController.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "CZHNavigationController.h"
10 |
11 | @interface CZHNavigationController ()
12 |
13 | @end
14 |
15 | @implementation CZHNavigationController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | self.navigationBar.translucent = NO;
20 | }
21 |
22 | - (void)didReceiveMemoryWarning {
23 | [super didReceiveMemoryWarning];
24 | // Dispose of any resources that can be recreated.
25 | }
26 |
27 | /*
28 | #pragma mark - Navigation
29 |
30 | // In a storyboard-based application, you will often want to do a little preparation before navigation
31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
32 | // Get the new view controller using [segue destinationViewController].
33 | // Pass the selected object to the new view controller.
34 | }
35 | */
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHShareLocalViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CZHShareLocalViewController.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/14.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CZHShareLocalViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHShareLocalViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHShareLocalViewController.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/14.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "CZHShareLocalViewController.h"
10 | #import "Header.h"
11 | #import "CZHShowSyntheticImageView.h"
12 | #import "UIImage+CZHExtension.h"
13 |
14 | @interface CZHShareLocalViewController ()
15 | ///<#注释#>
16 | @property (nonatomic, weak) UIImageView *headIconimageView;
17 | ///<#注释#>
18 | @property (nonatomic, weak) UIView *qrCodeView;
19 | ///<#注释#>
20 | @property (nonatomic, weak) UIImageView *qrCodeImageView;
21 | ///<#注释#>
22 | @property (nonatomic, weak) UILabel *nicknameLabel;
23 | ///<#注释#>
24 | @property (nonatomic, weak) UIImageView *prettyLogoImageView;
25 | ///<#注释#>
26 | @property (nonatomic, weak) UILabel *idNumberLabel;
27 | ///<#注释#>
28 | @property (nonatomic, weak) UILabel *fansLabel;
29 | ///<#注释#>
30 | @property (nonatomic, weak) UILabel *charmLabel;
31 | ///<#注释#>
32 | @property (nonatomic, weak) UILabel *tipLabel;
33 | @end
34 |
35 | @implementation CZHShareLocalViewController
36 |
37 | - (void)viewDidLoad {
38 | [super viewDidLoad];
39 | self.view.backgroundColor = CZHColor(0xffffff);
40 |
41 | [self czh_setUpView];
42 |
43 | [self czh_setData];
44 |
45 | [self czh_setUpNavigationBar];
46 | }
47 |
48 | - (void)czh_setUpNavigationBar {
49 |
50 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"点击分享" style:UIBarButtonItemStylePlain target:self action:@selector(buttonClick)];
51 |
52 | }
53 |
54 | - (void)buttonClick {
55 |
56 | UIImage *image = [UIImage czh_generateImageWithView:self.view];
57 |
58 | [CZHShowSyntheticImageView czh_showSyntheticImageViewWithImage:image];
59 |
60 | }
61 |
62 |
63 |
64 | - (void)czh_setData {
65 |
66 |
67 | self.headIconimageView.image = [UIImage imageNamed:@"1"];
68 |
69 | self.nicknameLabel.text = @"哈哈哈";
70 |
71 | self.idNumberLabel.text = @"ID:123456";
72 |
73 | self.fansLabel.text = @"粉丝:1234";
74 |
75 | self.charmLabel.text = @"魅力:1234";
76 |
77 | UIImage *image = [UIImage czh_generateQRCodeWithCodeContent:@"https://github.com/jolincheng" codeSize:CZH_ScaleWidth(90)];
78 | self.qrCodeImageView.image = image;
79 | }
80 |
81 |
82 | - (void)czh_setUpView {
83 |
84 | UIImageView *headIconimageView = [[UIImageView alloc] init];
85 | headIconimageView.contentMode = UIViewContentModeScaleAspectFill;
86 | headIconimageView.clipsToBounds = YES;
87 | [self.view addSubview:headIconimageView];
88 | self.headIconimageView = headIconimageView;
89 |
90 |
91 | UIView *qrCodeView = [[UIView alloc] init];
92 | qrCodeView.backgroundColor = CZHColor(0xffffff);
93 | [self.view addSubview:qrCodeView];
94 | self.qrCodeView = qrCodeView;
95 |
96 |
97 | UIImageView *qrCodeImageView = [[UIImageView alloc] init];
98 | qrCodeImageView.contentMode = UIViewContentModeScaleAspectFit;
99 | qrCodeImageView.backgroundColor = [UIColor redColor];
100 | [qrCodeView addSubview:qrCodeImageView];
101 | self.qrCodeImageView = qrCodeImageView;
102 |
103 |
104 | UILabel *nicknameLabel = [UILabel czh_setLabelWithFrame:CGRectZero font:CZHGlobelNormalFont(16) textColor:CZHColor(0x000000) textAliment:NSTextAlignmentCenter text:nil];
105 | [self.view addSubview:nicknameLabel];
106 | self.nicknameLabel = nicknameLabel;
107 |
108 |
109 |
110 | UILabel *idNumberLabel = [UILabel czh_setLabelWithFrame:CGRectZero font:CZHGlobelNormalFont(13) textColor:CZHColor(0x000000) textAliment:NSTextAlignmentCenter text:nil];
111 | [self.view addSubview:idNumberLabel];
112 | self.idNumberLabel = idNumberLabel;
113 |
114 |
115 | UILabel *fansLabel = [UILabel czh_setLabelWithFrame:CGRectZero font:CZHGlobelNormalFont(14) textColor:CZHColor(0xffffff) backgroundColor:CZHColor(0x000000) textAliment:NSTextAlignmentCenter text:nil];
116 | [self.view addSubview:fansLabel];
117 | self.fansLabel = fansLabel;
118 |
119 |
120 | UILabel *charmLabel = [UILabel czh_setLabelWithFrame:CGRectZero font:CZHGlobelNormalFont(14) textColor:CZHColor(0xffffff) backgroundColor:CZHColor(0xF578B3) textAliment:NSTextAlignmentCenter text:nil];
121 | [self.view addSubview:charmLabel];
122 | self.charmLabel = charmLabel;
123 |
124 |
125 | UILabel *tipLabel = [UILabel czh_setLabelWithFrame:CGRectZero font:CZHGlobelNormalFont(12) textColor:CZHColor(0x999999) textAliment:NSTextAlignmentCenter text:@"长按图片,识别二维码,和她一对一私密视频聊天"];
126 | [self.view addSubview:tipLabel];
127 | self.tipLabel = tipLabel;
128 |
129 | }
130 |
131 |
132 | - (void)viewWillLayoutSubviews {
133 | [super viewWillLayoutSubviews];
134 |
135 | self.headIconimageView.frame = CGRectMake(0, 0, ScreenWidth, CZH_ScaleWidth(300));
136 |
137 |
138 | CGFloat qrCodeViewW = CZH_ScaleWidth(100);
139 | CGFloat qrCodeViewH = CZH_ScaleWidth(100);
140 | CGFloat qrCodeViewY = self.headIconimageView.czh_bottom - qrCodeViewH * 0.5;
141 | CGFloat qrCodeViewX = (self.view.czh_width - qrCodeViewW) * 0.5;
142 | CGRect qrCodeViewF = CGRectMake(qrCodeViewX, qrCodeViewY, qrCodeViewW, qrCodeViewH);
143 | self.qrCodeView.frame = qrCodeViewF;
144 |
145 | CGFloat qrCodeImageViewX = CZH_ScaleWidth(5);
146 | CGFloat qrCodeImageViewY = CZH_ScaleWidth(5);
147 | CGFloat qrCodeImageViewW = self.qrCodeView.czh_width - qrCodeImageViewX * 2;
148 | CGFloat qrCodeImageViewH = self.qrCodeView.czh_height - qrCodeImageViewY * 2;
149 | CGRect qrCodeImageViewF = CGRectMake(qrCodeImageViewX, qrCodeImageViewY, qrCodeImageViewW, qrCodeImageViewH);
150 | self.qrCodeImageView.frame = qrCodeImageViewF;
151 |
152 |
153 |
154 | CGFloat nicknameLabelX = 0;
155 | CGFloat nicknameLabelY = self.qrCodeView.czh_bottom + CZH_ScaleWidth(5);
156 | CGFloat nicknameLabelW = self.view.czh_width;
157 | CGFloat nicknameLabelH = CZH_ScaleWidth(17);
158 | CGRect nicknameLabelF = CGRectMake(nicknameLabelX, nicknameLabelY, nicknameLabelW, nicknameLabelH);
159 | self.nicknameLabel.frame = nicknameLabelF;
160 |
161 |
162 | CGFloat idNumberLabelX = 0;
163 | CGFloat idNumberLabelY = self.qrCodeView.czh_bottom + CZH_ScaleWidth(36);
164 | CGFloat idNumberLabelW = self.view.czh_width;
165 | CGFloat idNumberLabelH = CZH_ScaleWidth(14);
166 | CGRect idNumberLabelF = CGRectMake(idNumberLabelX, idNumberLabelY, idNumberLabelW, idNumberLabelH);
167 | self.idNumberLabel.frame = idNumberLabelF;
168 |
169 |
170 | CGFloat fansLabelW = CZH_ScaleWidth(90);
171 | CGFloat fansLabelH = CZH_ScaleWidth(25);
172 | CGFloat fansLabelX = self.view.czh_width * 0.5 - fansLabelW - CZH_ScaleWidth(7.5);
173 | CGFloat fansLabelY = self.qrCodeView.czh_bottom + CZH_ScaleWidth(62);
174 | CGRect fansLabelF = CGRectMake(fansLabelX, fansLabelY, fansLabelW, fansLabelH);
175 | self.fansLabel.frame = fansLabelF;
176 | [self.fansLabel czh_cornerAllCornersWithCornerRadius:fansLabelH* 0.5];
177 |
178 | CGFloat charmLabelW = fansLabelW;
179 | CGFloat charmLabelH = fansLabelH;
180 | CGFloat charmLabelX = self.view.czh_width * 0.5 + CZH_ScaleWidth(7.5);
181 | CGFloat charmLabelY = fansLabelY;
182 | CGRect charmLabelF = CGRectMake(charmLabelX, charmLabelY, charmLabelW, charmLabelH);
183 | self.charmLabel.frame = charmLabelF;
184 | [self.charmLabel czh_cornerAllCornersWithCornerRadius:charmLabelH* 0.5];
185 |
186 | CGFloat tipLabelX = 0;
187 | CGFloat tipLabelY = self.qrCodeView.czh_bottom + CZH_ScaleWidth(106);
188 | CGFloat tipLabelW = self.view.czh_width;
189 | CGFloat tipLabelH = CZH_ScaleWidth(13);
190 | CGRect tipLabelF = CGRectMake(tipLabelX, tipLabelY, tipLabelW, tipLabelH);
191 | self.tipLabel.frame = tipLabelF;
192 |
193 |
194 | }
195 |
196 | @end
197 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHShowSyntheticImageView.h:
--------------------------------------------------------------------------------
1 | //
2 | // CZHShowSyntheticImageView.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CZHShowSyntheticImageView : UIView
12 |
13 | + (instancetype)czh_showSyntheticImageViewWithImage:(UIImage *)image;
14 |
15 | + (instancetype)czh_showSyntheticImageViewWithImage:(UIImage *)image isScreenShot:(BOOL)isScreenShot;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHShowSyntheticImageView.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHShowSyntheticImageView.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "CZHShowSyntheticImageView.h"
10 | #import "Header.h"
11 |
12 | @interface CZHShowSyntheticImageView ()
13 |
14 | ///<#注释#>
15 | @property (nonatomic, strong) UIImage *syntheticImage;
16 | ///<#注释#>
17 | @property (nonatomic, weak) UIImageView *syntheticImageView;
18 | ///<#注释#>
19 | @property (nonatomic, assign) BOOL isScreenShot;
20 | @end
21 |
22 | @implementation CZHShowSyntheticImageView
23 |
24 |
25 | + (instancetype)czh_showSyntheticImageViewWithImage:(UIImage *)image isScreenShot:(BOOL)isScreenShot {
26 |
27 | CZHShowSyntheticImageView *view = [[CZHShowSyntheticImageView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight) syntheticImage:image isScreenShot:isScreenShot];
28 |
29 | [view czh_showView];
30 |
31 | return view;
32 |
33 | }
34 |
35 | + (instancetype)czh_showSyntheticImageViewWithImage:(UIImage *)image {
36 |
37 |
38 | return [self czh_showSyntheticImageViewWithImage:image isScreenShot:NO];
39 | }
40 |
41 | - (instancetype)initWithFrame:(CGRect)frame syntheticImage:(UIImage *)syntheticImage isScreenShot:(BOOL)isScreenShot{
42 |
43 | if (self = [super initWithFrame:frame]) {
44 |
45 | self.syntheticImage = syntheticImage;
46 | self.isScreenShot = isScreenShot;
47 |
48 | CGFloat syntheticImageViewW = syntheticImage.size.width;
49 | CGFloat syntheticImageViewH = syntheticImage.size.height;
50 |
51 | if (isScreenShot == YES) {//如果是截屏的
52 | syntheticImageViewW = ScreenWidth * 0.5;
53 | syntheticImageViewH = ScreenHeight * 0.5;
54 | }
55 |
56 | CGFloat syntheticImageViewX = (self.czh_width - syntheticImageViewW) * 0.5;
57 | CGFloat syntheticImageViewY = (self.czh_height - syntheticImageViewH) * 0.5;
58 | CGRect syntheticImageViewF = CGRectMake(syntheticImageViewX, syntheticImageViewY, syntheticImageViewW, syntheticImageViewH);
59 |
60 |
61 | UIImageView *syntheticImageView = [[UIImageView alloc] init];
62 |
63 | syntheticImageView.frame = syntheticImageViewF;
64 |
65 | syntheticImageView.image = syntheticImage;
66 |
67 | [self addSubview:syntheticImageView];
68 |
69 | self.syntheticImageView = syntheticImageView;
70 |
71 |
72 | }
73 | return self;
74 | }
75 |
76 | - (void)czh_showView {
77 |
78 |
79 | [[UIApplication sharedApplication].keyWindow addSubview:self];
80 |
81 | self.backgroundColor = [UIColor clearColor];
82 |
83 | self.syntheticImageView.alpha = 0;
84 |
85 | [UIView animateWithDuration:0.5 animations:^{
86 | self.backgroundColor = CZHRGBColor(0x000000, 0.6);
87 | self.syntheticImageView.alpha = 1;
88 | }];
89 |
90 |
91 | }
92 |
93 | - (void)czh_hideView {
94 |
95 | [UIView animateWithDuration:0.5 animations:^{
96 | self.backgroundColor = [UIColor clearColor];
97 | self.syntheticImageView.alpha = 0;
98 | } completion:^(BOOL finished) {
99 | [self removeFromSuperview];
100 | }];
101 | }
102 |
103 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
104 |
105 | [self czh_hideView];
106 |
107 | }
108 |
109 | @end
110 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHSyntheticLocalImageController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CZHSyntheticLocalImageController.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "CZHImagePickerBaseController.h"
11 |
12 | @interface CZHSyntheticLocalImageController : CZHImagePickerBaseController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHSyntheticLocalImageController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHSyntheticLocalImageController.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #define MARGIN_WIDTH CZH_ScaleWidth(10)
10 | #define MARGIN_HEIGHT CZH_ScaleWidth(10)
11 |
12 |
13 | #import "CZHSyntheticLocalImageController.h"
14 | #import "Header.h"
15 | #import "CZHShowSyntheticImageView.h"
16 | #import "CZHTipsView.h"
17 |
18 | typedef NS_ENUM(NSInteger, CZHButtonType) {
19 |
20 | CZHButtonTypeChooseFirst,
21 | CZHButtonTypeChooseSecond,
22 | CZHButtonTypeChooseSynthetic
23 | };
24 |
25 | @interface CZHSyntheticLocalImageController ()
26 |
27 | ///底部图片
28 | @property (nonatomic, weak) UIImageView *firstImageView;
29 | ///上面图片
30 | @property (nonatomic, weak) UIImageView *secondImageView;
31 | ///按钮类型
32 | @property (nonatomic, assign) CZHButtonType buttonType;
33 | @end
34 |
35 | @implementation CZHSyntheticLocalImageController
36 |
37 | - (void)viewDidLoad {
38 | [super viewDidLoad];
39 | self.view.backgroundColor = CZHColor(0xffffff);
40 |
41 |
42 | [self czh_setUpView];
43 | }
44 |
45 | - (void)czh_setUpView {
46 |
47 | [self czh_setUpButton];
48 |
49 | [self czh_setUpImageView];
50 | }
51 |
52 | - (void)injected
53 | {
54 | NSLog(@"I've been injected: %@", self);
55 | }
56 |
57 | - (void)czh_setUpImageView {
58 |
59 | CGFloat containerViewX = MARGIN_WIDTH;
60 | CGFloat containerViewY = CZH_ScaleWidth(50);
61 | CGFloat containerViewW = ScreenWidth - containerViewX * 2;
62 | CGFloat containerViewH = ScreenHeight - CZHNavigationBarHeight - CZHTabbarHeight - containerViewY - CZH_ScaleWidth(40);
63 | CGRect containerViewF = CGRectMake(containerViewX, containerViewY, containerViewW, containerViewH);
64 | UIView *containerView = [[UIView alloc] init];
65 | containerView.frame = containerViewF;
66 | containerView.layer.borderWidth = 1;
67 | containerView.layer.borderColor = CZHColor(0x000000).CGColor;
68 | [self.view addSubview:containerView];
69 |
70 |
71 | UIImageView *firstImageView = [[UIImageView alloc] init];
72 | firstImageView.frame = containerView.bounds;
73 | firstImageView.backgroundColor = CZHRGBColor(0xff0000, 0.3);
74 | [containerView addSubview:firstImageView];
75 | self.firstImageView = firstImageView;
76 |
77 |
78 | CGFloat secondImageViewX = 0;
79 | CGFloat secondImageViewY = 0;
80 | CGFloat secondImageViewW = 100;
81 | CGFloat secondImageViewH = 100;
82 | CGRect secondImageViewF = CGRectMake(secondImageViewX, secondImageViewY, secondImageViewW, secondImageViewH);
83 | UIImageView *secondImageView = [[UIImageView alloc] init];
84 | secondImageView.frame = secondImageViewF;
85 | secondImageView.userInteractionEnabled = YES;
86 | secondImageView.backgroundColor = CZHRGBColor(0x00ff00, 0.3);
87 | [containerView addSubview:secondImageView];
88 | self.secondImageView = secondImageView;
89 |
90 |
91 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(move:)];
92 | [secondImageView addGestureRecognizer:pan];
93 |
94 |
95 | CGFloat firstButtonX = MARGIN_WIDTH;
96 | CGFloat firstButtonY = containerView.czh_bottom + CZH_ScaleWidth(5);
97 | CGFloat firstButtonW = ScreenWidth - firstButtonX * 2;
98 | CGFloat firstButtonH = CZH_ScaleWidth(30);
99 | CGRect firstButtonF = CGRectMake(firstButtonX, firstButtonY, firstButtonW, firstButtonH);
100 | UIButton *SyntheticButton = [self czh_quickSetUpButtonWithFrame:firstButtonF buttonType:CZHButtonTypeChooseSynthetic title:@"合成"];
101 | [self.view addSubview:SyntheticButton];
102 |
103 | }
104 |
105 |
106 | - (void)czh_setUpButton {
107 |
108 | CGFloat buttonWidth = (ScreenWidth - MARGIN_WIDTH * 3) * 0.5;
109 | CGFloat buttonHeight = CZH_ScaleWidth(30);
110 |
111 | CGFloat firstButtonX = MARGIN_WIDTH;
112 | CGFloat firstButtonY = MARGIN_HEIGHT;
113 | CGFloat firstButtonW = buttonWidth;
114 | CGFloat firstButtonH = buttonHeight;
115 | CGRect firstButtonF = CGRectMake(firstButtonX, firstButtonY, firstButtonW, firstButtonH);
116 | UIButton *firstButton = [self czh_quickSetUpButtonWithFrame:firstButtonF buttonType:CZHButtonTypeChooseFirst title:@"选择底部图片"];
117 | [self.view addSubview:firstButton];
118 |
119 |
120 | CGFloat secondButtonX = firstButton.czh_right + MARGIN_WIDTH;
121 | CGFloat secondButtonY = firstButtonY;
122 | CGFloat secondButtonW = buttonWidth;
123 | CGFloat secondButtonH = buttonHeight;
124 | CGRect secondButtonF = CGRectMake(secondButtonX, secondButtonY, secondButtonW, secondButtonH);
125 | UIButton *secondButton = [self czh_quickSetUpButtonWithFrame:secondButtonF buttonType:CZHButtonTypeChooseSecond title:@"选择上面图片"];
126 | [self.view addSubview:secondButton];
127 | }
128 |
129 | - (void)move:(UIPanGestureRecognizer *)gr {
130 |
131 |
132 | CGPoint pt = [gr translationInView:self.firstImageView];
133 |
134 | self.secondImageView.czh_centerX += pt.x;
135 | self.secondImageView.czh_centerY += pt.y;
136 |
137 | [gr setTranslation:CGPointZero inView:self.firstImageView];
138 |
139 | }
140 |
141 | - (void)buttonClick:(UIButton *)sender {
142 |
143 | if (sender.tag == CZHButtonTypeChooseSynthetic) {
144 |
145 | // NSAssert(self.firstImageView.image != nil && self.secondImageView.image != nil , @"please choose picture");
146 |
147 | if (self.firstImageView.image != nil && self.secondImageView.image != nil) {//没有选择图片不能合成
148 |
149 |
150 | UIImage *firstImage = self.firstImageView.image;
151 |
152 | UIImage *secondImage = self.secondImageView.image;
153 |
154 | //以底部图片大小为画布创建上下文
155 | UIGraphicsBeginImageContext(CGSizeMake(self.firstImageView.czh_width, self.firstImageView.czh_height));
156 | [firstImage drawInRect:self.firstImageView.frame];//先把底部图片 画到上下文中
157 | [secondImage drawInRect:self.secondImageView.frame];//再把上面图片 放在上下文中
158 | UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();//从当前上下文中获得最终图片
159 | UIGraphicsEndImageContext();//关闭上下文
160 |
161 |
162 | [CZHShowSyntheticImageView czh_showSyntheticImageViewWithImage:resultImg];
163 |
164 | } else {
165 | [CZHTipsView czh_showTipsViewWithString:@"请选选择图片"];
166 | }
167 |
168 | } else {
169 | self.buttonType = sender.tag;
170 |
171 | CZHWeakSelf(self);
172 | [self showImagePickerControllerWithSuccessHandler:^(UIImage *image) {//选择图片
173 |
174 | CZHStrongSelf(self);
175 |
176 | if (self.buttonType == CZHButtonTypeChooseFirst) {
177 | self.firstImageView.image = image;
178 | } else if (self.buttonType == CZHButtonTypeChooseSecond) {
179 | self.secondImageView.image = image;
180 | }
181 |
182 | }];
183 | }
184 | }
185 |
186 |
187 |
188 | - (UIButton *)czh_quickSetUpButtonWithFrame:(CGRect)frame buttonType:(CZHButtonType)buttonType title:(NSString *)title {
189 |
190 | UIButton *button = [[UIButton alloc] init];
191 | button.frame = frame;
192 | button.tag = buttonType;
193 | [button setTitle:title forState:UIControlStateNormal];
194 | [button setTitleColor:CZHColor(0xffffff) forState:UIControlStateNormal];
195 | button.titleLabel.font = CZHGlobelNormalFont(12);
196 | [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
197 | button.backgroundColor = CZHColor(0x000000);
198 | button.titleLabel.numberOfLines = 0;
199 |
200 | return button;
201 |
202 | }
203 | @end
204 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHSyntheticNetworkImageController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CZHSyntheticNetworkImageController.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "CZHImagePickerBaseController.h"
11 |
12 | @interface CZHSyntheticNetworkImageController : CZHImagePickerBaseController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHSyntheticNetworkImageController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHSyntheticNetworkImageController.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "CZHSyntheticNetworkImageController.h"
10 | #import "Header.h"
11 | #import "CZHShowSyntheticImageView.h"
12 |
13 | typedef NS_ENUM(NSInteger, CZHButtonType) {
14 |
15 | CZHButtonTypeChooseFirst,
16 | CZHButtonTypeChooseSecond
17 | };
18 |
19 | @interface CZHSyntheticNetworkImageController ()
20 |
21 | @end
22 |
23 | @implementation CZHSyntheticNetworkImageController
24 |
25 | - (void)viewDidLoad {
26 | [super viewDidLoad];
27 |
28 | //适用分享视频连接的时候,需求是分享的图片需要带上播放图片,但是一般视频也只是有一个封面而已,所以需要自己把播放的图片跟封面合成一张
29 |
30 | [self czh_setUpView];
31 |
32 | }
33 |
34 | - (void)czh_setUpView {
35 |
36 |
37 | CGFloat SyntheticButtonX = CZH_ScaleWidth(10);
38 | CGFloat SyntheticButtonY = CZH_ScaleWidth(30);
39 | CGFloat SyntheticButtonW = ScreenWidth - SyntheticButtonX * 2;
40 | CGFloat SyntheticButtonH = CZH_ScaleWidth(30);
41 | CGRect SyntheticButtonF = CGRectMake(SyntheticButtonX, SyntheticButtonY, SyntheticButtonW, SyntheticButtonH);
42 | UIButton *SyntheticButton = [self czh_quickSetUpButtonWithFrame:SyntheticButtonF buttonType:CZHButtonTypeChooseFirst title:@"一张网络图片一张本地合成"];
43 | [self.view addSubview:SyntheticButton];
44 |
45 |
46 | CGFloat twoNetworkImageButtonX = CZH_ScaleWidth(10);
47 | CGFloat twoNetworkImageButtonY = SyntheticButton.czh_bottom + CZH_ScaleWidth(20);
48 | CGFloat twoNetworkImageButtonW = ScreenWidth - SyntheticButtonX * 2;
49 | CGFloat twoNetworkImageButtonH = CZH_ScaleWidth(30);
50 | CGRect twoNetworkImageButtonF = CGRectMake(twoNetworkImageButtonX, twoNetworkImageButtonY, twoNetworkImageButtonW, twoNetworkImageButtonH);
51 | UIButton *twoNetworkImageButton = [self czh_quickSetUpButtonWithFrame:twoNetworkImageButtonF buttonType:CZHButtonTypeChooseSecond title:@"两张网络图片合成"];
52 | [self.view addSubview:twoNetworkImageButton];
53 |
54 | }
55 |
56 | - (void)buttonClick:(UIButton *)sender {
57 |
58 |
59 | if (sender.tag == CZHButtonTypeChooseFirst) {
60 |
61 | [self czh_syntheticLocalAndNetWork];
62 |
63 | } else if (sender.tag == CZHButtonTypeChooseSecond) {
64 |
65 | [self czh_syntheticNetWork];
66 |
67 | }
68 | }
69 |
70 |
71 | - (void)czh_syntheticNetWork {
72 |
73 | NSString *firstUrl = @"http://static.yygo.tv/avatar/2/5a712bc7790f2.png";
74 |
75 | NSString *secondUrl = @"http://static.yygo.tv/avatar/2/5a5756e2dd94b.png";
76 |
77 | //
78 | czh_dispatch_queue_async_safe(dispatch_get_global_queue(0, 0), ^{
79 |
80 | //
81 | NSData *fistData = [NSData dataWithContentsOfURL:[NSURL URLWithString:firstUrl]];
82 |
83 | UIImage *firstImage = [UIImage imageWithData:fistData];
84 |
85 |
86 | CGFloat firstImageW = 0;
87 | CGFloat firstImageH = 0;
88 | if (firstImage.size.height > 0 && firstImage.size.width > 0) {
89 |
90 | if (firstImage.size.height > firstImage.size.width) {
91 | firstImageW = ScreenWidth;
92 | firstImageH = firstImageW * firstImage.size.height / firstImage.size.width;
93 | } else {
94 | firstImageH = ScreenWidth;
95 | firstImageW = firstImageH * firstImage.size.width / firstImage.size.height;
96 | }
97 | }
98 |
99 |
100 | NSData *secondData = [NSData dataWithContentsOfURL:[NSURL URLWithString:secondUrl]];
101 |
102 | UIImage *secondImage = [UIImage imageWithData:secondData];
103 |
104 |
105 | CGFloat secondImageW = 0;
106 | CGFloat secondImageH = 0;
107 | if (secondImage.size.height > 0 && secondImage.size.width > 0) {
108 |
109 | if (secondImage.size.height > secondImage.size.width) {
110 | secondImageW = ScreenWidth;
111 | secondImageH = secondImageW * secondImage.size.height / secondImage.size.width;
112 | } else {
113 | secondImageH = ScreenWidth;
114 | secondImageW = secondImageH * secondImage.size.width / secondImage.size.height;
115 | }
116 | }
117 |
118 |
119 | //固定的大小为画布创建上下文
120 | UIGraphicsBeginImageContext(CGSizeMake(ScreenWidth, ScreenWidth));
121 |
122 | [firstImage drawInRect:CGRectMake((ScreenWidth - firstImageW)*0.5, (ScreenWidth - firstImageH)* 0.5, firstImageW, firstImageH)];//先把网络封面图片放在下面
123 |
124 | [secondImage drawInRect:CGRectMake((ScreenWidth - secondImageW * 0.5)*0.5, (ScreenWidth - secondImageH * 0.5)*0.5, secondImageW * 0.5, secondImageH * 0.5)];//再把小图放在上面
125 |
126 | //需要合成更多,继续添加
127 |
128 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();//从当前上下文中获得最终图片
129 | UIGraphicsEndImageContext();//关闭上下文
130 |
131 | czh_dispatch_main_sync_safe(^{
132 |
133 | [CZHShowSyntheticImageView czh_showSyntheticImageViewWithImage:resultImage];
134 | });
135 |
136 |
137 | });
138 |
139 | }
140 |
141 | - (void)czh_syntheticLocalAndNetWork {
142 |
143 | NSString *url = @"http://static.yygo.tv/avatar/2/5a712bc7790f2.png";
144 |
145 | // @"http://static.yygo.tv/avatar/2/5a5756e2dd94b.png"
146 | czh_dispatch_queue_async_safe(dispatch_get_global_queue(0, 0), ^{
147 |
148 | //
149 | NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
150 |
151 | UIImage *networkImage = [UIImage imageWithData:data];
152 | CGFloat networkImageW = 0;
153 | CGFloat networkImageH = 0;
154 | if (networkImage.size.height > 0 && networkImage.size.width > 0) {
155 |
156 | if (networkImage.size.height > networkImage.size.width) {
157 | networkImageW = ScreenWidth;
158 | networkImageH = networkImageW * networkImage.size.height / networkImage.size.width;
159 | } else {
160 | networkImageH = ScreenWidth;
161 | networkImageW = networkImageH * networkImage.size.width / networkImage.size.height;
162 | }
163 | }
164 |
165 | UIImage *localImage = [UIImage imageNamed:@"share_play"];
166 | CGFloat localImageW = localImage.size.width;
167 | CGFloat localImageH = localImage.size.height;
168 |
169 |
170 | //固定的大小为画布创建上下文
171 | UIGraphicsBeginImageContext(CGSizeMake(ScreenWidth, ScreenWidth));
172 |
173 | [networkImage drawInRect:CGRectMake((ScreenWidth - networkImageW)*0.5, (ScreenWidth - networkImageH)* 0.5, networkImageW, networkImageH)];//先把网络封面图片放在下面
174 |
175 | [localImage drawInRect:CGRectMake((ScreenWidth - localImageW)*0.5, (ScreenWidth - localImageH)*0.5, localImageW, localImageH)];//再把小图放在上面
176 |
177 | //需要合成更多,继续添加
178 |
179 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();//从当前上下文中获得最终图片
180 | UIGraphicsEndImageContext();//关闭上下文
181 |
182 | czh_dispatch_main_sync_safe(^{
183 |
184 | [CZHShowSyntheticImageView czh_showSyntheticImageViewWithImage:resultImage];
185 | });
186 |
187 |
188 |
189 | // NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
190 | // NSString *filePath = [path stringByAppendingPathComponent:@"01.png"];
191 | // [UIImagePNGRepresentation(resultlocalImage) writeToFile:filePath atomically:YES];//保存图片到沙盒
192 |
193 |
194 | });
195 |
196 | }
197 |
198 |
199 |
200 | - (UIButton *)czh_quickSetUpButtonWithFrame:(CGRect)frame buttonType:(CZHButtonType)buttonType title:(NSString *)title {
201 |
202 | UIButton *button = [[UIButton alloc] init];
203 | button.frame = frame;
204 | button.tag = buttonType;
205 | [button setTitle:title forState:UIControlStateNormal];
206 | [button setTitleColor:CZHColor(0xffffff) forState:UIControlStateNormal];
207 | button.titleLabel.font = CZHGlobelNormalFont(12);
208 | [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
209 | button.backgroundColor = CZHColor(0x000000);
210 | button.titleLabel.numberOfLines = 0;
211 |
212 | return button;
213 |
214 | }
215 |
216 |
217 |
218 | @end
219 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHTabBarController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CZHTabBarController.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CZHTabBarController : UITabBarController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHTabBarController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHTabBarController.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "CZHTabBarController.h"
10 | #import "CZHNavigationController.h"
11 | #import "CZHSyntheticNetworkImageController.h"
12 | #import "CZHSyntheticLocalImageController.h"
13 | #import "CZHShareLocalViewController.h"
14 |
15 | @interface CZHTabBarController ()
16 |
17 | @end
18 |
19 | @implementation CZHTabBarController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | self.tabBar.translucent = NO;
24 |
25 | // 添加所有子控制器
26 | [self czh_setUpAllChildViewController];
27 |
28 | }
29 |
30 |
31 | - (void)czh_setUpAllChildViewController {
32 |
33 | CZHSyntheticLocalImageController *localVc = [[CZHSyntheticLocalImageController alloc] init];
34 | CZHNavigationController *localNavi = [self czh_setUpOneChildViewController:localVc image:@"" selectedImage:@"" title:@"本地图片合成"];
35 | [self addChildViewController:localNavi];
36 |
37 |
38 | CZHSyntheticNetworkImageController *networkVc = [[CZHSyntheticNetworkImageController alloc] init];
39 | CZHNavigationController *networkNavi = [self czh_setUpOneChildViewController:networkVc image:@"" selectedImage:@"" title:@"网络图片合成"];
40 | [self addChildViewController:networkNavi];
41 |
42 |
43 | CZHShareLocalViewController *shareVc = [[CZHShareLocalViewController alloc] init];
44 | CZHNavigationController *shareVcNavi = [self czh_setUpOneChildViewController:shareVc image:@"" selectedImage:@"" title:@"分享本地视图"];
45 | [self addChildViewController:shareVcNavi];
46 |
47 | }
48 |
49 | - (CZHNavigationController *)czh_setUpOneChildViewController:(UIViewController *)vc image:(NSString *)image selectedImage:(NSString *)selectedImage title:(NSString *)title
50 | {
51 |
52 | vc.title = title;
53 | vc.tabBarItem.image = [UIImage imageNamed:image];
54 | vc.tabBarItem.selectedImage = [UIImage imageNamed:selectedImage];;
55 |
56 | // vc.tabBarItem.imageInsets = UIEdgeInsetsMake(-2, 0, 2, 0);
57 | // vc.tabBarItem.titlePositionAdjustment = UIOffsetMake(0, -1);
58 |
59 | CZHNavigationController *nav = [[CZHNavigationController alloc] initWithRootViewController:vc];
60 |
61 | return nav;
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHTipsView.h:
--------------------------------------------------------------------------------
1 | //
2 | // CZHTipsView.h
3 | // SexChat
4 | //
5 | // Created by 江焰 on 2018/4/2.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface CZHTipsView : UIView
13 |
14 | ///标题
15 | @property (nonatomic, strong) NSString *tipsTitle;
16 | ///提示字体大小
17 | @property (nonatomic, strong) UIFont *tipsFont;
18 | ///字体颜色
19 | @property (nonatomic, strong) UIColor *tipsColor;
20 | ///底部view的颜色
21 | @property (nonatomic, strong) UIColor *bottomViewColor;
22 |
23 | //+ (instancetype)tipsView;
24 |
25 | - (void)czh_show;
26 |
27 | ///和显示的view是同一个
28 | + (void)czh_hideTipsFromeView:(UIView *)view;
29 | //默认在keywindow
30 | + (void)czh_showTipsViewWithString:(NSString *)string enableClick:(BOOL)enableClick;
31 |
32 | + (void)czh_showTipsViewWithString:(NSString *)string durationTime:(CGFloat)durationTime enableClick:(BOOL)enableClick;
33 | //自己确定加在那个view上面
34 | + (void)czh_showTipsViewWithString:(NSString *)string withView:(UIView *)view enableClick:(BOOL)enableClick;
35 | //默认在keywindow
36 | + (void)czh_showTipsViewWithString:(NSString *)string;
37 |
38 | + (void)czh_showTipsViewWithString:(NSString *)string durationTime:(CGFloat)durationTime;
39 | //自己确定加在那个view上面
40 | + (void)czh_showTipsViewWithString:(NSString *)string withView:(UIView *)view;
41 |
42 | + (void)czh_hideTips;
43 |
44 | /**
45 | * 自己确定加在那个view上面,持续几秒消失
46 | *
47 | * string : 提示文字
48 | * durationTime : 持续时间, 为负数的时候不消失,需要手动调用隐藏
49 | * view : 显示在哪个view上面
50 | * enableClick : 默认是yes,如果为no,tips显示的时候不可点击
51 | */
52 | + (void)czh_showTipsViewWithString:(NSString *)string durationTime:(CGFloat)durationTime withView:(UIView *)view enableClick:(BOOL)enableClick;
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/CZHTipsView.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHTipsView.m
3 | // SexChat
4 | //
5 | // Created by 江焰 on 2018/4/2.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "CZHTipsView.h"
10 | #import "Header.h"
11 | #import "AppDelegate.h"
12 |
13 | @interface CZHTipsView ()
14 |
15 | ///<#注释#>
16 | @property (nonatomic, weak) UILabel *tipsLabel;
17 | ///<#注释#>
18 | @property (nonatomic, weak) UIView *tipsBottomView;
19 |
20 | @property (nonatomic, assign) CGFloat durationTime;
21 |
22 | @property (nonatomic, assign) dispatch_source_t timer;
23 |
24 | @property (nonatomic, assign) BOOL canClick;
25 |
26 | @end
27 |
28 | @implementation CZHTipsView
29 |
30 | + (instancetype)tipsViewWithString:(NSString *)string durationTime:(CGFloat)durationTime withView:(UIView *)view enableClick:(BOOL)enableClick{
31 | static CZHTipsView *_tips = nil;
32 | static dispatch_once_t onceToken;
33 | dispatch_once(&onceToken, ^{
34 | _tips = [[CZHTipsView alloc] init];
35 | });
36 | // ONSLog(@"====%@===%@", _tips.superview, view);
37 | if (_tips.superview != nil && _tips.superview != view) {//如果有父视图,表示加过,直接返回
38 | // ONSLog(@"====%@===%@", _tips.tipsLabel.text, _tips.tipsTitle);
39 | if (![string isEqualToString:_tips.tipsLabel.text]) {
40 | _tips.durationTime = durationTime;
41 | _tips.canClick = enableClick;
42 |
43 | _tips.tipsLabel.text = string;
44 |
45 | }
46 | } else if (_tips.superview == nil) {
47 | if (durationTime > 0) {
48 | [_tips createTime];
49 | }
50 | } else if (_tips.superview == view) {
51 | if (durationTime > 0) {
52 | [_tips createTime];
53 | }
54 | }
55 |
56 | [_tips czh_showView];
57 | return _tips;
58 | }
59 |
60 |
61 | - (instancetype)init {
62 | if (self = [super init]) {
63 |
64 | [self setView];
65 |
66 | }
67 | return self;
68 | }
69 |
70 | //设置默认属性值
71 | - (void)setFrame:(CGRect)frame {
72 | [super setFrame:frame];
73 |
74 | _tipsTitle = @"O(∩_∩)O哈哈哈~";
75 | _tipsFont = CZHGlobelNormalFont(14);
76 | _tipsColor = CZHColor(0xffffff);
77 | _bottomViewColor = CZHColor(0x333333);
78 | _canClick = YES;
79 | // _durationTime = 3;
80 | }
81 |
82 |
83 | - (void)setView {
84 |
85 | self.alpha = 0;
86 |
87 | UIView *tipsBottomView = [[UIView alloc] init];
88 | tipsBottomView.backgroundColor = _bottomViewColor;
89 | tipsBottomView.layer.shadowColor = CZHRGBColor(0x323232, 0.36).CGColor;
90 | tipsBottomView.layer.shadowOffset = CGSizeMake(1, 1);
91 | tipsBottomView.layer.shadowRadius = 6.0;
92 | tipsBottomView.layer.shadowOpacity = 1;
93 | [self addSubview:tipsBottomView];
94 | self.tipsBottomView = tipsBottomView;
95 |
96 |
97 | UILabel *tipsLabel = [[UILabel alloc] init];
98 | tipsLabel.numberOfLines = 0;
99 | tipsLabel.font = _tipsFont;
100 | tipsLabel.textColor = _tipsColor;
101 | tipsLabel.textAlignment = NSTextAlignmentCenter;
102 | [tipsBottomView addSubview:tipsLabel];
103 | self.tipsLabel = tipsLabel;
104 |
105 |
106 | }
107 |
108 | - (void)setTipsTitle:(NSString *)tipsTitle {
109 | _tipsTitle = tipsTitle;
110 | self.tipsLabel.text = tipsTitle;
111 | [self layoutSubviews];
112 | }
113 |
114 | - (void)setTipsFont:(UIFont *)tipsFont {
115 | _tipsFont = tipsFont;
116 | self.tipsLabel.font = tipsFont;
117 | // [self layoutSubviews];
118 | }
119 |
120 | - (void)setTipsColor:(UIColor *)tipsColor {
121 | _tipsColor = tipsColor;
122 | self.tipsColor = tipsColor;
123 | }
124 |
125 |
126 | - (void)setBottomViewColor:(UIColor *)bottomViewColor {
127 | _bottomViewColor = bottomViewColor;
128 | self.tipsBottomView.backgroundColor = bottomViewColor;
129 | }
130 |
131 |
132 | - (void)layoutSubviews {
133 | [super layoutSubviews];
134 |
135 | CGFloat maxW = ScreenWidth - CZH_ScaleWidth(60);
136 | CGSize tipsLabelSize = [_tipsTitle czh_sizeWithFont:_tipsFont maxW:maxW];
137 |
138 | CGFloat tipsLabelX = CZH_ScaleWidth(21);
139 | CGFloat tipsLabelY = CZH_ScaleWidth(10);
140 | CGFloat tipsLabelW = tipsLabelSize.width;
141 | CGFloat tipsLabelH = tipsLabelSize.height;
142 | self.tipsLabel.frame = CGRectMake(tipsLabelX, tipsLabelY, tipsLabelW, tipsLabelH);
143 |
144 |
145 |
146 |
147 | CGFloat tipsBottomViewW = CGRectGetMaxX(self.tipsLabel.frame) + CZH_ScaleWidth(21);
148 | CGFloat tipsBottomViewH = CGRectGetMaxY(self.tipsLabel.frame) + CZH_ScaleWidth(10);
149 | self.tipsBottomView.frame = CGRectMake(0, 0, tipsBottomViewW, tipsBottomViewH);
150 | self.tipsBottomView.czh_centerX = ScreenWidth * 0.5;
151 |
152 | //获取view的控制器
153 | UIViewController *vc = [self View:self.superview];
154 |
155 | // ONSLog(@"+++++%@===%@===%d", self.superview, [self View:self.superview], vc.navigationController.navigationBar.isHidden);
156 |
157 |
158 |
159 | if (self.superview == nil) {
160 | self.tipsBottomView.czh_centerY = ScreenHeight * 0.5;
161 | } else if (self.superview != nil && vc == nil) {
162 | self.tipsBottomView.czh_centerY = ScreenHeight * 0.5;
163 | } else if (vc != nil) {
164 | if (vc.navigationController.navigationBar.isHidden) {//控制器的导航栏被隐藏
165 | self.tipsBottomView.czh_centerY = ScreenHeight * 0.5;
166 | } else {
167 | self.tipsBottomView.czh_centerY = (ScreenHeight - CZHNavigationBarHeight) * 0.5 - 32;
168 | }
169 | }
170 |
171 |
172 | self.tipsBottomView.layer.cornerRadius = self.tipsBottomView.czh_height * 0.5;
173 |
174 | // ONSLog(@"----%@+++%@", NSStringFromCGRect(self.tipsLabel.frame), NSStringFromCGRect(self.tipsBottomView.frame));
175 | }
176 |
177 | //可以获取到父容器的控制器的方法,就是这个黑科技.
178 | - (UIViewController *)View:(UIView *)view{
179 | UIResponder *responder = view;
180 | //循环获取下一个响应者,直到响应者是一个UIViewController类的一个对象为止,然后返回该对象.
181 | while ((responder = [responder nextResponder])) {
182 | if ([responder isKindOfClass:[UIViewController class]]) {
183 | return (UIViewController *)responder;
184 | }
185 | }
186 | return nil;
187 | }
188 |
189 | - (void)czh_showView {
190 |
191 | if (self.superview == nil) {
192 | [UIView animateWithDuration:0.3 animations:^{
193 | self.alpha = 1;
194 | } completion:^(BOOL finished) {
195 |
196 | }];
197 | }
198 |
199 | if (_durationTime <= 0) {
200 |
201 | return ;
202 | }
203 |
204 | [self createTime];
205 |
206 | }
207 |
208 | - (void)createTime {
209 |
210 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
211 | //创建一个定时器
212 | self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
213 | //设置开始时间
214 | dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC));
215 | //设置时间间隔
216 | uint64_t interval = (uint64_t)(0.1* NSEC_PER_SEC);
217 | //设置定时器
218 | dispatch_source_set_timer(self.timer, start, interval, 0.0 * NSEC_PER_SEC);
219 | //设置回调
220 | dispatch_source_set_event_handler(self.timer, ^{
221 |
222 | self.durationTime -= 0.1;
223 | // ONSLog(@"+++++++%f", self.durationTime);
224 | dispatch_async(dispatch_get_main_queue(), ^{
225 |
226 | if (self.durationTime <= 0) {
227 | dispatch_cancel(self.timer);
228 | [UIView animateWithDuration:0.3 animations:^{
229 | self.alpha = 0;
230 | } completion:^(BOOL finished) {
231 | [self removeFromSuperview];
232 | }];
233 | }
234 | });
235 | });
236 | //由于定时器默认是暂停的所以我们启动一下
237 | //启动定时器
238 | dispatch_resume(self.timer);
239 | }
240 |
241 |
242 |
243 | + (void)czh_hideTips {
244 | AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
245 | [CZHTipsView czh_hideTipsFromeView:app.window];
246 | }
247 |
248 | + (void)czh_hideTipsFromeView:(UIView *)view {
249 |
250 | for (UIView *subView in view.subviews) {
251 | if ([subView isKindOfClass:[CZHTipsView class]]) {
252 | [UIView animateWithDuration:0.3 animations:^{
253 | subView.alpha = 0;
254 | } completion:^(BOOL finished) {
255 | [subView removeFromSuperview];
256 | }];
257 | }
258 | }
259 | }
260 |
261 | - (void)show {
262 | [[UIApplication sharedApplication].keyWindow addSubview:self];
263 | }
264 |
265 |
266 | //默认在keywindow
267 | + (void)czh_showTipsViewWithString:(NSString *)string enableClick:(BOOL)enableClick {
268 |
269 | AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
270 |
271 | [CZHTipsView czh_showTipsViewWithString:string durationTime:3 withView:app.window enableClick:enableClick];
272 | }
273 |
274 | + (void)czh_showTipsViewWithString:(NSString *)string durationTime:(CGFloat)durationTime enableClick:(BOOL)enableClick {
275 |
276 | AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
277 |
278 | [CZHTipsView czh_showTipsViewWithString:string durationTime:durationTime withView:app.window enableClick:enableClick];
279 | }
280 | //自己确定加在那个view上面
281 | + (void)czh_showTipsViewWithString:(NSString *)string withView:(UIView *)view enableClick:(BOOL)enableClick {
282 | AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
283 | [CZHTipsView czh_showTipsViewWithString:string durationTime:3 withView:app.window enableClick:enableClick];
284 | }
285 |
286 |
287 | + (void)czh_showTipsViewWithString:(NSString *)string {
288 |
289 | AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
290 |
291 | [CZHTipsView czh_showTipsViewWithString:string durationTime:3 withView:app.window enableClick:YES];
292 | }
293 |
294 | + (void)czh_showTipsViewWithString:(NSString *)string durationTime:(CGFloat)durationTime {
295 |
296 | AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
297 |
298 | [CZHTipsView czh_showTipsViewWithString:string durationTime:durationTime withView:app.window enableClick:YES];
299 | }
300 |
301 |
302 | + (void)czh_showTipsViewWithString:(NSString *)string withView:(UIView *)view {
303 | AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
304 | [CZHTipsView czh_showTipsViewWithString:string durationTime:3 withView:app.window enableClick:YES];
305 | }
306 |
307 | + (void)czh_showTipsViewWithString:(NSString *)string durationTime:(CGFloat)durationTime withView:(UIView *)view enableClick:(BOOL)enableClick{
308 |
309 | CZHTipsView *tips = [CZHTipsView tipsViewWithString:string durationTime:(CGFloat)durationTime withView:(UIView *)view enableClick:(BOOL)enableClick];
310 | tips.durationTime = durationTime;
311 | if (!enableClick) {
312 | tips.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);
313 | }else {
314 | tips.frame = CGRectZero;
315 | }
316 | tips.tipsTitle = string;
317 |
318 | // AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
319 | [view addSubview:tips];
320 |
321 | }
322 |
323 | /*
324 | // Only override drawRect: if you perform custom drawing.
325 | // An empty implementation adversely affects performance during animation.
326 | - (void)drawRect:(CGRect)rect {
327 | // Drawing code
328 | }
329 | */
330 |
331 | @end
332 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Header.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #ifndef Header_h
10 | #define Header_h
11 |
12 |
13 | #import "UIView+CZHExtension.h"
14 | #import "NSString+CZHSizeExtension.h"
15 | #import "UILabel+CZHExtension.h"
16 |
17 |
18 | ///weakSelf
19 | #define CZHWeakSelf(type) __weak typeof(type) weak##type = type;
20 | #define CZHStrongSelf(type) __strong typeof(type) type = weak##type;
21 |
22 | /**屏幕宽度*/
23 | #define ScreenWidth ([UIScreen mainScreen].bounds.size.width)
24 | /**屏幕高度*/
25 | #define ScreenHeight ([UIScreen mainScreen].bounds.size.height)
26 |
27 | /**全局字体*/
28 | #define CZHGlobelNormalFont(__VA_ARGS__) ([UIFont systemFontOfSize:CZH_ScaleFont(__VA_ARGS__)])
29 |
30 | /**宽度比例*/
31 | #define CZH_ScaleWidth(__VA_ARGS__) ([UIScreen mainScreen].bounds.size.width/375)*(__VA_ARGS__)
32 |
33 | /**高度比例*/
34 | #define CZH_ScaleHeight(__VA_ARGS__) ([UIScreen mainScreen].bounds.size.height/667)*(__VA_ARGS__)
35 |
36 | /**字体比例*/
37 | #define CZH_ScaleFont(__VA_ARGS__) ([UIScreen mainScreen].bounds.size.width/375)*(__VA_ARGS__)
38 |
39 | /**颜色*/
40 | #define CZHColor(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
41 |
42 | #define CZHRGBColor(rgbValue, a) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:a]
43 |
44 | /**yes:是iphoneX*/
45 | #define CZHIsiPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
46 |
47 | //状态栏高度
48 | #define CZHStatusHeight [[UIApplication sharedApplication] statusBarFrame].size.height
49 | /**导航栏高度*/
50 | #define CZHNavigationBarHeight (CZHIsiPhoneX ? 88 : 64)
51 |
52 | #define CZHTabbarHeight (CZHIsiPhoneX ? 83 : 49)
53 | //
54 | #define CZHSafeAreaBottomHeight (CZHIsiPhoneX ? 34 : 0)
55 |
56 |
57 | #ifndef czh_dispatch_queue_async_safe
58 | #define czh_dispatch_queue_async_safe(queue, block)\
59 | if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(queue)) == 0) {\
60 | block();\
61 | } else {\
62 | dispatch_async(queue, block);\
63 | }
64 | #endif
65 |
66 | #ifndef czh_dispatch_main_sync_safe
67 | #define czh_dispatch_main_sync_safe(block) czh_dispatch_queue_async_safe(dispatch_get_main_queue(), block)
68 | #endif
69 |
70 |
71 | #endif /* Header_h */
72 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 |
10 | NSPhotoLibraryUsageDescription
11 | app需要使用你的相册
12 | CFBundleDevelopmentRegion
13 | $(DEVELOPMENT_LANGUAGE)
14 | CFBundleExecutable
15 | $(EXECUTABLE_NAME)
16 | CFBundleIdentifier
17 | $(PRODUCT_BUNDLE_IDENTIFIER)
18 | CFBundleInfoDictionaryVersion
19 | 6.0
20 | CFBundleName
21 | $(PRODUCT_NAME)
22 | CFBundlePackageType
23 | APPL
24 | CFBundleShortVersionString
25 | 1.0
26 | CFBundleVersion
27 | 1
28 | LSRequiresIPhoneOS
29 |
30 | UILaunchStoryboardName
31 | LaunchScreen
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/NSString+CZHSizeExtension.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+CZHSizeExtension.h
3 | //
4 | //
5 | // Created by 程召华 on 2018/3/9.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface NSString (CZHSizeExtension)
13 |
14 | - (CGSize)czh_sizeWithFont:(UIFont *)font maxH:(CGFloat)maxH;
15 | - (CGSize)czh_sizeWithFont:(UIFont *)font maxW:(CGFloat)maxW;
16 | - (CGSize)czh_sizeWithFont:(UIFont *)font;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/NSString+CZHSizeExtension.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+CZHSizeExtension.m
3 | //
4 | //
5 | // Created by 程召华 on 2018/3/9.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "NSString+CZHSizeExtension.h"
10 |
11 | @implementation NSString (CZHSizeExtension)
12 |
13 | - (CGSize)czh_sizeWithFont:(UIFont *)font maxH:(CGFloat)maxH
14 | {
15 | NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
16 | attrs[NSFontAttributeName] = font;
17 | CGSize maxSize = CGSizeMake(MAXFLOAT, maxH);
18 |
19 |
20 | return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
21 | }
22 |
23 | - (CGSize)czh_sizeWithFont:(UIFont *)font maxW:(CGFloat)maxW
24 | {
25 |
26 | NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
27 | attrs[NSFontAttributeName] = font;
28 | CGSize maxSize = CGSizeMake(maxW, MAXFLOAT);
29 |
30 |
31 | return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
32 | }
33 |
34 | - (CGSize)czh_sizeWithFont:(UIFont *)font
35 | {
36 | return [self czh_sizeWithFont:font maxW:MAXFLOAT];
37 | }
38 |
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/NSBundle+TZImagePicker.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSBundle+TZImagePicker.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 16/08/18.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSBundle (TZImagePicker)
12 |
13 | + (NSBundle *)tz_imagePickerBundle;
14 |
15 | + (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value;
16 | + (NSString *)tz_localizedStringForKey:(NSString *)key;
17 |
18 | @end
19 |
20 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/NSBundle+TZImagePicker.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSBundle+TZImagePicker.m
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 16/08/18.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import "NSBundle+TZImagePicker.h"
10 | #import "TZImagePickerController.h"
11 |
12 | @implementation NSBundle (TZImagePicker)
13 |
14 | + (NSBundle *)tz_imagePickerBundle {
15 | NSBundle *bundle = [NSBundle bundleForClass:[TZImagePickerController class]];
16 | NSURL *url = [bundle URLForResource:@"TZImagePickerController" withExtension:@"bundle"];
17 | bundle = [NSBundle bundleWithURL:url];
18 | return bundle;
19 | }
20 |
21 | + (NSString *)tz_localizedStringForKey:(NSString *)key {
22 | return [self tz_localizedStringForKey:key value:@""];
23 | }
24 |
25 | + (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value {
26 | NSBundle *bundle = [TZImagePickerConfig sharedInstance].languageBundle;
27 | NSString *value1 = [bundle localizedStringForKey:key value:value table:nil];
28 | return value1;
29 | }
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZAssetCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZAssetCell.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | typedef enum : NSUInteger {
13 | TZAssetCellTypePhoto = 0,
14 | TZAssetCellTypeLivePhoto,
15 | TZAssetCellTypePhotoGif,
16 | TZAssetCellTypeVideo,
17 | TZAssetCellTypeAudio,
18 | } TZAssetCellType;
19 |
20 | @class TZAssetModel;
21 | @interface TZAssetCell : UICollectionViewCell
22 |
23 | @property (weak, nonatomic) UIButton *selectPhotoButton;
24 | @property (nonatomic, strong) TZAssetModel *model;
25 | @property (nonatomic, copy) void (^didSelectPhotoBlock)(BOOL);
26 | @property (nonatomic, assign) TZAssetCellType type;
27 | @property (nonatomic, assign) BOOL allowPickingGif;
28 | @property (nonatomic, assign) BOOL allowPickingMultipleVideo;
29 | @property (nonatomic, copy) NSString *representedAssetIdentifier;
30 | @property (nonatomic, assign) int32_t imageRequestID;
31 |
32 | @property (nonatomic, copy) NSString *photoSelImageName;
33 | @property (nonatomic, copy) NSString *photoDefImageName;
34 |
35 | @property (nonatomic, assign) BOOL showSelectBtn;
36 | @property (assign, nonatomic) BOOL allowPreview;
37 |
38 | @end
39 |
40 |
41 | @class TZAlbumModel;
42 |
43 | @interface TZAlbumCell : UITableViewCell
44 |
45 | @property (nonatomic, strong) TZAlbumModel *model;
46 | @property (weak, nonatomic) UIButton *selectedCountButton;
47 |
48 | @end
49 |
50 |
51 | @interface TZAssetCameraCell : UICollectionViewCell
52 |
53 | @property (nonatomic, strong) UIImageView *imageView;
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZAssetCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // TZAssetCell.m
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | //
8 |
9 | #import "TZAssetCell.h"
10 | #import "TZAssetModel.h"
11 | #import "UIView+Layout.h"
12 | #import "TZImageManager.h"
13 | #import "TZImagePickerController.h"
14 | #import "TZProgressView.h"
15 |
16 | @interface TZAssetCell ()
17 | @property (weak, nonatomic) UIImageView *imageView; // The photo / 照片
18 | @property (weak, nonatomic) UIImageView *selectImageView;
19 | @property (weak, nonatomic) UIView *bottomView;
20 | @property (weak, nonatomic) UILabel *timeLength;
21 |
22 | @property (nonatomic, weak) UIImageView *videoImgView;
23 | @property (nonatomic, strong) TZProgressView *progressView;
24 | @property (nonatomic, assign) int32_t bigImageRequestID;
25 | @end
26 |
27 | @implementation TZAssetCell
28 |
29 | - (void)setModel:(TZAssetModel *)model {
30 | _model = model;
31 | if (iOS8Later) {
32 | self.representedAssetIdentifier = [[TZImageManager manager] getAssetIdentifier:model.asset];
33 | }
34 | int32_t imageRequestID = [[TZImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.tz_width completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
35 | if (_progressView) {
36 | self.progressView.hidden = YES;
37 | self.imageView.alpha = 1.0;
38 | }
39 | // Set the cell's thumbnail image if it's still showing the same asset.
40 | if (!iOS8Later) {
41 | self.imageView.image = photo; return;
42 | }
43 | if ([self.representedAssetIdentifier isEqualToString:[[TZImageManager manager] getAssetIdentifier:model.asset]]) {
44 | self.imageView.image = photo;
45 | } else {
46 | // NSLog(@"this cell is showing other asset");
47 | [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
48 | }
49 | if (!isDegraded) {
50 | self.imageRequestID = 0;
51 | }
52 | } progressHandler:nil networkAccessAllowed:NO];
53 | if (imageRequestID && self.imageRequestID && imageRequestID != self.imageRequestID) {
54 | [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
55 | // NSLog(@"cancelImageRequest %d",self.imageRequestID);
56 | }
57 | self.imageRequestID = imageRequestID;
58 | self.selectPhotoButton.selected = model.isSelected;
59 | self.selectImageView.image = self.selectPhotoButton.isSelected ? [UIImage imageNamedFromMyBundle:self.photoSelImageName] : [UIImage imageNamedFromMyBundle:self.photoDefImageName];
60 | self.type = (NSInteger)model.type;
61 | // 让宽度/高度小于 最小可选照片尺寸 的图片不能选中
62 | if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) {
63 | if (_selectImageView.hidden == NO) {
64 | self.selectPhotoButton.hidden = YES;
65 | _selectImageView.hidden = YES;
66 | }
67 | }
68 | // 如果用户选中了该图片,提前获取一下大图
69 | if (model.isSelected) {
70 | [self fetchBigImage];
71 | }
72 | [self setNeedsLayout];
73 | }
74 |
75 | - (void)setShowSelectBtn:(BOOL)showSelectBtn {
76 | _showSelectBtn = showSelectBtn;
77 | if (!self.selectPhotoButton.hidden) {
78 | self.selectPhotoButton.hidden = !showSelectBtn;
79 | }
80 | if (!self.selectImageView.hidden) {
81 | self.selectImageView.hidden = !showSelectBtn;
82 | }
83 | }
84 |
85 | - (void)setType:(TZAssetCellType)type {
86 | _type = type;
87 | if (type == TZAssetCellTypePhoto || type == TZAssetCellTypeLivePhoto || (type == TZAssetCellTypePhotoGif && !self.allowPickingGif) || self.allowPickingMultipleVideo) {
88 | _selectImageView.hidden = NO;
89 | _selectPhotoButton.hidden = NO;
90 | _bottomView.hidden = YES;
91 | } else { // Video of Gif
92 | _selectImageView.hidden = YES;
93 | _selectPhotoButton.hidden = YES;
94 | }
95 |
96 | if (type == TZAssetCellTypeVideo) {
97 | self.bottomView.hidden = NO;
98 | self.timeLength.text = _model.timeLength;
99 | self.videoImgView.hidden = NO;
100 | _timeLength.tz_left = self.videoImgView.tz_right;
101 | _timeLength.textAlignment = NSTextAlignmentRight;
102 | } else if (type == TZAssetCellTypePhotoGif && self.allowPickingGif) {
103 | self.bottomView.hidden = NO;
104 | self.timeLength.text = @"GIF";
105 | self.videoImgView.hidden = YES;
106 | _timeLength.tz_left = 5;
107 | _timeLength.textAlignment = NSTextAlignmentLeft;
108 | }
109 | }
110 |
111 | - (void)selectPhotoButtonClick:(UIButton *)sender {
112 | if (self.didSelectPhotoBlock) {
113 | self.didSelectPhotoBlock(sender.isSelected);
114 | }
115 | self.selectImageView.image = sender.isSelected ? [UIImage imageNamedFromMyBundle:self.photoSelImageName] : [UIImage imageNamedFromMyBundle:self.photoDefImageName];
116 | if (sender.isSelected) {
117 | [UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:TZOscillatoryAnimationToBigger];
118 | // 用户选中了该图片,提前获取一下大图
119 | [self fetchBigImage];
120 | } else { // 取消选中,取消大图的获取
121 | if (_bigImageRequestID && _progressView) {
122 | [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID];
123 | [self hideProgressView];
124 | }
125 | }
126 | }
127 |
128 | - (void)hideProgressView {
129 | self.progressView.hidden = YES;
130 | self.imageView.alpha = 1.0;
131 | }
132 |
133 | - (void)fetchBigImage {
134 | _bigImageRequestID = [[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
135 | if (_progressView) {
136 | [self hideProgressView];
137 | }
138 | } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
139 | if (_model.isSelected) {
140 | progress = progress > 0.02 ? progress : 0.02;;
141 | self.progressView.progress = progress;
142 | self.progressView.hidden = NO;
143 | self.imageView.alpha = 0.4;
144 | if (progress >= 1) {
145 | [self hideProgressView];
146 | }
147 | } else {
148 | *stop = YES;
149 | [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
150 | }
151 | } networkAccessAllowed:YES];
152 | }
153 |
154 | #pragma mark - Lazy load
155 |
156 | - (UIButton *)selectPhotoButton {
157 | if (_selectImageView == nil) {
158 | UIButton *selectPhotoButton = [[UIButton alloc] init];
159 | [selectPhotoButton addTarget:self action:@selector(selectPhotoButtonClick:) forControlEvents:UIControlEventTouchUpInside];
160 | [self.contentView addSubview:selectPhotoButton];
161 | _selectPhotoButton = selectPhotoButton;
162 | }
163 | return _selectPhotoButton;
164 | }
165 |
166 | - (UIImageView *)imageView {
167 | if (_imageView == nil) {
168 | UIImageView *imageView = [[UIImageView alloc] init];
169 | imageView.contentMode = UIViewContentModeScaleAspectFill;
170 | imageView.clipsToBounds = YES;
171 | [self.contentView addSubview:imageView];
172 | _imageView = imageView;
173 |
174 | [self.contentView bringSubviewToFront:_selectImageView];
175 | [self.contentView bringSubviewToFront:_bottomView];
176 | }
177 | return _imageView;
178 | }
179 |
180 | - (UIImageView *)selectImageView {
181 | if (_selectImageView == nil) {
182 | UIImageView *selectImageView = [[UIImageView alloc] init];
183 | [self.contentView addSubview:selectImageView];
184 | _selectImageView = selectImageView;
185 | }
186 | return _selectImageView;
187 | }
188 |
189 | - (UIView *)bottomView {
190 | if (_bottomView == nil) {
191 | UIView *bottomView = [[UIView alloc] init];
192 | static NSInteger rgb = 0;
193 | bottomView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.8];
194 | [self.contentView addSubview:bottomView];
195 | _bottomView = bottomView;
196 | }
197 | return _bottomView;
198 | }
199 |
200 | - (UIImageView *)videoImgView {
201 | if (_videoImgView == nil) {
202 | UIImageView *videoImgView = [[UIImageView alloc] init];
203 | [videoImgView setImage:[UIImage imageNamedFromMyBundle:@"VideoSendIcon"]];
204 | [self.bottomView addSubview:videoImgView];
205 | _videoImgView = videoImgView;
206 | }
207 | return _videoImgView;
208 | }
209 |
210 | - (UILabel *)timeLength {
211 | if (_timeLength == nil) {
212 | UILabel *timeLength = [[UILabel alloc] init];
213 | timeLength.font = [UIFont boldSystemFontOfSize:11];
214 | timeLength.textColor = [UIColor whiteColor];
215 | timeLength.textAlignment = NSTextAlignmentRight;
216 | [self.bottomView addSubview:timeLength];
217 | _timeLength = timeLength;
218 | }
219 | return _timeLength;
220 | }
221 |
222 | - (TZProgressView *)progressView {
223 | if (_progressView == nil) {
224 | _progressView = [[TZProgressView alloc] init];
225 | _progressView.hidden = YES;
226 | [self addSubview:_progressView];
227 | }
228 | return _progressView;
229 | }
230 |
231 | - (void)layoutSubviews {
232 | [super layoutSubviews];
233 | if (self.allowPreview) {
234 | _selectPhotoButton.frame = CGRectMake(self.tz_width - 44, 0, 44, 44);
235 | } else {
236 | _selectPhotoButton.frame = self.bounds;
237 | }
238 | _selectImageView.frame = CGRectMake(self.tz_width - 27, 0, 27, 27);
239 | _imageView.frame = CGRectMake(0, 0, self.tz_width, self.tz_height);
240 |
241 | static CGFloat progressWH = 20;
242 | CGFloat progressXY = (self.tz_width - progressWH) / 2;
243 | _progressView.frame = CGRectMake(progressXY, progressXY, progressWH, progressWH);
244 |
245 | _bottomView.frame = CGRectMake(0, self.tz_height - 17, self.tz_width, 17);
246 | _videoImgView.frame = CGRectMake(8, 0, 17, 17);
247 | _timeLength.frame = CGRectMake(self.videoImgView.tz_right, 0, self.tz_width - self.videoImgView.tz_right - 5, 17);
248 |
249 | self.type = (NSInteger)self.model.type;
250 | self.showSelectBtn = self.showSelectBtn;
251 | }
252 |
253 | @end
254 |
255 | @interface TZAlbumCell ()
256 | @property (weak, nonatomic) UIImageView *posterImageView;
257 | @property (weak, nonatomic) UILabel *titleLabel;
258 | @end
259 |
260 | @implementation TZAlbumCell
261 |
262 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
263 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
264 | self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
265 | return self;
266 | }
267 |
268 | - (void)setModel:(TZAlbumModel *)model {
269 | _model = model;
270 |
271 | NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc] initWithString:model.name attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor blackColor]}];
272 | NSAttributedString *countString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%zd)",model.count] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor lightGrayColor]}];
273 | [nameString appendAttributedString:countString];
274 | self.titleLabel.attributedText = nameString;
275 | [[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) {
276 | self.posterImageView.image = postImage;
277 | }];
278 | if (model.selectedCount) {
279 | self.selectedCountButton.hidden = NO;
280 | [self.selectedCountButton setTitle:[NSString stringWithFormat:@"%zd",model.selectedCount] forState:UIControlStateNormal];
281 | } else {
282 | self.selectedCountButton.hidden = YES;
283 | }
284 | }
285 |
286 | /// For fitting iOS6
287 | - (void)layoutSubviews {
288 | if (iOS7Later) [super layoutSubviews];
289 | _selectedCountButton.frame = CGRectMake(self.tz_width - 24 - 30, 23, 24, 24);
290 | NSInteger titleHeight = ceil(self.titleLabel.font.lineHeight);
291 | self.titleLabel.frame = CGRectMake(80, (self.tz_height - titleHeight) / 2, self.tz_width - 80 - 50, titleHeight);
292 | self.posterImageView.frame = CGRectMake(0, 0, 70, 70);
293 | }
294 |
295 | - (void)layoutSublayersOfLayer:(CALayer *)layer {
296 | if (iOS7Later) [super layoutSublayersOfLayer:layer];
297 | }
298 |
299 | #pragma mark - Lazy load
300 |
301 | - (UIImageView *)posterImageView {
302 | if (_posterImageView == nil) {
303 | UIImageView *posterImageView = [[UIImageView alloc] init];
304 | posterImageView.contentMode = UIViewContentModeScaleAspectFill;
305 | posterImageView.clipsToBounds = YES;
306 | [self.contentView addSubview:posterImageView];
307 | _posterImageView = posterImageView;
308 | }
309 | return _posterImageView;
310 | }
311 |
312 | - (UILabel *)titleLabel {
313 | if (_titleLabel == nil) {
314 | UILabel *titleLabel = [[UILabel alloc] init];
315 | titleLabel.font = [UIFont boldSystemFontOfSize:17];
316 | titleLabel.textColor = [UIColor blackColor];
317 | titleLabel.textAlignment = NSTextAlignmentLeft;
318 | [self.contentView addSubview:titleLabel];
319 | _titleLabel = titleLabel;
320 | }
321 | return _titleLabel;
322 | }
323 |
324 | - (UIButton *)selectedCountButton {
325 | if (_selectedCountButton == nil) {
326 | UIButton *selectedCountButton = [[UIButton alloc] init];
327 | selectedCountButton.layer.cornerRadius = 12;
328 | selectedCountButton.clipsToBounds = YES;
329 | selectedCountButton.backgroundColor = [UIColor redColor];
330 | [selectedCountButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
331 | selectedCountButton.titleLabel.font = [UIFont systemFontOfSize:15];
332 | [self.contentView addSubview:selectedCountButton];
333 | _selectedCountButton = selectedCountButton;
334 | }
335 | return _selectedCountButton;
336 | }
337 |
338 | @end
339 |
340 |
341 |
342 | @implementation TZAssetCameraCell
343 |
344 | - (instancetype)initWithFrame:(CGRect)frame {
345 | self = [super initWithFrame:frame];
346 | if (self) {
347 | self.backgroundColor = [UIColor whiteColor];
348 | _imageView = [[UIImageView alloc] init];
349 | _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
350 | _imageView.contentMode = UIViewContentModeScaleAspectFill;
351 | [self addSubview:_imageView];
352 | self.clipsToBounds = YES;
353 | }
354 | return self;
355 | }
356 |
357 | - (void)layoutSubviews {
358 | [super layoutSubviews];
359 | _imageView.frame = self.bounds;
360 | }
361 |
362 | @end
363 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZAssetModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZAssetModel.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | typedef enum : NSUInteger {
13 | TZAssetModelMediaTypePhoto = 0,
14 | TZAssetModelMediaTypeLivePhoto,
15 | TZAssetModelMediaTypePhotoGif,
16 | TZAssetModelMediaTypeVideo,
17 | TZAssetModelMediaTypeAudio
18 | } TZAssetModelMediaType;
19 |
20 | @class PHAsset;
21 | @interface TZAssetModel : NSObject
22 |
23 | @property (nonatomic, strong) id asset; ///< PHAsset or ALAsset
24 | @property (nonatomic, assign) BOOL isSelected; ///< The select status of a photo, default is No
25 | @property (nonatomic, assign) TZAssetModelMediaType type;
26 | @property (nonatomic, copy) NSString *timeLength;
27 |
28 | /// Init a photo dataModel With a asset
29 | /// 用一个PHAsset/ALAsset实例,初始化一个照片模型
30 | + (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type;
31 | + (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength;
32 |
33 | @end
34 |
35 |
36 | @class PHFetchResult;
37 | @interface TZAlbumModel : NSObject
38 |
39 | @property (nonatomic, strong) NSString *name; ///< The album name
40 | @property (nonatomic, assign) NSInteger count; ///< Count of photos the album contain
41 | @property (nonatomic, strong) id result; ///< PHFetchResult or ALAssetsGroup
42 |
43 | @property (nonatomic, strong) NSArray *models;
44 | @property (nonatomic, strong) NSArray *selectedModels;
45 | @property (nonatomic, assign) NSUInteger selectedCount;
46 |
47 | @property (nonatomic, assign) BOOL isCameraRoll;
48 |
49 | - (void)setResult:(id)result needFetchAssets:(BOOL)needFetchAssets;
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZAssetModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // TZAssetModel.m
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | //
8 |
9 | #import "TZAssetModel.h"
10 | #import "TZImageManager.h"
11 |
12 | @implementation TZAssetModel
13 |
14 | + (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type{
15 | TZAssetModel *model = [[TZAssetModel alloc] init];
16 | model.asset = asset;
17 | model.isSelected = NO;
18 | model.type = type;
19 | return model;
20 | }
21 |
22 | + (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength {
23 | TZAssetModel *model = [self modelWithAsset:asset type:type];
24 | model.timeLength = timeLength;
25 | return model;
26 | }
27 |
28 | @end
29 |
30 |
31 |
32 | @implementation TZAlbumModel
33 |
34 | - (void)setResult:(id)result needFetchAssets:(BOOL)needFetchAssets {
35 | _result = result;
36 | if (needFetchAssets) {
37 | [[TZImageManager manager] getAssetsFromFetchResult:result completion:^(NSArray *models) {
38 | _models = models;
39 | if (_selectedModels) {
40 | [self checkSelectedModels];
41 | }
42 | }];
43 | }
44 | }
45 |
46 | - (void)setSelectedModels:(NSArray *)selectedModels {
47 | _selectedModels = selectedModels;
48 | if (_models) {
49 | [self checkSelectedModels];
50 | }
51 | }
52 |
53 | - (void)checkSelectedModels {
54 | self.selectedCount = 0;
55 | NSMutableArray *selectedAssets = [NSMutableArray array];
56 | for (TZAssetModel *model in _selectedModels) {
57 | [selectedAssets addObject:model.asset];
58 | }
59 | for (TZAssetModel *model in _models) {
60 | if ([[TZImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) {
61 | self.selectedCount ++;
62 | }
63 | }
64 | }
65 |
66 | - (NSString *)name {
67 | if (_name) {
68 | return _name;
69 | }
70 | return @"";
71 | }
72 |
73 | @end
74 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZGifPhotoPreviewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZGifPhotoPreviewController.h
3 | // TZImagePickerController
4 | //
5 | // Created by ttouch on 2016/12/13.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class TZAssetModel;
12 | @interface TZGifPhotoPreviewController : UIViewController
13 |
14 | @property (nonatomic, strong) TZAssetModel *model;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZGifPhotoPreviewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TZGifPhotoPreviewController.m
3 | // TZImagePickerController
4 | //
5 | // Created by ttouch on 2016/12/13.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import "TZGifPhotoPreviewController.h"
10 | #import "TZImagePickerController.h"
11 | #import "TZAssetModel.h"
12 | #import "UIView+Layout.h"
13 | #import "TZPhotoPreviewCell.h"
14 | #import "TZImageManager.h"
15 |
16 | #pragma clang diagnostic push
17 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
18 |
19 | @interface TZGifPhotoPreviewController () {
20 | UIView *_toolBar;
21 | UIButton *_doneButton;
22 | UIProgressView *_progress;
23 |
24 | TZPhotoPreviewView *_previewView;
25 |
26 | UIStatusBarStyle _originStatusBarStyle;
27 | }
28 | @end
29 |
30 | @implementation TZGifPhotoPreviewController
31 |
32 | - (void)viewDidLoad {
33 | [super viewDidLoad];
34 | self.view.backgroundColor = [UIColor blackColor];
35 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
36 | if (tzImagePickerVc) {
37 | self.navigationItem.title = [NSString stringWithFormat:@"GIF %@",tzImagePickerVc.previewBtnTitleStr];
38 | }
39 | [self configPreviewView];
40 | [self configBottomToolBar];
41 | }
42 |
43 | - (void)viewWillAppear:(BOOL)animated {
44 | [super viewWillAppear:animated];
45 | _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
46 | [UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque;
47 | }
48 |
49 | - (void)viewWillDisappear:(BOOL)animated {
50 | [super viewWillDisappear:animated];
51 | [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle;
52 | }
53 |
54 | - (void)configPreviewView {
55 | _previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
56 | _previewView.model = self.model;
57 | __weak typeof(self) weakSelf = self;
58 | [_previewView setSingleTapGestureBlock:^{
59 | __strong typeof(weakSelf) strongSelf = weakSelf;
60 | [strongSelf signleTapAction];
61 | }];
62 | [self.view addSubview:_previewView];
63 | }
64 |
65 | - (void)configBottomToolBar {
66 | _toolBar = [[UIView alloc] initWithFrame:CGRectZero];
67 | CGFloat rgb = 34 / 255.0;
68 | _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
69 |
70 | _doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
71 | _doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
72 | [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
73 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
74 | if (tzImagePickerVc) {
75 | [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
76 | [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
77 | } else {
78 | [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal];
79 | [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal];
80 | }
81 | [_toolBar addSubview:_doneButton];
82 |
83 | UILabel *byteLabel = [[UILabel alloc] init];
84 | byteLabel.textColor = [UIColor whiteColor];
85 | byteLabel.font = [UIFont systemFontOfSize:13];
86 | byteLabel.frame = CGRectMake(10, 0, 100, 44);
87 | [[TZImageManager manager] getPhotosBytesWithArray:@[_model] completion:^(NSString *totalBytes) {
88 | byteLabel.text = totalBytes;
89 | }];
90 | [_toolBar addSubview:byteLabel];
91 |
92 | [self.view addSubview:_toolBar];
93 | }
94 |
95 | #pragma mark - Layout
96 |
97 | - (void)viewDidLayoutSubviews {
98 | [super viewDidLayoutSubviews];
99 |
100 | _previewView.frame = self.view.bounds;
101 | _previewView.scrollView.frame = self.view.bounds;
102 | CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
103 | _toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
104 | _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
105 | }
106 |
107 | #pragma mark - Click Event
108 |
109 | - (void)signleTapAction {
110 | _toolBar.hidden = !_toolBar.isHidden;
111 | [self.navigationController setNavigationBarHidden:_toolBar.isHidden];
112 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
113 | if (iOS7Later) {
114 | if (_toolBar.isHidden) {
115 | [UIApplication sharedApplication].statusBarHidden = YES;
116 | } else if (tzImagePickerVc.needShowStatusBar) {
117 | [UIApplication sharedApplication].statusBarHidden = NO;
118 | }
119 | }
120 | }
121 |
122 | - (void)doneButtonClick {
123 | TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
124 | if (self.navigationController) {
125 | if (imagePickerVc.autoDismiss) {
126 | [self.navigationController dismissViewControllerAnimated:YES completion:^{
127 | [self callDelegateMethod];
128 | }];
129 | }
130 | } else {
131 | [self dismissViewControllerAnimated:YES completion:^{
132 | [self callDelegateMethod];
133 | }];
134 | }
135 | }
136 |
137 | - (void)callDelegateMethod {
138 | TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
139 | UIImage *animatedImage = _previewView.imageView.image;
140 | if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingGifImage:sourceAssets:)]) {
141 | [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingGifImage:animatedImage sourceAssets:_model.asset];
142 | }
143 | if (imagePickerVc.didFinishPickingGifImageHandle) {
144 | imagePickerVc.didFinishPickingGifImageHandle(animatedImage,_model.asset);
145 | }
146 | }
147 |
148 | #pragma clang diagnostic pop
149 |
150 | @end
151 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImageCropManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZImageCropManager.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 2016/12/5.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | // 图片裁剪管理类
8 |
9 | #import
10 | #import
11 |
12 | @interface TZImageCropManager : NSObject
13 |
14 | /// 裁剪框背景的处理
15 | + (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop;
16 |
17 | /*
18 | 1.7.2 为了解决多位同学对于图片裁剪的需求,我这两天有空便在研究图片裁剪
19 | 幸好有tuyou的PhotoTweaks库做参考,裁剪的功能实现起来简单许多
20 | 该方法和其内部引用的方法基本来自于tuyou的PhotoTweaks库,我做了稍许删减和修改
21 | 感谢tuyou同学在github开源了优秀的裁剪库PhotoTweaks,表示感谢
22 | PhotoTweaks库的github链接:https://github.com/itouch2/PhotoTweaks
23 | */
24 | /// 获得裁剪后的图片
25 | + (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView;
26 |
27 | /// 获取圆形图片
28 | + (UIImage *)circularClipImage:(UIImage *)image;
29 |
30 | @end
31 |
32 |
33 | /// 该分类的代码来自SDWebImage:https://github.com/rs/SDWebImage
34 | /// 为了防止冲突,我将分类名字和方法名字做了修改
35 | @interface UIImage (TZGif)
36 |
37 | + (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImageCropManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // TZImageCropManager.m
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 2016/12/5.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import "TZImageCropManager.h"
10 | #import "UIView+Layout.h"
11 | #import
12 | #import "TZImageManager.h"
13 |
14 | @implementation TZImageCropManager
15 |
16 | /// 裁剪框背景的处理
17 | + (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop {
18 | UIBezierPath *path= [UIBezierPath bezierPathWithRect:[UIScreen mainScreen].bounds];
19 | CAShapeLayer *layer = [CAShapeLayer layer];
20 | if (needCircleCrop) { // 圆形裁剪框
21 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:containerView.center radius:cropRect.size.width / 2 startAngle:0 endAngle: 2 * M_PI clockwise:NO]];
22 | } else { // 矩形裁剪框
23 | [path appendPath:[UIBezierPath bezierPathWithRect:cropRect]];
24 | }
25 | layer.path = path.CGPath;
26 | layer.fillRule = kCAFillRuleEvenOdd;
27 | layer.fillColor = [[UIColor blackColor] CGColor];
28 | layer.opacity = 0.5;
29 | [view.layer addSublayer:layer];
30 | }
31 |
32 | /// 获得裁剪后的图片
33 | + (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView {
34 | CGAffineTransform transform = CGAffineTransformIdentity;
35 | // 平移的处理
36 | CGRect imageViewRect = [imageView convertRect:imageView.bounds toView:containerView];
37 | CGPoint point = CGPointMake(imageViewRect.origin.x + imageViewRect.size.width / 2, imageViewRect.origin.y + imageViewRect.size.height / 2);
38 | CGFloat xMargin = containerView.tz_width - CGRectGetMaxX(rect) - rect.origin.x;
39 | CGPoint zeroPoint = CGPointMake((CGRectGetWidth(containerView.frame) - xMargin) / 2, containerView.center.y);
40 | CGPoint translation = CGPointMake(point.x - zeroPoint.x, point.y - zeroPoint.y);
41 | transform = CGAffineTransformTranslate(transform, translation.x, translation.y);
42 | // 缩放的处理
43 | transform = CGAffineTransformScale(transform, zoomScale, zoomScale);
44 |
45 | CGImageRef imageRef = [self newTransformedImage:transform
46 | sourceImage:imageView.image.CGImage
47 | sourceSize:imageView.image.size
48 | outputWidth:rect.size.width * [UIScreen mainScreen].scale
49 | cropSize:rect.size
50 | imageViewSize:imageView.frame.size];
51 | UIImage *cropedImage = [UIImage imageWithCGImage:imageRef];
52 | cropedImage = [[TZImageManager manager] fixOrientation:cropedImage];
53 | CGImageRelease(imageRef);
54 | return cropedImage;
55 | }
56 |
57 | + (CGImageRef)newTransformedImage:(CGAffineTransform)transform sourceImage:(CGImageRef)sourceImage sourceSize:(CGSize)sourceSize outputWidth:(CGFloat)outputWidth cropSize:(CGSize)cropSize imageViewSize:(CGSize)imageViewSize {
58 | CGImageRef source = [self newScaledImage:sourceImage toSize:sourceSize];
59 |
60 | CGFloat aspect = cropSize.height/cropSize.width;
61 | CGSize outputSize = CGSizeMake(outputWidth, outputWidth*aspect);
62 |
63 | CGContextRef context = CGBitmapContextCreate(NULL, outputSize.width, outputSize.height, CGImageGetBitsPerComponent(source), 0, CGImageGetColorSpace(source), CGImageGetBitmapInfo(source));
64 | CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
65 | CGContextFillRect(context, CGRectMake(0, 0, outputSize.width, outputSize.height));
66 |
67 | CGAffineTransform uiCoords = CGAffineTransformMakeScale(outputSize.width / cropSize.width, outputSize.height / cropSize.height);
68 | uiCoords = CGAffineTransformTranslate(uiCoords, cropSize.width/2.0, cropSize.height / 2.0);
69 | uiCoords = CGAffineTransformScale(uiCoords, 1.0, -1.0);
70 | CGContextConcatCTM(context, uiCoords);
71 |
72 | CGContextConcatCTM(context, transform);
73 | CGContextScaleCTM(context, 1.0, -1.0);
74 |
75 | CGContextDrawImage(context, CGRectMake(-imageViewSize.width/2, -imageViewSize.height/2.0, imageViewSize.width, imageViewSize.height), source);
76 | CGImageRef resultRef = CGBitmapContextCreateImage(context);
77 | CGContextRelease(context);
78 | CGImageRelease(source);
79 | return resultRef;
80 | }
81 |
82 | + (CGImageRef)newScaledImage:(CGImageRef)source toSize:(CGSize)size {
83 | CGSize srcSize = size;
84 | CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
85 | CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, rgbColorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
86 | CGColorSpaceRelease(rgbColorSpace);
87 |
88 | CGContextSetInterpolationQuality(context, kCGInterpolationNone);
89 | CGContextTranslateCTM(context, size.width/2, size.height/2);
90 |
91 | CGContextDrawImage(context, CGRectMake(-srcSize.width/2, -srcSize.height/2, srcSize.width, srcSize.height), source);
92 |
93 | CGImageRef resultRef = CGBitmapContextCreateImage(context);
94 | CGContextRelease(context);
95 | return resultRef;
96 | }
97 |
98 | /// 获取圆形图片
99 | + (UIImage *)circularClipImage:(UIImage *)image {
100 | UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
101 |
102 | CGContextRef ctx = UIGraphicsGetCurrentContext();
103 | CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
104 | CGContextAddEllipseInRect(ctx, rect);
105 | CGContextClip(ctx);
106 |
107 | [image drawInRect:rect];
108 | UIImage *circleImage = UIGraphicsGetImageFromCurrentImageContext();
109 |
110 | UIGraphicsEndImageContext();
111 | return circleImage;
112 | }
113 |
114 | @end
115 |
116 |
117 | @implementation UIImage (TZGif)
118 |
119 | + (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data {
120 | if (!data) {
121 | return nil;
122 | }
123 |
124 | CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
125 |
126 | size_t count = CGImageSourceGetCount(source);
127 |
128 | UIImage *animatedImage;
129 |
130 | if (count <= 1) {
131 | animatedImage = [[UIImage alloc] initWithData:data];
132 | }
133 | else {
134 | NSMutableArray *images = [NSMutableArray array];
135 |
136 | NSTimeInterval duration = 0.0f;
137 |
138 | for (size_t i = 0; i < count; i++) {
139 | CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
140 | if (!image) {
141 | continue;
142 | }
143 |
144 | duration += [self sd_frameDurationAtIndex:i source:source];
145 |
146 | [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
147 |
148 | CGImageRelease(image);
149 | }
150 |
151 | if (!duration) {
152 | duration = (1.0f / 10.0f) * count;
153 | }
154 |
155 | animatedImage = [UIImage animatedImageWithImages:images duration:duration];
156 | }
157 |
158 | CFRelease(source);
159 |
160 | return animatedImage;
161 | }
162 |
163 | + (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
164 | float frameDuration = 0.1f;
165 | CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
166 | NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
167 | NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
168 |
169 | NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
170 | if (delayTimeUnclampedProp) {
171 | frameDuration = [delayTimeUnclampedProp floatValue];
172 | }
173 | else {
174 |
175 | NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
176 | if (delayTimeProp) {
177 | frameDuration = [delayTimeProp floatValue];
178 | }
179 | }
180 |
181 | // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
182 | // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
183 | // a duration of <= 10 ms. See and
184 | // for more information.
185 |
186 | if (frameDuration < 0.011f) {
187 | frameDuration = 0.100f;
188 | }
189 |
190 | CFRelease(cfFrameProperties);
191 | return frameDuration;
192 | }
193 |
194 | @end
195 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImageManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZImageManager.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 16/1/4.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | // 图片资源获取管理类
8 |
9 | #import
10 | #import
11 | #import
12 | #import
13 | #import "TZAssetModel.h"
14 |
15 | @class TZAlbumModel,TZAssetModel;
16 | @protocol TZImagePickerControllerDelegate;
17 | @interface TZImageManager : NSObject
18 |
19 | @property (nonatomic, strong) PHCachingImageManager *cachingImageManager;
20 |
21 | + (instancetype)manager NS_SWIFT_NAME(default());
22 | + (void)deallocManager;
23 |
24 | @property (assign, nonatomic) id pickerDelegate;
25 |
26 | @property (nonatomic, assign) BOOL shouldFixOrientation;
27 |
28 | /// Default is 600px / 默认600像素宽
29 | @property (nonatomic, assign) CGFloat photoPreviewMaxWidth;
30 | /// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽
31 | @property (nonatomic, assign) CGFloat photoWidth;
32 |
33 | /// Default is 4, Use in photos collectionView in TZPhotoPickerController
34 | /// 默认4列, TZPhotoPickerController中的照片collectionView
35 | @property (nonatomic, assign) NSInteger columnNumber;
36 |
37 | /// Sort photos ascending by modificationDate,Default is YES
38 | /// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个
39 | @property (nonatomic, assign) BOOL sortAscendingByModificationDate;
40 |
41 | /// Minimum selectable photo width, Default is 0
42 | /// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中
43 | @property (nonatomic, assign) NSInteger minPhotoWidthSelectable;
44 | @property (nonatomic, assign) NSInteger minPhotoHeightSelectable;
45 | @property (nonatomic, assign) BOOL hideWhenCanNotSelect;
46 |
47 | /// Return YES if Authorized 返回YES如果得到了授权
48 | - (BOOL)authorizationStatusAuthorized;
49 | + (NSInteger)authorizationStatus;
50 | - (void)requestAuthorizationWithCompletion:(void (^)(void))completion;
51 |
52 | /// Get Album 获得相册/相册数组
53 | - (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion;
54 | - (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray *models))completion;
55 |
56 | /// Get Assets 获得Asset数组
57 | - (void)getAssetsFromFetchResult:(id)result completion:(void (^)(NSArray *models))completion;
58 | - (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray *models))completion;
59 | - (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *model))completion;
60 |
61 | /// Get photo 获得照片
62 | - (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion;
63 |
64 | - (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
65 | - (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
66 | - (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed;
67 | - (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed;
68 |
69 | /// Get full Image 获取原图
70 | /// 如下两个方法completion一般会调多次,一般会先返回缩略图,再返回原图(详见方法内部使用的系统API的说明),如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。
71 | - (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion;
72 | - (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
73 | // 该方法中,completion只会走一次
74 | - (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
75 |
76 | /// Save photo 保存照片
77 | - (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion;
78 | - (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion;
79 |
80 | /// Get video 获得视频
81 | - (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion;
82 | - (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion;
83 |
84 | /// Export video 导出视频 presetName: 预设名字,默认值是AVAssetExportPreset640x480
85 | - (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
86 | - (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
87 | /// Deprecated, Use -getVideoOutputPathWithAsset:failure:success:
88 | - (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion __attribute__((deprecated("Use -getVideoOutputPathWithAsset:failure:success:")));
89 |
90 | /// Get photo bytes 获得一组照片的大小
91 | - (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion;
92 |
93 | /// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
94 | - (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset;
95 |
96 | - (NSString *)getAssetIdentifier:(id)asset;
97 | - (BOOL)isCameraRollAlbum:(id)metadata;
98 |
99 | /// 检查照片大小是否满足最小要求
100 | - (BOOL)isPhotoSelectableWithAsset:(id)asset;
101 | - (CGSize)photoSizeWithAsset:(id)asset;
102 |
103 | /// 修正图片转向
104 | - (UIImage *)fixOrientation:(UIImage *)aImage;
105 |
106 | /// 获取asset的资源类型
107 | - (TZAssetModelMediaType)getAssetType:(id)asset;
108 |
109 | @end
110 |
111 | //@interface TZSortDescriptor : NSSortDescriptor
112 | //
113 | //@end
114 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/Root.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | StringsTable
6 | Root
7 | PreferenceSpecifiers
8 |
9 |
10 | Type
11 | PSGroupSpecifier
12 | Title
13 | Group
14 |
15 |
16 | Type
17 | PSTextFieldSpecifier
18 | Title
19 | Name
20 | Key
21 | name_preference
22 | DefaultValue
23 |
24 | IsSecure
25 |
26 | KeyboardType
27 | Alphabet
28 | AutocapitalizationType
29 | None
30 | AutocorrectionType
31 | No
32 |
33 |
34 | Type
35 | PSToggleSwitchSpecifier
36 | Title
37 | Enabled
38 | Key
39 | enabled_preference
40 | DefaultValue
41 |
42 |
43 |
44 | Type
45 | PSSliderSpecifier
46 | Key
47 | slider_preference
48 | DefaultValue
49 | 0.5
50 | MinimumValue
51 | 0
52 | MaximumValue
53 | 1
54 | MinimumValueImage
55 |
56 | MaximumValueImage
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/navi_back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/navi_back@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/takePicture@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/takePicture@2x.png
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/vi.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "OK" = "Xác nhận";
2 | "Back" = "Quay lại";
3 | "Done" = "Hoàn thành";
4 | "Sorry" = "Xin lỗi";
5 | "Cancel" = "Hủy";
6 | "Setting" = "Cài đặt";
7 | "Photos" = "Hình";
8 | "Videos" = "Clip";
9 | "Preview" = "Xem trước";
10 | "Full image" = "Hình gốc";
11 | "Processing..." = "Đang xử lý...";
12 | "Can not use camera" = "Máy chụp hình không khả dụng";
13 | "Synchronizing photos from iCloud" = "Đang đồng bộ hình ảnh từ ICloud";
14 | "Can not choose both video and photo" = "Trong lúc chọn hình ảnh không cùng lúc chọn video";
15 | "Can not choose both photo and GIF" = "Trong lúc chọn hình ảnh không cùng lúc chọn hình GIF";
16 | "Select the video when in multi state, we will handle the video as a photo" = "Chọn hình ảnh cùng video, video sẽ bị mặc nhận thành hình ảnh và gửi đi.";
17 | "Can not jump to the privacy settings page, please go to the settings page by self, thank you" = "Không thể chuyển tự động qua trang cài đặt riêng tư, bạn hãy thoát ra cà điều chỉnh lại, cám ơn bạn.";
18 |
19 | "Select a maximum of %zd photos" = "Bạn chỉ được chọn nhiều nhất %zd tấm hình";
20 | "Select a minimum of %zd photos" = "Chọn ít nhất %zd tấm hình";
21 | "Allow %@ to access your album in \"Settings -> Privacy -> Photos\"" = "Vui lòng tại mục iPhone \" Cài đặt – quyền riêng tư - Ảnh\" mở quyền cho phép %@ truy cập ảnh.";
22 | "Please allow %@ to access your camera in \"Settings -> Privacy -> Camera\"" = "Vui lòng tại mục iPhone \" Cài đặt – quyền riêng tư - Ảnh\" mở quyền cho phép %@ truy cập máy ảnh";
23 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jolincheng/CZHSyntheticImages/4dfce8faa8d56d60aa1e9d591552102f8abe26d6/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZImagePickerController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZImagePickerController.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | // version 2.0.0.6 - 2018.02.13
8 | // 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
9 |
10 | /*
11 | 经过测试,比起xib的方式,把TZAssetCell改用纯代码的方式来写,滑动帧数明显提高了(约提高10帧左右)
12 |
13 | 最初发现这个问题并修复的是@小鱼周凌宇同学,她的博客地址: http://zhoulingyu.com/
14 | 表示感谢~
15 |
16 | 原来xib确实会导致性能问题啊...大家也要注意了...
17 | */
18 |
19 | #import
20 | #import "TZAssetModel.h"
21 | #import "NSBundle+TZImagePicker.h"
22 |
23 | #define iOS7Later ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f)
24 | #define iOS8Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f)
25 | #define iOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f)
26 | #define iOS9_1Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f)
27 |
28 | @protocol TZImagePickerControllerDelegate;
29 | @interface TZImagePickerController : UINavigationController
30 |
31 | #pragma mark -
32 | /// Use this init method / 用这个初始化方法
33 | - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id)delegate;
34 | - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id)delegate;
35 | - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc;
36 | /// This init method just for previewing photos / 用这个初始化方法以预览图片
37 | - (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index;
38 | /// This init method for crop photo / 用这个初始化方法以裁剪图片
39 | - (instancetype)initCropTypeWithAsset:(id)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,id asset))completion;
40 |
41 | #pragma mark -
42 | /// Default is 9 / 默认最大可选9张图片
43 | @property (nonatomic, assign) NSInteger maxImagesCount;
44 |
45 | /// The minimum count photos user must pick, Default is 0
46 | /// 最小照片必选张数,默认是0
47 | @property (nonatomic, assign) NSInteger minImagesCount;
48 |
49 | /// Always enale the done button, not require minimum 1 photo be picked
50 | /// 让完成按钮一直可以点击,无须最少选择一张图片
51 | @property (nonatomic, assign) BOOL alwaysEnableDoneBtn;
52 |
53 | /// Sort photos ascending by modificationDate,Default is YES
54 | /// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个
55 | @property (nonatomic, assign) BOOL sortAscendingByModificationDate;
56 |
57 | /// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽
58 | @property (nonatomic, assign) CGFloat photoWidth;
59 |
60 | /// Default is 600px / 默认600像素宽
61 | @property (nonatomic, assign) CGFloat photoPreviewMaxWidth;
62 |
63 | /// Default is 15, While fetching photo, HUD will dismiss automatic if timeout;
64 | /// 超时时间,默认为15秒,当取图片时间超过15秒还没有取成功时,会自动dismiss HUD;
65 | @property (nonatomic, assign) NSInteger timeout;
66 |
67 | /// Default is YES, if set NO, the original photo button will hide. user can't picking original photo.
68 | /// 默认为YES,如果设置为NO,原图按钮将隐藏,用户不能选择发送原图
69 | @property (nonatomic, assign) BOOL allowPickingOriginalPhoto;
70 |
71 | /// Default is YES, if set NO, user can't picking video.
72 | /// 默认为YES,如果设置为NO,用户将不能选择视频
73 | @property (nonatomic, assign) BOOL allowPickingVideo;
74 | /// Default is NO / 默认为NO,为YES时可以多选视频/gif图片,和照片共享最大可选张数maxImagesCount的限制
75 | @property (nonatomic, assign) BOOL allowPickingMultipleVideo;
76 |
77 | /// Default is NO, if set YES, user can picking gif image.
78 | /// 默认为NO,如果设置为YES,用户可以选择gif图片
79 | @property (nonatomic, assign) BOOL allowPickingGif;
80 |
81 | /// Default is YES, if set NO, user can't picking image.
82 | /// 默认为YES,如果设置为NO,用户将不能选择发送图片
83 | @property(nonatomic, assign) BOOL allowPickingImage;
84 |
85 | /// Default is YES, if set NO, user can't take picture.
86 | /// 默认为YES,如果设置为NO,拍照按钮将隐藏,用户将不能选择照片
87 | @property(nonatomic, assign) BOOL allowTakePicture;
88 |
89 | /// 首选语言,如果设置了就用该语言,不设则取当前系统语言。
90 | /// 由于目前只支持中文、繁体中文、英文、越南语。故该属性只支持zh-Hans、zh-Hant、en、vi四种值,其余值无效。
91 | @property (copy, nonatomic) NSString *preferredLanguage;
92 |
93 | /// 语言bundle,preferredLanguage变化时languageBundle会变化
94 | /// 可通过手动设置bundle,让选择器支持新的的语言(需要在设置preferredLanguage后设置languageBundle)。欢迎提交PR把语言文件提交上来~
95 | @property (strong, nonatomic) NSBundle *languageBundle;
96 |
97 | /// Default is YES, if set NO, user can't preview photo.
98 | /// 默认为YES,如果设置为NO,预览按钮将隐藏,用户将不能去预览照片
99 | @property (nonatomic, assign) BOOL allowPreview;
100 |
101 | /// Default is YES, if set NO, the picker don't dismiss itself.
102 | /// 默认为YES,如果设置为NO, 选择器将不会自己dismiss
103 | @property(nonatomic, assign) BOOL autoDismiss;
104 |
105 | /// The photos user have selected
106 | /// 用户选中过的图片数组
107 | @property (nonatomic, strong) NSMutableArray *selectedAssets;
108 | @property (nonatomic, strong) NSMutableArray *selectedModels;
109 |
110 | /// Minimum selectable photo width, Default is 0
111 | /// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中
112 | @property (nonatomic, assign) NSInteger minPhotoWidthSelectable;
113 | @property (nonatomic, assign) NSInteger minPhotoHeightSelectable;
114 | /// Hide the photo what can not be selected, Default is NO
115 | /// 隐藏不可以选中的图片,默认是NO,不推荐将其设置为YES
116 | @property (nonatomic, assign) BOOL hideWhenCanNotSelect;
117 | /// Deprecated, Use statusBarStyle (顶部statusBar 是否为系统默认的黑色,默认为NO)
118 | @property (nonatomic, assign) BOOL isStatusBarDefault __attribute__((deprecated("Use -statusBarStyle.")));
119 | /// statusBar的样式,默认为UIStatusBarStyleLightContent
120 | @property (assign, nonatomic) UIStatusBarStyle statusBarStyle;
121 |
122 | #pragma mark -
123 | /// Single selection mode, valid when maxImagesCount = 1
124 | /// 单选模式,maxImagesCount为1时才生效
125 | @property (nonatomic, assign) BOOL showSelectBtn; ///< 在单选模式下,照片列表页中,显示选择按钮,默认为NO
126 | @property (nonatomic, assign) BOOL allowCrop; ///< 允许裁剪,默认为YES,showSelectBtn为NO才生效
127 | @property (nonatomic, assign) CGRect cropRect; ///< 裁剪框的尺寸
128 | @property (nonatomic, assign) CGRect cropRectPortrait; ///< 裁剪框的尺寸(竖屏)
129 | @property (nonatomic, assign) CGRect cropRectLandscape; ///< 裁剪框的尺寸(横屏)
130 | @property (nonatomic, assign) BOOL needCircleCrop; ///< 需要圆形裁剪框
131 | @property (nonatomic, assign) NSInteger circleCropRadius; ///< 圆形裁剪框半径大小
132 | @property (nonatomic, copy) void (^cropViewSettingBlock)(UIView *cropView); ///< 自定义裁剪框的其他属性
133 |
134 | @property (nonatomic, copy) void (^navLeftBarButtonSettingBlock)(UIButton *leftButton); ///< 自定义返回按钮样式及其属性
135 |
136 | #pragma mark -
137 | - (id)showAlertWithTitle:(NSString *)title;
138 | - (void)hideAlertView:(id)alertView;
139 | - (void)showProgressHUD;
140 | - (void)hideProgressHUD;
141 | @property (nonatomic, assign) BOOL isSelectOriginalPhoto;
142 | @property (assign, nonatomic) BOOL needShowStatusBar;
143 |
144 | #pragma mark -
145 | @property (nonatomic, copy) NSString *takePictureImageName;
146 | @property (nonatomic, copy) NSString *photoSelImageName;
147 | @property (nonatomic, copy) NSString *photoDefImageName;
148 | @property (nonatomic, copy) NSString *photoOriginSelImageName;
149 | @property (nonatomic, copy) NSString *photoOriginDefImageName;
150 | @property (nonatomic, copy) NSString *photoPreviewOriginDefImageName;
151 | @property (nonatomic, copy) NSString *photoNumberIconImageName;
152 |
153 | #pragma mark -
154 | /// Appearance / 外观颜色 + 按钮文字
155 | @property (nonatomic, strong) UIColor *oKButtonTitleColorNormal;
156 | @property (nonatomic, strong) UIColor *oKButtonTitleColorDisabled;
157 | @property (nonatomic, strong) UIColor *naviBgColor;
158 | @property (nonatomic, strong) UIColor *naviTitleColor;
159 | @property (nonatomic, strong) UIFont *naviTitleFont;
160 | @property (nonatomic, strong) UIColor *barItemTextColor;
161 | @property (nonatomic, strong) UIFont *barItemTextFont;
162 |
163 | @property (nonatomic, copy) NSString *doneBtnTitleStr;
164 | @property (nonatomic, copy) NSString *cancelBtnTitleStr;
165 | @property (nonatomic, copy) NSString *previewBtnTitleStr;
166 | @property (nonatomic, copy) NSString *fullImageBtnTitleStr;
167 | @property (nonatomic, copy) NSString *settingBtnTitleStr;
168 | @property (nonatomic, copy) NSString *processHintStr;
169 |
170 | #pragma mark -
171 | - (void)cancelButtonClick;
172 |
173 | // The picker should dismiss itself; when it dismissed these handle will be called.
174 | // You can also set autoDismiss to NO, then the picker don't dismiss itself.
175 | // If isOriginalPhoto is YES, user picked the original photo.
176 | // You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:].
177 | // The UIImage Object in photos default width is 828px, you can set it by photoWidth property.
178 | // 这个照片选择器会自己dismiss,当选择器dismiss的时候,会执行下面的handle
179 | // 你也可以设置autoDismiss属性为NO,选择器就不会自己dismis了
180 | // 如果isSelectOriginalPhoto为YES,表明用户选择了原图
181 | // 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:]
182 | // photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它
183 | @property (nonatomic, copy) void (^didFinishPickingPhotosHandle)(NSArray *photos,NSArray *assets,BOOL isSelectOriginalPhoto);
184 | @property (nonatomic, copy) void (^didFinishPickingPhotosWithInfosHandle)(NSArray *photos,NSArray *assets,BOOL isSelectOriginalPhoto,NSArray *infos);
185 | @property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)(void);
186 |
187 | // If user picking a video, this handle will be called.
188 | // If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class.
189 | // 如果用户选择了一个视频,下面的handle会被执行
190 | // 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象
191 | @property (nonatomic, copy) void (^didFinishPickingVideoHandle)(UIImage *coverImage,id asset);
192 |
193 | // If user picking a gif image, this callback will be called.
194 | // 如果用户选择了一个gif图片,下面的handle会被执行
195 | @property (nonatomic, copy) void (^didFinishPickingGifImageHandle)(UIImage *animatedImage,id sourceAssets);
196 |
197 | @property (nonatomic, weak) id pickerDelegate;
198 |
199 | @end
200 |
201 |
202 | @protocol TZImagePickerControllerDelegate
203 | @optional
204 | // The picker should dismiss itself; when it dismissed these handle will be called.
205 | // You can also set autoDismiss to NO, then the picker don't dismiss itself.
206 | // If isOriginalPhoto is YES, user picked the original photo.
207 | // You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:].
208 | // The UIImage Object in photos default width is 828px, you can set it by photoWidth property.
209 | // 这个照片选择器会自己dismiss,当选择器dismiss的时候,会执行下面的handle
210 | // 你也可以设置autoDismiss属性为NO,选择器就不会自己dismis了
211 | // 如果isSelectOriginalPhoto为YES,表明用户选择了原图
212 | // 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:]
213 | // photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它
214 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto;
215 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray *)infos;
216 | //- (void)imagePickerControllerDidCancel:(TZImagePickerController *)picker __attribute__((deprecated("Use -tz_imagePickerControllerDidCancel:.")));
217 | - (void)tz_imagePickerControllerDidCancel:(TZImagePickerController *)picker;
218 |
219 | // If user picking a video, this callback will be called.
220 | // If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class.
221 | // 如果用户选择了一个视频,下面的handle会被执行
222 | // 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象
223 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(id)asset;
224 |
225 | // If user picking a gif image, this callback will be called.
226 | // 如果用户选择了一个gif图片,下面的handle会被执行
227 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingGifImage:(UIImage *)animatedImage sourceAssets:(id)asset;
228 |
229 | // Decide album show or not't
230 | // 决定相册显示与否 albumName:相册名字 result:相册原始数据
231 | - (BOOL)isAlbumCanSelect:(NSString *)albumName result:(id)result;
232 |
233 | // Decide asset show or not't
234 | // 决定照片显示与否
235 | - (BOOL)isAssetCanSelect:(id)asset;
236 | @end
237 |
238 |
239 | @interface TZAlbumPickerController : UIViewController
240 | @property (nonatomic, assign) NSInteger columnNumber;
241 | @property (assign, nonatomic) BOOL isFirstAppear;
242 | - (void)configTableView;
243 | @end
244 |
245 |
246 | @interface UIImage (MyBundle)
247 | + (UIImage *)imageNamedFromMyBundle:(NSString *)name;
248 | @end
249 |
250 |
251 | @interface NSString (TzExtension)
252 | - (BOOL)tz_containsString:(NSString *)string;
253 | - (CGSize)tz_calculateSizeWithAttributes:(NSDictionary *)attributes maxSize:(CGSize)maxSize;
254 | @end
255 |
256 |
257 | @interface TZCommonTools : NSObject
258 | + (BOOL)tz_isIPhoneX;
259 | + (CGFloat)tz_statusBarHeight;
260 | // 获得Info.plist数据字典
261 | + (NSDictionary *)tz_getInfoDictionary;
262 | @end
263 |
264 |
265 | @interface TZImagePickerConfig : NSObject
266 | + (instancetype)sharedInstance;
267 | @property (copy, nonatomic) NSString *preferredLanguage;
268 | @property(nonatomic, assign) BOOL allowPickingImage;
269 | @property (nonatomic, assign) BOOL allowPickingVideo;
270 | @property (strong, nonatomic) NSBundle *languageBundle;
271 | @end
272 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZLocationManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZLocationManager.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 2017/06/03.
6 | // Copyright © 2017年 谭真. All rights reserved.
7 | // 定位管理类
8 |
9 |
10 | #import
11 | #import
12 |
13 | @interface TZLocationManager : NSObject
14 |
15 | + (instancetype)manager;
16 |
17 | /// 开始定位
18 | - (void)startLocation;
19 | - (void)startLocationWithSuccessBlock:(void (^)(CLLocation *location,CLLocation *oldLocation))successBlock failureBlock:(void (^)(NSError *error))failureBlock;
20 | - (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
21 | - (void)startLocationWithSuccessBlock:(void (^)(CLLocation *location,CLLocation *oldLocation))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
22 |
23 | @end
24 |
25 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZLocationManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // TZLocationManager.m
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 2017/06/03.
6 | // Copyright © 2017年 谭真. All rights reserved.
7 | // 定位管理类
8 |
9 | #import "TZLocationManager.h"
10 | #import "TZImagePickerController.h"
11 |
12 | @interface TZLocationManager ()
13 | @property (nonatomic, strong) CLLocationManager *locationManager;
14 | /// 定位成功的回调block
15 | @property (nonatomic, copy) void (^successBlock)(CLLocation *location,CLLocation *oldLocation);
16 | /// 编码成功的回调block
17 | @property (nonatomic, copy) void (^geocodeBlock)(NSArray *geocodeArray);
18 | /// 定位失败的回调block
19 | @property (nonatomic, copy) void (^failureBlock)(NSError *error);
20 | @end
21 |
22 | @implementation TZLocationManager
23 |
24 | + (instancetype)manager {
25 | static TZLocationManager *manager;
26 | static dispatch_once_t onceToken;
27 | dispatch_once(&onceToken, ^{
28 | manager = [[self alloc] init];
29 | manager.locationManager = [[CLLocationManager alloc] init];
30 | manager.locationManager.delegate = manager;
31 | if (iOS8Later) {
32 | [manager.locationManager requestWhenInUseAuthorization];
33 | }
34 | });
35 | return manager;
36 | }
37 |
38 | - (void)startLocation {
39 | [self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:nil];
40 | }
41 |
42 | - (void)startLocationWithSuccessBlock:(void (^)(CLLocation *location,CLLocation *oldLocation))successBlock failureBlock:(void (^)(NSError *error))failureBlock {
43 | [self startLocationWithSuccessBlock:successBlock failureBlock:failureBlock geocoderBlock:nil];
44 | }
45 |
46 | - (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock {
47 | [self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:geocoderBlock];
48 | }
49 |
50 | - (void)startLocationWithSuccessBlock:(void (^)(CLLocation *location,CLLocation *oldLocation))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock {
51 | [self.locationManager startUpdatingLocation];
52 | _successBlock = successBlock;
53 | _geocodeBlock = geocoderBlock;
54 | _failureBlock = failureBlock;
55 | }
56 |
57 | #pragma mark - CLLocationManagerDelegate
58 |
59 | /// 地理位置发生改变时触发
60 | - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
61 | [manager stopUpdatingLocation];
62 |
63 | if (_successBlock) {
64 | _successBlock(newLocation,oldLocation);
65 | }
66 |
67 | if (_geocodeBlock) {
68 | CLGeocoder *geocoder = [[CLGeocoder alloc] init];
69 | [geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *array, NSError *error) {
70 | _geocodeBlock(array);
71 | }];
72 | }
73 | }
74 |
75 | /// 定位失败回调方法
76 | - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
77 | NSLog(@"定位失败, 错误: %@",error);
78 | switch([error code]) {
79 | case kCLErrorDenied: { // 用户禁止了定位权限
80 |
81 | } break;
82 | default: break;
83 | }
84 | if (_failureBlock) {
85 | _failureBlock(error);
86 | }
87 | }
88 |
89 | @end
90 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZPhotoPickerController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZPhotoPickerController.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class TZAlbumModel;
12 | @interface TZPhotoPickerController : UIViewController
13 |
14 | @property (nonatomic, assign) BOOL isFirstAppear;
15 | @property (nonatomic, assign) NSInteger columnNumber;
16 | @property (nonatomic, strong) TZAlbumModel *model;
17 | @end
18 |
19 |
20 | @interface TZCollectionView : UICollectionView
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZPhotoPreviewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZPhotoPreviewCell.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class TZAssetModel;
12 | @interface TZAssetPreviewCell : UICollectionViewCell
13 | @property (nonatomic, strong) TZAssetModel *model;
14 | @property (nonatomic, copy) void (^singleTapGestureBlock)(void);
15 | - (void)configSubviews;
16 | - (void)photoPreviewCollectionViewDidScroll;
17 | @end
18 |
19 |
20 | @class TZAssetModel,TZProgressView,TZPhotoPreviewView;
21 | @interface TZPhotoPreviewCell : TZAssetPreviewCell
22 |
23 | @property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
24 |
25 | @property (nonatomic, strong) TZPhotoPreviewView *previewView;
26 |
27 | @property (nonatomic, assign) BOOL allowCrop;
28 | @property (nonatomic, assign) CGRect cropRect;
29 |
30 | - (void)recoverSubviews;
31 |
32 | @end
33 |
34 |
35 | @interface TZPhotoPreviewView : UIView
36 | @property (nonatomic, strong) UIImageView *imageView;
37 | @property (nonatomic, strong) UIScrollView *scrollView;
38 | @property (nonatomic, strong) UIView *imageContainerView;
39 | @property (nonatomic, strong) TZProgressView *progressView;
40 |
41 | @property (nonatomic, assign) BOOL allowCrop;
42 | @property (nonatomic, assign) CGRect cropRect;
43 |
44 | @property (nonatomic, strong) TZAssetModel *model;
45 | @property (nonatomic, strong) id asset;
46 | @property (nonatomic, copy) void (^singleTapGestureBlock)(void);
47 | @property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
48 |
49 | @property (nonatomic, assign) int32_t imageRequestID;
50 |
51 | - (void)recoverSubviews;
52 | @end
53 |
54 |
55 | @class AVPlayer, AVPlayerLayer;
56 | @interface TZVideoPreviewCell : TZAssetPreviewCell
57 | @property (strong, nonatomic) AVPlayer *player;
58 | @property (strong, nonatomic) AVPlayerLayer *playerLayer;
59 | @property (strong, nonatomic) UIButton *playButton;
60 | @property (strong, nonatomic) UIImage *cover;
61 | - (void)pausePlayerAndShowNaviBar;
62 | @end
63 |
64 |
65 | @interface TZGifPreviewCell : TZAssetPreviewCell
66 | @property (strong, nonatomic) TZPhotoPreviewView *previewView;
67 | @end
68 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZPhotoPreviewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // TZPhotoPreviewCell.m
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | //
8 |
9 | #import "TZPhotoPreviewCell.h"
10 | #import "TZAssetModel.h"
11 | #import "UIView+Layout.h"
12 | #import "TZImageManager.h"
13 | #import "TZProgressView.h"
14 | #import "TZImageCropManager.h"
15 | #import
16 | #import "TZImagePickerController.h"
17 |
18 | @implementation TZAssetPreviewCell
19 |
20 | - (instancetype)initWithFrame:(CGRect)frame {
21 | self = [super initWithFrame:frame];
22 | if (self) {
23 | self.backgroundColor = [UIColor blackColor];
24 | [self configSubviews];
25 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(photoPreviewCollectionViewDidScroll) name:@"photoPreviewCollectionViewDidScroll" object:nil];
26 | }
27 | return self;
28 | }
29 |
30 | - (void)configSubviews {
31 |
32 | }
33 |
34 | #pragma mark - Notification
35 |
36 | - (void)photoPreviewCollectionViewDidScroll {
37 |
38 | }
39 |
40 | - (void)dealloc {
41 | [[NSNotificationCenter defaultCenter] removeObserver:self];
42 | }
43 |
44 | @end
45 |
46 |
47 | @implementation TZPhotoPreviewCell
48 |
49 | - (void)configSubviews {
50 | self.previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
51 | __weak typeof(self) weakSelf = self;
52 | [self.previewView setSingleTapGestureBlock:^{
53 | __strong typeof(weakSelf) strongSelf = weakSelf;
54 | if (strongSelf.singleTapGestureBlock) {
55 | strongSelf.singleTapGestureBlock();
56 | }
57 | }];
58 | [self.previewView setImageProgressUpdateBlock:^(double progress) {
59 | __strong typeof(weakSelf) strongSelf = weakSelf;
60 | if (strongSelf.imageProgressUpdateBlock) {
61 | strongSelf.imageProgressUpdateBlock(progress);
62 | }
63 | }];
64 | [self addSubview:self.previewView];
65 | }
66 |
67 | - (void)setModel:(TZAssetModel *)model {
68 | [super setModel:model];
69 | _previewView.asset = model.asset;
70 | }
71 |
72 | - (void)recoverSubviews {
73 | [_previewView recoverSubviews];
74 | }
75 |
76 | - (void)setAllowCrop:(BOOL)allowCrop {
77 | _allowCrop = allowCrop;
78 | _previewView.allowCrop = allowCrop;
79 | }
80 |
81 | - (void)setCropRect:(CGRect)cropRect {
82 | _cropRect = cropRect;
83 | _previewView.cropRect = cropRect;
84 | }
85 |
86 | - (void)layoutSubviews {
87 | [super layoutSubviews];
88 | self.previewView.frame = self.bounds;
89 | }
90 |
91 | @end
92 |
93 |
94 | @interface TZPhotoPreviewView ()
95 |
96 | @end
97 |
98 | @implementation TZPhotoPreviewView
99 |
100 | - (instancetype)initWithFrame:(CGRect)frame {
101 | self = [super initWithFrame:frame];
102 | if (self) {
103 | _scrollView = [[UIScrollView alloc] init];
104 | _scrollView.bouncesZoom = YES;
105 | _scrollView.maximumZoomScale = 2.5;
106 | _scrollView.minimumZoomScale = 1.0;
107 | _scrollView.multipleTouchEnabled = YES;
108 | _scrollView.delegate = self;
109 | _scrollView.scrollsToTop = NO;
110 | _scrollView.showsHorizontalScrollIndicator = NO;
111 | _scrollView.showsVerticalScrollIndicator = YES;
112 | _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
113 | _scrollView.delaysContentTouches = NO;
114 | _scrollView.canCancelContentTouches = YES;
115 | _scrollView.alwaysBounceVertical = NO;
116 | [self addSubview:_scrollView];
117 |
118 | _imageContainerView = [[UIView alloc] init];
119 | _imageContainerView.clipsToBounds = YES;
120 | _imageContainerView.contentMode = UIViewContentModeScaleAspectFill;
121 | [_scrollView addSubview:_imageContainerView];
122 |
123 | _imageView = [[UIImageView alloc] init];
124 | _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
125 | _imageView.contentMode = UIViewContentModeScaleAspectFill;
126 | _imageView.clipsToBounds = YES;
127 | [_imageContainerView addSubview:_imageView];
128 |
129 | UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
130 | [self addGestureRecognizer:tap1];
131 | UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)];
132 | tap2.numberOfTapsRequired = 2;
133 | [tap1 requireGestureRecognizerToFail:tap2];
134 | [self addGestureRecognizer:tap2];
135 |
136 | [self configProgressView];
137 | }
138 | return self;
139 | }
140 |
141 | - (void)configProgressView {
142 | _progressView = [[TZProgressView alloc] init];
143 | _progressView.hidden = YES;
144 | [self addSubview:_progressView];
145 | }
146 |
147 | - (void)setModel:(TZAssetModel *)model {
148 | _model = model;
149 | [_scrollView setZoomScale:1.0 animated:NO];
150 | if (model.type == TZAssetModelMediaTypePhotoGif) {
151 | // 先显示缩略图
152 | [[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
153 | self.imageView.image = photo;
154 | [self resizeSubviews];
155 | // 再显示gif动图
156 | [[TZImageManager manager] getOriginalPhotoDataWithAsset:model.asset completion:^(NSData *data, NSDictionary *info, BOOL isDegraded) {
157 | if (!isDegraded) {
158 | self.imageView.image = [UIImage sd_tz_animatedGIFWithData:data];
159 | [self resizeSubviews];
160 | }
161 | }];
162 | } progressHandler:nil networkAccessAllowed:NO];
163 | } else {
164 | self.asset = model.asset;
165 | }
166 | }
167 |
168 | - (void)setAsset:(id)asset {
169 | if (_asset && self.imageRequestID) {
170 | [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
171 | }
172 |
173 | _asset = asset;
174 | self.imageRequestID = [[TZImageManager manager] getPhotoWithAsset:asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
175 | if (![asset isEqual:_asset]) return;
176 | self.imageView.image = photo;
177 | [self resizeSubviews];
178 | _progressView.hidden = YES;
179 | if (self.imageProgressUpdateBlock) {
180 | self.imageProgressUpdateBlock(1);
181 | }
182 | if (!isDegraded) {
183 | self.imageRequestID = 0;
184 | }
185 | } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
186 | if (![asset isEqual:_asset]) return;
187 | _progressView.hidden = NO;
188 | [self bringSubviewToFront:_progressView];
189 | progress = progress > 0.02 ? progress : 0.02;
190 | _progressView.progress = progress;
191 | if (self.imageProgressUpdateBlock && progress < 1) {
192 | self.imageProgressUpdateBlock(progress);
193 | }
194 |
195 | if (progress >= 1) {
196 | _progressView.hidden = YES;
197 | self.imageRequestID = 0;
198 | }
199 | } networkAccessAllowed:YES];
200 | }
201 |
202 | - (void)recoverSubviews {
203 | [_scrollView setZoomScale:1.0 animated:NO];
204 | [self resizeSubviews];
205 | }
206 |
207 | - (void)resizeSubviews {
208 | _imageContainerView.tz_origin = CGPointZero;
209 | _imageContainerView.tz_width = self.scrollView.tz_width;
210 |
211 | UIImage *image = _imageView.image;
212 | if (image.size.height / image.size.width > self.tz_height / self.scrollView.tz_width) {
213 | _imageContainerView.tz_height = floor(image.size.height / (image.size.width / self.scrollView.tz_width));
214 | } else {
215 | CGFloat height = image.size.height / image.size.width * self.scrollView.tz_width;
216 | if (height < 1 || isnan(height)) height = self.tz_height;
217 | height = floor(height);
218 | _imageContainerView.tz_height = height;
219 | _imageContainerView.tz_centerY = self.tz_height / 2;
220 | }
221 | if (_imageContainerView.tz_height > self.tz_height && _imageContainerView.tz_height - self.tz_height <= 1) {
222 | _imageContainerView.tz_height = self.tz_height;
223 | }
224 | CGFloat contentSizeH = MAX(_imageContainerView.tz_height, self.tz_height);
225 | _scrollView.contentSize = CGSizeMake(self.scrollView.tz_width, contentSizeH);
226 | [_scrollView scrollRectToVisible:self.bounds animated:NO];
227 | _scrollView.alwaysBounceVertical = _imageContainerView.tz_height <= self.tz_height ? NO : YES;
228 | _imageView.frame = _imageContainerView.bounds;
229 |
230 | [self refreshScrollViewContentSize];
231 | }
232 |
233 | - (void)setAllowCrop:(BOOL)allowCrop {
234 | _allowCrop = allowCrop;
235 | _scrollView.maximumZoomScale = allowCrop ? 4.0 : 2.5;
236 |
237 | if ([self.asset isKindOfClass:[PHAsset class]]) {
238 | PHAsset *phAsset = (PHAsset *)self.asset;
239 | CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight;
240 | // 优化超宽图片的显示
241 | if (aspectRatio > 1.5) {
242 | self.scrollView.maximumZoomScale *= aspectRatio / 1.5;
243 | }
244 | }
245 | }
246 |
247 | - (void)refreshScrollViewContentSize {
248 | if (_allowCrop) {
249 | // 1.7.2 如果允许裁剪,需要让图片的任意部分都能在裁剪框内,于是对_scrollView做了如下处理:
250 | // 1.让contentSize增大(裁剪框右下角的图片部分)
251 | CGFloat contentWidthAdd = self.scrollView.tz_width - CGRectGetMaxX(_cropRect);
252 | CGFloat contentHeightAdd = (MIN(_imageContainerView.tz_height, self.tz_height) - self.cropRect.size.height) / 2;
253 | CGFloat newSizeW = self.scrollView.contentSize.width + contentWidthAdd;
254 | CGFloat newSizeH = MAX(self.scrollView.contentSize.height, self.tz_height) + contentHeightAdd;
255 | _scrollView.contentSize = CGSizeMake(newSizeW, newSizeH);
256 | _scrollView.alwaysBounceVertical = YES;
257 | // 2.让scrollView新增滑动区域(裁剪框左上角的图片部分)
258 | if (contentHeightAdd > 0 || contentWidthAdd > 0) {
259 | _scrollView.contentInset = UIEdgeInsetsMake(contentHeightAdd, _cropRect.origin.x, 0, 0);
260 | } else {
261 | _scrollView.contentInset = UIEdgeInsetsZero;
262 | }
263 | }
264 | }
265 |
266 | - (void)layoutSubviews {
267 | [super layoutSubviews];
268 | _scrollView.frame = CGRectMake(10, 0, self.tz_width - 20, self.tz_height);
269 | static CGFloat progressWH = 40;
270 | CGFloat progressX = (self.tz_width - progressWH) / 2;
271 | CGFloat progressY = (self.tz_height - progressWH) / 2;
272 | _progressView.frame = CGRectMake(progressX, progressY, progressWH, progressWH);
273 |
274 | [self recoverSubviews];
275 | }
276 |
277 | #pragma mark - UITapGestureRecognizer Event
278 |
279 | - (void)doubleTap:(UITapGestureRecognizer *)tap {
280 | if (_scrollView.zoomScale > 1.0) {
281 | _scrollView.contentInset = UIEdgeInsetsZero;
282 | [_scrollView setZoomScale:1.0 animated:YES];
283 | } else {
284 | CGPoint touchPoint = [tap locationInView:self.imageView];
285 | CGFloat newZoomScale = _scrollView.maximumZoomScale;
286 | CGFloat xsize = self.frame.size.width / newZoomScale;
287 | CGFloat ysize = self.frame.size.height / newZoomScale;
288 | [_scrollView zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES];
289 | }
290 | }
291 |
292 | - (void)singleTap:(UITapGestureRecognizer *)tap {
293 | if (self.singleTapGestureBlock) {
294 | self.singleTapGestureBlock();
295 | }
296 | }
297 |
298 | #pragma mark - UIScrollViewDelegate
299 |
300 | - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
301 | return _imageContainerView;
302 | }
303 |
304 | - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
305 | scrollView.contentInset = UIEdgeInsetsZero;
306 | }
307 |
308 | - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
309 | [self refreshImageContainerViewCenter];
310 | }
311 |
312 | - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
313 | [self refreshScrollViewContentSize];
314 | }
315 |
316 | #pragma mark - Private
317 |
318 | - (void)refreshImageContainerViewCenter {
319 | CGFloat offsetX = (_scrollView.tz_width > _scrollView.contentSize.width) ? ((_scrollView.tz_width - _scrollView.contentSize.width) * 0.5) : 0.0;
320 | CGFloat offsetY = (_scrollView.tz_height > _scrollView.contentSize.height) ? ((_scrollView.tz_height - _scrollView.contentSize.height) * 0.5) : 0.0;
321 | self.imageContainerView.center = CGPointMake(_scrollView.contentSize.width * 0.5 + offsetX, _scrollView.contentSize.height * 0.5 + offsetY);
322 | }
323 |
324 | @end
325 |
326 |
327 | @implementation TZVideoPreviewCell
328 |
329 | - (void)configSubviews {
330 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil];
331 | }
332 |
333 | - (void)configPlayButton {
334 | if (_playButton) {
335 | [_playButton removeFromSuperview];
336 | }
337 | _playButton = [UIButton buttonWithType:UIButtonTypeCustom];
338 | [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
339 | [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted];
340 | [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
341 | [self addSubview:_playButton];
342 | }
343 |
344 | - (void)setModel:(TZAssetModel *)model {
345 | [super setModel:model];
346 | [self configMoviePlayer];
347 | }
348 |
349 | - (void)configMoviePlayer {
350 | if (_player) {
351 | [_playerLayer removeFromSuperlayer];
352 | _playerLayer = nil;
353 | [_player pause];
354 | _player = nil;
355 | }
356 |
357 | [[TZImageManager manager] getPhotoWithAsset:self.model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
358 | _cover = photo;
359 | }];
360 | [[TZImageManager manager] getVideoWithAsset:self.model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
361 | dispatch_async(dispatch_get_main_queue(), ^{
362 | _player = [AVPlayer playerWithPlayerItem:playerItem];
363 | _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
364 | _playerLayer.backgroundColor = [UIColor blackColor].CGColor;
365 | _playerLayer.frame = self.bounds;
366 | [self.layer addSublayer:_playerLayer];
367 | [self configPlayButton];
368 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
369 | });
370 | }];
371 | }
372 |
373 | - (void)layoutSubviews {
374 | [super layoutSubviews];
375 | _playerLayer.frame = self.bounds;
376 | _playButton.frame = CGRectMake(0, 64, self.tz_width, self.tz_height - 64 - 44);
377 | }
378 |
379 | - (void)photoPreviewCollectionViewDidScroll {
380 | [self pausePlayerAndShowNaviBar];
381 | }
382 |
383 | #pragma mark - Click Event
384 |
385 | - (void)playButtonClick {
386 | CMTime currentTime = _player.currentItem.currentTime;
387 | CMTime durationTime = _player.currentItem.duration;
388 | if (_player.rate == 0.0f) {
389 | if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)];
390 | [_player play];
391 | [_playButton setImage:nil forState:UIControlStateNormal];
392 | if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
393 | if (self.singleTapGestureBlock) {
394 | self.singleTapGestureBlock();
395 | }
396 | } else {
397 | [self pausePlayerAndShowNaviBar];
398 | }
399 | }
400 |
401 | - (void)pausePlayerAndShowNaviBar {
402 | if (_player.rate != 0.0) {
403 | [_player pause];
404 | [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
405 | if (self.singleTapGestureBlock) {
406 | self.singleTapGestureBlock();
407 | }
408 | }
409 | }
410 |
411 | @end
412 |
413 |
414 | @implementation TZGifPreviewCell
415 |
416 | - (void)configSubviews {
417 | [self configPreviewView];
418 | }
419 |
420 | - (void)configPreviewView {
421 | _previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
422 | __weak typeof(self) weakSelf = self;
423 | [_previewView setSingleTapGestureBlock:^{
424 | __strong typeof(weakSelf) strongSelf = weakSelf;
425 | [strongSelf signleTapAction];
426 | }];
427 | [self addSubview:_previewView];
428 | }
429 |
430 | - (void)setModel:(TZAssetModel *)model {
431 | [super setModel:model];
432 | _previewView.model = self.model;
433 | }
434 |
435 | - (void)layoutSubviews {
436 | [super layoutSubviews];
437 | _previewView.frame = self.bounds;
438 | }
439 |
440 | #pragma mark - Click Event
441 |
442 | - (void)signleTapAction {
443 | if (self.singleTapGestureBlock) {
444 | self.singleTapGestureBlock();
445 | }
446 | }
447 |
448 | @end
449 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZPhotoPreviewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZPhotoPreviewController.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 15/12/24.
6 | // Copyright © 2015年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TZPhotoPreviewController : UIViewController
12 |
13 | @property (nonatomic, strong) NSMutableArray *models; ///< All photo models / 所有图片模型数组
14 | @property (nonatomic, strong) NSMutableArray *photos; ///< All photos / 所有图片数组
15 | @property (nonatomic, assign) NSInteger currentIndex; ///< Index of the photo user click / 用户点击的图片的索引
16 | @property (nonatomic, assign) BOOL isSelectOriginalPhoto; ///< If YES,return original photo / 是否返回原图
17 | @property (nonatomic, assign) BOOL isCropImage;
18 |
19 | /// Return the new selected photos / 返回最新的选中图片数组
20 | @property (nonatomic, copy) void (^backButtonClickBlock)(BOOL isSelectOriginalPhoto);
21 | @property (nonatomic, copy) void (^doneButtonClickBlock)(BOOL isSelectOriginalPhoto);
22 | @property (nonatomic, copy) void (^doneButtonClickBlockCropMode)(UIImage *cropedImage,id asset);
23 | @property (nonatomic, copy) void (^doneButtonClickBlockWithPreviewType)(NSArray *photos,NSArray *assets,BOOL isSelectOriginalPhoto);
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZProgressView.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZProgressView.h
3 | // TZImagePickerController
4 | //
5 | // Created by ttouch on 2016/12/6.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TZProgressView : UIView
12 |
13 | @property (nonatomic, assign) double progress;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZProgressView.m:
--------------------------------------------------------------------------------
1 | //
2 | // TZProgressView.m
3 | // TZImagePickerController
4 | //
5 | // Created by ttouch on 2016/12/6.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import "TZProgressView.h"
10 |
11 | @interface TZProgressView ()
12 | @property (nonatomic, strong) CAShapeLayer *progressLayer;
13 | @end
14 |
15 | @implementation TZProgressView
16 |
17 | - (instancetype)init {
18 | self = [super init];
19 | if (self) {
20 | self.backgroundColor = [UIColor clearColor];
21 |
22 | _progressLayer = [CAShapeLayer layer];
23 | _progressLayer.fillColor = [[UIColor clearColor] CGColor];
24 | _progressLayer.strokeColor = [[UIColor whiteColor] CGColor];
25 | _progressLayer.opacity = 1;
26 | _progressLayer.lineCap = kCALineCapRound;
27 | _progressLayer.lineWidth = 5;
28 |
29 | [_progressLayer setShadowColor:[UIColor blackColor].CGColor];
30 | [_progressLayer setShadowOffset:CGSizeMake(1, 1)];
31 | [_progressLayer setShadowOpacity:0.5];
32 | [_progressLayer setShadowRadius:2];
33 | }
34 | return self;
35 | }
36 |
37 | - (void)drawRect:(CGRect)rect {
38 | CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2);
39 | CGFloat radius = rect.size.width / 2;
40 | CGFloat startA = - M_PI_2;
41 | CGFloat endA = - M_PI_2 + M_PI * 2 * _progress;
42 | _progressLayer.frame = self.bounds;
43 | UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
44 | _progressLayer.path =[path CGPath];
45 |
46 | [_progressLayer removeFromSuperlayer];
47 | [self.layer addSublayer:_progressLayer];
48 | }
49 |
50 | - (void)setProgress:(double)progress {
51 | _progress = progress;
52 | [self setNeedsDisplay];
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZVideoPlayerController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TZVideoPlayerController.h
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 16/1/5.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class TZAssetModel;
12 | @interface TZVideoPlayerController : UIViewController
13 |
14 | @property (nonatomic, strong) TZAssetModel *model;
15 |
16 | @end
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/TZVideoPlayerController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TZVideoPlayerController.m
3 | // TZImagePickerController
4 | //
5 | // Created by 谭真 on 16/1/5.
6 | // Copyright © 2016年 谭真. All rights reserved.
7 | //
8 |
9 | #import "TZVideoPlayerController.h"
10 | #import
11 | #import "UIView+Layout.h"
12 | #import "TZImageManager.h"
13 | #import "TZAssetModel.h"
14 | #import "TZImagePickerController.h"
15 | #import "TZPhotoPreviewController.h"
16 |
17 | @interface TZVideoPlayerController () {
18 | AVPlayer *_player;
19 | AVPlayerLayer *_playerLayer;
20 | UIButton *_playButton;
21 | UIImage *_cover;
22 |
23 | UIView *_toolBar;
24 | UIButton *_doneButton;
25 | UIProgressView *_progress;
26 |
27 | UIStatusBarStyle _originStatusBarStyle;
28 | }
29 | @end
30 |
31 | #pragma clang diagnostic push
32 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
33 |
34 | @implementation TZVideoPlayerController
35 |
36 | - (void)viewDidLoad {
37 | [super viewDidLoad];
38 | self.view.backgroundColor = [UIColor blackColor];
39 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
40 | if (tzImagePickerVc) {
41 | self.navigationItem.title = tzImagePickerVc.previewBtnTitleStr;
42 | }
43 | [self configMoviePlayer];
44 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil];
45 | }
46 |
47 | - (void)viewWillAppear:(BOOL)animated {
48 | [super viewWillAppear:animated];
49 | _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
50 | [UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque;
51 | }
52 |
53 | - (void)viewWillDisappear:(BOOL)animated {
54 | [super viewWillDisappear:animated];
55 | [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle;
56 | }
57 |
58 | - (void)configMoviePlayer {
59 | [[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
60 | if (!isDegraded && photo) {
61 | _cover = photo;
62 | _doneButton.enabled = YES;
63 | }
64 | }];
65 | [[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
66 | dispatch_async(dispatch_get_main_queue(), ^{
67 | _player = [AVPlayer playerWithPlayerItem:playerItem];
68 | _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
69 | _playerLayer.frame = self.view.bounds;
70 | [self.view.layer addSublayer:_playerLayer];
71 | [self addProgressObserver];
72 | [self configPlayButton];
73 | [self configBottomToolBar];
74 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
75 | });
76 | }];
77 | }
78 |
79 | /// Show progress,do it next time / 给播放器添加进度更新,下次加上
80 | - (void)addProgressObserver{
81 | AVPlayerItem *playerItem = _player.currentItem;
82 | UIProgressView *progress = _progress;
83 | [_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
84 | float current = CMTimeGetSeconds(time);
85 | float total = CMTimeGetSeconds([playerItem duration]);
86 | if (current) {
87 | [progress setProgress:(current/total) animated:YES];
88 | }
89 | }];
90 | }
91 |
92 | - (void)configPlayButton {
93 | _playButton = [UIButton buttonWithType:UIButtonTypeCustom];
94 | [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
95 | [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted];
96 | [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
97 | [self.view addSubview:_playButton];
98 | }
99 |
100 | - (void)configBottomToolBar {
101 | _toolBar = [[UIView alloc] initWithFrame:CGRectZero];
102 | CGFloat rgb = 34 / 255.0;
103 | _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
104 |
105 | _doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
106 | _doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
107 | if (!_cover) {
108 | _doneButton.enabled = NO;
109 | }
110 | [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
111 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
112 | if (tzImagePickerVc) {
113 | [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
114 | [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
115 | } else {
116 | [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal];
117 | [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal];
118 | }
119 | [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled];
120 | [_toolBar addSubview:_doneButton];
121 | [self.view addSubview:_toolBar];
122 | }
123 |
124 | #pragma mark - Layout
125 |
126 | - (void)viewDidLayoutSubviews {
127 | [super viewDidLayoutSubviews];
128 |
129 | CGFloat statusBarHeight = [TZCommonTools tz_statusBarHeight];
130 | CGFloat statusBarAndNaviBarHeight = statusBarHeight + self.navigationController.navigationBar.tz_height;
131 | _playerLayer.frame = self.view.bounds;
132 | CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
133 | _toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
134 | _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
135 | _playButton.frame = CGRectMake(0, statusBarAndNaviBarHeight, self.view.tz_width, self.view.tz_height - statusBarAndNaviBarHeight - toolBarHeight);
136 | }
137 |
138 | #pragma mark - Click Event
139 |
140 | - (void)playButtonClick {
141 | CMTime currentTime = _player.currentItem.currentTime;
142 | CMTime durationTime = _player.currentItem.duration;
143 | if (_player.rate == 0.0f) {
144 | if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)];
145 | [_player play];
146 | [self.navigationController setNavigationBarHidden:YES];
147 | _toolBar.hidden = YES;
148 | [_playButton setImage:nil forState:UIControlStateNormal];
149 | if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
150 | } else {
151 | [self pausePlayerAndShowNaviBar];
152 | }
153 | }
154 |
155 | - (void)doneButtonClick {
156 | TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
157 | if (self.navigationController) {
158 | if (imagePickerVc.autoDismiss) {
159 | [self.navigationController dismissViewControllerAnimated:YES completion:^{
160 | [self callDelegateMethod];
161 | }];
162 | } else {
163 | [self callDelegateMethod];
164 | }
165 | } else {
166 | [self dismissViewControllerAnimated:YES completion:^{
167 | [self callDelegateMethod];
168 | }];
169 | }
170 | }
171 |
172 | - (void)callDelegateMethod {
173 | TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
174 | if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) {
175 | [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingVideo:_cover sourceAssets:_model.asset];
176 | }
177 | if (imagePickerVc.didFinishPickingVideoHandle) {
178 | imagePickerVc.didFinishPickingVideoHandle(_cover,_model.asset);
179 | }
180 | }
181 |
182 | #pragma mark - Notification Method
183 |
184 | - (void)pausePlayerAndShowNaviBar {
185 | [_player pause];
186 | _toolBar.hidden = NO;
187 | [self.navigationController setNavigationBarHidden:NO];
188 | [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
189 |
190 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
191 | if (tzImagePickerVc.needShowStatusBar && iOS7Later) {
192 | [UIApplication sharedApplication].statusBarHidden = NO;
193 | }
194 | }
195 |
196 | - (void)dealloc {
197 | [[NSNotificationCenter defaultCenter] removeObserver:self];
198 | }
199 |
200 | #pragma clang diagnostic pop
201 |
202 | @end
203 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/UIView+Layout.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Layout.h
3 | //
4 | // Created by 谭真 on 15/2/24.
5 | // Copyright © 2015年 谭真. All rights reserved.
6 | //
7 |
8 | #import
9 |
10 | typedef enum : NSUInteger {
11 | TZOscillatoryAnimationToBigger,
12 | TZOscillatoryAnimationToSmaller,
13 | } TZOscillatoryAnimationType;
14 |
15 | @interface UIView (Layout)
16 |
17 | @property (nonatomic) CGFloat tz_left; ///< Shortcut for frame.origin.x.
18 | @property (nonatomic) CGFloat tz_top; ///< Shortcut for frame.origin.y
19 | @property (nonatomic) CGFloat tz_right; ///< Shortcut for frame.origin.x + frame.size.width
20 | @property (nonatomic) CGFloat tz_bottom; ///< Shortcut for frame.origin.y + frame.size.height
21 | @property (nonatomic) CGFloat tz_width; ///< Shortcut for frame.size.width.
22 | @property (nonatomic) CGFloat tz_height; ///< Shortcut for frame.size.height.
23 | @property (nonatomic) CGFloat tz_centerX; ///< Shortcut for center.x
24 | @property (nonatomic) CGFloat tz_centerY; ///< Shortcut for center.y
25 | @property (nonatomic) CGPoint tz_origin; ///< Shortcut for frame.origin.
26 | @property (nonatomic) CGSize tz_size; ///< Shortcut for frame.size.
27 |
28 | + (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(TZOscillatoryAnimationType)type;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/TZImagePickerController/UIView+Layout.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Layout.m
3 | //
4 | // Created by 谭真 on 15/2/24.
5 | // Copyright © 2015年 谭真. All rights reserved.
6 | //
7 |
8 | #import "UIView+Layout.h"
9 |
10 | @implementation UIView (Layout)
11 |
12 | - (CGFloat)tz_left {
13 | return self.frame.origin.x;
14 | }
15 |
16 | - (void)setTz_left:(CGFloat)x {
17 | CGRect frame = self.frame;
18 | frame.origin.x = x;
19 | self.frame = frame;
20 | }
21 |
22 | - (CGFloat)tz_top {
23 | return self.frame.origin.y;
24 | }
25 |
26 | - (void)setTz_top:(CGFloat)y {
27 | CGRect frame = self.frame;
28 | frame.origin.y = y;
29 | self.frame = frame;
30 | }
31 |
32 | - (CGFloat)tz_right {
33 | return self.frame.origin.x + self.frame.size.width;
34 | }
35 |
36 | - (void)setTz_right:(CGFloat)right {
37 | CGRect frame = self.frame;
38 | frame.origin.x = right - frame.size.width;
39 | self.frame = frame;
40 | }
41 |
42 | - (CGFloat)tz_bottom {
43 | return self.frame.origin.y + self.frame.size.height;
44 | }
45 |
46 | - (void)setTz_bottom:(CGFloat)bottom {
47 | CGRect frame = self.frame;
48 | frame.origin.y = bottom - frame.size.height;
49 | self.frame = frame;
50 | }
51 |
52 | - (CGFloat)tz_width {
53 | return self.frame.size.width;
54 | }
55 |
56 | - (void)setTz_width:(CGFloat)width {
57 | CGRect frame = self.frame;
58 | frame.size.width = width;
59 | self.frame = frame;
60 | }
61 |
62 | - (CGFloat)tz_height {
63 | return self.frame.size.height;
64 | }
65 |
66 | - (void)setTz_height:(CGFloat)height {
67 | CGRect frame = self.frame;
68 | frame.size.height = height;
69 | self.frame = frame;
70 | }
71 |
72 | - (CGFloat)tz_centerX {
73 | return self.center.x;
74 | }
75 |
76 | - (void)setTz_centerX:(CGFloat)centerX {
77 | self.center = CGPointMake(centerX, self.center.y);
78 | }
79 |
80 | - (CGFloat)tz_centerY {
81 | return self.center.y;
82 | }
83 |
84 | - (void)setTz_centerY:(CGFloat)centerY {
85 | self.center = CGPointMake(self.center.x, centerY);
86 | }
87 |
88 | - (CGPoint)tz_origin {
89 | return self.frame.origin;
90 | }
91 |
92 | - (void)setTz_origin:(CGPoint)origin {
93 | CGRect frame = self.frame;
94 | frame.origin = origin;
95 | self.frame = frame;
96 | }
97 |
98 | - (CGSize)tz_size {
99 | return self.frame.size;
100 | }
101 |
102 | - (void)setTz_size:(CGSize)size {
103 | CGRect frame = self.frame;
104 | frame.size = size;
105 | self.frame = frame;
106 | }
107 |
108 | + (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(TZOscillatoryAnimationType)type{
109 | NSNumber *animationScale1 = type == TZOscillatoryAnimationToBigger ? @(1.15) : @(0.5);
110 | NSNumber *animationScale2 = type == TZOscillatoryAnimationToBigger ? @(0.92) : @(1.15);
111 |
112 | [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
113 | [layer setValue:animationScale1 forKeyPath:@"transform.scale"];
114 | } completion:^(BOOL finished) {
115 | [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
116 | [layer setValue:animationScale2 forKeyPath:@"transform.scale"];
117 | } completion:^(BOOL finished) {
118 | [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
119 | [layer setValue:@(1.0) forKeyPath:@"transform.scale"];
120 | } completion:nil];
121 | }];
122 | }];
123 | }
124 |
125 | @end
126 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/UIImage+CZHExtension.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+CZHExtension.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/14.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIImage (CZHExtension)
12 |
13 |
14 | + (UIImage *)czh_generateScreenShotImage;
15 | /**
16 | * 使用视图生成图片
17 | */
18 | + (UIImage *)czh_generateImageWithView:(UIView *)view;
19 |
20 | //生成二维码
21 | + (UIImage *)czh_generateQRCodeWithCodeContent:(NSString *)codeContent codeSize:(CGFloat)codeSize;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/UIImage+CZHExtension.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+CZHExtension.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/14.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "UIImage+CZHExtension.h"
10 |
11 | @implementation UIImage (CZHExtension)
12 |
13 |
14 |
15 | ////截取当前屏幕
16 | + (UIImage *)czh_generateScreenShotImage {
17 |
18 | CGSize imageSize = CGSizeZero;
19 | imageSize = [UIScreen mainScreen].bounds.size;
20 |
21 | UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale);
22 |
23 | CGContextRef context = UIGraphicsGetCurrentContext();
24 |
25 | for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
26 |
27 | CGContextSaveGState(context);
28 | CGContextTranslateCTM(context, window.center.x, window.center.y);
29 | CGContextConcatCTM(context, window.transform);
30 | CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
31 |
32 | if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
33 |
34 | [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
35 |
36 | } else {
37 |
38 | [window.layer renderInContext:context];
39 |
40 | }
41 | CGContextRestoreGState(context);
42 | }
43 |
44 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
45 | UIGraphicsEndImageContext();
46 | NSData *imageData = UIImagePNGRepresentation(image);
47 |
48 | return [UIImage imageWithData:imageData];
49 |
50 | }
51 |
52 |
53 | + (UIImage *)czh_generateImageWithView:(UIView *)view {
54 |
55 | CGSize size = view.bounds.size;
56 |
57 | // 下面方法,第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数就是屏幕密度了,关键就是第三个参数。
58 |
59 | UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
60 |
61 | [view.layer renderInContext:UIGraphicsGetCurrentContext()];
62 |
63 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
64 |
65 | UIGraphicsEndImageContext();
66 |
67 | return image;
68 | }
69 |
70 | //生成二维码
71 | + (UIImage *)czh_generateQRCodeWithCodeContent:(NSString *)codeContent codeSize:(CGFloat)codeSize {
72 |
73 | // 1.创建过滤器,这里的@"CIQRCodeGenerator"是固定的
74 | CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
75 |
76 | // 2.恢复默认设置
77 | [filter setDefaults];
78 |
79 | // 3. 给过滤器添加数据
80 | NSString *dataString = codeContent;
81 |
82 | NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
83 | // 注意,这里的value必须是NSData类型
84 | [filter setValue:data forKeyPath:@"inputMessage"];
85 |
86 | // 4. 生成二维码
87 | CIImage *outputImage = [filter outputImage];
88 |
89 |
90 | CGRect extent = CGRectIntegral(outputImage.extent);
91 | CGFloat scale = MIN(codeSize/CGRectGetWidth(extent), codeSize/CGRectGetHeight(extent));
92 |
93 | // 1. 创建bitmap
94 | size_t width = CGRectGetWidth(extent) * scale;
95 | size_t height = CGRectGetHeight(extent) * scale;
96 | CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
97 | CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
98 | CIContext *context = [CIContext contextWithOptions:nil];
99 | CGImageRef bitmapImage = [context createCGImage:outputImage fromRect:extent];
100 | CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
101 | CGContextScaleCTM(bitmapRef, scale, scale);
102 | CGContextDrawImage(bitmapRef, extent, bitmapImage);
103 |
104 | // 2.保存bitmap图片
105 | CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
106 | CGContextRelease(bitmapRef);
107 | CGImageRelease(bitmapImage);
108 |
109 | return [UIImage imageWithCGImage:scaledImage];
110 | }
111 |
112 |
113 | @end
114 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/UILabel+CZHExtension.h:
--------------------------------------------------------------------------------
1 | //
2 | // UILabel+CZHExtension.h
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/14.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UILabel (CZHExtension)
12 | /**
13 | * 快速创建label
14 | * frame : frame
15 | * font : 字体
16 | * textColor : 字体颜色
17 | * backgroundColor : 背景颜色
18 | * textAliment : 文字样式
19 | * shadowColor : 阴影颜色
20 | * shadowOffset : 阴影偏移量
21 | * text : 文本
22 | */
23 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor textAliment:(NSTextAlignment)textAliment shadowColor:(UIColor *)shadowColor shadowOffset:(CGSize)shadowOffset text:(NSString *)text;
24 | /**
25 | * 快速创建label
26 | * frame : frame
27 | * font : 字体
28 | * textColor : 字体颜色
29 | * backgroundColor : 背景颜色
30 | * textAliment : 文字样式
31 | * text : 文本
32 | */
33 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor textAliment:(NSTextAlignment)textAliment text:(NSString *)text;
34 | /**
35 | * 快速创建label
36 | * frame : frame
37 | * font : 字体
38 | * textColor : 字体颜色
39 | * text : 文本
40 | */
41 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor text:(NSString *)text;
42 | /**
43 | * 快速创建label
44 | * frame : frame
45 | * font : 字体
46 | * textColor : 字体颜色
47 | * backgroundColor : 背景颜色
48 | * text : 文本
49 | */
50 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor text:(NSString *)text;
51 | /**
52 | * 快速创建label
53 | * frame : frame
54 | * font : 字体
55 | * textColor : 字体颜色
56 | * textAliment : 文字样式
57 | * text : 文本
58 | */
59 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor textAliment:(NSTextAlignment)textAliment text:(NSString *)text;
60 | /**
61 | * 快速创建label
62 | * frame : frame
63 | * font : 字体
64 | * textColor : 字体颜色
65 | * textAliment : 文字样式
66 | */
67 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor;
68 |
69 | /**
70 | * 快速创建label
71 | * font : 字体
72 | * textColor : 字体颜色
73 | */
74 | + (UILabel *)czh_setLabelWithFont:(UIFont *)font textColor:(UIColor *)textColor ;
75 | /**
76 | * 快速创建label
77 | * font : 字体
78 | * textColor : 字体颜色
79 | * textAliment : 文字样式
80 | */
81 | + (UILabel *)czh_setLabelWithFont:(UIFont *)font textColor:(UIColor *)textColor textAliment:(NSTextAlignment)textAliment;
82 |
83 | /**
84 | * 快速创建label
85 | * font : 字体
86 | * textColor : 字体颜色
87 | * textAliment : 文字样式
88 | * numberOfLines : 行数
89 | */
90 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor textAliment:(NSTextAlignment)textAliment numberOfLines:(NSInteger)numberOfLines text:(NSString *)text;
91 | @end
92 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/UILabel+CZHExtension.m:
--------------------------------------------------------------------------------
1 | //
2 | // UILabel+CZHExtension.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/14.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import "UILabel+CZHExtension.h"
10 |
11 | @implementation UILabel (CZHExtension)
12 |
13 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor textAliment:(NSTextAlignment)textAliment shadowColor:(UIColor *)shadowColor shadowOffset:(CGSize)shadowOffset numberOfLines:(NSInteger)numberOfLines text:(NSString *)text {
14 | UILabel *label = [[UILabel alloc] init];
15 | label.frame = frame;
16 | label.textAlignment = textAliment;
17 | label.text = text;
18 | label.numberOfLines = numberOfLines;
19 | label.shadowColor = shadowColor;
20 | label.shadowOffset = shadowOffset;
21 | if (backgroundColor == nil) {
22 | label.backgroundColor = [UIColor clearColor];
23 | } else {
24 | label.backgroundColor = backgroundColor;
25 | }
26 | label.font = font;
27 | label.textColor = textColor;
28 |
29 | return label;
30 | }
31 |
32 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor textAliment:(NSTextAlignment)textAliment shadowColor:(UIColor *)shadowColor shadowOffset:(CGSize)shadowOffset text:(NSString *)text {
33 |
34 | return [UILabel czh_setLabelWithFrame:frame font:font textColor:textColor backgroundColor:backgroundColor textAliment:textAliment shadowColor:shadowColor shadowOffset:shadowOffset numberOfLines:1 text:text];
35 | }
36 |
37 | + (UILabel *)czh_czh_setLabelWithFont:(UIFont *)font textColor:(UIColor *)textColor {
38 |
39 | return [UILabel czh_setLabelWithFrame:CGRectZero font:font textColor:textColor backgroundColor:[UIColor clearColor] textAliment:NSTextAlignmentLeft shadowColor:nil shadowOffset:CGSizeZero numberOfLines:1 text:nil];
40 | }
41 |
42 | + (UILabel *)czh_setLabelWithFont:(UIFont *)font textColor:(UIColor *)textColor textAliment:(NSTextAlignment)textAliment{
43 |
44 | return [UILabel czh_setLabelWithFrame:CGRectZero font:font textColor:textColor backgroundColor:[UIColor clearColor] textAliment:textAliment shadowColor:nil shadowOffset:CGSizeZero numberOfLines:1 text:nil];
45 | }
46 |
47 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor textAliment:(NSTextAlignment)textAliment numberOfLines:(NSInteger)numberOfLines text:(NSString *)text{
48 |
49 | return [UILabel czh_setLabelWithFrame:frame font:font textColor:textColor backgroundColor:[UIColor clearColor] textAliment:textAliment shadowColor:nil shadowOffset:CGSizeZero numberOfLines:numberOfLines text:text];
50 | }
51 |
52 |
53 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor textAliment:(NSTextAlignment)textAliment text:(NSString *)text {
54 |
55 | return [UILabel czh_setLabelWithFrame:frame font:font textColor:textColor backgroundColor:backgroundColor textAliment:textAliment shadowColor:nil shadowOffset:CGSizeZero text:text];
56 | }
57 |
58 |
59 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor text:(NSString *)text {
60 | return [UILabel czh_setLabelWithFrame:frame font:font textColor:textColor backgroundColor:backgroundColor textAliment:NSTextAlignmentLeft text:text];
61 | }
62 |
63 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor textAliment:(NSTextAlignment)textAliment text:(NSString *)text {
64 | return [UILabel czh_setLabelWithFrame:frame font:font textColor:textColor backgroundColor:[UIColor clearColor] textAliment:textAliment text:text];
65 | }
66 |
67 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor text:(NSString *)text {
68 | return [UILabel czh_setLabelWithFrame:frame font:font textColor:textColor backgroundColor:[UIColor clearColor] textAliment:NSTextAlignmentLeft text:text];
69 | }
70 |
71 | + (UILabel *)czh_setLabelWithFrame:(CGRect)frame font:(UIFont *)font textColor:(UIColor *)textColor {
72 | return [UILabel czh_setLabelWithFrame:frame font:font textColor:textColor backgroundColor:[UIColor clearColor] textAliment:NSTextAlignmentLeft text:nil];
73 | }
74 | @end
75 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/UIView+CZHExtension.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+CZHExtension.h
3 | // CZHDatePickerView
4 | //
5 | // Created by 程召华 on 2017/11/20.
6 | // Copyright © 2017年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIView (CZHExtension)
12 | @property (nonatomic, assign) CGFloat czh_top;
13 | @property (nonatomic, assign) CGFloat czh_bottom;
14 | @property (nonatomic, assign) CGFloat czh_left;
15 | @property (nonatomic, assign) CGFloat czh_right;
16 | @property (nonatomic, assign) CGFloat czh_x;
17 | @property (nonatomic, assign) CGFloat czh_y;
18 | @property (nonatomic, assign) CGFloat czh_centerX;
19 | @property (nonatomic, assign) CGFloat czh_centerY;
20 | @property (nonatomic, assign) CGFloat czh_width;
21 | @property (nonatomic, assign) CGFloat czh_height;
22 | @property (nonatomic, assign) CGSize czh_size;
23 | @property (nonatomic, assign) CGPoint czh_origin;
24 |
25 | /**
26 | * 给view切圆角
27 | * corners : 哪个角
28 | * cornerRadii : 圆角size
29 | */
30 | - (instancetype)czh_cornerByRoundingCorners:(UIRectCorner)corners cornerRadius:(CGFloat)cornerRadius;
31 | /**
32 | * 给view所有角切圆角
33 | * cornerRadii : 圆角size
34 | */
35 | - (instancetype)czh_cornerAllCornersWithCornerRadius:(CGFloat)cornerRadius;
36 | @end
37 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/UIView+CZHExtension.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+CZHExtension.m
3 | // CZHDatePickerView
4 | //
5 | // Created by 程召华 on 2017/11/20.
6 | // Copyright © 2017年 程召华. All rights reserved.
7 | //
8 |
9 | #import "UIView+CZHExtension.h"
10 |
11 | @implementation UIView (CZHExtension)
12 |
13 | - (CGFloat)czh_top {
14 | return self.frame.origin.y;
15 | }
16 |
17 | - (void)setCzh_top:(CGFloat)czh_top {
18 | CGRect frame = self.frame;
19 | frame.origin.y = czh_top;
20 | self.frame = frame;
21 | }
22 |
23 | - (CGFloat)czh_left {
24 | return self.frame.origin.x;
25 | }
26 |
27 | - (void)setCzh_left:(CGFloat)czh_left {
28 | CGRect frame = self.frame;
29 | frame.origin.x = czh_left;
30 | self.frame = frame;
31 | }
32 |
33 |
34 | - (CGFloat)czh_right {
35 | return CGRectGetMaxX(self.frame);
36 | }
37 |
38 | - (void)setCzh_right:(CGFloat)czh_right {
39 | self.czh_x = czh_right - self.czh_width;
40 | }
41 |
42 |
43 | - (CGFloat)czh_bottom {
44 | return CGRectGetMaxY(self.frame);
45 | }
46 |
47 | - (void)setCzh_bottom:(CGFloat)czh_bottom {
48 | self.czh_y = czh_bottom - self.czh_height;
49 | }
50 |
51 | - (void)setCzh_x:(CGFloat)czh_x {
52 | CGRect frame = self.frame;
53 | frame.origin.x = czh_x;
54 | self.frame = frame;
55 | }
56 |
57 | - (void)setCzh_y:(CGFloat)czh_y
58 | {
59 | CGRect frame = self.frame;
60 | frame.origin.y = czh_y;
61 | self.frame = frame;
62 | }
63 |
64 | - (CGFloat)czh_x
65 | {
66 | return self.frame.origin.x;
67 | }
68 |
69 | - (CGFloat)czh_y
70 | {
71 | return self.frame.origin.y;
72 | }
73 |
74 | - (void)setCzh_centerX:(CGFloat)czh_centerX
75 | {
76 | CGPoint center = self.center;
77 | center.x = czh_centerX;
78 | self.center = center;
79 | }
80 |
81 | - (CGFloat)czh_centerX
82 | {
83 | return self.center.x;
84 | }
85 |
86 | - (void)setCzh_centerY:(CGFloat)czh_centerY
87 | {
88 | CGPoint center = self.center;
89 | center.y = czh_centerY;
90 | self.center = center;
91 | }
92 |
93 | - (CGFloat)czh_centerY
94 | {
95 | return self.center.y;
96 | }
97 |
98 | - (void)setCzh_width:(CGFloat)czh_width
99 | {
100 | CGRect frame = self.frame;
101 | frame.size.width = czh_width;
102 | self.frame = frame;
103 | }
104 |
105 | - (void)setCzh_height:(CGFloat)czh_height
106 | {
107 | CGRect frame = self.frame;
108 | frame.size.height = czh_height;
109 | self.frame = frame;
110 | }
111 |
112 | - (CGFloat)czh_height
113 | {
114 | return self.frame.size.height;
115 | }
116 |
117 | - (CGFloat)czh_width
118 | {
119 | return self.frame.size.width;
120 | }
121 |
122 | - (void)setCzh_size:(CGSize)czh_size
123 | {
124 | CGRect frame = self.frame;
125 | frame.size = czh_size;
126 | self.frame = frame;
127 | }
128 |
129 | - (CGSize)czh_size
130 | {
131 | return self.frame.size;
132 | }
133 |
134 | - (void)setCzh_origin:(CGPoint)czh_origin
135 | {
136 | CGRect frame = self.frame;
137 | frame.origin = czh_origin;
138 | self.frame = frame;
139 | }
140 |
141 | - (CGPoint)czh_origin
142 | {
143 | return self.frame.origin;
144 | }
145 | /**
146 | * 给view切圆角
147 | * corners : 哪个角
148 | * cornerRadii : 圆角size
149 | */
150 | - (instancetype)czh_cornerByRoundingCorners:(UIRectCorner)corners cornerRadius:(CGFloat)cornerRadius {
151 | UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(cornerRadius, cornerRadius)];
152 | CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
153 | maskLayer.frame = self.bounds;
154 | maskLayer.path = maskPath.CGPath;
155 | self.layer.mask = maskLayer;
156 | self.layer.contentsScale = [[UIScreen mainScreen] scale];
157 | return self;
158 | }
159 | /**
160 | * 给view所有角切圆角
161 | * cornerRadii : 圆角size
162 | */
163 | - (instancetype)czh_cornerAllCornersWithCornerRadius:(CGFloat)cornerRadius {
164 |
165 | return [self czh_cornerByRoundingCorners:UIRectCornerAllCorners cornerRadius:cornerRadius];
166 |
167 | }
168 |
169 |
170 | @end
171 |
--------------------------------------------------------------------------------
/CZHSyntheticImages/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // CZHSyntheticImages
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/CZHSyntheticImagesTests/CZHSyntheticImagesTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHSyntheticImagesTests.m
3 | // CZHSyntheticImagesTests
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CZHSyntheticImagesTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation CZHSyntheticImagesTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/CZHSyntheticImagesTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/CZHSyntheticImagesUITests/CZHSyntheticImagesUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // CZHSyntheticImagesUITests.m
3 | // CZHSyntheticImagesUITests
4 | //
5 | // Created by 程召华 on 2018/6/13.
6 | // Copyright © 2018年 程召华. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CZHSyntheticImagesUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation CZHSyntheticImagesUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/CZHSyntheticImagesUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 
5 |
6 |
7 | ```
8 | /**合成本地图片*/
9 | UIImage *firstImage = self.firstImageView.image;
10 |
11 | UIImage *secondImage = self.secondImageView.image;
12 |
13 | //以底部图片大小为画布创建上下文
14 | UIGraphicsBeginImageContext(CGSizeMake(self.firstImageView.czh_width, self.firstImageView.czh_height));
15 | //先把底部图片 画到上下文中
16 | [firstImage drawInRect:self.firstImageView.frame];
17 | //再把上面图片 放在上下文中
18 | [secondImage drawInRect:self.secondImageView.frame];
19 | //从当前上下文中获得最终图片
20 | UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
21 | //关闭上下文
22 | UIGraphicsEndImageContext();
23 |
24 | ```
25 |
26 | ```
27 | 合成网络图片
28 | NSString *firstUrl = @"http://static.yygo.tv/avatar/2/5a712bc7790f2.png";
29 |
30 | NSString *secondUrl = @"http://static.yygo.tv/avatar/2/5a5756e2dd94b.png";
31 |
32 | //
33 | czh_dispatch_queue_async_safe(dispatch_get_global_queue(0, 0), ^{
34 |
35 | //
36 | NSData *fistData = [NSData dataWithContentsOfURL:[NSURL URLWithString:firstUrl]];
37 |
38 | UIImage *firstImage = [UIImage imageWithData:fistData];
39 |
40 |
41 | CGFloat firstImageW = 0;
42 | CGFloat firstImageH = 0;
43 | if (firstImage.size.height > 0 && firstImage.size.width > 0) {
44 |
45 | if (firstImage.size.height > firstImage.size.width) {
46 | firstImageW = ScreenWidth;
47 | firstImageH = firstImageW * firstImage.size.height / firstImage.size.width;
48 | } else {
49 | firstImageH = ScreenWidth;
50 | firstImageW = firstImageH * firstImage.size.width / firstImage.size.height;
51 | }
52 | }
53 |
54 |
55 | NSData *secondData = [NSData dataWithContentsOfURL:[NSURL URLWithString:secondUrl]];
56 |
57 | UIImage *secondImage = [UIImage imageWithData:secondData];
58 |
59 |
60 | CGFloat secondImageW = 0;
61 | CGFloat secondImageH = 0;
62 | if (secondImage.size.height > 0 && secondImage.size.width > 0) {
63 |
64 | if (secondImage.size.height > secondImage.size.width) {
65 | secondImageW = ScreenWidth;
66 | secondImageH = secondImageW * secondImage.size.height / secondImage.size.width;
67 | } else {
68 | secondImageH = ScreenWidth;
69 | secondImageW = secondImageH * secondImage.size.width / secondImage.size.height;
70 | }
71 | }
72 |
73 |
74 | //固定的大小为画布创建上下文
75 | UIGraphicsBeginImageContext(CGSizeMake(ScreenWidth, ScreenWidth));
76 |
77 | [firstImage drawInRect:CGRectMake((ScreenWidth - firstImageW)*0.5, (ScreenWidth - firstImageH)* 0.5, firstImageW, firstImageH)];//先把网络封面图片放在下面
78 |
79 | [secondImage drawInRect:CGRectMake((ScreenWidth - secondImageW * 0.5)*0.5, (ScreenWidth - secondImageH * 0.5)*0.5, secondImageW * 0.5, secondImageH * 0.5)];//再把小图放在上面
80 |
81 | //需要合成更多,继续添加
82 |
83 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();//从当前上下文中获得最终图片
84 | UIGraphicsEndImageContext();//关闭上下文
85 |
86 | czh_dispatch_main_sync_safe(^{
87 |
88 | [CZHShowSyntheticImageView czh_showSyntheticImageViewWithImage:resultImage];
89 | });
90 |
91 |
92 | });
93 |
94 | ```
95 |
96 | ```
97 | //把视图生成图片
98 | + (UIImage *)czh_generateImageWithView:(UIView *)view {
99 |
100 | CGSize size = view.bounds.size;
101 |
102 | // 下面方法,第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数就是屏幕密度了,关键就是第三个参数。
103 |
104 | UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
105 |
106 | [view.layer renderInContext:UIGraphicsGetCurrentContext()];
107 |
108 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
109 |
110 | UIGraphicsEndImageContext();
111 |
112 | return image;
113 | }
114 |
115 | ```
116 |
117 | ```
118 | 截图功能,首先监听通知
119 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDidTakeScreenshot:) name:UIApplicationUserDidTakeScreenshotNotification object:nil];
120 |
121 | 然后获取当前页面生成图片
122 | ////截取当前屏幕
123 | + (UIImage *)czh_generateScreenShotImage {
124 |
125 | CGSize imageSize = CGSizeZero;
126 | imageSize = [UIScreen mainScreen].bounds.size;
127 |
128 | UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale);
129 |
130 | CGContextRef context = UIGraphicsGetCurrentContext();
131 |
132 | for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
133 |
134 | CGContextSaveGState(context);
135 | CGContextTranslateCTM(context, window.center.x, window.center.y);
136 | CGContextConcatCTM(context, window.transform);
137 | CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
138 |
139 | if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
140 |
141 | [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
142 |
143 | } else {
144 |
145 | [window.layer renderInContext:context];
146 |
147 | }
148 | CGContextRestoreGState(context);
149 | }
150 |
151 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
152 | UIGraphicsEndImageContext();
153 | NSData *imageData = UIImagePNGRepresentation(image);
154 |
155 | return [UIImage imageWithData:imageData];
156 |
157 | }
158 |
159 | ```
160 | [博客地址](https://blog.csdn.net/HurryUpCheng)
161 | [简书地址](https://www.jianshu.com/u/2add458bf239)
162 |
--------------------------------------------------------------------------------