Commit 89c5d1425d3781882e060e00ccd0927c716127d3

Authored by 梁星国
1 parent f4202c95

提交解决问题

TODO:    1.bundle文件整理
		2.宏定义改为系统方法编写
Showing 46 changed files with 4707 additions and 0 deletions

Too many changes to show.

To preserve performance only 46 of 62 files are displayed.

CNLiveImagePickerController.podspec 0 → 100644
  1 +#
  2 +# Be sure to run `pod spec lint CNLiveImagePickerController.podspec' to ensure this is a
  3 +# valid spec and to remove all comments including this before submitting the spec.
  4 +#
  5 +# To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
  6 +# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
  7 +#
  8 +
  9 +Pod::Spec.new do |s|
  10 +
  11 + # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  12 + #
  13 + # These will help people to find your library, and whilst it
  14 + # can feel like a chore to fill in it's definitely to your advantage. The
  15 + # summary should be tweet-length, and the description more in depth.
  16 + #
  17 +
  18 + s.name = "CNLiveImagePickerController" # 项目名称
  19 + s.version = "0.0.1" # 版本号 与 你仓库的 标签号 对应
  20 + s.summary = "相册选择基于TZImagePickerController" # 项目简介
  21 +
  22 + # This description is used to generate tags and improve search results.
  23 + # * Think: What does it do? Why did you write it? What is the focus?
  24 + # * Try to keep it short, snappy and to the point.
  25 + # * Write the description between the DESC delimiters below.
  26 + # * Finally, don't worry about the indent, CocoaPods strips it!
  27 + s.description = <<-DESC
  28 + 1.相册选择图片,视频
  29 + DESC
  30 +
  31 + s.homepage = "http://bj.gitlab.cnlive.com/ios-team/CNLiveImagePickerController"
  32 +
  33 + # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
  34 +
  35 +
  36 + # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  37 + #
  38 + # Licensing your code is important. See http://choosealicense.com for more info.
  39 + # CocoaPods will detect a license file if there is a named LICENSE*
  40 + # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
  41 + #
  42 +
  43 + s.license = "MIT" # 开源证书
  44 + # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
  45 +
  46 +
  47 + # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  48 + #
  49 + # Specify the authors of the library, with email addresses. Email addresses
  50 + # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
  51 + # accepts just a name if you'd rather not provide an email address.
  52 + #
  53 + # Specify a social_media_url where others can refer to, for example a twitter
  54 + # profile URL.
  55 + #
  56 +
  57 + s.author = { "梁星国" => "liangxingguo@cnlive.com" }
  58 + # Or just: s.author = "梁星国"
  59 + # s.authors = { "梁星国" => "jyyjkt@qq.com" }
  60 + # s.social_media_url = "http://twitter.com/梁星国"
  61 +
  62 + # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  63 + #
  64 + # If this Pod runs only on iOS or OS X, then specify the platform and
  65 + # the deployment target. You can optionally include the target after the platform.
  66 + #
  67 +
  68 + # s.platform = :ios
  69 + s.platform = :ios, "9.0"
  70 +
  71 + # When using multiple platforms
  72 + # s.ios.deployment_target = "5.0"
  73 + # s.osx.deployment_target = "10.7"
  74 + # s.watchos.deployment_target = "2.0"
  75 + # s.tvos.deployment_target = "9.0"
  76 +
  77 +
  78 + # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  79 + #
  80 + # Specify the location from where the source should be retrieved.
  81 + # Supports git, hg, bzr, svn and HTTP.
  82 + #
  83 +
  84 + s.source = { :git => "http://bj.gitlab.cnlive.com/ios-team/CNLiveImagePickerController.git", :tag => "#{s.version}" } #你的仓库地址
  85 +
  86 +
  87 + # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  88 + #
  89 + # CocoaPods is smart about how it includes source code. For source files
  90 + # giving a folder will include any swift, h, m, mm, c & cpp files.
  91 + # For header files it will include any header in the folder.
  92 + # Not including the public_header_files will make all headers public.
  93 + #
  94 +
  95 + s.source_files = "CNLiveImagePickerController/*"
  96 + s.exclude_files = "Classes/Exclude"
  97 +
  98 + # s.public_header_files = "Classes/**/*.h"
  99 +
  100 +
  101 + # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  102 + #
  103 + # A list of resources included with the Pod. These are copied into the
  104 + # target bundle with a build phase script. Anything else will be cleaned.
  105 + # You can preserve files from being cleaned, please don't preserve
  106 + # non-essential files like tests, examples and documentation.
  107 + #
  108 +
  109 + # s.resource = "icon.png"
  110 + # s.resources = "Resources/*.png"
  111 +
  112 + # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
  113 +
  114 +
  115 + # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  116 + #
  117 + # Link your library with frameworks, or libraries. Libraries do not include
  118 + # the lib prefix of their name.
  119 + #
  120 +
  121 + # s.framework = "SomeFramework"
  122 + s.frameworks = "UIKit", "Foundation" #支持的框架
  123 +
  124 + # s.library = "iconv"
  125 + # s.libraries = "iconv", "xml2"
  126 +
  127 +
  128 + # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  129 + #
  130 + # If your library depends on compiler flags you can set them in the xcconfig hash
  131 + # where they will only apply to your library. If you depend on other Podspecs
  132 + # you can include multiple dependencies to ensure it works.
  133 +
  134 + s.requires_arc = true
  135 +
  136 + # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
  137 + # s.dependency "JSONKit", "~> 1.4"
  138 +
  139 +end
CNLiveImagePickerController/AppCommonDefine.h 0 → 100644
  1 +//
  2 +// AppCommonDefine.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 张旭 on 2018/1/2.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#ifndef AppCommonDefine_h
  10 +#define AppCommonDefine_h
  11 +
  12 +#ifndef CNLiveNetAddUrlSchems
  13 +#define CNLiveNetAddUrlSchems @"CNLiveNetAddUrlSchems" //
  14 +#endif
  15 +
  16 +#ifndef CNThirdPayBack
  17 +#define CNThirdPayBack @"CNThirdPayBack" //三方支付返回标识
  18 +#endif
  19 +
  20 +#ifndef CNThirdPayOrderId
  21 +#define CNThirdPayOrderId @"CNThirdPayOrderId" //三方支付订单Id
  22 +#endif
  23 +
  24 +#ifndef CNDarenHomeSelectChangeNotification
  25 +#define CNDarenHomeSelectChangeNotification @"CNDarenHomeSelectChangeNotification" //达人主页选择type 改变
  26 +#define CNAddGroupMemberNotification @"CNAddGroupMemberNotification" //添加群成员
  27 +#define CNDeleteGroupMemberNotification @"CNDeleteGroupMemberNotification" //删除群成功
  28 +#define CNMoviePlaybackStateChangeNotication @"CNMoviePlaybackStateChangeNotication" //播放状态发生改变
  29 +#define CNApplyRefundSuccessNotification @"CNApplyRefundSuccessNotification" //申请退款成功
  30 +#define CNEvaluateSuccessNotioncation @"CNEvaluateSuccessNotioncation" //评论成功
  31 +#define CNUpdateDefultAddressSuccessNotication @"CNUpdateDefultAddressSuccessNotication" //添加或修个收货地址成功
  32 +#define CNDeleteDefultAddressSuccessNotication @"CNDeleteDefultAddressSUccessNotication" //删除默认的收货地址
  33 +#define CNSendImageSuccessNotication @"CNSendImageSuccessNotication" //发送图片成功,更新UI
  34 +#define CNRatatePortraitNotication @"CNRatatePortraitNotication" //全屏点击分享通知播放界面 由全屏变为竖屏
  35 +#endif
  36 +
  37 +//*** Native Classify
  38 +
  39 +//点击推荐页的栏目 跳转到对应栏目详细页
  40 +#define ChangeHomeChannel @"changeHomeChannel"
  41 +
  42 +//首页pagingView News类型的页面从屏幕上消失 news页面上的播放器同时消失
  43 +#define NewsPagingViewDisappear @"NewsPagingViewDisappear"
  44 +
  45 +#define OldChannelVersion @"OldChannelVersion" //首页频道列表版本号
  46 +#define NewChannelVersion @"NewChannelVersion"
  47 +
  48 +#define NormalChannelArray @"NormalChannelArray" //常用频道
  49 +#define OtherChannelArray @"OtherChannelArray" //其他频道
  50 +
  51 +#define AppVersion [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] //CFBundleShortVersionString
  52 +
  53 +//***
  54 +
  55 +// 分类板块h5地址存储
  56 +#ifndef CNLiveNetAddCategoryChannels
  57 +#define CNLiveNetAddCategoryChannels @"CNLiveNetAddCategoryChannels"
  58 +#endif
  59 +// App Store版本号存储
  60 +#ifndef CNLiveNetAddAppStoreVersionNumber
  61 +#define CNLiveNetAddAppStoreVersionNumber @"CNLiveNetAddAppStoreVersionNumber"
  62 +#endif
  63 +////////////////////////////////////////////////////////
  64 +//////////// AppDelegate
  65 +////////////////////////////////////////////////////////
  66 +#ifndef AppKeyWindow
  67 +#define AppKeyWindow ((AppDelegate *)[UIApplication sharedApplication].delegate).window
  68 +#endif
  69 +
  70 +#ifndef CNAppDelegate
  71 +#define CNAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
  72 +#endif
  73 +
  74 +
  75 +////////////////////////////////////////////////////////
  76 +//////////// function
  77 +////////////////////////////////////////////////////////
  78 +#define isAllowChangeTheme 0
  79 +
  80 +
  81 +////////////////////////////////////////////////////////
  82 +//////////// SCreen
  83 +////////////////////////////////////////////////////////
  84 +#define KScreenWidth ([UIScreen mainScreen].bounds.size.width > [UIScreen mainScreen].bounds.size.height ? [UIScreen mainScreen].bounds.size.height : [UIScreen mainScreen].bounds.size.width)
  85 +#define KScreenHeight ([UIScreen mainScreen].bounds.size.width > [UIScreen mainScreen].bounds.size.height ? [UIScreen mainScreen].bounds.size.width : [UIScreen mainScreen].bounds.size.height)
  86 +
  87 +
  88 +//判断iPHoneXr
  89 +#define Device_Is_iPhoneXS_XR ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(828, 1792), [[UIScreen mainScreen] currentMode].size) : NO)
  90 +
  91 +//判断iPHoneX、iPHoneXs
  92 +#define Device_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
  93 +#define Device_Is_iPhoneXS ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
  94 +
  95 +//判断iPhoneXs Max
  96 +#define Device_Is_iPhoneXS_MAX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1242, 2688), [[UIScreen mainScreen] currentMode].size) : NO)
  97 +
  98 +#define IS_IPhoneX_All (CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(375, 812)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(812, 375)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(414, 896)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(896, 414)))
  99 +
  100 +
  101 +#define kStatusHeight (int)[UIApplication sharedApplication].statusBarFrame.size.height //x44 非x20
  102 +#define kNavigationBarHeight ((int)[UIApplication sharedApplication].statusBarFrame.size.height+44) //x88 非x64
  103 +#define kVerticalNaviBarHeight ((IS_IPhoneX_All > 0) ? 88 : 44)
  104 +#define kVerticalTabBarTotalHeight ((IS_IPhoneX_All > 0) ? 83 : 49)
  105 +#define kVerticalBottomSafeHeight ((IS_IPhoneX_All > 0) ? 34 : 0)
  106 +#define kVerticalStatusHeight ((IS_IPhoneX_All > 0) ? 44 : 20)
  107 +#define kVerticalTopHeight ((IS_IPhoneX_All > 0) ? 24 : 0)
  108 +#define kHorizontalTopNaviBarHeight 32
  109 +#define kHorizontalBottomHeight ((IS_IPhoneX_All > 0) ? 21 : 0)
  110 +#define kHorizontalLeftHeight ((IS_IPhoneX_All > 0) ? 44 : 0)
  111 +#define kHorizontalRightHeight ((IS_IPhoneX_All > 0) ? 44 : 0)
  112 +#define kHorizontalTopHeight ((IS_IPhoneX_All > 0) ? 24 : 0)
  113 +//////////////////////分类中直播点播横屏特用////////////////////////////
  114 +#define kLiveHorizontalTopHeight ((Device_Is_iPhoneX > 0) ? 6 : 0)
  115 +#define kLiveHorizontalBottomHeight ((Device_Is_iPhoneX > 0) ? 11 : 0)
  116 +
  117 +////////////////////////////////////////////////////////
  118 +//////////// Font
  119 +////////////////////////////////////////////////////////
  120 +#define kAppLargeTextFont [UIFont systemFontOfSize:16]
  121 +#define kAppMiddleTextFont [UIFont systemFontOfSize:14]
  122 +#define kAppSmallTextFont [UIFont systemFontOfSize:12]
  123 +
  124 +#define TopToolBarHeight (64.0 + IPhoneXSafeAreaInsets.bottom)
  125 +
  126 +////////////////////////////////////////////////////////
  127 +//////////// 发送图片,视频限制
  128 +////////////////////////////////////////////////////////
  129 +#define kFriendsCircle_limit_photo 20*1024.0*1024.0 //朋友圈限制图片20M
  130 +#define kFirendsCircle_limit_video 30*1024.0*1024.0 //朋友圈限制视频30M
  131 +#define kTarentoComment_limit_photo 10*1024.0*1024.0 //达人评论10M
  132 +#define kSweepCode_limit_phoho 10*1024.0*1024.0 //扫码10M限制
  133 +#define kChat_limit_photo 20*1024.0*1024.0 //聊天限制图片20M
  134 +#define kChat_limit_video 20*1024.0*1024.0 //聊天限制视频20M
  135 +
  136 +#define kChat_limit_video_length 5*60 //聊天限制视频5分钟
  137 +#define kFriendsCircle_limit_video_maxEdit 5*60 //朋友圈限制视频5分钟
  138 +#define kFriendsCircle_limit_video_max 10*60 //朋友圈限制最大视频编辑10分钟
  139 +
  140 +////////////////////////////////////////////////////////
  141 +//////////// Color
  142 +////////////////////////////////////////////////////////
  143 +
  144 +#define RGBOF(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
  145 +green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
  146 +blue:((float)(rgbValue & 0xFF))/255.0 \
  147 +alpha:1.0]
  148 +
  149 +#define RGBA_OF(rgbValue) [UIColor colorWithRed:((float)(((rgbValue) & 0xFF000000) >> 24))/255.0 \
  150 +green:((float)(((rgbValue) & 0x00FF0000) >> 16))/255.0 \
  151 +blue:((float)(rgbValue & 0x0000FF00) >> 8)/255.0 \
  152 +alpha:((float)(rgbValue & 0x000000FF))/255.0]
  153 +
  154 +#define RGBAOF(v, a) [UIColor colorWithRed:((float)(((v) & 0xFF0000) >> 16))/255.0 \
  155 +green:((float)(((v) & 0x00FF00) >> 8))/255.0 \
  156 +blue:((float)(v & 0x0000FF))/255.0 \
  157 +alpha:a]
  158 +
  159 +
  160 +
  161 +#define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a]
  162 +#define RGB(r,g,b) RGBA(r,g,b,1.0f)
  163 +#define CommonBgColor [UIColor colorWithHexString:@"eeeeee"];
  164 +
  165 +#define kDarenBgColor [UIColor colorWithRed:0.36 green:0.36 blue:0.36 alpha:1.00]
  166 +
  167 +#define kDarenGradeColor [UIColor colorWithRed:0.85 green:0.36 blue:0.10 alpha:1.00]
  168 +
  169 +#define kDarenYellowColor [UIColor colorWithRed:0.97 green:0.75 blue:0.03 alpha:1.00]
  170 +
  171 +#define kDarenGreenColor [UIColor colorWithRed:0.08 green:0.86 blue:0.52 alpha:1.00]
  172 +
  173 +#define kToolGrayColor [UIColor colorWithRed:0.94 green:0.94 blue:0.94 alpha:1.00]
  174 +
  175 +#define kCameraNextBtnGrayColor [UIColor colorWithRed:0.56 green:0.56 blue:0.56 alpha:1.00]
  176 +
  177 +#define kViewCommonGrayColor [UIColor colorWithRed:0.97 green:0.97 blue:0.97 alpha:1.00]
  178 +
  179 +#define kLineGrayColor [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.00]
  180 +#define kLineBlueColor [UIColor colorWithRed:0.00 green:0.36 blue:1.00 alpha:1.00]
  181 +
  182 +#define kPublishRedColor [UIColor colorWithRed:0.88 green:0.10 blue:0.13 alpha:1.00]
  183 +
  184 +#define kPublishNaviRedColor [UIColor colorWithRed:1.00 green:0.17 blue:0.29 alpha:1.00]
  185 +
  186 +#define kNaviTintColor [UIColor colorWithRed:0.00 green:0.58 blue:1.00 alpha:1.00]
  187 +
  188 +#define kNaviThemeTintColor [UIColor colorWithRed:0.35 green:0.35 blue:0.35 alpha:1.00]
  189 +
  190 +#define kPublishSuccessColor [UIColor colorWithRed:0.21 green:1.00 blue:0.75 alpha:1.00]
  191 +
  192 +#define kPublishFailureColor [UIColor colorWithRed:1.00 green:0.00 blue:0.00 alpha:1.00]
  193 +
  194 +#define kMomentOrgangeColor [UIColor colorWithRed:0.98 green:0.55 blue:0.11 alpha:1.00]
  195 +
  196 +#define kMomentLineColor [UIColor colorWithRed:0.79 green:0.79 blue:0.79 alpha:1.00]
  197 +
  198 +///////正式
  199 +#define kBackGrayColor [UIColor colorWithRed:0.53 green:0.53 blue:0.53 alpha:1.00]
  200 +
  201 +#define kGuangbiaoColor [UIColor colorWithRed:0.20 green:0.35 blue:0.95 alpha:1.00]
  202 +
  203 +////////////////////////////////////////////////////////
  204 +//////////// firendCricle
  205 +////////////////////////////////////////////////////////
  206 +#define contentLabelFontSize 16
  207 +
  208 +
  209 +////////////////////////////////////////////////////////
  210 +//////////// SystemVersion
  211 +////////////////////////////////////////////////////////
  212 +#define iOS7Later ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f)
  213 +#define iOS8Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f)
  214 +#define iOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f)
  215 +#define iOS9_1Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f)
  216 +#define iOS10Later ([UIDevice currentDevice].systemVersion.floatValue >= 10.0f)
  217 +
  218 +
  219 +////////////////////////////////////////////////////////
  220 +//////////// WeakSelf&StrongSelf
  221 +////////////////////////////////////////////////////////
  222 +/**
  223 + * weakSelf
  224 + */
  225 +#ifndef weakself
  226 +#define weakself __weak typeof(self)weakSelf = self;
  227 +#endif
  228 +/**
  229 + * strongSelf
  230 + */
  231 +#ifndef strongself
  232 +#define strongself __strong typeof(weakSelf)self = weakSelf;
  233 +#endif
  234 +
  235 +////////////////////////////////////////////////////////
  236 +//////////// 输出测试
  237 +////////////////////////////////////////////////////////
  238 +#ifdef DEBUG
  239 +#define NSLog(s, ... ) NSLog( @"[%@ in line %d] ===============>%@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
  240 +#else
  241 +#define NSLog(s, ... )
  242 +#endif
  243 +
  244 +////////////////////////////////////////////////////////
  245 +//////////// NSUserDefault
  246 +////////////////////////////////////////////////////////
  247 +#ifndef CNUserIsLogin
  248 +#define CNUserIsLogin @"CNUserIsLogin"
  249 +#endif
  250 +
  251 +#ifndef CNUserInfo
  252 +#define CNUserInfo @"CNUserInfo"
  253 +#endif
  254 +
  255 +#ifndef kCNLiveUserDefaultsTingYunUIDKey
  256 +#define kCNLiveUserDefaultsTingYunUIDKey @"kCNLiveUserDefaultsTingYunUIDKey"
  257 +#endif
  258 +
  259 +#ifndef CNGroupListInfo // 某群组成员列表list
  260 +#define CNGroupListInfo @"CNGroupListInfo"
  261 +#endif
  262 +
  263 +#ifndef CNGroupsList // 群组列表list
  264 +#define CNGroupsList @"CNGroupsList"
  265 +#endif
  266 +
  267 +#ifndef CNRefundReason
  268 +#define CNRefundReason @"CNRefundReason"
  269 +#endif
  270 +
  271 +////////////////////////////////////////////////////////
  272 +//////////// Refresh
  273 +////////////////////////////////////////////////////////
  274 +#define TableViewDefaultOffestHeight 64.f
  275 +
  276 +//////////////////////////IM////////////////////////////////
  277 +#pragma mark - IM
  278 +
  279 +#define kSaftyWordsCode 80001
  280 +
  281 +// 是否支持富文本显示
  282 +#define kTestChatAttachment 1
  283 +
  284 +////////////////////////////////////////////////////////
  285 +//////////// 动态跟随系统设置的字体大小改变字体和行高
  286 +////////////////////////////////////////////////////////
  287 +#define RATIO [CNSetUserDefaultTool getScaleCoefficient]
  288 +
  289 +
  290 +//字体大小
  291 +#define Text_FONT(F) [UIFont systemFontOfSize:F]
  292 +
  293 +#define SINGLETON_FOR_HEADER(className) \
  294 +\
  295 ++ (className *)shared##className;
  296 +
  297 +#define SINGLETON_FOR_CLASS(className) \
  298 +\
  299 ++ (className *)shared##className { \
  300 +static className *shared##className = nil; \
  301 +static dispatch_once_t onceToken; \
  302 +dispatch_once(&onceToken, ^{ \
  303 +shared##className = [[self alloc] init]; \
  304 +}); \
  305 +return shared##className; \
  306 +}
  307 +
  308 +#endif /* AppCommonDefine_h */
CNLiveImagePickerController/CNEditVideoController.h 0 → 100755
  1 +//
  2 +// ZLEditVideoController.h
  3 +// ZLPhotoBrowser
  4 +//
  5 +// Created by long on 2017/9/15.
  6 +// Copyright © 2017年 long. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +
  13 +@interface CNEditVideoController : UIViewController
  14 +
  15 +@property (nonatomic, strong) TZAssetModel *model;
  16 +
  17 +@property (nonatomic, strong) NSMutableArray *models; ///< All photo models / 所有图片模型数组
  18 +@property (nonatomic, strong) NSMutableArray *photos; ///< All photos / 所有图片数组
  19 +@property (nonatomic, assign) NSInteger currentIndex;
  20 +@property (nonatomic, assign) BOOL isCropImage;
  21 +
  22 +/// Return the new selected photos / 返回最新的选中图片数组
  23 +@property (nonatomic, copy) void (^backButtonEditClickBlock)(BOOL isSelectOriginalPhoto);
  24 +@property (nonatomic, copy) void (^doneButtonEditClickBlock)(BOOL isSelectOriginalPhoto);
  25 +
  26 +
  27 +@end
CNLiveImagePickerController/CNEditVideoController.m 0 → 100755
  1 +//
  2 +// ZLEditVideoController.m
  3 +// ZLPhotoBrowser
  4 +//
  5 +// Created by long on 2017/9/15.
  6 +// Copyright © 2017年 long. All rights reserved.
  7 +//
  8 +
  9 +#import "CNEditVideoController.h"
  10 +#import <AVFoundation/AVFoundation.h>
  11 +#import "TZAssetModel.h"
  12 +#import <objc/runtime.h>
  13 +#import <AssetsLibrary/AssetsLibrary.h>
  14 +#import "TZImagePickerController.h"
  15 +#import "TZPhotoPreviewCell.h"
  16 +#import "TZImageCropManager.h"
  17 +
  18 +#define kItemWidth kItemHeight * 2/3
  19 +#define kItemHeight 50
  20 +#define kAPPName @"网++"
  21 +
  22 +#pragma mark - 显示帧数的CNEditFrameView
  23 +
  24 +@interface CNEditVideoCell : UICollectionViewCell
  25 +
  26 +@property (nonatomic, strong) UIImageView *imageView;
  27 +
  28 +@end
  29 +
  30 +@implementation CNEditVideoCell
  31 +
  32 +- (UIImageView *)imageView
  33 +{
  34 + if (!_imageView) {
  35 + _imageView = [[UIImageView alloc] init];
  36 + _imageView.frame = self.bounds;
  37 + _imageView.contentMode = UIViewContentModeScaleAspectFill;
  38 + _imageView.clipsToBounds = YES;
  39 + [self.contentView addSubview:_imageView];
  40 + }
  41 + return _imageView;
  42 +}
  43 +
  44 +@end
  45 +
  46 +#pragma mark - 协议编辑帧数协议CNEditFrameViewDelegate
  47 +@protocol CNEditFrameViewDelegate <NSObject>
  48 +
  49 +- (void)editViewValidRectChanged;//有效范围更变
  50 +
  51 +- (void)editViewValidRectEndChanged;//有效范围更变结束
  52 +
  53 +@end
  54 +
  55 +#pragma mark - 编辑时视图CNEditFrameView
  56 +@interface CNEditFrameView : UIView
  57 +{
  58 + UIImageView *_leftView;//左视图
  59 + UIImageView *_rightView;//有视图
  60 +}
  61 +
  62 +@property (nonatomic, assign) CGRect validRect;
  63 +@property (nonatomic, weak) id<CNEditFrameViewDelegate> delegate;
  64 +
  65 +@end
  66 +
  67 +@implementation CNEditFrameView
  68 +
  69 +- (instancetype)init
  70 +{
  71 + self = [super init];
  72 + if (self) {
  73 + [self setupUI];
  74 + }
  75 + return self;
  76 +}
  77 +
  78 +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
  79 +{
  80 + //扩大下有效范围
  81 + CGRect left = _leftView.frame;
  82 + left.origin.x -= kItemWidth/2;
  83 + left.size.width += kItemWidth/2;
  84 + CGRect right = _rightView.frame;
  85 + right.size.width += kItemWidth/2;
  86 +
  87 + if (CGRectContainsPoint(left, point)) {
  88 + return _leftView;
  89 + }
  90 + if (CGRectContainsPoint(right, point)) {
  91 + return _rightView;
  92 + }
  93 + return nil;
  94 +}
  95 +
  96 +- (void)setupUI
  97 +{
  98 + self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.5];
  99 + self.layer.borderWidth = 2;
  100 + self.layer.borderColor = [UIColor clearColor].CGColor;
  101 +
  102 + _leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"video_edit_left"]];
  103 + _leftView.userInteractionEnabled = YES;
  104 + _leftView.tag = 0;
  105 + UIPanGestureRecognizer *lg = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
  106 + [_leftView addGestureRecognizer:lg];
  107 + [self addSubview:_leftView];
  108 +
  109 + _rightView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"video_edit_right"]];
  110 + _rightView.userInteractionEnabled = YES;
  111 + _rightView.tag = 1;
  112 + UIPanGestureRecognizer *rg = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
  113 + [_rightView addGestureRecognizer:rg];
  114 + [self addSubview:_rightView];
  115 +}
  116 +
  117 +- (void)panAction:(UIGestureRecognizer *)pan //滑动收拾实现
  118 +{
  119 + self.layer.borderColor = [[UIColor whiteColor] colorWithAlphaComponent:.4].CGColor;
  120 + CGPoint point = [pan locationInView:self];
  121 +
  122 + CGRect rct = self.validRect;
  123 +
  124 + const CGFloat W = self.frame.size.width;
  125 + CGFloat minX = 0;
  126 + CGFloat maxX = W;
  127 +
  128 + switch (pan.view.tag) {
  129 + case 0: {
  130 + //left视图响应
  131 + maxX = rct.origin.x + rct.size.width - kItemWidth;
  132 +
  133 + point.x = MAX(minX, MIN(point.x, maxX));
  134 + point.y = 0;
  135 +
  136 + rct.size.width -= (point.x - rct.origin.x);
  137 + rct.origin.x = point.x;
  138 + }
  139 + break;
  140 +
  141 + case 1:
  142 + {
  143 + //right视图响应
  144 + minX = rct.origin.x + kItemWidth/2;
  145 + maxX = W - kItemWidth/2;
  146 +
  147 + point.x = MAX(minX, MIN(point.x, maxX));
  148 + point.y = 0;
  149 +
  150 + rct.size.width = (point.x - rct.origin.x + kItemWidth/2);
  151 + }
  152 + break;
  153 + }
  154 +
  155 + switch (pan.state) {
  156 + case UIGestureRecognizerStateBegan:
  157 + case UIGestureRecognizerStateChanged:
  158 + if (self.delegate && [self.delegate respondsToSelector:@selector(editViewValidRectChanged)]) {
  159 + [self.delegate editViewValidRectChanged];//滑动响应实现
  160 + }
  161 + break;
  162 +
  163 + case UIGestureRecognizerStateEnded:
  164 + case UIGestureRecognizerStateCancelled:
  165 + self.layer.borderColor = [UIColor clearColor].CGColor;
  166 + if (self.delegate && [self.delegate respondsToSelector:@selector(editViewValidRectEndChanged)]) {
  167 + [self.delegate editViewValidRectEndChanged];//滑动结束响应实现
  168 + }
  169 + break;
  170 +
  171 + default:
  172 + break;
  173 + }
  174 +
  175 +
  176 + self.validRect = rct;
  177 +}
  178 +
  179 +- (void)setValidRect:(CGRect)validRect//根据范围
  180 +{
  181 + _validRect = validRect;
  182 + _leftView.frame = CGRectMake(validRect.origin.x - kItemWidth/4, 0, kItemWidth/2, kItemHeight);
  183 + _rightView.frame = CGRectMake(validRect.origin.x+validRect.size.width-kItemWidth/4, 0, kItemWidth/2, kItemHeight);
  184 +
  185 + [self setNeedsDisplay];
  186 +}
  187 +
  188 +- (void)drawRect:(CGRect)rect
  189 +{
  190 + CGContextRef context = UIGraphicsGetCurrentContext();
  191 +
  192 + CGContextClearRect(context, self.validRect);
  193 +
  194 + CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
  195 + CGContextSetLineWidth(context, 4.0);
  196 +
  197 + CGPoint topPoints[2];
  198 + topPoints[0] = CGPointMake(self.validRect.origin.x, 0);
  199 + topPoints[1] = CGPointMake(self.validRect.origin.x+self.validRect.size.width, 0);
  200 +
  201 + CGPoint bottomPoints[2];
  202 + bottomPoints[0] = CGPointMake(self.validRect.origin.x, kItemHeight);
  203 + bottomPoints[1] = CGPointMake(self.validRect.origin.x+self.validRect.size.width, kItemHeight);
  204 +
  205 + CGContextAddLines(context, topPoints, 2);
  206 + CGContextAddLines(context, bottomPoints, 2);
  207 +
  208 + CGContextDrawPath(context, kCGPathStroke);
  209 +}
  210 +
  211 +@end
  212 +
  213 +
  214 +#pragma mark - 编辑视频控制器CNEditVideoController
  215 +@interface CNEditVideoController () <UIScrollViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate, CNEditFrameViewDelegate>
  216 +{
  217 + UIView *_bottomView;
  218 + UIButton *_cancelBtn;
  219 + UIButton *_doneBtn;
  220 +
  221 + NSTimer *_timer;
  222 +
  223 + //下方collectionview偏移量
  224 + CGFloat _offsetX;
  225 + BOOL _orientationChanged;
  226 +
  227 + UIView *_indicatorLine;
  228 +
  229 + AVAsset *_avAsset;
  230 +
  231 + NSTimeInterval _interval;
  232 +
  233 + NSInteger _measureCount;
  234 + NSOperationQueue *_queue;
  235 + NSMutableDictionary<NSString *, UIImage *> *_imageCache;
  236 + NSMutableDictionary<NSString *, NSBlockOperation *> *_opCache;
  237 +}
  238 +
  239 +@property (nonatomic, strong) AVPlayerLayer *playerLayer;
  240 +@property (nonatomic, strong) UICollectionView *collectionView;
  241 +@property (nonatomic, strong) CNEditFrameView *editView;
  242 +@property (nonatomic, strong) AVAssetImageGenerator *generator;
  243 +
  244 +@end
  245 +
  246 +@implementation CNEditVideoController
  247 +
  248 +- (void)dealloc
  249 +{
  250 + [_queue cancelAllOperations];
  251 + [self stopTimer];
  252 + [[NSNotificationCenter defaultCenter] removeObserver:self];
  253 +// NSLog(@"---- %s", __FUNCTION__);
  254 +}
  255 +
  256 +- (AVAssetImageGenerator *)generator
  257 +{
  258 + if (!_generator) {
  259 + _generator = [[AVAssetImageGenerator alloc] initWithAsset:_avAsset];
  260 + _generator.maximumSize = CGSizeMake(kItemWidth*4, kItemHeight*4);
  261 + _generator.appliesPreferredTrackTransform = YES;
  262 + _generator.requestedTimeToleranceBefore = kCMTimeZero;
  263 + _generator.requestedTimeToleranceAfter = kCMTimeZero;
  264 + _generator.apertureMode = AVAssetImageGeneratorApertureModeProductionAperture;
  265 + }
  266 + return _generator;
  267 +}
  268 +
  269 +- (void)viewDidLoad {
  270 + [super viewDidLoad];
  271 + [self setupUI];
  272 + [self analysisAssetImages];
  273 +
  274 + _queue = [[NSOperationQueue alloc] init];
  275 + _queue.maxConcurrentOperationCount = 3;
  276 +
  277 + _imageCache = [NSMutableDictionary dictionary];
  278 + _opCache = [NSMutableDictionary dictionary];
  279 +
  280 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationChanged:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
  281 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appResignActive) name:UIApplicationWillResignActiveNotification object:nil];
  282 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
  283 +}
  284 +
  285 +- (void)viewWillAppear:(BOOL)animated
  286 +{
  287 + [super viewWillAppear:animated];
  288 + [UIApplication sharedApplication].statusBarHidden = YES;
  289 + self.navigationController.navigationBar.hidden = YES;
  290 +}
  291 +
  292 +- (void)viewWillDisappear:(BOOL)animated
  293 +{
  294 + [super viewWillDisappear:animated];
  295 + self.navigationController.navigationBar.hidden = NO;
  296 +}
  297 +
  298 +- (void)viewDidLayoutSubviews
  299 +{
  300 + [super viewDidLayoutSubviews];
  301 +
  302 + UIEdgeInsets inset = UIEdgeInsetsZero;
  303 + if (@available(iOS 11, *)) {
  304 + inset = self.view.safeAreaInsets;
  305 + }
  306 +
  307 + self.playerLayer.frame = CGRectMake(15, inset.top>0?inset.top:30, [UIScreen mainScreen].bounds.size.width-30, [UIScreen mainScreen].bounds.size.height-160-inset.bottom);
  308 +
  309 + self.editView.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width-kItemWidth*10)/2, [UIScreen mainScreen].bounds.size.height-100-inset.bottom, kItemWidth*10, kItemHeight);
  310 + self.editView.validRect = self.editView.bounds;
  311 + self.collectionView.frame = CGRectMake(inset.left, [UIScreen mainScreen].bounds.size.height-100-inset.bottom, [UIScreen mainScreen].bounds.size.width-inset.left-inset.right, kItemHeight);
  312 +
  313 + CGFloat leftOffset = (([UIScreen mainScreen].bounds.size.width-kItemWidth*10)/2-inset.left);
  314 + CGFloat rightOffset = (([UIScreen mainScreen].bounds.size.width-kItemWidth*10)/2-inset.right);
  315 + [self.collectionView setContentInset:UIEdgeInsetsMake(0, leftOffset, 0, rightOffset)];
  316 + [self.collectionView setContentOffset:CGPointMake(_offsetX-leftOffset, 0)];
  317 +
  318 + CGFloat bottomViewH = 44;
  319 + CGFloat bottomBtnH = 30;
  320 + _bottomView.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height-bottomViewH-inset.bottom, [UIScreen mainScreen].bounds.size.width, kItemHeight);
  321 + _cancelBtn.frame = CGRectMake(10+inset.left, 7, 60, bottomBtnH);
  322 + _doneBtn.frame = CGRectMake([UIScreen mainScreen].bounds.size.width-70-inset.right, 7, 60, bottomBtnH);
  323 +
  324 + [self.playerLayer setBackgroundColor:[UIColor clearColor].CGColor];
  325 +}
  326 +
  327 +#pragma mark - notifies
  328 +//设备旋转
  329 +- (void)deviceOrientationChanged:(NSNotification *)notify
  330 +{
  331 + _offsetX = self.collectionView.contentOffset.x + self.collectionView.contentInset.left;
  332 + _orientationChanged = YES;
  333 +}
  334 +
  335 +- (void)appResignActive
  336 +{
  337 + [self stopTimer];
  338 +}
  339 +
  340 +- (void)appBecomeActive
  341 +{
  342 + [self startTimer];
  343 +}
  344 +
  345 +- (void)setupUI
  346 +{
  347 + //禁用返回手势
  348 + if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
  349 + self.navigationController.interactivePopGestureRecognizer.delegate = nil;
  350 + self.navigationController.interactivePopGestureRecognizer.enabled = NO;
  351 + }
  352 +
  353 + self.view.backgroundColor = [UIColor blackColor];
  354 +
  355 + self.playerLayer = [[AVPlayerLayer alloc] init];
  356 + [self.view.layer addSublayer:self.playerLayer];
  357 +
  358 + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
  359 + layout.itemSize = CGSizeMake(kItemWidth, kItemHeight);
  360 + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  361 + layout.minimumInteritemSpacing = 0;
  362 + layout.minimumLineSpacing = 0;
  363 +
  364 + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
  365 + self.collectionView.delegate = self;
  366 + self.collectionView.dataSource = self;
  367 + self.collectionView.backgroundColor = [UIColor clearColor];
  368 + self.collectionView.showsHorizontalScrollIndicator = NO;
  369 + [self.collectionView registerClass:CNEditVideoCell.class forCellWithReuseIdentifier:@"CNEditVideoCell"];
  370 +
  371 + [self.view addSubview:self.collectionView];
  372 +
  373 + [self creatBottomView];
  374 +
  375 + self.editView = [[CNEditFrameView alloc] init];
  376 + self.editView.delegate = self;
  377 + [self.view addSubview:self.editView];
  378 +
  379 + _indicatorLine = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2, kItemHeight)];
  380 +// _indicatorLine.backgroundColor = [RGBOF(0x0BBE06) colorWithAlphaComponent:.7];
  381 +}
  382 +
  383 +- (void)creatBottomView
  384 +{
  385 + //下方视图
  386 + _bottomView = [[UIView alloc] init];
  387 + _bottomView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.7];
  388 + [self.view addSubview:_bottomView];
  389 +
  390 + _cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  391 + _cancelBtn.titleLabel.font = [UIFont systemFontOfSize:15];
  392 + [_cancelBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  393 + [_cancelBtn setTitle:@"取消" forState:UIControlStateNormal];
  394 + [_cancelBtn addTarget:self action:@selector(cancelBtn_click) forControlEvents:UIControlEventTouchUpInside];
  395 + [_bottomView addSubview:_cancelBtn];
  396 +
  397 + _doneBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  398 + [_doneBtn setTitle:@"完成" forState:UIControlStateNormal];
  399 + [_doneBtn setBackgroundColor:[UIColor clearColor]];
  400 +// [_doneBtn setTitleColor:RGBOF(0x0BBE06) forState:UIControlStateNormal];
  401 + _doneBtn.titleLabel.font = [UIFont systemFontOfSize:15];
  402 + _doneBtn.layer.masksToBounds = YES;
  403 + _doneBtn.layer.cornerRadius = 3.0f;
  404 + [_doneBtn addTarget:self action:@selector(btnDone_click) forControlEvents:UIControlEventTouchUpInside];
  405 + [_bottomView addSubview:_doneBtn];
  406 +}
  407 +
  408 +#pragma mark - 解析视频每一帧图片
  409 +- (void)analysisAssetImages
  410 +{
  411 + NSTimeInterval duration = 0.0;
  412 + if ([self.model.asset isKindOfClass:[PHAsset class]]) {
  413 + PHAsset *asset = self.model.asset;
  414 + duration = asset.duration;
  415 + }else if([self.model.asset isKindOfClass:[ALAsset class]]){
  416 + duration = [[self.model.asset valueForProperty:ALAssetPropertyDuration] doubleValue];
  417 + }
  418 +
  419 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  420 + _interval = _tzImagePickerVc.maxEditVideoTime/10.0;
  421 + _measureCount = (NSInteger)(duration / _interval);
  422 + ///播放视频的
  423 + if ([self.model.asset isKindOfClass:[PHAsset class]]) {//PHAsset
  424 + __weak typeof(self) weakSelf = self;
  425 + [[PHCachingImageManager defaultManager] requestPlayerItemForVideo:self.model.asset options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
  426 + dispatch_async(dispatch_get_main_queue(), ^{
  427 + __strong typeof(weakSelf) strongSelf = weakSelf;
  428 + if (!playerItem) return;
  429 + AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
  430 + strongSelf.playerLayer.player = player;
  431 + [strongSelf startTimer];
  432 + });
  433 +
  434 + }];
  435 +
  436 + ///截取视频帧数
  437 + PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
  438 + options.version = PHVideoRequestOptionsVersionOriginal;
  439 + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  440 + options.networkAccessAllowed = YES;
  441 + [[PHImageManager defaultManager] requestAVAssetForVideo:self.model.asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
  442 + __strong typeof(weakSelf) strongSelf = weakSelf;
  443 + strongSelf->_avAsset = asset;
  444 + dispatch_async(dispatch_get_main_queue(), ^{
  445 + [strongSelf.collectionView reloadData];
  446 + });
  447 + }];
  448 +
  449 + }else if([self.model.asset isKindOfClass:[ALAsset class]]){//ALAsset
  450 + ///播放视频的
  451 + ALAsset *alAsset = (ALAsset *)self.model.asset;
  452 + ALAssetRepresentation *defaultRepresentation = [alAsset defaultRepresentation];
  453 + NSString *uti = [defaultRepresentation UTI];
  454 + NSURL *videoURL = [[alAsset valueForProperty:ALAssetPropertyURLs] valueForKey:uti];
  455 + AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:videoURL];
  456 + AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
  457 + self.playerLayer.player = player;
  458 + [self startTimer];
  459 +
  460 + ///截取视频帧数
  461 + NSURL *videoURL_al =[self.model.asset valueForProperty:ALAssetPropertyAssetURL]; // ALAssetPropertyURLs
  462 + AVAsset *videoAsset = [AVURLAsset assetWithURL:videoURL];
  463 + _avAsset = videoAsset ;
  464 + [self.collectionView reloadData];
  465 +
  466 + }
  467 +
  468 +}
  469 +
  470 +#pragma mark - action
  471 +- (void)cancelBtn_click
  472 +{
  473 + [self stopTimer];
  474 +
  475 + if (self.backButtonEditClickBlock) {
  476 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  477 + self.backButtonEditClickBlock(_tzImagePickerVc.isSelectOriginalPhoto);
  478 + }
  479 + UIViewController *vc = [self.navigationController popViewControllerAnimated:NO];
  480 + if (!vc) {
  481 + [self dismissViewControllerAnimated:YES completion:nil];
  482 + }
  483 +}
  484 +
  485 +- (void)btnDone_click
  486 +{
  487 + [self stopTimer];
  488 +
  489 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  490 + [_tzImagePickerVc showProgressHUD];
  491 +
  492 + [self exportEditVideoForAsset:_avAsset range:[self getTimeRange] complete:^(BOOL isSuc, id asset) {
  493 + [_tzImagePickerVc hideProgressHUD];
  494 + if (isSuc) {
  495 + TZAssetModel *editModel = [TZAssetModel modelWithAsset:asset type:TZAssetModelMediaTypeVideo];
  496 +
  497 + // 如果没有选中过照片 点击确定时选中当前预览的照片
  498 + if (_tzImagePickerVc.selectedModels.count == 0 && _tzImagePickerVc.minImagesCount <= 0) {
  499 + [_tzImagePickerVc addSelectedModel:editModel];
  500 + }
  501 +
  502 + if (self.doneButtonEditClickBlock) {
  503 + self.doneButtonEditClickBlock(_tzImagePickerVc.isSelectOriginalPhoto);
  504 + }
  505 + [_tzImagePickerVc hideProgressHUD];
  506 + }else{
  507 + [_tzImagePickerVc showAlertWithTitle:@"编辑失败"];
  508 + }
  509 +
  510 + }];
  511 +}
  512 +#pragma mark - 截取视频
  513 +
  514 +- (void)exportEditVideoForAsset:(AVAsset *)asset range:(CMTimeRange)range complete:(void (^)(BOOL, id))complete
  515 +{
  516 + [self export:asset range:range presetName:AVAssetExportPresetPassthrough renderSize:CGSizeZero imageSize:CGSizeZero effectImage:nil birthRate:0 velocity:0 complete:^(NSString *exportFilePath, NSError *error) {
  517 + if (!error) {
  518 + [self saveVideoToAblum:[NSURL fileURLWithPath:exportFilePath] completion:^(BOOL isSuc, id asset) {
  519 + dispatch_async(dispatch_get_main_queue(), ^{
  520 + if (complete) complete(isSuc, asset);
  521 + });
  522 + }];
  523 + } else {
  524 + dispatch_async(dispatch_get_main_queue(), ^{
  525 + if (complete) complete(NO, nil);
  526 + });
  527 + }
  528 + }];
  529 +}
  530 +
  531 +///保存视频到相册
  532 +- (void)saveVideoToAblum:(NSURL *)url completion:(void (^)(BOOL, id))completion
  533 +{
  534 + if (iOS8Later) {
  535 + PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
  536 + if (status == PHAuthorizationStatusDenied) {
  537 + if (completion) completion(NO, nil);
  538 + } else if (status == PHAuthorizationStatusRestricted) {
  539 + if (completion) completion(NO, nil);
  540 + } else {
  541 + __block PHObjectPlaceholder *placeholderAsset=nil;
  542 + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  543 + PHAssetChangeRequest *newAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
  544 + placeholderAsset = newAssetRequest.placeholderForCreatedAsset;
  545 + } completionHandler:^(BOOL success, NSError * _Nullable error) {
  546 + if (!success) {
  547 + if (completion) completion(NO, nil);
  548 + return;
  549 + }
  550 + PHAsset *asset = [self getAssetFromlocalIdentifier:placeholderAsset.localIdentifier];
  551 + PHAssetCollection *desCollection = [self getDestinationCollection];
  552 + if (!desCollection) completion(NO, nil);
  553 +
  554 + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  555 + [[PHAssetCollectionChangeRequest changeRequestForAssetCollection:desCollection] addAssets:@[asset]];
  556 + } completionHandler:^(BOOL success, NSError * _Nullable error) {
  557 + if (completion) completion(success, asset);
  558 + }];
  559 + }];
  560 + }
  561 + }else{
  562 +
  563 + ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];
  564 + [assetLibrary writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) {
  565 + if (error) {
  566 + NSLog(@"保存视频出错:%@",error.localizedDescription);
  567 + if (completion) {
  568 + completion(NO,nil);
  569 + }
  570 + } else {
  571 + [assetLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
  572 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  573 + if (completion) {
  574 + completion(YES,asset);
  575 + }
  576 + });
  577 + } failureBlock:^(NSError *error) {
  578 +
  579 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  580 + if (completion) {
  581 + completion(NO,nil);
  582 + }
  583 + });
  584 +
  585 + }];
  586 + }
  587 + }];
  588 +
  589 + }
  590 +
  591 +}
  592 +
  593 +- (PHAsset *)getAssetFromlocalIdentifier:(NSString *)localIdentifier{
  594 + if(localIdentifier == nil){
  595 + NSLog(@"Cannot get asset from localID because it is nil");
  596 + return nil;
  597 + }
  598 + PHFetchResult *result = [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil];
  599 + if(result.count){
  600 + return result[0];
  601 + }
  602 + return nil;
  603 +}
  604 +
  605 +//获取自定义相册
  606 +- (PHAssetCollection *)getDestinationCollection
  607 +{
  608 + //找是否已经创建自定义相册
  609 + PHFetchResult<PHAssetCollection *> *collectionResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
  610 + for (PHAssetCollection *collection in collectionResult) {
  611 + if ([collection.localizedTitle isEqualToString:kAPPName]) {
  612 + return collection;
  613 + }
  614 + }
  615 + //新建自定义相册
  616 + __block NSString *collectionId = nil;
  617 + NSError *error = nil;
  618 + [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
  619 + collectionId = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:kAPPName].placeholderForCreatedAssetCollection.localIdentifier;
  620 + } error:&error];
  621 + if (error) {
  622 + return nil;
  623 + }
  624 + return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[collectionId] options:nil].lastObject;
  625 +}
  626 +
  627 +- (void)export:(AVAsset *)asset range:(CMTimeRange)range presetName:(NSString *)presetName renderSize:(CGSize)renderSize imageSize:(CGSize)imageSize effectImage:(UIImage *)effectImage birthRate:(NSInteger)birthRate velocity:(CGFloat)velocity complete:(void (^)(NSString *exportFilePath, NSError *error))complete
  628 +{
  629 + NSString *exportFilePath = [self getVideoExportFilePath];
  630 +
  631 + AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:presetName];
  632 +
  633 + NSURL *exportFileUrl = [NSURL fileURLWithPath:exportFilePath];
  634 +
  635 + exportSession.outputURL = exportFileUrl;
  636 + exportSession.outputFileType = AVFileTypeMPEG4;
  637 + exportSession.timeRange = range;
  638 + // exportSession.shouldOptimizeForNetworkUse = YES;
  639 + if (!CGSizeEqualToSize(renderSize, CGSizeZero)) {
  640 + AVMutableVideoComposition *com = [self getVideoComposition:asset renderSize:renderSize imageSize:imageSize effectImage:effectImage birthRate:birthRate velocity:velocity];
  641 + if (!com) {
  642 + if (complete) {
  643 + complete(nil, [NSError errorWithDomain:@"视频裁剪导出失败" code:-1 userInfo:@{@"message": @"视频对象格式可能有错误,没有检测到视频通道"}]);
  644 + }
  645 + return;
  646 + }
  647 + exportSession.videoComposition = com;
  648 + }
  649 +
  650 + [exportSession exportAsynchronouslyWithCompletionHandler:^{
  651 + BOOL suc = NO;
  652 + switch ([exportSession status]) {
  653 + case AVAssetExportSessionStatusFailed:
  654 + NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
  655 + break;
  656 + case AVAssetExportSessionStatusCancelled:
  657 + NSLog(@"Export canceled");
  658 + break;
  659 +
  660 + case AVAssetExportSessionStatusCompleted:{
  661 + NSLog(@"Export completed");
  662 + suc = YES;
  663 + }
  664 + break;
  665 +
  666 + default:
  667 + NSLog(@"Export other");
  668 + break;
  669 + }
  670 +
  671 + if (complete) {
  672 + complete(suc?exportFilePath:nil, suc?nil:exportSession.error);
  673 + if (!suc) {
  674 + [exportSession cancelExport];
  675 + }
  676 + }
  677 + }];
  678 +}
  679 +
  680 +- (NSString *)getVideoExportFilePath
  681 +{
  682 + NSString *format = @"mp4";
  683 +
  684 + NSString *exportFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", [self getUniqueStrByUUID], format]];
  685 +
  686 + return exportFilePath;
  687 +}
  688 +
  689 +- (NSString *)getUniqueStrByUUID
  690 +{
  691 + CFUUIDRef uuidObj = CFUUIDCreate(nil);//create a new UUID
  692 +
  693 + //get the string representation of the UUID
  694 + CFStringRef uuidString = CFUUIDCreateString(nil, uuidObj);
  695 +
  696 + NSString *str = [NSString stringWithString:(__bridge NSString *)uuidString];
  697 +
  698 + CFRelease(uuidObj);
  699 + CFRelease(uuidString);
  700 +
  701 + return [str lowercaseString];
  702 +}
  703 +
  704 +
  705 +- (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset renderSize:(CGSize)renderSize imageSize:(CGSize)imageSize effectImage:(UIImage *)effectImage birthRate:(NSInteger)birthRate velocity:(CGFloat)velocity
  706 +{
  707 + AVMutableComposition *composition = [AVMutableComposition composition];
  708 + //视频通道
  709 + AVMutableCompositionTrack *assetVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
  710 + //音频通道
  711 + AVMutableCompositionTrack *assetAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
  712 +
  713 + NSError *error = nil;
  714 + //裁剪时长
  715 + CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
  716 +
  717 + AVAssetTrack *videoTrack = [asset tracksWithMediaType:AVMediaTypeVideo].firstObject;//视频
  718 + AVAssetTrack *audioTrack = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;//音频
  719 +
  720 + if (!videoTrack) {
  721 + return nil;
  722 + }
  723 + [assetVideoTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:&error];
  724 + NSLog(@"%@", error);
  725 + if (audioTrack) {
  726 + [assetAudioTrack insertTimeRange:timeRange ofTrack:audioTrack atTime:kCMTimeZero error:&error];
  727 + NSLog(@"%@", error);
  728 + }
  729 +
  730 + if (error) {
  731 + return nil;
  732 + }
  733 +
  734 + AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  735 + instruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration);
  736 +
  737 + //处理视频旋转
  738 + AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:assetVideoTrack];
  739 + [layerInstruction setOpacity:0.0 atTime:assetVideoTrack.timeRange.duration];
  740 + //视频旋转,获取视频旋转角度,然后旋转对应角度,保持视频方向正确
  741 + CGFloat degree = [self getVideoDegree:videoTrack];
  742 + CGSize naturalSize = assetVideoTrack.naturalSize;
  743 +
  744 + CGAffineTransform mixedTransform = CGAffineTransformIdentity;
  745 + //处理renderSize,不能大于视频宽高
  746 + CGFloat videoWidth = (degree==0 || degree==M_PI) ? naturalSize.width : naturalSize.height;
  747 + CGFloat videoHeight = (degree==0 || degree==M_PI) ? naturalSize.height : naturalSize.width;
  748 + CGSize cropSize = CGSizeMake(MIN(videoWidth, renderSize.width), MIN(videoHeight, renderSize.height));
  749 + CGFloat x, y;
  750 + if (degree == M_PI_2) {
  751 + //顺时针 90°
  752 + CGAffineTransform t = CGAffineTransformMakeTranslation(naturalSize.height,.0);
  753 + CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI_2);
  754 + //x为正向下 y为正向左
  755 + x = -(videoHeight-cropSize.height)/2;
  756 + y = (videoWidth-cropSize.width)/2;
  757 + mixedTransform = CGAffineTransformTranslate(t1, x, y);
  758 + } else if (degree == M_PI) {
  759 + //顺时针 180°
  760 + CGAffineTransform t = CGAffineTransformMakeTranslation(naturalSize.width, naturalSize.height);
  761 + CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI);
  762 + //x为正向左 y为正向上
  763 + x = (videoWidth-cropSize.width)/2;
  764 + y = (videoHeight-cropSize.height)/2;
  765 + mixedTransform = CGAffineTransformTranslate(t1, x, y);
  766 + } else if (degree == (M_PI_2 * 3)) {
  767 + //顺时针 270°
  768 + CGAffineTransform t = CGAffineTransformMakeTranslation(.0, naturalSize.width);
  769 + CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI_2*3);
  770 + //x为正向上 y为正向右
  771 + x = (videoHeight-cropSize.height)/2;
  772 + y = -(videoWidth-cropSize.width)/2;
  773 + mixedTransform = CGAffineTransformTranslate(t1, x, y);
  774 + } else {
  775 + //x为正向右 y为正向下
  776 + x = -(videoWidth-cropSize.width)/2;
  777 + y = -(videoHeight-cropSize.height)/2;
  778 + mixedTransform = CGAffineTransformMakeTranslation(x, y);
  779 + }
  780 +
  781 + [layerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  782 +
  783 + //管理所有需要处理的视频
  784 + AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
  785 + videoComposition.frameDuration = CMTimeMake(1, 30);
  786 + videoComposition.renderScale = 1;
  787 + videoComposition.renderSize = cropSize;
  788 +
  789 + instruction.layerInstructions = @[layerInstruction];
  790 + videoComposition.instructions = @[instruction];
  791 +
  792 + return videoComposition;
  793 +}
  794 +
  795 +- (CGFloat)getVideoDegree:(AVAssetTrack *)videoTrack
  796 +{
  797 + CGAffineTransform tf = videoTrack.preferredTransform;
  798 +
  799 + CGFloat degree = 0;
  800 + if (tf.b == 1.0 && tf.c == -1.0) {
  801 + degree = M_PI_2;
  802 + } else if (tf.a == -1.0 && tf.d == -1.0) {
  803 + degree = M_PI;
  804 + } else if (tf.b == -1.0 && tf.c == 1.0) {
  805 + degree = M_PI_2 * 3;
  806 + }
  807 + return degree;
  808 +}
  809 +
  810 +
  811 +
  812 +#pragma mark - timer
  813 +- (void)startTimer
  814 +{
  815 + [self stopTimer];
  816 +
  817 + CGFloat duration = _interval * self.editView.validRect.size.width / (kItemWidth);
  818 + _timer = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:@selector(playPartVideo:) userInfo:nil repeats:YES];
  819 + [_timer fire];
  820 + [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
  821 +
  822 + _indicatorLine.frame = CGRectMake(self.editView.validRect.origin.x, 0, 4, kItemHeight);
  823 + [self.editView addSubview:_indicatorLine];
  824 + [UIView animateWithDuration:duration delay:.0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear animations:^{
  825 + _indicatorLine.frame = CGRectMake(CGRectGetMaxX(self.editView.validRect)-2, 0, 2, kItemHeight);
  826 + } completion:nil];
  827 +}
  828 +
  829 +- (void)stopTimer
  830 +{
  831 + [_timer invalidate];
  832 + _timer = nil;
  833 + [_indicatorLine removeFromSuperview];
  834 + [self.playerLayer.player pause];
  835 +}
  836 +
  837 +- (CMTime)getStartTime
  838 +{
  839 + CGRect rect = [self.collectionView convertRect:self.editView.validRect fromView:self.editView];
  840 + CGFloat s = MAX(0, _interval * rect.origin.x / (kItemWidth));
  841 + return CMTimeMakeWithSeconds(s, self.playerLayer.player.currentTime.timescale);
  842 +}
  843 +
  844 +- (CMTimeRange)getTimeRange
  845 +{
  846 + CMTime start = [self getStartTime];
  847 + CGFloat d = _interval * self.editView.validRect.size.width / (kItemWidth);
  848 + CMTime duration = CMTimeMakeWithSeconds(d, self.playerLayer.player.currentTime.timescale);
  849 + return CMTimeRangeMake(start, duration);
  850 +}
  851 +
  852 +- (void)playPartVideo:(NSTimer *)timer
  853 +{
  854 + [self.playerLayer.player play];
  855 + [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
  856 +}
  857 +
  858 +#pragma mark - edit view delegate
  859 +- (void)editViewValidRectChanged
  860 +{
  861 + [self stopTimer];
  862 + [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
  863 +}
  864 +
  865 +- (void)editViewValidRectEndChanged
  866 +{
  867 + [self startTimer];
  868 +}
  869 +
  870 +#pragma mark - scroll view delegate
  871 +- (void)scrollViewDidScroll:(UIScrollView *)scrollView
  872 +{
  873 + if (!self.playerLayer.player || _orientationChanged) {
  874 + _orientationChanged = NO;
  875 + return;
  876 + }
  877 + [self stopTimer];
  878 + [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
  879 +}
  880 +
  881 +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
  882 +{
  883 + if (!decelerate) {
  884 + [self startTimer];
  885 + }
  886 +}
  887 +
  888 +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
  889 +{
  890 + [self startTimer];
  891 +}
  892 +
  893 +#pragma mark - collection view data sources
  894 +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
  895 +{
  896 + return _measureCount;
  897 +}
  898 +
  899 +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  900 +{
  901 + CNEditVideoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CNEditVideoCell" forIndexPath:indexPath];
  902 +
  903 + UIImage *image = _imageCache[@(indexPath.row).stringValue];
  904 + if (image) {
  905 + cell.imageView.image = image;
  906 + }
  907 +
  908 + return cell;
  909 +}
  910 +
  911 +static const char _CNOperationCellKey;
  912 +- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
  913 +{
  914 + if (!_avAsset) return;
  915 +
  916 + if (_imageCache[@(indexPath.row).stringValue] || _opCache[@(indexPath.row).stringValue]) {
  917 + return;
  918 + }
  919 +
  920 + NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
  921 + NSInteger row = indexPath.row;
  922 + NSInteger i = row * _interval;
  923 +
  924 + CMTime time = CMTimeMake((i+0.35) * _avAsset.duration.timescale, _avAsset.duration.timescale);
  925 +
  926 + NSError *error = nil;
  927 + CGImageRef cgImg = [self.generator copyCGImageAtTime:time actualTime:NULL error:&error];
  928 + if (!error && cgImg) {
  929 + UIImage *image = [UIImage imageWithCGImage:cgImg];
  930 + CGImageRelease(cgImg);
  931 +
  932 + [_imageCache setValue:image forKey:@(row).stringValue];
  933 +
  934 + dispatch_async(dispatch_get_main_queue(), ^{
  935 +
  936 + NSIndexPath *nowIndexPath = [collectionView indexPathForCell:cell];
  937 + if (row == nowIndexPath.row) {
  938 + [(CNEditVideoCell *)cell imageView].image = image;
  939 + } else {
  940 + UIImage *cacheImage = _imageCache[@(nowIndexPath.row).stringValue];
  941 + if (cacheImage) {
  942 + [(CNEditVideoCell *)cell imageView].image = cacheImage;
  943 + }
  944 + }
  945 + });
  946 + [_opCache removeObjectForKey:@(row).stringValue];
  947 + }
  948 + objc_removeAssociatedObjects(cell);
  949 + }];
  950 + [_queue addOperation:op];
  951 + [_opCache setValue:op forKey:@(indexPath.row).stringValue];
  952 +
  953 + objc_setAssociatedObject(cell, &_CNOperationCellKey, op, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  954 +}
  955 +
  956 +- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
  957 +{
  958 + NSBlockOperation *op = objc_getAssociatedObject(cell, &_CNOperationCellKey);
  959 + if (op) {
  960 + [op cancel];
  961 + objc_removeAssociatedObjects(cell);
  962 + [_opCache removeObjectForKey:@(indexPath.row).stringValue];
  963 + }
  964 +}
  965 +
  966 +- (void)didReceiveMemoryWarning {
  967 + [super didReceiveMemoryWarning];
  968 + // Dispose of any resources that can be recreated.
  969 +}
  970 +
  971 +/*
  972 +#pragma mark - Navigation
  973 +
  974 +// In a storyboard-based application, you will often want to do a little preparation before navigation
  975 +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  976 + // Get the new view controller using [segue destinationViewController].
  977 + // Pass the selected object to the new view controller.
  978 +}
  979 +*/
  980 +
  981 +@end
CNLiveImagePickerController/CNImagePickerController.bundle/Root.plist 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>StringsTable</key>
  6 + <string>Root</string>
  7 + <key>PreferenceSpecifiers</key>
  8 + <array>
  9 + <dict>
  10 + <key>Type</key>
  11 + <string>PSGroupSpecifier</string>
  12 + <key>Title</key>
  13 + <string>Group</string>
  14 + </dict>
  15 + <dict>
  16 + <key>Type</key>
  17 + <string>PSTextFieldSpecifier</string>
  18 + <key>Title</key>
  19 + <string>Name</string>
  20 + <key>Key</key>
  21 + <string>name_preference</string>
  22 + <key>DefaultValue</key>
  23 + <string></string>
  24 + <key>IsSecure</key>
  25 + <false/>
  26 + <key>KeyboardType</key>
  27 + <string>Alphabet</string>
  28 + <key>AutocapitalizationType</key>
  29 + <string>None</string>
  30 + <key>AutocorrectionType</key>
  31 + <string>No</string>
  32 + </dict>
  33 + <dict>
  34 + <key>Type</key>
  35 + <string>PSToggleSwitchSpecifier</string>
  36 + <key>Title</key>
  37 + <string>Enabled</string>
  38 + <key>Key</key>
  39 + <string>enabled_preference</string>
  40 + <key>DefaultValue</key>
  41 + <true/>
  42 + </dict>
  43 + <dict>
  44 + <key>Type</key>
  45 + <string>PSSliderSpecifier</string>
  46 + <key>Key</key>
  47 + <string>slider_preference</string>
  48 + <key>DefaultValue</key>
  49 + <real>0.5</real>
  50 + <key>MinimumValue</key>
  51 + <integer>0</integer>
  52 + <key>MaximumValue</key>
  53 + <integer>1</integer>
  54 + <key>MinimumValueImage</key>
  55 + <string></string>
  56 + <key>MaximumValueImage</key>
  57 + <string></string>
  58 + </dict>
  59 + </array>
  60 +</dict>
  61 +</plist>
CNLiveImagePickerController/CNImagePickerController.bundle/en.lproj/Root.strings 0 → 100644
1 Binary files /dev/null and b/CNLiveImagePickerController/CNImagePickerController.bundle/en.lproj/Root.strings differ 1 Binary files /dev/null and b/CNLiveImagePickerController/CNImagePickerController.bundle/en.lproj/Root.strings differ
CNLiveImagePickerController/CNImagePickerController.h 0 → 100644
  1 +//
  2 +// CNTZImagePickerControllerViewController.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/8/22.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "TZImagePickerController.h"
  10 +
  11 +@interface CNImagePickerController : TZImagePickerController
  12 +
  13 +/**
  14 + 配置
  15 + */
  16 +- (void)configTZImagePicker;
  17 +
  18 +@end
CNLiveImagePickerController/CNImagePickerController.m 0 → 100644
  1 +//
  2 +// CNTZImagePickerControllerViewController.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/8/22.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNImagePickerController.h"
  10 +#import "AppCommonDefine.h"
  11 +
  12 +@interface CNImagePickerController ()
  13 +
  14 +@end
  15 +
  16 +@implementation CNImagePickerController
  17 +
  18 +- (void)viewDidLoad {
  19 + [super viewDidLoad];
  20 +
  21 +}
  22 +
  23 +/**
  24 + 配置
  25 + */
  26 +- (void)configTZImagePicker{
  27 +
  28 + // imagePickerVc.navigationBar.translucent = NO;
  29 +
  30 +#pragma mark - 五类个性化设置,这些参数都可以不传,此时会走默认设置
  31 + // 1.设置目前已经选中的图片数组
  32 + self.allowTakePicture = NO; // 在内部显示拍照按钮
  33 + self.allowTakeVideo = NO;// 在内部拍摄按钮
  34 + self.videoMaximumDuration = 10; // 视频最大拍摄时间
  35 + [self setUiImagePickerControllerSettingBlock:^(UIImagePickerController *imagePickerController) {
  36 + imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;//拍摄分辨率
  37 + }];
  38 + // imagePickerVc.photoWidth = 1000;
  39 +
  40 + // 2. Set the appearance
  41 + // 2. 在这里设置imagePickerVc的外观
  42 + // if (iOS7Later) {
  43 + // imagePickerVc.navigationBar.barTintColor = [UIColor greenColor];
  44 + // }
  45 + // imagePickerVc.oKButtonTitleColorDisabled = [UIColor lightGrayColor];
  46 + // imagePickerVc.oKButtonTitleColorNormal = [UIColor greenColor];
  47 + // imagePickerVc.navigationBar.translucent = NO;
  48 + self.iconThemeColor = RGBOF(0x00BBE06);// 主体颜色
  49 + self.showPhotoCannotSelectLayer = YES;//达到上限是否有浮层
  50 + self.cannotSelectLayerColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];//设置达到上限的浮层
  51 + self.photoDefImage = [UIImage imageNamed:@"photo_cell_normal"];
  52 +#pragma mark - TODO:RGBOF
  53 +// self.photoSelImage = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06) size:CGSizeMake(22, 22) cornerRadius:11];
  54 + self.photoOriginDefImage = [UIImage imageNamed:@"photo_original_nor"];
  55 +
  56 + // 3. Set allow picking video & photo & originalPhoto or not
  57 + // 3. 设置是否可以选择视频/图片/原图/gif(未开放)
  58 + self.allowPickingVideo = YES;// 显示视频
  59 + self.allowPickingImage = YES;// 显示图片
  60 + self.allowPickingOriginalPhoto = YES; //显示原图
  61 + self.allowPickingGif = NO;// 显示GIF
  62 + self.allowPickingMultipleVideo = YES; // 是否可以多选视频
  63 +
  64 + // 4. 照片排列按修改时间升序
  65 + self.sortAscendingByModificationDate = YES;
  66 +
  67 + // imagePickerVc.minImagesCount = 3;
  68 + // imagePickerVc.alwaysEnableDoneBtn = YES;
  69 +
  70 + // imagePickerVc.minPhotoWidthSelectable = 3000;
  71 + // imagePickerVc.minPhotoHeightSelectable = 2000;
  72 +
  73 + /// 5. Single selection mode, valid when maxImagesCount = 1
  74 + /// 5. 单选模式,maxImagesCount为1时才生效
  75 + self.showSelectBtn = NO;
  76 + self.allowCrop = NO;
  77 + self.needCircleCrop = NO;
  78 + // 设置横屏下的裁剪尺寸
  79 + // imagePickerVc.cropRectLandscape = CGRectMake((self.view.tz_height - widthHeight) / 2, left, widthHeight, widthHeight);
  80 + /*
  81 + [imagePickerVc setCropViewSettingBlock:^(UIView *cropView) {
  82 + cropView.layer.borderColor = [UIColor redColor].CGColor;
  83 + cropView.layer.borderWidth = 2.0;
  84 + }];*/
  85 +
  86 + //imagePickerVc.allowPreview = NO;
  87 + // 自定义导航栏上的返回按钮
  88 + /*
  89 + [imagePickerVc setNavLeftBarButtonSettingBlock:^(UIButton *leftButton){
  90 + [leftButton setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal];
  91 + [leftButton setImageEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 20)];
  92 + }];
  93 + imagePickerVc.delegate = self;
  94 + */
  95 +
  96 + self.statusBarStyle = UIStatusBarStyleDefault;//状态栏黑色
  97 +
  98 + self.showSelectedIndex = YES; // 设置是否显示图片序号
  99 +
  100 + self.naviBgColor = RGBOF(0xFFFFFF);//导航栏颜色
  101 + self.naviTitleColor = RGBOF(0x282828);//相册title
  102 + self.naviTitleFont = [UIFont fontWithName:@"PingFangSC-Medium" size:18];//title文字大小
  103 + [self setNavLeftBarButtonSettingBlock:^(UIButton *leftButton) {//设置返回按钮图标
  104 + [leftButton setImage:[UIImage imageNamed:@"photo_back"] forState:UIControlStateNormal];//返回按钮图片
  105 + [leftButton setTitle:@"返回" forState:UIControlStateNormal];//设置文字大小
  106 + [leftButton setTitleColor:RGBOF(0x282828) forState:UIControlStateNormal];//设置文字颜色
  107 + leftButton.titleLabel.font = [UIFont systemFontOfSize:15];//设置文字大小
  108 + leftButton.imageEdgeInsets = UIEdgeInsetsMake(0, -7, 0, +7);//设置图片边缘
  109 + }];
  110 + self.barItemTextColor = RGBOF(0x282828);//设置barItem文字颜色
  111 + self.barItemTextFont = [UIFont systemFontOfSize:15];
  112 +
  113 + // 设置首选语言 / Set preferred language
  114 + // imagePickerVc.preferredLanguage = @"zh-Hans";
  115 +
  116 + // 设置languageBundle以使用其它语言 / Set languageBundle to use other language
  117 + // imagePickerVc.languageBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"tz-ru" ofType:@"lproj"]];
  118 +
  119 + /// 【自定义各页面/组件的样式】在界面初始化/组件setModel完成后调用,允许外界修改样式等
  120 + //相册
  121 + [self setPhotoPickerPageUIConfigBlock:^(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine) {
  122 +
  123 + //底部栏
  124 + [bottomToolBar setBackgroundColor:RGBOF(0xFFFFFF)];
  125 +
  126 + //预览
  127 + previewButton.titleLabel.font = [UIFont systemFontOfSize:16];
  128 + [previewButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];//禁用
  129 + [previewButton setTitleColor:RGBOF(0x000000) forState:UIControlStateNormal];//默认
  130 +
  131 + //原图按钮
  132 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateDisabled];//禁用
  133 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateNormal];//默认
  134 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_select"] forState:UIControlStateSelected];//选中
  135 + originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16];
  136 + [originalPhotoButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];
  137 + [originalPhotoButton setTitleColor:RGBOF(0x000000) forState:UIControlStateNormal];
  138 +
  139 + //原图文字提示
  140 + originalPhotoLabel.font = [UIFont fontWithName:@"PingFang-SC-Regular" size:16];
  141 + originalPhotoLabel.textColor = RGBOF(0xB3B3B3);
  142 + originalPhotoLabel.hidden = YES;
  143 +
  144 + //选中提示
  145 + numberImageView = [UIImageView new];
  146 + numberLabel = [UILabel new];
  147 +
  148 + //完成按钮
  149 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  150 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  151 + [doneButton setTitleColor:RGBAOF(0xFFFFFF, 0.5) forState:UIControlStateDisabled];
  152 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  153 +
  154 + //颜色绘制成图片
  155 +// UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  156 +// [doneButton setBackgroundImage:dis_image forState:UIControlStateDisabled];
  157 +// UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  158 +// [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  159 + doneButton.layer.masksToBounds = YES;
  160 + doneButton.layer.cornerRadius = 5;
  161 +
  162 + //分割线
  163 + [divideLine setBackgroundColor:RGBOF(0xDEDEDE)];
  164 +
  165 + }];
  166 +
  167 + //图片预览
  168 + [self setPhotoPreviewPageUIConfigBlock:^(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel) {
  169 +
  170 + //返回按钮
  171 + [backButton setImage:[UIImage imageNamed:@"photo_original_back"] forState:UIControlStateNormal];
  172 + //选择按钮
  173 + [selectButton setImage:[UIImage imageNamed:@"photo_original_nor"] forState:UIControlStateNormal];
  174 +// [selectButton setImage:[UIImage qmui_imageWithColor:RGBOF(0x0BBE06) size:CGSizeMake(28, 28) cornerRadius:14] forState:UIControlStateSelected];
  175 + [selectButton setTitle:@"" forState:UIControlStateDisabled];
  176 +
  177 + //原图按钮
  178 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateDisabled];//禁用
  179 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateNormal];//默认
  180 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_select"] forState:UIControlStateSelected];//选中
  181 + originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16];
  182 + [originalPhotoButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];
  183 + [originalPhotoButton setTitleColor:RGBAOF(0xFFFFFF, 0.7) forState:UIControlStateNormal];
  184 + //原图内容隐藏
  185 + originalPhotoLabel.hidden = YES;
  186 +
  187 + //完成按钮
  188 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  189 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  190 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  191 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  192 +
  193 + //颜色绘制成图片
  194 +// UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  195 +// [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  196 +// UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  197 +// [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  198 + doneButton.layer.masksToBounds = YES;
  199 + doneButton.layer.cornerRadius = 5;
  200 + }];
  201 +
  202 + //视频预览
  203 + [self setVideoPreviewPageUIConfigBlock:^(UIButton *playButton, UIView *toolBar, UIButton *doneButton) {
  204 +
  205 + //完成按钮
  206 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  207 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  208 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  209 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  210 +
  211 + //颜色绘制成图片
  212 +// UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  213 +// [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  214 +// UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  215 +// [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  216 + doneButton.layer.masksToBounds = YES;
  217 + doneButton.layer.cornerRadius = 5;
  218 +
  219 + }];
  220 +
  221 + //gif预览
  222 + [self setGifPreviewPageUIConfigBlock:^(UIView *toolBar, UIButton *doneButton) {
  223 +
  224 + //完成按钮
  225 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  226 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  227 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  228 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  229 +
  230 + //颜色绘制成图片
  231 +// UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  232 +// [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  233 +// UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  234 +// [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  235 + doneButton.layer.masksToBounds = YES;
  236 + doneButton.layer.cornerRadius = 5;
  237 +
  238 + }];
  239 + //相册cell
  240 + [self setAssetCellDidSetModelBlock:^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) {
  241 +
  242 +
  243 + }];
  244 + //相簿
  245 + [self setAlbumCellDidSetModelBlock:^(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel) {
  246 + [posterImageView setBackgroundColor:[UIColor blueColor]];
  247 + [posterImageView setBackgroundColor:[UIColor blueColor]];
  248 +
  249 + }];
  250 +
  251 +
  252 + /// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等
  253 + //相册
  254 + [self setPhotoPickerPageDidLayoutSubviewsBlock:^(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine) {
  255 +
  256 + CGRect frame = bottomToolBar.frame;
  257 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  258 +
  259 + CGRect originalPhotoLabelFrame = originalPhotoLabel.frame;
  260 + CGFloat originalX = (bottomToolBar.frame.size.width - originalPhotoLabelFrame.size.width) /2;
  261 + CGFloat originalY = originalPhotoLabelFrame.origin.y;
  262 + originalPhotoButton.frame = CGRectMake(originalX, originalY, originalPhotoLabelFrame.size.width, originalPhotoLabelFrame.size.height);
  263 +
  264 +
  265 + }];
  266 + //图片预览
  267 + [self setPhotoPreviewPageDidLayoutSubviewsBlock:^(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel) {
  268 +
  269 + CGRect frame = toolBar.frame;
  270 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  271 +
  272 + }];
  273 + //视频预览
  274 + [self setVideoPreviewPageDidLayoutSubviewsBlock:^(UIButton *playButton, UIView *toolBar, UIButton *doneButton) {
  275 +
  276 + CGRect frame = toolBar.frame;
  277 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  278 +
  279 + }];
  280 + //gif预览
  281 + [self setGifPreviewPageDidLayoutSubviewsBlock:^(UIView *toolBar, UIButton *doneButton) {
  282 +
  283 + CGRect frame = toolBar.frame;
  284 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  285 +
  286 + }];
  287 + //相册cell
  288 +
  289 + [self setAssetCellDidLayoutSubviewsBlock:^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) {
  290 + }];
  291 + //相簿
  292 + [self setAlbumCellDidLayoutSubviewsBlock:^(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel) {
  293 +
  294 + }];
  295 +
  296 + //设置图片个数
  297 + self.photoNumberIconImage = [UIImage new];
  298 +
  299 +}
  300 +
  301 +- (void)didReceiveMemoryWarning {
  302 + [super didReceiveMemoryWarning];
  303 + // Dispose of any resources that can be recreated.
  304 +}
  305 +
  306 +
  307 +@end
CNLiveImagePickerController/CNImagePickerManager.h 0 → 100644
  1 +//
  2 +// CNImagePickerManager.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/10/8.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import <Foundation/Foundation.h>
  11 +#import "CNImagePickerController.h"
  12 +
  13 +
  14 +typedef void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto);//选着图片返回
  15 +
  16 +//typedef void (^failureBlock)(NSMutableArray* errorArray, NSError *error);//失败数组,错误
  17 +
  18 +typedef NS_ENUM(NSUInteger, CNImagePickerEnterType) {
  19 + CNImagePickerEnterTypeFriendsCircle = 0,//朋友圈
  20 + CNImagePickerEnterTypeComment = 1,//评论
  21 + CNImagePickerEnterTypeSweepCode = 2,//扫码
  22 + CNImagePickerEnterTypeChat = 3,//聊天
  23 + CNImagePickerEnterTypeOther = 4,//其他
  24 + CNImagePickerEnterTypeWitness = 5, //目击者
  25 +
  26 +};
  27 +@interface CNImagePickerManager : NSObject
  28 +
  29 +
  30 +
  31 +/**
  32 + 打开相册选择图片
  33 +
  34 + @param maxImagesCount 最大图片
  35 + @param columnNumber 列个数
  36 + @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>)
  37 + @param pushPhotoPickerVc 是否跳转到相册
  38 + @param isSelectOriginalPhoto 是否原图
  39 + @param selectedAssets 选择图片
  40 + @param enterType 进入方式
  41 + @param pickingPhotosHandle 选择结束回调
  42 + */
  43 ++ (void)ImagePickerWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto selectedAssets:(NSMutableArray *)selectedAssets enterType:(CNImagePickerEnterType )enterType pickingPhotosHandle:(didFinishPickingPhotosHandle) pickingPhotosHandle;
  44 +
  45 +/**
  46 + 预览图片
  47 +
  48 + @param maxImagesCount 最大限制
  49 + @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>)
  50 + @param selectedAssets 选中Assets
  51 + @param selectedPhotos 选中Photos
  52 + @param index 选中第几个
  53 + @param isSelectOriginalPhoto 是否原图
  54 + @param enterType 进入方式
  55 + @param pickingPhotosHandle 回调参数
  56 + */
  57 ++ (void)ImagePickerWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate selectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto enterType:(CNImagePickerEnterType )enterType pickingPhotosHandle:(didFinishPickingPhotosHandle) pickingPhotosHandle;
  58 +
  59 +
  60 +/**
  61 + 预览单个视频
  62 +
  63 + @param selectedAsset 选择视频
  64 + @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>)
  65 + */
  66 ++ (void)ImagePickerWithSelectedAsset:(id)selectedAsset delegate:(id<TZImagePickerControllerDelegate>)delegate;
  67 +
  68 +
  69 +/**
  70 + 保存图片
  71 +
  72 + @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>)
  73 + @param image 图片
  74 + @param location 地点
  75 + @param success 成功
  76 + @param failure 失败
  77 +
  78 + */
  79 ++(void)ImageManagerSavePhotoWithDelegate:(id<TZImagePickerControllerDelegate>)delegate image:(UIImage *)image location:(CLLocation *)location success:(void (^)(TZAssetModel *assetModel))success failure:(void (^)(NSError *error))failure;
  80 +
  81 +
  82 +/**
  83 + 判断Asset类型
  84 +
  85 + @param asset asset
  86 + @return 返回类型
  87 + */
  88 ++ (TZAssetModelMediaType)getAssetType:(id)asset;
  89 +
  90 +
  91 +@end
  92 +
CNLiveImagePickerController/CNImagePickerManager.m 0 → 100644
  1 +//
  2 +// CNImagePickerManager.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/10/8.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNImagePickerManager.h"
  10 +#import <AssetsLibrary/AssetsLibrary.h>
  11 +#import "AppCommonDefine.h"
  12 +
  13 +@implementation CNImagePickerManager
  14 +
  15 +/// 打开相册选择图片
  16 ++ (void)ImagePickerWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto selectedAssets:(NSMutableArray *)selectedAssets enterType:(CNImagePickerEnterType )enterType pickingPhotosHandle:(didFinishPickingPhotosHandle) pickingPhotosHandle{
  17 +
  18 + if (![delegate isKindOfClass:[UIViewController class]]) {
  19 + return;
  20 + }
  21 + UIViewController *vc = (UIViewController *)delegate;
  22 +
  23 + CNImagePickerController *imagePickerVc = [[CNImagePickerController alloc] initWithMaxImagesCount:maxImagesCount columnNumber:columnNumber delegate:delegate pushPhotoPickerVc:pushPhotoPickerVc];
  24 + [imagePickerVc configTZImagePicker];//基本配置
  25 + //特殊配置
  26 + switch (enterType) {
  27 + case CNImagePickerEnterTypeFriendsCircle:
  28 + imagePickerVc.maxEditVideoTime = kFriendsCircle_limit_video_maxEdit;//编辑长度
  29 + imagePickerVc.maxVideoDuration = kFriendsCircle_limit_video_max;//编辑视频最大长度
  30 + // 3. 设置是否可以混选选择视频/图片/原图
  31 + imagePickerVc.allowPickingMultipleVideo = NO;
  32 + break;
  33 + case CNImagePickerEnterTypeComment:
  34 +
  35 + break;
  36 + case CNImagePickerEnterTypeSweepCode:
  37 +
  38 + break;
  39 + case CNImagePickerEnterTypeChat:
  40 +
  41 + break;
  42 + case CNImagePickerEnterTypeWitness:
  43 + imagePickerVc.allowPickingImage = NO;// 显示图片
  44 + imagePickerVc.allowPickingMultipleVideo = NO;
  45 + imagePickerVc.maxEditVideoTime = kFriendsCircle_limit_video_maxEdit;//编辑长度
  46 + imagePickerVc.maxVideoDuration = kFriendsCircle_limit_video_max;//编辑视频最大长度
  47 + break;
  48 + default://其他
  49 + break;
  50 + }
  51 +
  52 + imagePickerVc.isSelectOriginalPhoto = isSelectOriginalPhoto;//是否选择原图
  53 + // 1.设置目前已经选中的图片数组
  54 + imagePickerVc.selectedAssets = selectedAssets; // 目前已经选中的图片数组
  55 + /// 5. Single selection mode, valid when maxImagesCount = 1
  56 + /// 5. 单选模式,maxImagesCount为1时才生效
  57 + // 设置竖屏下的裁剪尺寸
  58 + NSInteger left = 30;
  59 + NSInteger widthHeight = vc.view.frame.size.width - 2 * left;
  60 + NSInteger top = (vc.view.frame.size.height - widthHeight) / 2;
  61 + imagePickerVc.cropRect = CGRectMake(left, top, widthHeight, widthHeight);
  62 + // 你可以通过block或者代理,来得到用户选择的照片.
  63 + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  64 + // 回调参数
  65 + !pickingPhotosHandle ? : pickingPhotosHandle(photos, assets, isSelectOriginalPhoto);
  66 +
  67 + }];
  68 +
  69 + [vc presentViewController:imagePickerVc animated:YES completion:nil];
  70 +}
  71 +
  72 +/// 预览图片
  73 ++ (void)ImagePickerWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate selectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto enterType:(CNImagePickerEnterType )enterType pickingPhotosHandle:(didFinishPickingPhotosHandle) pickingPhotosHandle {
  74 +
  75 + if (![delegate isKindOfClass:[UIViewController class]]) {
  76 + return;
  77 + }
  78 + UIViewController *vc = (UIViewController *)delegate;
  79 +
  80 + CNImagePickerController *imagePickerVc = [[CNImagePickerController alloc] initWithSelectedAssets:selectedAssets selectedPhotos:selectedPhotos index:index];
  81 + [imagePickerVc configTZImagePicker];//基本配置
  82 + //特殊配置
  83 + switch (enterType) {
  84 + case CNImagePickerEnterTypeFriendsCircle:
  85 + imagePickerVc.allowPickingGif = NO;
  86 + imagePickerVc.allowPickingOriginalPhoto = YES;
  87 + imagePickerVc.allowPickingMultipleVideo = NO;
  88 + break;
  89 + case CNImagePickerEnterTypeComment:
  90 +#pragma mark - TODO:根据不同设置
  91 + break;
  92 + case CNImagePickerEnterTypeSweepCode:
  93 +
  94 + break;
  95 + case CNImagePickerEnterTypeChat:
  96 +
  97 + break;
  98 + case CNImagePickerEnterTypeOther:
  99 + break;
  100 + default://其他
  101 + break;
  102 + }
  103 +
  104 + imagePickerVc.maxImagesCount = maxImagesCount;
  105 + imagePickerVc.isSelectOriginalPhoto = isSelectOriginalPhoto;
  106 +
  107 + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  108 + // 回调参数
  109 + !pickingPhotosHandle ? : pickingPhotosHandle(photos, assets, isSelectOriginalPhoto);
  110 +
  111 + }];
  112 + [vc presentViewController:imagePickerVc animated:YES completion:nil];
  113 +
  114 +}
  115 +
  116 +/// 预览单个视频
  117 ++ (void)ImagePickerWithSelectedAsset:(id)selectedAsset delegate:(id<TZImagePickerControllerDelegate>)delegate {
  118 +
  119 + if (![delegate isKindOfClass:[UIViewController class]]) {
  120 + return;
  121 + }
  122 + UIViewController *vc = (UIViewController *)delegate;
  123 +
  124 + TZVideoPlayerController *videoVC = [[TZVideoPlayerController alloc] init];
  125 + TZAssetModel *model = [TZAssetModel modelWithAsset:selectedAsset type:TZAssetModelMediaTypeVideo timeLength:@""];
  126 + videoVC.isOther = YES;//(LXG)相册外进入
  127 + videoVC.model = model;
  128 + [vc presentViewController:videoVC animated:YES completion:nil];
  129 +
  130 +}
  131 +
  132 +/// 返回类型
  133 ++ (TZAssetModelMediaType)getAssetType:(id)asset {
  134 +
  135 + TZAssetModelMediaType type = TZAssetModelMediaTypePhoto;
  136 + if ([asset isKindOfClass:[PHAsset class]]) {
  137 + PHAsset *phAsset = (PHAsset *)asset;
  138 + if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo;
  139 + else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio;
  140 + else if (phAsset.mediaType == PHAssetMediaTypeImage) {
  141 + if (iOS9_1Later) {
  142 + if (@available(iOS 9.1, *)) {
  143 + if (phAsset.mediaSubtypes == PHAssetMediaSubtypePhotoLive)
  144 + {
  145 + type = TZAssetModelMediaTypeLivePhoto;
  146 + }
  147 + } else {
  148 + // Fallback on earlier versions
  149 + }
  150 + }
  151 + // Gif
  152 + if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) {
  153 + type = TZAssetModelMediaTypePhotoGif;
  154 + }
  155 + }
  156 + } else {
  157 + if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) {
  158 + type = TZAssetModelMediaTypeVideo;
  159 + }
  160 + }
  161 + return type;
  162 +}
  163 +
  164 +
  165 ++(void)ImageManagerSavePhotoWithDelegate:(id<TZImagePickerControllerDelegate>)delegate image:(UIImage *)image location:(CLLocation *)location success:(void (^)(TZAssetModel *assetModel))success failure:(void (^)(NSError *error))failure {
  166 +
  167 + TZImagePickerController *tzImagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:delegate];
  168 + tzImagePickerVc.sortAscendingByModificationDate = YES;
  169 +
  170 + [tzImagePickerVc showProgressHUD];
  171 + // save photo and get asset / 保存图片,获取到asset
  172 + [[TZImageManager manager] savePhotoWithImage:image location:location completion:^(NSError *error){
  173 +
  174 + if (error) {
  175 + [tzImagePickerVc hideProgressHUD];
  176 + failure(error);
  177 + NSLog(@"图片保存失败 %@",error);
  178 + } else {
  179 +
  180 + [[TZImageManager manager] getCameraRollAlbum:NO allowPickingImage:YES needFetchAssets:YES completion:^(TZAlbumModel *model) {
  181 + [[TZImageManager manager] getAssetsFromFetchResult:model.result allowPickingVideo:NO allowPickingImage:YES completion:^(NSArray<TZAssetModel *> *models) {
  182 + [tzImagePickerVc hideProgressHUD];
  183 + TZAssetModel *assetModel = [models firstObject];
  184 + if (tzImagePickerVc.sortAscendingByModificationDate) {
  185 + assetModel = [models lastObject];
  186 + }
  187 + success(assetModel);
  188 + }];
  189 +
  190 + }];
  191 + }
  192 + }];
  193 +
  194 +}
  195 +
  196 +
  197 +
  198 +
  199 +
  200 +
  201 +
  202 +
  203 +
  204 +@end
CNLiveImagePickerController/NSBundle+TZImagePicker.h 0 → 100755
  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 <UIKit/UIKit.h>
  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 +
CNLiveImagePickerController/NSBundle+TZImagePicker.m 0 → 100755
  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
CNLiveImagePickerController/TZAssetCell.h 0 → 100755
  1 +//
  2 +// TZAssetCell.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import <Photos/Photos.h>
  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 +@property (weak, nonatomic) UIButton *selectPhotoButton;
  23 +@property (weak, nonatomic) UIButton *cannotSelectLayerButton;
  24 +@property (nonatomic, strong) TZAssetModel *model;
  25 +@property (assign, nonatomic) NSInteger index;
  26 +@property (nonatomic, copy) void (^didSelectPhotoBlock)(BOOL);
  27 +@property (nonatomic, assign) TZAssetCellType type;
  28 +@property (nonatomic, assign) BOOL allowPickingGif;
  29 +@property (nonatomic, assign) BOOL allowPickingMultipleVideo;
  30 +@property (nonatomic, copy) NSString *representedAssetIdentifier;
  31 +@property (nonatomic, assign) int32_t imageRequestID;
  32 +
  33 +@property (nonatomic, strong) UIImage *photoSelImage;
  34 +@property (nonatomic, strong) UIImage *photoDefImage;
  35 +
  36 +@property (nonatomic, assign) BOOL showSelectBtn;
  37 +@property (assign, nonatomic) BOOL allowPreview;
  38 +@property (assign, nonatomic) BOOL useCachedImage;
  39 +
  40 +@property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
  41 +@property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
  42 +@end
  43 +
  44 +
  45 +@class TZAlbumModel;
  46 +@interface TZAlbumCell : UITableViewCell
  47 +@property (nonatomic, strong) TZAlbumModel *model;
  48 +@property (weak, nonatomic) UIButton *selectedCountButton;
  49 +
  50 +@property (nonatomic, copy) void (^albumCellDidSetModelBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
  51 +@property (nonatomic, copy) void (^albumCellDidLayoutSubviewsBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
  52 +@end
  53 +
  54 +
  55 +@interface TZAssetCameraCell : UICollectionViewCell
  56 +@property (nonatomic, strong) UIImageView *imageView;
  57 +@end
CNLiveImagePickerController/TZAssetCell.m 0 → 100755
  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) UILabel *indexLabel;
  20 +@property (weak, nonatomic) UIView *bottomView;
  21 +@property (weak, nonatomic) UILabel *timeLength;
  22 +@property (strong, nonatomic) UITapGestureRecognizer *tapGesture;
  23 +
  24 +@property (nonatomic, weak) UIImageView *videoImgView;
  25 +@property (nonatomic, strong) TZProgressView *progressView;
  26 +@property (nonatomic, assign) int32_t bigImageRequestID;
  27 +@end
  28 +
  29 +@implementation TZAssetCell
  30 +
  31 +- (void)setModel:(TZAssetModel *)model {
  32 + _model = model;
  33 + if (iOS8Later) {
  34 + self.representedAssetIdentifier = [[TZImageManager manager] getAssetIdentifier:model.asset];
  35 + }
  36 + if (self.useCachedImage && model.cachedImage) {
  37 + self.imageView.image = model.cachedImage;
  38 + } else {
  39 + self.model.cachedImage = nil;
  40 + int32_t imageRequestID = [[TZImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.tz_width completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  41 + // Set the cell's thumbnail image if it's still showing the same asset.
  42 + if (!iOS8Later) {
  43 + self.imageView.image = photo;
  44 + self.model.cachedImage = photo;
  45 + [self hideProgressView];
  46 + return;
  47 + }
  48 + if ([self.representedAssetIdentifier isEqualToString:[[TZImageManager manager] getAssetIdentifier:model.asset]]) {
  49 + self.imageView.image = photo;
  50 + self.model.cachedImage = photo;
  51 + } else {
  52 + // NSLog(@"this cell is showing other asset");
  53 + [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
  54 + }
  55 + if (!isDegraded) {
  56 + [self hideProgressView];
  57 + self.imageRequestID = 0;
  58 + }
  59 + } progressHandler:nil networkAccessAllowed:NO];
  60 + if (imageRequestID && self.imageRequestID && imageRequestID != self.imageRequestID) {
  61 + [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
  62 + // NSLog(@"cancelImageRequest %d",self.imageRequestID);
  63 + }
  64 + self.imageRequestID = imageRequestID;
  65 + }
  66 + self.selectPhotoButton.selected = model.isSelected;
  67 + self.selectImageView.image = self.selectPhotoButton.isSelected ? self.photoSelImage : self.photoDefImage;
  68 + self.indexLabel.hidden = !self.selectPhotoButton.isSelected;
  69 +
  70 + self.type = (NSInteger)model.type;
  71 + // 让宽度/高度小于 最小可选照片尺寸 的图片不能选中
  72 + if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) {
  73 + if (_selectImageView.hidden == NO) {
  74 + self.selectPhotoButton.hidden = YES;
  75 + _selectImageView.hidden = YES;
  76 + }
  77 + }
  78 + // 如果用户选中了该图片,提前获取一下大图
  79 + if (model.isSelected) {
  80 + [self requestBigImage];
  81 + } else {
  82 + [self cancelBigImageRequest];
  83 + }
  84 + if (model.needOscillatoryAnimation) {
  85 + [UIView showOscillatoryAnimationWithLayer:self.selectImageView.layer type:TZOscillatoryAnimationToBigger];
  86 + }
  87 + model.needOscillatoryAnimation = NO;
  88 + [self setNeedsLayout];
  89 +
  90 + if (self.assetCellDidSetModelBlock) {
  91 + self.assetCellDidSetModelBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView);
  92 + }
  93 +}
  94 +
  95 +- (void)setIndex:(NSInteger)index {
  96 + _index = index;
  97 + self.indexLabel.text = [NSString stringWithFormat:@"%zd", index];
  98 + [self.contentView bringSubviewToFront:self.indexLabel];
  99 +}
  100 +
  101 +- (void)setShowSelectBtn:(BOOL)showSelectBtn {
  102 + _showSelectBtn = showSelectBtn;
  103 + BOOL selectable = [[TZImageManager manager] isPhotoSelectableWithAsset:self.model.asset];
  104 + if (!self.selectPhotoButton.hidden) {
  105 + self.selectPhotoButton.hidden = !showSelectBtn || !selectable;
  106 + }
  107 + if (!self.selectImageView.hidden) {
  108 + self.selectImageView.hidden = !showSelectBtn || !selectable;
  109 + }
  110 +}
  111 +
  112 +- (void)setType:(TZAssetCellType)type {
  113 + _type = type;
  114 + if (type == TZAssetCellTypePhoto || type == TZAssetCellTypeLivePhoto || (type == TZAssetCellTypePhotoGif && !self.allowPickingGif) || self.allowPickingMultipleVideo) {
  115 + _selectImageView.hidden = NO;
  116 + _selectPhotoButton.hidden = NO;
  117 + _bottomView.hidden = YES;
  118 + } else { // Video of Gif
  119 + _selectImageView.hidden = YES;
  120 + _selectPhotoButton.hidden = YES;
  121 + }
  122 +
  123 + if (type == TZAssetCellTypeVideo) {
  124 + self.bottomView.hidden = NO;
  125 + self.timeLength.text = _model.timeLength;
  126 + self.videoImgView.hidden = NO;
  127 + _timeLength.tz_left = self.videoImgView.tz_right;
  128 + _timeLength.textAlignment = NSTextAlignmentRight;
  129 + } else if (type == TZAssetCellTypePhotoGif && self.allowPickingGif) {
  130 + self.bottomView.hidden = NO;
  131 + self.timeLength.text = @"GIF";
  132 + self.videoImgView.hidden = YES;
  133 + _timeLength.tz_left = 5;
  134 + _timeLength.textAlignment = NSTextAlignmentLeft;
  135 + }
  136 +}
  137 +
  138 +- (void)setAllowPreview:(BOOL)allowPreview {
  139 + _allowPreview = allowPreview;
  140 + if (allowPreview) {
  141 + _imageView.userInteractionEnabled = NO;
  142 + _tapGesture.enabled = NO;
  143 + } else {
  144 + _imageView.userInteractionEnabled = YES;
  145 + _tapGesture.enabled = YES;
  146 + }
  147 +}
  148 +
  149 +- (void)selectPhotoButtonClick:(UIButton *)sender {
  150 + if (self.didSelectPhotoBlock) {
  151 + self.didSelectPhotoBlock(sender.isSelected);
  152 + }
  153 + self.selectImageView.image = sender.isSelected ? self.photoSelImage : self.photoDefImage;
  154 + if (sender.isSelected) {
  155 + if (![TZImagePickerConfig sharedInstance].showSelectedIndex && ![TZImagePickerConfig sharedInstance].showPhotoCannotSelectLayer) {
  156 + [UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:TZOscillatoryAnimationToBigger];
  157 + }
  158 + // 用户选中了该图片,提前获取一下大图
  159 + [self requestBigImage];
  160 + } else { // 取消选中,取消大图的获取
  161 + [self cancelBigImageRequest];
  162 + }
  163 +}
  164 +
  165 +/// 只在单选状态且allowPreview为NO时会有该事件
  166 +- (void)didTapImageView {
  167 + if (self.didSelectPhotoBlock) {
  168 + self.didSelectPhotoBlock(NO);
  169 + }
  170 +}
  171 +
  172 +- (void)hideProgressView {
  173 + if (_progressView) {
  174 + self.progressView.hidden = YES;
  175 + self.imageView.alpha = 1.0;
  176 + }
  177 +}
  178 +
  179 +- (void)requestBigImage {
  180 + if (_bigImageRequestID) {
  181 + [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID];
  182 + }
  183 +
  184 + _bigImageRequestID = [[TZImageManager manager] requestImageDataForAsset:_model.asset completion:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  185 + [self hideProgressView];
  186 + } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  187 + if (self.model.isSelected) {
  188 + progress = progress > 0.02 ? progress : 0.02;;
  189 + self.progressView.progress = progress;
  190 + self.progressView.hidden = NO;
  191 + self.imageView.alpha = 0.4;
  192 + if (progress >= 1) {
  193 + [self hideProgressView];
  194 + }
  195 + } else {
  196 + *stop = YES;
  197 + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
  198 + [self cancelBigImageRequest];
  199 + }
  200 + }];
  201 +}
  202 +
  203 +- (void)cancelBigImageRequest {
  204 + if (_bigImageRequestID) {
  205 + [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID];
  206 + }
  207 + [self hideProgressView];
  208 +}
  209 +
  210 +#pragma mark - Lazy load
  211 +
  212 +- (UIButton *)selectPhotoButton {
  213 + if (_selectPhotoButton == nil) {
  214 + UIButton *selectPhotoButton = [[UIButton alloc] init];
  215 + [selectPhotoButton addTarget:self action:@selector(selectPhotoButtonClick:) forControlEvents:UIControlEventTouchUpInside];
  216 + [self.contentView addSubview:selectPhotoButton];
  217 + _selectPhotoButton = selectPhotoButton;
  218 + }
  219 + return _selectPhotoButton;
  220 +}
  221 +
  222 +- (UIImageView *)imageView {
  223 + if (_imageView == nil) {
  224 + UIImageView *imageView = [[UIImageView alloc] init];
  225 + imageView.contentMode = UIViewContentModeScaleAspectFill;
  226 + imageView.clipsToBounds = YES;
  227 + [self.contentView addSubview:imageView];
  228 + _imageView = imageView;
  229 +
  230 + _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapImageView)];
  231 + [_imageView addGestureRecognizer:_tapGesture];
  232 + }
  233 + return _imageView;
  234 +}
  235 +
  236 +- (UIImageView *)selectImageView {
  237 + if (_selectImageView == nil) {
  238 + UIImageView *selectImageView = [[UIImageView alloc] init];
  239 + selectImageView.contentMode = UIViewContentModeCenter;
  240 + selectImageView.clipsToBounds = YES;
  241 + [self.contentView addSubview:selectImageView];
  242 + _selectImageView = selectImageView;
  243 + }
  244 + return _selectImageView;
  245 +}
  246 +
  247 +- (UIView *)bottomView {
  248 + if (_bottomView == nil) {
  249 + UIView *bottomView = [[UIView alloc] init];
  250 + static NSInteger rgb = 0;
  251 + bottomView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.8];
  252 + [self.contentView addSubview:bottomView];
  253 + _bottomView = bottomView;
  254 + }
  255 + return _bottomView;
  256 +}
  257 +
  258 +- (UIButton *)cannotSelectLayerButton {
  259 + if (_cannotSelectLayerButton == nil) {
  260 + UIButton *cannotSelectLayerButton = [[UIButton alloc] init];
  261 + [self.contentView addSubview:cannotSelectLayerButton];
  262 + _cannotSelectLayerButton = cannotSelectLayerButton;
  263 + }
  264 + return _cannotSelectLayerButton;
  265 +}
  266 +
  267 +- (UIImageView *)videoImgView {
  268 + if (_videoImgView == nil) {
  269 + UIImageView *videoImgView = [[UIImageView alloc] init];
  270 + [videoImgView setImage:[UIImage imageNamedFromMyBundle:@"VideoSendIcon"]];
  271 + [self.bottomView addSubview:videoImgView];
  272 + _videoImgView = videoImgView;
  273 + }
  274 + return _videoImgView;
  275 +}
  276 +
  277 +- (UILabel *)timeLength {
  278 + if (_timeLength == nil) {
  279 + UILabel *timeLength = [[UILabel alloc] init];
  280 + timeLength.font = [UIFont boldSystemFontOfSize:11];
  281 + timeLength.textColor = [UIColor whiteColor];
  282 + timeLength.textAlignment = NSTextAlignmentRight;
  283 + [self.bottomView addSubview:timeLength];
  284 + _timeLength = timeLength;
  285 + }
  286 + return _timeLength;
  287 +}
  288 +
  289 +- (UILabel *)indexLabel {
  290 + if (_indexLabel == nil) {
  291 + UILabel *indexLabel = [[UILabel alloc] init];
  292 + indexLabel.font = [UIFont systemFontOfSize:14];
  293 + indexLabel.textColor = [UIColor whiteColor];
  294 + indexLabel.textAlignment = NSTextAlignmentCenter;
  295 + [self.contentView addSubview:indexLabel];
  296 + _indexLabel = indexLabel;
  297 + }
  298 + return _indexLabel;
  299 +}
  300 +
  301 +- (TZProgressView *)progressView {
  302 + if (_progressView == nil) {
  303 + _progressView = [[TZProgressView alloc] init];
  304 + _progressView.hidden = YES;
  305 + [self addSubview:_progressView];
  306 + }
  307 + return _progressView;
  308 +}
  309 +
  310 +- (void)layoutSubviews {
  311 + [super layoutSubviews];
  312 + _cannotSelectLayerButton.frame = self.bounds;
  313 + if (self.allowPreview) {
  314 + _selectPhotoButton.frame = CGRectMake(self.tz_width - 44, 0, 44, 44);
  315 + } else {
  316 + _selectPhotoButton.frame = self.bounds;
  317 + }
  318 + _selectImageView.frame = CGRectMake(self.tz_width - 27, 3, 24, 24);
  319 + if (_selectImageView.image.size.width <= 27) {
  320 + _selectImageView.contentMode = UIViewContentModeCenter;
  321 + } else {
  322 + _selectImageView.contentMode = UIViewContentModeScaleAspectFit;
  323 + }
  324 + _indexLabel.frame = _selectImageView.frame;
  325 + _imageView.frame = CGRectMake(0, 0, self.tz_width, self.tz_height);
  326 +
  327 + static CGFloat progressWH = 20;
  328 + CGFloat progressXY = (self.tz_width - progressWH) / 2;
  329 + _progressView.frame = CGRectMake(progressXY, progressXY, progressWH, progressWH);
  330 +
  331 + _bottomView.frame = CGRectMake(0, self.tz_height - 17, self.tz_width, 17);
  332 + _videoImgView.frame = CGRectMake(8, 0, 17, 17);
  333 + _timeLength.frame = CGRectMake(self.videoImgView.tz_right, 0, self.tz_width - self.videoImgView.tz_right - 5, 17);
  334 +
  335 + self.type = (NSInteger)self.model.type;
  336 + self.showSelectBtn = self.showSelectBtn;
  337 +
  338 + [self.contentView bringSubviewToFront:_bottomView];
  339 + [self.contentView bringSubviewToFront:_cannotSelectLayerButton];
  340 + [self.contentView bringSubviewToFront:_selectPhotoButton];
  341 + [self.contentView bringSubviewToFront:_selectImageView];
  342 + [self.contentView bringSubviewToFront:_indexLabel];
  343 +
  344 + if (self.assetCellDidLayoutSubviewsBlock) {
  345 + self.assetCellDidLayoutSubviewsBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView);
  346 + }
  347 +}
  348 +
  349 +@end
  350 +
  351 +@interface TZAlbumCell ()
  352 +@property (weak, nonatomic) UIImageView *posterImageView;
  353 +@property (weak, nonatomic) UILabel *titleLabel;
  354 +@end
  355 +
  356 +@implementation TZAlbumCell
  357 +
  358 +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
  359 + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  360 + self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  361 + return self;
  362 +}
  363 +
  364 +- (void)setModel:(TZAlbumModel *)model {
  365 + _model = model;
  366 +
  367 + NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc] initWithString:model.name attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor blackColor]}];
  368 + NSAttributedString *countString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%zd)",model.count] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor lightGrayColor]}];
  369 + [nameString appendAttributedString:countString];
  370 + self.titleLabel.attributedText = nameString;
  371 + [[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) {
  372 + self.posterImageView.image = postImage;
  373 + }];
  374 + if (model.selectedCount) {
  375 + self.selectedCountButton.hidden = NO;
  376 + [self.selectedCountButton setTitle:[NSString stringWithFormat:@"%zd",model.selectedCount] forState:UIControlStateNormal];
  377 + } else {
  378 + self.selectedCountButton.hidden = YES;
  379 + }
  380 +
  381 + if (self.albumCellDidSetModelBlock) {
  382 + self.albumCellDidSetModelBlock(self, _posterImageView, _titleLabel);
  383 + }
  384 +}
  385 +
  386 +/// For fitting iOS6
  387 +- (void)layoutSubviews {
  388 + if (iOS7Later) [super layoutSubviews];
  389 + _selectedCountButton.frame = CGRectMake(self.tz_width - 24 - 30, 23, 24, 24);
  390 + NSInteger titleHeight = ceil(self.titleLabel.font.lineHeight);
  391 + self.titleLabel.frame = CGRectMake(80, (self.tz_height - titleHeight) / 2, self.tz_width - 80 - 50, titleHeight);
  392 + self.posterImageView.frame = CGRectMake(0, 0, 70, 70);
  393 +
  394 + if (self.albumCellDidLayoutSubviewsBlock) {
  395 + self.albumCellDidLayoutSubviewsBlock(self, _posterImageView, _titleLabel);
  396 + }
  397 +}
  398 +
  399 +- (void)layoutSublayersOfLayer:(CALayer *)layer {
  400 + if (iOS7Later) [super layoutSublayersOfLayer:layer];
  401 +}
  402 +
  403 +#pragma mark - Lazy load
  404 +
  405 +- (UIImageView *)posterImageView {
  406 + if (_posterImageView == nil) {
  407 + UIImageView *posterImageView = [[UIImageView alloc] init];
  408 + posterImageView.contentMode = UIViewContentModeScaleAspectFill;
  409 + posterImageView.clipsToBounds = YES;
  410 + [self.contentView addSubview:posterImageView];
  411 + _posterImageView = posterImageView;
  412 + }
  413 + return _posterImageView;
  414 +}
  415 +
  416 +- (UILabel *)titleLabel {
  417 + if (_titleLabel == nil) {
  418 + UILabel *titleLabel = [[UILabel alloc] init];
  419 + titleLabel.font = [UIFont boldSystemFontOfSize:17];
  420 + titleLabel.textColor = [UIColor blackColor];
  421 + titleLabel.textAlignment = NSTextAlignmentLeft;
  422 + [self.contentView addSubview:titleLabel];
  423 + _titleLabel = titleLabel;
  424 + }
  425 + return _titleLabel;
  426 +}
  427 +
  428 +- (UIButton *)selectedCountButton {
  429 + if (_selectedCountButton == nil) {
  430 + UIButton *selectedCountButton = [[UIButton alloc] init];
  431 + selectedCountButton.layer.cornerRadius = 12;
  432 + selectedCountButton.clipsToBounds = YES;
  433 + selectedCountButton.backgroundColor = [UIColor redColor];
  434 + [selectedCountButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  435 + selectedCountButton.titleLabel.font = [UIFont systemFontOfSize:15];
  436 + [self.contentView addSubview:selectedCountButton];
  437 + _selectedCountButton = selectedCountButton;
  438 + }
  439 + return _selectedCountButton;
  440 +}
  441 +
  442 +@end
  443 +
  444 +
  445 +
  446 +@implementation TZAssetCameraCell
  447 +
  448 +- (instancetype)initWithFrame:(CGRect)frame {
  449 + self = [super initWithFrame:frame];
  450 + if (self) {
  451 + self.backgroundColor = [UIColor whiteColor];
  452 + _imageView = [[UIImageView alloc] init];
  453 + _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
  454 + _imageView.contentMode = UIViewContentModeScaleAspectFill;
  455 + [self.contentView addSubview:_imageView];
  456 + self.clipsToBounds = YES;
  457 + }
  458 + return self;
  459 +}
  460 +
  461 +- (void)layoutSubviews {
  462 + [super layoutSubviews];
  463 + _imageView.frame = self.bounds;
  464 +}
  465 +
  466 +@end
CNLiveImagePickerController/TZAssetModel.h 0 → 100755
  1 +//
  2 +// TZAssetModel.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  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 (assign, nonatomic) BOOL needOscillatoryAnimation;
  27 +@property (nonatomic, copy) NSString *timeLength;
  28 +@property (strong, nonatomic) UIImage *cachedImage;
  29 +
  30 +/// Init a photo dataModel With a asset
  31 +/// 用一个PHAsset/ALAsset实例,初始化一个照片模型
  32 ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type;
  33 ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength;
  34 +
  35 +@end
  36 +
  37 +
  38 +@class PHFetchResult;
  39 +@interface TZAlbumModel : NSObject
  40 +
  41 +@property (nonatomic, strong) NSString *name; ///< The album name
  42 +@property (nonatomic, assign) NSInteger count; ///< Count of photos the album contain
  43 +@property (nonatomic, strong) id result; ///< PHFetchResult<PHAsset> or ALAssetsGroup<ALAsset>
  44 +
  45 +@property (nonatomic, strong) NSArray *models;
  46 +@property (nonatomic, strong) NSArray *selectedModels;
  47 +@property (nonatomic, assign) NSUInteger selectedCount;
  48 +
  49 +@property (nonatomic, assign) BOOL isCameraRoll;
  50 +
  51 +- (void)setResult:(id)result needFetchAssets:(BOOL)needFetchAssets;
  52 +
  53 +@end
CNLiveImagePickerController/TZAssetModel.m 0 → 100755
  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<TZAssetModel *> *models) {
  38 + self->_models = models;
  39 + if (self->_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
CNLiveImagePickerController/TZGifPhotoPreviewController.h 0 → 100755
  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 <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +@interface TZGifPhotoPreviewController : UIViewController
  13 +
  14 +@property (nonatomic, strong) TZAssetModel *model;
  15 +
  16 +@end
CNLiveImagePickerController/TZGifPhotoPreviewController.m 0 → 100755
  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 + if (tzImagePickerVc.gifPreviewPageUIConfigBlock) {
  95 + tzImagePickerVc.gifPreviewPageUIConfigBlock(_toolBar, _doneButton);
  96 + }
  97 +}
  98 +
  99 +#pragma mark - Layout
  100 +
  101 +- (void)viewDidLayoutSubviews {
  102 + [super viewDidLayoutSubviews];
  103 +
  104 + _previewView.frame = self.view.bounds;
  105 + _previewView.scrollView.frame = self.view.bounds;
  106 + CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
  107 + _toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
  108 + _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
  109 +
  110 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  111 + if (tzImagePickerVc.gifPreviewPageDidLayoutSubviewsBlock) {
  112 + tzImagePickerVc.gifPreviewPageDidLayoutSubviewsBlock(_toolBar, _doneButton);
  113 + }
  114 +}
  115 +
  116 +#pragma mark - Click Event
  117 +
  118 +- (void)signleTapAction {
  119 + _toolBar.hidden = !_toolBar.isHidden;
  120 + [self.navigationController setNavigationBarHidden:_toolBar.isHidden];
  121 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  122 + if (iOS7Later) {
  123 + if (_toolBar.isHidden) {
  124 + [UIApplication sharedApplication].statusBarHidden = YES;
  125 + } else if (tzImagePickerVc.needShowStatusBar) {
  126 + [UIApplication sharedApplication].statusBarHidden = NO;
  127 + }
  128 + }
  129 +}
  130 +
  131 +- (void)doneButtonClick {
  132 + if (self.navigationController) {
  133 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  134 + if (imagePickerVc.autoDismiss) {
  135 + [self.navigationController dismissViewControllerAnimated:YES completion:^{
  136 + [self callDelegateMethod];
  137 + }];
  138 + } else {
  139 + [self callDelegateMethod];
  140 + }
  141 + } else {
  142 + [self dismissViewControllerAnimated:YES completion:^{
  143 + [self callDelegateMethod];
  144 + }];
  145 + }
  146 +}
  147 +
  148 +- (void)callDelegateMethod {
  149 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  150 + UIImage *animatedImage = _previewView.imageView.image;
  151 + if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingGifImage:sourceAssets:)]) {
  152 + [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingGifImage:animatedImage sourceAssets:_model.asset];
  153 + }
  154 + if (imagePickerVc.didFinishPickingGifImageHandle) {
  155 + imagePickerVc.didFinishPickingGifImageHandle(animatedImage,_model.asset);
  156 + }
  157 +}
  158 +
  159 +#pragma clang diagnostic pop
  160 +
  161 +@end
CNLiveImagePickerController/TZImageCropManager.h 0 → 100755
  1 +//
  2 +// TZImageCropManager.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2016/12/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +// 图片裁剪管理类
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  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
CNLiveImagePickerController/TZImageCropManager.m 0 → 100755
  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 <ImageIO/ImageIO.h>
  12 +#import "TZImageManager.h"
  13 +#import "TZImagePickerController.h"
  14 +
  15 +@implementation TZImageCropManager
  16 +
  17 +/// 裁剪框背景的处理
  18 ++ (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop {
  19 + UIBezierPath *path= [UIBezierPath bezierPathWithRect:[UIScreen mainScreen].bounds];
  20 + CAShapeLayer *layer = [CAShapeLayer layer];
  21 + if (needCircleCrop) { // 圆形裁剪框
  22 + [path appendPath:[UIBezierPath bezierPathWithArcCenter:containerView.center radius:cropRect.size.width / 2 startAngle:0 endAngle: 2 * M_PI clockwise:NO]];
  23 + } else { // 矩形裁剪框
  24 + [path appendPath:[UIBezierPath bezierPathWithRect:cropRect]];
  25 + }
  26 + layer.path = path.CGPath;
  27 + layer.fillRule = kCAFillRuleEvenOdd;
  28 + layer.fillColor = [[UIColor blackColor] CGColor];
  29 + layer.opacity = 0.5;
  30 + [view.layer addSublayer:layer];
  31 +}
  32 +
  33 +/// 获得裁剪后的图片
  34 ++ (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView {
  35 + CGAffineTransform transform = CGAffineTransformIdentity;
  36 + // 平移的处理
  37 + CGRect imageViewRect = [imageView convertRect:imageView.bounds toView:containerView];
  38 + CGPoint point = CGPointMake(imageViewRect.origin.x + imageViewRect.size.width / 2, imageViewRect.origin.y + imageViewRect.size.height / 2);
  39 + CGFloat xMargin = containerView.tz_width - CGRectGetMaxX(rect) - rect.origin.x;
  40 + CGPoint zeroPoint = CGPointMake((CGRectGetWidth(containerView.frame) - xMargin) / 2, containerView.center.y);
  41 + CGPoint translation = CGPointMake(point.x - zeroPoint.x, point.y - zeroPoint.y);
  42 + transform = CGAffineTransformTranslate(transform, translation.x, translation.y);
  43 + // 缩放的处理
  44 + transform = CGAffineTransformScale(transform, zoomScale, zoomScale);
  45 +
  46 + CGImageRef imageRef = [self newTransformedImage:transform
  47 + sourceImage:imageView.image.CGImage
  48 + sourceSize:imageView.image.size
  49 + outputWidth:rect.size.width * [UIScreen mainScreen].scale
  50 + cropSize:rect.size
  51 + imageViewSize:imageView.frame.size];
  52 + UIImage *cropedImage = [UIImage imageWithCGImage:imageRef];
  53 + cropedImage = [[TZImageManager manager] fixOrientation:cropedImage];
  54 + CGImageRelease(imageRef);
  55 + return cropedImage;
  56 +}
  57 +
  58 ++ (CGImageRef)newTransformedImage:(CGAffineTransform)transform sourceImage:(CGImageRef)sourceImage sourceSize:(CGSize)sourceSize outputWidth:(CGFloat)outputWidth cropSize:(CGSize)cropSize imageViewSize:(CGSize)imageViewSize {
  59 + CGImageRef source = [self newScaledImage:sourceImage toSize:sourceSize];
  60 +
  61 + CGFloat aspect = cropSize.height/cropSize.width;
  62 + CGSize outputSize = CGSizeMake(outputWidth, outputWidth*aspect);
  63 +
  64 + CGContextRef context = CGBitmapContextCreate(NULL, outputSize.width, outputSize.height, CGImageGetBitsPerComponent(source), 0, CGImageGetColorSpace(source), CGImageGetBitmapInfo(source));
  65 + CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
  66 + CGContextFillRect(context, CGRectMake(0, 0, outputSize.width, outputSize.height));
  67 +
  68 + CGAffineTransform uiCoords = CGAffineTransformMakeScale(outputSize.width / cropSize.width, outputSize.height / cropSize.height);
  69 + uiCoords = CGAffineTransformTranslate(uiCoords, cropSize.width/2.0, cropSize.height / 2.0);
  70 + uiCoords = CGAffineTransformScale(uiCoords, 1.0, -1.0);
  71 + CGContextConcatCTM(context, uiCoords);
  72 +
  73 + CGContextConcatCTM(context, transform);
  74 + CGContextScaleCTM(context, 1.0, -1.0);
  75 +
  76 + CGContextDrawImage(context, CGRectMake(-imageViewSize.width/2, -imageViewSize.height/2.0, imageViewSize.width, imageViewSize.height), source);
  77 + CGImageRef resultRef = CGBitmapContextCreateImage(context);
  78 + CGContextRelease(context);
  79 + CGImageRelease(source);
  80 + return resultRef;
  81 +}
  82 +
  83 ++ (CGImageRef)newScaledImage:(CGImageRef)source toSize:(CGSize)size {
  84 + CGSize srcSize = size;
  85 + CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
  86 + CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, rgbColorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
  87 + CGColorSpaceRelease(rgbColorSpace);
  88 +
  89 + CGContextSetInterpolationQuality(context, kCGInterpolationNone);
  90 + CGContextTranslateCTM(context, size.width/2, size.height/2);
  91 +
  92 + CGContextDrawImage(context, CGRectMake(-srcSize.width/2, -srcSize.height/2, srcSize.width, srcSize.height), source);
  93 +
  94 + CGImageRef resultRef = CGBitmapContextCreateImage(context);
  95 + CGContextRelease(context);
  96 + return resultRef;
  97 +}
  98 +
  99 +/// 获取圆形图片
  100 ++ (UIImage *)circularClipImage:(UIImage *)image {
  101 + UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
  102 +
  103 + CGContextRef ctx = UIGraphicsGetCurrentContext();
  104 + CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
  105 + CGContextAddEllipseInRect(ctx, rect);
  106 + CGContextClip(ctx);
  107 +
  108 + [image drawInRect:rect];
  109 + UIImage *circleImage = UIGraphicsGetImageFromCurrentImageContext();
  110 +
  111 + UIGraphicsEndImageContext();
  112 + return circleImage;
  113 +}
  114 +
  115 +@end
  116 +
  117 +
  118 +@implementation UIImage (TZGif)
  119 +
  120 ++ (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data {
  121 + if (!data) {
  122 + return nil;
  123 + }
  124 +
  125 + CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
  126 +
  127 + size_t count = CGImageSourceGetCount(source);
  128 +
  129 + UIImage *animatedImage;
  130 +
  131 + if (count <= 1) {
  132 + animatedImage = [[UIImage alloc] initWithData:data];
  133 + }
  134 + else {
  135 + // images数组过大时内存会飙升,在这里限制下最大count
  136 + NSInteger maxCount = [TZImagePickerConfig sharedInstance].gifPreviewMaxImagesCount ?: 200;
  137 + NSInteger interval = MAX((count + maxCount / 2) / maxCount, 1);
  138 +
  139 + NSMutableArray *images = [NSMutableArray array];
  140 +
  141 + NSTimeInterval duration = 0.0f;
  142 +
  143 + for (size_t i = 0; i < count; i+=interval) {
  144 + CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
  145 + if (!image) {
  146 + continue;
  147 + }
  148 +
  149 + duration += [self sd_frameDurationAtIndex:i source:source] * MIN(interval, 3);
  150 +
  151 + [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
  152 +
  153 + CGImageRelease(image);
  154 + }
  155 +
  156 + if (!duration) {
  157 + duration = (1.0f / 10.0f) * count;
  158 + }
  159 +
  160 + animatedImage = [UIImage animatedImageWithImages:images duration:duration];
  161 + }
  162 +
  163 + CFRelease(source);
  164 +
  165 + return animatedImage;
  166 +}
  167 +
  168 ++ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
  169 + float frameDuration = 0.1f;
  170 + CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
  171 + NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
  172 + NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
  173 +
  174 + NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
  175 + if (delayTimeUnclampedProp) {
  176 + frameDuration = [delayTimeUnclampedProp floatValue];
  177 + }
  178 + else {
  179 +
  180 + NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
  181 + if (delayTimeProp) {
  182 + frameDuration = [delayTimeProp floatValue];
  183 + }
  184 + }
  185 +
  186 + // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
  187 + // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
  188 + // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
  189 + // for more information.
  190 +
  191 + if (frameDuration < 0.011f) {
  192 + frameDuration = 0.100f;
  193 + }
  194 +
  195 + CFRelease(cfFrameProperties);
  196 + return frameDuration;
  197 +}
  198 +
  199 +@end
CNLiveImagePickerController/TZImageManager.h 0 → 100755
  1 +//
  2 +// TZImageManager.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/4.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +// 图片资源获取管理类
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +#import <AVFoundation/AVFoundation.h>
  12 +#import <Photos/Photos.h>
  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 (weak, nonatomic) id<TZImagePickerControllerDelegate> pickerDelegate;
  25 +
  26 +#pragma mark - 添加: 原有逻辑-会话id(LXG)
  27 +//zl__会话Id用于视频导出路径
  28 +@property (nonatomic, strong) NSString *conversationId;
  29 +
  30 +@property (nonatomic, assign) BOOL shouldFixOrientation;
  31 +
  32 +/// Default is 600px / 默认600像素宽
  33 +@property (nonatomic, assign) CGFloat photoPreviewMaxWidth;
  34 +/// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽
  35 +@property (nonatomic, assign) CGFloat photoWidth;
  36 +
  37 +/// Default is 4, Use in photos collectionView in TZPhotoPickerController
  38 +/// 默认4列, TZPhotoPickerController中的照片collectionView
  39 +@property (nonatomic, assign) NSInteger columnNumber;
  40 +
  41 +/// Sort photos ascending by modificationDate,Default is YES
  42 +/// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个
  43 +@property (nonatomic, assign) BOOL sortAscendingByModificationDate;
  44 +
  45 +/// Minimum selectable photo width, Default is 0
  46 +/// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中
  47 +@property (nonatomic, assign) NSInteger minPhotoWidthSelectable;
  48 +@property (nonatomic, assign) NSInteger minPhotoHeightSelectable;
  49 +@property (nonatomic, assign) BOOL hideWhenCanNotSelect;
  50 +
  51 +/// Return YES if Authorized 返回YES如果得到了授权
  52 +- (BOOL)authorizationStatusAuthorized;
  53 ++ (NSInteger)authorizationStatus;
  54 +- (void)requestAuthorizationWithCompletion:(void (^)(void))completion;
  55 +
  56 +/// Get Album 获得相册/相册数组
  57 +- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion;
  58 +- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray<TZAlbumModel *> *models))completion;
  59 +
  60 +/// Get Assets 获得Asset数组
  61 +- (void)getAssetsFromFetchResult:(id)result completion:(void (^)(NSArray<TZAssetModel *> *models))completion;
  62 +- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *models))completion;
  63 +- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *model))completion;
  64 +
  65 +/// Get photo 获得照片
  66 +- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion;
  67 +
  68 +- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  69 +- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  70 +- (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;
  71 +- (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;
  72 +- (int32_t)requestImageDataForAsset:(id)asset completion:(void (^)(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler;
  73 +
  74 +/// Get full Image 获取原图
  75 +/// 如下两个方法completion一般会调多次,一般会先返回缩略图,再返回原图(详见方法内部使用的系统API的说明),如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。
  76 +- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion;
  77 +- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  78 +// 该方法中,completion只会走一次
  79 +- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
  80 +- (void)getOriginalPhotoDataWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
  81 +
  82 +/// Save photo 保存照片
  83 +- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion;
  84 +- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion;
  85 +
  86 +/// Save video 保存视频
  87 +- (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(NSError *error))completion;
  88 +- (void)saveVideoWithUrl:(NSURL *)url location:(CLLocation *)location completion:(void (^)(NSError *error))completion;
  89 +
  90 +/// Get video 获得视频
  91 +- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion;
  92 +- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion;
  93 +
  94 +/// Export video 导出视频 presetName: 预设名字,默认值是AVAssetExportPreset640x480
  95 +- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
  96 +- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
  97 +/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success:
  98 +- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion __attribute__((deprecated("Use -getVideoOutputPathWithAsset:failure:success:")));
  99 +
  100 +/// Get photo bytes 获得一组照片的大小
  101 +- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion;
  102 +
  103 +/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
  104 +- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset;
  105 +
  106 +- (NSString *)getAssetIdentifier:(id)asset;
  107 +- (BOOL)isCameraRollAlbum:(id)metadata;
  108 +
  109 +/// 检查照片大小是否满足最小要求
  110 +- (BOOL)isPhotoSelectableWithAsset:(id)asset;
  111 +- (CGSize)photoSizeWithAsset:(id)asset;
  112 +
  113 +/// 修正图片转向
  114 +- (UIImage *)fixOrientation:(UIImage *)aImage;
  115 +
  116 +/// 获取asset的资源类型
  117 +- (TZAssetModelMediaType)getAssetType:(id)asset;
  118 +/// 缩放图片至新尺寸
  119 +- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size;
  120 +
  121 +/// 判断asset是否是视频
  122 +- (BOOL)isVideo:(id)asset;
  123 +
  124 +@end
  125 +
  126 +//@interface TZSortDescriptor : NSSortDescriptor
  127 +//
  128 +//@end
CNLiveImagePickerController/TZImageManager.m 0 → 100755
  1 +//
  2 +// TZImageManager.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/4.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZImageManager.h"
  10 +#import <AssetsLibrary/AssetsLibrary.h>
  11 +#import "TZAssetModel.h"
  12 +#import "TZImagePickerController.h"
  13 +
  14 +@interface TZImageManager ()
  15 +#pragma clang diagnostic push
  16 +#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  17 +@property (nonatomic, strong) ALAssetsLibrary *assetLibrary;
  18 +@end
  19 +
  20 +@implementation TZImageManager
  21 +
  22 +CGSize AssetGridThumbnailSize;
  23 +CGFloat TZScreenWidth;
  24 +CGFloat TZScreenScale;
  25 +
  26 +static TZImageManager *manager;
  27 +static dispatch_once_t onceToken;
  28 +
  29 ++ (instancetype)manager {
  30 + dispatch_once(&onceToken, ^{
  31 + manager = [[self alloc] init];
  32 + if (iOS8Later) {
  33 + // manager.cachingImageManager = [[PHCachingImageManager alloc] init];
  34 + // manager.cachingImageManager.allowsCachingHighQualityImages = YES;
  35 + }
  36 +
  37 + [manager configTZScreenWidth];
  38 + });
  39 + return manager;
  40 +}
  41 +
  42 ++ (void)deallocManager {
  43 + onceToken = 0;
  44 + manager = nil;
  45 +}
  46 +
  47 +- (void)setPhotoWidth:(CGFloat)photoWidth {
  48 + _photoWidth = photoWidth;
  49 + TZScreenWidth = photoWidth / 2;
  50 +}
  51 +
  52 +- (void)setColumnNumber:(NSInteger)columnNumber {
  53 + [self configTZScreenWidth];
  54 +
  55 + _columnNumber = columnNumber;
  56 + CGFloat margin = 4;
  57 + CGFloat itemWH = (TZScreenWidth - 2 * margin - 4) / columnNumber - margin;
  58 + AssetGridThumbnailSize = CGSizeMake(itemWH * TZScreenScale, itemWH * TZScreenScale);
  59 +}
  60 +
  61 +- (void)configTZScreenWidth {
  62 + TZScreenWidth = [UIScreen mainScreen].bounds.size.width;
  63 + // 测试发现,如果scale在plus真机上取到3.0,内存会增大特别多。故这里写死成2.0
  64 + TZScreenScale = 2.0;
  65 + if (TZScreenWidth > 700) {
  66 + TZScreenScale = 1.5;
  67 + }
  68 +}
  69 +
  70 +- (ALAssetsLibrary *)assetLibrary {
  71 + if (_assetLibrary == nil) _assetLibrary = [[ALAssetsLibrary alloc] init];
  72 + return _assetLibrary;
  73 +}
  74 +
  75 +/// Return YES if Authorized 返回YES如果得到了授权
  76 +- (BOOL)authorizationStatusAuthorized {
  77 + NSInteger status = [self.class authorizationStatus];
  78 + if (status == 0) {
  79 + /**
  80 + * 当某些情况下AuthorizationStatus == AuthorizationStatusNotDetermined时,无法弹出系统首次使用的授权alertView,系统应用设置里亦没有相册的设置,此时将无法使用,故作以下操作,弹出系统首次使用的授权alertView
  81 + */
  82 + [self requestAuthorizationWithCompletion:nil];
  83 + }
  84 +
  85 + return status == 3;
  86 +}
  87 +
  88 ++ (NSInteger)authorizationStatus {
  89 + if (iOS8Later) {
  90 + return [PHPhotoLibrary authorizationStatus];
  91 + } else {
  92 + return [ALAssetsLibrary authorizationStatus];
  93 + }
  94 + return NO;
  95 +}
  96 +
  97 +- (void)requestAuthorizationWithCompletion:(void (^)(void))completion {
  98 + void (^callCompletionBlock)(void) = ^(){
  99 + dispatch_async(dispatch_get_main_queue(), ^{
  100 + if (completion) {
  101 + completion();
  102 + }
  103 + });
  104 + };
  105 +
  106 + if (iOS8Later) {
  107 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  108 + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
  109 + callCompletionBlock();
  110 + }];
  111 + });
  112 + } else {
  113 + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
  114 + callCompletionBlock();
  115 + } failureBlock:^(NSError *error) {
  116 + callCompletionBlock();
  117 + }];
  118 + }
  119 +}
  120 +
  121 +#pragma mark - Get Album
  122 +
  123 +/// Get Album 获得相册/相册数组
  124 +- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion {
  125 + __block TZAlbumModel *model;
  126 + if (iOS8Later) {
  127 + PHFetchOptions *option = [[PHFetchOptions alloc] init];
  128 + if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
  129 + if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
  130 + PHAssetMediaTypeVideo];
  131 + // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]];
  132 + if (!self.sortAscendingByModificationDate) {
  133 + option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]];
  134 + }
  135 + PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
  136 + for (PHAssetCollection *collection in smartAlbums) {
  137 + // 有可能是PHCollectionList类的的对象,过滤掉
  138 + if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
  139 + // 过滤空相册
  140 + if (collection.estimatedAssetCount <= 0) continue;
  141 + if ([self isCameraRollAlbum:collection]) {
  142 + PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
  143 + model = [self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:YES needFetchAssets:needFetchAssets];
  144 + if (completion) completion(model);
  145 + break;
  146 + }
  147 + }
  148 + } else {
  149 + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
  150 + if ([group numberOfAssets] < 1) return;
  151 + if ([self isCameraRollAlbum:group]) {
  152 + NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
  153 + model = [self modelWithResult:group name:name isCameraRoll:YES needFetchAssets:needFetchAssets];
  154 + if (completion) completion(model);
  155 + *stop = YES;
  156 + }
  157 + } failureBlock:nil];
  158 + }
  159 +}
  160 +
  161 +- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray<TZAlbumModel *> *))completion{
  162 + NSMutableArray *albumArr = [NSMutableArray array];
  163 + if (iOS8Later) {
  164 + PHFetchOptions *option = [[PHFetchOptions alloc] init];
  165 + if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
  166 + if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
  167 + PHAssetMediaTypeVideo];
  168 + // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]];
  169 + if (!self.sortAscendingByModificationDate) {
  170 + option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]];
  171 + }
  172 + // 我的照片流 1.6.10重新加入..
  173 + PHFetchResult *myPhotoStreamAlbum = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream options:nil];
  174 + PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
  175 + PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
  176 + PHFetchResult *syncedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumSyncedAlbum options:nil];
  177 + PHFetchResult *sharedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumCloudShared options:nil];
  178 + NSArray *allAlbums = @[myPhotoStreamAlbum,smartAlbums,topLevelUserCollections,syncedAlbums,sharedAlbums];
  179 + for (PHFetchResult *fetchResult in allAlbums) {
  180 + for (PHAssetCollection *collection in fetchResult) {
  181 + // 有可能是PHCollectionList类的的对象,过滤掉
  182 + if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
  183 + // 过滤空相册
  184 + if (collection.estimatedAssetCount <= 0) continue;
  185 + PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
  186 + if (fetchResult.count < 1) continue;
  187 +
  188 + if ([self.pickerDelegate respondsToSelector:@selector(isAlbumCanSelect:result:)]) {
  189 + if (![self.pickerDelegate isAlbumCanSelect:collection.localizedTitle result:fetchResult]) {
  190 + continue;
  191 + }
  192 + }
  193 +
  194 + if (collection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumAllHidden) continue;
  195 + if (collection.assetCollectionSubtype == 1000000201) continue; //『最近删除』相册
  196 + if ([self isCameraRollAlbum:collection]) {
  197 + [albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:YES needFetchAssets:needFetchAssets] atIndex:0];
  198 + } else {
  199 + [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:NO needFetchAssets:needFetchAssets]];
  200 + }
  201 + }
  202 + }
  203 + if (completion && albumArr.count > 0) completion(albumArr);
  204 + } else {
  205 + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
  206 + if (group == nil) {
  207 + if (completion && albumArr.count > 0) completion(albumArr);
  208 + }
  209 + if ([group numberOfAssets] < 1) return;
  210 + NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
  211 +
  212 + if ([self.pickerDelegate respondsToSelector:@selector(isAlbumCanSelect:result:)]) {
  213 + if (![self.pickerDelegate isAlbumCanSelect:name result:group]) {
  214 + return;
  215 + }
  216 + }
  217 +
  218 + if ([self isCameraRollAlbum:group]) {
  219 + [albumArr insertObject:[self modelWithResult:group name:name isCameraRoll:YES needFetchAssets:needFetchAssets] atIndex:0];
  220 + } else if ([[group valueForProperty:ALAssetsGroupPropertyType] intValue] == ALAssetsGroupPhotoStream) {
  221 + if (albumArr.count) {
  222 + [albumArr insertObject:[self modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets] atIndex:1];
  223 + } else {
  224 + [albumArr addObject:[self modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets]];
  225 + }
  226 + } else {
  227 + [albumArr addObject:[self modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets]];
  228 + }
  229 + } failureBlock:nil];
  230 + }
  231 +}
  232 +
  233 +#pragma mark - Get Assets
  234 +
  235 +/// Get Assets 获得照片数组
  236 +- (void)getAssetsFromFetchResult:(id)result completion:(void (^)(NSArray<TZAssetModel *> *))completion {
  237 + TZImagePickerConfig *config = [TZImagePickerConfig sharedInstance];
  238 + return [self getAssetsFromFetchResult:result allowPickingVideo:config.allowPickingVideo allowPickingImage:config.allowPickingImage completion:completion];
  239 +}
  240 +
  241 +- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *))completion {
  242 + NSMutableArray *photoArr = [NSMutableArray array];
  243 + if ([result isKindOfClass:[PHFetchResult class]]) {
  244 + PHFetchResult *fetchResult = (PHFetchResult *)result;
  245 + [fetchResult enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  246 + TZAssetModel *model = [self assetModelWithAsset:obj allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
  247 + if (model) {
  248 + [photoArr addObject:model];
  249 + }
  250 + }];
  251 + if (completion) completion(photoArr);
  252 + } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
  253 + ALAssetsGroup *group = (ALAssetsGroup *)result;
  254 + if (allowPickingImage && allowPickingVideo) {
  255 + [group setAssetsFilter:[ALAssetsFilter allAssets]];
  256 + } else if (allowPickingVideo) {
  257 + [group setAssetsFilter:[ALAssetsFilter allVideos]];
  258 + } else if (allowPickingImage) {
  259 + [group setAssetsFilter:[ALAssetsFilter allPhotos]];
  260 + }
  261 + ALAssetsGroupEnumerationResultsBlock resultBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
  262 + if (result == nil) {
  263 + if (completion) completion(photoArr);
  264 + }
  265 + TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
  266 + if (model) {
  267 + [photoArr addObject:model];
  268 + }
  269 + };
  270 + if (self.sortAscendingByModificationDate) {
  271 + [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
  272 + if (resultBlock) { resultBlock(result,index,stop); }
  273 + }];
  274 + } else {
  275 + [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
  276 + if (resultBlock) {resultBlock(result,index,stop); }
  277 + }];
  278 + }
  279 + }
  280 +}
  281 +
  282 +/// Get asset at index 获得下标为index的单个照片
  283 +/// if index beyond bounds, return nil in callback 如果索引越界, 在回调中返回 nil
  284 +- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *))completion {
  285 + if ([result isKindOfClass:[PHFetchResult class]]) {
  286 + PHFetchResult *fetchResult = (PHFetchResult *)result;
  287 + PHAsset *asset;
  288 + @try {
  289 + asset = fetchResult[index];
  290 + }
  291 + @catch (NSException* e) {
  292 + if (completion) completion(nil);
  293 + return;
  294 + }
  295 + TZAssetModel *model = [self assetModelWithAsset:asset allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
  296 + if (completion) completion(model);
  297 + } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
  298 + ALAssetsGroup *group = (ALAssetsGroup *)result;
  299 + if (allowPickingImage && allowPickingVideo) {
  300 + [group setAssetsFilter:[ALAssetsFilter allAssets]];
  301 + } else if (allowPickingVideo) {
  302 + [group setAssetsFilter:[ALAssetsFilter allVideos]];
  303 + } else if (allowPickingImage) {
  304 + [group setAssetsFilter:[ALAssetsFilter allPhotos]];
  305 + }
  306 + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:index];
  307 + @try {
  308 + [group enumerateAssetsAtIndexes:indexSet options:NSEnumerationConcurrent usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
  309 + if (!result) return;
  310 + TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
  311 + if (completion) completion(model);
  312 + }];
  313 + }
  314 + @catch (NSException* e) {
  315 + if (completion) completion(nil);
  316 + }
  317 + }
  318 +}
  319 +
  320 +- (TZAssetModel *)assetModelWithAsset:(id)asset allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage {
  321 + BOOL canSelect = YES;
  322 + if ([self.pickerDelegate respondsToSelector:@selector(isAssetCanSelect:)]) {
  323 + canSelect = [self.pickerDelegate isAssetCanSelect:asset];
  324 + }
  325 + if (!canSelect) return nil;
  326 +
  327 + TZAssetModel *model;
  328 + TZAssetModelMediaType type = [self getAssetType:asset];
  329 + if ([asset isKindOfClass:[PHAsset class]]) {
  330 + if (!allowPickingVideo && type == TZAssetModelMediaTypeVideo) return nil;
  331 + if (!allowPickingImage && type == TZAssetModelMediaTypePhoto) return nil;
  332 + if (!allowPickingImage && type == TZAssetModelMediaTypePhotoGif) return nil;
  333 +
  334 + PHAsset *phAsset = (PHAsset *)asset;
  335 + if (self.hideWhenCanNotSelect) {
  336 + // 过滤掉尺寸不满足要求的图片
  337 + if (![self isPhotoSelectableWithAsset:phAsset]) {
  338 + return nil;
  339 + }
  340 + }
  341 + NSString *timeLength = type == TZAssetModelMediaTypeVideo ? [NSString stringWithFormat:@"%0.0f",phAsset.duration] : @"";
  342 + timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue];
  343 + model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength];
  344 + } else {
  345 + if (!allowPickingVideo){
  346 + model = [TZAssetModel modelWithAsset:asset type:type];
  347 + return model;
  348 + }
  349 + /// Allow picking video
  350 + if (type == TZAssetModelMediaTypeVideo) {
  351 + NSTimeInterval duration = [[asset valueForProperty:ALAssetPropertyDuration] doubleValue];
  352 + NSString *timeLength = [NSString stringWithFormat:@"%0.0f",duration];
  353 + timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue];
  354 + model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength];
  355 + } else {
  356 + if (self.hideWhenCanNotSelect) {
  357 + // 过滤掉尺寸不满足要求的图片
  358 + if (![self isPhotoSelectableWithAsset:asset]) {
  359 + return nil;
  360 + }
  361 + }
  362 + model = [TZAssetModel modelWithAsset:asset type:type];
  363 + }
  364 + }
  365 + return model;
  366 +}
  367 +
  368 +- (TZAssetModelMediaType)getAssetType:(id)asset {
  369 + TZAssetModelMediaType type = TZAssetModelMediaTypePhoto;
  370 + if ([asset isKindOfClass:[PHAsset class]]) {
  371 + PHAsset *phAsset = (PHAsset *)asset;
  372 + if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo;
  373 + else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio;
  374 + else if (phAsset.mediaType == PHAssetMediaTypeImage) {
  375 + if (@available(iOS 9.1, *)) {
  376 + // if (asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) type = TZAssetModelMediaTypeLivePhoto;
  377 + }
  378 + // Gif
  379 + if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) {
  380 + type = TZAssetModelMediaTypePhotoGif;
  381 + }
  382 + }
  383 + } else {
  384 + if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) {
  385 + type = TZAssetModelMediaTypeVideo;
  386 + }
  387 + }
  388 + return type;
  389 +}
  390 +
  391 +- (NSString *)getNewTimeFromDurationSecond:(NSInteger)duration {
  392 + NSString *newTime;
  393 + if (duration < 10) {
  394 + newTime = [NSString stringWithFormat:@"0:0%zd",duration];
  395 + } else if (duration < 60) {
  396 + newTime = [NSString stringWithFormat:@"0:%zd",duration];
  397 + } else {
  398 + NSInteger min = duration / 60;
  399 + NSInteger sec = duration - (min * 60);
  400 + if (sec < 10) {
  401 + newTime = [NSString stringWithFormat:@"%zd:0%zd",min,sec];
  402 + } else {
  403 + newTime = [NSString stringWithFormat:@"%zd:%zd",min,sec];
  404 + }
  405 + }
  406 + return newTime;
  407 +}
  408 +
  409 +/// Get photo bytes 获得一组照片的大小
  410 +- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion {
  411 + if (!photos || !photos.count) {
  412 + if (completion) completion(@"0B");
  413 + return;
  414 + }
  415 + __block NSInteger dataLength = 0;
  416 + __block NSInteger assetCount = 0;
  417 + for (NSInteger i = 0; i < photos.count; i++) {
  418 + TZAssetModel *model = photos[i];
  419 + if ([model.asset isKindOfClass:[PHAsset class]]) {
  420 + PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  421 + options.resizeMode = PHImageRequestOptionsResizeModeFast;
  422 + options.networkAccessAllowed = YES;
  423 + if (model.type == TZAssetModelMediaTypePhotoGif) {
  424 + options.version = PHImageRequestOptionsVersionOriginal;
  425 + }
  426 + [[PHImageManager defaultManager] requestImageDataForAsset:model.asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  427 + if (model.type != TZAssetModelMediaTypeVideo) dataLength += imageData.length;
  428 + assetCount ++;
  429 + if (assetCount >= photos.count) {
  430 + NSString *bytes = [self getBytesFromDataLength:dataLength];
  431 + if (completion) completion(bytes);
  432 + }
  433 + }];
  434 + } else if ([model.asset isKindOfClass:[ALAsset class]]) {
  435 + ALAssetRepresentation *representation = [model.asset defaultRepresentation];
  436 + if (model.type != TZAssetModelMediaTypeVideo) dataLength += (NSInteger)representation.size;
  437 + if (i >= photos.count - 1) {
  438 + NSString *bytes = [self getBytesFromDataLength:dataLength];
  439 + if (completion) completion(bytes);
  440 + }
  441 + }
  442 + }
  443 +}
  444 +
  445 +- (NSString *)getBytesFromDataLength:(NSInteger)dataLength {
  446 + NSString *bytes;
  447 + if (dataLength >= 0.1 * (1024 * 1024)) {
  448 + bytes = [NSString stringWithFormat:@"%0.1fM",dataLength/1024/1024.0];
  449 + } else if (dataLength >= 1024) {
  450 + bytes = [NSString stringWithFormat:@"%0.0fK",dataLength/1024.0];
  451 + } else {
  452 + bytes = [NSString stringWithFormat:@"%zdB",dataLength];
  453 + }
  454 + return bytes;
  455 +}
  456 +
  457 +#pragma mark - Get Photo
  458 +
  459 +/// Get photo 获得照片本身
  460 +- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *, NSDictionary *, BOOL isDegraded))completion {
  461 + CGFloat fullScreenWidth = TZScreenWidth;
  462 + if (fullScreenWidth > _photoPreviewMaxWidth) {
  463 + fullScreenWidth = _photoPreviewMaxWidth;
  464 + }
  465 + return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:nil networkAccessAllowed:YES];
  466 +}
  467 +
  468 +- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion {
  469 + return [self getPhotoWithAsset:asset photoWidth:photoWidth completion:completion progressHandler:nil networkAccessAllowed:YES];
  470 +}
  471 +
  472 +- (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 {
  473 + CGFloat fullScreenWidth = TZScreenWidth;
  474 + if (fullScreenWidth > _photoPreviewMaxWidth) {
  475 + fullScreenWidth = _photoPreviewMaxWidth;
  476 + }
  477 + return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:progressHandler networkAccessAllowed:networkAccessAllowed];
  478 +}
  479 +
  480 +- (int32_t)requestImageDataForAsset:(id)asset completion:(void (^)(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler {
  481 + if ([asset isKindOfClass:[PHAsset class]]) {
  482 + PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  483 + options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  484 + dispatch_async(dispatch_get_main_queue(), ^{
  485 + if (progressHandler) {
  486 + progressHandler(progress, error, stop, info);
  487 + }
  488 + });
  489 + };
  490 + options.networkAccessAllowed = YES;
  491 + options.resizeMode = PHImageRequestOptionsResizeModeFast;
  492 + int32_t imageRequestID = [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  493 + if (completion) completion(imageData,dataUTI,orientation,info);
  494 + }];
  495 + return imageRequestID;
  496 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  497 + ALAsset *alAsset = (ALAsset *)asset;
  498 + dispatch_async(dispatch_get_global_queue(0,0), ^{
  499 + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
  500 + CGImageRef fullScrennImageRef = [assetRep fullScreenImage];
  501 + UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp];
  502 + dispatch_async(dispatch_get_main_queue(), ^{
  503 + if (completion) completion(UIImageJPEGRepresentation(fullScrennImage, 0.83), nil, UIImageOrientationUp, nil);
  504 + });
  505 + });
  506 + }
  507 + return 0;
  508 +}
  509 +
  510 +- (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 {
  511 + if ([asset isKindOfClass:[PHAsset class]]) {
  512 + CGSize imageSize;
  513 + if (photoWidth < TZScreenWidth && photoWidth < _photoPreviewMaxWidth) {
  514 + imageSize = AssetGridThumbnailSize;
  515 + } else {
  516 + PHAsset *phAsset = (PHAsset *)asset;
  517 + CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight;
  518 + CGFloat pixelWidth = photoWidth * TZScreenScale * 1.5;
  519 + // 超宽图片
  520 + if (aspectRatio > 1.8) {
  521 + pixelWidth = pixelWidth * aspectRatio;
  522 + }
  523 + // 超高图片
  524 + if (aspectRatio < 0.2) {
  525 + pixelWidth = pixelWidth * 0.5;
  526 + }
  527 + CGFloat pixelHeight = pixelWidth / aspectRatio;
  528 + imageSize = CGSizeMake(pixelWidth, pixelHeight);
  529 + }
  530 +
  531 + __block UIImage *image;
  532 + // 修复获取图片时出现的瞬间内存过高问题
  533 + // 下面两行代码,来自hsjcom,他的github是:https://github.com/hsjcom 表示感谢
  534 + PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
  535 + option.resizeMode = PHImageRequestOptionsResizeModeFast;
  536 + int32_t imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
  537 + if (result) {
  538 + image = result;
  539 + }
  540 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  541 + if (downloadFinined && result) {
  542 + result = [self fixOrientation:result];
  543 + if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
  544 + }
  545 + // Download image from iCloud / 从iCloud下载图片
  546 + if ([info objectForKey:PHImageResultIsInCloudKey] && !result && networkAccessAllowed) {
  547 + PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  548 + options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  549 + dispatch_async(dispatch_get_main_queue(), ^{
  550 + if (progressHandler) {
  551 + progressHandler(progress, error, stop, info);
  552 + }
  553 + });
  554 + };
  555 + options.networkAccessAllowed = YES;
  556 + options.resizeMode = PHImageRequestOptionsResizeModeFast;
  557 + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  558 + UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1];
  559 + if (![TZImagePickerConfig sharedInstance].notScaleImage) {
  560 + resultImage = [self scaleImage:resultImage toSize:imageSize];
  561 + }
  562 + if (!resultImage) {
  563 + resultImage = image;
  564 + }
  565 + resultImage = [self fixOrientation:resultImage];
  566 + if (completion) completion(resultImage,info,NO);
  567 + }];
  568 + }
  569 + }];
  570 + return imageRequestID;
  571 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  572 + ALAsset *alAsset = (ALAsset *)asset;
  573 + dispatch_async(dispatch_get_global_queue(0,0), ^{
  574 + CGImageRef thumbnailImageRef = alAsset.thumbnail;
  575 + UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnailImageRef scale:2.0 orientation:UIImageOrientationUp];
  576 + dispatch_async(dispatch_get_main_queue(), ^{
  577 + if (completion) completion(thumbnailImage,nil,YES);
  578 +
  579 + if (photoWidth == TZScreenWidth || photoWidth == self->_photoPreviewMaxWidth) {
  580 + dispatch_async(dispatch_get_global_queue(0,0), ^{
  581 + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
  582 + CGImageRef fullScrennImageRef = [assetRep fullScreenImage];
  583 + UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp];
  584 +
  585 + dispatch_async(dispatch_get_main_queue(), ^{
  586 + if (completion) completion(fullScrennImage,nil,NO);
  587 + });
  588 + });
  589 + }
  590 + });
  591 + });
  592 + }
  593 + return 0;
  594 +}
  595 +
  596 +/// Get postImage / 获取封面图
  597 +- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *))completion {
  598 + if (iOS8Later) {
  599 + id asset = [model.result lastObject];
  600 + if (!self.sortAscendingByModificationDate) {
  601 + asset = [model.result firstObject];
  602 + }
  603 + [[TZImageManager manager] getPhotoWithAsset:asset photoWidth:80 completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  604 + if (completion) completion(photo);
  605 + }];
  606 + } else {
  607 + ALAssetsGroup *group = model.result;
  608 + UIImage *postImage = [UIImage imageWithCGImage:group.posterImage];
  609 + if (completion) completion(postImage);
  610 + }
  611 +}
  612 +
  613 +/// Get Original Photo / 获取原图
  614 +- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion {
  615 + [self getOriginalPhotoWithAsset:asset newCompletion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  616 + if (completion) {
  617 + completion(photo,info);
  618 + }
  619 + }];
  620 +}
  621 +
  622 +- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion {
  623 + if ([asset isKindOfClass:[PHAsset class]]) {
  624 + PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init];
  625 + option.networkAccessAllowed = YES;
  626 + option.resizeMode = PHImageRequestOptionsResizeModeFast;
  627 + [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage *result, NSDictionary *info) {
  628 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  629 + if (downloadFinined && result) {
  630 + result = [self fixOrientation:result];
  631 + BOOL isDegraded = [[info objectForKey:PHImageResultIsDegradedKey] boolValue];
  632 + if (completion) completion(result,info,isDegraded);
  633 + }
  634 + }];
  635 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  636 + ALAsset *alAsset = (ALAsset *)asset;
  637 + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
  638 +
  639 + dispatch_async(dispatch_get_global_queue(0,0), ^{
  640 + CGImageRef originalImageRef = [assetRep fullResolutionImage];
  641 + UIImage *originalImage = [UIImage imageWithCGImage:originalImageRef scale:1.0 orientation:UIImageOrientationUp];
  642 +
  643 + dispatch_async(dispatch_get_main_queue(), ^{
  644 + if (completion) completion(originalImage,nil,NO);
  645 + });
  646 + });
  647 + }
  648 +}
  649 +
  650 +- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion {
  651 + [self getOriginalPhotoDataWithAsset:asset progressHandler:nil completion:completion];
  652 +}
  653 +
  654 +- (void)getOriginalPhotoDataWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion {
  655 + if ([asset isKindOfClass:[PHAsset class]]) {
  656 + PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
  657 + option.networkAccessAllowed = YES;
  658 + if ([[asset valueForKey:@"filename"] hasSuffix:@"GIF"]) {
  659 + // if version isn't PHImageRequestOptionsVersionOriginal, the gif may cann't play
  660 + option.version = PHImageRequestOptionsVersionOriginal;
  661 + }
  662 + [option setProgressHandler:progressHandler];
  663 + option.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
  664 + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  665 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  666 + if (downloadFinined && imageData) {
  667 + if (completion) completion(imageData,info,NO);
  668 + }
  669 + }];
  670 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  671 + ALAsset *alAsset = (ALAsset *)asset;
  672 + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
  673 + Byte *imageBuffer = (Byte *)malloc(assetRep.size);
  674 + NSUInteger bufferSize = [assetRep getBytes:imageBuffer fromOffset:0.0 length:assetRep.size error:nil];
  675 + NSData *imageData = [NSData dataWithBytesNoCopy:imageBuffer length:bufferSize freeWhenDone:YES];
  676 + if (completion) completion(imageData,nil,NO);
  677 + }
  678 +}
  679 +
  680 +#pragma mark - Save photo
  681 +
  682 +- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion {
  683 + [self savePhotoWithImage:image location:nil completion:completion];
  684 +}
  685 +
  686 +- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion {
  687 + if (iOS8Later) {
  688 + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  689 + if (@available(iOS 9, *)) {
  690 + NSData *data = UIImageJPEGRepresentation(image, 0.9);
  691 + PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
  692 + options.shouldMoveFile = YES;
  693 + PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
  694 + [request addResourceWithType:PHAssetResourceTypePhoto data:data options:options];
  695 + if (location) {
  696 + request.location = location;
  697 + }
  698 + request.creationDate = [NSDate date];
  699 + } else {
  700 + PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
  701 + if (location) {
  702 + request.location = location;
  703 + }
  704 + request.creationDate = [NSDate date];
  705 + }
  706 + } completionHandler:^(BOOL success, NSError *error) {
  707 + dispatch_async(dispatch_get_main_queue(), ^{
  708 + if (success && completion) {
  709 + completion(nil);
  710 + } else if (error) {
  711 + NSLog(@"保存照片出错:%@",error.localizedDescription);
  712 + if (completion) {
  713 + completion(error);
  714 + }
  715 + }
  716 + });
  717 + }];
  718 + } else {
  719 + [self.assetLibrary writeImageToSavedPhotosAlbum:image.CGImage orientation:[self orientationFromImage:image] completionBlock:^(NSURL *assetURL, NSError *error) {
  720 + if (error) {
  721 + NSLog(@"保存图片失败:%@",error.localizedDescription);
  722 + if (completion) {
  723 + completion(error);
  724 + }
  725 + } else {
  726 + // 多给系统0.5秒的时间,让系统去更新相册数据
  727 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  728 + if (completion) {
  729 + completion(nil);
  730 + }
  731 + });
  732 + }
  733 + }];
  734 + }
  735 +}
  736 +
  737 +#pragma mark - Save video
  738 +
  739 +- (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(NSError *error))completion {
  740 + [self saveVideoWithUrl:url location:nil completion:completion];
  741 +}
  742 +
  743 +- (void)saveVideoWithUrl:(NSURL *)url location:(CLLocation *)location completion:(void (^)(NSError *error))completion {
  744 + if (iOS8Later) {
  745 + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  746 + if (@available(iOS 9, *)) {
  747 + PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
  748 + options.shouldMoveFile = YES;
  749 + PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
  750 + [request addResourceWithType:PHAssetResourceTypeVideo fileURL:url options:options];
  751 + if (location) {
  752 + request.location = location;
  753 + }
  754 + request.creationDate = [NSDate date];
  755 + } else {
  756 + PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
  757 + if (location) {
  758 + request.location = location;
  759 + }
  760 + request.creationDate = [NSDate date];
  761 + }
  762 + } completionHandler:^(BOOL success, NSError *error) {
  763 + dispatch_async(dispatch_get_main_queue(), ^{
  764 + if (success && completion) {
  765 + completion(nil);
  766 + } else if (error) {
  767 + NSLog(@"保存视频出错:%@",error.localizedDescription);
  768 + if (completion) {
  769 + completion(error);
  770 + }
  771 + }
  772 + });
  773 + }];
  774 + } else {
  775 + [self.assetLibrary writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) {
  776 + if (error) {
  777 + NSLog(@"保存视频出错:%@",error.localizedDescription);
  778 + if (completion) {
  779 + completion(error);
  780 + }
  781 + } else {
  782 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  783 + if (completion) {
  784 + completion(nil);
  785 + }
  786 + });
  787 + }
  788 + }];
  789 + }
  790 +}
  791 +
  792 +#pragma mark - Get Video
  793 +
  794 +/// Get Video / 获取视频
  795 +- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem *, NSDictionary *))completion {
  796 + [self getVideoWithAsset:asset progressHandler:nil completion:completion];
  797 +}
  798 +
  799 +- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion {
  800 + if ([asset isKindOfClass:[PHAsset class]]) {
  801 + PHVideoRequestOptions *option = [[PHVideoRequestOptions alloc] init];
  802 + option.networkAccessAllowed = YES;
  803 + option.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  804 + dispatch_async(dispatch_get_main_queue(), ^{
  805 + if (progressHandler) {
  806 + progressHandler(progress, error, stop, info);
  807 + }
  808 + });
  809 + };
  810 + [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:option resultHandler:^(AVPlayerItem *playerItem, NSDictionary *info) {
  811 + if (completion) completion(playerItem,info);
  812 + }];
  813 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  814 + ALAsset *alAsset = (ALAsset *)asset;
  815 + ALAssetRepresentation *defaultRepresentation = [alAsset defaultRepresentation];
  816 + NSString *uti = [defaultRepresentation UTI];
  817 + NSURL *videoURL = [[asset valueForProperty:ALAssetPropertyURLs] valueForKey:uti];
  818 + AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:videoURL];
  819 + if (completion && playerItem) completion(playerItem,nil);
  820 + }
  821 +}
  822 +
  823 +#pragma mark - Export video
  824 +
  825 +/// Export Video / 导出视频
  826 +- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
  827 + [self getVideoOutputPathWithAsset:asset presetName:AVAssetExportPreset640x480 success:success failure:failure];
  828 +}
  829 +
  830 +- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
  831 + if ([asset isKindOfClass:[PHAsset class]]) {
  832 + PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
  833 + options.version = PHVideoRequestOptionsVersionOriginal;
  834 + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  835 + options.networkAccessAllowed = YES;
  836 + [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
  837 + // NSLog(@"Info:\n%@",info);
  838 + AVURLAsset *videoAsset = (AVURLAsset*)avasset;
  839 + // NSLog(@"AVAsset URL: %@",myAsset.URL);
  840 + [self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure];
  841 + }];
  842 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  843 + NSURL *videoURL =[asset valueForProperty:ALAssetPropertyAssetURL]; // ALAssetPropertyURLs
  844 + AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
  845 + [self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure];
  846 + }
  847 +}
  848 +
  849 +/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success:
  850 +- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion {
  851 + [self getVideoOutputPathWithAsset:asset success:completion failure:nil];
  852 +}
  853 +
  854 +- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
  855 + // Find compatible presets by video asset.
  856 + NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:videoAsset];
  857 +
  858 + // Begin to compress video
  859 + // Now we just compress to low resolution if it supports
  860 + // If you need to upload to the server, but server does't support to upload by streaming,
  861 + // You can compress the resolution to lower. Or you can support more higher resolution.
  862 + if ([presets containsObject:presetName]) {
  863 + AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:presetName];
  864 +
  865 + NSDateFormatter *formater = [[NSDateFormatter alloc] init];
  866 + [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss-SSS"];
  867 +#pragma mark - TODO: 添加: 原有逻辑-根据会话id取得path(LXG)
  868 + NSString *filaName = [NSString stringWithFormat:@"output-%@_fileType=videoType.mp4",[formater stringFromDate:[NSDate date]]];
  869 +// NSString *outputPath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/output-%@.mp4", [formater stringFromDate:[NSDate date]]];
  870 + NSString *outputPath = @"";
  871 + if (self.conversationId) {
  872 +// outputPath = [[CNTools newChatFilePathByUserId:self.conversationId] stringByAppendingPathComponent:filaName];//聊天
  873 +//
  874 + }
  875 + else
  876 + {
  877 +
  878 +// outputPath = [[CNTools chatFilePathByUserId:[IMAPlatform sharedInstance].host.userId] stringByAppendingString:filaName];//朋友圈
  879 + }
  880 + NSLog(@"video outputPath = %@",outputPath);
  881 +
  882 + session.outputURL = [NSURL fileURLWithPath:outputPath];
  883 +
  884 + // Optimize for network use.
  885 + session.shouldOptimizeForNetworkUse = true;
  886 +
  887 + NSArray *supportedTypeArray = session.supportedFileTypes;
  888 + if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
  889 + session.outputFileType = AVFileTypeMPEG4;
  890 + } else if (supportedTypeArray.count == 0) {
  891 + if (failure) {
  892 + failure(@"该视频类型暂不支持导出", nil);
  893 + }
  894 + NSLog(@"No supported file types 视频类型暂不支持导出");
  895 + return;
  896 + } else {
  897 + session.outputFileType = [supportedTypeArray objectAtIndex:0];
  898 + }
  899 +
  900 + if (![[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"]]) {
  901 + [[NSFileManager defaultManager] createDirectoryAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"] withIntermediateDirectories:YES attributes:nil error:nil];
  902 + }
  903 +
  904 + if ([TZImagePickerConfig sharedInstance].needFixComposition) {
  905 + AVMutableVideoComposition *videoComposition = [self fixedCompositionWithAsset:videoAsset];
  906 + if (videoComposition.renderSize.width) {
  907 + // 修正视频转向
  908 + session.videoComposition = videoComposition;
  909 + }
  910 + }
  911 +
  912 + // Begin to export video to the output path asynchronously.
  913 +#pragma mark - 添加: 原有逻辑-会话id置空(LXG)
  914 + self.conversationId = nil;
  915 + [session exportAsynchronouslyWithCompletionHandler:^(void) {
  916 + dispatch_async(dispatch_get_main_queue(), ^{
  917 +
  918 + switch (session.status) {
  919 + case AVAssetExportSessionStatusUnknown: {
  920 + NSLog(@"AVAssetExportSessionStatusUnknown");
  921 + } break;
  922 + case AVAssetExportSessionStatusWaiting: {
  923 + NSLog(@"AVAssetExportSessionStatusWaiting");
  924 + } break;
  925 + case AVAssetExportSessionStatusExporting: {
  926 + NSLog(@"AVAssetExportSessionStatusExporting");
  927 + } break;
  928 + case AVAssetExportSessionStatusCompleted: {
  929 + NSLog(@"AVAssetExportSessionStatusCompleted");
  930 + if (success) {
  931 + success(outputPath);
  932 + }
  933 + } break;
  934 + case AVAssetExportSessionStatusFailed: {
  935 + NSLog(@"AVAssetExportSessionStatusFailed");
  936 + if (failure) {
  937 + failure(@"视频导出失败", session.error);
  938 + }
  939 + } break;
  940 + case AVAssetExportSessionStatusCancelled: {
  941 + NSLog(@"AVAssetExportSessionStatusCancelled");
  942 + if (failure) {
  943 + failure(@"导出任务已被取消", nil);
  944 + }
  945 + } break;
  946 + default:
  947 + NSLog(@"未知错误");
  948 + break;
  949 + }
  950 + });
  951 + }];
  952 + } else {
  953 + if (failure) {
  954 + NSString *errorMessage = [NSString stringWithFormat:@"当前设备不支持该预设:%@", presetName];
  955 + failure(errorMessage, nil);
  956 + }
  957 + }
  958 +}
  959 +
  960 +/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
  961 +- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset {
  962 + if (iOS8Later) {
  963 + return [assets containsObject:asset];
  964 + } else {
  965 + NSMutableArray *selectedAssetUrls = [NSMutableArray array];
  966 + for (ALAsset *asset_item in assets) {
  967 + [selectedAssetUrls addObject:[asset_item valueForProperty:ALAssetPropertyURLs]];
  968 + }
  969 + return [selectedAssetUrls containsObject:[asset valueForProperty:ALAssetPropertyURLs]];
  970 + }
  971 +}
  972 +
  973 +- (BOOL)isCameraRollAlbum:(id)metadata {
  974 + if ([metadata isKindOfClass:[PHAssetCollection class]]) {
  975 + NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""];
  976 + if (versionStr.length <= 1) {
  977 + versionStr = [versionStr stringByAppendingString:@"00"];
  978 + } else if (versionStr.length <= 2) {
  979 + versionStr = [versionStr stringByAppendingString:@"0"];
  980 + }
  981 + CGFloat version = versionStr.floatValue;
  982 + // 目前已知8.0.0 ~ 8.0.2系统,拍照后的图片会保存在最近添加中
  983 + if (version >= 800 && version <= 802) {
  984 + return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumRecentlyAdded;
  985 + } else {
  986 + return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumUserLibrary;
  987 + }
  988 + }
  989 + if ([metadata isKindOfClass:[ALAssetsGroup class]]) {
  990 + ALAssetsGroup *group = metadata;
  991 + return ([[group valueForProperty:ALAssetsGroupPropertyType] intValue] == ALAssetsGroupSavedPhotos);
  992 + }
  993 +
  994 + return NO;
  995 +}
  996 +
  997 +- (NSString *)getAssetIdentifier:(id)asset {
  998 + if (iOS8Later) {
  999 + PHAsset *phAsset = (PHAsset *)asset;
  1000 + return phAsset.localIdentifier;
  1001 + } else {
  1002 + ALAsset *alAsset = (ALAsset *)asset;
  1003 + NSURL *assetUrl = [alAsset valueForProperty:ALAssetPropertyAssetURL];
  1004 + return assetUrl.absoluteString;
  1005 + }
  1006 +}
  1007 +
  1008 +/// 检查照片大小是否满足最小要求
  1009 +- (BOOL)isPhotoSelectableWithAsset:(id)asset {
  1010 + CGSize photoSize = [self photoSizeWithAsset:asset];
  1011 + if (self.minPhotoWidthSelectable > photoSize.width || self.minPhotoHeightSelectable > photoSize.height) {
  1012 + return NO;
  1013 + }
  1014 + return YES;
  1015 +}
  1016 +
  1017 +- (CGSize)photoSizeWithAsset:(id)asset {
  1018 + if (iOS8Later) {
  1019 + PHAsset *phAsset = (PHAsset *)asset;
  1020 + return CGSizeMake(phAsset.pixelWidth, phAsset.pixelHeight);
  1021 + } else {
  1022 + ALAsset *alAsset = (ALAsset *)asset;
  1023 + return alAsset.defaultRepresentation.dimensions;
  1024 + }
  1025 +}
  1026 +
  1027 +#pragma mark - Private Method
  1028 +
  1029 +- (TZAlbumModel *)modelWithResult:(id)result name:(NSString *)name isCameraRoll:(BOOL)isCameraRoll needFetchAssets:(BOOL)needFetchAssets {
  1030 + TZAlbumModel *model = [[TZAlbumModel alloc] init];
  1031 + [model setResult:result needFetchAssets:needFetchAssets];
  1032 + model.name = name;
  1033 + model.isCameraRoll = isCameraRoll;
  1034 + if ([result isKindOfClass:[PHFetchResult class]]) {
  1035 + PHFetchResult *fetchResult = (PHFetchResult *)result;
  1036 + model.count = fetchResult.count;
  1037 + } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
  1038 + ALAssetsGroup *group = (ALAssetsGroup *)result;
  1039 + model.count = [group numberOfAssets];
  1040 + }
  1041 + return model;
  1042 +}
  1043 +
  1044 +/// 缩放图片至新尺寸
  1045 +- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size {
  1046 + if (image.size.width > size.width) {
  1047 + UIGraphicsBeginImageContext(size);
  1048 + [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
  1049 + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
  1050 + UIGraphicsEndImageContext();
  1051 + return newImage;
  1052 +
  1053 + /* 好像不怎么管用:https://mp.weixin.qq.com/s/CiqMlEIp1Ir2EJSDGgMooQ
  1054 + CGFloat maxPixelSize = MAX(size.width, size.height);
  1055 + CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)UIImageJPEGRepresentation(image, 0.9), nil);
  1056 + NSDictionary *options = @{(__bridge id)kCGImageSourceCreateThumbnailFromImageAlways:(__bridge id)kCFBooleanTrue,
  1057 + (__bridge id)kCGImageSourceThumbnailMaxPixelSize:[NSNumber numberWithFloat:maxPixelSize]
  1058 + };
  1059 + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
  1060 + UIImage *newImage = [UIImage imageWithCGImage:imageRef scale:2 orientation:image.imageOrientation];
  1061 + CGImageRelease(imageRef);
  1062 + CFRelease(sourceRef);
  1063 + return newImage;
  1064 + */
  1065 + } else {
  1066 + return image;
  1067 + }
  1068 +}
  1069 +
  1070 +/// 判断asset是否是视频
  1071 +- (BOOL)isVideo:(id)asset {
  1072 + if (iOS8Later) {
  1073 + PHAsset *phAsset = asset;
  1074 + return phAsset.mediaType == PHAssetMediaTypeVideo;
  1075 + } else {
  1076 + ALAsset *alAsset = asset;
  1077 + NSString *alAssetType = [[alAsset valueForProperty:ALAssetPropertyType] stringValue];
  1078 + return [alAssetType isEqualToString:ALAssetTypeVideo];
  1079 + }
  1080 +}
  1081 +
  1082 +- (ALAssetOrientation)orientationFromImage:(UIImage *)image {
  1083 + NSInteger orientation = image.imageOrientation;
  1084 + return orientation;
  1085 +}
  1086 +
  1087 +/// 获取优化后的视频转向信息
  1088 +- (AVMutableVideoComposition *)fixedCompositionWithAsset:(AVAsset *)videoAsset {
  1089 + AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
  1090 + // 视频转向
  1091 + int degrees = [self degressFromVideoFileWithAsset:videoAsset];
  1092 + if (degrees != 0) {
  1093 + CGAffineTransform translateToCenter;
  1094 + CGAffineTransform mixedTransform;
  1095 + videoComposition.frameDuration = CMTimeMake(1, 30);
  1096 +
  1097 + NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeVideo];
  1098 + AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
  1099 +
  1100 + AVMutableVideoCompositionInstruction *roateInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  1101 + roateInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [videoAsset duration]);
  1102 + AVMutableVideoCompositionLayerInstruction *roateLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
  1103 +
  1104 + if (degrees == 90) {
  1105 + // 顺时针旋转90°
  1106 + translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.height, 0.0);
  1107 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2);
  1108 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
  1109 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1110 + } else if(degrees == 180){
  1111 + // 顺时针旋转180°
  1112 + translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.width, videoTrack.naturalSize.height);
  1113 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI);
  1114 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.width,videoTrack.naturalSize.height);
  1115 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1116 + } else if(degrees == 270){
  1117 + // 顺时针旋转270°
  1118 + translateToCenter = CGAffineTransformMakeTranslation(0.0, videoTrack.naturalSize.width);
  1119 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2*3.0);
  1120 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
  1121 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1122 + }
  1123 +
  1124 + roateInstruction.layerInstructions = @[roateLayerInstruction];
  1125 + // 加入视频方向信息
  1126 + videoComposition.instructions = @[roateInstruction];
  1127 + }
  1128 + return videoComposition;
  1129 +}
  1130 +
  1131 +/// 获取视频角度
  1132 +- (int)degressFromVideoFileWithAsset:(AVAsset *)asset {
  1133 + int degress = 0;
  1134 + NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
  1135 + if([tracks count] > 0) {
  1136 + AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
  1137 + CGAffineTransform t = videoTrack.preferredTransform;
  1138 + if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
  1139 + // Portrait
  1140 + degress = 90;
  1141 + } else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
  1142 + // PortraitUpsideDown
  1143 + degress = 270;
  1144 + } else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
  1145 + // LandscapeRight
  1146 + degress = 0;
  1147 + } else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
  1148 + // LandscapeLeft
  1149 + degress = 180;
  1150 + }
  1151 + }
  1152 + return degress;
  1153 +}
  1154 +
  1155 +/// 修正图片转向
  1156 +- (UIImage *)fixOrientation:(UIImage *)aImage {
  1157 + if (!self.shouldFixOrientation) return aImage;
  1158 +
  1159 + // No-op if the orientation is already correct
  1160 + if (aImage.imageOrientation == UIImageOrientationUp)
  1161 + return aImage;
  1162 +
  1163 + // We need to calculate the proper transformation to make the image upright.
  1164 + // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
  1165 + CGAffineTransform transform = CGAffineTransformIdentity;
  1166 +
  1167 + switch (aImage.imageOrientation) {
  1168 + case UIImageOrientationDown:
  1169 + case UIImageOrientationDownMirrored:
  1170 + transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
  1171 + transform = CGAffineTransformRotate(transform, M_PI);
  1172 + break;
  1173 +
  1174 + case UIImageOrientationLeft:
  1175 + case UIImageOrientationLeftMirrored:
  1176 + transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
  1177 + transform = CGAffineTransformRotate(transform, M_PI_2);
  1178 + break;
  1179 +
  1180 + case UIImageOrientationRight:
  1181 + case UIImageOrientationRightMirrored:
  1182 + transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
  1183 + transform = CGAffineTransformRotate(transform, -M_PI_2);
  1184 + break;
  1185 + default:
  1186 + break;
  1187 + }
  1188 +
  1189 + switch (aImage.imageOrientation) {
  1190 + case UIImageOrientationUpMirrored:
  1191 + case UIImageOrientationDownMirrored:
  1192 + transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
  1193 + transform = CGAffineTransformScale(transform, -1, 1);
  1194 + break;
  1195 +
  1196 + case UIImageOrientationLeftMirrored:
  1197 + case UIImageOrientationRightMirrored:
  1198 + transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
  1199 + transform = CGAffineTransformScale(transform, -1, 1);
  1200 + break;
  1201 + default:
  1202 + break;
  1203 + }
  1204 +
  1205 + // Now we draw the underlying CGImage into a new context, applying the transform
  1206 + // calculated above.
  1207 + CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
  1208 + CGImageGetBitsPerComponent(aImage.CGImage), 0,
  1209 + CGImageGetColorSpace(aImage.CGImage),
  1210 + CGImageGetBitmapInfo(aImage.CGImage));
  1211 + CGContextConcatCTM(ctx, transform);
  1212 + switch (aImage.imageOrientation) {
  1213 + case UIImageOrientationLeft:
  1214 + case UIImageOrientationLeftMirrored:
  1215 + case UIImageOrientationRight:
  1216 + case UIImageOrientationRightMirrored:
  1217 + // Grr...
  1218 + CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
  1219 + break;
  1220 +
  1221 + default:
  1222 + CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
  1223 + break;
  1224 + }
  1225 +
  1226 + // And now we just create a new UIImage from the drawing context
  1227 + CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
  1228 + UIImage *img = [UIImage imageWithCGImage:cgimg];
  1229 + CGContextRelease(ctx);
  1230 + CGImageRelease(cgimg);
  1231 + return img;
  1232 +}
  1233 +
  1234 +#pragma clang diagnostic pop
  1235 +
  1236 +@end
  1237 +
  1238 +
  1239 +//@implementation TZSortDescriptor
  1240 +//
  1241 +//- (id)reversedSortDescriptor {
  1242 +// return [NSNumber numberWithBool:![TZImageManager manager].sortAscendingByModificationDate];
  1243 +//}
  1244 +//
  1245 +//@end
CNLiveImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png 0 → 100755

3.56 KB

CNLiveImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png 0 → 100755

3.56 KB

CNLiveImagePickerController/TZImagePickerController.bundle/Root.plist 0 → 100755
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>StringsTable</key>
  6 + <string>Root</string>
  7 + <key>PreferenceSpecifiers</key>
  8 + <array>
  9 + <dict>
  10 + <key>Type</key>
  11 + <string>PSGroupSpecifier</string>
  12 + <key>Title</key>
  13 + <string>Group</string>
  14 + </dict>
  15 + <dict>
  16 + <key>Type</key>
  17 + <string>PSTextFieldSpecifier</string>
  18 + <key>Title</key>
  19 + <string>Name</string>
  20 + <key>Key</key>
  21 + <string>name_preference</string>
  22 + <key>DefaultValue</key>
  23 + <string></string>
  24 + <key>IsSecure</key>
  25 + <false/>
  26 + <key>KeyboardType</key>
  27 + <string>Alphabet</string>
  28 + <key>AutocapitalizationType</key>
  29 + <string>None</string>
  30 + <key>AutocorrectionType</key>
  31 + <string>No</string>
  32 + </dict>
  33 + <dict>
  34 + <key>Type</key>
  35 + <string>PSToggleSwitchSpecifier</string>
  36 + <key>Title</key>
  37 + <string>Enabled</string>
  38 + <key>Key</key>
  39 + <string>enabled_preference</string>
  40 + <key>DefaultValue</key>
  41 + <true/>
  42 + </dict>
  43 + <dict>
  44 + <key>Type</key>
  45 + <string>PSSliderSpecifier</string>
  46 + <key>Key</key>
  47 + <string>slider_preference</string>
  48 + <key>DefaultValue</key>
  49 + <real>0.5</real>
  50 + <key>MinimumValue</key>
  51 + <integer>0</integer>
  52 + <key>MaximumValue</key>
  53 + <integer>1</integer>
  54 + <key>MinimumValueImage</key>
  55 + <string></string>
  56 + <key>MaximumValueImage</key>
  57 + <string></string>
  58 + </dict>
  59 + </array>
  60 +</dict>
  61 +</plist>
CNLiveImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png 0 → 100755

223 Bytes

CNLiveImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings 0 → 100755
1 Binary files /dev/null and b/CNLiveImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings differ 1 Binary files /dev/null and b/CNLiveImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings differ
CNLiveImagePickerController/TZImagePickerController.bundle/fb_quxiao@2x.png 0 → 100755

1.16 KB

CNLiveImagePickerController/TZImagePickerController.bundle/navi_back@2x.png 0 → 100755

116 Bytes

CNLiveImagePickerController/TZImagePickerController.bundle/ph_select@2x.png 0 → 100755

1.31 KB

CNLiveImagePickerController/TZImagePickerController.bundle/ph_unselect@2x.png 0 → 100755

902 Bytes

CNLiveImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png 0 → 100755

1.13 KB

CNLiveImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png 0 → 100755

1.13 KB

CNLiveImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png 0 → 100755

501 Bytes

CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png 0 → 100755

1.56 KB

CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png 0 → 100755

620 Bytes

CNLiveImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png 0 → 100755

1006 Bytes

CNLiveImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png 0 → 100755

1.16 KB

CNLiveImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png 0 → 100755

501 Bytes

CNLiveImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png 0 → 100755

392 Bytes

CNLiveImagePickerController/TZImagePickerController.bundle/takePicture80@2x.png 0 → 100755

1.25 KB

CNLiveImagePickerController/TZImagePickerController.bundle/takePicture@2x.png 0 → 100755

2.98 KB

CNLiveImagePickerController/TZImagePickerController.bundle/upload_selection1@2x.png 0 → 100755

1.35 KB

CNLiveImagePickerController/TZImagePickerController.bundle/vi.lproj/Localizable.strings 0 → 100755
  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";
CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings 0 → 100755
1 Binary files /dev/null and b/CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings differ 1 Binary files /dev/null and b/CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings differ
CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings 0 → 100755
1 Binary files /dev/null and b/CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings differ 1 Binary files /dev/null and b/CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings differ