├── 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 | ![QQ20180614-161704.gif](https://upload-images.jianshu.io/upload_images/6709174-509eb0c4fb9f5274.gif?imageMogr2/auto-orient/strip) 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 | --------------------------------------------------------------------------------