From 8e680a1593ca22c8d3fb8a79180f06df4c4ca681 Mon Sep 17 00:00:00 2001 From: 单军华 <WindShan@danjunhuas-MacBook-Pro.local> Date: Wed, 22 Feb 2017 16:07:22 +0800 Subject: [PATCH] 相册拍照图片分享demo --- ios_share/SDWebImage/SDWebImageDecoder.h | 0 camerademo/camerademo/demo/UIImage/UIImage+GIF.m | 158 camerademo/camerademo/demo/UIImage/UIImage+Vector.m | 140 camerademo/camerademo/demo/UIImage/UIImage+FX.m | 426 + ios_share/SDWebImage/SDWebImageDecoder.m | 0 ios_share/test/Base.lproj/LaunchScreen.storyboard | 0 ios_share/SDWebImage/SDWebImageDownloader.m | 0 camerademo/camerademo/demo/UIImage/UIImage+Vector.h | 65 camerademo/camerademo/demo/UIImage/UIImage+FX.h | 56 TZImagePickerController/TZImagePickerController/ScreenShots/photoPreviewVc.PNG | 0 camerademo/camerademo/demo/UIImage/UIImage+GIF.h | 0 camerademo/camerademo/Info.plist | 38 TZImagePickerController/TZImagePickerController/Assets.xcassets/AlbumAddBtn.imageset/AlbumAddBtn@2x.png | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings | 0 JHChart/JHChartDemo/JHChart/JHLineChart.m | 4 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/Root.plist | 61 camerademo/camerademo/demo/UIImage/UIImage+Resize.h | 21 camerademo/camerademo/demo/UIImage/UIImage+Resize.m | 200 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.h | 214 camerademo/camerademo/demo/UIImage/UIImage+Capture.m | 105 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.m | 616 ++ JHChart/JHChartDemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist | 36 camerademo/camerademo/demo/UIImage/UIImage+Capture.h | 35 ios_share/test/AppDelegate.m | 0 camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.h | 32 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.m | 792 +++ ios_share/test/AppDelegate.h | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.h | 25 camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.m | 114 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png | 0 ios_share/test/2.jpg | 0 ios_share/SDWebImage/SDWebImageDownloader.h | 0 JHChart/JHChartDemo/JHShowController.m | 36 TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.m | 44 camerademo/camerademo/demo/Model/MPImageItemModel.h | 46 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.h | 17 camerademo/camerademo/demo/Model/MPImageItemModel.m | 100 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.h | 15 TZImagePickerController/TZImagePickerController/ScreenShots/photoPickerVc.PNG | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png | 0 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.m | 107 camerademo/camerademo/demo/UIImage/UIImage+Orientation.h | 69 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.h | 39 TZImagePickerController/TZImagePickerController/Base.lproj/LaunchScreen.storyboard | 18 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png | 0 camerademo/camerademo/Assets.xcassets/AppIcon.appiconset/Contents.json | 0 camerademo/camerademo/demo/UIImage/UIImage+Orientation.m | 181 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.m | 194 ios_share/SDWebImage/SDWebImageManager.m | 0 ios_share/SDWebImage/SDWebImageManager.h | 0 camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.h | 10 TZImagePickerController/TZImagePickerController/ScreenShots/videoPlayerVc.PNG | 0 camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.m | 79 camerademo/camerademo/demo/OtherHelper/dateTimeHelper.m | 24 ios_share/test/Assets.xcassets/AppIcon.appiconset/Contents.json | 0 camerademo/camerademo/demo/OtherHelper/dateTimeHelper.h | 16 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.m | 143 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.h | 16 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.h | 17 ios_share/test/6.jpg | 0 camerademo/camerademo/demo/UIImage/UIImage+Blur.h | 24 ios_share/test.xcodeproj/project.pbxproj | 11 camerademo/camerademo/demo/UIImage/UIImage+Blur.m | 281 + TZImagePickerController/TZImagePickerController.xcodeproj/project.pbxproj | 658 ++ camerademo/camerademo/Base.lproj/LaunchScreen.storyboard | 27 TZImagePickerController/.gitignore | 28 TZImagePickerController/TZImagePickerController/TZImagePickerController/UIView+Layout.h | 30 ios_share/SDWebImage/UIImageView+WebCache.m | 0 ios_share/SDWebImage/SDWebImageDownloaderOperation.h | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m | 170 TZImagePickerController/TZImagePickerController/TZImagePickerController/UIView+Layout.m | 125 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.h | 16 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m | 127 ios_share/testUITests/Info.plist | 0 ios_share/SDWebImage/UIImage+GIF.h | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png | 0 ios_share/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/xcschememanagement.plist | 0 camerademo/camerademo/AppDelegate.h | 17 ios_share/test/Info.plist | 0 camerademo/camerademo/AppDelegate.m | 51 ios_share/SDWebImage/UIImage+GIF.m | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.h | 15 ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/test.xcscheme | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.m | 55 TZImagePickerController/TZImagePickerController/main.m | 16 ios_share/SDWebImage/UIImageView+WebCache.h | 0 ios_share/SDWebImage/SDWebImageDownloaderOperation.m | 0 camerademo/camerademo/demo/OtherHelper/cameraHelper.h | 23 ios_share/SDWebImage/UIButton+WebCache.m | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/takePicture@2x.png | 0 ios_share/test.xcodeproj/project.xcworkspace/contents.xcworkspacedata | 0 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.m | 53 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.m | 344 + camerademo/camerademo/demo/OtherHelper/cameraHelper.m | 50 ios_share/SDWebImage/UIButton+WebCache.h | 0 ios_share/test/3.jpg | 0 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.h | 39 TZImagePickerController/LICENSE | 22 ios_share/SDWebImage/SDWebImageCompat.m | 0 TZImagePickerController/TZImagePickerController/AppDelegate.m | 42 TZImagePickerController/TZImagePickerController/AppDelegate.h | 17 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/TableViewArrow@2x.png | 0 ios_share/SDWebImage/SDWebImageCompat.h | 0 ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist | 0 camerademo/camerademo/demo/UIImage/UIImage+FileName.h | 21 TZImagePickerController/TZImagePickerController/Info.plist | 47 camerademo/camerademo/demo/UIImage/UIImage+FileName.m | 57 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.h | 96 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.m | 940 ++++ TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png | 0 camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.m | 270 + camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.h | 29 ios_share/SDWebImage/SDImageCache.h | 0 JHChart/JHChartDemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate | 0 TZImagePickerController/TZImagePickerController/TZTestCell.m | 104 camerademo/camerademo/demo/MPUploadImageHelper.m | 82 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.h | 13 TZImagePickerController/TZImagePickerController/LxGridViewFlowLayout.h | 57 TZImagePickerController/TZImagePickerController/TZTestCell.h | 23 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.m | 47 camerademo/camerademo/demo/MPUploadImageHelper.h | 34 TZImagePickerController/TZImagePickerController/LxGridViewFlowLayout.m | 408 + camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.h | 13 ios_share/SDWebImage/SDImageCache.m | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.m | 433 + ios_share/test.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.h | 25 camerademo/camerademo/demo/MPUploadImagesViewController.m | 231 camerademo/camerademo/demo/UIImage/UIImage+Color.m | 175 ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/bin.shen.xcuserdatad/UserInterfaceState.xcuserstate | 0 camerademo/camerademo/demo/UIImage/UIImage+Color.h | 53 ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/mb985.xcuserdatad/UserInterfaceState.xcuserstate | 0 ios_share/test/7.jpg | 0 camerademo/camerademo/demo/MPUploadImagesViewController.h | 14 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png | 0 camerademo/camerademo/demo/UIImage/UIImage+Alpha.m | 234 + camerademo/camerademo/demo/UIImage/UIImage+Alpha.h | 40 TZImagePickerController/TZImagePickerController.xcodeproj/project.xcworkspace/contents.xcworkspacedata | 7 TZImagePickerController/TZImagePickerController/zh-Hans.lproj/Main.strings | 18 TZImagePickerController/TZImagePickerController/Assets.xcassets/AlbumAddBtn.imageset/Contents.json | 21 camerademo/camerademo/main.m | 16 TZImagePickerController/TZImagePickerControllerUITests/TZImagePickerControllerUITests.m | 40 camerademo/camerademo/demo/UIImage/UIImage+PDF.h | 13 camerademo/camerademo/demo/OtherHelper/imageCompressHelper.m | 163 camerademo/camerademo/demo/OtherHelper/imageCompressHelper.h | 42 camerademo/camerademo/Base.lproj/Main.storyboard | 9 ios_share/test/main.m | 0 camerademo/camerademo/demo/UIImage/UIImage+PDF.m | 13 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.m | 30 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.h | 15 camerademo/camerademo.xcodeproj/project.xcworkspace/contents.xcworkspacedata | 7 TZImagePickerController/TZImagePickerControllerTests/Info.plist | 0 ios_share/SDWebImage/MKAnnotationView+WebCache.h | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.m | 259 + ios_share/SDWebImage/MKAnnotationView+WebCache.m | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.h | 43 camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.h | 47 ios_share/test/4.jpg | 0 camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.m | 405 + camerademo/camerademo.xcodeproj/project.pbxproj | 317 + camerademo/camerademo/demo/OtherHelper/UITapImageView.h | 17 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.h | 53 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/navi_back@2x.png | 0 camerademo/camerademo/demo/OtherHelper/UITapImageView.m | 53 ios_share/test.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/test.xcscheme | 101 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png | 0 TZImagePickerController/TZImagePickerController.podspec | 14 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.m | 349 + ios_share/SDWebImage/UIImageView+HighlightedWebCache.h | 0 ios_share/SDWebImage/SDWebImageOperation.h | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png | 0 ios_share/SDWebImage/UIImageView+HighlightedWebCache.m | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png | 0 TZImagePickerController/TZImagePickerController/zh-Hans.lproj/LaunchScreen.strings | 1 TZImagePickerController/README.md | 70 TZImagePickerController/TZImagePickerController/Assets.xcassets/AppIcon.appiconset/Contents.json | 48 camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist | 22 ios_share/SDWebImage/UIView+WebCacheOperation.m | 0 ios_share/SDWebImage/UIView+WebCacheOperation.h | 0 camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.strings | 18 camerademo/camerademo/demo/UIImage/UIImage+BetterFace.h | 23 camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.h | 16 TZImagePickerController/TZImagePickerController/Assets.xcassets/Contents.json | 6 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png | 0 camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.m | 76 ios_share/SDWebImage/UIImage+MultiFormat.m | 0 camerademo/camerademo/demo/FileManager/MPFileManager.m | 133 ios_share/SDWebImage/UIImage+MultiFormat.h | 0 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings | 0 camerademo/camerademo/demo/UIImage/UIImage+BetterFace.m | 111 ios_share/test/Base.lproj/Main.storyboard | 30 ios_share/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/test.xcscheme | 0 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.m | 48 ios_share/test/ViewController.h | 0 ios_share/test/ViewController.m | 0 camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.h | 15 ios_share/test/1.jpg | 0 ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate | 0 TZImagePickerController/TZImagePickerControllerUITests/Info.plist | 0 TZImagePickerController/TZImagePickerController/Assets.xcassets/photo_delete.imageset/photo_delete@2x.png | 0 ios_share/SDWebImage/NSData+ImageContentType.h | 0 ios_share/testUITests/testUITests.m | 0 ios_share/SDWebImage/NSData+ImageContentType.m | 0 ios_share/SDWebImage/UIImage+WebP.m | 0 camerademo/camerademo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate | 0 ios_share/SDWebImage/SDWebImagePrefetcher.m | 0 ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/xcschememanagement.plist | 0 camerademo/camerademo/demo/UIImage/UIImage+Merge.h | 21 camerademo/camerademo/demo/FileManager/MPFileManager.h | 31 camerademo/camerademo/ViewController.m | 29 camerademo/camerademo/demo/UIImage/UIImage+Merge.m | 35 camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.h | 16 TZImagePickerController/TZImagePickerController/ViewController.m | 600 ++ camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/camerademo.xcscheme | 46 camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.m | 112 ios_share/SDWebImage/SDWebImagePrefetcher.h | 0 ios_share/SDWebImage/UIImage+WebP.h | 0 TZImagePickerController/TZImagePickerController/ViewController.h | 15 ios_share/test/5.jpg | 0 camerademo/camerademo/ViewController.h | 15 TZImagePickerController/TZImagePickerController/Assets.xcassets/photo_delete.imageset/Contents.json | 21 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.m | 66 TZImagePickerController/TZImagePickerControllerTests/TZImagePickerControllerTests.m | 39 TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.h | 46 TZImagePickerController/TZImagePickerController/Base.lproj/Main.storyboard | 279 + 227 files changed, 13,987 insertions(+), 49 deletions(-) diff --git a/JHChart/JHChartDemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate b/JHChart/JHChartDemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate index 2e019bf..11cd5c1 100644 --- a/JHChart/JHChartDemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate +++ b/JHChart/JHChartDemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate Binary files differ diff --git a/JHChart/JHChartDemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JHChart/JHChartDemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 85e0ba4..aa3e7a3 100644 --- a/JHChart/JHChartDemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/JHChart/JHChartDemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -10,11 +10,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "JHChartDemo/JHShowController.m" - timestampString = "503827514.562585" + timestampString = "508733656.451317" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "152" - endingLineNumber = "152" + startingLineNumber = "156" + endingLineNumber = "156" landmarkName = "-showFirstAndSecondQuardrant" landmarkType = "7"> </BreakpointContent> @@ -26,11 +26,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "JHChartDemo/JHShowController.m" - timestampString = "503827531.262425" + timestampString = "508733656.451317" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "161" - endingLineNumber = "161" + startingLineNumber = "165" + endingLineNumber = "165" landmarkName = "-showFirstAndFouthQuardrant" landmarkType = "7"> </BreakpointContent> @@ -42,11 +42,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "JHChartDemo/JHShowController.m" - timestampString = "503827531.968218" + timestampString = "508733656.451317" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "160" - endingLineNumber = "160" + startingLineNumber = "164" + endingLineNumber = "164" landmarkName = "-showFirstAndFouthQuardrant" landmarkType = "7"> </BreakpointContent> @@ -58,11 +58,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "JHChartDemo/JHShowController.m" - timestampString = "503827553.141509" + timestampString = "508733656.451317" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "117" - endingLineNumber = "117" + startingLineNumber = "121" + endingLineNumber = "121" landmarkName = "-showFirstAndSecondQuardrant" landmarkType = "7"> </BreakpointContent> @@ -74,11 +74,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "JHChartDemo/JHShowController.m" - timestampString = "503827636.711069" + timestampString = "508733656.451317" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "122" - endingLineNumber = "122" + startingLineNumber = "126" + endingLineNumber = "126" landmarkName = "-showFirstAndSecondQuardrant" landmarkType = "7"> </BreakpointContent> @@ -106,11 +106,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "JHChartDemo/JHShowController.m" - timestampString = "503827918.828834" + timestampString = "508733656.451317" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "121" - endingLineNumber = "121" + startingLineNumber = "125" + endingLineNumber = "125" landmarkName = "-showFirstAndSecondQuardrant" landmarkType = "7"> </BreakpointContent> diff --git a/JHChart/JHChartDemo/JHChart/JHLineChart.m b/JHChart/JHChartDemo/JHChart/JHLineChart.m index 1cb3d16..7d88e41 100755 --- a/JHChart/JHChartDemo/JHChart/JHLineChart.m +++ b/JHChart/JHChartDemo/JHChart/JHLineChart.m @@ -40,7 +40,7 @@ if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor colorWithRed:0.2 green:0.7 blue:0.2 alpha:0.3]; _lineType = lineChartType; - _lineWidth = 0.5; + _lineWidth = 5; // ������������ self.contentInsets = UIEdgeInsetsMake(10, 20, 10, 10); _yLineDataArr = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7"]; _xLineDataArr = @[@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7"]; @@ -891,7 +891,7 @@ UIColor *color = (_valueLineColorArr.count==_drawDataArr.count?(_valueLineColorArr[colorIndex]):([UIColor orangeColor])); shapeLayer.strokeColor = color.CGColor; shapeLayer.fillColor = [UIColor clearColor].CGColor; - shapeLayer.lineWidth = (_animationPathWidth<=0?2:_animationPathWidth); + shapeLayer.lineWidth = [self lineWidth];// (_animationPathWidth<=0?5:_animationPathWidth); //��������������� diff --git a/JHChart/JHChartDemo/JHShowController.m b/JHChart/JHChartDemo/JHShowController.m index 62ef732..44275ce 100755 --- a/JHChart/JHChartDemo/JHShowController.m +++ b/JHChart/JHChartDemo/JHShowController.m @@ -80,31 +80,35 @@ /* The scale value of the X axis can be passed into the NSString or NSNumber type and the data structure changes with the change of the line chart type. The details look at the document or other quadrant X axis data source sample.*/ - lineChart.xLineDataArr = @[@"0",@"1",@"2",@3,@4,@5,@6,@7]; + lineChart.xLineDataArr = @[@"10",@"11",@"12",@13,@14,@15,@16,@17]; /* The different types of the broken line chart, according to the quadrant division, different quadrant correspond to different X axis scale data source and different value data source. */ lineChart.lineChartQuadrantType = JHLineChartQuadrantTypeFirstQuardrant; - lineChart.valueArr = @[@[@"1",@"12",@"1",@6,@4,@9,@6,@7],@[@"3",@"1",@"2",@16,@2,@3,@5,@10]]; -// lineChart.showYLevelLine = YES; + lineChart.lineWidth = 3.0; + + lineChart.valueArr = @[@[@"11",@"112",@"11",@16,@14,@19,@16,@17]]; + /* ������������������������������*/ + //lineChart.showYLevelLine = YES; + /* * whether this chart shows leading lines for value point or not,default is YES ������������������������������*/ lineChart.showValueLeadingLine = NO; - /* Line Chart colors */ - lineChart.valueLineColorArr =@[ [UIColor purpleColor], [UIColor brownColor]]; - /* Colors for every line chart*/ - lineChart.pointColorArr = @[[UIColor orangeColor],[UIColor yellowColor]]; - /* color for XY axis */ - lineChart.xAndYLineColor = [UIColor blackColor]; - /* XY axis scale color */ - lineChart.xAndYNumberColor = [UIColor blueColor]; + /* Line Chart colors ������������ */ + lineChart.valueLineColorArr =@[[UIColor redColor]]; + /* Colors for every line chart ������������������*/ + lineChart.pointColorArr = @[[UIColor whiteColor]]; + /* color for XY axis XY������������������*/ + lineChart.xAndYLineColor = [UIColor whiteColor]; + /* XY axis scale color XY������������������������*/ + lineChart.xAndYNumberColor = [UIColor whiteColor]; /* Dotted line color of the coordinate point */ - lineChart.positionLineColorArr = @[[UIColor blueColor],[UIColor greenColor]]; - /* Set whether to fill the content, the default is False */ - lineChart.contentFill = YES; + lineChart.positionLineColorArr = @[[UIColor whiteColor]]; + /* Set whether to fill the content, the default is False ������������������������������ */ + lineChart.contentFill = NO; /* Set whether the curve path */ lineChart.pathCurve = YES; - /* Set fill color array */ - lineChart.contentFillColorArr = @[[UIColor colorWithRed:0.500 green:0.000 blue:0.500 alpha:0.468],[UIColor colorWithRed:0.500 green:0.214 blue:0.098 alpha:0.468]]; + /* Set fill color array ��������������������������������� */ + lineChart.contentFillColorArr = @[[UIColor whiteColor]]; [self.view addSubview:lineChart]; /* Start animation */ [lineChart showAnimation]; diff --git a/TZImagePickerController/.gitignore b/TZImagePickerController/.gitignore new file mode 100755 index 0000000..754e6b7 --- /dev/null +++ b/TZImagePickerController/.gitignore @@ -0,0 +1,28 @@ +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control +# +#Pods/ + +.DS_Store diff --git a/TZImagePickerController/LICENSE b/TZImagePickerController/LICENSE new file mode 100755 index 0000000..d2a8818 --- /dev/null +++ b/TZImagePickerController/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 Zhen Tan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/TZImagePickerController/README.md b/TZImagePickerController/README.md new file mode 100755 index 0000000..eab84f9 --- /dev/null +++ b/TZImagePickerController/README.md @@ -0,0 +1,70 @@ +# TZImagePickerController + A clone of UIImagePickerController, support picking multiple photos���original photo���video, also allow preview photo and video, fitting iOS6789 system. + ���������������������������������������������������������������������������������������������iOS6789��������� + + ������������iOS10���Xcdoe8���������: + ���Xcode8���������������������������iOS10���������/������������������������������������������������������info.plist������������������Privacy - Photo Library Usage Description���Privacy - Camera Usage Description���������������Demo���info.plist��������������� + + 1. ������������������1.6.5. ������������������������bug������������������������������������������������������������������������������������������������������������������������������ + 2. ������������pod search TZImagePickerController ���������������������������������������������������������cd���������������������������������Desktop���������������pod setup������������������spec���������������������������������,���������������������������. + 3. ���������������bug������������issue������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������~ + +  +  +  + +## ���. Installation ������ + + * CocoaPods���pod 'TZImagePickerController' + * ������������������TZImagePickerController���������������������������������������������#import "TZImagePickerController.h" + +## ���. Example ������ + + TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:self]; + + // You can get the photos by block, the same as by delegate. + // ���������������block���������������������������������������������. + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets) { + + }]; + [self presentViewController:imagePickerVc animated:YES completion:nil]; + +## ���. Requirements ������ + iOS 6 or later. Requires ARC + iOS6������������������������. ARC������. + + When system version is iOS6 or iOS7, Using AssetsLibrary. + When system version is iOS 8 or later, Using PhotoKit. + ���������������iOS6���7���������������������AssetsLibrary������������������������ + ���������������iOS8������������������������������PhotoKit������������������������ + +## ���. More ������ + + If you find a bug, please create a issue. + Welcome to pull requests. + More infomation please view code. + ������������������bug���������������issue��� + ���������������pull requests��� + ���������������������������������������������������: [������������](http://www.cnblogs.com/tanzhenblog/ "��������� - ���������") + + +2016.5.23��������� +������������������������������������������������1.4.5������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Demo������������������������������������������������������������������������������������������������������������������������������������������bug������������������������ + +������������������������1.4.5������������������������������������������iOS9.3.2������6s������������870������������������������������������58���������������������������������iOS7.0.4���4s���������(124���������)������������������������57���������������������������������������������QQ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Core Animation������������������������������������������������6s������������������������52������������������������������50������4s���������������������������������������������������������������������������������������������~���������������������������������~��� + +tip: ������������������������������������������������������������������������������iOS7������6������������������������������iOS7���6���������������������... + +2016.6.22������: +������������������������������������������������1.5.0������������������ +1.���������������������������������,������������������������sheet������������������������������������ +2.���������sortAscendingByModificationDate������������������YES������������NO��������������������������������������������������������������������� +3.���������Demo���������UI���������6��������������������������������������������������������������������� +4.���������������bug��� + +������������: +1.7.7 ������GIF������������������������ +1.7.6 ��������������������������������������������� +1.7.5 ��������������������������������������������� +1.7.4 ������������������������������������������������������������������������ +1.7.3 ������iCloud������������������������ diff --git a/TZImagePickerController/TZImagePickerController.podspec b/TZImagePickerController/TZImagePickerController.podspec new file mode 100755 index 0000000..4a9f269 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController.podspec @@ -0,0 +1,14 @@ +Pod::Spec.new do |s| + s.name = "TZImagePickerController" + s.version = "1.7.8" + s.summary = "A clone of UIImagePickerController, support picking multiple photos���original photo and video" + s.homepage = "https://github.com/banchichen/TZImagePickerController" + s.license = "MIT" + s.author = { "banchichen" => "tanzhenios@foxmail.com" } + s.platform = :ios + s.ios.deployment_target = "6.0" + s.source = { :git => "https://github.com/banchichen/TZImagePickerController.git", :tag => "1.7.8" } + s.requires_arc = true + s.resources = "TZImagePickerController/TZImagePickerController/*.{png,xib,nib,bundle}" + s.source_files = "TZImagePickerController/TZImagePickerController/*.{h,m}" +end diff --git a/TZImagePickerController/TZImagePickerController.xcodeproj/project.pbxproj b/TZImagePickerController/TZImagePickerController.xcodeproj/project.pbxproj new file mode 100755 index 0000000..bd55e54 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController.xcodeproj/project.pbxproj @@ -0,0 +1,658 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 6D32B9BD1CD83640005CE1E0 /* LxGridViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D32B9BC1CD83640005CE1E0 /* LxGridViewFlowLayout.m */; }; + 6D4608311DFFC60D004FB009 /* TZGifPhotoPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D4608301DFFC60D004FB009 /* TZGifPhotoPreviewController.m */; }; + 6D5358CD1D64600F00928CC6 /* NSBundle+TZImagePicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D5358CC1D64600F00928CC6 /* NSBundle+TZImagePicker.m */; }; + 6DC358661CC8BAFD00898D29 /* TZImagePickerController.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6DC358651CC8BAFD00898D29 /* TZImagePickerController.bundle */; }; + 6DC84D0A1DF5358500A107A9 /* TZImageCropManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DC84D091DF5358500A107A9 /* TZImageCropManager.m */; }; + 6DD0502B1DF659ED0057C78D /* TZProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6DD0502A1DF659ED0057C78D /* TZProgressView.m */; }; + 900E65811C2BB8D5003D9A9E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65801C2BB8D5003D9A9E /* main.m */; }; + 900E65841C2BB8D5003D9A9E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65831C2BB8D5003D9A9E /* AppDelegate.m */; }; + 900E65871C2BB8D5003D9A9E /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65861C2BB8D5003D9A9E /* ViewController.m */; }; + 900E658A1C2BB8D5003D9A9E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 900E65881C2BB8D5003D9A9E /* Main.storyboard */; }; + 900E658C1C2BB8D5003D9A9E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 900E658B1C2BB8D5003D9A9E /* Assets.xcassets */; }; + 900E658F1C2BB8D5003D9A9E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 900E658D1C2BB8D5003D9A9E /* LaunchScreen.storyboard */; }; + 900E659A1C2BB8D5003D9A9E /* TZImagePickerControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65991C2BB8D5003D9A9E /* TZImagePickerControllerTests.m */; }; + 900E65A51C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65A41C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m */; }; + 900EEFF81C2BBF9500EA709B /* TZImagePickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EEFF71C2BBF9500EA709B /* TZImagePickerController.m */; }; + 900EEFFE1C2BD58B00EA709B /* TZPhotoPickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EEFFD1C2BD58B00EA709B /* TZPhotoPickerController.m */; }; + 900EF0021C2BD7E400EA709B /* TZAssetCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EF0001C2BD7E400EA709B /* TZAssetCell.m */; }; + 900EF00F1C2C0B1100EA709B /* TZAssetModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EF00E1C2C0B1100EA709B /* TZAssetModel.m */; }; + 900EF0121C2C107400EA709B /* TZPhotoPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EF0111C2C107400EA709B /* TZPhotoPreviewController.m */; }; + 900EF0161C2C134900EA709B /* TZPhotoPreviewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EF0141C2C134900EA709B /* TZPhotoPreviewCell.m */; }; + 9038D5911C3974F0007DE549 /* TZTestCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9038D5901C3974F0007DE549 /* TZTestCell.m */; }; + 90CE84AE1C3A89EF003D0779 /* TZImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 90CE84AD1C3A89EF003D0779 /* TZImageManager.m */; }; + 90CE84B71C3BABB6003D0779 /* TZVideoPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */; }; + 90EBF5D61C2E298000CB9BCC /* UIView+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 90EBF5D51C2E298000CB9BCC /* UIView+Layout.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 900E65961C2BB8D5003D9A9E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 900E65741C2BB8D5003D9A9E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 900E657B1C2BB8D5003D9A9E; + remoteInfo = TZImagePickerController; + }; + 900E65A11C2BB8D5003D9A9E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 900E65741C2BB8D5003D9A9E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 900E657B1C2BB8D5003D9A9E; + remoteInfo = TZImagePickerController; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 6D12FC191D66B71E00182C44 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Main.strings"; sourceTree = "<group>"; }; + 6D12FC1A1D66B71E00182C44 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/LaunchScreen.strings"; sourceTree = "<group>"; }; + 6D32B9BB1CD83640005CE1E0 /* LxGridViewFlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LxGridViewFlowLayout.h; sourceTree = "<group>"; }; + 6D32B9BC1CD83640005CE1E0 /* LxGridViewFlowLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LxGridViewFlowLayout.m; sourceTree = "<group>"; }; + 6D46082F1DFFC60D004FB009 /* TZGifPhotoPreviewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZGifPhotoPreviewController.h; sourceTree = "<group>"; }; + 6D4608301DFFC60D004FB009 /* TZGifPhotoPreviewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZGifPhotoPreviewController.m; sourceTree = "<group>"; }; + 6D5358CB1D64600F00928CC6 /* NSBundle+TZImagePicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+TZImagePicker.h"; sourceTree = "<group>"; }; + 6D5358CC1D64600F00928CC6 /* NSBundle+TZImagePicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+TZImagePicker.m"; sourceTree = "<group>"; }; + 6DC358651CC8BAFD00898D29 /* TZImagePickerController.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TZImagePickerController.bundle; sourceTree = "<group>"; }; + 6DC84D081DF5358500A107A9 /* TZImageCropManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageCropManager.h; sourceTree = "<group>"; }; + 6DC84D091DF5358500A107A9 /* TZImageCropManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageCropManager.m; sourceTree = "<group>"; }; + 6DD050291DF659ED0057C78D /* TZProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZProgressView.h; sourceTree = "<group>"; }; + 6DD0502A1DF659ED0057C78D /* TZProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZProgressView.m; sourceTree = "<group>"; }; + 900E657C1C2BB8D5003D9A9E /* TZImagePickerController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TZImagePickerController.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 900E65801C2BB8D5003D9A9E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + 900E65821C2BB8D5003D9A9E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; + 900E65831C2BB8D5003D9A9E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; + 900E65851C2BB8D5003D9A9E /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; + 900E65861C2BB8D5003D9A9E /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; + 900E65891C2BB8D5003D9A9E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; + 900E658B1C2BB8D5003D9A9E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; + 900E658E1C2BB8D5003D9A9E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; + 900E65901C2BB8D5003D9A9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 900E65951C2BB8D5003D9A9E /* TZImagePickerControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TZImagePickerControllerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 900E65991C2BB8D5003D9A9E /* TZImagePickerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TZImagePickerControllerTests.m; sourceTree = "<group>"; }; + 900E659B1C2BB8D5003D9A9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 900E65A01C2BB8D5003D9A9E /* TZImagePickerControllerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TZImagePickerControllerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 900E65A41C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TZImagePickerControllerUITests.m; sourceTree = "<group>"; }; + 900E65A61C2BB8D5003D9A9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 900EEFF61C2BBF9500EA709B /* TZImagePickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImagePickerController.h; sourceTree = "<group>"; }; + 900EEFF71C2BBF9500EA709B /* TZImagePickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImagePickerController.m; sourceTree = "<group>"; }; + 900EEFFC1C2BD58B00EA709B /* TZPhotoPickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPickerController.h; sourceTree = "<group>"; }; + 900EEFFD1C2BD58B00EA709B /* TZPhotoPickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPickerController.m; sourceTree = "<group>"; }; + 900EEFFF1C2BD7E400EA709B /* TZAssetCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZAssetCell.h; sourceTree = "<group>"; }; + 900EF0001C2BD7E400EA709B /* TZAssetCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZAssetCell.m; sourceTree = "<group>"; }; + 900EF00D1C2C0B1100EA709B /* TZAssetModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZAssetModel.h; sourceTree = "<group>"; }; + 900EF00E1C2C0B1100EA709B /* TZAssetModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZAssetModel.m; sourceTree = "<group>"; }; + 900EF0101C2C107400EA709B /* TZPhotoPreviewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPreviewController.h; sourceTree = "<group>"; }; + 900EF0111C2C107400EA709B /* TZPhotoPreviewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPreviewController.m; sourceTree = "<group>"; }; + 900EF0131C2C134800EA709B /* TZPhotoPreviewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPreviewCell.h; sourceTree = "<group>"; }; + 900EF0141C2C134900EA709B /* TZPhotoPreviewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPreviewCell.m; sourceTree = "<group>"; }; + 9038D58F1C3974F0007DE549 /* TZTestCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZTestCell.h; sourceTree = "<group>"; }; + 9038D5901C3974F0007DE549 /* TZTestCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZTestCell.m; sourceTree = "<group>"; }; + 90CE84AC1C3A89EF003D0779 /* TZImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageManager.h; sourceTree = "<group>"; }; + 90CE84AD1C3A89EF003D0779 /* TZImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageManager.m; sourceTree = "<group>"; }; + 90CE84B51C3BABB6003D0779 /* TZVideoPlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZVideoPlayerController.h; sourceTree = "<group>"; }; + 90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZVideoPlayerController.m; sourceTree = "<group>"; }; + 90EBF5D41C2E298000CB9BCC /* UIView+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Layout.h"; sourceTree = "<group>"; }; + 90EBF5D51C2E298000CB9BCC /* UIView+Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Layout.m"; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 900E65791C2BB8D5003D9A9E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 900E65921C2BB8D5003D9A9E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 900E659D1C2BB8D5003D9A9E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 6DC358641CC8BAE300898D29 /* Resources */ = { + isa = PBXGroup; + children = ( + 6DC358651CC8BAFD00898D29 /* TZImagePickerController.bundle */, + ); + name = Resources; + sourceTree = "<group>"; + }; + 900E65731C2BB8D5003D9A9E = { + isa = PBXGroup; + children = ( + 900E657E1C2BB8D5003D9A9E /* TZImagePickerController */, + 900E65981C2BB8D5003D9A9E /* TZImagePickerControllerTests */, + 900E65A31C2BB8D5003D9A9E /* TZImagePickerControllerUITests */, + 900E657D1C2BB8D5003D9A9E /* Products */, + ); + sourceTree = "<group>"; + }; + 900E657D1C2BB8D5003D9A9E /* Products */ = { + isa = PBXGroup; + children = ( + 900E657C1C2BB8D5003D9A9E /* TZImagePickerController.app */, + 900E65951C2BB8D5003D9A9E /* TZImagePickerControllerTests.xctest */, + 900E65A01C2BB8D5003D9A9E /* TZImagePickerControllerUITests.xctest */, + ); + name = Products; + sourceTree = "<group>"; + }; + 900E657E1C2BB8D5003D9A9E /* TZImagePickerController */ = { + isa = PBXGroup; + children = ( + 900EEFF51C2BBF7600EA709B /* TZImagePickerController */, + 900E65821C2BB8D5003D9A9E /* AppDelegate.h */, + 900E65831C2BB8D5003D9A9E /* AppDelegate.m */, + 900E65851C2BB8D5003D9A9E /* ViewController.h */, + 900E65861C2BB8D5003D9A9E /* ViewController.m */, + 6D32B9BB1CD83640005CE1E0 /* LxGridViewFlowLayout.h */, + 6D32B9BC1CD83640005CE1E0 /* LxGridViewFlowLayout.m */, + 9038D58F1C3974F0007DE549 /* TZTestCell.h */, + 9038D5901C3974F0007DE549 /* TZTestCell.m */, + 900E65881C2BB8D5003D9A9E /* Main.storyboard */, + 900E658B1C2BB8D5003D9A9E /* Assets.xcassets */, + 900E658D1C2BB8D5003D9A9E /* LaunchScreen.storyboard */, + 900E65901C2BB8D5003D9A9E /* Info.plist */, + 900E657F1C2BB8D5003D9A9E /* Supporting Files */, + ); + path = TZImagePickerController; + sourceTree = "<group>"; + }; + 900E657F1C2BB8D5003D9A9E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 900E65801C2BB8D5003D9A9E /* main.m */, + ); + name = "Supporting Files"; + sourceTree = "<group>"; + }; + 900E65981C2BB8D5003D9A9E /* TZImagePickerControllerTests */ = { + isa = PBXGroup; + children = ( + 900E65991C2BB8D5003D9A9E /* TZImagePickerControllerTests.m */, + 900E659B1C2BB8D5003D9A9E /* Info.plist */, + ); + path = TZImagePickerControllerTests; + sourceTree = "<group>"; + }; + 900E65A31C2BB8D5003D9A9E /* TZImagePickerControllerUITests */ = { + isa = PBXGroup; + children = ( + 900E65A41C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m */, + 900E65A61C2BB8D5003D9A9E /* Info.plist */, + ); + path = TZImagePickerControllerUITests; + sourceTree = "<group>"; + }; + 900EEFF51C2BBF7600EA709B /* TZImagePickerController */ = { + isa = PBXGroup; + children = ( + 900EEFF61C2BBF9500EA709B /* TZImagePickerController.h */, + 900EEFF71C2BBF9500EA709B /* TZImagePickerController.m */, + 900EEFFC1C2BD58B00EA709B /* TZPhotoPickerController.h */, + 900EEFFD1C2BD58B00EA709B /* TZPhotoPickerController.m */, + 900EEFFF1C2BD7E400EA709B /* TZAssetCell.h */, + 900EF0001C2BD7E400EA709B /* TZAssetCell.m */, + 900EF00D1C2C0B1100EA709B /* TZAssetModel.h */, + 900EF00E1C2C0B1100EA709B /* TZAssetModel.m */, + 900EF0101C2C107400EA709B /* TZPhotoPreviewController.h */, + 900EF0111C2C107400EA709B /* TZPhotoPreviewController.m */, + 900EF0131C2C134800EA709B /* TZPhotoPreviewCell.h */, + 900EF0141C2C134900EA709B /* TZPhotoPreviewCell.m */, + 90CE84B51C3BABB6003D0779 /* TZVideoPlayerController.h */, + 90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */, + 6D46082F1DFFC60D004FB009 /* TZGifPhotoPreviewController.h */, + 6D4608301DFFC60D004FB009 /* TZGifPhotoPreviewController.m */, + 6DD050291DF659ED0057C78D /* TZProgressView.h */, + 6DD0502A1DF659ED0057C78D /* TZProgressView.m */, + 90CE84AC1C3A89EF003D0779 /* TZImageManager.h */, + 90CE84AD1C3A89EF003D0779 /* TZImageManager.m */, + 6DC84D081DF5358500A107A9 /* TZImageCropManager.h */, + 6DC84D091DF5358500A107A9 /* TZImageCropManager.m */, + 90EBF5D41C2E298000CB9BCC /* UIView+Layout.h */, + 90EBF5D51C2E298000CB9BCC /* UIView+Layout.m */, + 6D5358CB1D64600F00928CC6 /* NSBundle+TZImagePicker.h */, + 6D5358CC1D64600F00928CC6 /* NSBundle+TZImagePicker.m */, + 6DC358641CC8BAE300898D29 /* Resources */, + ); + path = TZImagePickerController; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 900E657B1C2BB8D5003D9A9E /* TZImagePickerController */ = { + isa = PBXNativeTarget; + buildConfigurationList = 900E65A91C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerController" */; + buildPhases = ( + 900E65781C2BB8D5003D9A9E /* Sources */, + 900E65791C2BB8D5003D9A9E /* Frameworks */, + 900E657A1C2BB8D5003D9A9E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TZImagePickerController; + productName = TZImagePickerController; + productReference = 900E657C1C2BB8D5003D9A9E /* TZImagePickerController.app */; + productType = "com.apple.product-type.application"; + }; + 900E65941C2BB8D5003D9A9E /* TZImagePickerControllerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 900E65AC1C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerControllerTests" */; + buildPhases = ( + 900E65911C2BB8D5003D9A9E /* Sources */, + 900E65921C2BB8D5003D9A9E /* Frameworks */, + 900E65931C2BB8D5003D9A9E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 900E65971C2BB8D5003D9A9E /* PBXTargetDependency */, + ); + name = TZImagePickerControllerTests; + productName = TZImagePickerControllerTests; + productReference = 900E65951C2BB8D5003D9A9E /* TZImagePickerControllerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 900E659F1C2BB8D5003D9A9E /* TZImagePickerControllerUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 900E65AF1C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerControllerUITests" */; + buildPhases = ( + 900E659C1C2BB8D5003D9A9E /* Sources */, + 900E659D1C2BB8D5003D9A9E /* Frameworks */, + 900E659E1C2BB8D5003D9A9E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 900E65A21C2BB8D5003D9A9E /* PBXTargetDependency */, + ); + name = TZImagePickerControllerUITests; + productName = TZImagePickerControllerUITests; + productReference = 900E65A01C2BB8D5003D9A9E /* TZImagePickerControllerUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 900E65741C2BB8D5003D9A9E /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "������"; + TargetAttributes = { + 900E657B1C2BB8D5003D9A9E = { + CreatedOnToolsVersion = 7.2; + DevelopmentTeam = VGXA77XL6T; + ProvisioningStyle = Automatic; + }; + 900E65941C2BB8D5003D9A9E = { + CreatedOnToolsVersion = 7.2; + TestTargetID = 900E657B1C2BB8D5003D9A9E; + }; + 900E659F1C2BB8D5003D9A9E = { + CreatedOnToolsVersion = 7.2; + TestTargetID = 900E657B1C2BB8D5003D9A9E; + }; + }; + }; + buildConfigurationList = 900E65771C2BB8D5003D9A9E /* Build configuration list for PBXProject "TZImagePickerController" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 900E65731C2BB8D5003D9A9E; + productRefGroup = 900E657D1C2BB8D5003D9A9E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 900E657B1C2BB8D5003D9A9E /* TZImagePickerController */, + 900E65941C2BB8D5003D9A9E /* TZImagePickerControllerTests */, + 900E659F1C2BB8D5003D9A9E /* TZImagePickerControllerUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 900E657A1C2BB8D5003D9A9E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 900E658F1C2BB8D5003D9A9E /* LaunchScreen.storyboard in Resources */, + 6DC358661CC8BAFD00898D29 /* TZImagePickerController.bundle in Resources */, + 900E658C1C2BB8D5003D9A9E /* Assets.xcassets in Resources */, + 900E658A1C2BB8D5003D9A9E /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 900E65931C2BB8D5003D9A9E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 900E659E1C2BB8D5003D9A9E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 900E65781C2BB8D5003D9A9E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9038D5911C3974F0007DE549 /* TZTestCell.m in Sources */, + 900EF00F1C2C0B1100EA709B /* TZAssetModel.m in Sources */, + 900EEFFE1C2BD58B00EA709B /* TZPhotoPickerController.m in Sources */, + 90EBF5D61C2E298000CB9BCC /* UIView+Layout.m in Sources */, + 90CE84B71C3BABB6003D0779 /* TZVideoPlayerController.m in Sources */, + 900EF0021C2BD7E400EA709B /* TZAssetCell.m in Sources */, + 6DD0502B1DF659ED0057C78D /* TZProgressView.m in Sources */, + 6D32B9BD1CD83640005CE1E0 /* LxGridViewFlowLayout.m in Sources */, + 6D4608311DFFC60D004FB009 /* TZGifPhotoPreviewController.m in Sources */, + 900EF0161C2C134900EA709B /* TZPhotoPreviewCell.m in Sources */, + 900E65871C2BB8D5003D9A9E /* ViewController.m in Sources */, + 90CE84AE1C3A89EF003D0779 /* TZImageManager.m in Sources */, + 900E65841C2BB8D5003D9A9E /* AppDelegate.m in Sources */, + 900E65811C2BB8D5003D9A9E /* main.m in Sources */, + 900EF0121C2C107400EA709B /* TZPhotoPreviewController.m in Sources */, + 6D5358CD1D64600F00928CC6 /* NSBundle+TZImagePicker.m in Sources */, + 900EEFF81C2BBF9500EA709B /* TZImagePickerController.m in Sources */, + 6DC84D0A1DF5358500A107A9 /* TZImageCropManager.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 900E65911C2BB8D5003D9A9E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 900E659A1C2BB8D5003D9A9E /* TZImagePickerControllerTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 900E659C1C2BB8D5003D9A9E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 900E65A51C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 900E65971C2BB8D5003D9A9E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 900E657B1C2BB8D5003D9A9E /* TZImagePickerController */; + targetProxy = 900E65961C2BB8D5003D9A9E /* PBXContainerItemProxy */; + }; + 900E65A21C2BB8D5003D9A9E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 900E657B1C2BB8D5003D9A9E /* TZImagePickerController */; + targetProxy = 900E65A11C2BB8D5003D9A9E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 900E65881C2BB8D5003D9A9E /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 900E65891C2BB8D5003D9A9E /* Base */, + 6D12FC191D66B71E00182C44 /* zh-Hans */, + ); + name = Main.storyboard; + sourceTree = "<group>"; + }; + 900E658D1C2BB8D5003D9A9E /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 900E658E1C2BB8D5003D9A9E /* Base */, + 6D12FC1A1D66B71E00182C44 /* zh-Hans */, + ); + name = LaunchScreen.storyboard; + sourceTree = "<group>"; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 900E65A71C2BB8D5003D9A9E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 900E65A81C2BB8D5003D9A9E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 900E65AA1C2BB8D5003D9A9E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = VGXA77XL6T; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/TZImagePickerController", + ); + INFOPLIST_FILE = TZImagePickerController/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerController; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 900E65AB1C2BB8D5003D9A9E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEVELOPMENT_TEAM = VGXA77XL6T; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/TZImagePickerController", + ); + INFOPLIST_FILE = TZImagePickerController/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerController; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 900E65AD1C2BB8D5003D9A9E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = TZImagePickerControllerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerControllerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TZImagePickerController.app/TZImagePickerController"; + }; + name = Debug; + }; + 900E65AE1C2BB8D5003D9A9E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = TZImagePickerControllerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerControllerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TZImagePickerController.app/TZImagePickerController"; + }; + name = Release; + }; + 900E65B01C2BB8D5003D9A9E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = TZImagePickerControllerUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerControllerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = TZImagePickerController; + USES_XCTRUNNER = YES; + }; + name = Debug; + }; + 900E65B11C2BB8D5003D9A9E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = TZImagePickerControllerUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerControllerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = TZImagePickerController; + USES_XCTRUNNER = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 900E65771C2BB8D5003D9A9E /* Build configuration list for PBXProject "TZImagePickerController" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 900E65A71C2BB8D5003D9A9E /* Debug */, + 900E65A81C2BB8D5003D9A9E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 900E65A91C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerController" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 900E65AA1C2BB8D5003D9A9E /* Debug */, + 900E65AB1C2BB8D5003D9A9E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 900E65AC1C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerControllerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 900E65AD1C2BB8D5003D9A9E /* Debug */, + 900E65AE1C2BB8D5003D9A9E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 900E65AF1C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerControllerUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 900E65B01C2BB8D5003D9A9E /* Debug */, + 900E65B11C2BB8D5003D9A9E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 900E65741C2BB8D5003D9A9E /* Project object */; +} diff --git a/TZImagePickerController/TZImagePickerController.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/TZImagePickerController/TZImagePickerController.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..bd70cc9 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:TZImagePickerController.xcodeproj"> + </FileRef> +</Workspace> diff --git a/TZImagePickerController/TZImagePickerController/AppDelegate.h b/TZImagePickerController/TZImagePickerController/AppDelegate.h new file mode 100755 index 0000000..9027dc4 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface AppDelegate : UIResponder <UIApplicationDelegate> + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/TZImagePickerController/TZImagePickerController/AppDelegate.m b/TZImagePickerController/TZImagePickerController/AppDelegate.m new file mode 100755 index 0000000..a0df51b --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/AppDelegate.m @@ -0,0 +1,42 @@ +// +// AppDelegate.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + +} + +- (void)applicationWillTerminate:(UIApplication *)application { + +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/Assets.xcassets/AlbumAddBtn.imageset/AlbumAddBtn@2x.png b/TZImagePickerController/TZImagePickerController/Assets.xcassets/AlbumAddBtn.imageset/AlbumAddBtn@2x.png new file mode 100755 index 0000000..b458d89 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/Assets.xcassets/AlbumAddBtn.imageset/AlbumAddBtn@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/Assets.xcassets/AlbumAddBtn.imageset/Contents.json b/TZImagePickerController/TZImagePickerController/Assets.xcassets/AlbumAddBtn.imageset/Contents.json new file mode 100755 index 0000000..bcfdb24 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/Assets.xcassets/AlbumAddBtn.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "AlbumAddBtn@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TZImagePickerController/TZImagePickerController/Assets.xcassets/AppIcon.appiconset/Contents.json b/TZImagePickerController/TZImagePickerController/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100755 index 0000000..b8236c6 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,48 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TZImagePickerController/TZImagePickerController/Assets.xcassets/Contents.json b/TZImagePickerController/TZImagePickerController/Assets.xcassets/Contents.json new file mode 100755 index 0000000..da4a164 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TZImagePickerController/TZImagePickerController/Assets.xcassets/photo_delete.imageset/Contents.json b/TZImagePickerController/TZImagePickerController/Assets.xcassets/photo_delete.imageset/Contents.json new file mode 100755 index 0000000..e9fe6b4 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/Assets.xcassets/photo_delete.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "photo_delete@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TZImagePickerController/TZImagePickerController/Assets.xcassets/photo_delete.imageset/photo_delete@2x.png b/TZImagePickerController/TZImagePickerController/Assets.xcassets/photo_delete.imageset/photo_delete@2x.png new file mode 100755 index 0000000..d07e714 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/Assets.xcassets/photo_delete.imageset/photo_delete@2x.png Binary files differ diff --git a/test/test/Base.lproj/Main.storyboard b/TZImagePickerController/TZImagePickerController/Base.lproj/LaunchScreen.storyboard old mode 100644 new mode 100755 similarity index 67% copy from test/test/Base.lproj/Main.storyboard copy to TZImagePickerController/TZImagePickerController/Base.lproj/LaunchScreen.storyboard index f56d2f3..1042eb6 --- a/test/test/Base.lproj/Main.storyboard +++ b/TZImagePickerController/TZImagePickerController/Base.lproj/LaunchScreen.storyboard @@ -1,25 +1,27 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="14F1509" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM"> <dependencies> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/> </dependencies> <scenes> <!--View Controller--> - <scene sceneID="tne-QT-ifu"> + <scene sceneID="EHf-IW-A2E"> <objects> - <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController"> + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> <layoutGuides> - <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> - <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> + <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/> + <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/> </layoutGuides> - <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> </view> </viewController> - <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> </objects> + <point key="canvasLocation" x="53" y="375"/> </scene> </scenes> </document> diff --git a/TZImagePickerController/TZImagePickerController/Base.lproj/Main.storyboard b/TZImagePickerController/TZImagePickerController/Base.lproj/Main.storyboard new file mode 100755 index 0000000..31becd4 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/Base.lproj/Main.storyboard @@ -0,0 +1,279 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2657" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> + <device id="retina4_7" orientation="portrait"> + <adaptation id="fullscreen"/> + </device> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="tne-QT-ifu"> + <objects> + <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> + <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4Ae-5T-gEc" userLabel="TopContentView"> + <rect key="frame" x="0.0" y="0.0" width="320" height="405"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="obE-hs-XLa" userLabel="View1"> + <rect key="frame" x="0.0" y="15" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jpa-B9-8n6"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <connections> + <action selector="showTakePhotoBtnSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="t9n-F2-EH7"/> + </connections> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="������������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="R92-Zn-NWV"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wWK-ob-W4A" userLabel="View2"> + <rect key="frame" x="0.0" y="55" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rbt-bh-r0x"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="���������������������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UL3-n3-Hmt"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kJv-DR-NlY" userLabel="View3"> + <rect key="frame" x="0.0" y="90" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="a58-aK-ZB0"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <connections> + <action selector="allowPickingVideoSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="kMA-4q-CZa"/> + </connections> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xCu-D3-IZg"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Z20-6k-hhA" userLabel="View4"> + <rect key="frame" x="0.0" y="125" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iRQ-aE-1KG"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <connections> + <action selector="allowPickingImageSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="MHy-72-YhW"/> + </connections> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vNN-OI-9z1"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jKt-h1-BC7" userLabel="View5"> + <rect key="frame" x="0.0" y="195" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4L3-Da-pcd"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <connections> + <action selector="allowPickingOriginPhotoSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="mdw-vb-h0y"/> + </connections> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="������������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7mi-Lf-2N5"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Qrr-87-KzM" userLabel="View7"> + <rect key="frame" x="0.0" y="230" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="uHt-bT-lBZ"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <connections> + <action selector="showSheetSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="kmV-vK-SDz"/> + </connections> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="���������������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jop-5R-ioj"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PA2-zk-4Ey" userLabel="View8"> + <rect key="frame" x="0.0" y="265" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="������������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rK3-1U-kcW"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="9" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="37K-cO-hgf"> + <rect key="frame" x="220" y="2" width="80" height="30"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <textInputTraits key="textInputTraits" keyboardType="numberPad"/> + </textField> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VUP-wm-Ah2" userLabel="View9"> + <rect key="frame" x="0.0" y="300" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="������������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fbH-6q-oeE"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="4" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="YR1-nJ-q0v"> + <rect key="frame" x="220" y="2" width="80" height="30"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="14"/> + <textInputTraits key="textInputTraits" keyboardType="numberPad"/> + </textField> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="92q-n9-Zwf" userLabel="View10"> + <rect key="frame" x="0.0" y="335" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="0ju-HJ-A06"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <connections> + <action selector="allowCropSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="tw0-q2-Fa7"/> + </connections> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="���������������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ibb-kN-MWC"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uex-bO-uvg" userLabel="View11"> + <rect key="frame" x="0.0" y="370" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="hsH-wt-l1R"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <connections> + <action selector="needCircleCropSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="2yt-Uf-LNh"/> + </connections> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="���������������������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TiG-df-jDs"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gde-hr-2Sy" userLabel="View6"> + <rect key="frame" x="0.0" y="160" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <subviews> + <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="zLj-vc-Xwz"> + <rect key="frame" x="225" y="2" width="51" height="31"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <connections> + <action selector="allowPickingGifSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="O9W-7a-uc8"/> + <action selector="allowPickingOriginPhotoSwitchClick:" destination="BYZ-38-t0r" eventType="valueChanged" id="Y1n-2W-q5O"/> + </connections> + </switch> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="������������Gif������" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ly2-uJ-7DN"> + <rect key="frame" x="0.0" y="0.0" width="200" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <fontDescription key="fontDescription" type="system" pointSize="15"/> + <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + </subviews> + </view> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + <connections> + <outlet property="allowCropSwitch" destination="0ju-HJ-A06" id="PHl-Yf-uf2"/> + <outlet property="allowPickingGifSwitch" destination="zLj-vc-Xwz" id="1UG-vY-alU"/> + <outlet property="allowPickingImageSwitch" destination="iRQ-aE-1KG" id="V7a-u6-cLv"/> + <outlet property="allowPickingOriginalPhotoSwitch" destination="4L3-Da-pcd" id="KFm-Zl-dpD"/> + <outlet property="allowPickingVideoSwitch" destination="a58-aK-ZB0" id="9Ti-hW-QRj"/> + <outlet property="columnNumberTF" destination="YR1-nJ-q0v" id="TE2-iH-EWE"/> + <outlet property="maxCountTF" destination="37K-cO-hgf" id="776-gE-tea"/> + <outlet property="needCircleCropSwitch" destination="hsH-wt-l1R" id="SVP-EE-wgf"/> + <outlet property="showSheetSwitch" destination="uHt-bT-lBZ" id="NxK-wM-ivE"/> + <outlet property="showTakePhotoBtnSwitch" destination="jpa-B9-8n6" id="lh8-2O-IWS"/> + <outlet property="sortAscendingSwitch" destination="Rbt-bh-r0x" id="WEA-Vq-uSg"/> + </connections> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="368" y="318"/> + </scene> + </scenes> +</document> diff --git a/TZImagePickerController/TZImagePickerController/Info.plist b/TZImagePickerController/TZImagePickerController/Info.plist new file mode 100755 index 0000000..06477d1 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/Info.plist @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.7.8</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>NSCameraUsageDescription</key> + <string>���������������������</string> + <key>NSPhotoLibraryUsageDescription</key> + <string>���������������������������</string> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIMainStoryboardFile</key> + <string>Main</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>armv7</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> + </array> + <key>UIViewControllerBasedStatusBarAppearance</key> + <false/> +</dict> +</plist> diff --git a/TZImagePickerController/TZImagePickerController/LxGridViewFlowLayout.h b/TZImagePickerController/TZImagePickerController/LxGridViewFlowLayout.h new file mode 100755 index 0000000..7974061 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/LxGridViewFlowLayout.h @@ -0,0 +1,57 @@ +// +// LxGridViewFlowLayout.h +// LxGridView +// + +#import <UIKit/UIKit.h> + +/* + ���������������DeveloperLx������������������������LxGridView + github���������https://github.com/DeveloperLx/LxGridView + ��������������������������������������������� + ������DeveloperLx���������������~ + */ + +@interface LxGridViewFlowLayout : UICollectionViewFlowLayout + +@property (nonatomic,assign) BOOL panGestureRecognizerEnable; + +@end + +@protocol LxGridViewDataSource <UICollectionViewDataSource> + +@optional + +- (void)collectionView:(UICollectionView *)collectionView + itemAtIndexPath:(NSIndexPath *)sourceIndexPath + willMoveToIndexPath:(NSIndexPath *)destinationIndexPath; +- (void)collectionView:(UICollectionView *)collectionView + itemAtIndexPath:(NSIndexPath *)sourceIndexPath + didMoveToIndexPath:(NSIndexPath *)destinationIndexPath; + +- (BOOL)collectionView:(UICollectionView *)collectionView +canMoveItemAtIndexPath:(NSIndexPath *)indexPath; +- (BOOL)collectionView:(UICollectionView *)collectionView + itemAtIndexPath:(NSIndexPath *)sourceIndexPath + canMoveToIndexPath:(NSIndexPath *)destinationIndexPath; + +@end + +@protocol LxGridViewDelegateFlowLayout <UICollectionViewDelegateFlowLayout> + +@optional + +- (void)collectionView:(UICollectionView *)collectionView + layout:(UICollectionViewLayout *)collectionViewLayout +willBeginDraggingItemAtIndexPath:(NSIndexPath *)indexPath; +- (void)collectionView:(UICollectionView *)collectionView + layout:(UICollectionViewLayout *)collectionViewLayout +didBeginDraggingItemAtIndexPath:(NSIndexPath *)indexPath; +- (void)collectionView:(UICollectionView *)collectionView + layout:(UICollectionViewLayout *)collectionViewLayout +willEndDraggingItemAtIndexPath:(NSIndexPath *)indexPath; +- (void)collectionView:(UICollectionView *)collectionView + layout:(UICollectionViewLayout *)collectionViewLayout +didEndDraggingItemAtIndexPath:(NSIndexPath *)indexPath; + +@end \ No newline at end of file diff --git a/TZImagePickerController/TZImagePickerController/LxGridViewFlowLayout.m b/TZImagePickerController/TZImagePickerController/LxGridViewFlowLayout.m new file mode 100755 index 0000000..b8486a3 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/LxGridViewFlowLayout.m @@ -0,0 +1,408 @@ +// +// LxGridViewFlowLayout.m +// LxGridView +// + +#import "LxGridViewFlowLayout.h" +#import "TZTestCell.h" +#import "UIView+Layout.h" + +#define stringify __STRING + +static CGFloat const PRESS_TO_MOVE_MIN_DURATION = 0.1; +static CGFloat const MIN_PRESS_TO_BEGIN_EDITING_DURATION = 0.6; + +CG_INLINE CGPoint CGPointOffset(CGPoint point, CGFloat dx, CGFloat dy) +{ + return CGPointMake(point.x + dx, point.y + dy); +} + +/* + ���������������DeveloperLx������������������������LxGridView + github���������https://github.com/DeveloperLx/LxGridView + ��������������������������������������������� + ������DeveloperLx���������������~ + */ + +@interface LxGridViewFlowLayout () <UIGestureRecognizerDelegate> + +@property (nonatomic,readonly) id<LxGridViewDataSource> dataSource; +@property (nonatomic,readonly) id<LxGridViewDelegateFlowLayout> delegate; + +@end + +@implementation LxGridViewFlowLayout +{ + UILongPressGestureRecognizer * _longPressGestureRecognizer; + UIPanGestureRecognizer * _panGestureRecognizer; + NSIndexPath * _movingItemIndexPath; + UIView * _beingMovedPromptView; + CGPoint _sourceItemCollectionViewCellCenter; + + CADisplayLink * _displayLink; + CFTimeInterval _remainSecondsToBeginEditing; +} + +#pragma mark - setup + +- (void)dealloc +{ + [_displayLink invalidate]; + + [self removeGestureRecognizers]; + [self removeObserver:self forKeyPath:@stringify(collectionView)]; +} + +- (instancetype)init +{ + if (self = [super init]) { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + if (self = [super initWithCoder:coder]) { + [self setup]; + } + return self; +} + +- (void)setup +{ + [self addObserver:self forKeyPath:@stringify(collectionView) options:NSKeyValueObservingOptionNew context:nil]; +} + +- (void)addGestureRecognizers +{ + self.collectionView.userInteractionEnabled = YES; + + _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPressGestureRecognizerTriggerd:)]; + _longPressGestureRecognizer.cancelsTouchesInView = NO; + _longPressGestureRecognizer.minimumPressDuration = PRESS_TO_MOVE_MIN_DURATION; + _longPressGestureRecognizer.delegate = self; + + for (UIGestureRecognizer * gestureRecognizer in self.collectionView.gestureRecognizers) { + if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) { + [gestureRecognizer requireGestureRecognizerToFail:_longPressGestureRecognizer]; + } + } + + [self.collectionView addGestureRecognizer:_longPressGestureRecognizer]; + + _panGestureRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestureRecognizerTriggerd:)]; + _panGestureRecognizer.delegate = self; + [self.collectionView addGestureRecognizer:_panGestureRecognizer]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; +} + +- (void)removeGestureRecognizers +{ + if (_longPressGestureRecognizer) { + if (_longPressGestureRecognizer.view) { + [_longPressGestureRecognizer.view removeGestureRecognizer:_longPressGestureRecognizer]; + } + _longPressGestureRecognizer = nil; + } + + if (_panGestureRecognizer) { + if (_panGestureRecognizer.view) { + [_panGestureRecognizer.view removeGestureRecognizer:_panGestureRecognizer]; + } + _panGestureRecognizer = nil; + } + + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil]; +} + +#pragma mark - getter and setter implementation + +- (id<LxGridViewDataSource>)dataSource +{ + return (id<LxGridViewDataSource>)self.collectionView.dataSource; +} + +- (id<LxGridViewDelegateFlowLayout>)delegate +{ + return (id<LxGridViewDelegateFlowLayout>)self.collectionView.delegate; +} + +#pragma mark - override UICollectionViewLayout methods + +- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect +{ + NSArray * layoutAttributesForElementsInRect = [super layoutAttributesForElementsInRect:rect]; + + for (UICollectionViewLayoutAttributes * layoutAttributes in layoutAttributesForElementsInRect) { + + if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) { + layoutAttributes.hidden = [layoutAttributes.indexPath isEqual:_movingItemIndexPath]; + } + } + return layoutAttributesForElementsInRect; +} + +- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath +{ + UICollectionViewLayoutAttributes * layoutAttributes = [super layoutAttributesForItemAtIndexPath:indexPath]; + if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) { + layoutAttributes.hidden = [layoutAttributes.indexPath isEqual:_movingItemIndexPath]; + } + return layoutAttributes; +} + +#pragma mark - gesture + +- (void)setPanGestureRecognizerEnable:(BOOL)panGestureRecognizerEnable +{ + _panGestureRecognizer.enabled = panGestureRecognizerEnable; +} + +- (BOOL)panGestureRecognizerEnable +{ + return _panGestureRecognizer.enabled; +} + +- (void)longPressGestureRecognizerTriggerd:(UILongPressGestureRecognizer *)longPress +{ + switch (longPress.state) { + case UIGestureRecognizerStatePossible: + break; + case UIGestureRecognizerStateBegan: + { + if (_displayLink == nil) { + _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTriggered:)]; + _displayLink.frameInterval = 6; + [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + + _remainSecondsToBeginEditing = MIN_PRESS_TO_BEGIN_EDITING_DURATION; + } + + _movingItemIndexPath = [self.collectionView indexPathForItemAtPoint:[longPress locationInView:self.collectionView]]; + if ([self.dataSource respondsToSelector:@selector(collectionView:canMoveItemAtIndexPath:)] && [self.dataSource collectionView:self.collectionView canMoveItemAtIndexPath:_movingItemIndexPath] == NO) { + _movingItemIndexPath = nil; + return; + } + + if ([self.delegate respondsToSelector:@selector(collectionView:layout:willBeginDraggingItemAtIndexPath:)]) { + [self.delegate collectionView:self.collectionView layout:self willBeginDraggingItemAtIndexPath:_movingItemIndexPath]; + } + + UICollectionViewCell *sourceCollectionViewCell = [self.collectionView cellForItemAtIndexPath:_movingItemIndexPath]; + TZTestCell *sourceCell = (TZTestCell *)sourceCollectionViewCell; + + _beingMovedPromptView = [[UIView alloc]initWithFrame:CGRectOffset(sourceCollectionViewCell.frame, -10, -10)]; + _beingMovedPromptView.tz_width += 20; + _beingMovedPromptView.tz_height += 20; + + sourceCollectionViewCell.highlighted = YES; + UIView * highlightedSnapshotView = [sourceCell snapshotView]; + highlightedSnapshotView.frame = _beingMovedPromptView.bounds; + highlightedSnapshotView.alpha = 1; + + sourceCollectionViewCell.highlighted = NO; + UIView * snapshotView = [sourceCell snapshotView]; + snapshotView.frame = _beingMovedPromptView.bounds; + snapshotView.alpha = 0; + + [_beingMovedPromptView addSubview:snapshotView]; + [_beingMovedPromptView addSubview:highlightedSnapshotView]; + [self.collectionView addSubview:_beingMovedPromptView]; + + _sourceItemCollectionViewCellCenter = sourceCollectionViewCell.center; + + typeof(self) __weak weakSelf = self; + [UIView animateWithDuration:0 + delay:0 + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + + typeof(self) __strong strongSelf = weakSelf; + if (strongSelf) { + highlightedSnapshotView.alpha = 0; + snapshotView.alpha = 1; + } + } + completion:^(BOOL finished) { + + typeof(self) __strong strongSelf = weakSelf; + if (strongSelf) { + [highlightedSnapshotView removeFromSuperview]; + + if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didBeginDraggingItemAtIndexPath:)]) { + [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didBeginDraggingItemAtIndexPath:_movingItemIndexPath]; + } + } + }]; + + [self invalidateLayout]; + } + break; + case UIGestureRecognizerStateChanged: + break; + case UIGestureRecognizerStateEnded: + case UIGestureRecognizerStateCancelled: + { + [_displayLink invalidate]; + _displayLink = nil; + + NSIndexPath * movingItemIndexPath = _movingItemIndexPath; + + if (movingItemIndexPath) { + if ([self.delegate respondsToSelector:@selector(collectionView:layout:willEndDraggingItemAtIndexPath:)]) { + [self.delegate collectionView:self.collectionView layout:self willEndDraggingItemAtIndexPath:movingItemIndexPath]; + } + + _movingItemIndexPath = nil; + _sourceItemCollectionViewCellCenter = CGPointZero; + + UICollectionViewLayoutAttributes * movingItemCollectionViewLayoutAttributes = [self layoutAttributesForItemAtIndexPath:movingItemIndexPath]; + + _longPressGestureRecognizer.enabled = NO; + + typeof(self) __weak weakSelf = self; + [UIView animateWithDuration:0.2 + delay:0 + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + typeof(self) __strong strongSelf = weakSelf; + if (strongSelf) { + _beingMovedPromptView.center = movingItemCollectionViewLayoutAttributes.center; + } + } + completion:^(BOOL finished) { + + _longPressGestureRecognizer.enabled = YES; + + typeof(self) __strong strongSelf = weakSelf; + if (strongSelf) { + [_beingMovedPromptView removeFromSuperview]; + _beingMovedPromptView = nil; + [strongSelf invalidateLayout]; + + if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didEndDraggingItemAtIndexPath:)]) { + [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didEndDraggingItemAtIndexPath:movingItemIndexPath]; + } + } + }]; + } + } + break; + case UIGestureRecognizerStateFailed: + break; + default: + break; + } +} + +- (void)panGestureRecognizerTriggerd:(UIPanGestureRecognizer *)pan +{ + switch (pan.state) { + case UIGestureRecognizerStatePossible: + break; + case UIGestureRecognizerStateBegan: + case UIGestureRecognizerStateChanged: + { + CGPoint panTranslation = [pan translationInView:self.collectionView]; + _beingMovedPromptView.center = CGPointOffset(_sourceItemCollectionViewCellCenter, panTranslation.x, panTranslation.y); + + NSIndexPath * sourceIndexPath = _movingItemIndexPath; + NSIndexPath * destinationIndexPath = [self.collectionView indexPathForItemAtPoint:_beingMovedPromptView.center]; + + if ((destinationIndexPath == nil) || [destinationIndexPath isEqual:sourceIndexPath]) { + return; + } + + if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:canMoveToIndexPath:)] && [self.dataSource collectionView:self.collectionView itemAtIndexPath:sourceIndexPath canMoveToIndexPath:destinationIndexPath] == NO) { + return; + } + + if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:willMoveToIndexPath:)]) { + [self.dataSource collectionView:self.collectionView itemAtIndexPath:sourceIndexPath willMoveToIndexPath:destinationIndexPath]; + } + + _movingItemIndexPath = destinationIndexPath; + + typeof(self) __weak weakSelf = self; + [self.collectionView performBatchUpdates:^{ + typeof(self) __strong strongSelf = weakSelf; + if (strongSelf) { + if (sourceIndexPath && destinationIndexPath) { + [strongSelf.collectionView deleteItemsAtIndexPaths:@[sourceIndexPath]]; + [strongSelf.collectionView insertItemsAtIndexPaths:@[destinationIndexPath]]; + } + } + } completion:^(BOOL finished) { + typeof(self) __strong strongSelf = weakSelf; + if ([strongSelf.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:didMoveToIndexPath:)]) { + [strongSelf.dataSource collectionView:strongSelf.collectionView itemAtIndexPath:sourceIndexPath didMoveToIndexPath:destinationIndexPath]; + } + }]; + } + break; + case UIGestureRecognizerStateEnded: + break; + case UIGestureRecognizerStateCancelled: + break; + case UIGestureRecognizerStateFailed: + break; + default: + break; + } +} + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer +{ + if ([_panGestureRecognizer isEqual:gestureRecognizer]) { + return _movingItemIndexPath != nil; + } + return YES; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer +{ + // only _longPressGestureRecognizer and _panGestureRecognizer can recognize simultaneously + if ([_longPressGestureRecognizer isEqual:gestureRecognizer]) { + return [_panGestureRecognizer isEqual:otherGestureRecognizer]; + } + if ([_panGestureRecognizer isEqual:gestureRecognizer]) { + return [_longPressGestureRecognizer isEqual:otherGestureRecognizer]; + } + return NO; +} + +#pragma mark - displayLink + +- (void)displayLinkTriggered:(CADisplayLink *)displayLink +{ + if (_remainSecondsToBeginEditing <= 0) { + [_displayLink invalidate]; + _displayLink = nil; + } + + _remainSecondsToBeginEditing = _remainSecondsToBeginEditing - 0.1; +} + +#pragma mark - KVO and notification + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:@stringify(collectionView)]) { + if (self.collectionView) { + [self addGestureRecognizers]; + } + else { + [self removeGestureRecognizers]; + } + } +} + +- (void)applicationWillResignActive:(NSNotification *)notificaiton +{ + _panGestureRecognizer.enabled = NO; + _panGestureRecognizer.enabled = YES; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/ScreenShots/photoPickerVc.PNG b/TZImagePickerController/TZImagePickerController/ScreenShots/photoPickerVc.PNG new file mode 100755 index 0000000..ac51892 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/ScreenShots/photoPickerVc.PNG Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/ScreenShots/photoPreviewVc.PNG b/TZImagePickerController/TZImagePickerController/ScreenShots/photoPreviewVc.PNG new file mode 100755 index 0000000..272bfd5 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/ScreenShots/photoPreviewVc.PNG Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/ScreenShots/videoPlayerVc.PNG b/TZImagePickerController/TZImagePickerController/ScreenShots/videoPlayerVc.PNG new file mode 100755 index 0000000..2239666 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/ScreenShots/videoPlayerVc.PNG Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.h new file mode 100755 index 0000000..f697224 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.h @@ -0,0 +1,17 @@ +// +// NSBundle+TZImagePicker.h +// TZImagePickerController +// +// Created by ������ on 16/08/18. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface NSBundle (TZImagePicker) + ++ (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value; ++ (NSString *)tz_localizedStringForKey:(NSString *)key; + +@end + diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.m new file mode 100755 index 0000000..8467dfa --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.m @@ -0,0 +1,44 @@ +// +// NSBundle+TZImagePicker.m +// TZImagePickerController +// +// Created by ������ on 16/08/18. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import "NSBundle+TZImagePicker.h" +#import "TZImagePickerController.h" + +@implementation NSBundle (TZImagePicker) + ++ (instancetype)tz_imagePickerBundle { + static NSBundle *tzBundle = nil; + if (tzBundle == nil) { + NSString *path = [[NSBundle mainBundle] pathForResource:@"TZImagePickerController" ofType:@"bundle"]; + if (!path) { + path = [[NSBundle mainBundle] pathForResource:@"TZImagePickerController" ofType:@"bundle" inDirectory:@"Frameworks/TZImagePickerController.framework/"]; + } + tzBundle = [NSBundle bundleWithPath:path]; + } + return tzBundle; +} + ++ (NSString *)tz_localizedStringForKey:(NSString *)key { + return [self tz_localizedStringForKey:key value:@""]; +} + ++ (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value { + static NSBundle *bundle = nil; + if (bundle == nil) { + NSString *language = [NSLocale preferredLanguages].firstObject; + if ([language rangeOfString:@"zh-Hans"].location != NSNotFound) { + language = @"zh-Hans"; + } else { + language = @"en"; + } + bundle = [NSBundle bundleWithPath:[[NSBundle tz_imagePickerBundle] pathForResource:language ofType:@"lproj"]]; + } + NSString *value1 = [bundle localizedStringForKey:key value:value table:nil]; + return value1; +} +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.h new file mode 100755 index 0000000..5c2f059 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.h @@ -0,0 +1,53 @@ +// +// TZAssetCell.h +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import <Photos/Photos.h> + +typedef enum : NSUInteger { + TZAssetCellTypePhoto = 0, + TZAssetCellTypeLivePhoto, + TZAssetCellTypePhotoGif, + TZAssetCellTypeVideo, + TZAssetCellTypeAudio, +} TZAssetCellType; + +@class TZAssetModel; +@interface TZAssetCell : UICollectionViewCell + +@property (weak, nonatomic) UIButton *selectPhotoButton; +@property (nonatomic, strong) TZAssetModel *model; +@property (nonatomic, copy) void (^didSelectPhotoBlock)(BOOL); +@property (nonatomic, assign) TZAssetCellType type; +@property (nonatomic, assign) BOOL allowPickingGif; +@property (nonatomic, copy) NSString *representedAssetIdentifier; +@property (nonatomic, assign) PHImageRequestID imageRequestID; + +@property (nonatomic, copy) NSString *photoSelImageName; +@property (nonatomic, copy) NSString *photoDefImageName; + +@property (nonatomic, assign) BOOL showSelectBtn; + +@end + + +@class TZAlbumModel; + +@interface TZAlbumCell : UITableViewCell + +@property (nonatomic, strong) TZAlbumModel *model; +@property (weak, nonatomic) UIButton *selectedCountButton; + +@end + + +@interface TZAssetCameraCell : UICollectionViewCell + +@property (nonatomic, strong) UIImageView *imageView; + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.m new file mode 100755 index 0000000..8615289 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.m @@ -0,0 +1,349 @@ +// +// TZAssetCell.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import "TZAssetCell.h" +#import "TZAssetModel.h" +#import "UIView+Layout.h" +#import "TZImageManager.h" +#import "TZImagePickerController.h" +#import "TZProgressView.h" + +@interface TZAssetCell () +@property (weak, nonatomic) UIImageView *imageView; // The photo / ������ +@property (weak, nonatomic) UIImageView *selectImageView; +@property (weak, nonatomic) UIView *bottomView; +@property (weak, nonatomic) UILabel *timeLength; + +@property (nonatomic, weak) UIImageView *videoImgView; +@property (nonatomic, strong) TZProgressView *progressView; +@property (nonatomic, assign) PHImageRequestID bigImageRequestID; +@end + +@implementation TZAssetCell + +- (void)setModel:(TZAssetModel *)model { + _model = model; + if (iOS8Later) { + self.representedAssetIdentifier = [[TZImageManager manager] getAssetIdentifier:model.asset]; + } + PHImageRequestID imageRequestID = [[TZImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.tz_width completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { + if (_progressView) { + self.progressView.hidden = YES; + self.imageView.alpha = 1.0; + } + // Set the cell's thumbnail image if it's still showing the same asset. + if (!iOS8Later) { + self.imageView.image = photo; return; + } + if ([self.representedAssetIdentifier isEqualToString:[[TZImageManager manager] getAssetIdentifier:model.asset]]) { + self.imageView.image = photo; + } else { + // NSLog(@"this cell is showing other asset"); + [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; + } + if (!isDegraded) { + self.imageRequestID = 0; + } + } progressHandler:nil networkAccessAllowed:NO]; + if (imageRequestID && self.imageRequestID && imageRequestID != self.imageRequestID) { + [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; + // NSLog(@"cancelImageRequest %d",self.imageRequestID); + } + self.imageRequestID = imageRequestID; + self.selectPhotoButton.selected = model.isSelected; + self.selectImageView.image = self.selectPhotoButton.isSelected ? [UIImage imageNamedFromMyBundle:self.photoSelImageName] : [UIImage imageNamedFromMyBundle:self.photoDefImageName]; + self.type = (NSInteger)model.type; + // ���������/������������ ������������������������ ��������������������� + if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) { + if (_selectImageView.hidden == NO) { + self.selectPhotoButton.hidden = YES; + _selectImageView.hidden = YES; + } + } + // ��������������������������������������������������������� + if (model.isSelected) { + [self fetchBigImage]; + } +} + +- (void)setShowSelectBtn:(BOOL)showSelectBtn { + _showSelectBtn = showSelectBtn; + if (!self.selectPhotoButton.hidden) { + self.selectPhotoButton.hidden = !showSelectBtn; + } + if (!self.selectImageView.hidden) { + self.selectImageView.hidden = !showSelectBtn; + } +} + +- (void)setType:(TZAssetCellType)type { + _type = type; + if (type == TZAssetCellTypePhoto || type == TZAssetCellTypeLivePhoto || (type == TZAssetCellTypePhotoGif && !self.allowPickingGif)) { + _selectImageView.hidden = NO; + _selectPhotoButton.hidden = NO; + _bottomView.hidden = YES; + } else { // Video of Gif + _selectImageView.hidden = YES; + _selectPhotoButton.hidden = YES; + _bottomView.hidden = NO; + if (type == TZAssetCellTypeVideo) { + self.timeLength.text = _model.timeLength; + self.videoImgView.hidden = NO; + _timeLength.tz_left = self.videoImgView.tz_right; + _timeLength.textAlignment = NSTextAlignmentRight; + } else { + self.timeLength.text = @"GIF"; + self.videoImgView.hidden = YES; + _timeLength.tz_left = 5; + _timeLength.textAlignment = NSTextAlignmentLeft; + } + } +} + +- (void)selectPhotoButtonClick:(UIButton *)sender { + if (self.didSelectPhotoBlock) { + self.didSelectPhotoBlock(sender.isSelected); + } + self.selectImageView.image = sender.isSelected ? [UIImage imageNamedFromMyBundle:self.photoSelImageName] : [UIImage imageNamedFromMyBundle:self.photoDefImageName]; + if (sender.isSelected) { + [UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:TZOscillatoryAnimationToBigger]; + // ��������������������������������������������������� + [self fetchBigImage]; + } else { // ������������������������������������ + if (_bigImageRequestID && _progressView) { + [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID]; + [self hideProgressView]; + } + } +} + +- (void)hideProgressView { + self.progressView.hidden = YES; + self.imageView.alpha = 1.0; +} + +- (void)fetchBigImage { + _bigImageRequestID = [[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { + if (_progressView) { + [self hideProgressView]; + } + } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { + if (_model.isSelected) { + progress = progress > 0.02 ? progress : 0.02;; + self.progressView.progress = progress; + self.progressView.hidden = NO; + self.imageView.alpha = 0.4; + } else { + *stop = YES; + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; + } + } networkAccessAllowed:YES]; +} + +#pragma mark - Lazy load + +- (UIButton *)selectPhotoButton { + if (_selectImageView == nil) { + UIButton *selectPhotoButton = [[UIButton alloc] init]; + selectPhotoButton.frame = CGRectMake(self.tz_width - 44, 0, 44, 44); + [selectPhotoButton addTarget:self action:@selector(selectPhotoButtonClick:) forControlEvents:UIControlEventTouchUpInside]; + [self.contentView addSubview:selectPhotoButton]; + _selectPhotoButton = selectPhotoButton; + } + return _selectPhotoButton; +} + +- (UIImageView *)imageView { + if (_imageView == nil) { + UIImageView *imageView = [[UIImageView alloc] init]; + imageView.frame = CGRectMake(0, 0, self.tz_width, self.tz_height); + imageView.contentMode = UIViewContentModeScaleAspectFill; + imageView.clipsToBounds = YES; + [self.contentView addSubview:imageView]; + _imageView = imageView; + + [self.contentView bringSubviewToFront:_selectImageView]; + [self.contentView bringSubviewToFront:_bottomView]; + } + return _imageView; +} + +- (UIImageView *)selectImageView { + if (_selectImageView == nil) { + UIImageView *selectImageView = [[UIImageView alloc] init]; + selectImageView.frame = CGRectMake(self.tz_width - 27, 0, 27, 27); + [self.contentView addSubview:selectImageView]; + _selectImageView = selectImageView; + } + return _selectImageView; +} + +- (UIView *)bottomView { + if (_bottomView == nil) { + UIView *bottomView = [[UIView alloc] init]; + bottomView.frame = CGRectMake(0, self.tz_height - 17, self.tz_width, 17); + static NSInteger rgb = 0; + bottomView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.8]; + [self.contentView addSubview:bottomView]; + _bottomView = bottomView; + } + return _bottomView; +} + +- (UIImageView *)videoImgView { + if (_videoImgView == nil) { + UIImageView *videoImgView = [[UIImageView alloc] init]; + videoImgView.frame = CGRectMake(8, 0, 17, 17); + [videoImgView setImage:[UIImage imageNamedFromMyBundle:@"VideoSendIcon.png"]]; + [self.bottomView addSubview:videoImgView]; + _videoImgView = videoImgView; + } + return _videoImgView; +} + +- (UILabel *)timeLength { + if (_timeLength == nil) { + UILabel *timeLength = [[UILabel alloc] init]; + timeLength.font = [UIFont boldSystemFontOfSize:11]; + timeLength.frame = CGRectMake(self.videoImgView.tz_right, 0, self.tz_width - self.videoImgView.tz_right - 5, 17); + timeLength.textColor = [UIColor whiteColor]; + timeLength.textAlignment = NSTextAlignmentRight; + [self.bottomView addSubview:timeLength]; + _timeLength = timeLength; + } + return _timeLength; +} + +- (TZProgressView *)progressView { + if (_progressView == nil) { + _progressView = [[TZProgressView alloc] init]; + static CGFloat progressWH = 20; + CGFloat progressXY = (self.tz_width - progressWH) / 2; + _progressView.hidden = YES; + _progressView.frame = CGRectMake(progressXY, progressXY, progressWH, progressWH); + [self addSubview:_progressView]; + } + return _progressView; +} + +@end + +@interface TZAlbumCell () +@property (weak, nonatomic) UIImageView *posterImageView; +@property (weak, nonatomic) UILabel *titleLabel; +@property (weak, nonatomic) UIImageView *arrowImageView; +@end + +@implementation TZAlbumCell + +- (void)setModel:(TZAlbumModel *)model { + _model = model; + + NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc] initWithString:model.name attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor blackColor]}]; + NSAttributedString *countString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%zd)",model.count] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor lightGrayColor]}]; + [nameString appendAttributedString:countString]; + self.titleLabel.attributedText = nameString; + [[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) { + self.posterImageView.image = postImage; + }]; + if (model.selectedCount) { + self.selectedCountButton.hidden = NO; + [self.selectedCountButton setTitle:[NSString stringWithFormat:@"%zd",model.selectedCount] forState:UIControlStateNormal]; + } else { + self.selectedCountButton.hidden = YES; + } +} + +/// For fitting iOS6 +- (void)layoutSubviews { + if (iOS7Later) [super layoutSubviews]; + _selectedCountButton.frame = CGRectMake(self.tz_width - 24 - 30, 23, 24, 24); +} + +- (void)layoutSublayersOfLayer:(CALayer *)layer { + if (iOS7Later) [super layoutSublayersOfLayer:layer]; +} + +#pragma mark - Lazy load + +- (UIImageView *)posterImageView { + if (_posterImageView == nil) { + UIImageView *posterImageView = [[UIImageView alloc] init]; + posterImageView.contentMode = UIViewContentModeScaleAspectFill; + posterImageView.clipsToBounds = YES; + posterImageView.frame = CGRectMake(0, 0, 70, 70); + [self.contentView addSubview:posterImageView]; + _posterImageView = posterImageView; + } + return _posterImageView; +} + +- (UILabel *)titleLabel { + if (_titleLabel == nil) { + UILabel *titleLabel = [[UILabel alloc] init]; + titleLabel.font = [UIFont boldSystemFontOfSize:17]; + titleLabel.frame = CGRectMake(80, 0, self.tz_width - 80 - 50, self.tz_height); + titleLabel.textColor = [UIColor blackColor]; + titleLabel.textAlignment = NSTextAlignmentLeft; + [self.contentView addSubview:titleLabel]; + _titleLabel = titleLabel; + } + return _titleLabel; +} + +- (UIImageView *)arrowImageView { + if (_arrowImageView == nil) { + UIImageView *arrowImageView = [[UIImageView alloc] init]; + CGFloat arrowWH = 15; + arrowImageView.frame = CGRectMake(self.tz_width - arrowWH - 12, 28, arrowWH, arrowWH); + [arrowImageView setImage:[UIImage imageNamedFromMyBundle:@"TableViewArrow.png"]]; + [self.contentView addSubview:arrowImageView]; + _arrowImageView = arrowImageView; + } + return _arrowImageView; +} + +- (UIButton *)selectedCountButton { + if (_selectedCountButton == nil) { + UIButton *selectedCountButton = [[UIButton alloc] init]; + selectedCountButton.layer.cornerRadius = 12; + selectedCountButton.clipsToBounds = YES; + selectedCountButton.backgroundColor = [UIColor redColor]; + [selectedCountButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + selectedCountButton.titleLabel.font = [UIFont systemFontOfSize:15]; + [self.contentView addSubview:selectedCountButton]; + _selectedCountButton = selectedCountButton; + } + return _selectedCountButton; +} + +@end + + + +@implementation TZAssetCameraCell + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor whiteColor]; + _imageView = [[UIImageView alloc] init]; + _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500]; + _imageView.contentMode = UIViewContentModeScaleAspectFill; + [self addSubview:_imageView]; + self.clipsToBounds = YES; + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + _imageView.frame = self.bounds; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.h new file mode 100755 index 0000000..8fad470 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.h @@ -0,0 +1,46 @@ +// +// TZAssetModel.h +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> + +typedef enum : NSUInteger { + TZAssetModelMediaTypePhoto = 0, + TZAssetModelMediaTypeLivePhoto, + TZAssetModelMediaTypePhotoGif, + TZAssetModelMediaTypeVideo, + TZAssetModelMediaTypeAudio +} TZAssetModelMediaType; + +@class PHAsset; +@interface TZAssetModel : NSObject + +@property (nonatomic, strong) id asset; ///< PHAsset or ALAsset +@property (nonatomic, assign) BOOL isSelected; ///< The select status of a photo, default is No +@property (nonatomic, assign) TZAssetModelMediaType type; +@property (nonatomic, copy) NSString *timeLength; + +/// Init a photo dataModel With a asset +/// ���������PHAsset/ALAsset������������������������������������ ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type; ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength; + +@end + + +@class PHFetchResult; +@interface TZAlbumModel : NSObject + +@property (nonatomic, strong) NSString *name; ///< The album name +@property (nonatomic, assign) NSInteger count; ///< Count of photos the album contain +@property (nonatomic, strong) id result; ///< PHFetchResult<PHAsset> or ALAssetsGroup<ALAsset> + +@property (nonatomic, strong) NSArray *models; +@property (nonatomic, strong) NSArray *selectedModels; +@property (nonatomic, assign) NSUInteger selectedCount; +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.m new file mode 100755 index 0000000..7b21c78 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.m @@ -0,0 +1,66 @@ +// +// TZAssetModel.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import "TZAssetModel.h" +#import "TZImageManager.h" + +@implementation TZAssetModel + ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type{ + TZAssetModel *model = [[TZAssetModel alloc] init]; + model.asset = asset; + model.isSelected = NO; + model.type = type; + return model; +} + ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength { + TZAssetModel *model = [self modelWithAsset:asset type:type]; + model.timeLength = timeLength; + return model; +} + +@end + + + +@implementation TZAlbumModel + +- (void)setResult:(id)result { + _result = result; + BOOL allowPickingImage = [[[NSUserDefaults standardUserDefaults] objectForKey:@"tz_allowPickingImage"] isEqualToString:@"1"]; + BOOL allowPickingVideo = [[[NSUserDefaults standardUserDefaults] objectForKey:@"tz_allowPickingVideo"] isEqualToString:@"1"]; + [[TZImageManager manager] getAssetsFromFetchResult:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage completion:^(NSArray<TZAssetModel *> *models) { + _models = models; + if (_selectedModels) { + [self checkSelectedModels]; + } + }]; +} + +- (void)setSelectedModels:(NSArray *)selectedModels { + _selectedModels = selectedModels; + if (_models) { + [self checkSelectedModels]; + } +} + +- (void)checkSelectedModels { + self.selectedCount = 0; + NSMutableArray *selectedAssets = [NSMutableArray array]; + for (TZAssetModel *model in _selectedModels) { + [selectedAssets addObject:model.asset]; + } + for (TZAssetModel *model in _models) { + if ([[TZImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) { + self.selectedCount ++; + } + } +} + +@end \ No newline at end of file diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.h new file mode 100755 index 0000000..4ebb192 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.h @@ -0,0 +1,16 @@ +// +// TZGifPhotoPreviewController.h +// TZImagePickerController +// +// Created by ttouch on 2016/12/13. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@class TZAssetModel; +@interface TZGifPhotoPreviewController : UIViewController + +@property (nonatomic, strong) TZAssetModel *model; + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m new file mode 100755 index 0000000..514e5fa --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m @@ -0,0 +1,127 @@ +// +// TZGifPhotoPreviewController.m +// TZImagePickerController +// +// Created by ttouch on 2016/12/13. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import "TZGifPhotoPreviewController.h" +#import "TZImagePickerController.h" +#import "TZAssetModel.h" +#import "UIView+Layout.h" +#import "TZPhotoPreviewCell.h" +#import "TZImageManager.h" + +@interface TZGifPhotoPreviewController () { + UIView *_toolBar; + UIButton *_doneButton; + UIProgressView *_progress; + + TZPhotoPreviewView *_previewView; + + UIStatusBarStyle _originStatusBarStyle; +} +@end + +@implementation TZGifPhotoPreviewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor blackColor]; + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (tzImagePickerVc) { + self.navigationItem.title = [NSString stringWithFormat:@"GIF %@",tzImagePickerVc.previewBtnTitleStr]; + } + [self configPreviewView]; + [self configBottomToolBar]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; + [UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; +} + +- (void)configPreviewView { + _previewView = [[TZPhotoPreviewView alloc] initWithFrame:self.view.bounds]; + _previewView.scrollView.frame = self.view.bounds; + _previewView.model = self.model; + __weak typeof(self) weakSelf = self; + [_previewView setSingleTapGestureBlock:^{ + [weakSelf signleTapAction]; + }]; + [self.view addSubview:_previewView]; +} + +- (void)configBottomToolBar { + _toolBar = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.tz_height - 44, self.view.tz_width, 44)]; + CGFloat rgb = 34 / 255.0; + _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7]; + + _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44); + _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; + [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (tzImagePickerVc) { + [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; + } else { + [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal]; + [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal]; + } + [_toolBar addSubview:_doneButton]; + + UILabel *byteLabel = [[UILabel alloc] init]; + byteLabel.textColor = [UIColor whiteColor]; + byteLabel.font = [UIFont systemFontOfSize:13]; + byteLabel.frame = CGRectMake(10, 0, 100, 44); + [[TZImageManager manager] getPhotosBytesWithArray:@[_model] completion:^(NSString *totalBytes) { + byteLabel.text = totalBytes; + }]; + [_toolBar addSubview:byteLabel]; + + [self.view addSubview:_toolBar]; +} + +#pragma mark - Click Event + +- (void)signleTapAction { + _toolBar.hidden = !_toolBar.isHidden; + [self.navigationController setNavigationBarHidden:_toolBar.isHidden]; + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = _toolBar.isHidden; +} + +- (void)doneButtonClick { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + if (self.navigationController) { + if (imagePickerVc.autoDismiss) { + [self.navigationController dismissViewControllerAnimated:YES completion:^{ + [self callDelegateMethod]; + }]; + } + } else { + [self dismissViewControllerAnimated:YES completion:^{ + [self callDelegateMethod]; + }]; + } +} + +- (void)callDelegateMethod { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + UIImage *animatedImage = _previewView.imageView.image; + if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingGifImage:sourceAssets:)]) { + [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingGifImage:animatedImage sourceAssets:_model.asset]; + } + if (imagePickerVc.didFinishPickingGifImageHandle) { + imagePickerVc.didFinishPickingGifImageHandle(animatedImage,_model.asset); + } +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.h new file mode 100755 index 0000000..9dc1cc1 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.h @@ -0,0 +1,39 @@ +// +// TZImageCropManager.h +// TZImagePickerController +// +// Created by ������ on 2016/12/5. +// Copyright �� 2016��� ������. All rights reserved. +// ��������������������� + +#import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> + +@interface TZImageCropManager : NSObject + +/// ������������������������ ++ (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop; + +/* + 1.7.2 ������������������������������������������������������������������������������������������������ + ���������tuyou���PhotoTweaks������������������������������������������������������ + ���������������������������������������������������tuyou���PhotoTweaks������������������������������������ + ������tuyou���������github���������������������������PhotoTweaks��������������� + PhotoTweaks������github���������https://github.com/itouch2/PhotoTweaks + */ +/// ������������������������ ++ (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView; + +/// ������������������ ++ (UIImage *)circularClipImage:(UIImage *)image; + +@end + + +/// ������������������������SDWebImage:https://github.com/rs/SDWebImage +/// ������������������������������������������������������������������ +@interface UIImage (TZGif) + ++ (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data; + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.m new file mode 100755 index 0000000..6485a80 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.m @@ -0,0 +1,194 @@ +// +// TZImageCropManager.m +// TZImagePickerController +// +// Created by ������ on 2016/12/5. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import "TZImageCropManager.h" +#import "UIView+Layout.h" +#import <ImageIO/ImageIO.h> +#import "TZImageManager.h" + +@implementation TZImageCropManager + +/// ������������������������ ++ (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop { + UIBezierPath *path= [UIBezierPath bezierPathWithRect:[UIScreen mainScreen].bounds]; + CAShapeLayer *layer = [CAShapeLayer layer]; + if (needCircleCrop) { // ��������������� + [path appendPath:[UIBezierPath bezierPathWithArcCenter:containerView.center radius:cropRect.size.width / 2 startAngle:0 endAngle: 2 * M_PI clockwise:NO]]; + } else { // ��������������� + [path appendPath:[UIBezierPath bezierPathWithRect:cropRect]]; + } + layer.path = path.CGPath; + layer.fillRule = kCAFillRuleEvenOdd; + layer.fillColor = [[UIColor blackColor] CGColor]; + layer.opacity = 0.5; + [view.layer addSublayer:layer]; +} + +/// ������������������������ ++ (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView { + CGAffineTransform transform = CGAffineTransformIdentity; + // ��������������� + CGRect imageViewRect = [imageView convertRect:imageView.bounds toView:containerView]; + CGPoint point = CGPointMake(imageViewRect.origin.x + imageViewRect.size.width / 2, imageViewRect.origin.y + imageViewRect.size.height / 2); + CGFloat xMargin = containerView.tz_width - CGRectGetMaxX(rect) - rect.origin.x; + CGPoint zeroPoint = CGPointMake((CGRectGetWidth(containerView.frame) - xMargin) / 2, containerView.center.y); + CGPoint translation = CGPointMake(point.x - zeroPoint.x, point.y - zeroPoint.y); + transform = CGAffineTransformTranslate(transform, translation.x, translation.y); + // ��������������� + transform = CGAffineTransformScale(transform, zoomScale, zoomScale); + + CGImageRef imageRef = [self newTransformedImage:transform + sourceImage:imageView.image.CGImage + sourceSize:imageView.image.size + outputWidth:rect.size.width * [UIScreen mainScreen].scale + cropSize:rect.size + imageViewSize:imageView.frame.size]; + UIImage *cropedImage = [UIImage imageWithCGImage:imageRef]; + cropedImage = [[TZImageManager manager] fixOrientation:cropedImage]; + CGImageRelease(imageRef); + return cropedImage; +} + ++ (CGImageRef)newTransformedImage:(CGAffineTransform)transform sourceImage:(CGImageRef)sourceImage sourceSize:(CGSize)sourceSize outputWidth:(CGFloat)outputWidth cropSize:(CGSize)cropSize imageViewSize:(CGSize)imageViewSize { + CGImageRef source = [self newScaledImage:sourceImage toSize:sourceSize]; + + CGFloat aspect = cropSize.height/cropSize.width; + CGSize outputSize = CGSizeMake(outputWidth, outputWidth*aspect); + + CGContextRef context = CGBitmapContextCreate(NULL, outputSize.width, outputSize.height, CGImageGetBitsPerComponent(source), 0, CGImageGetColorSpace(source), CGImageGetBitmapInfo(source)); + CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]); + CGContextFillRect(context, CGRectMake(0, 0, outputSize.width, outputSize.height)); + + CGAffineTransform uiCoords = CGAffineTransformMakeScale(outputSize.width / cropSize.width, outputSize.height / cropSize.height); + uiCoords = CGAffineTransformTranslate(uiCoords, cropSize.width/2.0, cropSize.height / 2.0); + uiCoords = CGAffineTransformScale(uiCoords, 1.0, -1.0); + CGContextConcatCTM(context, uiCoords); + + CGContextConcatCTM(context, transform); + CGContextScaleCTM(context, 1.0, -1.0); + + CGContextDrawImage(context, CGRectMake(-imageViewSize.width/2, -imageViewSize.height/2.0, imageViewSize.width, imageViewSize.height), source); + CGImageRef resultRef = CGBitmapContextCreateImage(context); + CGContextRelease(context); + CGImageRelease(source); + return resultRef; +} + ++ (CGImageRef)newScaledImage:(CGImageRef)source toSize:(CGSize)size { + CGSize srcSize = size; + CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, rgbColorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); + CGColorSpaceRelease(rgbColorSpace); + + CGContextSetInterpolationQuality(context, kCGInterpolationNone); + CGContextTranslateCTM(context, size.width/2, size.height/2); + + CGContextDrawImage(context, CGRectMake(-srcSize.width/2, -srcSize.height/2, srcSize.width, srcSize.height), source); + + CGImageRef resultRef = CGBitmapContextCreateImage(context); + CGContextRelease(context); + return resultRef; +} + +/// ������������������ ++ (UIImage *)circularClipImage:(UIImage *)image { + UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale); + + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); + CGContextAddEllipseInRect(ctx, rect); + CGContextClip(ctx); + + [image drawInRect:rect]; + UIImage *circleImage = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + return circleImage; +} + +@end + + +@implementation UIImage (TZGif) + ++ (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data { + if (!data) { + return nil; + } + + CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); + + size_t count = CGImageSourceGetCount(source); + + UIImage *animatedImage; + + if (count <= 1) { + animatedImage = [[UIImage alloc] initWithData:data]; + } + else { + NSMutableArray *images = [NSMutableArray array]; + + NSTimeInterval duration = 0.0f; + + for (size_t i = 0; i < count; i++) { + CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); + if (!image) { + continue; + } + + duration += [self sd_frameDurationAtIndex:i source:source]; + + [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; + + CGImageRelease(image); + } + + if (!duration) { + duration = (1.0f / 10.0f) * count; + } + + animatedImage = [UIImage animatedImageWithImages:images duration:duration]; + } + + CFRelease(source); + + return animatedImage; +} + ++ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { + float frameDuration = 0.1f; + CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); + NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; + NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary]; + + NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; + if (delayTimeUnclampedProp) { + frameDuration = [delayTimeUnclampedProp floatValue]; + } + else { + + NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; + if (delayTimeProp) { + frameDuration = [delayTimeProp floatValue]; + } + } + + // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. + // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify + // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082> + // for more information. + + if (frameDuration < 0.011f) { + frameDuration = 0.100f; + } + + CFRelease(cfFrameProperties); + return frameDuration; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.h new file mode 100755 index 0000000..1f7aee6 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.h @@ -0,0 +1,96 @@ +// +// TZImageManager.h +// TZImagePickerController +// +// Created by ������ on 16/1/4. +// Copyright �� 2016��� ������. All rights reserved. +// ��������������������������� + +#import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> +#import <AVFoundation/AVFoundation.h> +#import <Photos/Photos.h> + +@class TZAlbumModel,TZAssetModel; +@interface TZImageManager : NSObject + +@property (nonatomic, strong) PHCachingImageManager *cachingImageManager; + ++ (instancetype)manager NS_SWIFT_NAME(default()); + +@property (nonatomic, assign) BOOL shouldFixOrientation; + +/// Default is 600px / ������600��������� +@property (nonatomic, assign) CGFloat photoPreviewMaxWidth; + +/// Default is 4, Use in photos collectionView in TZPhotoPickerController +/// ������4���, TZPhotoPickerController������������collectionView +@property (nonatomic, assign) NSInteger columnNumber; + +/// Sort photos ascending by modificationDate���Default is YES +/// ���������������������������������������������������YES������������������NO,������������������������������������������������������������������������������ +@property (nonatomic, assign) BOOL sortAscendingByModificationDate; + +/// Minimum selectable photo width, Default is 0 +/// ������������������������������������������0������������������������������������������ +@property (nonatomic, assign) NSInteger minPhotoWidthSelectable; +@property (nonatomic, assign) NSInteger minPhotoHeightSelectable; +@property (nonatomic, assign) BOOL hideWhenCanNotSelect; + +/// Return YES if Authorized ������YES��������������������� +- (BOOL)authorizationStatusAuthorized; +- (NSInteger)authorizationStatus; + +/// Get Album ������������/������������ +- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAlbumModel *model))completion; +- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAlbumModel *> *models))completion; + +/// Get Assets ������Asset������ +- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *models))completion; +- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *model))completion; + +/// Get photo ������������ +- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion; + +- (PHImageRequestID)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; +- (PHImageRequestID)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; +- (PHImageRequestID)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; +- (PHImageRequestID)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; + +/// Get full Image ������������ +/// ���������������������������������������������������������info[PHImageResultIsDegradedKey] ��� YES������������������������������������������������������������ +- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion; +- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; +- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion; + +/// Save photo ������������ +- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion; + +/// Get video ������������ +- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion; + +/// Export video ������������ +- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion; + +/// Get photo bytes ��������������������������� +- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion; + +/// Judge is a assets array contain the asset ������������assets������������������������asset +- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset; + +- (NSString *)getAssetIdentifier:(id)asset; +- (BOOL)isCameraRollAlbum:(NSString *)albumName; + +/// ������������������������������������������ +- (BOOL)isPhotoSelectableWithAsset:(id)asset; +- (CGSize)photoSizeWithAsset:(id)asset; + +/// ������������������ +- (UIImage *)fixOrientation:(UIImage *)aImage; + +@end + + +//@interface TZSortDescriptor : NSSortDescriptor +// +//@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.m new file mode 100755 index 0000000..9b8d731 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.m @@ -0,0 +1,940 @@ +// +// TZImageManager.m +// TZImagePickerController +// +// Created by ������ on 16/1/4. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import "TZImageManager.h" +#import <AssetsLibrary/AssetsLibrary.h> +#import "TZAssetModel.h" +#import "TZImagePickerController.h" + +@interface TZImageManager () +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +@property (nonatomic, strong) ALAssetsLibrary *assetLibrary; +@end + +@implementation TZImageManager + +static CGSize AssetGridThumbnailSize; +static CGFloat TZScreenWidth; +static CGFloat TZScreenScale; + ++ (instancetype)manager { + static TZImageManager *manager; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[self alloc] init]; + if (iOS8Later) { + manager.cachingImageManager = [[PHCachingImageManager alloc] init]; + // manager.cachingImageManager.allowsCachingHighQualityImages = YES; + } + + TZScreenWidth = [UIScreen mainScreen].bounds.size.width; + // ���������������������scale���plus���������������3.0������������������������������������������������2.0 + TZScreenScale = 2.0; + if (TZScreenWidth > 700) { + TZScreenScale = 1.5; + } + }); + return manager; +} + +- (void)setColumnNumber:(NSInteger)columnNumber { + _columnNumber = columnNumber; + CGFloat margin = 4; + CGFloat itemWH = (TZScreenWidth - 2 * margin - 4) / columnNumber - margin; + AssetGridThumbnailSize = CGSizeMake(itemWH * TZScreenScale, itemWH * TZScreenScale); +} + +- (ALAssetsLibrary *)assetLibrary { + if (_assetLibrary == nil) _assetLibrary = [[ALAssetsLibrary alloc] init]; + return _assetLibrary; +} + +/// Return YES if Authorized ������YES��������������������� +- (BOOL)authorizationStatusAuthorized { + NSInteger status = [self authorizationStatus]; + if (status == 0) { + /** + * ������������������AuthorizationStatus == AuthorizationStatusNotDetermined���������������������������������������������alertView���������������������������������������������������������������������������������������������������������������������������������alertView + */ + [self requestAuthorizationWhenNotDetermined]; + } + + return status == 3; +} + +- (NSInteger)authorizationStatus { + if (iOS8Later) { + return [PHPhotoLibrary authorizationStatus]; + } else { + return [ALAssetsLibrary authorizationStatus]; + } + return NO; +} + +//AuthorizationStatus == AuthorizationStatusNotDetermined ���������������������������������alertView +- (void)requestAuthorizationWhenNotDetermined { + if (iOS8Later) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { + dispatch_async(dispatch_get_main_queue(), ^{ + }); + }]; + }); + } else { + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { + } failureBlock:nil]; + } +} + +#pragma mark - Get Album + +/// Get Album ������������/������������ +- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAlbumModel *))completion{ + __block TZAlbumModel *model; + if (iOS8Later) { + PHFetchOptions *option = [[PHFetchOptions alloc] init]; + if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage]; + if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", + PHAssetMediaTypeVideo]; + // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]]; + if (!self.sortAscendingByModificationDate) { + option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]]; + } + PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; + for (PHAssetCollection *collection in smartAlbums) { + // ������������PHCollectionList��������������������������� + if (![collection isKindOfClass:[PHAssetCollection class]]) continue; + if ([self isCameraRollAlbum:collection.localizedTitle]) { + PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option]; + model = [self modelWithResult:fetchResult name:collection.localizedTitle]; + if (completion) completion(model); + break; + } + } + } else { + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { + if ([group numberOfAssets] < 1) return; + NSString *name = [group valueForProperty:ALAssetsGroupPropertyName]; + if ([self isCameraRollAlbum:name]) { + model = [self modelWithResult:group name:name]; + if (completion) completion(model); + *stop = YES; + } + } failureBlock:nil]; + } +} + +- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAlbumModel *> *))completion{ + NSMutableArray *albumArr = [NSMutableArray array]; + if (iOS8Later) { + PHFetchOptions *option = [[PHFetchOptions alloc] init]; + if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage]; + if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", + PHAssetMediaTypeVideo]; + // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]]; + if (!self.sortAscendingByModificationDate) { + option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]]; + } + // ��������������� 1.6.10������������.. + PHFetchResult *myPhotoStreamAlbum = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream options:nil]; + PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; + PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil]; + PHFetchResult *syncedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumSyncedAlbum options:nil]; + PHFetchResult *sharedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumCloudShared options:nil]; + NSArray *allAlbums = @[myPhotoStreamAlbum,smartAlbums,topLevelUserCollections,syncedAlbums,sharedAlbums]; + for (PHFetchResult *fetchResult in allAlbums) { + for (PHAssetCollection *collection in fetchResult) { + // ������������PHCollectionList��������������������������� + if (![collection isKindOfClass:[PHAssetCollection class]]) continue; + PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option]; + if (fetchResult.count < 1) continue; + if ([collection.localizedTitle containsString:@"Deleted"] || [collection.localizedTitle isEqualToString:@"������������"]) continue; + if ([self isCameraRollAlbum:collection.localizedTitle]) { + [albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle] atIndex:0]; + } else { + [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle]]; + } + } + } + if (completion && albumArr.count > 0) completion(albumArr); + } else { + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { + if (group == nil) { + if (completion && albumArr.count > 0) completion(albumArr); + } + if ([group numberOfAssets] < 1) return; + NSString *name = [group valueForProperty:ALAssetsGroupPropertyName]; + if ([self isCameraRollAlbum:name]) { + [albumArr insertObject:[self modelWithResult:group name:name] atIndex:0]; + } else if ([name isEqualToString:@"My Photo Stream"] || [name isEqualToString:@"���������������"]) { + if (albumArr.count) { + [albumArr insertObject:[self modelWithResult:group name:name] atIndex:1]; + } else { + [albumArr addObject:[self modelWithResult:group name:name]]; + } + } else { + [albumArr addObject:[self modelWithResult:group name:name]]; + } + } failureBlock:nil]; + } +} + +#pragma mark - Get Assets + +/// Get Assets ������������������ +- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *))completion { + NSMutableArray *photoArr = [NSMutableArray array]; + if ([result isKindOfClass:[PHFetchResult class]]) { + PHFetchResult *fetchResult = (PHFetchResult *)result; + [fetchResult enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + TZAssetModel *model = [self assetModelWithAsset:obj allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage]; + if (model) { + [photoArr addObject:model]; + } + }]; + if (completion) completion(photoArr); + } else if ([result isKindOfClass:[ALAssetsGroup class]]) { + ALAssetsGroup *group = (ALAssetsGroup *)result; + if (allowPickingImage && allowPickingVideo) { + [group setAssetsFilter:[ALAssetsFilter allAssets]]; + } else if (allowPickingVideo) { + [group setAssetsFilter:[ALAssetsFilter allVideos]]; + } else if (allowPickingImage) { + [group setAssetsFilter:[ALAssetsFilter allPhotos]]; + } + ALAssetsGroupEnumerationResultsBlock resultBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) { + if (result == nil) { + if (completion) completion(photoArr); + } + TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage]; + if (model) { + [photoArr addObject:model]; + } + }; + if (self.sortAscendingByModificationDate) { + [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { + if (resultBlock) { resultBlock(result,index,stop); } + }]; + } else { + [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { + if (resultBlock) { resultBlock(result,index,stop); } + }]; + } + } +} + +/// Get asset at index ���������������index��������������� +/// if index beyond bounds, return nil in callback ������������������, ������������������ nil +- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *))completion { + if ([result isKindOfClass:[PHFetchResult class]]) { + PHFetchResult *fetchResult = (PHFetchResult *)result; + PHAsset *asset; + @try { + asset = fetchResult[index]; + } + @catch (NSException* e) { + if (completion) completion(nil); + return; + } + TZAssetModel *model = [self assetModelWithAsset:asset allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage]; + if (completion) completion(model); + } else if ([result isKindOfClass:[ALAssetsGroup class]]) { + ALAssetsGroup *group = (ALAssetsGroup *)result; + if (allowPickingImage && allowPickingVideo) { + [group setAssetsFilter:[ALAssetsFilter allAssets]]; + } else if (allowPickingVideo) { + [group setAssetsFilter:[ALAssetsFilter allVideos]]; + } else if (allowPickingImage) { + [group setAssetsFilter:[ALAssetsFilter allPhotos]]; + } + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:index]; + @try { + [group enumerateAssetsAtIndexes:indexSet options:NSEnumerationConcurrent usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { + if (!result) return; + TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage]; + if (completion) completion(model); + }]; + } + @catch (NSException* e) { + if (completion) completion(nil); + } + } +} + +- (TZAssetModel *)assetModelWithAsset:(id)asset allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage { + TZAssetModel *model; + TZAssetModelMediaType type = TZAssetModelMediaTypePhoto; + if ([asset isKindOfClass:[PHAsset class]]) { + PHAsset *phAsset = (PHAsset *)asset; + if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo; + else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio; + else if (phAsset.mediaType == PHAssetMediaTypeImage) { + if (iOS9_1Later) { + // if (asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) type = TZAssetModelMediaTypeLivePhoto; + } + // Gif + if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) { + type = TZAssetModelMediaTypePhotoGif; + } + } + if (!allowPickingVideo && type == TZAssetModelMediaTypeVideo) return nil; + if (!allowPickingImage && type == TZAssetModelMediaTypePhoto) return nil; + if (!allowPickingImage && type == TZAssetModelMediaTypePhotoGif) return nil; + + if (self.hideWhenCanNotSelect) { + // ��������������������������������������� + if (![self isPhotoSelectableWithAsset:phAsset]) { + return nil; + } + } + NSString *timeLength = type == TZAssetModelMediaTypeVideo ? [NSString stringWithFormat:@"%0.0f",phAsset.duration] : @""; + timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue]; + model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength]; + } else { + if (!allowPickingVideo){ + model = [TZAssetModel modelWithAsset:asset type:type]; + return model; + } + /// Allow picking video + if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) { + type = TZAssetModelMediaTypeVideo; + NSTimeInterval duration = [[asset valueForProperty:ALAssetPropertyDuration] integerValue]; + NSString *timeLength = [NSString stringWithFormat:@"%0.0f",duration]; + timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue]; + model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength]; + } else { + if (self.hideWhenCanNotSelect) { + // ��������������������������������������� + if (![self isPhotoSelectableWithAsset:asset]) { + return nil; + } + } + model = [TZAssetModel modelWithAsset:asset type:type]; + } + } + return model; +} + +- (NSString *)getNewTimeFromDurationSecond:(NSInteger)duration { + NSString *newTime; + if (duration < 10) { + newTime = [NSString stringWithFormat:@"0:0%zd",duration]; + } else if (duration < 60) { + newTime = [NSString stringWithFormat:@"0:%zd",duration]; + } else { + NSInteger min = duration / 60; + NSInteger sec = duration - (min * 60); + if (sec < 10) { + newTime = [NSString stringWithFormat:@"%zd:0%zd",min,sec]; + } else { + newTime = [NSString stringWithFormat:@"%zd:%zd",min,sec]; + } + } + return newTime; +} + +/// Get photo bytes ��������������������������� +- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion { + __block NSInteger dataLength = 0; + __block NSInteger assetCount = 0; + for (NSInteger i = 0; i < photos.count; i++) { + TZAssetModel *model = photos[i]; + if ([model.asset isKindOfClass:[PHAsset class]]) { + [[PHImageManager defaultManager] requestImageDataForAsset:model.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { + if (model.type != TZAssetModelMediaTypeVideo) dataLength += imageData.length; + assetCount ++; + if (assetCount >= photos.count) { + NSString *bytes = [self getBytesFromDataLength:dataLength]; + if (completion) completion(bytes); + } + }]; + } else if ([model.asset isKindOfClass:[ALAsset class]]) { + ALAssetRepresentation *representation = [model.asset defaultRepresentation]; + if (model.type != TZAssetModelMediaTypeVideo) dataLength += (NSInteger)representation.size; + if (i >= photos.count - 1) { + NSString *bytes = [self getBytesFromDataLength:dataLength]; + if (completion) completion(bytes); + } + } + } +} + +- (NSString *)getBytesFromDataLength:(NSInteger)dataLength { + NSString *bytes; + if (dataLength >= 0.1 * (1024 * 1024)) { + bytes = [NSString stringWithFormat:@"%0.1fM",dataLength/1024/1024.0]; + } else if (dataLength >= 1024) { + bytes = [NSString stringWithFormat:@"%0.0fK",dataLength/1024.0]; + } else { + bytes = [NSString stringWithFormat:@"%zdB",dataLength]; + } + return bytes; +} + +#pragma mark - Get Photo + +/// Get photo ������������������ +- (PHImageRequestID)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *, NSDictionary *, BOOL isDegraded))completion { + CGFloat fullScreenWidth = TZScreenWidth; + if (fullScreenWidth > _photoPreviewMaxWidth) { + fullScreenWidth = _photoPreviewMaxWidth; + } + return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:nil networkAccessAllowed:YES]; +} + +- (PHImageRequestID)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion { + return [self getPhotoWithAsset:asset photoWidth:photoWidth completion:completion progressHandler:nil networkAccessAllowed:YES]; +} + +- (PHImageRequestID)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 { + CGFloat fullScreenWidth = TZScreenWidth; + if (fullScreenWidth > _photoPreviewMaxWidth) { + fullScreenWidth = _photoPreviewMaxWidth; + } + return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:progressHandler networkAccessAllowed:networkAccessAllowed]; +} + +- (PHImageRequestID)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 { + if ([asset isKindOfClass:[PHAsset class]]) { + CGSize imageSize; + if (photoWidth < TZScreenWidth && photoWidth < _photoPreviewMaxWidth) { + imageSize = AssetGridThumbnailSize; + } else { + PHAsset *phAsset = (PHAsset *)asset; + CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight; + CGFloat pixelWidth = photoWidth * TZScreenScale; + CGFloat pixelHeight = pixelWidth / aspectRatio; + imageSize = CGSizeMake(pixelWidth, pixelHeight); + } + // ������������������������������������������������������ + // ���������������������������hsjcom���������github������https://github.com/hsjcom ������������ + PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init]; + option.resizeMode = PHImageRequestOptionsResizeModeFast; + PHImageRequestID imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); + if (downloadFinined && result) { + result = [self fixOrientation:result]; + if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]); + } + // Download image from iCloud / ���iCloud������������ + if ([info objectForKey:PHImageResultIsInCloudKey] && !result && networkAccessAllowed) { + PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; + options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (progressHandler) { + progressHandler(progress, error, stop, info); + } + }); + }; + options.networkAccessAllowed = YES; + options.resizeMode = PHImageRequestOptionsResizeModeFast; + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { + UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1]; + resultImage = [self scaleImage:resultImage toSize:imageSize]; + if (resultImage) { + resultImage = [self fixOrientation:resultImage]; + if (completion) completion(resultImage,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]); + } + }]; + } + }]; + return imageRequestID; + } else if ([asset isKindOfClass:[ALAsset class]]) { + ALAsset *alAsset = (ALAsset *)asset; + dispatch_async(dispatch_get_global_queue(0,0), ^{ + CGImageRef thumbnailImageRef = alAsset.thumbnail; + UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnailImageRef scale:2.0 orientation:UIImageOrientationUp]; + dispatch_async(dispatch_get_main_queue(), ^{ + if (completion) completion(thumbnailImage,nil,YES); + + if (photoWidth == TZScreenWidth || photoWidth == _photoPreviewMaxWidth) { + dispatch_async(dispatch_get_global_queue(0,0), ^{ + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; + CGImageRef fullScrennImageRef = [assetRep fullScreenImage]; + UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp]; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (completion) completion(fullScrennImage,nil,NO); + }); + }); + } + }); + }); + } + return 0; +} + +/// Get postImage / ��������������� +- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *))completion { + if (iOS8Later) { + id asset = [model.result lastObject]; + if (!self.sortAscendingByModificationDate) { + asset = [model.result firstObject]; + } + [[TZImageManager manager] getPhotoWithAsset:asset photoWidth:80 completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { + if (completion) completion(photo); + }]; + } else { + ALAssetsGroup *group = model.result; + UIImage *postImage = [UIImage imageWithCGImage:group.posterImage]; + if (completion) completion(postImage); + } +} + +/// Get Original Photo / ������������ +- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion { + [self getOriginalPhotoWithAsset:asset newCompletion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { + if (completion) { + completion(photo,info); + } + }]; +} + +- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion { + if ([asset isKindOfClass:[PHAsset class]]) { + PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init]; + option.networkAccessAllowed = YES; + [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); + if (downloadFinined && result) { + result = [self fixOrientation:result]; + BOOL isDegraded = [[info objectForKey:PHImageResultIsDegradedKey] boolValue]; + if (completion) completion(result,info,isDegraded); + } + }]; + } else if ([asset isKindOfClass:[ALAsset class]]) { + ALAsset *alAsset = (ALAsset *)asset; + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; + + dispatch_async(dispatch_get_global_queue(0,0), ^{ + CGImageRef originalImageRef = [assetRep fullResolutionImage]; + UIImage *originalImage = [UIImage imageWithCGImage:originalImageRef scale:1.0 orientation:UIImageOrientationUp]; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (completion) completion(originalImage,nil,NO); + }); + }); + } +} + +- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion { + if ([asset isKindOfClass:[PHAsset class]]) { + PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init]; + option.networkAccessAllowed = YES; + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); + if (downloadFinined && imageData) { + BOOL isDegraded = [[info objectForKey:PHImageResultIsDegradedKey] boolValue]; + if (completion) completion(imageData,info,isDegraded); + } + }]; + } else if ([asset isKindOfClass:[ALAsset class]]) { + ALAsset *alAsset = (ALAsset *)asset; + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; + Byte *imageBuffer = (Byte *)malloc(assetRep.size); + NSUInteger bufferSize = [assetRep getBytes:imageBuffer fromOffset:0.0 length:assetRep.size error:nil]; + NSData *imageData = [NSData dataWithBytesNoCopy:imageBuffer length:bufferSize freeWhenDone:YES]; + if (completion) completion(imageData,nil,NO); + } +} + +#pragma mark - Save photo + +- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion { + NSData *data = UIImageJPEGRepresentation(image, 0.9); + if (iOS9Later) { // ������������... iOS8������������������������������������������ ���������������PHAssetResourceType���iOS9���������... + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ + PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init]; + options.shouldMoveFile = YES; + [[PHAssetCreationRequest creationRequestForAsset] addResourceWithType:PHAssetResourceTypePhoto data:data options:options]; + } completionHandler:^(BOOL success, NSError * _Nullable error) { + dispatch_sync(dispatch_get_main_queue(), ^{ + if (success && completion) { + completion(nil); + } else if (error) { + NSLog(@"������������������:%@",error.localizedDescription); + if (completion) { + completion(error); + } + } + }); + }]; + } else { + [self.assetLibrary writeImageToSavedPhotosAlbum:image.CGImage orientation:[self orientationFromImage:image] completionBlock:^(NSURL *assetURL, NSError *error) { + if (error) { + NSLog(@"������������������:%@",error.localizedDescription); + if (completion) { + completion(error); + } + } else { + // ������������0.5��������������������������������������������� + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + if (completion) { + completion(nil); + } + }); + } + }]; + } +} + +#pragma mark - Get Video + +/// Get Video / ������������ +- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * _Nullable, NSDictionary * _Nullable))completion { + if ([asset isKindOfClass:[PHAsset class]]) { + [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) { + if (completion) completion(playerItem,info); + }]; + } else if ([asset isKindOfClass:[ALAsset class]]) { + ALAsset *alAsset = (ALAsset *)asset; + ALAssetRepresentation *defaultRepresentation = [alAsset defaultRepresentation]; + NSString *uti = [defaultRepresentation UTI]; + NSURL *videoURL = [[asset valueForProperty:ALAssetPropertyURLs] valueForKey:uti]; + AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:videoURL]; + if (completion && playerItem) completion(playerItem,nil); + } +} + +#pragma mark - Export video + +/// Export Video / ������������ +- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion { + if ([asset isKindOfClass:[PHAsset class]]) { + PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init]; + options.version = PHVideoRequestOptionsVersionOriginal; + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic; + options.networkAccessAllowed = YES; + [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){ + // NSLog(@"Info:\n%@",info); + AVURLAsset *videoAsset = (AVURLAsset*)avasset; + // NSLog(@"AVAsset URL: %@",myAsset.URL); + [self startExportVideoWithVideoAsset:videoAsset completion:completion]; + }]; + } else if ([asset isKindOfClass:[ALAsset class]]) { + NSURL *videoURL =[asset valueForProperty:ALAssetPropertyAssetURL]; // ALAssetPropertyURLs + AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoURL options:nil]; + [self startExportVideoWithVideoAsset:videoAsset completion:completion]; + } +} + +- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset completion:(void (^)(NSString *outputPath))completion { + // Find compatible presets by video asset. + NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:videoAsset]; + + // Begin to compress video + // Now we just compress to low resolution if it supports + // If you need to upload to the server, but server does't support to upload by streaming, + // You can compress the resolution to lower. Or you can support more higher resolution. + if ([presets containsObject:AVAssetExportPreset640x480]) { + AVAssetExportSession *session = [[AVAssetExportSession alloc]initWithAsset:videoAsset presetName:AVAssetExportPreset640x480]; + + NSDateFormatter *formater = [[NSDateFormatter alloc] init]; + [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss"]; + NSString *outputPath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/output-%@.mp4", [formater stringFromDate:[NSDate date]]]; + NSLog(@"video outputPath = %@",outputPath); + session.outputURL = [NSURL fileURLWithPath:outputPath]; + + // Optimize for network use. + session.shouldOptimizeForNetworkUse = true; + + NSArray *supportedTypeArray = session.supportedFileTypes; + if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) { + session.outputFileType = AVFileTypeMPEG4; + } else if (supportedTypeArray.count == 0) { + NSLog(@"No supported file types ������������������������������"); + return; + } else { + session.outputFileType = [supportedTypeArray objectAtIndex:0]; + } + + if (![[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"]]) { + [[NSFileManager defaultManager] createDirectoryAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"] withIntermediateDirectories:YES attributes:nil error:nil]; + } + + AVMutableVideoComposition *videoComposition = [self fixedCompositionWithAsset:videoAsset]; + if (videoComposition.renderSize.width) { + // ������������������ + session.videoComposition = videoComposition; + } + + // Begin to export video to the output path asynchronously. + [session exportAsynchronouslyWithCompletionHandler:^(void) { + switch (session.status) { + case AVAssetExportSessionStatusUnknown: + NSLog(@"AVAssetExportSessionStatusUnknown"); break; + case AVAssetExportSessionStatusWaiting: + NSLog(@"AVAssetExportSessionStatusWaiting"); break; + case AVAssetExportSessionStatusExporting: + NSLog(@"AVAssetExportSessionStatusExporting"); break; + case AVAssetExportSessionStatusCompleted: { + NSLog(@"AVAssetExportSessionStatusCompleted"); + dispatch_async(dispatch_get_main_queue(), ^{ + if (completion) { + completion(outputPath); + } + }); + } break; + case AVAssetExportSessionStatusFailed: + NSLog(@"AVAssetExportSessionStatusFailed"); break; + default: break; + } + }]; + } +} + +/// Judge is a assets array contain the asset ������������assets������������������������asset +- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset { + if (iOS8Later) { + return [assets containsObject:asset]; + } else { + NSMutableArray *selectedAssetUrls = [NSMutableArray array]; + for (ALAsset *asset_item in assets) { + [selectedAssetUrls addObject:[asset_item valueForProperty:ALAssetPropertyURLs]]; + } + return [selectedAssetUrls containsObject:[asset valueForProperty:ALAssetPropertyURLs]]; + } +} + +- (BOOL)isCameraRollAlbum:(NSString *)albumName { + NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""]; + if (versionStr.length <= 1) { + versionStr = [versionStr stringByAppendingString:@"00"]; + } else if (versionStr.length <= 2) { + versionStr = [versionStr stringByAppendingString:@"0"]; + } + CGFloat version = versionStr.floatValue; + // ������������8.0.0 - 8.0.2������������������������������������������������������ + if (version >= 800 && version <= 802) { + return [albumName isEqualToString:@"������������"] || [albumName isEqualToString:@"Recently Added"]; + } else { + return [albumName isEqualToString:@"Camera Roll"] || [albumName isEqualToString:@"������������"] || [albumName isEqualToString:@"������������"] || [albumName isEqualToString:@"All Photos"]; + } +} + +- (NSString *)getAssetIdentifier:(id)asset { + if (iOS8Later) { + PHAsset *phAsset = (PHAsset *)asset; + return phAsset.localIdentifier; + } else { + ALAsset *alAsset = (ALAsset *)asset; + NSURL *assetUrl = [alAsset valueForProperty:ALAssetPropertyAssetURL]; + return assetUrl.absoluteString; + } +} + +/// ������������������������������������������ +- (BOOL)isPhotoSelectableWithAsset:(id)asset { + CGSize photoSize = [self photoSizeWithAsset:asset]; + if (self.minPhotoWidthSelectable > photoSize.width || self.minPhotoHeightSelectable > photoSize.height) { + return NO; + } + return YES; +} + +- (CGSize)photoSizeWithAsset:(id)asset { + if (iOS8Later) { + PHAsset *phAsset = (PHAsset *)asset; + return CGSizeMake(phAsset.pixelWidth, phAsset.pixelHeight); + } else { + ALAsset *alAsset = (ALAsset *)asset; + return alAsset.defaultRepresentation.dimensions; + } +} + +#pragma mark - Private Method + +- (TZAlbumModel *)modelWithResult:(id)result name:(NSString *)name{ + TZAlbumModel *model = [[TZAlbumModel alloc] init]; + model.result = result; + model.name = name; + if ([result isKindOfClass:[PHFetchResult class]]) { + PHFetchResult *fetchResult = (PHFetchResult *)result; + model.count = fetchResult.count; + } else if ([result isKindOfClass:[ALAssetsGroup class]]) { + ALAssetsGroup *group = (ALAssetsGroup *)result; + model.count = [group numberOfAssets]; + } + return model; +} + +- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size { + if (image.size.width > size.width) { + UIGraphicsBeginImageContext(size); + [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return newImage; + } else { + return image; + } +} + +- (ALAssetOrientation)orientationFromImage:(UIImage *)image { + NSInteger orientation = image.imageOrientation; + return orientation; +} + +/// ������������������������������������ +- (AVMutableVideoComposition *)fixedCompositionWithAsset:(AVAsset *)videoAsset { + AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; + // ������������ + int degrees = [self degressFromVideoFileWithAsset:videoAsset]; + if (degrees != 0) { + CGAffineTransform translateToCenter; + CGAffineTransform mixedTransform; + videoComposition.frameDuration = CMTimeMake(1, 30); + + NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeVideo]; + AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; + + if (degrees == 90) { + // ���������������90�� + translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.height, 0.0); + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2); + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width); + } else if(degrees == 180){ + // ���������������180�� + translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.width, videoTrack.naturalSize.height); + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI); + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.width,videoTrack.naturalSize.height); + } else if(degrees == 270){ + // ���������������270�� + translateToCenter = CGAffineTransformMakeTranslation(0.0, videoTrack.naturalSize.width); + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2*3.0); + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width); + } + + AVMutableVideoCompositionInstruction *roateInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; + roateInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [videoAsset duration]); + AVMutableVideoCompositionLayerInstruction *roateLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; + + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero]; + + roateInstruction.layerInstructions = @[roateLayerInstruction]; + // ������������������������ + videoComposition.instructions = @[roateInstruction]; + } + return videoComposition; +} + +/// ������������������ +- (int)degressFromVideoFileWithAsset:(AVAsset *)asset { + int degress = 0; + NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; + if([tracks count] > 0) { + AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; + CGAffineTransform t = videoTrack.preferredTransform; + if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){ + // Portrait + degress = 90; + } else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){ + // PortraitUpsideDown + degress = 270; + } else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){ + // LandscapeRight + degress = 0; + } else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){ + // LandscapeLeft + degress = 180; + } + } + return degress; +} + +/// ������������������ +- (UIImage *)fixOrientation:(UIImage *)aImage { + if (!self.shouldFixOrientation) return aImage; + + // No-op if the orientation is already correct + if (aImage.imageOrientation == UIImageOrientationUp) + return aImage; + + // We need to calculate the proper transformation to make the image upright. + // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. + CGAffineTransform transform = CGAffineTransformIdentity; + + switch (aImage.imageOrientation) { + case UIImageOrientationDown: + case UIImageOrientationDownMirrored: + transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height); + transform = CGAffineTransformRotate(transform, M_PI); + break; + + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); + transform = CGAffineTransformRotate(transform, M_PI_2); + break; + + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + transform = CGAffineTransformTranslate(transform, 0, aImage.size.height); + transform = CGAffineTransformRotate(transform, -M_PI_2); + break; + default: + break; + } + + switch (aImage.imageOrientation) { + case UIImageOrientationUpMirrored: + case UIImageOrientationDownMirrored: + transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + + case UIImageOrientationLeftMirrored: + case UIImageOrientationRightMirrored: + transform = CGAffineTransformTranslate(transform, aImage.size.height, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + default: + break; + } + + // Now we draw the underlying CGImage into a new context, applying the transform + // calculated above. + CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height, + CGImageGetBitsPerComponent(aImage.CGImage), 0, + CGImageGetColorSpace(aImage.CGImage), + CGImageGetBitmapInfo(aImage.CGImage)); + CGContextConcatCTM(ctx, transform); + switch (aImage.imageOrientation) { + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + // Grr... + CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage); + break; + + default: + CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage); + break; + } + + // And now we just create a new UIImage from the drawing context + CGImageRef cgimg = CGBitmapContextCreateImage(ctx); + UIImage *img = [UIImage imageWithCGImage:cgimg]; + CGContextRelease(ctx); + CGImageRelease(cgimg); + return img; +} +#pragma clang diagnostic pop + +@end + + +//@implementation TZSortDescriptor +// +//- (id)reversedSortDescriptor { +// return [NSNumber numberWithBool:![TZImageManager manager].sortAscendingByModificationDate]; +//} +// +//@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png new file mode 100755 index 0000000..7a51372 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png new file mode 100755 index 0000000..ffcadc1 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/Root.plist b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/Root.plist new file mode 100755 index 0000000..b1b6fea --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/Root.plist @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>StringsTable</key> + <string>Root</string> + <key>PreferenceSpecifiers</key> + <array> + <dict> + <key>Type</key> + <string>PSGroupSpecifier</string> + <key>Title</key> + <string>Group</string> + </dict> + <dict> + <key>Type</key> + <string>PSTextFieldSpecifier</string> + <key>Title</key> + <string>Name</string> + <key>Key</key> + <string>name_preference</string> + <key>DefaultValue</key> + <string></string> + <key>IsSecure</key> + <false/> + <key>KeyboardType</key> + <string>Alphabet</string> + <key>AutocapitalizationType</key> + <string>None</string> + <key>AutocorrectionType</key> + <string>No</string> + </dict> + <dict> + <key>Type</key> + <string>PSToggleSwitchSpecifier</string> + <key>Title</key> + <string>Enabled</string> + <key>Key</key> + <string>enabled_preference</string> + <key>DefaultValue</key> + <true/> + </dict> + <dict> + <key>Type</key> + <string>PSSliderSpecifier</string> + <key>Key</key> + <string>slider_preference</string> + <key>DefaultValue</key> + <real>0.5</real> + <key>MinimumValue</key> + <integer>0</integer> + <key>MaximumValue</key> + <integer>1</integer> + <key>MinimumValueImage</key> + <string></string> + <key>MaximumValueImage</key> + <string></string> + </dict> + </array> +</dict> +</plist> diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/TableViewArrow@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/TableViewArrow@2x.png new file mode 100755 index 0000000..eb8f505 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/TableViewArrow@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png new file mode 100755 index 0000000..110543a --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings new file mode 100755 index 0000000..ef699fa --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/navi_back@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/navi_back@2x.png new file mode 100755 index 0000000..633b9e6 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/navi_back@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png new file mode 100755 index 0000000..1415cae --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png new file mode 100755 index 0000000..1415cae --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png new file mode 100755 index 0000000..789335b --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png new file mode 100755 index 0000000..c9792ef --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png new file mode 100755 index 0000000..8889b13 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png new file mode 100755 index 0000000..57012cb --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png new file mode 100755 index 0000000..827c794 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png new file mode 100755 index 0000000..789335b --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png new file mode 100755 index 0000000..9476d15 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/takePicture@2x.png b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/takePicture@2x.png new file mode 100755 index 0000000..2697e7f --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/takePicture@2x.png Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings new file mode 100755 index 0000000..ffe35b9 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings Binary files differ diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.h new file mode 100755 index 0000000..ad653b5 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.h @@ -0,0 +1,214 @@ +// +// TZImagePickerController.h +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// version 1.7.8 - 2016.12.20 + +/* + ���������������������xib���������������TZAssetCell������������������������������������������������������������������������10������������ + + ���������������������������������������@������������������������������������������: http://zhoulingyu.com/ + ������������~ + + ������xib������������������������������...���������������������... + */ + +#import <UIKit/UIKit.h> +#import "TZAssetModel.h" +#import "NSBundle+TZImagePicker.h" + +#define iOS7Later ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f) +#define iOS8Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f) +#define iOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f) +#define iOS9_1Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f) + +@protocol TZImagePickerControllerDelegate; +@interface TZImagePickerController : UINavigationController + +/// Use this init method / ������������������������ +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate; +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate; +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc; +/// This init method just for previewing photos / ��������������������������������������� +- (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index; +/// This init method for crop photo / ��������������������������������������� +- (instancetype)initCropTypeWithAsset:(id)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,id asset))completion; + +/// Default is 9 / ������������������9��������� +@property (nonatomic, assign) NSInteger maxImagesCount; + +/// The minimum count photos user must pick, Default is 0 +/// ������������������������,���������0 +@property (nonatomic, assign) NSInteger minImagesCount; + +/// Always enale the done button, not require minimum 1 photo be picked +/// ������������������������������������������������������������������ +@property (nonatomic, assign) BOOL alwaysEnableDoneBtn; + +/// Sort photos ascending by modificationDate���Default is YES +/// ���������������������������������������������������YES������������������NO,������������������������������������������������������������������������������ +@property (nonatomic, assign) BOOL sortAscendingByModificationDate; + +/// Default is 828px / ������828��������� +@property (nonatomic, assign) CGFloat photoWidth; + +/// Default is 600px / ������600��������� +@property (nonatomic, assign) CGFloat photoPreviewMaxWidth; + +/// Default is 15, While fetching photo, HUD will dismiss automatic if timeout; +/// ������������������������15������������������������������15������������������������������������dismiss HUD��� +@property (nonatomic, assign) NSInteger timeout; + +/// Default is YES, if set NO, the original photo button will hide. user can't picking original photo. +/// ���������YES������������������NO,������������������������������������������������������ +@property (nonatomic, assign) BOOL allowPickingOriginalPhoto; + +/// Default is YES, if set NO, user can't picking video. +/// ���������YES������������������NO,��������������������������� +@property (nonatomic, assign) BOOL allowPickingVideo; + +/// Default is NO, if set YES, user can picking gif image. +/// ���������NO������������������YES,������������������gif������ +@property (nonatomic, assign) BOOL allowPickingGif; + +/// Default is YES, if set NO, user can't picking image. +/// ���������YES������������������NO,��������������������������������� +@property(nonatomic, assign) BOOL allowPickingImage; + +/// Default is YES, if set NO, user can't take picture. +/// ���������YES������������������NO,���������������������,��������������������������� +@property(nonatomic, assign) BOOL allowTakePicture; + +/// Default is YES, if set NO, user can't preview photo. +/// ���������YES������������������NO,���������������������,������������������������������ +@property (nonatomic, assign) BOOL allowPreview; + +/// Default is YES, if set NO, the picker don't dismiss itself. +/// ���������YES������������������NO, ������������������������dismiss +@property(nonatomic, assign) BOOL autoDismiss; + +/// The photos user have selected +/// ������������������������������ +@property (nonatomic, strong) NSMutableArray *selectedAssets; +@property (nonatomic, strong) NSMutableArray<TZAssetModel *> *selectedModels; + +/// Minimum selectable photo width, Default is 0 +/// ������������������������������������������0������������������������������������������ +@property (nonatomic, assign) NSInteger minPhotoWidthSelectable; +@property (nonatomic, assign) NSInteger minPhotoHeightSelectable; +/// Hide the photo what can not be selected, Default is NO +/// ������������������������������������������NO���������������������������YES +@property (nonatomic, assign) BOOL hideWhenCanNotSelect; + +/// Single selection mode, valid when maxImagesCount = 1 +/// ������������,maxImagesCount���1������������ +@property (nonatomic, assign) BOOL showSelectBtn; ///< ������������������������������������������������������������,���������NO +@property (nonatomic, assign) BOOL allowCrop; ///< ������������,���������YES���showSelectBtn���NO��������� +@property (nonatomic, assign) CGRect cropRect; ///< ������������������ +@property (nonatomic, assign) BOOL needCircleCrop; ///< ��������������������� +@property (nonatomic, assign) NSInteger circleCropRadius; ///< ��������������������������� +@property (nonatomic, copy) void (^cropViewSettingBlock)(UIView *cropView); ///< ��������������������������������� + +- (void)showAlertWithTitle:(NSString *)title; +- (void)showProgressHUD; +- (void)hideProgressHUD; +@property (nonatomic, assign) BOOL isSelectOriginalPhoto; + +@property (nonatomic, copy) NSString *takePictureImageName; +@property (nonatomic, copy) NSString *photoSelImageName; +@property (nonatomic, copy) NSString *photoDefImageName; +@property (nonatomic, copy) NSString *photoOriginSelImageName; +@property (nonatomic, copy) NSString *photoOriginDefImageName; +@property (nonatomic, copy) NSString *photoPreviewOriginDefImageName; +@property (nonatomic, copy) NSString *photoNumberIconImageName; + +/// Appearance / ������������ + ������������ +@property (nonatomic, strong) UIColor *oKButtonTitleColorNormal; +@property (nonatomic, strong) UIColor *oKButtonTitleColorDisabled; +@property (nonatomic, strong) UIColor *naviBgColor; +@property (nonatomic, strong) UIColor *naviTitleColor; +@property (nonatomic, strong) UIFont *naviTitleFont; +@property (nonatomic, strong) UIColor *barItemTextColor; +@property (nonatomic, strong) UIFont *barItemTextFont; + +@property (nonatomic, copy) NSString *doneBtnTitleStr; +@property (nonatomic, copy) NSString *cancelBtnTitleStr; +@property (nonatomic, copy) NSString *previewBtnTitleStr; +@property (nonatomic, copy) NSString *fullImageBtnTitleStr; +@property (nonatomic, copy) NSString *settingBtnTitleStr; +@property (nonatomic, copy) NSString *processHintStr; + +/// Public Method +- (void)cancelButtonClick; + +// The picker should dismiss itself; when it dismissed these handle will be called. +// You can also set autoDismiss to NO, then the picker don't dismiss itself. +// If isOriginalPhoto is YES, user picked the original photo. +// You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:]. +// The UIImage Object in photos default width is 828px, you can set it by photoWidth property. +// ������������������������������dismiss���������������dismiss������������������������������handle +// ������������������autoDismiss���������NO���������������������������dismis��� +// ������isSelectOriginalPhoto���YES������������������������������ +// ���������������������asset������������������������������������[[TZImageManager manager] getOriginalPhotoWithAsset:completion:] +// photos������������UIImage������������������828���������������������������������photoWidth������������������������ +@property (nonatomic, copy) void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto); +@property (nonatomic, copy) void (^didFinishPickingPhotosWithInfosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto,NSArray<NSDictionary *> *infos); +@property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)(); + +// If user picking a video, this handle will be called. +// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class. +// ���������������������������������������������handle������������ +// ������������������������iOS8���asset���PHAsset������������������������ALAsset������������ +@property (nonatomic, copy) void (^didFinishPickingVideoHandle)(UIImage *coverImage,id asset); + +// If user picking a gif image, this callback will be called. +// ���������������������������gif������������������handle������������ +@property (nonatomic, copy) void (^didFinishPickingGifImageHandle)(UIImage *animatedImage,id sourceAssets); + +@property (nonatomic, weak) id<TZImagePickerControllerDelegate> pickerDelegate; + +@end + + +@protocol TZImagePickerControllerDelegate <NSObject> +@optional +// The picker should dismiss itself; when it dismissed these handle will be called. +// You can also set autoDismiss to NO, then the picker don't dismiss itself. +// If isOriginalPhoto is YES, user picked the original photo. +// You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:]. +// The UIImage Object in photos default width is 828px, you can set it by photoWidth property. +// ������������������������������dismiss���������������dismiss������������������������������handle +// ������������������autoDismiss���������NO���������������������������dismis��� +// ������isSelectOriginalPhoto���YES������������������������������ +// ���������������������asset������������������������������������[[TZImageManager manager] getOriginalPhotoWithAsset:completion:] +// photos������������UIImage������������������828���������������������������������photoWidth������������������������ +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto; +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray<NSDictionary *> *)infos; +- (void)imagePickerControllerDidCancel:(TZImagePickerController *)picker __attribute__((deprecated("Use -tz_imagePickerControllerDidCancel:."))); +- (void)tz_imagePickerControllerDidCancel:(TZImagePickerController *)picker; + +// If user picking a video, this callback will be called. +// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class. +// ���������������������������������������������handle������������ +// ������������������������iOS8���asset���PHAsset������������������������ALAsset������������ +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(id)asset; + +// If user picking a gif image, this callback will be called. +// ���������������������������gif������������������handle������������ +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingGifImage:(UIImage *)animatedImage sourceAssets:(id)asset; +@end + + +@interface TZAlbumPickerController : UIViewController +@property (nonatomic, assign) NSInteger columnNumber; +@end + + +@interface UIImage (MyBundle) + ++ (UIImage *)imageNamedFromMyBundle:(NSString *)name; + +@end + diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.m new file mode 100755 index 0000000..28ded3a --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.m @@ -0,0 +1,616 @@ +// +// TZImagePickerController.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// version 1.7.8 - 2016.12.20 + +#import "TZImagePickerController.h" +#import "TZPhotoPickerController.h" +#import "TZPhotoPreviewController.h" +#import "TZAssetModel.h" +#import "TZAssetCell.h" +#import "UIView+Layout.h" +#import "TZImageManager.h" + +@interface TZImagePickerController () { + NSTimer *_timer; + UILabel *_tipLabel; + UIButton *_settingBtn; + BOOL _pushPhotoPickerVc; + BOOL _didPushPhotoPickerVc; + + UIButton *_progressHUD; + UIView *_HUDContainer; + UIActivityIndicatorView *_HUDIndicatorView; + UILabel *_HUDLabel; + + UIStatusBarStyle _originStatusBarStyle; +} +/// Default is 4, Use in photos collectionView in TZPhotoPickerController +/// ������4���, TZPhotoPickerController������������collectionView +@property (nonatomic, assign) NSInteger columnNumber; +@end + +@implementation TZImagePickerController + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor whiteColor]; + self.navigationBar.barStyle = UIBarStyleBlack; + self.navigationBar.translucent = YES; + [TZImageManager manager].shouldFixOrientation = NO; + + // Default appearance, you can reset these after this method + // ��������������������������������������������������� + self.oKButtonTitleColorNormal = [UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0]; + self.oKButtonTitleColorDisabled = [UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:0.5]; + + if (iOS7Later) { + self.navigationBar.barTintColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:1.0]; + self.navigationBar.tintColor = [UIColor whiteColor]; + self.automaticallyAdjustsScrollViewInsets = NO; + } +} + +- (void)setNaviBgColor:(UIColor *)naviBgColor { + _naviBgColor = naviBgColor; + self.navigationBar.barTintColor = naviBgColor; +} + +- (void)setNaviTitleColor:(UIColor *)naviTitleColor { + _naviTitleColor = naviTitleColor; + [self configNaviTitleAppearance]; +} + +- (void)setNaviTitleFont:(UIFont *)naviTitleFont { + _naviTitleFont = naviTitleFont; + [self configNaviTitleAppearance]; +} + +- (void)configNaviTitleAppearance { + NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary]; + textAttrs[NSForegroundColorAttributeName] = self.naviTitleColor; + textAttrs[NSFontAttributeName] = self.naviTitleFont; + self.navigationBar.titleTextAttributes = textAttrs; +} + +- (void)setBarItemTextFont:(UIFont *)barItemTextFont { + _barItemTextFont = barItemTextFont; + [self configBarButtonItemAppearance]; +} + +- (void)setBarItemTextColor:(UIColor *)barItemTextColor { + _barItemTextColor = barItemTextColor; + [self configBarButtonItemAppearance]; +} + +- (void)configBarButtonItemAppearance { + UIBarButtonItem *barItem; + if (iOS9Later) { + barItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]]; + } else { + barItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil]; + } + NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary]; + textAttrs[NSForegroundColorAttributeName] = self.barItemTextColor; + textAttrs[NSFontAttributeName] = self.barItemTextFont; + [barItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; + [UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; + [self hideProgressHUD]; +} + +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate { + return [self initWithMaxImagesCount:maxImagesCount columnNumber:4 delegate:delegate pushPhotoPickerVc:YES]; +} + +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate { + return [self initWithMaxImagesCount:maxImagesCount columnNumber:columnNumber delegate:delegate pushPhotoPickerVc:YES]; +} + +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc { + _pushPhotoPickerVc = pushPhotoPickerVc; + TZAlbumPickerController *albumPickerVc = [[TZAlbumPickerController alloc] init]; + albumPickerVc.columnNumber = columnNumber; + self = [super initWithRootViewController:albumPickerVc]; + if (self) { + self.maxImagesCount = maxImagesCount > 0 ? maxImagesCount : 9; // Default is 9 / ������������������9��������� + self.pickerDelegate = delegate; + self.selectedModels = [NSMutableArray array]; + + // Allow user picking original photo and video, you also can set No after this method + // ���������������������������������������, ������������������������������������NO + self.allowPickingOriginalPhoto = YES; + self.allowPickingVideo = YES; + self.allowPickingImage = YES; + self.allowTakePicture = YES; + self.sortAscendingByModificationDate = YES; + self.autoDismiss = YES; + self.columnNumber = columnNumber; + [self configDefaultSetting]; + + if (![[TZImageManager manager] authorizationStatusAuthorized]) { + _tipLabel = [[UILabel alloc] init]; + _tipLabel.frame = CGRectMake(8, 120, self.view.tz_width - 16, 60); + _tipLabel.textAlignment = NSTextAlignmentCenter; + _tipLabel.numberOfLines = 0; + _tipLabel.font = [UIFont systemFontOfSize:16]; + _tipLabel.textColor = [UIColor blackColor]; + NSString *appName = [[NSBundle mainBundle].infoDictionary valueForKey:@"CFBundleDisplayName"]; + if (!appName) appName = [[NSBundle mainBundle].infoDictionary valueForKey:@"CFBundleName"]; + NSString *tipText = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Allow %@ to access your album in \"Settings -> Privacy -> Photos\""],appName]; + _tipLabel.text = tipText; + [self.view addSubview:_tipLabel]; + + _settingBtn = [UIButton buttonWithType:UIButtonTypeSystem]; + [_settingBtn setTitle:self.settingBtnTitleStr forState:UIControlStateNormal]; + _settingBtn.frame = CGRectMake(0, 180, self.view.tz_width, 44); + _settingBtn.titleLabel.font = [UIFont systemFontOfSize:18]; + [_settingBtn addTarget:self action:@selector(settingBtnClick) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:_settingBtn]; + + _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:YES]; + } else { + [self pushPhotoPickerVc]; + } + } + return self; +} + +/// This init method just for previewing photos / ��������������������������������������� +- (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index{ + TZPhotoPreviewController *previewVc = [[TZPhotoPreviewController alloc] init]; + self = [super initWithRootViewController:previewVc]; + if (self) { + self.selectedAssets = [NSMutableArray arrayWithArray:selectedAssets]; + self.allowPickingOriginalPhoto = self.allowPickingOriginalPhoto; + [self configDefaultSetting]; + + previewVc.photos = [NSMutableArray arrayWithArray:selectedPhotos]; + previewVc.currentIndex = index; + __weak typeof(self) weakSelf = self; + [previewVc setDoneButtonClickBlockWithPreviewType:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) { + [weakSelf dismissViewControllerAnimated:YES completion:^{ + if (weakSelf.didFinishPickingPhotosHandle) { + weakSelf.didFinishPickingPhotosHandle(photos,assets,isSelectOriginalPhoto); + } + }]; + }]; + } + return self; +} + +/// This init method for crop photo / ��������������������������������������� +- (instancetype)initCropTypeWithAsset:(id)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,id asset))completion { + TZPhotoPreviewController *previewVc = [[TZPhotoPreviewController alloc] init]; + self = [super initWithRootViewController:previewVc]; + if (self) { + self.maxImagesCount = 1; + self.allowCrop = YES; + self.selectedAssets = [NSMutableArray arrayWithArray:@[asset]]; + [self configDefaultSetting]; + + previewVc.photos = [NSMutableArray arrayWithArray:@[photo]]; + previewVc.isCropImage = YES; + previewVc.currentIndex = 0; + __weak typeof(self) weakSelf = self; + [previewVc setDoneButtonClickBlockCropMode:^(UIImage *cropImage, id asset) { + [weakSelf dismissViewControllerAnimated:YES completion:^{ + if (completion) { + completion(cropImage,asset); + } + }]; + }]; + } + return self; +} + +- (void)configDefaultSetting { + self.timeout = 15; + self.photoWidth = 828.0; + self.photoPreviewMaxWidth = 600; + self.naviTitleColor = [UIColor whiteColor]; + self.naviTitleFont = [UIFont systemFontOfSize:17]; + self.barItemTextFont = [UIFont systemFontOfSize:15]; + self.barItemTextColor = [UIColor whiteColor]; + self.allowPreview = YES; + + [self configDefaultImageName]; + [self configDefaultBtnTitle]; +} + +- (void)configDefaultImageName { + self.takePictureImageName = @"takePicture.png"; + self.photoSelImageName = @"photo_sel_photoPickerVc.png"; + self.photoDefImageName = @"photo_def_photoPickerVc.png"; + self.photoNumberIconImageName = @"photo_number_icon.png"; + self.photoPreviewOriginDefImageName = @"preview_original_def.png"; + self.photoOriginDefImageName = @"photo_original_def.png"; + self.photoOriginSelImageName = @"photo_original_sel.png"; +} + +- (void)configDefaultBtnTitle { + self.doneBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Done"]; + self.cancelBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Cancel"]; + self.previewBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Preview"]; + self.fullImageBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Full image"]; + self.settingBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Setting"]; + self.processHintStr = [NSBundle tz_localizedStringForKey:@"Processing..."]; +} + +- (void)observeAuthrizationStatusChange { + if ([[TZImageManager manager] authorizationStatusAuthorized]) { + [_tipLabel removeFromSuperview]; + [_settingBtn removeFromSuperview]; + [_timer invalidate]; + _timer = nil; + [self pushPhotoPickerVc]; + } +} + +- (void)pushPhotoPickerVc { + _didPushPhotoPickerVc = NO; + // 1.6.8 ������������������push���������������������������_pushPhotoPickerVc���NO,������push + if (!_didPushPhotoPickerVc && _pushPhotoPickerVc) { + TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init]; + photoPickerVc.isFirstAppear = YES; + photoPickerVc.columnNumber = self.columnNumber; + [[TZImageManager manager] getCameraRollAlbum:self.allowPickingVideo allowPickingImage:self.allowPickingImage completion:^(TZAlbumModel *model) { + photoPickerVc.model = model; + [self pushViewController:photoPickerVc animated:YES]; + _didPushPhotoPickerVc = YES; + }]; + } +} + +- (void)showAlertWithTitle:(NSString *)title { + if (iOS8Later) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert]; + [alertController addAction:[UIAlertAction actionWithTitle:[NSBundle tz_localizedStringForKey:@"OK"] style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alertController animated:YES completion:nil]; + } else { + [[[UIAlertView alloc] initWithTitle:title message:nil delegate:nil cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"OK"] otherButtonTitles:nil, nil] show]; + } +} + +- (void)showProgressHUD { + if (!_progressHUD) { + _progressHUD = [UIButton buttonWithType:UIButtonTypeCustom]; + [_progressHUD setBackgroundColor:[UIColor clearColor]]; + + _HUDContainer = [[UIView alloc] init]; + _HUDContainer.frame = CGRectMake((self.view.tz_width - 120) / 2, (self.view.tz_height - 90) / 2, 120, 90); + _HUDContainer.layer.cornerRadius = 8; + _HUDContainer.clipsToBounds = YES; + _HUDContainer.backgroundColor = [UIColor darkGrayColor]; + _HUDContainer.alpha = 0.7; + + _HUDIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; + _HUDIndicatorView.frame = CGRectMake(45, 15, 30, 30); + + _HUDLabel = [[UILabel alloc] init]; + _HUDLabel.frame = CGRectMake(0,40, 120, 50); + _HUDLabel.textAlignment = NSTextAlignmentCenter; + _HUDLabel.text = self.processHintStr; + _HUDLabel.font = [UIFont systemFontOfSize:15]; + _HUDLabel.textColor = [UIColor whiteColor]; + + [_HUDContainer addSubview:_HUDLabel]; + [_HUDContainer addSubview:_HUDIndicatorView]; + [_progressHUD addSubview:_HUDContainer]; + } + [_HUDIndicatorView startAnimating]; + [[UIApplication sharedApplication].keyWindow addSubview:_progressHUD]; + + // if over time, dismiss HUD automatic + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self hideProgressHUD]; + }); +} + +- (void)hideProgressHUD { + if (_progressHUD) { + [_HUDIndicatorView stopAnimating]; + [_progressHUD removeFromSuperview]; + } +} + +- (void)setMaxImagesCount:(NSInteger)maxImagesCount { + _maxImagesCount = maxImagesCount; + if (maxImagesCount > 1) { + _showSelectBtn = YES; + _allowCrop = NO; + } +} + +- (void)setShowSelectBtn:(BOOL)showSelectBtn { + _showSelectBtn = showSelectBtn; + // ������������������������������showSelectBtn���NO + if (!showSelectBtn && _maxImagesCount > 1) { + _showSelectBtn = YES; + } +} + +- (void)setAllowCrop:(BOOL)allowCrop { + _allowCrop = _maxImagesCount > 1 ? NO : allowCrop; + if (allowCrop) { // ������������������������������������������GIF + self.allowPickingOriginalPhoto = NO; + self.allowPickingGif = NO; + } +} + +- (void)setCircleCropRadius:(NSInteger)circleCropRadius { + _circleCropRadius = circleCropRadius; + _cropRect = CGRectMake(self.view.tz_width / 2 - circleCropRadius, self.view.tz_height / 2 - _circleCropRadius, _circleCropRadius * 2, _circleCropRadius * 2); +} + +- (CGRect)cropRect { + if (_cropRect.size.width > 0) { + return _cropRect; + } + CGFloat cropViewWH = self.view.tz_width; + return CGRectMake(0, (self.view.tz_height - self.view.tz_width) / 2, cropViewWH, cropViewWH); +} + +- (void)setTimeout:(NSInteger)timeout { + _timeout = timeout; + if (timeout < 5) { + _timeout = 5; + } else if (_timeout > 60) { + _timeout = 60; + } +} + +- (void)setColumnNumber:(NSInteger)columnNumber { + _columnNumber = columnNumber; + if (columnNumber <= 2) { + _columnNumber = 2; + } else if (columnNumber >= 6) { + _columnNumber = 6; + } + + TZAlbumPickerController *albumPickerVc = [self.childViewControllers firstObject]; + albumPickerVc.columnNumber = _columnNumber; + [TZImageManager manager].columnNumber = _columnNumber; +} + +- (void)setMinPhotoWidthSelectable:(NSInteger)minPhotoWidthSelectable { + _minPhotoWidthSelectable = minPhotoWidthSelectable; + [TZImageManager manager].minPhotoWidthSelectable = minPhotoWidthSelectable; +} + +- (void)setMinPhotoHeightSelectable:(NSInteger)minPhotoHeightSelectable { + _minPhotoHeightSelectable = minPhotoHeightSelectable; + [TZImageManager manager].minPhotoHeightSelectable = minPhotoHeightSelectable; +} + +- (void)setHideWhenCanNotSelect:(BOOL)hideWhenCanNotSelect { + _hideWhenCanNotSelect = hideWhenCanNotSelect; + [TZImageManager manager].hideWhenCanNotSelect = hideWhenCanNotSelect; +} + +- (void)setPhotoPreviewMaxWidth:(CGFloat)photoPreviewMaxWidth { + _photoPreviewMaxWidth = photoPreviewMaxWidth; + if (photoPreviewMaxWidth > 800) { + _photoPreviewMaxWidth = 800; + } else if (photoPreviewMaxWidth < 500) { + _photoPreviewMaxWidth = 500; + } + [TZImageManager manager].photoPreviewMaxWidth = _photoPreviewMaxWidth; +} + +- (void)setSelectedAssets:(NSMutableArray *)selectedAssets { + _selectedAssets = selectedAssets; + _selectedModels = [NSMutableArray array]; + for (id asset in selectedAssets) { + TZAssetModel *model = [TZAssetModel modelWithAsset:asset type:TZAssetModelMediaTypePhoto]; + model.isSelected = YES; + [_selectedModels addObject:model]; + } +} + +- (void)setAllowPickingImage:(BOOL)allowPickingImage { + _allowPickingImage = allowPickingImage; + NSString *allowPickingImageStr = _allowPickingImage ? @"1" : @"0"; + [[NSUserDefaults standardUserDefaults] setObject:allowPickingImageStr forKey:@"tz_allowPickingImage"]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)setAllowPickingVideo:(BOOL)allowPickingVideo { + _allowPickingVideo = allowPickingVideo; + NSString *allowPickingVideoStr = _allowPickingVideo ? @"1" : @"0"; + [[NSUserDefaults standardUserDefaults] setObject:allowPickingVideoStr forKey:@"tz_allowPickingVideo"]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)setSortAscendingByModificationDate:(BOOL)sortAscendingByModificationDate { + _sortAscendingByModificationDate = sortAscendingByModificationDate; + [TZImageManager manager].sortAscendingByModificationDate = sortAscendingByModificationDate; +} + +- (void)settingBtnClick { + if (iOS8Later) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + } else { + NSURL *privacyUrl = [NSURL URLWithString:@"prefs:root=Privacy&path=PHOTOS"]; + if ([[UIApplication sharedApplication] canOpenURL:privacyUrl]) { + [[UIApplication sharedApplication] openURL:privacyUrl]; + } else { + NSString *message = [NSBundle tz_localizedStringForKey:@"Can not jump to the privacy settings page, please go to the settings page by self, thank you"]; + UIAlertView * alert = [[UIAlertView alloc]initWithTitle:[NSBundle tz_localizedStringForKey:@"Sorry"] message:message delegate:nil cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"OK"] otherButtonTitles: nil]; + [alert show]; + } + } +} + +- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { + if (iOS7Later) viewController.automaticallyAdjustsScrollViewInsets = NO; + if (_timer) { [_timer invalidate]; _timer = nil;} + [super pushViewController:viewController animated:animated]; +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { + return UIInterfaceOrientationMaskPortrait; +} + +#pragma mark - Public + +- (void)cancelButtonClick { + if (self.autoDismiss) { + [self dismissViewControllerAnimated:YES completion:^{ + [self callDelegateMethod]; + }]; + } else { + [self callDelegateMethod]; + } +} + +- (void)callDelegateMethod { + // ��������������� + if ([self.pickerDelegate respondsToSelector:@selector(imagePickerControllerDidCancel:)]) { + [self.pickerDelegate imagePickerControllerDidCancel:self]; + } + if ([self.pickerDelegate respondsToSelector:@selector(tz_imagePickerControllerDidCancel:)]) { + [self.pickerDelegate tz_imagePickerControllerDidCancel:self]; + } + if (self.imagePickerControllerDidCancelHandle) { + self.imagePickerControllerDidCancelHandle(); + } +} + +@end + + +@interface TZAlbumPickerController ()<UITableViewDataSource,UITableViewDelegate> { + UITableView *_tableView; +} +@property (nonatomic, strong) NSMutableArray *albumArr; +@end + +@implementation TZAlbumPickerController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor whiteColor]; + self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Photos"]; + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:imagePickerVc.cancelBtnTitleStr style:UIBarButtonItemStylePlain target:imagePickerVc action:@selector(cancelButtonClick)]; + [self configTableView]; + // 1.6.10 ���������������������������������������������������backBarButtonItem��������������������������������������� + self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Back"] style:UIBarButtonItemStylePlain target:nil action:nil]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + [imagePickerVc hideProgressHUD]; + if (_albumArr) { + for (TZAlbumModel *albumModel in _albumArr) { + albumModel.selectedModels = imagePickerVc.selectedModels; + } + [_tableView reloadData]; + } else { + [self configTableView]; + } + if (imagePickerVc.allowTakePicture) { + self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Photos"]; + } else if (imagePickerVc.allowPickingVideo) { + self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Videos"]; + } +} + +- (void)configTableView { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + [[TZImageManager manager] getAllAlbums:imagePickerVc.allowPickingVideo allowPickingImage:imagePickerVc.allowPickingImage completion:^(NSArray<TZAlbumModel *> *models) { + _albumArr = [NSMutableArray arrayWithArray:models]; + for (TZAlbumModel *albumModel in _albumArr) { + albumModel.selectedModels = imagePickerVc.selectedModels; + } + if (!_tableView) { + + CGFloat top = 0; + CGFloat tableViewHeight = 0; + if (self.navigationController.navigationBar.isTranslucent) { + top = 44; + if (iOS7Later) top += 20; + tableViewHeight = self.view.tz_height - top; + } else { + CGFloat navigationHeight = 44; + if (iOS7Later) navigationHeight += 20; + tableViewHeight = self.view.tz_height - navigationHeight; + } + + _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, top, self.view.tz_width, tableViewHeight) style:UITableViewStylePlain]; + _tableView.rowHeight = 70; + _tableView.tableFooterView = [[UIView alloc] init]; + _tableView.dataSource = self; + _tableView.delegate = self; + [_tableView registerClass:[TZAlbumCell class] forCellReuseIdentifier:@"TZAlbumCell"]; + [self.view addSubview:_tableView]; + } else { + [_tableView reloadData]; + } + }]; +} + +#pragma mark - UITableViewDataSource && Delegate + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return _albumArr.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + TZAlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TZAlbumCell"]; + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + cell.selectedCountButton.backgroundColor = imagePickerVc.oKButtonTitleColorNormal; + cell.model = _albumArr[indexPath.row]; + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + return cell; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init]; + photoPickerVc.columnNumber = self.columnNumber; + TZAlbumModel *model = _albumArr[indexPath.row]; + photoPickerVc.model = model; + __weak typeof(self) weakSelf = self; + [photoPickerVc setBackButtonClickHandle:^(TZAlbumModel *model) { + [weakSelf.albumArr replaceObjectAtIndex:indexPath.row withObject:model]; + }]; + [self.navigationController pushViewController:photoPickerVc animated:YES]; + [tableView deselectRowAtIndexPath:indexPath animated:NO]; +} +#pragma clang diagnostic pop + +@end + + +@implementation UIImage (MyBundle) + ++ (UIImage *)imageNamedFromMyBundle:(NSString *)name { + UIImage *image = [UIImage imageNamed:[@"TZImagePickerController.bundle" stringByAppendingPathComponent:name]]; + if (image) { + return image; + } else { + image = [UIImage imageNamed:[@"Frameworks/TZImagePickerController.framework/TZImagePickerController.bundle" stringByAppendingPathComponent:name]]; + if (!image) { + image = [UIImage imageNamed:name]; + } + return image; + } +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.h new file mode 100755 index 0000000..c7dc021 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.h @@ -0,0 +1,25 @@ +// +// TZPhotoPickerController.h +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@class TZAlbumModel; +@interface TZPhotoPickerController : UIViewController + +@property (nonatomic, assign) BOOL isFirstAppear; +@property (nonatomic, assign) NSInteger columnNumber; +@property (nonatomic, strong) TZAlbumModel *model; + +@property (nonatomic, copy) void (^backButtonClickHandle)(TZAlbumModel *model); + +@end + + +@interface TZCollectionView : UICollectionView + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.m new file mode 100755 index 0000000..fd1b95a --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.m @@ -0,0 +1,792 @@ +// +// TZPhotoPickerController.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import "TZPhotoPickerController.h" +#import "TZImagePickerController.h" +#import "TZPhotoPreviewController.h" +#import "TZAssetCell.h" +#import "TZAssetModel.h" +#import "UIView+Layout.h" +#import "TZImageManager.h" +#import "TZVideoPlayerController.h" +#import "TZGifPhotoPreviewController.h" + +@interface TZPhotoPickerController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIAlertViewDelegate> { + NSMutableArray *_models; + + UIButton *_previewButton; + UIButton *_doneButton; + UIImageView *_numberImageView; + UILabel *_numberLabel; + UIButton *_originalPhotoButton; + UILabel *_originalPhotoLabel; + + BOOL _shouldScrollToBottom; + BOOL _showTakePhotoBtn; +} +@property CGRect previousPreheatRect; +@property (nonatomic, assign) BOOL isSelectOriginalPhoto; +@property (nonatomic, strong) TZCollectionView *collectionView; +@property (nonatomic, strong) UIImagePickerController *imagePickerVc; +@end + +static CGSize AssetGridThumbnailSize; + +@implementation TZPhotoPickerController + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +- (UIImagePickerController *)imagePickerVc { + if (_imagePickerVc == nil) { + _imagePickerVc = [[UIImagePickerController alloc] init]; + _imagePickerVc.delegate = self; + // set appearance / ��������������������������������������� + _imagePickerVc.navigationBar.barTintColor = self.navigationController.navigationBar.barTintColor; + _imagePickerVc.navigationBar.tintColor = self.navigationController.navigationBar.tintColor; + UIBarButtonItem *tzBarItem, *BarItem; + if (iOS9Later) { + tzBarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]]; + BarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UIImagePickerController class]]]; + } else { + tzBarItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil]; + BarItem = [UIBarButtonItem appearanceWhenContainedIn:[UIImagePickerController class], nil]; + } + NSDictionary *titleTextAttributes = [tzBarItem titleTextAttributesForState:UIControlStateNormal]; + [BarItem setTitleTextAttributes:titleTextAttributes forState:UIControlStateNormal]; + } + return _imagePickerVc; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + _isSelectOriginalPhoto = tzImagePickerVc.isSelectOriginalPhoto; + _shouldScrollToBottom = YES; + self.view.backgroundColor = [UIColor whiteColor]; + self.navigationItem.title = _model.name; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:tzImagePickerVc.cancelBtnTitleStr style:UIBarButtonItemStylePlain target:tzImagePickerVc action:@selector(cancelButtonClick)]; + _showTakePhotoBtn = (([[TZImageManager manager] isCameraRollAlbum:_model.name]) && tzImagePickerVc.allowTakePicture); + if (!tzImagePickerVc.sortAscendingByModificationDate && _isFirstAppear && iOS8Later) { + [[TZImageManager manager] getCameraRollAlbum:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage completion:^(TZAlbumModel *model) { + _model = model; + _models = [NSMutableArray arrayWithArray:_model.models]; + [self initSubviews]; + }]; + } else { + if (_showTakePhotoBtn || !iOS8Later || _isFirstAppear) { + [[TZImageManager manager] getAssetsFromFetchResult:_model.result allowPickingVideo:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage completion:^(NSArray<TZAssetModel *> *models) { + _models = [NSMutableArray arrayWithArray:models]; + [self initSubviews]; + }]; + } else { + _models = [NSMutableArray arrayWithArray:_model.models]; + [self initSubviews]; + } + } + // [self resetCachedAssets]; +} + +- (void)initSubviews { + [self checkSelectedModels]; + [self configCollectionView]; + [self configBottomToolBar]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + tzImagePickerVc.isSelectOriginalPhoto = _isSelectOriginalPhoto; + if (self.backButtonClickHandle) { + self.backButtonClickHandle(_model); + } +} + +- (BOOL)prefersStatusBarHidden { + return NO; +} + +- (void)configCollectionView { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + CGFloat margin = 5; + CGFloat itemWH = (self.view.tz_width - (self.columnNumber + 1) * margin) / self.columnNumber; + layout.itemSize = CGSizeMake(itemWH, itemWH); + layout.minimumInteritemSpacing = margin; + layout.minimumLineSpacing = margin; + + CGFloat top = 0; + CGFloat collectionViewHeight = 0; + if (self.navigationController.navigationBar.isTranslucent) { + top = 44; + if (iOS7Later) top += 20; + collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - 50 - top : self.view.tz_height - top;; + } else { + CGFloat navigationHeight = 44; + if (iOS7Later) navigationHeight += 20; + collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - 50 - navigationHeight : self.view.tz_height - navigationHeight; + } + + _collectionView = [[TZCollectionView alloc] initWithFrame:CGRectMake(0, top, self.view.tz_width, collectionViewHeight) collectionViewLayout:layout]; + _collectionView.backgroundColor = [UIColor whiteColor]; + _collectionView.dataSource = self; + _collectionView.delegate = self; + _collectionView.alwaysBounceHorizontal = NO; + _collectionView.contentInset = UIEdgeInsetsMake(margin, margin, margin, margin); + + if (_showTakePhotoBtn && tzImagePickerVc.allowTakePicture ) { + _collectionView.contentSize = CGSizeMake(self.view.tz_width, ((_model.count + self.columnNumber) / self.columnNumber) * self.view.tz_width); + } else { + _collectionView.contentSize = CGSizeMake(self.view.tz_width, ((_model.count + self.columnNumber - 1) / self.columnNumber) * self.view.tz_width); + } + [self.view addSubview:_collectionView]; + [_collectionView registerClass:[TZAssetCell class] forCellWithReuseIdentifier:@"TZAssetCell"]; + [_collectionView registerClass:[TZAssetCameraCell class] forCellWithReuseIdentifier:@"TZAssetCameraCell"]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self scrollCollectionViewToBottom]; + // Determine the size of the thumbnails to request from the PHCachingImageManager + CGFloat scale = 2.0; + if ([UIScreen mainScreen].bounds.size.width > 600) { + scale = 1.0; + } + CGSize cellSize = ((UICollectionViewFlowLayout *)_collectionView.collectionViewLayout).itemSize; + AssetGridThumbnailSize = CGSizeMake(cellSize.width * scale, cellSize.height * scale); +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + if (iOS8Later) { + // [self updateCachedAssets]; + } +} + +- (void)configBottomToolBar { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (!tzImagePickerVc.showSelectBtn) return; + + CGFloat yOffset = 0; + if (self.navigationController.navigationBar.isTranslucent) { + yOffset = self.view.tz_height - 50; + } else { + CGFloat navigationHeight = 44; + if (iOS7Later) navigationHeight += 20; + yOffset = self.view.tz_height - 50 - navigationHeight; + } + + UIView *bottomToolBar = [[UIView alloc] initWithFrame:CGRectMake(0, yOffset, self.view.tz_width, 50)]; + CGFloat rgb = 253 / 255.0; + bottomToolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0]; + + CGFloat previewWidth = [tzImagePickerVc.previewBtnTitleStr boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} context:nil].size.width + 2; + if (!tzImagePickerVc.allowPreview) { + previewWidth = 0.0; + } + _previewButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _previewButton.frame = CGRectMake(10, 3, previewWidth, 44); + _previewButton.tz_width = !tzImagePickerVc.showSelectBtn ? 0 : previewWidth; + [_previewButton addTarget:self action:@selector(previewButtonClick) forControlEvents:UIControlEventTouchUpInside]; + _previewButton.titleLabel.font = [UIFont systemFontOfSize:16]; + [_previewButton setTitle:tzImagePickerVc.previewBtnTitleStr forState:UIControlStateNormal]; + [_previewButton setTitle:tzImagePickerVc.previewBtnTitleStr forState:UIControlStateDisabled]; + [_previewButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [_previewButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled]; + _previewButton.enabled = tzImagePickerVc.selectedModels.count; + + if (tzImagePickerVc.allowPickingOriginalPhoto) { + CGFloat fullImageWidth = [tzImagePickerVc.fullImageBtnTitleStr boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} context:nil].size.width; + _originalPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _originalPhotoButton.frame = CGRectMake(CGRectGetMaxX(_previewButton.frame), self.view.tz_height - 50, fullImageWidth + 56, 50); + _originalPhotoButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0); + [_originalPhotoButton addTarget:self action:@selector(originalPhotoButtonClick) forControlEvents:UIControlEventTouchUpInside]; + _originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16]; + [_originalPhotoButton setTitle:tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateNormal]; + [_originalPhotoButton setTitle:tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateSelected]; + [_originalPhotoButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; + [_originalPhotoButton setTitleColor:[UIColor blackColor] forState:UIControlStateSelected]; + [_originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:tzImagePickerVc.photoOriginDefImageName] forState:UIControlStateNormal]; + [_originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:tzImagePickerVc.photoOriginSelImageName] forState:UIControlStateSelected]; + _originalPhotoButton.selected = _isSelectOriginalPhoto; + _originalPhotoButton.enabled = tzImagePickerVc.selectedModels.count > 0; + + _originalPhotoLabel = [[UILabel alloc] init]; + _originalPhotoLabel.frame = CGRectMake(fullImageWidth + 46, 0, 80, 50); + _originalPhotoLabel.textAlignment = NSTextAlignmentLeft; + _originalPhotoLabel.font = [UIFont systemFontOfSize:16]; + _originalPhotoLabel.textColor = [UIColor blackColor]; + if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes]; + } + + _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 3, 44, 44); + _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; + [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; + [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; + [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateDisabled]; + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled]; + _doneButton.enabled = tzImagePickerVc.selectedModels.count || tzImagePickerVc.alwaysEnableDoneBtn; + + _numberImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamedFromMyBundle:tzImagePickerVc.photoNumberIconImageName]]; + _numberImageView.frame = CGRectMake(self.view.tz_width - 56 - 28, 10, 30, 30); + _numberImageView.hidden = tzImagePickerVc.selectedModels.count <= 0; + _numberImageView.backgroundColor = [UIColor clearColor]; + + _numberLabel = [[UILabel alloc] init]; + _numberLabel.frame = _numberImageView.frame; + _numberLabel.font = [UIFont systemFontOfSize:15]; + _numberLabel.textColor = [UIColor whiteColor]; + _numberLabel.textAlignment = NSTextAlignmentCenter; + _numberLabel.text = [NSString stringWithFormat:@"%zd",tzImagePickerVc.selectedModels.count]; + _numberLabel.hidden = tzImagePickerVc.selectedModels.count <= 0; + _numberLabel.backgroundColor = [UIColor clearColor]; + + UIView *divide = [[UIView alloc] init]; + CGFloat rgb2 = 222 / 255.0; + divide.backgroundColor = [UIColor colorWithRed:rgb2 green:rgb2 blue:rgb2 alpha:1.0]; + divide.frame = CGRectMake(0, 0, self.view.tz_width, 1); + + [bottomToolBar addSubview:divide]; + [bottomToolBar addSubview:_previewButton]; + [bottomToolBar addSubview:_doneButton]; + [bottomToolBar addSubview:_numberImageView]; + [bottomToolBar addSubview:_numberLabel]; + [self.view addSubview:bottomToolBar]; + [self.view addSubview:_originalPhotoButton]; + [_originalPhotoButton addSubview:_originalPhotoLabel]; +} + +#pragma mark - Click Event + +- (void)previewButtonClick { + TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init]; + [self pushPhotoPrevireViewController:photoPreviewVc]; +} + +- (void)originalPhotoButtonClick { + _originalPhotoButton.selected = !_originalPhotoButton.isSelected; + _isSelectOriginalPhoto = _originalPhotoButton.isSelected; + _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected; + if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes]; +} + +- (void)doneButtonClick { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + // 1.6.8 ��������������������������������������������� + if (tzImagePickerVc.minImagesCount && tzImagePickerVc.selectedModels.count < tzImagePickerVc.minImagesCount) { + NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a minimum of %zd photos"], tzImagePickerVc.minImagesCount]; + [tzImagePickerVc showAlertWithTitle:title]; + return; + } + + [tzImagePickerVc showProgressHUD]; + NSMutableArray *photos = [NSMutableArray array]; + NSMutableArray *assets = [NSMutableArray array]; + NSMutableArray *infoArr = [NSMutableArray array]; + for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) { [photos addObject:@1];[assets addObject:@1];[infoArr addObject:@1]; } + + __block BOOL havenotShowAlert = YES; + [TZImageManager manager].shouldFixOrientation = YES; + for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) { + TZAssetModel *model = tzImagePickerVc.selectedModels[i]; + [[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { + if (isDegraded) return; + if (photo) { + photo = [self scaleImage:photo toSize:CGSizeMake(tzImagePickerVc.photoWidth, (int)(tzImagePickerVc.photoWidth * photo.size.height / photo.size.width))]; + [photos replaceObjectAtIndex:i withObject:photo]; + } + if (info) [infoArr replaceObjectAtIndex:i withObject:info]; + [assets replaceObjectAtIndex:i withObject:model.asset]; + + for (id item in photos) { if ([item isKindOfClass:[NSNumber class]]) return; } + + if (havenotShowAlert) { + [self didGetAllPhotos:photos assets:assets infoArr:infoArr]; + } + } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { + // ���������������������iCloud���������,������������ + if (progress < 1 && havenotShowAlert) { + [tzImagePickerVc hideProgressHUD]; + [tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Synchronizing photos from iCloud"]]; + havenotShowAlert = NO; + return; + } + } networkAccessAllowed:YES]; + } + if (tzImagePickerVc.selectedModels.count <= 0) { + [self didGetAllPhotos:photos assets:assets infoArr:infoArr]; + } +} + +- (void)didGetAllPhotos:(NSArray *)photos assets:(NSArray *)assets infoArr:(NSArray *)infoArr { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + [tzImagePickerVc hideProgressHUD]; + + if (tzImagePickerVc.autoDismiss) { + [self.navigationController dismissViewControllerAnimated:YES completion:^{ + [self callDelegateMethodWithPhotos:photos assets:assets infoArr:infoArr]; + }]; + } else { + [self callDelegateMethodWithPhotos:photos assets:assets infoArr:infoArr]; + } +} + +- (void)callDelegateMethodWithPhotos:(NSArray *)photos assets:(NSArray *)assets infoArr:(NSArray *)infoArr { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if ([tzImagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:)]) { + [tzImagePickerVc.pickerDelegate imagePickerController:tzImagePickerVc didFinishPickingPhotos:photos sourceAssets:assets isSelectOriginalPhoto:_isSelectOriginalPhoto]; + } + if ([tzImagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:infos:)]) { + [tzImagePickerVc.pickerDelegate imagePickerController:tzImagePickerVc didFinishPickingPhotos:photos sourceAssets:assets isSelectOriginalPhoto:_isSelectOriginalPhoto infos:infoArr]; + } + if (tzImagePickerVc.didFinishPickingPhotosHandle) { + tzImagePickerVc.didFinishPickingPhotosHandle(photos,assets,_isSelectOriginalPhoto); + } + if (tzImagePickerVc.didFinishPickingPhotosWithInfosHandle) { + tzImagePickerVc.didFinishPickingPhotosWithInfosHandle(photos,assets,_isSelectOriginalPhoto,infoArr); + } +} + +#pragma mark - UICollectionViewDataSource && Delegate + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + if (_showTakePhotoBtn) { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (tzImagePickerVc.allowPickingImage && tzImagePickerVc.allowTakePicture) { + return _models.count + 1; + } + } + return _models.count; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + // the cell lead to take a picture / ������������cell + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (((tzImagePickerVc.sortAscendingByModificationDate && indexPath.row >= _models.count) || (!tzImagePickerVc.sortAscendingByModificationDate && indexPath.row == 0)) && _showTakePhotoBtn) { + TZAssetCameraCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZAssetCameraCell" forIndexPath:indexPath]; + cell.imageView.image = [UIImage imageNamedFromMyBundle:tzImagePickerVc.takePictureImageName]; + return cell; + } + // the cell dipaly photo or video / ������������������������cell + TZAssetCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZAssetCell" forIndexPath:indexPath]; + cell.photoDefImageName = tzImagePickerVc.photoDefImageName; + cell.photoSelImageName = tzImagePickerVc.photoSelImageName; + TZAssetModel *model; + if (tzImagePickerVc.sortAscendingByModificationDate || !_showTakePhotoBtn) { + model = _models[indexPath.row]; + } else { + model = _models[indexPath.row - 1]; + } + cell.allowPickingGif = tzImagePickerVc.allowPickingGif; + cell.model = model; + cell.showSelectBtn = tzImagePickerVc.showSelectBtn; + if (!tzImagePickerVc.allowPreview) { + cell.selectPhotoButton.frame = cell.bounds; + } + + __weak typeof(cell) weakCell = cell; + __weak typeof(self) weakSelf = self; + __weak typeof(_numberImageView.layer) weakLayer = _numberImageView.layer; + cell.didSelectPhotoBlock = ^(BOOL isSelected) { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)weakSelf.navigationController; + // 1. cancel select / ������������ + if (isSelected) { + weakCell.selectPhotoButton.selected = NO; + model.isSelected = NO; + NSArray *selectedModels = [NSArray arrayWithArray:tzImagePickerVc.selectedModels]; + for (TZAssetModel *model_item in selectedModels) { + if ([[[TZImageManager manager] getAssetIdentifier:model.asset] isEqualToString:[[TZImageManager manager] getAssetIdentifier:model_item.asset]]) { + [tzImagePickerVc.selectedModels removeObject:model_item]; + break; + } + } + [weakSelf refreshBottomToolBarStatus]; + } else { + // 2. select:check if over the maxImagesCount / ������������,������������������������������������������ + if (tzImagePickerVc.selectedModels.count < tzImagePickerVc.maxImagesCount) { + weakCell.selectPhotoButton.selected = YES; + model.isSelected = YES; + [tzImagePickerVc.selectedModels addObject:model]; + [weakSelf refreshBottomToolBarStatus]; + } else { + NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a maximum of %zd photos"], tzImagePickerVc.maxImagesCount]; + [tzImagePickerVc showAlertWithTitle:title]; + } + } + [UIView showOscillatoryAnimationWithLayer:weakLayer type:TZOscillatoryAnimationToSmaller]; + }; + return cell; +} + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + // take a photo / ��������� + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (((tzImagePickerVc.sortAscendingByModificationDate && indexPath.row >= _models.count) || (!tzImagePickerVc.sortAscendingByModificationDate && indexPath.row == 0)) && _showTakePhotoBtn) { + [self takePhoto]; return; + } + // preview phote or video / ��������������������� + NSInteger index = indexPath.row; + if (!tzImagePickerVc.sortAscendingByModificationDate && _showTakePhotoBtn) { + index = indexPath.row - 1; + } + TZAssetModel *model = _models[index]; + if (model.type == TZAssetModelMediaTypeVideo) { + if (tzImagePickerVc.selectedModels.count > 0) { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + [imagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Can not choose both video and photo"]]; + } else { + TZVideoPlayerController *videoPlayerVc = [[TZVideoPlayerController alloc] init]; + videoPlayerVc.model = model; + [self.navigationController pushViewController:videoPlayerVc animated:YES]; + } + } else if (model.type == TZAssetModelMediaTypePhotoGif && tzImagePickerVc.allowPickingGif) { + if (tzImagePickerVc.selectedModels.count > 0) { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + [imagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Can not choose both photo and GIF"]]; + } else { + TZGifPhotoPreviewController *gifPreviewVc = [[TZGifPhotoPreviewController alloc] init]; + gifPreviewVc.model = model; + [self.navigationController pushViewController:gifPreviewVc animated:YES]; + } + } else { + TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init]; + photoPreviewVc.currentIndex = index; + photoPreviewVc.models = _models; + [self pushPhotoPrevireViewController:photoPreviewVc]; + } +} + +#pragma mark - UIScrollViewDelegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + if (iOS8Later) { + // [self updateCachedAssets]; + } +} + +#pragma mark - Private Method + +- (void)takePhoto { + AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + if ((authStatus == AVAuthorizationStatusRestricted || authStatus ==AVAuthorizationStatusDenied) && iOS7Later) { + // ��������� ������������������������ + NSString *appName = [[NSBundle mainBundle].infoDictionary valueForKey:@"CFBundleDisplayName"]; + if (!appName) appName = [[NSBundle mainBundle].infoDictionary valueForKey:@"CFBundleName"]; + NSString *message = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Please allow %@ to access your camera in \"Settings -> Privacy -> Camera\""],appName]; + UIAlertView * alert = [[UIAlertView alloc]initWithTitle:[NSBundle tz_localizedStringForKey:@"Can not use camera"] message:message delegate:self cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"Cancel"] otherButtonTitles:[NSBundle tz_localizedStringForKey:@"Setting"], nil]; + [alert show]; + } else { // ������������ + UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; + if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) { + self.imagePickerVc.sourceType = sourceType; + if(iOS8Later) { + _imagePickerVc.modalPresentationStyle = UIModalPresentationOverCurrentContext; + } + [self presentViewController:_imagePickerVc animated:YES completion:nil]; + } else { + NSLog(@"���������������������������������,���������������������"); + } + } +} + +- (void)refreshBottomToolBarStatus { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + + _previewButton.enabled = tzImagePickerVc.selectedModels.count > 0; + _doneButton.enabled = tzImagePickerVc.selectedModels.count > 0 || tzImagePickerVc.alwaysEnableDoneBtn; + + _numberImageView.hidden = tzImagePickerVc.selectedModels.count <= 0; + _numberLabel.hidden = tzImagePickerVc.selectedModels.count <= 0; + _numberLabel.text = [NSString stringWithFormat:@"%zd",tzImagePickerVc.selectedModels.count]; + + _originalPhotoButton.enabled = tzImagePickerVc.selectedModels.count > 0; + _originalPhotoButton.selected = (_isSelectOriginalPhoto && _originalPhotoButton.enabled); + _originalPhotoLabel.hidden = (!_originalPhotoButton.isSelected); + if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes]; +} + +- (void)pushPhotoPrevireViewController:(TZPhotoPreviewController *)photoPreviewVc { + __weak typeof(self) weakSelf = self; + photoPreviewVc.isSelectOriginalPhoto = _isSelectOriginalPhoto; + [photoPreviewVc setBackButtonClickBlock:^(BOOL isSelectOriginalPhoto) { + weakSelf.isSelectOriginalPhoto = isSelectOriginalPhoto; + [weakSelf.collectionView reloadData]; + [weakSelf refreshBottomToolBarStatus]; + }]; + [photoPreviewVc setDoneButtonClickBlock:^(BOOL isSelectOriginalPhoto) { + weakSelf.isSelectOriginalPhoto = isSelectOriginalPhoto; + [weakSelf doneButtonClick]; + }]; + [photoPreviewVc setDoneButtonClickBlockCropMode:^(UIImage *cropedImage, id asset) { + [weakSelf didGetAllPhotos:@[cropedImage] assets:@[asset] infoArr:nil]; + }]; + [self.navigationController pushViewController:photoPreviewVc animated:YES]; +} + +- (void)getSelectedPhotoBytes { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + [[TZImageManager manager] getPhotosBytesWithArray:imagePickerVc.selectedModels completion:^(NSString *totalBytes) { + _originalPhotoLabel.text = [NSString stringWithFormat:@"(%@)",totalBytes]; + }]; +} + +/// Scale image / ������������ +- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size { + if (image.size.width < size.width) { + return image; + } + UIGraphicsBeginImageContext(size); + [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return newImage; +} + +- (void)scrollCollectionViewToBottom { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (_shouldScrollToBottom && _models.count > 0 && tzImagePickerVc.sortAscendingByModificationDate) { + NSInteger item = _models.count - 1; + if (_showTakePhotoBtn) { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (tzImagePickerVc.allowPickingImage && tzImagePickerVc.allowTakePicture) { + item += 1; + } + } + [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:item inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; + _shouldScrollToBottom = NO; + } +} + +- (void)checkSelectedModels { + for (TZAssetModel *model in _models) { + model.isSelected = NO; + NSMutableArray *selectedAssets = [NSMutableArray array]; + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + for (TZAssetModel *model in tzImagePickerVc.selectedModels) { + [selectedAssets addObject:model.asset]; + } + if ([[TZImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) { + model.isSelected = YES; + } + } +} + +#pragma mark - UIAlertViewDelegate + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + if (buttonIndex == 1) { // ������������������������������������������ + if (iOS8Later) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + } else { + NSURL *privacyUrl = [NSURL URLWithString:@"prefs:root=Privacy&path=CAMERA"]; + if ([[UIApplication sharedApplication] canOpenURL:privacyUrl]) { + [[UIApplication sharedApplication] openURL:privacyUrl]; + } else { + NSString *message = [NSBundle tz_localizedStringForKey:@"Can not jump to the privacy settings page, please go to the settings page by self, thank you"]; + UIAlertView * alert = [[UIAlertView alloc]initWithTitle:[NSBundle tz_localizedStringForKey:@"Sorry"] message:message delegate:nil cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"OK"] otherButtonTitles: nil]; + [alert show]; + } + } + } +} + +#pragma mark - UIImagePickerControllerDelegate + +- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + [picker dismissViewControllerAnimated:YES completion:nil]; + NSString *type = [info objectForKey:UIImagePickerControllerMediaType]; + if ([type isEqualToString:@"public.image"]) { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + [imagePickerVc showProgressHUD]; + UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; + if (image) { + [[TZImageManager manager] savePhotoWithImage:image completion:^(NSError *error){ + if (!error) { + [self reloadPhotoArray]; + } + }]; + } + } +} + +- (void)reloadPhotoArray { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + [[TZImageManager manager] getCameraRollAlbum:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage completion:^(TZAlbumModel *model) { + _model = model; + [[TZImageManager manager] getAssetsFromFetchResult:_model.result allowPickingVideo:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage completion:^(NSArray<TZAssetModel *> *models) { + [tzImagePickerVc hideProgressHUD]; + + TZAssetModel *assetModel; + if (tzImagePickerVc.sortAscendingByModificationDate) { + assetModel = [models lastObject]; + [_models addObject:assetModel]; + } else { + assetModel = [models firstObject]; + [_models insertObject:assetModel atIndex:0]; + } + + if (tzImagePickerVc.maxImagesCount <= 1) { + if (tzImagePickerVc.allowCrop) { + TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init]; + photoPreviewVc.currentIndex = _models.count - 1; + photoPreviewVc.models = _models; + [self pushPhotoPrevireViewController:photoPreviewVc]; + } else { + [tzImagePickerVc.selectedModels addObject:assetModel]; + [self doneButtonClick]; + } + return; + } + + if (tzImagePickerVc.selectedModels.count < tzImagePickerVc.maxImagesCount) { + assetModel.isSelected = YES; + [tzImagePickerVc.selectedModels addObject:assetModel]; + [self refreshBottomToolBarStatus]; + } + [_collectionView reloadData]; + + _shouldScrollToBottom = YES; + [self scrollCollectionViewToBottom]; + }]; + }]; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [picker dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)dealloc { + //NSLog(@"TZPhotoPickerController dealloc"); +} + +#pragma mark - Asset Caching + +- (void)resetCachedAssets { + [[TZImageManager manager].cachingImageManager stopCachingImagesForAllAssets]; + self.previousPreheatRect = CGRectZero; +} + +- (void)updateCachedAssets { + BOOL isViewVisible = [self isViewLoaded] && [[self view] window] != nil; + if (!isViewVisible) { return; } + + // The preheat window is twice the height of the visible rect. + CGRect preheatRect = _collectionView.bounds; + preheatRect = CGRectInset(preheatRect, 0.0f, -0.5f * CGRectGetHeight(preheatRect)); + + /* + Check if the collection view is showing an area that is significantly + different to the last preheated area. + */ + CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect)); + if (delta > CGRectGetHeight(_collectionView.bounds) / 3.0f) { + + // Compute the assets to start caching and to stop caching. + NSMutableArray *addedIndexPaths = [NSMutableArray array]; + NSMutableArray *removedIndexPaths = [NSMutableArray array]; + + [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect removedHandler:^(CGRect removedRect) { + NSArray *indexPaths = [self aapl_indexPathsForElementsInRect:removedRect]; + [removedIndexPaths addObjectsFromArray:indexPaths]; + } addedHandler:^(CGRect addedRect) { + NSArray *indexPaths = [self aapl_indexPathsForElementsInRect:addedRect]; + [addedIndexPaths addObjectsFromArray:indexPaths]; + }]; + + NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths]; + NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths]; + + // Update the assets the PHCachingImageManager is caching. + [[TZImageManager manager].cachingImageManager startCachingImagesForAssets:assetsToStartCaching + targetSize:AssetGridThumbnailSize + contentMode:PHImageContentModeAspectFill + options:nil]; + [[TZImageManager manager].cachingImageManager stopCachingImagesForAssets:assetsToStopCaching + targetSize:AssetGridThumbnailSize + contentMode:PHImageContentModeAspectFill + options:nil]; + + // Store the preheat rect to compare against in the future. + self.previousPreheatRect = preheatRect; + } +} + +- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler { + if (CGRectIntersectsRect(newRect, oldRect)) { + CGFloat oldMaxY = CGRectGetMaxY(oldRect); + CGFloat oldMinY = CGRectGetMinY(oldRect); + CGFloat newMaxY = CGRectGetMaxY(newRect); + CGFloat newMinY = CGRectGetMinY(newRect); + + if (newMaxY > oldMaxY) { + CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY)); + addedHandler(rectToAdd); + } + + if (oldMinY > newMinY) { + CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY)); + addedHandler(rectToAdd); + } + + if (newMaxY < oldMaxY) { + CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY)); + removedHandler(rectToRemove); + } + + if (oldMinY < newMinY) { + CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY)); + removedHandler(rectToRemove); + } + } else { + addedHandler(newRect); + removedHandler(oldRect); + } +} + +- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths { + if (indexPaths.count == 0) { return nil; } + + NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count]; + for (NSIndexPath *indexPath in indexPaths) { + if (indexPath.item < _models.count) { + TZAssetModel *model = _models[indexPath.item]; + [assets addObject:model.asset]; + } + } + + return assets; +} + +- (NSArray *)aapl_indexPathsForElementsInRect:(CGRect)rect { + NSArray *allLayoutAttributes = [_collectionView.collectionViewLayout layoutAttributesForElementsInRect:rect]; + if (allLayoutAttributes.count == 0) { return nil; } + NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:allLayoutAttributes.count]; + for (UICollectionViewLayoutAttributes *layoutAttributes in allLayoutAttributes) { + NSIndexPath *indexPath = layoutAttributes.indexPath; + [indexPaths addObject:indexPath]; + } + return indexPaths; +} +#pragma clang diagnostic pop + +@end + + + +@implementation TZCollectionView + +- (BOOL)touchesShouldCancelInContentView:(UIView *)view { + if ( [view isKindOfClass:[UIControl class]]) { + return YES; + } + return [super touchesShouldCancelInContentView:view]; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.h new file mode 100755 index 0000000..4e77386 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.h @@ -0,0 +1,43 @@ +// +// TZPhotoPreviewCell.h +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@class TZAssetModel,TZProgressView,TZPhotoPreviewView; +@interface TZPhotoPreviewCell : UICollectionViewCell + +@property (nonatomic, strong) TZAssetModel *model; +@property (nonatomic, copy) void (^singleTapGestureBlock)(); +@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress); + +@property (nonatomic, strong) TZPhotoPreviewView *previewView; + +@property (nonatomic, assign) BOOL allowCrop; +@property (nonatomic, assign) CGRect cropRect; + +- (void)recoverSubviews; + +@end + + +@interface TZPhotoPreviewView : UIView +@property (nonatomic, strong) UIImageView *imageView; +@property (nonatomic, strong) UIScrollView *scrollView; +@property (nonatomic, strong) UIView *imageContainerView; +@property (nonatomic, strong) TZProgressView *progressView; + +@property (nonatomic, assign) BOOL allowCrop; +@property (nonatomic, assign) CGRect cropRect; + +@property (nonatomic, strong) TZAssetModel *model; +@property (nonatomic, strong) id asset; +@property (nonatomic, copy) void (^singleTapGestureBlock)(); +@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress); + +- (void)recoverSubviews; +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.m new file mode 100755 index 0000000..93461bc --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.m @@ -0,0 +1,259 @@ +// +// TZPhotoPreviewCell.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import "TZPhotoPreviewCell.h" +#import "TZAssetModel.h" +#import "UIView+Layout.h" +#import "TZImageManager.h" +#import "TZProgressView.h" +#import "TZImageCropManager.h" + +@interface TZPhotoPreviewCell () +@end + +@implementation TZPhotoPreviewCell + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor blackColor]; + self.previewView = [[TZPhotoPreviewView alloc] initWithFrame:self.bounds]; + __weak typeof(self) weakSelf = self; + [self.previewView setSingleTapGestureBlock:^{ + if (weakSelf.singleTapGestureBlock) { + weakSelf.singleTapGestureBlock(); + } + }]; + [self.previewView setImageProgressUpdateBlock:^(double progress) { + if (weakSelf.imageProgressUpdateBlock) { + weakSelf.imageProgressUpdateBlock(progress); + } + }]; + [self addSubview:self.previewView]; + } + return self; +} + +- (void)setModel:(TZAssetModel *)model { + _model = model; + _previewView.asset = model.asset; +} + +- (void)recoverSubviews { + [_previewView recoverSubviews]; +} + +- (void)setAllowCrop:(BOOL)allowCrop { + _allowCrop = allowCrop; + _previewView.allowCrop = allowCrop; +} + +- (void)setCropRect:(CGRect)cropRect { + _cropRect = cropRect; + _previewView.cropRect = cropRect; +} + +@end + + +@interface TZPhotoPreviewView ()<UIScrollViewDelegate> + +@end + +@implementation TZPhotoPreviewView + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _scrollView = [[UIScrollView alloc] init]; + _scrollView.frame = CGRectMake(10, 0, self.tz_width - 20, self.tz_height); + _scrollView.bouncesZoom = YES; + _scrollView.maximumZoomScale = 2.5; + _scrollView.minimumZoomScale = 1.0; + _scrollView.multipleTouchEnabled = YES; + _scrollView.delegate = self; + _scrollView.scrollsToTop = NO; + _scrollView.showsHorizontalScrollIndicator = NO; + _scrollView.showsVerticalScrollIndicator = NO; + _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _scrollView.delaysContentTouches = NO; + _scrollView.canCancelContentTouches = YES; + _scrollView.alwaysBounceVertical = NO; + [self addSubview:_scrollView]; + + _imageContainerView = [[UIView alloc] init]; + _imageContainerView.clipsToBounds = YES; + _imageContainerView.contentMode = UIViewContentModeScaleAspectFill; + [_scrollView addSubview:_imageContainerView]; + + _imageView = [[UIImageView alloc] init]; + _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500]; + _imageView.contentMode = UIViewContentModeScaleAspectFill; + _imageView.clipsToBounds = YES; + [_imageContainerView addSubview:_imageView]; + + UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)]; + [self addGestureRecognizer:tap1]; + UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)]; + tap2.numberOfTapsRequired = 2; + [tap1 requireGestureRecognizerToFail:tap2]; + [self addGestureRecognizer:tap2]; + + [self configProgressView]; + } + return self; +} + +- (void)configProgressView { + _progressView = [[TZProgressView alloc] init]; + static CGFloat progressWH = 40; + CGFloat progressX = (self.tz_width - progressWH) / 2; + CGFloat progressY = (self.tz_height - progressWH) / 2; + _progressView.frame = CGRectMake(progressX, progressY, progressWH, progressWH); + _progressView.hidden = YES; + [self addSubview:_progressView]; +} + +- (void)setModel:(TZAssetModel *)model { + _model = model; + [_scrollView setZoomScale:1.0 animated:NO]; + if (model.type == TZAssetModelMediaTypePhotoGif) { + [[TZImageManager manager] getOriginalPhotoDataWithAsset:model.asset completion:^(NSData *data, NSDictionary *info, BOOL isDegraded) { + if (!isDegraded) { + self.imageView.image = [UIImage sd_tz_animatedGIFWithData:data]; + [self resizeSubviews]; + } + }]; + } else { + self.asset = model.asset; + } +} + +- (void)setAsset:(id)asset { + _asset = asset; + [[TZImageManager manager] getPhotoWithAsset:asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { + self.imageView.image = photo; + [self resizeSubviews]; + _progressView.hidden = YES; + if (self.imageProgressUpdateBlock) { + self.imageProgressUpdateBlock(1); + } + } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { + _progressView.hidden = NO; + [self bringSubviewToFront:_progressView]; + progress = progress > 0.02 ? progress : 0.02;; + _progressView.progress = progress; + if (self.imageProgressUpdateBlock) { + self.imageProgressUpdateBlock(progress); + } + } networkAccessAllowed:YES]; +} + +- (void)recoverSubviews { + [_scrollView setZoomScale:1.0 animated:NO]; + [self resizeSubviews]; +} + +- (void)resizeSubviews { + _imageContainerView.tz_origin = CGPointZero; + _imageContainerView.tz_width = self.scrollView.tz_width; + + UIImage *image = _imageView.image; + if (image.size.height / image.size.width > self.tz_height / self.scrollView.tz_width) { + _imageContainerView.tz_height = floor(image.size.height / (image.size.width / self.scrollView.tz_width)); + } else { + CGFloat height = image.size.height / image.size.width * self.scrollView.tz_width; + if (height < 1 || isnan(height)) height = self.tz_height; + height = floor(height); + _imageContainerView.tz_height = height; + _imageContainerView.tz_centerY = self.tz_height / 2; + } + if (_imageContainerView.tz_height > self.tz_height && _imageContainerView.tz_height - self.tz_height <= 1) { + _imageContainerView.tz_height = self.tz_height; + } + CGFloat contentSizeH = MAX(_imageContainerView.tz_height, self.tz_height); + _scrollView.contentSize = CGSizeMake(self.scrollView.tz_width, contentSizeH); + [_scrollView scrollRectToVisible:self.bounds animated:NO]; + _scrollView.alwaysBounceVertical = _imageContainerView.tz_height <= self.tz_height ? NO : YES; + _imageView.frame = _imageContainerView.bounds; + + [self refreshScrollViewContentSize]; +} + +- (void)setAllowCrop:(BOOL)allowCrop { + _allowCrop = allowCrop; + _scrollView.maximumZoomScale = allowCrop ? 4.0 : 2.5; +} + +- (void)refreshScrollViewContentSize { + if (_allowCrop) { + // 1.7.2 ������������������,���������������������������������������������������������������_scrollView��������������������� + // 1.���contentSize������(���������������������������������) + CGFloat contentWidthAdd = self.scrollView.tz_width - CGRectGetMaxX(_cropRect); + CGFloat contentHeightAdd = (MIN(_imageContainerView.tz_height, self.tz_height) - self.cropRect.size.height) / 2; + CGFloat newSizeW = self.scrollView.contentSize.width + contentWidthAdd; + CGFloat newSizeH = MAX(self.scrollView.contentSize.height, self.tz_height) + contentHeightAdd; + _scrollView.contentSize = CGSizeMake(newSizeW, newSizeH); + _scrollView.alwaysBounceVertical = YES; + // 2.���scrollView��������������������������������������������������������� + if (contentHeightAdd > 0) { + _scrollView.contentInset = UIEdgeInsetsMake(contentHeightAdd, _cropRect.origin.x, 0, 0); + } else { + _scrollView.contentInset = UIEdgeInsetsZero; + } + } +} + +#pragma mark - UITapGestureRecognizer Event + +- (void)doubleTap:(UITapGestureRecognizer *)tap { + if (_scrollView.zoomScale > 1.0) { + _scrollView.contentInset = UIEdgeInsetsZero; + [_scrollView setZoomScale:1.0 animated:YES]; + } else { + CGPoint touchPoint = [tap locationInView:self.imageView]; + CGFloat newZoomScale = _scrollView.maximumZoomScale; + CGFloat xsize = self.frame.size.width / newZoomScale; + CGFloat ysize = self.frame.size.height / newZoomScale; + [_scrollView zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES]; + } +} + +- (void)singleTap:(UITapGestureRecognizer *)tap { + if (self.singleTapGestureBlock) { + self.singleTapGestureBlock(); + } +} + +#pragma mark - UIScrollViewDelegate + +- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { + return _imageContainerView; +} + +- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { + scrollView.contentInset = UIEdgeInsetsZero; +} + +- (void)scrollViewDidZoom:(UIScrollView *)scrollView { + [self refreshImageContainerViewCenter]; +} + +- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { + [self refreshScrollViewContentSize]; +} + +#pragma mark - Private + +- (void)refreshImageContainerViewCenter { + CGFloat offsetX = (_scrollView.tz_width > _scrollView.contentSize.width) ? ((_scrollView.tz_width - _scrollView.contentSize.width) * 0.5) : 0.0; + CGFloat offsetY = (_scrollView.tz_height > _scrollView.contentSize.height) ? ((_scrollView.tz_height - _scrollView.contentSize.height) * 0.5) : 0.0; + self.imageContainerView.center = CGPointMake(_scrollView.contentSize.width * 0.5 + offsetX, _scrollView.contentSize.height * 0.5 + offsetY); +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.h new file mode 100755 index 0000000..2d5d677 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.h @@ -0,0 +1,25 @@ +// +// TZPhotoPreviewController.h +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface TZPhotoPreviewController : UIViewController + +@property (nonatomic, strong) NSMutableArray *models; ///< All photo models / ������������������������ +@property (nonatomic, strong) NSMutableArray *photos; ///< All photos / ������������������ +@property (nonatomic, assign) NSInteger currentIndex; ///< Index of the photo user click / ������������������������������ +@property (nonatomic, assign) BOOL isSelectOriginalPhoto; ///< If YES,return original photo / ������������������ +@property (nonatomic, assign) BOOL isCropImage; + +/// Return the new selected photos / ��������������������������������� +@property (nonatomic, copy) void (^backButtonClickBlock)(BOOL isSelectOriginalPhoto); +@property (nonatomic, copy) void (^doneButtonClickBlock)(BOOL isSelectOriginalPhoto); +@property (nonatomic, copy) void (^doneButtonClickBlockCropMode)(UIImage *cropedImage,id asset); +@property (nonatomic, copy) void (^doneButtonClickBlockWithPreviewType)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto); + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.m new file mode 100755 index 0000000..5b6d0f1 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.m @@ -0,0 +1,433 @@ +// +// TZPhotoPreviewController.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import "TZPhotoPreviewController.h" +#import "TZPhotoPreviewCell.h" +#import "TZAssetModel.h" +#import "UIView+Layout.h" +#import "TZImagePickerController.h" +#import "TZImageManager.h" +#import "TZImageCropManager.h" + +@interface TZPhotoPreviewController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIScrollViewDelegate> { + UICollectionView *_collectionView; + NSArray *_photosTemp; + NSArray *_assetsTemp; + + UIView *_naviBar; + UIButton *_backButton; + UIButton *_selectButton; + + UIView *_toolBar; + UIButton *_doneButton; + UIImageView *_numberImageView; + UILabel *_numberLabel; + UIButton *_originalPhotoButton; + UILabel *_originalPhotoLabel; +} +@property (nonatomic, assign) BOOL isHideNaviBar; +@property (nonatomic, strong) UIView *cropBgView; +@property (nonatomic, strong) UIView *cropView; + +@property (nonatomic, assign) double progress; +@end + +@implementation TZPhotoPreviewController + +- (void)viewDidLoad { + [super viewDidLoad]; + [TZImageManager manager].shouldFixOrientation = YES; + __weak typeof(self) weakSelf = self; + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)weakSelf.navigationController; + if (!self.models.count) { + self.models = [NSMutableArray arrayWithArray:_tzImagePickerVc.selectedModels]; + _assetsTemp = [NSMutableArray arrayWithArray:_tzImagePickerVc.selectedAssets]; + self.isSelectOriginalPhoto = _tzImagePickerVc.isSelectOriginalPhoto; + } + [self configCollectionView]; + [self configCropView]; + [self configCustomNaviBar]; + [self configBottomToolBar]; + self.view.clipsToBounds = YES; +} + +- (void)setPhotos:(NSMutableArray *)photos { + _photos = photos; + _photosTemp = [NSArray arrayWithArray:photos]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.navigationController setNavigationBarHidden:YES]; + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES; + if (_currentIndex) [_collectionView setContentOffset:CGPointMake((self.view.tz_width + 20) * _currentIndex, 0) animated:NO]; + [self refreshNaviBarAndBottomBarState]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [self.navigationController setNavigationBarHidden:NO]; + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = NO; + [TZImageManager manager].shouldFixOrientation = NO; +} + +- (BOOL)prefersStatusBarHidden { + return YES; +} + +- (void)configCustomNaviBar { + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + + _naviBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.tz_width, 64)]; + _naviBar.backgroundColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:0.7]; + + _backButton = [[UIButton alloc] initWithFrame:CGRectMake(10, 10, 44, 44)]; + [_backButton setImage:[UIImage imageNamedFromMyBundle:@"navi_back.png"] forState:UIControlStateNormal]; + [_backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [_backButton addTarget:self action:@selector(backButtonClick) forControlEvents:UIControlEventTouchUpInside]; + + _selectButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.tz_width - 54, 10, 42, 42)]; + [_selectButton setImage:[UIImage imageNamedFromMyBundle:tzImagePickerVc.photoDefImageName] forState:UIControlStateNormal]; + [_selectButton setImage:[UIImage imageNamedFromMyBundle:tzImagePickerVc.photoSelImageName] forState:UIControlStateSelected]; + [_selectButton addTarget:self action:@selector(select:) forControlEvents:UIControlEventTouchUpInside]; + _selectButton.hidden = !tzImagePickerVc.showSelectBtn; + + [_naviBar addSubview:_selectButton]; + [_naviBar addSubview:_backButton]; + [self.view addSubview:_naviBar]; +} + +- (void)configBottomToolBar { + _toolBar = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.tz_height - 44, self.view.tz_width, 44)]; + static CGFloat rgb = 34 / 255.0; + _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7]; + + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (_tzImagePickerVc.allowPickingOriginalPhoto) { + CGFloat fullImageWidth = [_tzImagePickerVc.fullImageBtnTitleStr boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} context:nil].size.width; + _originalPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _originalPhotoButton.frame = CGRectMake(0, 0, fullImageWidth + 56, 44); + _originalPhotoButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0); + _originalPhotoButton.backgroundColor = [UIColor clearColor]; + [_originalPhotoButton addTarget:self action:@selector(originalPhotoButtonClick) forControlEvents:UIControlEventTouchUpInside]; + _originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:13]; + [_originalPhotoButton setTitle:_tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateNormal]; + [_originalPhotoButton setTitle:_tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateSelected]; + [_originalPhotoButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; + [_originalPhotoButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; + [_originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:_tzImagePickerVc.photoPreviewOriginDefImageName] forState:UIControlStateNormal]; + [_originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:_tzImagePickerVc.photoOriginSelImageName] forState:UIControlStateSelected]; + + _originalPhotoLabel = [[UILabel alloc] init]; + _originalPhotoLabel.frame = CGRectMake(fullImageWidth + 42, 0, 80, 44); + _originalPhotoLabel.textAlignment = NSTextAlignmentLeft; + _originalPhotoLabel.font = [UIFont systemFontOfSize:13]; + _originalPhotoLabel.textColor = [UIColor whiteColor]; + _originalPhotoLabel.backgroundColor = [UIColor clearColor]; + if (_isSelectOriginalPhoto) [self showPhotoBytes]; + } + + _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44); + _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; + [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; + [_doneButton setTitle:_tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; + [_doneButton setTitleColor:_tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; + + _numberImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamedFromMyBundle:_tzImagePickerVc.photoNumberIconImageName]]; + _numberImageView.backgroundColor = [UIColor clearColor]; + _numberImageView.frame = CGRectMake(self.view.tz_width - 56 - 28, 7, 30, 30); + _numberImageView.hidden = _tzImagePickerVc.selectedModels.count <= 0; + + _numberLabel = [[UILabel alloc] init]; + _numberLabel.frame = _numberImageView.frame; + _numberLabel.font = [UIFont systemFontOfSize:15]; + _numberLabel.textColor = [UIColor whiteColor]; + _numberLabel.textAlignment = NSTextAlignmentCenter; + _numberLabel.text = [NSString stringWithFormat:@"%zd",_tzImagePickerVc.selectedModels.count]; + _numberLabel.hidden = _tzImagePickerVc.selectedModels.count <= 0; + _numberLabel.backgroundColor = [UIColor clearColor]; + + [_originalPhotoButton addSubview:_originalPhotoLabel]; + [_toolBar addSubview:_doneButton]; + [_toolBar addSubview:_originalPhotoButton]; + [_toolBar addSubview:_numberImageView]; + [_toolBar addSubview:_numberLabel]; + [self.view addSubview:_toolBar]; +} + +- (void)configCollectionView { + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + layout.itemSize = CGSizeMake(self.view.tz_width + 20, self.view.tz_height); + layout.minimumInteritemSpacing = 0; + layout.minimumLineSpacing = 0; + _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(-10, 0, self.view.tz_width + 20, self.view.tz_height) collectionViewLayout:layout]; + _collectionView.backgroundColor = [UIColor blackColor]; + _collectionView.dataSource = self; + _collectionView.delegate = self; + _collectionView.pagingEnabled = YES; + _collectionView.scrollsToTop = NO; + _collectionView.showsHorizontalScrollIndicator = NO; + _collectionView.contentOffset = CGPointMake(0, 0); + _collectionView.contentSize = CGSizeMake(self.models.count * (self.view.tz_width + 20), 0); + [self.view addSubview:_collectionView]; + [_collectionView registerClass:[TZPhotoPreviewCell class] forCellWithReuseIdentifier:@"TZPhotoPreviewCell"]; +} + +- (void)configCropView { + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (!_tzImagePickerVc.showSelectBtn && _tzImagePickerVc.allowCrop) { + _cropBgView = [UIView new]; + _cropBgView.userInteractionEnabled = NO; + _cropBgView.backgroundColor = [UIColor clearColor]; + _cropBgView.frame = self.view.bounds; + [self.view addSubview:_cropBgView]; + [TZImageCropManager overlayClippingWithView:_cropBgView cropRect:_tzImagePickerVc.cropRect containerView:self.view needCircleCrop:_tzImagePickerVc.needCircleCrop]; + + _cropView = [UIView new]; + _cropView.userInteractionEnabled = NO; + _cropView.backgroundColor = [UIColor clearColor]; + _cropView.frame = _tzImagePickerVc.cropRect; + _cropView.layer.borderColor = [UIColor whiteColor].CGColor; + _cropView.layer.borderWidth = 1.0; + if (_tzImagePickerVc.needCircleCrop) { + _cropView.layer.cornerRadius = _tzImagePickerVc.cropRect.size.width / 2; + _cropView.clipsToBounds = YES; + } + [self.view addSubview:_cropView]; + if (_tzImagePickerVc.cropViewSettingBlock) { + _tzImagePickerVc.cropViewSettingBlock(_cropView); + } + } +} + +#pragma mark - Click Event + +- (void)select:(UIButton *)selectButton { + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; + TZAssetModel *model = _models[_currentIndex]; + if (!selectButton.isSelected) { + // 1. select:check if over the maxImagesCount / ������������,������������������������������������������ + if (_tzImagePickerVc.selectedModels.count >= _tzImagePickerVc.maxImagesCount) { + NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a maximum of %zd photos"], _tzImagePickerVc.maxImagesCount]; + [_tzImagePickerVc showAlertWithTitle:title]; + return; + // 2. if not over the maxImagesCount / ������������������������������������ + } else { + [_tzImagePickerVc.selectedModels addObject:model]; + if (self.photos) { + [_tzImagePickerVc.selectedAssets addObject:_assetsTemp[_currentIndex]]; + [self.photos addObject:_photosTemp[_currentIndex]]; + } + if (model.type == TZAssetModelMediaTypeVideo) { + [_tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Select the video when in multi state, we will handle the video as a photo"]]; + } + } + } else { + NSArray *selectedModels = [NSArray arrayWithArray:_tzImagePickerVc.selectedModels]; + for (TZAssetModel *model_item in selectedModels) { + if ([[[TZImageManager manager] getAssetIdentifier:model.asset] isEqualToString:[[TZImageManager manager] getAssetIdentifier:model_item.asset]]) { + // 1.6.7������������:������������������������model,��������������������� + NSArray *selectedModelsTmp = [NSArray arrayWithArray:_tzImagePickerVc.selectedModels]; + for (NSInteger i = 0; i < selectedModelsTmp.count; i++) { + TZAssetModel *model = selectedModelsTmp[i]; + if ([model isEqual:model_item]) { + [_tzImagePickerVc.selectedModels removeObjectAtIndex:i]; + break; + } + } + // [_tzImagePickerVc.selectedModels removeObject:model_item]; + if (self.photos) { + // 1.6.7������������:������������������������asset,��������������������� + NSArray *selectedAssetsTmp = [NSArray arrayWithArray:_tzImagePickerVc.selectedAssets]; + for (NSInteger i = 0; i < selectedAssetsTmp.count; i++) { + id asset = selectedAssetsTmp[i]; + if ([asset isEqual:_assetsTemp[_currentIndex]]) { + [_tzImagePickerVc.selectedAssets removeObjectAtIndex:i]; + break; + } + } + // [_tzImagePickerVc.selectedAssets removeObject:_assetsTemp[_currentIndex]]; + [self.photos removeObject:_photosTemp[_currentIndex]]; + } + break; + } + } + } + model.isSelected = !selectButton.isSelected; + [self refreshNaviBarAndBottomBarState]; + if (model.isSelected) { + [UIView showOscillatoryAnimationWithLayer:selectButton.imageView.layer type:TZOscillatoryAnimationToBigger]; + } + [UIView showOscillatoryAnimationWithLayer:_numberImageView.layer type:TZOscillatoryAnimationToSmaller]; +} + +- (void)backButtonClick { + if (self.navigationController.childViewControllers.count < 2) { + [self.navigationController dismissViewControllerAnimated:YES completion:nil]; + return; + } + [self.navigationController popViewControllerAnimated:YES]; + if (self.backButtonClickBlock) { + self.backButtonClickBlock(_isSelectOriginalPhoto); + } +} + +- (void)doneButtonClick { + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; + // ���������������������iCloud���������,������������ + if (_progress > 0 && _progress < 1) { + [_tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Synchronizing photos from iCloud"]]; return; + } + + // ��������������������������� ������������������������������������������ + if (_tzImagePickerVc.selectedModels.count == 0 && _tzImagePickerVc.minImagesCount <= 0) { + TZAssetModel *model = _models[_currentIndex]; + [_tzImagePickerVc.selectedModels addObject:model]; + } + if (_tzImagePickerVc.allowCrop) { // ������������ + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:_currentIndex inSection:0]; + TZPhotoPreviewCell *cell = (TZPhotoPreviewCell *)[_collectionView cellForItemAtIndexPath:indexPath]; + UIImage *cropedImage = [TZImageCropManager cropImageView:cell.previewView.imageView toRect:_tzImagePickerVc.cropRect zoomScale:cell.previewView.scrollView.zoomScale containerView:self.view]; + if (_tzImagePickerVc.needCircleCrop) { + cropedImage = [TZImageCropManager circularClipImage:cropedImage]; + } + if (self.doneButtonClickBlockCropMode) { + TZAssetModel *model = _models[_currentIndex]; + self.doneButtonClickBlockCropMode(cropedImage,model.asset); + } + } else if (self.doneButtonClickBlock) { // ��������������� + self.doneButtonClickBlock(_isSelectOriginalPhoto); + } + if (self.doneButtonClickBlockWithPreviewType) { + self.doneButtonClickBlockWithPreviewType(self.photos,_tzImagePickerVc.selectedAssets,self.isSelectOriginalPhoto); + } +} + +- (void)originalPhotoButtonClick { + _originalPhotoButton.selected = !_originalPhotoButton.isSelected; + _isSelectOriginalPhoto = _originalPhotoButton.isSelected; + _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected; + if (_isSelectOriginalPhoto) { + [self showPhotoBytes]; + if (!_selectButton.isSelected) { + // ��������������������������������� < ������������������ && ������������������������1��������������������� + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (_tzImagePickerVc.selectedModels.count < _tzImagePickerVc.maxImagesCount && _tzImagePickerVc.showSelectBtn) { + [self select:_selectButton]; + } + } + } +} + +#pragma mark - UIScrollViewDelegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + CGFloat offSetWidth = scrollView.contentOffset.x; + offSetWidth = offSetWidth + ((self.view.tz_width + 20) * 0.5); + + NSInteger currentIndex = offSetWidth / (self.view.tz_width + 20); + + if (currentIndex < _models.count && _currentIndex != currentIndex) { + _currentIndex = currentIndex; + [self refreshNaviBarAndBottomBarState]; + } +} + +#pragma mark - UICollectionViewDataSource && Delegate + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return _models.count; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + TZPhotoPreviewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZPhotoPreviewCell" forIndexPath:indexPath]; + cell.model = _models[indexPath.row]; + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; + cell.cropRect = _tzImagePickerVc.cropRect; + cell.allowCrop = _tzImagePickerVc.allowCrop; + __weak typeof(self) weakSelf = self; + if (!cell.singleTapGestureBlock) { + __weak typeof(_naviBar) weakNaviBar = _naviBar; + __weak typeof(_toolBar) weakToolBar = _toolBar; + cell.singleTapGestureBlock = ^(){ + // show or hide naviBar / ������������������������ + weakSelf.isHideNaviBar = !weakSelf.isHideNaviBar; + weakNaviBar.hidden = weakSelf.isHideNaviBar; + weakToolBar.hidden = weakSelf.isHideNaviBar; + }; + } + [cell setImageProgressUpdateBlock:^(double progress) { + weakSelf.progress = progress; + }]; + return cell; +} + +- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { + if ([cell isKindOfClass:[TZPhotoPreviewCell class]]) { + [(TZPhotoPreviewCell *)cell recoverSubviews]; + } +} + +- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { + if ([cell isKindOfClass:[TZPhotoPreviewCell class]]) { + [(TZPhotoPreviewCell *)cell recoverSubviews]; + } +} + +#pragma mark - Private Method + +- (void)dealloc { + //NSLog(@"TZPhotoPreviewController dealloc"); +} + +- (void)refreshNaviBarAndBottomBarState { + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; + TZAssetModel *model = _models[_currentIndex]; + _selectButton.selected = model.isSelected; + _numberLabel.text = [NSString stringWithFormat:@"%zd",_tzImagePickerVc.selectedModels.count]; + _numberImageView.hidden = (_tzImagePickerVc.selectedModels.count <= 0 || _isHideNaviBar || _isCropImage); + _numberLabel.hidden = (_tzImagePickerVc.selectedModels.count <= 0 || _isHideNaviBar || _isCropImage); + + _originalPhotoButton.selected = _isSelectOriginalPhoto; + _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected; + if (_isSelectOriginalPhoto) [self showPhotoBytes]; + + // If is previewing video, hide original photo button + // ��������������������������������������������������� + if (!_isHideNaviBar) { + if (model.type == TZAssetModelMediaTypeVideo) { + _originalPhotoButton.hidden = YES; + _originalPhotoLabel.hidden = YES; + } else { + _originalPhotoButton.hidden = NO; + if (_isSelectOriginalPhoto) _originalPhotoLabel.hidden = NO; + } + } + + _doneButton.hidden = NO; + _selectButton.hidden = !_tzImagePickerVc.showSelectBtn; + // ���������/������������ ������������������������ ��������������������� + if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) { + _numberLabel.hidden = YES; + _numberImageView.hidden = YES; + _selectButton.hidden = YES; + _originalPhotoButton.hidden = YES; + _originalPhotoLabel.hidden = YES; + _doneButton.hidden = YES; + } +} + +- (void)showPhotoBytes { + [[TZImageManager manager] getPhotosBytesWithArray:@[_models[_currentIndex]] completion:^(NSString *totalBytes) { + _originalPhotoLabel.text = [NSString stringWithFormat:@"(%@)",totalBytes]; + }]; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.h new file mode 100755 index 0000000..65d4459 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.h @@ -0,0 +1,15 @@ +// +// TZProgressView.h +// TZImagePickerController +// +// Created by ttouch on 2016/12/6. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface TZProgressView : UIView + +@property (nonatomic, assign) double progress; + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.m new file mode 100755 index 0000000..31a6182 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.m @@ -0,0 +1,55 @@ +// +// TZProgressView.m +// TZImagePickerController +// +// Created by ttouch on 2016/12/6. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import "TZProgressView.h" + +@interface TZProgressView () +@property (nonatomic, strong) CAShapeLayer *progressLayer; +@end + +@implementation TZProgressView + +- (instancetype)init { + self = [super init]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + + _progressLayer = [CAShapeLayer layer]; + _progressLayer.fillColor = [[UIColor clearColor] CGColor]; + _progressLayer.strokeColor = [[UIColor whiteColor] CGColor]; + _progressLayer.opacity = 1; + _progressLayer.lineCap = kCALineCapRound; + _progressLayer.lineWidth = 5; + + [_progressLayer setShadowColor:[UIColor blackColor].CGColor]; + [_progressLayer setShadowOffset:CGSizeMake(1, 1)]; + [_progressLayer setShadowOpacity:0.5]; + [_progressLayer setShadowRadius:2]; + } + return self; +} + +- (void)drawRect:(CGRect)rect { + CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2); + CGFloat radius = rect.size.width / 2; + CGFloat startA = - M_PI_2; + CGFloat endA = - M_PI_2 + M_PI * 2 * _progress; + _progressLayer.frame = self.bounds; + UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES]; + _progressLayer.path =[path CGPath]; + + [_progressLayer removeFromSuperlayer]; + [self.layer addSublayer:_progressLayer]; +} + +- (void)setProgress:(double)progress { + _progress = progress; + [self setNeedsDisplay]; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.h new file mode 100755 index 0000000..6886894 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.h @@ -0,0 +1,16 @@ +// +// TZVideoPlayerController.h +// TZImagePickerController +// +// Created by ������ on 16/1/5. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@class TZAssetModel; +@interface TZVideoPlayerController : UIViewController + +@property (nonatomic, strong) TZAssetModel *model; + +@end \ No newline at end of file diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m new file mode 100755 index 0000000..7f6ed2c --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m @@ -0,0 +1,170 @@ +// +// TZVideoPlayerController.m +// TZImagePickerController +// +// Created by ������ on 16/1/5. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import "TZVideoPlayerController.h" +#import <MediaPlayer/MediaPlayer.h> +#import "UIView+Layout.h" +#import "TZImageManager.h" +#import "TZAssetModel.h" +#import "TZImagePickerController.h" +#import "TZPhotoPreviewController.h" + +@interface TZVideoPlayerController () { + AVPlayer *_player; + UIButton *_playButton; + UIImage *_cover; + + UIView *_toolBar; + UIButton *_doneButton; + UIProgressView *_progress; + + UIStatusBarStyle _originStatusBarStyle; +} +@end + +@implementation TZVideoPlayerController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor blackColor]; + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (tzImagePickerVc) { + self.navigationItem.title = tzImagePickerVc.previewBtnTitleStr; + } + [self configMoviePlayer]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; + [UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; +} + +- (void)configMoviePlayer { + [[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { + _cover = photo; + }]; + [[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) { + dispatch_async(dispatch_get_main_queue(), ^{ + _player = [AVPlayer playerWithPlayerItem:playerItem]; + AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player]; + playerLayer.frame = self.view.bounds; + [self.view.layer addSublayer:playerLayer]; + [self addProgressObserver]; + [self configPlayButton]; + [self configBottomToolBar]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem]; + }); + }]; +} + +/// Show progress���do it next time / ������������������������������,������������ +- (void)addProgressObserver{ + AVPlayerItem *playerItem = _player.currentItem; + UIProgressView *progress = _progress; + [_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) { + float current = CMTimeGetSeconds(time); + float total = CMTimeGetSeconds([playerItem duration]); + if (current) { + [progress setProgress:(current/total) animated:YES]; + } + }]; +} + +- (void)configPlayButton { + _playButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _playButton.frame = CGRectMake(0, 64, self.view.tz_width, self.view.tz_height - 64 - 44); + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay.png"] forState:UIControlStateNormal]; + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlayHL.png"] forState:UIControlStateHighlighted]; + [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:_playButton]; +} + +- (void)configBottomToolBar { + _toolBar = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.tz_height - 44, self.view.tz_width, 44)]; + CGFloat rgb = 34 / 255.0; + _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7]; + + _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; + _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44); + _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; + [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; + if (tzImagePickerVc) { + [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; + } else { + [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal]; + [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal]; + } + [_toolBar addSubview:_doneButton]; + [self.view addSubview:_toolBar]; +} + +#pragma mark - Click Event + +- (void)playButtonClick { + CMTime currentTime = _player.currentItem.currentTime; + CMTime durationTime = _player.currentItem.duration; + if (_player.rate == 0.0f) { + if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)]; + [_player play]; + [self.navigationController setNavigationBarHidden:YES]; + _toolBar.hidden = YES; + [_playButton setImage:nil forState:UIControlStateNormal]; + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES; + } else { + [self pausePlayerAndShowNaviBar]; + } +} + +- (void)doneButtonClick { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + if (self.navigationController) { + if (imagePickerVc.autoDismiss) { + [self.navigationController dismissViewControllerAnimated:YES completion:^{ + [self callDelegateMethod]; + }]; + } + } else { + [self dismissViewControllerAnimated:YES completion:^{ + [self callDelegateMethod]; + }]; + } +} + +- (void)callDelegateMethod { + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; + if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) { + [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingVideo:_cover sourceAssets:_model.asset]; + } + if (imagePickerVc.didFinishPickingVideoHandle) { + imagePickerVc.didFinishPickingVideoHandle(_cover,_model.asset); + } +} + +#pragma mark - Notification Method + +- (void)pausePlayerAndShowNaviBar { + [_player pause]; + _toolBar.hidden = NO; + [self.navigationController setNavigationBarHidden:NO]; + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay.png"] forState:UIControlStateNormal]; + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = NO; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/UIView+Layout.h b/TZImagePickerController/TZImagePickerController/TZImagePickerController/UIView+Layout.h new file mode 100755 index 0000000..68cdab3 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/UIView+Layout.h @@ -0,0 +1,30 @@ +// +// UIView+Layout.h +// +// Created by ������ on 15/2/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +typedef enum : NSUInteger { + TZOscillatoryAnimationToBigger, + TZOscillatoryAnimationToSmaller, +} TZOscillatoryAnimationType; + +@interface UIView (Layout) + +@property (nonatomic) CGFloat tz_left; ///< Shortcut for frame.origin.x. +@property (nonatomic) CGFloat tz_top; ///< Shortcut for frame.origin.y +@property (nonatomic) CGFloat tz_right; ///< Shortcut for frame.origin.x + frame.size.width +@property (nonatomic) CGFloat tz_bottom; ///< Shortcut for frame.origin.y + frame.size.height +@property (nonatomic) CGFloat tz_width; ///< Shortcut for frame.size.width. +@property (nonatomic) CGFloat tz_height; ///< Shortcut for frame.size.height. +@property (nonatomic) CGFloat tz_centerX; ///< Shortcut for center.x +@property (nonatomic) CGFloat tz_centerY; ///< Shortcut for center.y +@property (nonatomic) CGPoint tz_origin; ///< Shortcut for frame.origin. +@property (nonatomic) CGSize tz_size; ///< Shortcut for frame.size. + ++ (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(TZOscillatoryAnimationType)type; + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZImagePickerController/UIView+Layout.m b/TZImagePickerController/TZImagePickerController/TZImagePickerController/UIView+Layout.m new file mode 100755 index 0000000..ee8949c --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZImagePickerController/UIView+Layout.m @@ -0,0 +1,125 @@ +// +// UIView+Layout.m +// +// Created by ������ on 15/2/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import "UIView+Layout.h" + +@implementation UIView (Layout) + +- (CGFloat)tz_left { + return self.frame.origin.x; +} + +- (void)setTz_left:(CGFloat)x { + CGRect frame = self.frame; + frame.origin.x = x; + self.frame = frame; +} + +- (CGFloat)tz_top { + return self.frame.origin.y; +} + +- (void)setTz_top:(CGFloat)y { + CGRect frame = self.frame; + frame.origin.y = y; + self.frame = frame; +} + +- (CGFloat)tz_right { + return self.frame.origin.x + self.frame.size.width; +} + +- (void)setTz_right:(CGFloat)right { + CGRect frame = self.frame; + frame.origin.x = right - frame.size.width; + self.frame = frame; +} + +- (CGFloat)tz_bottom { + return self.frame.origin.y + self.frame.size.height; +} + +- (void)setTz_bottom:(CGFloat)bottom { + CGRect frame = self.frame; + frame.origin.y = bottom - frame.size.height; + self.frame = frame; +} + +- (CGFloat)tz_width { + return self.frame.size.width; +} + +- (void)setTz_width:(CGFloat)width { + CGRect frame = self.frame; + frame.size.width = width; + self.frame = frame; +} + +- (CGFloat)tz_height { + return self.frame.size.height; +} + +- (void)setTz_height:(CGFloat)height { + CGRect frame = self.frame; + frame.size.height = height; + self.frame = frame; +} + +- (CGFloat)tz_centerX { + return self.center.x; +} + +- (void)setTz_centerX:(CGFloat)centerX { + self.center = CGPointMake(centerX, self.center.y); +} + +- (CGFloat)tz_centerY { + return self.center.y; +} + +- (void)setTz_centerY:(CGFloat)centerY { + self.center = CGPointMake(self.center.x, centerY); +} + +- (CGPoint)tz_origin { + return self.frame.origin; +} + +- (void)setTz_origin:(CGPoint)origin { + CGRect frame = self.frame; + frame.origin = origin; + self.frame = frame; +} + +- (CGSize)tz_size { + return self.frame.size; +} + +- (void)setTz_size:(CGSize)size { + CGRect frame = self.frame; + frame.size = size; + self.frame = frame; +} + ++ (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(TZOscillatoryAnimationType)type{ + NSNumber *animationScale1 = type == TZOscillatoryAnimationToBigger ? @(1.15) : @(0.5); + NSNumber *animationScale2 = type == TZOscillatoryAnimationToBigger ? @(0.92) : @(1.15); + + [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{ + [layer setValue:animationScale1 forKeyPath:@"transform.scale"]; + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{ + [layer setValue:animationScale2 forKeyPath:@"transform.scale"]; + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{ + [layer setValue:@(1.0) forKeyPath:@"transform.scale"]; + } completion:nil]; + }]; + }]; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/TZTestCell.h b/TZImagePickerController/TZImagePickerController/TZTestCell.h new file mode 100755 index 0000000..294bb1a --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZTestCell.h @@ -0,0 +1,23 @@ +// +// TZTestCell.h +// TZImagePickerController +// +// Created by ������ on 16/1/3. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface TZTestCell : UICollectionViewCell + +@property (nonatomic, strong) UIImageView *imageView; +@property (nonatomic, strong) UIImageView *videoImageView; +@property (nonatomic, strong) UIButton *deleteBtn; +@property (nonatomic, strong) UILabel *gifLable; +@property (nonatomic, assign) NSInteger row; +@property (nonatomic, strong) id asset; + +- (UIView *)snapshotView; + +@end + diff --git a/TZImagePickerController/TZImagePickerController/TZTestCell.m b/TZImagePickerController/TZImagePickerController/TZTestCell.m new file mode 100755 index 0000000..d74fbf4 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/TZTestCell.m @@ -0,0 +1,104 @@ +// +// TZTestCell.m +// TZImagePickerController +// +// Created by ������ on 16/1/3. +// Copyright �� 2016��� ������. All rights reserved. +// + +#import "TZTestCell.h" +#import "UIView+Layout.h" +#import <Photos/Photos.h> +#import <AssetsLibrary/AssetsLibrary.h> +#import "TZImagePickerController/TZImagePickerController.h" + +@implementation TZTestCell + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor whiteColor]; + _imageView = [[UIImageView alloc] init]; + _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500]; + _imageView.contentMode = UIViewContentModeScaleAspectFit; + [self addSubview:_imageView]; + self.clipsToBounds = YES; + + _videoImageView = [[UIImageView alloc] init]; + _videoImageView.image = [UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"]; + _videoImageView.contentMode = UIViewContentModeScaleAspectFill; + _videoImageView.hidden = YES; + [self addSubview:_videoImageView]; + + _deleteBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + [_deleteBtn setImage:[UIImage imageNamed:@"photo_delete"] forState:UIControlStateNormal]; + _deleteBtn.frame = CGRectMake(self.tz_width - 36, 0, 36, 36); + _deleteBtn.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 0, -10); + _deleteBtn.alpha = 0.6; + [self addSubview:_deleteBtn]; + + _gifLable = [[UILabel alloc] init]; + _gifLable.text = @"GIF"; + _gifLable.textColor = [UIColor whiteColor]; + _gifLable.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.8]; + _gifLable.textAlignment = NSTextAlignmentCenter; + _gifLable.font = [UIFont systemFontOfSize:10]; + _gifLable.frame = CGRectMake(self.tz_width - 25, self.tz_height - 14, 25, 14); + [self addSubview:_gifLable]; + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + _imageView.frame = self.bounds; + CGFloat width = self.tz_width / 3.0; + _videoImageView.frame = CGRectMake(width, width, width, width); +} + +- (void)setAsset:(id)asset +{ + _asset = asset; + if ([asset isKindOfClass:[PHAsset class]]) + { + PHAsset *phAsset = asset; + _videoImageView.hidden = phAsset.mediaType != PHAssetMediaTypeVideo; + _gifLable.hidden = ![[phAsset valueForKey:@"filename"] containsString:@"GIF"]; + } + else if ([asset isKindOfClass:[ALAsset class]]) + { + ALAsset *alAsset = asset; + _videoImageView.hidden = ![[alAsset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]; + _gifLable.hidden = YES; + } + } + +- (void)setRow:(NSInteger)row { + _row = row; + _deleteBtn.tag = row; +} + +- (UIView *)snapshotView { + UIView *snapshotView = [[UIView alloc]init]; + + UIView *cellSnapshotView = nil; + + if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) { + cellSnapshotView = [self snapshotViewAfterScreenUpdates:NO]; + } else { + CGSize size = CGSizeMake(self.bounds.size.width + 20, self.bounds.size.height + 20); + UIGraphicsBeginImageContextWithOptions(size, self.opaque, 0); + [self.layer renderInContext:UIGraphicsGetCurrentContext()]; + UIImage * cellSnapshotImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + cellSnapshotView = [[UIImageView alloc]initWithImage:cellSnapshotImage]; + } + + snapshotView.frame = CGRectMake(0, 0, cellSnapshotView.frame.size.width, cellSnapshotView.frame.size.height); + cellSnapshotView.frame = CGRectMake(0, 0, cellSnapshotView.frame.size.width, cellSnapshotView.frame.size.height); + + [snapshotView addSubview:cellSnapshotView]; + return snapshotView; +} + +@end diff --git a/TZImagePickerController/TZImagePickerController/ViewController.h b/TZImagePickerController/TZImagePickerController/ViewController.h new file mode 100755 index 0000000..80445ec --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface ViewController : UIViewController + + +@end + diff --git a/TZImagePickerController/TZImagePickerController/ViewController.m b/TZImagePickerController/TZImagePickerController/ViewController.m new file mode 100755 index 0000000..ef0f79a --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/ViewController.m @@ -0,0 +1,600 @@ +// +// ViewController.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import "ViewController.h" +#import "TZImagePickerController.h" +#import "UIView+Layout.h" +#import "TZTestCell.h" +#import <AssetsLibrary/AssetsLibrary.h> +#import <Photos/Photos.h> +#import "LxGridViewFlowLayout.h" +#import "TZImageManager.h" +#import "TZVideoPlayerController.h" +#import "TZPhotoPreviewController.h" +#import "TZGifPhotoPreviewController.h" + +@interface ViewController ()<TZImagePickerControllerDelegate,UICollectionViewDataSource,UICollectionViewDelegate,UIActionSheetDelegate,UIImagePickerControllerDelegate,UIAlertViewDelegate,UINavigationControllerDelegate> { + NSMutableArray *_selectedPhotos; + NSMutableArray *_selectedAssets; + BOOL _isSelectOriginalPhoto; // ������������������ + + CGFloat _itemWH; + CGFloat _margin; +} +@property (nonatomic, strong) UIImagePickerController *imagePickerVc; +@property (nonatomic, strong) UICollectionView *collectionView; +// 6��������������� +@property (weak, nonatomic) IBOutlet UISwitch *showTakePhotoBtnSwitch; ///< ��������������������������� +@property (weak, nonatomic) IBOutlet UISwitch *sortAscendingSwitch; ///< ��������������������������������� +@property (weak, nonatomic) IBOutlet UISwitch *allowPickingVideoSwitch; ///< ������������������ +@property (weak, nonatomic) IBOutlet UISwitch *allowPickingImageSwitch; ///< ������������������ +@property (weak, nonatomic) IBOutlet UISwitch *allowPickingGifSwitch; +@property (weak, nonatomic) IBOutlet UISwitch *allowPickingOriginalPhotoSwitch; ///< ������������������ +@property (weak, nonatomic) IBOutlet UISwitch *showSheetSwitch; ///< ������������sheet,��������������������������� +@property (weak, nonatomic) IBOutlet UITextField *maxCountTF; ///< ������������������������������������1������������������ +@property (weak, nonatomic) IBOutlet UITextField *columnNumberTF;// ��������������������� +@property (weak, nonatomic) IBOutlet UISwitch *allowCropSwitch; +@property (weak, nonatomic) IBOutlet UISwitch *needCircleCropSwitch; +@end + +@implementation ViewController + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +- (UIImagePickerController *)imagePickerVc +{ + if (_imagePickerVc == nil) + { + _imagePickerVc = [[UIImagePickerController alloc] init]; + _imagePickerVc.delegate = self; + // set appearance / ��������������������������������������� + _imagePickerVc.navigationBar.barTintColor = self.navigationController.navigationBar.barTintColor; + _imagePickerVc.navigationBar.tintColor = self.navigationController.navigationBar.tintColor; + UIBarButtonItem *tzBarItem, *BarItem; + if (iOS9Later) + { + tzBarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]]; + BarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UIImagePickerController class]]]; + } + else + { + tzBarItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil]; + BarItem = [UIBarButtonItem appearanceWhenContainedIn:[UIImagePickerController class], nil]; + } + + NSDictionary *titleTextAttributes = [tzBarItem titleTextAttributesForState:UIControlStateNormal]; + [BarItem setTitleTextAttributes:titleTextAttributes forState:UIControlStateNormal]; + } + return _imagePickerVc; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor whiteColor]; + _selectedPhotos = [NSMutableArray array]; + _selectedAssets = [NSMutableArray array]; + [self configCollectionView]; +} + +- (BOOL)prefersStatusBarHidden +{ + return NO; +} + +- (void)configCollectionView +{ + // ������������������������������������LxGridViewFlowLayout���������UICollectionViewFlowLayout������ + LxGridViewFlowLayout *layout = [[LxGridViewFlowLayout alloc] init]; + _margin = 4; + _itemWH = (self.view.tz_width - 2 * _margin - 4) / 3 - _margin; + layout.itemSize = CGSizeMake(_itemWH, _itemWH); + layout.minimumInteritemSpacing = _margin; + layout.minimumLineSpacing = _margin; + + _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 409, self.view.tz_width, self.view.tz_height - 409) collectionViewLayout:layout]; + CGFloat rgb = 244 / 255.0; + _collectionView.alwaysBounceVertical = YES; + _collectionView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0]; + _collectionView.contentInset = UIEdgeInsetsMake(4, 4, 4, 4); + _collectionView.dataSource = self; + _collectionView.delegate = self; + _collectionView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; + [self.view addSubview:_collectionView]; + [_collectionView registerClass:[TZTestCell class] forCellWithReuseIdentifier:@"TZTestCell"]; +} + +#pragma mark UICollectionView + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return _selectedPhotos.count + 1; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + TZTestCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZTestCell" forIndexPath:indexPath]; + cell.videoImageView.hidden = YES; + if (indexPath.row == _selectedPhotos.count) + { + cell.imageView.image = [UIImage imageNamed:@"AlbumAddBtn.png"]; + cell.deleteBtn.hidden = YES; + cell.gifLable.hidden = YES; + } + else + { + cell.imageView.image = _selectedPhotos[indexPath.row]; + cell.asset = _selectedAssets[indexPath.row]; + cell.deleteBtn.hidden = NO; + } + + // ������������������������gif������ + if (!self.allowPickingGifSwitch.isOn) + { + cell.gifLable.hidden = YES; + } + + cell.deleteBtn.tag = indexPath.row; + [cell.deleteBtn addTarget:self action:@selector(deleteBtnClik:) forControlEvents:UIControlEventTouchUpInside]; + return cell; +} + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.row == _selectedPhotos.count) + { + BOOL showSheet = self.showSheetSwitch.isOn; + if (showSheet) + { + UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"������" destructiveButtonTitle:nil otherButtonTitles:@"������",@"���������������", nil]; + [sheet showInView:self.view]; + } + else + { + [self pushImagePickerController]; + } + } + else + { + // preview photos or video / ������������������������ + id asset = _selectedAssets[indexPath.row]; + BOOL isVideo = NO; + if ([asset isKindOfClass:[PHAsset class]]) + { + PHAsset *phAsset = asset; + isVideo = phAsset.mediaType == PHAssetMediaTypeVideo; + } + else if ([asset isKindOfClass:[ALAsset class]]) + { + ALAsset *alAsset = asset; + isVideo = [[alAsset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]; + } + + if ([[asset valueForKey:@"filename"] containsString:@"GIF"] && self.allowPickingGifSwitch.isOn) + { + TZGifPhotoPreviewController *vc = [[TZGifPhotoPreviewController alloc] init]; + TZAssetModel *model = [TZAssetModel modelWithAsset:asset type:TZAssetModelMediaTypePhotoGif timeLength:@""]; + vc.model = model; + [self presentViewController:vc animated:YES completion:nil]; + } + else if (isVideo) + { // perview video / ������������ + TZVideoPlayerController *vc = [[TZVideoPlayerController alloc] init]; + TZAssetModel *model = [TZAssetModel modelWithAsset:asset type:TZAssetModelMediaTypeVideo timeLength:@""]; + vc.model = model; + [self presentViewController:vc animated:YES completion:nil]; + } + else + { // preview photos / ������������ + TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithSelectedAssets:_selectedAssets selectedPhotos:_selectedPhotos index:indexPath.row]; + imagePickerVc.maxImagesCount = self.maxCountTF.text.integerValue; + imagePickerVc.allowPickingOriginalPhoto = self.allowPickingOriginalPhotoSwitch.isOn; + imagePickerVc.isSelectOriginalPhoto = _isSelectOriginalPhoto; + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) + { + _selectedPhotos = [NSMutableArray arrayWithArray:photos]; + _selectedAssets = [NSMutableArray arrayWithArray:assets]; + _isSelectOriginalPhoto = isSelectOriginalPhoto; + [_collectionView reloadData]; + _collectionView.contentSize = CGSizeMake(0, ((_selectedPhotos.count + 2) / 3 ) * (_margin + _itemWH)); + }]; + + [self presentViewController:imagePickerVc animated:YES completion:nil]; + } + } +} + +#pragma mark - LxGridViewDataSource + +/// ��������������������������������������������� +- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath +{ + return indexPath.item < _selectedPhotos.count; +} + +- (BOOL)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)sourceIndexPath canMoveToIndexPath:(NSIndexPath *)destinationIndexPath { + return (sourceIndexPath.item < _selectedPhotos.count && destinationIndexPath.item < _selectedPhotos.count); +} + +- (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)sourceIndexPath didMoveToIndexPath:(NSIndexPath *)destinationIndexPath { + UIImage *image = _selectedPhotos[sourceIndexPath.item]; + [_selectedPhotos removeObjectAtIndex:sourceIndexPath.item]; + [_selectedPhotos insertObject:image atIndex:destinationIndexPath.item]; + + id asset = _selectedAssets[sourceIndexPath.item]; + [_selectedAssets removeObjectAtIndex:sourceIndexPath.item]; + [_selectedAssets insertObject:asset atIndex:destinationIndexPath.item]; + + [_collectionView reloadData]; +} + +#pragma mark - TZImagePickerController + +- (void)pushImagePickerController +{ + if (self.maxCountTF.text.integerValue <= 0) + { + return; + } + + TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:self.maxCountTF.text.integerValue columnNumber:self.columnNumberTF.text.integerValue delegate:self pushPhotoPickerVc:YES]; + + +#pragma mark - ������������������������������������������������������������������������������ + imagePickerVc.isSelectOriginalPhoto = _isSelectOriginalPhoto; + + if (self.maxCountTF.text.integerValue > 1) + { + // 1.��������������������������������������� + imagePickerVc.selectedAssets = _selectedAssets; // ��������������������������������� + } + + imagePickerVc.allowTakePicture = self.showTakePhotoBtnSwitch.isOn; // ��������������������������� + + // 2. Set the appearance + // 2. ���������������imagePickerVc��������� + // imagePickerVc.navigationBar.barTintColor = [UIColor greenColor]; + // imagePickerVc.oKButtonTitleColorDisabled = [UIColor lightGrayColor]; + // imagePickerVc.oKButtonTitleColorNormal = [UIColor greenColor]; + // imagePickerVc.navigationBar.translucent = NO; + + // 3. Set allow picking video & photo & originalPhoto or not + // 3. ������������������������������/������/������ + imagePickerVc.allowPickingVideo = self.allowPickingVideoSwitch.isOn; + imagePickerVc.allowPickingImage = self.allowPickingImageSwitch.isOn; + imagePickerVc.allowPickingOriginalPhoto = self.allowPickingOriginalPhotoSwitch.isOn; + imagePickerVc.allowPickingGif = self.allowPickingGifSwitch.isOn; + + // 4. ��������������������������������� + imagePickerVc.sortAscendingByModificationDate = self.sortAscendingSwitch.isOn; + + // imagePickerVc.minImagesCount = 3; + // imagePickerVc.alwaysEnableDoneBtn = YES; + + // imagePickerVc.minPhotoWidthSelectable = 3000; + // imagePickerVc.minPhotoHeightSelectable = 2000; + + /// 5. Single selection mode, valid when maxImagesCount = 1 + /// 5. ������������,maxImagesCount���1������������ + imagePickerVc.showSelectBtn = NO; + imagePickerVc.allowCrop = self.allowCropSwitch.isOn; + imagePickerVc.needCircleCrop = self.needCircleCropSwitch.isOn; + imagePickerVc.circleCropRadius = 100; + /* + [imagePickerVc setCropViewSettingBlock:^(UIView *cropView) { + cropView.layer.borderColor = [UIColor redColor].CGColor; + cropView.layer.borderWidth = 2.0; + }];*/ + + //imagePickerVc.allowPreview = NO; +#pragma mark - ��������������� + + // You can get the photos by block, the same as by delegate. + // ���������������block���������������������������������������������. + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) + { + + }]; + + [self presentViewController:imagePickerVc animated:YES completion:nil]; +} + +#pragma mark - UIImagePickerController + +- (void)takePhoto +{ + AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + if ((authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied) && iOS7Later) + { + // ��������������� ������������������������ + UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"������������������" message:@"������iPhone���""������-������-������""���������������������" delegate:self cancelButtonTitle:@"������" otherButtonTitles:@"������", nil]; + [alert show]; + // ��������������������������������������� + } else if ([[TZImageManager manager] authorizationStatus] == 2) { // ��������������������������������������������������������������� + UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"������������������" message:@"������iPhone���""������-������-������""���������������������" delegate:self cancelButtonTitle:@"������" otherButtonTitles:@"������", nil]; + alert.tag = 1; + [alert show]; + } + else if ([[TZImageManager manager] authorizationStatus] == 0) + { + // ��������������������������������������������������������������������� + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + return [self takePhoto]; + }); + } + else + { // ������������ + UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; + if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) + { + self.imagePickerVc.sourceType = sourceType; + if(iOS8Later) { + _imagePickerVc.modalPresentationStyle = UIModalPresentationOverCurrentContext; + } + [self presentViewController:_imagePickerVc animated:YES completion:nil]; + } + else + { + NSLog(@"���������������������������������,���������������������"); + } + } +} + +- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info +{ + [picker dismissViewControllerAnimated:YES completion:nil]; + NSString *type = [info objectForKey:UIImagePickerControllerMediaType]; + if ([type isEqualToString:@"public.image"]) + { + TZImagePickerController *tzImagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:self]; + tzImagePickerVc.sortAscendingByModificationDate = self.sortAscendingSwitch.isOn; + [tzImagePickerVc showProgressHUD]; + UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; + // save photo and get asset / ������������������������asset + [[TZImageManager manager] savePhotoWithImage:image completion:^(NSError *error) + { + if (error) + { + [tzImagePickerVc hideProgressHUD]; + NSLog(@"������������������ %@",error); + } + else + { + [[TZImageManager manager] getCameraRollAlbum:NO allowPickingImage:YES completion:^(TZAlbumModel *model) { + [[TZImageManager manager] getAssetsFromFetchResult:model.result allowPickingVideo:NO allowPickingImage:YES completion:^(NSArray<TZAssetModel *> *models) { + [tzImagePickerVc hideProgressHUD]; + TZAssetModel *assetModel = [models firstObject]; + if (tzImagePickerVc.sortAscendingByModificationDate) + { + assetModel = [models lastObject]; + } + + if (self.allowCropSwitch.isOn) + { + // ������������,��������� + TZImagePickerController *imagePicker = [[TZImagePickerController alloc] initCropTypeWithAsset:assetModel.asset photo:image completion:^(UIImage *cropImage, id asset) + { + [self refreshCollectionViewWithAddedAsset:asset image:cropImage]; + }]; + + imagePicker.needCircleCrop = self.needCircleCropSwitch.isOn; + imagePicker.circleCropRadius = 100; + [self presentViewController:imagePicker animated:YES completion:nil]; + } + else + { + [self refreshCollectionViewWithAddedAsset:assetModel.asset image:image]; + } + }]; + }]; + } + }]; + } +} + +- (void)refreshCollectionViewWithAddedAsset:(id)asset image:(UIImage *)image +{ + [_selectedAssets addObject:asset]; + [_selectedPhotos addObject:image]; + [_collectionView reloadData]; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker +{ + if ([picker isKindOfClass:[UIImagePickerController class]]) { + [picker dismissViewControllerAnimated:YES completion:nil]; + } +} + +#pragma mark - UIActionSheetDelegate + +- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { + if (buttonIndex == 0) { // take photo / ��������� + [self takePhoto]; + } else if (buttonIndex == 1) { + [self pushImagePickerController]; + } +} + +#pragma mark - UIAlertViewDelegate + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + if (buttonIndex == 1) { // ������������������������������������������ + if (iOS8Later) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + } else { + NSURL *privacyUrl; + if (alertView.tag == 1) { + privacyUrl = [NSURL URLWithString:@"prefs:root=Privacy&path=PHOTOS"]; + } else { + privacyUrl = [NSURL URLWithString:@"prefs:root=Privacy&path=CAMERA"]; + } + if ([[UIApplication sharedApplication] canOpenURL:privacyUrl]) { + [[UIApplication sharedApplication] openURL:privacyUrl]; + } else { + UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"������" message:@"������������������������������������������������������������������������" delegate:nil cancelButtonTitle:@"������" otherButtonTitles: nil]; + [alert show]; + } + } + } +} + +#pragma mark - TZImagePickerControllerDelegate + +/// User click cancel button +/// ��������������������� +- (void)tz_imagePickerControllerDidCancel:(TZImagePickerController *)picker { + // NSLog(@"cancel"); + } + +// The picker should dismiss itself; when it dismissed these handle will be called. +// If isOriginalPhoto is YES, user picked the original photo. +// You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:]. +// The UIImage Object in photos default width is 828px, you can set it by photoWidth property. +// ������������������������������dismiss���������������dismiss������������������������������������������ +// ������isSelectOriginalPhoto���YES������������������������������ +// ���������������������asset������������������������������������[[TZImageManager manager] getOriginalPhotoWithAsset:completion:] +// photos������������UIImage������������������828���������������������������������photoWidth������������������������ +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto { + _selectedPhotos = [NSMutableArray arrayWithArray:photos]; + _selectedAssets = [NSMutableArray arrayWithArray:assets]; + _isSelectOriginalPhoto = isSelectOriginalPhoto; + [_collectionView reloadData]; + // _collectionView.contentSize = CGSizeMake(0, ((_selectedPhotos.count + 2) / 3 ) * (_margin + _itemWH)); + + // 1.������������������ + [self printAssetsName:assets]; +} + +// If user picking a video, this callback will be called. +// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class. +// ���������������������������������������������handle������������ +// ������������������������iOS8���asset���PHAsset������������������������ALAsset������������ +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(id)asset { + _selectedPhotos = [NSMutableArray arrayWithArray:@[coverImage]]; + _selectedAssets = [NSMutableArray arrayWithArray:@[asset]]; + // open this code to send video / ������������������������������ + // [[TZImageManager manager] getVideoOutputPathWithAsset:asset completion:^(NSString *outputPath) { + // NSLog(@"���������������������������,���������������:%@",outputPath); + // Export completed, send video here, send by outputPath or NSData + // ������������������������������������������������������������������NSData������ + + // }]; + [_collectionView reloadData]; + // _collectionView.contentSize = CGSizeMake(0, ((_selectedPhotos.count + 2) / 3 ) * (_margin + _itemWH)); +} + +// If user picking a gif image, this callback will be called. +// ���������������������������gif������������������handle������������ +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingGifImage:(UIImage *)animatedImage sourceAssets:(id)asset { + _selectedPhotos = [NSMutableArray arrayWithArray:@[animatedImage]]; + _selectedAssets = [NSMutableArray arrayWithArray:@[asset]]; + [_collectionView reloadData]; +} + +#pragma mark - Click Event + +- (void)deleteBtnClik:(UIButton *)sender { + [_selectedPhotos removeObjectAtIndex:sender.tag]; + [_selectedAssets removeObjectAtIndex:sender.tag]; + + [_collectionView performBatchUpdates:^{ + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:sender.tag inSection:0]; + [_collectionView deleteItemsAtIndexPaths:@[indexPath]]; + } completion:^(BOOL finished) { + [_collectionView reloadData]; + }]; +} + +- (IBAction)showTakePhotoBtnSwitchClick:(UISwitch *)sender { + if (sender.isOn) { + [_showSheetSwitch setOn:NO animated:YES]; + [_allowPickingImageSwitch setOn:YES animated:YES]; + } +} + +- (IBAction)showSheetSwitchClick:(UISwitch *)sender { + if (sender.isOn) { + [_showTakePhotoBtnSwitch setOn:NO animated:YES]; + [_allowPickingImageSwitch setOn:YES animated:YES]; + } +} + +- (IBAction)allowPickingOriginPhotoSwitchClick:(UISwitch *)sender { + if (sender.isOn) { + [_allowPickingImageSwitch setOn:YES animated:YES]; + [self.needCircleCropSwitch setOn:NO animated:YES]; + [self.allowCropSwitch setOn:NO animated:YES]; + } +} + +- (IBAction)allowPickingImageSwitchClick:(UISwitch *)sender { + if (!sender.isOn) { + [_allowPickingOriginalPhotoSwitch setOn:NO animated:YES]; + [_showTakePhotoBtnSwitch setOn:NO animated:YES]; + [_allowPickingVideoSwitch setOn:YES animated:YES]; + [_allowPickingGifSwitch setOn:NO animated:YES]; + } +} + +- (IBAction)allowPickingGifSwitchClick:(UISwitch *)sender { + if (sender.isOn) { + [_allowPickingImageSwitch setOn:YES animated:YES]; + } +} + +- (IBAction)allowPickingVideoSwitchClick:(UISwitch *)sender { + if (!sender.isOn) { + [_allowPickingImageSwitch setOn:YES animated:YES]; + } +} + +- (IBAction)allowCropSwitchClick:(UISwitch *)sender { + if (sender.isOn) { + self.maxCountTF.text = @"1"; + [self.allowPickingOriginalPhotoSwitch setOn:NO animated:YES]; + } else { + [self.needCircleCropSwitch setOn:NO animated:YES]; + } +} + +- (IBAction)needCircleCropSwitchClick:(UISwitch *)sender { + if (sender.isOn) { + [self.allowCropSwitch setOn:YES animated:YES]; + self.maxCountTF.text = @"1"; + [self.allowPickingOriginalPhotoSwitch setOn:NO animated:YES]; + } +} + +- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { + [self.view endEditing:YES]; +} + +#pragma mark - Private + +/// ������������������ +- (void)printAssetsName:(NSArray *)assets { + NSString *fileName; + for (id asset in assets) { + if ([asset isKindOfClass:[PHAsset class]]) { + PHAsset *phAsset = (PHAsset *)asset; + fileName = [phAsset valueForKey:@"filename"]; + } else if ([asset isKindOfClass:[ALAsset class]]) { + ALAsset *alAsset = (ALAsset *)asset; + fileName = alAsset.defaultRepresentation.filename;; + } + //NSLog(@"������������:%@",fileName); + } +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { + return UIInterfaceOrientationMaskPortrait; +} +#pragma clang diagnostic pop + +@end diff --git a/TZImagePickerController/TZImagePickerController/main.m b/TZImagePickerController/TZImagePickerController/main.m new file mode 100755 index 0000000..2c76a8c --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/main.m @@ -0,0 +1,16 @@ +// +// main.m +// TZImagePickerController +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/TZImagePickerController/TZImagePickerController/zh-Hans.lproj/LaunchScreen.strings b/TZImagePickerController/TZImagePickerController/zh-Hans.lproj/LaunchScreen.strings new file mode 100755 index 0000000..8b13789 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/zh-Hans.lproj/LaunchScreen.strings @@ -0,0 +1 @@ + diff --git a/TZImagePickerController/TZImagePickerController/zh-Hans.lproj/Main.strings b/TZImagePickerController/TZImagePickerController/zh-Hans.lproj/Main.strings new file mode 100755 index 0000000..64c63b6 --- /dev/null +++ b/TZImagePickerController/TZImagePickerController/zh-Hans.lproj/Main.strings @@ -0,0 +1,18 @@ + +/* Class = "UILabel"; text = "������������������������"; ObjectID = "7mi-Lf-2N5"; */ +"7mi-Lf-2N5.text" = "������������������������"; + +/* Class = "UILabel"; text = "������������������������"; ObjectID = "R92-Zn-NWV"; */ +"R92-Zn-NWV.text" = "������������������������"; + +/* Class = "UILabel"; text = "���������������������������������"; ObjectID = "UL3-n3-Hmt"; */ +"UL3-n3-Hmt.text" = "���������������������������������"; + +/* Class = "UILabel"; text = "���������������������������"; ObjectID = "jop-5R-ioj"; */ +"jop-5R-ioj.text" = "���������������������������"; + +/* Class = "UILabel"; text = "������������������"; ObjectID = "vNN-OI-9z1"; */ +"vNN-OI-9z1.text" = "������������������"; + +/* Class = "UILabel"; text = "������������������"; ObjectID = "xCu-D3-IZg"; */ +"xCu-D3-IZg.text" = "������������������"; diff --git a/test/testUITests/Info.plist b/TZImagePickerController/TZImagePickerControllerTests/Info.plist old mode 100644 new mode 100755 similarity index 100% copy from test/testUITests/Info.plist copy to TZImagePickerController/TZImagePickerControllerTests/Info.plist diff --git a/TZImagePickerController/TZImagePickerControllerTests/TZImagePickerControllerTests.m b/TZImagePickerController/TZImagePickerControllerTests/TZImagePickerControllerTests.m new file mode 100755 index 0000000..565b02b --- /dev/null +++ b/TZImagePickerController/TZImagePickerControllerTests/TZImagePickerControllerTests.m @@ -0,0 +1,39 @@ +// +// TZImagePickerControllerTests.m +// TZImagePickerControllerTests +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <XCTest/XCTest.h> + +@interface TZImagePickerControllerTests : XCTestCase + +@end + +@implementation TZImagePickerControllerTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/test/testUITests/Info.plist b/TZImagePickerController/TZImagePickerControllerUITests/Info.plist old mode 100644 new mode 100755 similarity index 100% copy from test/testUITests/Info.plist copy to TZImagePickerController/TZImagePickerControllerUITests/Info.plist diff --git a/TZImagePickerController/TZImagePickerControllerUITests/TZImagePickerControllerUITests.m b/TZImagePickerController/TZImagePickerControllerUITests/TZImagePickerControllerUITests.m new file mode 100755 index 0000000..ca4f9c9 --- /dev/null +++ b/TZImagePickerController/TZImagePickerControllerUITests/TZImagePickerControllerUITests.m @@ -0,0 +1,40 @@ +// +// TZImagePickerControllerUITests.m +// TZImagePickerControllerUITests +// +// Created by ������ on 15/12/24. +// Copyright �� 2015��� ������. All rights reserved. +// + +#import <XCTest/XCTest.h> + +@interface TZImagePickerControllerUITests : XCTestCase + +@end + +@implementation TZImagePickerControllerUITests + +- (void)setUp { + [super setUp]; + + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + self.continueAfterFailure = NO; + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + [[[XCUIApplication alloc] init] launch]; + + // In UI tests it���s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +@end diff --git a/camerademo/camerademo.xcodeproj/project.pbxproj b/camerademo/camerademo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a75fd57 --- /dev/null +++ b/camerademo/camerademo.xcodeproj/project.pbxproj @@ -0,0 +1,317 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + E52F59F01E5C21890084B3E2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E52F59EF1E5C21890084B3E2 /* main.m */; }; + E52F59F31E5C21890084B3E2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E52F59F21E5C21890084B3E2 /* AppDelegate.m */; }; + E52F59F61E5C21890084B3E2 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E52F59F51E5C21890084B3E2 /* ViewController.m */; }; + E52F59F91E5C21890084B3E2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E52F59F71E5C21890084B3E2 /* Main.storyboard */; }; + E52F59FB1E5C21890084B3E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E52F59FA1E5C21890084B3E2 /* Assets.xcassets */; }; + E52F59FE1E5C21890084B3E2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E52F59FC1E5C21890084B3E2 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + E52F59EB1E5C21890084B3E2 /* camerademo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = camerademo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E52F59EF1E5C21890084B3E2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + E52F59F11E5C21890084B3E2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; + E52F59F21E5C21890084B3E2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; + E52F59F41E5C21890084B3E2 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; + E52F59F51E5C21890084B3E2 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; + E52F59F81E5C21890084B3E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; + E52F59FA1E5C21890084B3E2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; + E52F59FD1E5C21890084B3E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; + E52F59FF1E5C21890084B3E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E52F59E81E5C21890084B3E2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + E52F59E21E5C21890084B3E2 = { + isa = PBXGroup; + children = ( + E52F59ED1E5C21890084B3E2 /* camerademo */, + E52F59EC1E5C21890084B3E2 /* Products */, + ); + sourceTree = "<group>"; + }; + E52F59EC1E5C21890084B3E2 /* Products */ = { + isa = PBXGroup; + children = ( + E52F59EB1E5C21890084B3E2 /* camerademo.app */, + ); + name = Products; + sourceTree = "<group>"; + }; + E52F59ED1E5C21890084B3E2 /* camerademo */ = { + isa = PBXGroup; + children = ( + E52F59F11E5C21890084B3E2 /* AppDelegate.h */, + E52F59F21E5C21890084B3E2 /* AppDelegate.m */, + E52F59F41E5C21890084B3E2 /* ViewController.h */, + E52F59F51E5C21890084B3E2 /* ViewController.m */, + E52F59F71E5C21890084B3E2 /* Main.storyboard */, + E52F59FA1E5C21890084B3E2 /* Assets.xcassets */, + E52F59FC1E5C21890084B3E2 /* LaunchScreen.storyboard */, + E52F59FF1E5C21890084B3E2 /* Info.plist */, + E52F59EE1E5C21890084B3E2 /* Supporting Files */, + ); + path = camerademo; + sourceTree = "<group>"; + }; + E52F59EE1E5C21890084B3E2 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + E52F59EF1E5C21890084B3E2 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + E52F59EA1E5C21890084B3E2 /* camerademo */ = { + isa = PBXNativeTarget; + buildConfigurationList = E52F5A021E5C21890084B3E2 /* Build configuration list for PBXNativeTarget "camerademo" */; + buildPhases = ( + E52F59E71E5C21890084B3E2 /* Sources */, + E52F59E81E5C21890084B3E2 /* Frameworks */, + E52F59E91E5C21890084B3E2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = camerademo; + productName = camerademo; + productReference = E52F59EB1E5C21890084B3E2 /* camerademo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E52F59E31E5C21890084B3E2 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = WindShan; + TargetAttributes = { + E52F59EA1E5C21890084B3E2 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = VGXA77XL6T; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = E52F59E61E5C21890084B3E2 /* Build configuration list for PBXProject "camerademo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = E52F59E21E5C21890084B3E2; + productRefGroup = E52F59EC1E5C21890084B3E2 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E52F59EA1E5C21890084B3E2 /* camerademo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E52F59E91E5C21890084B3E2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E52F59FE1E5C21890084B3E2 /* LaunchScreen.storyboard in Resources */, + E52F59FB1E5C21890084B3E2 /* Assets.xcassets in Resources */, + E52F59F91E5C21890084B3E2 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E52F59E71E5C21890084B3E2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E52F59F61E5C21890084B3E2 /* ViewController.m in Sources */, + E52F59F31E5C21890084B3E2 /* AppDelegate.m in Sources */, + E52F59F01E5C21890084B3E2 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + E52F59F71E5C21890084B3E2 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + E52F59F81E5C21890084B3E2 /* Base */, + ); + name = Main.storyboard; + sourceTree = "<group>"; + }; + E52F59FC1E5C21890084B3E2 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + E52F59FD1E5C21890084B3E2 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = "<group>"; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + E52F5A001E5C21890084B3E2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + E52F5A011E5C21890084B3E2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + E52F5A031E5C21890084B3E2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = VGXA77XL6T; + INFOPLIST_FILE = camerademo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.moral.camerademo.camerademo; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + E52F5A041E5C21890084B3E2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = VGXA77XL6T; + INFOPLIST_FILE = camerademo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.moral.camerademo.camerademo; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E52F59E61E5C21890084B3E2 /* Build configuration list for PBXProject "camerademo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E52F5A001E5C21890084B3E2 /* Debug */, + E52F5A011E5C21890084B3E2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E52F5A021E5C21890084B3E2 /* Build configuration list for PBXNativeTarget "camerademo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E52F5A031E5C21890084B3E2 /* Debug */, + E52F5A041E5C21890084B3E2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = E52F59E31E5C21890084B3E2 /* Project object */; +} diff --git a/camerademo/camerademo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/camerademo/camerademo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..ac29a49 --- /dev/null +++ b/camerademo/camerademo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:camerademo.xcodeproj"> + </FileRef> +</Workspace> diff --git a/camerademo/camerademo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate b/camerademo/camerademo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..3f97b50 --- /dev/null +++ b/camerademo/camerademo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate Binary files differ diff --git a/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/camerademo.xcscheme b/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/camerademo.xcscheme new file mode 100644 index 0000000..b422b1d --- /dev/null +++ b/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/camerademo.xcscheme @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0820" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + </Testables> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist b/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..01e9d0f --- /dev/null +++ b/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>SchemeUserState</key> + <dict> + <key>camerademo.xcscheme</key> + <dict> + <key>orderHint</key> + <integer>0</integer> + </dict> + </dict> + <key>SuppressBuildableAutocreation</key> + <dict> + <key>E52F59EA1E5C21890084B3E2</key> + <dict> + <key>primary</key> + <true/> + </dict> + </dict> +</dict> +</plist> diff --git a/camerademo/camerademo/AppDelegate.h b/camerademo/camerademo/AppDelegate.h new file mode 100644 index 0000000..ca2a55e --- /dev/null +++ b/camerademo/camerademo/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// camerademo +// +// Created by WindShan on 2017/2/21. +// Copyright �� 2017��� WindShan. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface AppDelegate : UIResponder <UIApplicationDelegate> + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/camerademo/camerademo/AppDelegate.m b/camerademo/camerademo/AppDelegate.m new file mode 100644 index 0000000..c5b854e --- /dev/null +++ b/camerademo/camerademo/AppDelegate.m @@ -0,0 +1,51 @@ +// +// AppDelegate.m +// camerademo +// +// Created by WindShan on 2017/2/21. +// Copyright �� 2017��� WindShan. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. +} + + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. +} + + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + + +@end diff --git a/test/test/Assets.xcassets/AppIcon.appiconset/Contents.json b/camerademo/camerademo/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% copy from test/test/Assets.xcassets/AppIcon.appiconset/Contents.json copy to camerademo/camerademo/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/camerademo/camerademo/Base.lproj/LaunchScreen.storyboard b/camerademo/camerademo/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/camerademo/camerademo/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> + <dependencies> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="EHf-IW-A2E"> + <objects> + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/> + <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="53" y="375"/> + </scene> + </scenes> +</document> diff --git a/test/test/Base.lproj/Main.storyboard b/camerademo/camerademo/Base.lproj/Main.storyboard similarity index 70% rename from test/test/Base.lproj/Main.storyboard rename to camerademo/camerademo/Base.lproj/Main.storyboard index f56d2f3..4529698 100644 --- a/test/test/Base.lproj/Main.storyboard +++ b/camerademo/camerademo/Base.lproj/Main.storyboard @@ -1,7 +1,8 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> <dependencies> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <scenes> <!--View Controller--> @@ -13,9 +14,9 @@ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> </layoutGuides> <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> - <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> - <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> </view> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> diff --git a/camerademo/camerademo/Info.plist b/camerademo/camerademo/Info.plist new file mode 100644 index 0000000..38e98af --- /dev/null +++ b/camerademo/camerademo/Info.plist @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>en</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleVersion</key> + <string>1</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIMainStoryboardFile</key> + <string>Main</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>armv7</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> +</dict> +</plist> diff --git a/camerademo/camerademo/ViewController.h b/camerademo/camerademo/ViewController.h new file mode 100644 index 0000000..ca96e2d --- /dev/null +++ b/camerademo/camerademo/ViewController.h @@ -0,0 +1,15 @@ +// +// ViewController.h +// camerademo +// +// Created by WindShan on 2017/2/21. +// Copyright �� 2017��� WindShan. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface ViewController : UIViewController + + +@end + diff --git a/camerademo/camerademo/ViewController.m b/camerademo/camerademo/ViewController.m new file mode 100644 index 0000000..d49c4e7 --- /dev/null +++ b/camerademo/camerademo/ViewController.m @@ -0,0 +1,29 @@ +// +// ViewController.m +// camerademo +// +// Created by WindShan on 2017/2/21. +// Copyright �� 2017��� WindShan. All rights reserved. +// + +#import "ViewController.h" + +@interface ViewController () + +@end + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. +} + + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + + +@end diff --git a/camerademo/camerademo/demo/FileManager/MPFileManager.h b/camerademo/camerademo/demo/FileManager/MPFileManager.h new file mode 100755 index 0000000..15562d4 --- /dev/null +++ b/camerademo/camerademo/demo/FileManager/MPFileManager.h @@ -0,0 +1,31 @@ +// +// MPFileManager.h +// MobileProject ��������������� +// +// Created by wujunyang on 16/7/22. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import <AssetsLibrary/ALAsset.h> +#import <AssetsLibrary/ALAssetsLibrary.h> +#import <AssetsLibrary/ALAssetsGroup.h> +#import <AssetsLibrary/ALAssetRepresentation.h> + +@interface MPFileManager : NSObject + ++ (MPFileManager *)sharedManager; + +//������������������ ++ (NSString *)downloadPath; +//������������������ ++ (NSString *)uploadPath; + +//���������������������APP������������ ++ (BOOL)writeUploadDataWithName:(NSString *)fileName andAsset:(ALAsset *)asset; +//���������������������APP������������ ++ (BOOL)writeUploadDataWithName:(NSString *)fileName andImage:(UIImage *)image; +//������APP��������������������� ++ (BOOL)deleteUploadDataWithName:(NSString *)fileName; + +@end diff --git a/camerademo/camerademo/demo/FileManager/MPFileManager.m b/camerademo/camerademo/demo/FileManager/MPFileManager.m new file mode 100755 index 0000000..f514428 --- /dev/null +++ b/camerademo/camerademo/demo/FileManager/MPFileManager.m @@ -0,0 +1,133 @@ +// +// MPFileManager.m +// MobileProject +// +// Created by wujunyang on 16/7/22. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import "MPFileManager.h" + +@implementation MPFileManager + ++ (MPFileManager *)sharedManager { + static MPFileManager *_sharedManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _sharedManager = [[MPFileManager alloc] init]; + }); + return _sharedManager; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [[self class] createFolder:[[self class] downloadPath]]; + [[self class] createFolder:[[self class] uploadPath]]; + } + return self; +} + +/** + * @author wujunyang, 16-07-22 11:07:41 + * + * @brief ������������������ + * + * @return <#return value description#> + */ ++ (NSString *)downloadPath{ + NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; + NSString *downloadPath = [documentPath stringByAppendingPathComponent:@"MobileProject_Download"]; + return downloadPath; +} + +/** + * @author wujunyang, 16-07-22 11:07:58 + * + * @brief ������������������ + * + * @return <#return value description#> + */ ++ (NSString *)uploadPath{ + NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; + NSString *uploadPath = [documentPath stringByAppendingPathComponent:@"MobileProject_Upload"]; + return uploadPath; +} + +/** + * @author wujunyang, 16-07-22 11:07:50 + * + * @brief ��������������������� + * + * @param path <#path description#> + * + * @return <#return value description#> + */ ++ (BOOL)createFolder:(NSString *)path{ + BOOL isDir = NO; + NSFileManager *fileManager = [NSFileManager defaultManager]; + BOOL existed = [fileManager fileExistsAtPath:path isDirectory:&isDir]; + BOOL isCreated = NO; + if (!(isDir == YES && existed == YES)){ + isCreated = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; + }else{ + isCreated = YES; + } + return isCreated; +} + + ++ (BOOL)writeUploadDataWithName:(NSString *)fileName andAsset:(ALAsset *)asset{ + if (![self createFolder:[self uploadPath]]) { + return NO; + } + NSString *filePath = [[self uploadPath] stringByAppendingPathComponent:fileName]; + + [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]; + NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:filePath]; + if (!handle) { + return NO; + } + static const NSUInteger BufferSize = 1024*1024; + + ALAssetRepresentation *rep = [asset defaultRepresentation]; + uint8_t *buffer = calloc(BufferSize, sizeof(*buffer)); + NSUInteger offset = 0, bytesRead = 0; + + do { + @try { + bytesRead = [rep getBytes:buffer fromOffset:offset length:BufferSize error:nil]; + [handle writeData:[NSData dataWithBytesNoCopy:buffer length:bytesRead freeWhenDone:NO]]; + offset += bytesRead; + } @catch (NSException *exception) { + free(buffer); + + return NO; + } + } while (bytesRead > 0); + + free(buffer); + return YES; +} + ++ (BOOL)writeUploadDataWithName:(NSString *)fileName andImage:(UIImage *)image{ + if (![self createFolder:[self uploadPath]]) { + return NO; + } + NSString *filePath = [[self uploadPath] stringByAppendingPathComponent:fileName]; + + return [UIImageJPEGRepresentation(image, 1.0) writeToFile:filePath options:NSAtomicWrite error:nil]; +} + ++ (BOOL)deleteUploadDataWithName:(NSString *)fileName{ + NSString *filePath = [[self uploadPath] stringByAppendingPathComponent:fileName]; + NSFileManager *fm = [NSFileManager defaultManager]; + if ([fm fileExistsAtPath:filePath]) { + return [fm removeItemAtPath:filePath error:nil]; + }else{ + return YES; + } +} + +@end diff --git a/camerademo/camerademo/demo/MPUploadImageHelper.h b/camerademo/camerademo/demo/MPUploadImageHelper.h new file mode 100755 index 0000000..e752fb2 --- /dev/null +++ b/camerademo/camerademo/demo/MPUploadImageHelper.h @@ -0,0 +1,34 @@ +// +// MPUploadImageHelper.h +// MobileProject +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "MPImageItemModel.h" + +@interface MPUploadImageHelper : NSObject + +//������������������imagesArray ���������selectedAssetURLs������������KVO������������ +@property (readwrite, nonatomic, strong) NSMutableArray *imagesArray; +@property (readwrite, nonatomic, strong) NSMutableArray *selectedAssetURLs; + + +- (void)addASelectedAssetURL:(NSURL *)assetURL; +- (void)deleteASelectedAssetURL:(NSURL *)assetURL; +- (void)deleteAImage:(MPImageItemModel *)imageInfo; + +/** + * @author wujunyang, 16-07-25 13:07:17 + * + * @brief <#Description#> + * + * @param isUploadProcess ������������������������YES��������������������� + * + * @return <#return value description#> + */ ++(MPUploadImageHelper *)MPUploadImageForSend:(BOOL)isUploadProcess; + +@end diff --git a/camerademo/camerademo/demo/MPUploadImageHelper.m b/camerademo/camerademo/demo/MPUploadImageHelper.m new file mode 100755 index 0000000..8cd4d65 --- /dev/null +++ b/camerademo/camerademo/demo/MPUploadImageHelper.m @@ -0,0 +1,82 @@ +// +// MPUploadImageHelper.m +// MobileProject +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import "MPUploadImageHelper.h" + +@interface MPUploadImageHelper() +@property(nonatomic)BOOL isUploadProcess; +@end + +static MPUploadImageHelper *_mpUploadImageHelper = nil; + +@implementation MPUploadImageHelper + ++(MPUploadImageHelper *)MPUploadImageForSend:(BOOL)isUploadProcess +{ + _mpUploadImageHelper = [[MPUploadImageHelper alloc] init]; + _mpUploadImageHelper.isUploadProcess=isUploadProcess; + return _mpUploadImageHelper; +} + +- (void)setSelectedAssetURLs:(NSMutableArray *)selectedAssetURLs{ + NSMutableArray *needToAdd = [NSMutableArray new]; + NSMutableArray *needToDelete = [NSMutableArray new]; + [self.selectedAssetURLs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (![selectedAssetURLs containsObject:obj]) { + [needToDelete addObject:obj]; + } + }]; + [needToDelete enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [self deleteASelectedAssetURL:obj]; + }]; + [selectedAssetURLs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (![self.selectedAssetURLs containsObject:obj]) { + [needToAdd addObject:obj]; + } + }]; + [needToAdd enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [self addASelectedAssetURL:obj]; + }]; +} + + +- (void)addASelectedAssetURL:(NSURL *)assetURL{ + if (!_selectedAssetURLs) { + _selectedAssetURLs = [NSMutableArray new]; + } + if (!_imagesArray) { + _imagesArray = [NSMutableArray new]; + } + + [_selectedAssetURLs addObject:assetURL]; + + NSMutableArray *imagesArray = [self mutableArrayValueForKey:@"imagesArray"];//������kvo + MPImageItemModel *imageItem = [MPImageItemModel imageWithAssetURL:assetURL isUploadProcess:self.isUploadProcess]; + [imagesArray addObject:imageItem]; +} + +- (void)deleteASelectedAssetURL:(NSURL *)assetURL{ + [self.selectedAssetURLs removeObject:assetURL]; + NSMutableArray *imagesArray = [self mutableArrayValueForKey:@"imagesArray"];//������kvo + [imagesArray enumerateObjectsUsingBlock:^(MPImageItemModel *obj, NSUInteger idx, BOOL *stop) { + if (obj.assetURL == assetURL) { + [imagesArray removeObject:obj]; + *stop = YES; + } + }]; +} + +- (void)deleteAImage:(MPImageItemModel *)imageInfo{ + NSMutableArray *imagesArray = [self mutableArrayValueForKey:@"imagesArray"];//������kvo + [imagesArray removeObject:imageInfo]; + if (imageInfo.assetURL) { + [self.selectedAssetURLs removeObject:imageInfo.assetURL]; + } +} + +@end diff --git a/camerademo/camerademo/demo/MPUploadImagesViewController.h b/camerademo/camerademo/demo/MPUploadImagesViewController.h new file mode 100755 index 0000000..1ed9601 --- /dev/null +++ b/camerademo/camerademo/demo/MPUploadImagesViewController.h @@ -0,0 +1,14 @@ +// +// MPUploadImagesViewController.h +// MobileProject ������������ +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import <UIKit/UIKit.h> + + +@interface MPUploadImagesViewController : UIViewController + +@end diff --git a/camerademo/camerademo/demo/MPUploadImagesViewController.m b/camerademo/camerademo/demo/MPUploadImagesViewController.m new file mode 100755 index 0000000..99c2a66 --- /dev/null +++ b/camerademo/camerademo/demo/MPUploadImagesViewController.m @@ -0,0 +1,231 @@ +// +// MPUploadImagesViewController.m +// MobileProject +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import "MPUploadImagesViewController.h" + +@interface MPUploadImagesViewController()<UITableViewDataSource, UITableViewDelegate,UIActionSheetDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, QBImagePickerControllerDelegate> +@property (nonatomic,strong) UITableView *myTableView; +@property (strong, nonatomic) MPUploadImageHelper *curUploadImageHelper; +@end + + +@implementation MPUploadImagesViewController + + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor=[UIColor whiteColor]; + self.navigationItem.title=@"������������"; + + //��������� + _curUploadImageHelper=[MPUploadImageHelper MPUploadImageForSend:NO]; + + //��������������� + if (!_myTableView) { + _myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0,0, Main_Screen_Width, Main_Screen_Height) style:UITableViewStylePlain]; + _myTableView.tableFooterView=[UIView new]; + _myTableView.showsVerticalScrollIndicator = NO; + _myTableView.showsHorizontalScrollIndicator = NO; + _myTableView.dataSource = self; + _myTableView.delegate = self; + [_myTableView registerClass:[MPImageUploadCell class] forCellReuseIdentifier:NSStringFromClass([MPImageUploadCell class])]; + [self.view addSubview:_myTableView]; + [_myTableView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(UIEdgeInsetsMake(0, 0, 0, 0)); + }]; + } + + //������������ + UIButton*rightButton = [[UIButton alloc]initWithFrame:CGRectMake(0,0,70,30)]; + [rightButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; + [rightButton setTitle:@"������" forState:UIControlStateNormal]; + [rightButton addTarget:self action:@selector(myAction)forControlEvents:UIControlEventTouchUpInside]; + UIBarButtonItem*rightItem = [[UIBarButtonItem alloc]initWithCustomView:rightButton]; + self.navigationItem.rightBarButtonItem= rightItem; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; +} + + +- (void)dealloc +{ + _myTableView.delegate = nil; + _myTableView.dataSource = nil; +} + +#pragma mark UITableViewDataSource, UITableViewDelegate������������ + +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ + return 1; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + MPImageUploadCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MPImageUploadCell class]) forIndexPath:indexPath]; + __weak typeof(self)weakSelf = self; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.curUploadImageHelper=self.curUploadImageHelper; + cell.addPicturesBlock = ^(){ + [weakSelf showActionForPhoto]; + }; + cell.deleteImageBlock = ^(MPImageItemModel *toDelete) + { + [weakSelf.curUploadImageHelper deleteAImage:toDelete]; + [weakSelf.myTableView reloadData]; + }; + return cell; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ + return [MPImageUploadCell cellHeightWithObj:self.curUploadImageHelper]; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ + [tableView deselectRowAtIndexPath:indexPath animated:YES]; +} + + +#pragma mark UIActionSheetDelegate + +- (void)actionSheet:(UIActionSheet *)modalView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (buttonIndex == 0) + { + //������ + if (![cameraHelper checkCameraAuthorizationStatus]) { + return; + } + UIImagePickerController *picker = [[UIImagePickerController alloc] init]; + picker.delegate = self; + picker.allowsEditing = NO;//��������������� + picker.sourceType = UIImagePickerControllerSourceTypeCamera; + [self presentViewController:picker animated:YES completion:nil];//������������������ + }else if (buttonIndex == 1) + { + //������ + if (![cameraHelper checkPhotoLibraryAuthorizationStatus]) { + return; + } + QBImagePickerController *imagePickerController = [[QBImagePickerController alloc] init]; + [imagePickerController.selectedAssetURLs removeAllObjects]; + [imagePickerController.selectedAssetURLs addObjectsFromArray:self.curUploadImageHelper.selectedAssetURLs]; + imagePickerController.filterType = QBImagePickerControllerFilterTypePhotos; + imagePickerController.delegate = self; + imagePickerController.maximumNumberOfSelection = kupdateMaximumNumberOfImage; + imagePickerController.allowsMultipleSelection = YES; + UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:imagePickerController]; + [self presentViewController:navigationController animated:YES completion:NULL]; + } +} + + +#pragma mark UIImagePickerControllerDelegate + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info +{ + UIImage *pickerImage = [info objectForKey:UIImagePickerControllerOriginalImage]; + ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init]; + [assetsLibrary writeImageToSavedPhotosAlbum:[pickerImage CGImage] orientation:(ALAssetOrientation)pickerImage.imageOrientation completionBlock:^(NSURL *assetURL, NSError *error) { + [self.curUploadImageHelper addASelectedAssetURL:assetURL]; + //������������ ������������������������ + [self partialTableViewRefresh]; + }]; + [picker dismissViewControllerAnimated:YES completion:^{}]; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker +{ + [picker dismissViewControllerAnimated:YES completion:nil]; +} + + +#pragma mark UINavigationControllerDelegate, QBImagePickerControllerDelegate + +- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAssets:(NSArray *)assets{ + NSMutableArray *selectedAssetURLs = [NSMutableArray new]; + [imagePickerController.selectedAssetURLs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [selectedAssetURLs addObject:obj]; + }]; + MPWeakSelf(self) + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + self.curUploadImageHelper.selectedAssetURLs = selectedAssetURLs; + dispatch_async(dispatch_get_main_queue(), ^{ + MPStrongSelf(self) + //������������ ������������������������ + [self partialTableViewRefresh]; + }); + }); + [self dismissViewControllerAnimated:YES completion:nil]; +} +- (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +#pragma mark ��������������� + +//��������������� +-(void)showActionForPhoto +{ + UIActionSheet *actionSheet = [[UIActionSheet alloc] + initWithTitle:nil + delegate:self + cancelButtonTitle:@"������" + destructiveButtonTitle:nil + otherButtonTitles:@"������",@"���������������",nil]; + actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque; + [actionSheet showInView:self.view]; +} + +//��������������������������������� ������������������������ +-(void)partialTableViewRefresh +{ + [self.myTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; +} + +//������������ +-(void)myAction +{ + if (self.curUploadImageHelper.selectedAssetURLs.count==0) { + [MBProgressHUD showAutoMessage:@"���������������������������" ToView:nil]; + return; + } + + MPUploadImageService *req=[[MPUploadImageService alloc]initWithUploadImages:self.curUploadImageHelper]; + + [req startWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest *request) { + //������������������������������ + + } failure:^(__kindof YTKBaseRequest *request) { + [MPRequstFailedHelper requstFailed:request]; + }]; + + //������������ + MPWeakSelf(self) + req.uploadPropressBlock = ^(NSUInteger __unused bytesWritten, + long long totalBytesWritten, + long long totalBytesExpectedToWrite) + { + + MPStrongSelf(self); + CGFloat propress = totalBytesWritten*1.0/totalBytesExpectedToWrite; + NSLog(@"���������������%lld/%lld___%2f",totalBytesWritten,totalBytesExpectedToWrite,propress); + dispatch_async(dispatch_get_main_queue(), ^{ + //������UI + }); + + + }; +} +@end diff --git a/camerademo/camerademo/demo/Model/MPImageItemModel.h b/camerademo/camerademo/demo/Model/MPImageItemModel.h new file mode 100755 index 0000000..a23da37 --- /dev/null +++ b/camerademo/camerademo/demo/Model/MPImageItemModel.h @@ -0,0 +1,46 @@ +// +// MPImageItemModel.h +// MobileProject ������������������������ +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "MPFileManager.h" +#import "imageCompressHelper.h" +#import "dateTimeHelper.h" +#import "UIImage+Resize.h" +#import "UIImage+FX.h" + +typedef NS_ENUM(NSInteger, MPImageUploadState) +{ + MPImageUploadStateInit = 0, + MPImageUploadStateIng, + MPImageUploadStateSuccess, + MPImageUploadStateFail +}; + + +@interface MPImageItemModel : NSObject + +//������ ��������� +@property (readwrite, nonatomic, strong) UIImage *image, *thumbnailImage; +//������������asstURL +@property (strong, nonatomic) NSURL *assetURL; +//������������ +@property (assign, nonatomic) MPImageUploadState uploadState; +//���������������������[���������������������������������������������������������������������������������������������������,������������] +@property(nonatomic,copy)NSString *httpUrl; +@property(nonatomic,copy)NSString *upServicePath; +//������������������ ������������ ��������� ������������ +@property (readwrite, nonatomic, strong) NSString *photoName; +@property (readwrite, nonatomic, strong) NSString *photoLatitude; +@property (readwrite, nonatomic, strong) NSString *photoLongitude; +@property (readwrite, nonatomic, strong) NSString *photoTime; + +//������������ ++ (instancetype)imageWithAssetURL:(NSURL *)assetURL isUploadProcess:(BOOL)isUploadProcess; ++ (instancetype)imageWithAssetURL:(NSURL *)assetURL andImage:(UIImage *)image; + +@end diff --git a/camerademo/camerademo/demo/Model/MPImageItemModel.m b/camerademo/camerademo/demo/Model/MPImageItemModel.m new file mode 100755 index 0000000..2d0bc80 --- /dev/null +++ b/camerademo/camerademo/demo/Model/MPImageItemModel.m @@ -0,0 +1,100 @@ +// +// MPImageItemModel.m +// MobileProject +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import "MPImageItemModel.h" +#import <CoreLocation/CoreLocation.h> + +@implementation MPImageItemModel + ++ (instancetype)imageWithAssetURL:(NSURL *)assetURL isUploadProcess:(BOOL)isUploadProcess{ + MPImageItemModel *imageItem = [[MPImageItemModel alloc] init]; + imageItem.uploadState = MPImageUploadStateInit; + imageItem.assetURL = assetURL; + + MPWeakSelf(self); + + void (^selectAsset)(ALAsset *) = ^(ALAsset *asset){ + if (asset) { + UIImage *highQualityImage = [imageCompressHelper fullScreenImageALAsset:asset]; + UIImage *thumbnailImage = [UIImage imageWithCGImage:[asset thumbnail]]; + + //������������ + MPStrongSelf(self); + [self imageInfoWithALAsset:asset imageItem:imageItem]; + + dispatch_async(dispatch_get_main_queue(), ^{ + imageItem.image = [imageCompressHelper compressedImageToLimitSizeOfKB:100 image:highQualityImage];; + imageItem.thumbnailImage = thumbnailImage; + + if (isUploadProcess) { + //��������������� ��������������������������������� + [MPFileManager writeUploadDataWithName:imageItem.photoName andImage:imageItem.image]; + } + }); + } + }; + + ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init]; + MPWeakSelf(assetsLibrary); + [assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) { + if (asset) { + selectAsset(asset); + }else{ + MPStrongSelf(assetsLibrary); + [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupPhotoStream usingBlock:^(ALAssetsGroup *group, BOOL *stop) { + [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopG) { + if([result.defaultRepresentation.url isEqual:assetURL]) { + selectAsset(result); + *stop = YES; + *stopG = YES; + } + }]; + } failureBlock:^(NSError *error) { + NSLog(@"������������������"); + }]; + } + }failureBlock:^(NSError *error) { + NSLog(@"������������������"); + }]; + return imageItem; + +} + +//������������������������ ++(void)imageInfoWithALAsset:(ALAsset *)asset imageItem:(MPImageItemModel *)imageItem +{ + //������������ + NSDate * nsALAssetPropertyDate = [ asset valueForProperty:ALAssetPropertyDate ]; + if (nsALAssetPropertyDate!=nil) { + imageItem.photoTime=[dateTimeHelper htcTimeToLocationStr:nsALAssetPropertyDate]; + } + + //GPS������ + CLLocation *location = [asset valueForProperty:ALAssetPropertyLocation]; + if (location) { + CLLocationCoordinate2D curCoordinate=location.coordinate; + imageItem.photoLatitude=[NSString stringWithFormat:@"%f",curCoordinate.latitude]; + imageItem.photoLongitude=[NSString stringWithFormat:@"%f",curCoordinate.longitude]; + } + + //������������ + ALAssetRepresentation *representation = [asset defaultRepresentation]; + imageItem.photoName = [representation filename]; +} + + ++ (instancetype)imageWithAssetURL:(NSURL *)assetURL andImage:(UIImage *)image{ + MPImageItemModel *imageItem = [[MPImageItemModel alloc] init]; + imageItem.uploadState = MPImageUploadStateInit; + imageItem.assetURL = assetURL; + imageItem.image = image; + imageItem.thumbnailImage = [image imageScaledToSize:CGSizeMake(AdaptedWidth(70), AdaptedWidth(70))]; + return imageItem; +} + +@end diff --git a/camerademo/camerademo/demo/OtherHelper/UITapImageView.h b/camerademo/camerademo/demo/OtherHelper/UITapImageView.h new file mode 100755 index 0000000..3d3233b --- /dev/null +++ b/camerademo/camerademo/demo/OtherHelper/UITapImageView.h @@ -0,0 +1,17 @@ +// +// UITapImageView.h +// zxptUser +// +// Created by wujunyang on 16/6/8. +// Copyright �� 2016��� qijia. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface UITapImageView : UIImageView + +- (void)addTapBlock:(void(^)(id obj))tapAction; + +-(void)setImageWithUrl:(NSURL *)imgUrl placeholderImage:(UIImage *)placeholderImage tapBlock:(void(^)(id obj))tapAction; + +@end diff --git a/camerademo/camerademo/demo/OtherHelper/UITapImageView.m b/camerademo/camerademo/demo/OtherHelper/UITapImageView.m new file mode 100755 index 0000000..4193a43 --- /dev/null +++ b/camerademo/camerademo/demo/OtherHelper/UITapImageView.m @@ -0,0 +1,53 @@ +// +// UITapImageView.m +// zxptUser +// +// Created by wujunyang on 16/6/8. +// Copyright �� 2016��� qijia. All rights reserved. +// + +#import "UITapImageView.h" + +@interface UITapImageView () + +@property (nonatomic, copy) void(^tapAction)(id); + +@end + +@implementation UITapImageView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +- (instancetype)init +{ + return [self initWithFrame:CGRectZero]; +} + +- (void)tap{ + if (self.tapAction) { + self.tapAction(self); + } +} +- (void)addTapBlock:(void(^)(id obj))tapAction{ + self.tapAction = tapAction; + if (![self gestureRecognizers]) { + self.userInteractionEnabled = YES; + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)]; + [self addGestureRecognizer:tap]; + } +} + +-(void)setImageWithUrl:(NSURL *)imgUrl placeholderImage:(UIImage *)placeholderImage tapBlock:(void(^)(id obj))tapAction{ + [self sd_setImageWithURL:imgUrl placeholderImage:placeholderImage]; + [self addTapBlock:tapAction]; +} + + +@end diff --git a/camerademo/camerademo/demo/OtherHelper/cameraHelper.h b/camerademo/camerademo/demo/OtherHelper/cameraHelper.h new file mode 100755 index 0000000..609027f --- /dev/null +++ b/camerademo/camerademo/demo/OtherHelper/cameraHelper.h @@ -0,0 +1,23 @@ +// +// cameraHelper.h +// MobileProject +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@interface cameraHelper : NSObject + +/** + * ������������"������"������������, ���������������������, ������������������������������������. + */ ++ (BOOL)checkPhotoLibraryAuthorizationStatus; + +/** + * ������������"������"������������, ���������������������, ������������������������������������. + */ ++ (BOOL)checkCameraAuthorizationStatus; + +@end diff --git a/camerademo/camerademo/demo/OtherHelper/cameraHelper.m b/camerademo/camerademo/demo/OtherHelper/cameraHelper.m new file mode 100755 index 0000000..73a9a94 --- /dev/null +++ b/camerademo/camerademo/demo/OtherHelper/cameraHelper.m @@ -0,0 +1,50 @@ +// +// cameraHelper.m +// MobileProject +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import "cameraHelper.h" +#import <AssetsLibrary/ALAsset.h> +#import <AssetsLibrary/ALAssetsLibrary.h> +#import <AssetsLibrary/ALAssetsGroup.h> +#import <AssetsLibrary/ALAssetRepresentation.h> + +@import AVFoundation; + +@implementation cameraHelper + ++ (BOOL)checkPhotoLibraryAuthorizationStatus +{ + //if ([ALAssetsLibrary respondsToSelector:@selector(authorizationStatus)]) { + ALAuthorizationStatus authStatus = [ALAssetsLibrary authorizationStatus]; + if (ALAuthorizationStatusDenied == authStatus || + ALAuthorizationStatusRestricted == authStatus) { + [MBProgressHUD showAutoMessage:@"������iPhone������������->������->������������������������������������������" ToView:nil]; + return NO; + // } + } + return YES; +} + ++ (BOOL)checkCameraAuthorizationStatus +{ + if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { + [MBProgressHUD showAutoMessage:@"������������������������" ToView:nil]; + return NO; + } + + if ([AVCaptureDevice respondsToSelector:@selector(authorizationStatusForMediaType:)]) { + AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + if (AVAuthorizationStatusDenied == authStatus || + AVAuthorizationStatusRestricted == authStatus) { + [MBProgressHUD showAutoMessage:@"������iPhone������������->������->������������������������������������������" ToView:nil]; + return NO; + } + } + return YES; +} + +@end diff --git a/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.h b/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.h new file mode 100755 index 0000000..7e25da9 --- /dev/null +++ b/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.h @@ -0,0 +1,16 @@ +// +// dateTimeHelper.h +// MobileProject +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import <Foundation/Foundation.h> + +@interface dateTimeHelper : NSObject + +//������������������������������ ++ (NSString *)htcTimeToLocationStr:(NSDate*)curDate; + +@end diff --git a/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.m b/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.m new file mode 100755 index 0000000..0cb4e18 --- /dev/null +++ b/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.m @@ -0,0 +1,24 @@ +// +// dateTimeHelper.m +// MobileProject +// +// Created by wujunyang on 16/7/20. +// Copyright �� 2016��� wujunyang. All rights reserved. +// + +#import "dateTimeHelper.h" + +@implementation dateTimeHelper + ++ (NSString *)htcTimeToLocationStr:(NSDate*)curDate +{ + if (curDate==nil) { + return @""; + } + NSDateFormatter* dateFormatter = [[NSDateFormatter alloc]init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + NSString *fixString = [dateFormatter stringFromDate:curDate]; + return fixString; +} + +@end diff --git a/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.h b/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.h new file mode 100755 index 0000000..e94a550 --- /dev/null +++ b/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.h @@ -0,0 +1,42 @@ +// +// imageCompressHelper.h +// zxptUser ������������ +// +// Created by wujunyang on 16/4/14. +// Copyright �� 2016��� qijia. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import <AssetsLibrary/ALAsset.h> +#import <AssetsLibrary/ALAssetsLibrary.h> +#import <AssetsLibrary/ALAssetsGroup.h> +#import <AssetsLibrary/ALAssetRepresentation.h> + +@interface imageCompressHelper : NSObject + +/** + * @author wujunyang, 16-04-14 15:04:54 + * + * @brief ������������������KB��������������� + * + * @param kb <#kb description#> + * @param image <#image description#> + * + * @return <#return value description#> + */ ++(UIImage*)compressedImageToLimitSizeOfKB:(CGFloat)kb image:(UIImage*)image; + ++(NSData*)returnDataCompressedImageToLimitSizeOfKB:(CGFloat)kb image:(UIImage*)image; + +//��������������������� ��������������������� ++(UIImage*) circleImage:(UIImage*) image withParam:(CGFloat) inset; + +//��������������������������� ++(UIImage *) imageCompressForWidth:(UIImage *)sourceImage targetWidth:(CGFloat)defineWidth; + +//���������������,size ������������������������ ������������ CGSizeMake(300, 140) ++(UIImage *)compressImage:(UIImage *)sourceImage toTargetWidth:(CGFloat)targetWidth; + +//������������������ ++ (UIImage *)fullScreenImageALAsset:(ALAsset *)asset; +@end diff --git a/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.m b/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.m new file mode 100755 index 0000000..2852c6a --- /dev/null +++ b/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.m @@ -0,0 +1,163 @@ +// +// imageCompressHelper.m +// zxptUser +// +// Created by wujunyang on 16/4/14. +// Copyright �� 2016��� qijia. All rights reserved. +// + +#import "imageCompressHelper.h" + +@implementation imageCompressHelper + ++(UIImage*)compressedImageToLimitSizeOfKB:(CGFloat)kb image:(UIImage*)image +{ + //������������kb��������������������� + long imagePixel = CGImageGetWidth(image.CGImage)*CGImageGetHeight(image.CGImage); + long imageKB = imagePixel * CGImageGetBitsPerPixel(image.CGImage) / (8 * 1024); + if (imageKB > kb){ + float compressedParam = kb / imageKB; + return [UIImage imageWithData:UIImageJPEGRepresentation(image, compressedParam)]; + } + //������������ + else{ + return image; + } +} + ++(NSData*)returnDataCompressedImageToLimitSizeOfKB:(CGFloat)kb image:(UIImage*)image +{ + //������������kb��������������������� + long imagePixel = CGImageGetWidth(image.CGImage)*CGImageGetHeight(image.CGImage); + long imageKB = imagePixel * CGImageGetBitsPerPixel(image.CGImage) / (8 * 1024); + if (imageKB > kb){ + float compressedParam = kb / imageKB; + return UIImageJPEGRepresentation(image, compressedParam); + } + //������������ + else{ + return UIImageJPEGRepresentation(image, 1); + } +} + + ++(UIImage*) circleImage:(UIImage*) image withParam:(CGFloat) inset +{ + //UIGraphicsBeginImageContext(image.size); + //������������ ��������������� + UIGraphicsBeginImageContextWithOptions(image.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef context =UIGraphicsGetCurrentContext(); + + //���������������������2������������������ + + CGContextSetLineWidth(context,2); + + CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor); + + CGRect rect = CGRectMake(inset, inset, image.size.width - inset *2.0f, image.size.height - inset *2.0f); + + CGContextAddEllipseInRect(context, rect); + + CGContextClip(context); + + //���������������������image������ + + [image drawInRect:rect]; + + CGContextAddEllipseInRect(context, rect); + + CGContextStrokePath(context); + + //������������image + + UIImage *newimg = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + + return newimg; +} + ++(UIImage *) imageCompressForWidth:(UIImage *)sourceImage targetWidth:(CGFloat)defineWidth +{ + UIImage *newImage = nil; + CGSize imageSize = sourceImage.size; + CGFloat width = imageSize.width; + CGFloat height = imageSize.height; + CGFloat targetWidth = defineWidth; + CGFloat targetHeight = height / (width / targetWidth); + CGSize size = CGSizeMake(targetWidth, targetHeight); + CGFloat scaleFactor = 0.0; + CGFloat scaledWidth = targetWidth; + CGFloat scaledHeight = targetHeight; + CGPoint thumbnailPoint = CGPointMake(0.0, 0.0); + + if(CGSizeEqualToSize(imageSize, size) == NO){ + + CGFloat widthFactor = targetWidth / width; + CGFloat heightFactor = targetHeight / height; + + if(widthFactor > heightFactor){ + scaleFactor = widthFactor; + } + else{ + scaleFactor = heightFactor; + } + scaledWidth = width * scaleFactor; + scaledHeight = height * scaleFactor; + + if(widthFactor > heightFactor){ + + thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; + + }else if(widthFactor < heightFactor){ + + thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; + } + } + + UIGraphicsBeginImageContext(size); + + CGRect thumbnailRect = CGRectZero; + thumbnailRect.origin = thumbnailPoint; + thumbnailRect.size.width = scaledWidth; + thumbnailRect.size.height = scaledHeight; + + [sourceImage drawInRect:thumbnailRect]; + + newImage = UIGraphicsGetImageFromCurrentImageContext(); + + if(newImage == nil){ + + NSLog(@"scale image fail"); + } + UIGraphicsEndImageContext(); + return newImage; +} + + ++(UIImage *)compressImage:(UIImage *)sourceImage toTargetWidth:(CGFloat)targetWidth +{ + CGSize imageSize = sourceImage.size; + + CGFloat width = imageSize.width; + CGFloat height = imageSize.height; + + CGFloat targetHeight = (targetWidth / width) * height; + + UIGraphicsBeginImageContext(CGSizeMake(targetWidth, targetHeight)); + [sourceImage drawInRect:CGRectMake(0, 0, targetWidth, targetHeight)]; + + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return newImage; +} + + ++ (UIImage *)fullScreenImageALAsset:(ALAsset *)asset{ + ALAssetRepresentation *assetRep = [asset defaultRepresentation]; + CGImageRef imgRef = [assetRep fullScreenImage];//fullScreenImage������������������������ + UIImage *img = [UIImage imageWithCGImage:imgRef]; + return img; +} +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.h new file mode 100755 index 0000000..161379c --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.h @@ -0,0 +1,13 @@ +// +// QBAssetsCollectionCheckmarkView.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2014/01/01. +// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface QBAssetsCollectionCheckmarkView : UIView + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.m new file mode 100755 index 0000000..82ee42d --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.m @@ -0,0 +1,53 @@ +// +// QBAssetsCollectionCheckmarkView.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2014/01/01. +// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved. +// + +#import "QBAssetsCollectionCheckmarkView.h" + +@implementation QBAssetsCollectionCheckmarkView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + + if (self) { + // View settings + self.backgroundColor = [UIColor clearColor]; + } + + return self; +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + return CGSizeMake(24.0, 24.0); +} + +- (void)drawRect:(CGRect)rect +{ + CGContextRef context = UIGraphicsGetCurrentContext(); + + // Border + CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); + CGContextFillEllipseInRect(context, self.bounds); + + // Body + CGContextSetRGBFillColor(context, 20.0/255.0, 111.0/255.0, 223.0/255.0, 1.0); + CGContextFillEllipseInRect(context, CGRectInset(self.bounds, 1.0, 1.0)); + + // Checkmark + CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0); + CGContextSetLineWidth(context, 1.2); + + CGContextMoveToPoint(context, 6.0, 12.0); + CGContextAddLineToPoint(context, 10.0, 16.0); + CGContextAddLineToPoint(context, 18.0, 8.0); + + CGContextStrokePath(context); +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.h new file mode 100755 index 0000000..630307c --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.h @@ -0,0 +1,15 @@ +// +// QBAssetsCollectionFooterView.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface QBAssetsCollectionFooterView : UICollectionReusableView + +@property (nonatomic, strong, readonly) UILabel *textLabel; + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.m new file mode 100755 index 0000000..3d23af8 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.m @@ -0,0 +1,48 @@ +// +// QBAssetsCollectionFooterView.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import "QBAssetsCollectionFooterView.h" + +@interface QBAssetsCollectionFooterView () + +@property (nonatomic, strong, readwrite) UILabel *textLabel; + +@end + +@implementation QBAssetsCollectionFooterView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + + if (self) { + // Create a label + UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + textLabel.font = [UIFont systemFontOfSize:17]; + textLabel.textColor = [UIColor blackColor]; + textLabel.textAlignment = NSTextAlignmentCenter; + + [self addSubview:textLabel]; + self.textLabel = textLabel; + } + + return self; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + // Layout text label + self.textLabel.frame = CGRectMake(0, + (self.bounds.size.height - 21.0) / 2.0, + self.bounds.size.width, + 21.0); +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.h new file mode 100755 index 0000000..b4b5b39 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.h @@ -0,0 +1,13 @@ +// +// QBAssetsCollectionOverlayView.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2014/01/01. +// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface QBAssetsCollectionOverlayView : UIView + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.m new file mode 100755 index 0000000..caa7ae6 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.m @@ -0,0 +1,47 @@ +// +// QBAssetsCollectionOverlayView.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2014/01/01. +// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved. +// + +#import "QBAssetsCollectionOverlayView.h" +#import <QuartzCore/QuartzCore.h> + +// Views +#import "QBAssetsCollectionCheckmarkView.h" + +@interface QBAssetsCollectionOverlayView () + +@property (nonatomic, strong) QBAssetsCollectionCheckmarkView *checkmarkView; + +@end + +@implementation QBAssetsCollectionOverlayView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + + if (self) { + // View settings + self.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.4]; + + // Create a checkmark view + QBAssetsCollectionCheckmarkView *checkmarkView = [[QBAssetsCollectionCheckmarkView alloc] initWithFrame:CGRectMake(self.bounds.size.width - (4.0 + 24.0), self.bounds.size.height - (4.0 + 24.0), 24.0, 24.0)]; + checkmarkView.autoresizingMask = UIViewAutoresizingNone; + + checkmarkView.layer.shadowColor = [[UIColor grayColor] CGColor]; + checkmarkView.layer.shadowOffset = CGSizeMake(0, 0); + checkmarkView.layer.shadowOpacity = 0.6; + checkmarkView.layer.shadowRadius = 2.0; + + [self addSubview:checkmarkView]; + self.checkmarkView = checkmarkView; + } + + return self; +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.h new file mode 100755 index 0000000..58a78dc --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.h @@ -0,0 +1,15 @@ +// +// QBAssetsCollectionVideoIndicatorView.h +// QBImagePickerControllerDemo +// +// Created by Katsuma Tanaka on 2014/08/07. +// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface QBAssetsCollectionVideoIndicatorView : UIView + +@property (nonatomic, assign) NSTimeInterval duration; + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.m new file mode 100755 index 0000000..4aba36c --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.m @@ -0,0 +1,107 @@ +// +// QBAssetsCollectionVideoIndicatorView.m +// QBImagePickerControllerDemo +// +// Created by Katsuma Tanaka on 2014/08/07. +// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved. +// + +#import "QBAssetsCollectionVideoIndicatorView.h" +#import <QuartzCore/QuartzCore.h> + +@implementation QBAssetsCollectionVideoIndicatorView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + + if (self) { + self.backgroundColor = [UIColor clearColor]; + self.clipsToBounds = YES; + } + + return self; +} + + +#pragma mark - Accessors + +- (void)setDuration:(NSTimeInterval)duration +{ + _duration = duration; + + [self setNeedsDisplay]; +} + + +#pragma mark - Drawing the View + +- (void)drawRect:(CGRect)rect +{ + // Draw linear gradient + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGFloat colors[12] = { + 0.0, 0.0, 0.0, 0.9, + 0.0, 0.0, 0.0, 0.45, + 0.0, 0.0, 0.0, 0.0 + }; + const CGFloat locations[] = { 0.0, 0.55, 1.0 }; + CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, 3); + CGColorSpaceRelease(colorSpace); + + CGPoint startPoint = CGPointMake(0, CGRectGetHeight(self.bounds)); + CGPoint endPoint = CGPointMake(0, 0); + CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation); + + CGGradientRelease(gradient); + + // Draw camera icon + CGSize cameraIconSize = CGSizeMake(14.0, 8.0); + CGRect cameraIconRect = CGRectMake(5.0, (CGRectGetHeight(self.bounds) - cameraIconSize.height) / 2.0, cameraIconSize.width, cameraIconSize.height); + [self drawCameraIconInRect:cameraIconRect]; + + // Draw duration + NSInteger minutes = (NSInteger)(self.duration / 60.0); + NSInteger seconds = (NSInteger)ceil(self.duration - 60.0 * (double)minutes); + NSString *durationString = [NSString stringWithFormat:@"%02ld:%02ld", (long)minutes, (long)seconds]; + + NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + paragraphStyle.alignment = NSTextAlignmentRight; + + UIFont *durationFont = [UIFont systemFontOfSize:12.0]; + + CGRect durationRect = CGRectMake(CGRectGetMaxX(cameraIconRect), 0, CGRectGetWidth(self.bounds) - CGRectGetMaxX(cameraIconRect), CGRectGetHeight(self.bounds)); + durationRect = CGRectInset(durationRect, 5.0, (CGRectGetHeight(self.bounds) - durationFont.lineHeight) / 2.0); + + [durationString drawInRect:durationRect + withAttributes:@{ + NSParagraphStyleAttributeName: [paragraphStyle copy], + NSFontAttributeName: durationFont, + NSForegroundColorAttributeName: [UIColor whiteColor] + }]; +} + +- (void)drawCameraIconInRect:(CGRect)rect +{ + [[UIColor whiteColor] setFill]; + + // Draw triangle + CGRect triangleRect = CGRectMake(0, CGRectGetMinY(rect), ceil(CGRectGetHeight(rect) / 2.0), CGRectGetHeight(rect)); + triangleRect.origin.x = CGRectGetMinX(rect) + CGRectGetWidth(rect) - CGRectGetWidth(triangleRect); + + UIBezierPath *trianglePath = [UIBezierPath bezierPath]; + [trianglePath moveToPoint:CGPointMake(CGRectGetMinX(triangleRect) + CGRectGetWidth(triangleRect), CGRectGetMinY(triangleRect))]; + [trianglePath addLineToPoint:CGPointMake(CGRectGetMinX(triangleRect) + CGRectGetWidth(triangleRect), CGRectGetMaxY(triangleRect))]; + [trianglePath addLineToPoint:CGPointMake(CGRectGetMinX(triangleRect), CGRectGetMidY(triangleRect))]; + [trianglePath closePath]; + [trianglePath fill]; + + // Draw rounded square + CGRect squareRect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect) - CGRectGetWidth(triangleRect) - 1.0, CGRectGetHeight(rect)); + UIBezierPath *squarePath = [UIBezierPath bezierPathWithRoundedRect:squareRect cornerRadius:2.0]; + [squarePath fill]; +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.h new file mode 100755 index 0000000..caba987 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.h @@ -0,0 +1,17 @@ +// +// QBAssetsCollectionViewCell.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import <AssetsLibrary/AssetsLibrary.h> + +@interface QBAssetsCollectionViewCell : UICollectionViewCell + +@property (nonatomic, strong) ALAsset *asset; +@property (nonatomic, assign) BOOL showsOverlayViewWhenSelected; + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.m new file mode 100755 index 0000000..502dc93 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.m @@ -0,0 +1,143 @@ +// +// QBAssetsCollectionViewCell.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import "QBAssetsCollectionViewCell.h" + +// Views +#import "QBAssetsCollectionOverlayView.h" +#import "QBAssetsCollectionVideoIndicatorView.h" + +@interface QBAssetsCollectionViewCell () + +@property (nonatomic, strong) UIImageView *imageView; +@property (nonatomic, strong) QBAssetsCollectionOverlayView *overlayView; +@property (nonatomic, strong) QBAssetsCollectionVideoIndicatorView *videoIndicatorView; + +@property (nonatomic, strong) UIImage *blankImage; + +@end + +@implementation QBAssetsCollectionViewCell + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + + if (self) { + self.showsOverlayViewWhenSelected = YES; + + // Create a image view + UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.contentView.bounds]; + imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + [self.contentView addSubview:imageView]; + self.imageView = imageView; + } + + return self; +} + +- (void)setSelected:(BOOL)selected +{ + [super setSelected:selected]; + + // Show/hide overlay view + if (selected && self.showsOverlayViewWhenSelected) { + [self showOverlayView]; + } else { + [self hideOverlayView]; + } +} + + +#pragma mark - Overlay View + +- (void)showOverlayView +{ + [self hideOverlayView]; + + QBAssetsCollectionOverlayView *overlayView = [[QBAssetsCollectionOverlayView alloc] initWithFrame:self.contentView.bounds]; + overlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + [self.contentView addSubview:overlayView]; + self.overlayView = overlayView; +} + +- (void)hideOverlayView +{ + if (self.overlayView) { + [self.overlayView removeFromSuperview]; + self.overlayView = nil; + } +} + + +#pragma mark - Video Indicator View + +- (void)showVideoIndicatorView +{ + CGFloat height = 19.0; + CGRect frame = CGRectMake(0, CGRectGetHeight(self.bounds) - height, CGRectGetWidth(self.bounds), height); + QBAssetsCollectionVideoIndicatorView *videoIndicatorView = [[QBAssetsCollectionVideoIndicatorView alloc] initWithFrame:frame]; + videoIndicatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + videoIndicatorView.duration = [[self.asset valueForProperty:ALAssetPropertyDuration] doubleValue]; + + [self.contentView addSubview:videoIndicatorView]; + self.videoIndicatorView = videoIndicatorView; +} + +- (void)hideVideoIndicatorView +{ + if (self.videoIndicatorView) { + [self.videoIndicatorView removeFromSuperview]; + self.videoIndicatorView = nil; + } +} + + +#pragma mark - Accessors + +- (void)setAsset:(ALAsset *)asset +{ + _asset = asset; + + // Update view + CGImageRef thumbnailImageRef = [asset thumbnail]; + + if (thumbnailImageRef) { + self.imageView.image = [UIImage imageWithCGImage:thumbnailImageRef]; + } else { + self.imageView.image = [self blankImage]; + } + + // Show video indicator if the asset is video + if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) { + [self showVideoIndicatorView]; + } else { + [self hideVideoIndicatorView]; + } +} + +- (UIImage *)blankImage +{ + if (_blankImage == nil) { + CGSize size = CGSizeMake(100.0, 100.0); + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); + + [[UIColor colorWithWhite:(240.0 / 255.0) alpha:1.0] setFill]; + UIRectFill(CGRectMake(0, 0, size.width, size.height)); + + _blankImage = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + } + + return _blankImage; +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.h new file mode 100755 index 0000000..036e7f6 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.h @@ -0,0 +1,39 @@ +// +// QBAssetsCollectionViewController.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import <AssetsLibrary/AssetsLibrary.h> + +// ViewControllers +#import "QBImagePickerController.h" + +@class QBAssetsCollectionViewController; + +@protocol QBAssetsCollectionViewControllerDelegate <NSObject> + +@optional +- (void)assetsCollectionViewController:(QBAssetsCollectionViewController *)assetsCollectionViewController didSelectAsset:(ALAsset *)asset; +- (void)assetsCollectionViewController:(QBAssetsCollectionViewController *)assetsCollectionViewController didDeselectAsset:(ALAsset *)asset; +- (void)assetsCollectionViewControllerDidFinishSelection:(QBAssetsCollectionViewController *)assetsCollectionViewController; + +@end + +@interface QBAssetsCollectionViewController : UICollectionViewController <UICollectionViewDelegateFlowLayout> + +@property (nonatomic, weak) QBImagePickerController *imagePickerController; + +@property (nonatomic, weak) id<QBAssetsCollectionViewControllerDelegate> delegate; +@property (nonatomic, strong) ALAssetsGroup *assetsGroup; +@property (nonatomic, assign) QBImagePickerControllerFilterType filterType; +@property (nonatomic, assign) BOOL allowsMultipleSelection; +@property (nonatomic, assign) NSUInteger minimumNumberOfSelection; +@property (nonatomic, assign) NSUInteger maximumNumberOfSelection; + +- (void)selectAssetHavingURL:(NSURL *)URL; + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.m new file mode 100755 index 0000000..b3fc9c3 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.m @@ -0,0 +1,344 @@ +// +// QBAssetsCollectionViewController.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import "QBAssetsCollectionViewController.h" + +// Views +#import "QBAssetsCollectionViewCell.h" +#import "QBAssetsCollectionFooterView.h" + +@interface QBAssetsCollectionViewController () + +@property (nonatomic, strong) NSMutableArray *assets; + +@property (nonatomic, assign) NSUInteger numberOfAssets; +@property (nonatomic, assign) NSUInteger numberOfPhotos; +@property (nonatomic, assign) NSUInteger numberOfVideos; + +@property (nonatomic, assign) BOOL disableScrollToBottom; + +@end + +@implementation QBAssetsCollectionViewController + +- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout +{ + self = [super initWithCollectionViewLayout:layout]; + + if (self) { + // View settings + self.collectionView.backgroundColor = [UIColor whiteColor]; + + // Register cell class + [self.collectionView registerClass:[QBAssetsCollectionViewCell class] + forCellWithReuseIdentifier:@"AssetsCell"]; + [self.collectionView registerClass:[QBAssetsCollectionFooterView class] + forSupplementaryViewOfKind:UICollectionElementKindSectionFooter + withReuseIdentifier:@"FooterView"]; + } + + return self; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + // Scroll to bottom + if (self.isMovingToParentViewController && !self.disableScrollToBottom) { + CGFloat topInset; + if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { // iOS7 or later + topInset = ((self.edgesForExtendedLayout && UIRectEdgeTop) && (self.collectionView.contentInset.top == 0)) ? (20.0 + 44.0) : 0.0; + } else { + topInset = (self.collectionView.contentInset.top == 0) ? (20.0 + 44.0) : 0.0; + } + + [self.collectionView setContentOffset:CGPointMake(0, self.collectionView.collectionViewLayout.collectionViewContentSize.height - self.collectionView.frame.size.height + topInset) + animated:NO]; + } + + // Validation + if (self.allowsMultipleSelection) { + self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:self.imagePickerController.selectedAssetURLs.count]; + } +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + + self.disableScrollToBottom = YES; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + self.disableScrollToBottom = NO; +} + + +#pragma mark - Accessors + +- (void)setFilterType:(QBImagePickerControllerFilterType)filterType +{ + _filterType = filterType; + + // Set assets filter + [self.assetsGroup setAssetsFilter:ALAssetsFilterFromQBImagePickerControllerFilterType(self.filterType)]; +} + +- (void)setAssetsGroup:(ALAssetsGroup *)assetsGroup +{ + _assetsGroup = assetsGroup; + + // Set title + self.title = [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName]; + + // Set assets filter + [self.assetsGroup setAssetsFilter:ALAssetsFilterFromQBImagePickerControllerFilterType(self.filterType)]; + + // Load assets + NSMutableArray *assets = [NSMutableArray array]; + __block NSUInteger numberOfAssets = 0; + __block NSUInteger numberOfPhotos = 0; + __block NSUInteger numberOfVideos = 0; + + [self.assetsGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { + if (result) { + numberOfAssets++; + + NSString *type = [result valueForProperty:ALAssetPropertyType]; + if ([type isEqualToString:ALAssetTypePhoto]) numberOfPhotos++; + else if ([type isEqualToString:ALAssetTypeVideo]) numberOfVideos++; + + [assets addObject:result]; + } + }]; + + self.assets = assets; + self.numberOfAssets = numberOfAssets; + self.numberOfPhotos = numberOfPhotos; + self.numberOfVideos = numberOfVideos; + + // Update view + [self.collectionView reloadData]; +} + +- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection +{ + self.collectionView.allowsMultipleSelection = allowsMultipleSelection; + + // Show/hide done button + if (allowsMultipleSelection) { + UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)]; + [self.navigationItem setRightBarButtonItem:doneButton animated:NO]; + } else { + [self.navigationItem setRightBarButtonItem:nil animated:NO]; + } +} + +- (BOOL)allowsMultipleSelection +{ + return self.collectionView.allowsMultipleSelection; +} + + +#pragma mark - Actions + +- (void)done:(id)sender +{ + // Delegate + if (self.delegate && [self.delegate respondsToSelector:@selector(assetsCollectionViewControllerDidFinishSelection:)]) { + [self.delegate assetsCollectionViewControllerDidFinishSelection:self]; + } +} + + +#pragma mark - Managing Selection + +- (void)selectAssetHavingURL:(NSURL *)URL +{ + for (NSInteger i = 0; i < self.assets.count; i++) { + ALAsset *asset = self.assets[i]; + NSURL *assetURL = [asset valueForProperty:ALAssetPropertyAssetURL]; + + if ([assetURL isEqual:URL]) { + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; + [self.collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone]; + + return; + } + } +} + + +#pragma mark - Validating Selections + +- (BOOL)validateNumberOfSelections:(NSUInteger)numberOfSelections +{ + NSUInteger minimumNumberOfSelection = MAX(1, self.minimumNumberOfSelection); + BOOL qualifiesMinimumNumberOfSelection = (numberOfSelections >= minimumNumberOfSelection); + + BOOL qualifiesMaximumNumberOfSelection = YES; + if (minimumNumberOfSelection <= self.maximumNumberOfSelection) { + qualifiesMaximumNumberOfSelection = (numberOfSelections <= self.maximumNumberOfSelection); + } + + return (qualifiesMinimumNumberOfSelection && qualifiesMaximumNumberOfSelection); +} + +- (BOOL)validateMaximumNumberOfSelections:(NSUInteger)numberOfSelections +{ + NSUInteger minimumNumberOfSelection = MAX(1, self.minimumNumberOfSelection); + + if (minimumNumberOfSelection <= self.maximumNumberOfSelection) { + if (numberOfSelections > self.maximumNumberOfSelection) { + [MBProgressHUD showAutoMessage:[NSString stringWithFormat:@"������������������%lu���������", (unsigned long)self.maximumNumberOfSelection]]; + } + return (numberOfSelections <= self.maximumNumberOfSelection); + } + + return YES; +} + + +#pragma mark - UICollectionViewDataSource + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView +{ + return 1; +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return self.numberOfAssets; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + QBAssetsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AssetsCell" forIndexPath:indexPath]; + cell.showsOverlayViewWhenSelected = self.allowsMultipleSelection; + + ALAsset *asset = self.assets[indexPath.row]; + cell.asset = asset; + + return cell; +} + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section +{ + return CGSizeMake(collectionView.bounds.size.width, 46.0); +} + +- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath +{ + if (kind == UICollectionElementKindSectionFooter) { + QBAssetsCollectionFooterView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter + withReuseIdentifier:@"FooterView" + forIndexPath:indexPath]; + + switch (self.filterType) { + case QBImagePickerControllerFilterTypeNone:{ + NSString *format; + if (self.numberOfPhotos == 1) { + if (self.numberOfVideos == 1) { + format = @"format_photo_and_video"; + } else { + format = @"format_photo_and_videos"; + } + } else if (self.numberOfVideos == 1) { + format = @"format_photos_and_video"; + } else { + format = @"format_photos_and_videos"; + } + footerView.textLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(format, + @"QBImagePickerController", + nil), + self.numberOfPhotos, + self.numberOfVideos + ]; + break; + } + + case QBImagePickerControllerFilterTypePhotos:{ + NSString *format = (self.numberOfPhotos == 1) ? @"format_photo" : @"format_photos"; + footerView.textLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(format, + @"QBImagePickerController", + nil), + self.numberOfPhotos + ]; + break; + } + + case QBImagePickerControllerFilterTypeVideos:{ + NSString *format = (self.numberOfVideos == 1) ? @"format_video" : @"format_videos"; + footerView.textLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(format, + @"QBImagePickerController", + nil), + self.numberOfVideos + ]; + break; + } + } + + return footerView; + } + + return nil; +} + + +#pragma mark - UICollectionViewDelegateFlowLayout + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath +{ + return CGSizeMake(77.5, 77.5); +} + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section +{ + return UIEdgeInsetsMake(2, 2, 2, 2); +} + +- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + return [self validateMaximumNumberOfSelections:(self.imagePickerController.selectedAssetURLs.count + 1)]; +} + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + ALAsset *asset = self.assets[indexPath.row]; + + // Validation + if (self.allowsMultipleSelection) { + self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:(self.imagePickerController.selectedAssetURLs.count + 1)]; + } + + // Delegate + if (self.delegate && [self.delegate respondsToSelector:@selector(assetsCollectionViewController:didSelectAsset:)]) { + [self.delegate assetsCollectionViewController:self didSelectAsset:asset]; + } +} + +- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath +{ + ALAsset *asset = self.assets[indexPath.row]; + + // Validation + if (self.allowsMultipleSelection) { + self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:(self.imagePickerController.selectedAssetURLs.count - 1)]; + } + + // Delegate + if (self.delegate && [self.delegate respondsToSelector:@selector(assetsCollectionViewController:didDeselectAsset:)]) { + [self.delegate assetsCollectionViewController:self didDeselectAsset:asset]; + } +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.h new file mode 100755 index 0000000..f75811e --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.h @@ -0,0 +1,15 @@ +// +// QBAssetsCollectionViewLayout.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface QBAssetsCollectionViewLayout : UICollectionViewFlowLayout + ++ (instancetype)layout; + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.m new file mode 100755 index 0000000..4d6f452 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.m @@ -0,0 +1,30 @@ +// +// QBAssetsCollectionViewLayout.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import "QBAssetsCollectionViewLayout.h" + +@implementation QBAssetsCollectionViewLayout + ++ (instancetype)layout +{ + return [[self alloc] init]; +} + +- (instancetype)init +{ + self = [super init]; + + if (self) { + self.minimumLineSpacing = 2.0; + self.minimumInteritemSpacing = 2.0; + } + + return self; +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.h b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.h new file mode 100755 index 0000000..006bf6f --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.h @@ -0,0 +1,47 @@ +// +// QBImagePickerController.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/30. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import <AssetsLibrary/AssetsLibrary.h> + +typedef NS_ENUM(NSUInteger, QBImagePickerControllerFilterType) { + QBImagePickerControllerFilterTypeNone, + QBImagePickerControllerFilterTypePhotos, + QBImagePickerControllerFilterTypeVideos +}; + +UIKIT_EXTERN ALAssetsFilter * ALAssetsFilterFromQBImagePickerControllerFilterType(QBImagePickerControllerFilterType type); + +@class QBImagePickerController; + +@protocol QBImagePickerControllerDelegate <NSObject> + +@optional +- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAsset:(ALAsset *)asset; +- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAssets:(NSArray *)assets; +- (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController; + +@end + +@interface QBImagePickerController : UITableViewController + +@property (nonatomic, strong, readonly) ALAssetsLibrary *assetsLibrary; +@property (nonatomic, copy, readonly) NSArray *assetsGroups; +@property (nonatomic, strong, readonly) NSMutableOrderedSet *selectedAssetURLs; + +@property (nonatomic, weak) id<QBImagePickerControllerDelegate> delegate; +@property (nonatomic, copy) NSArray *groupTypes; +@property (nonatomic, assign) QBImagePickerControllerFilterType filterType; +@property (nonatomic, assign) BOOL showsCancelButton; +@property (nonatomic, assign) BOOL allowsMultipleSelection; +@property (nonatomic, assign) NSUInteger minimumNumberOfSelection; +@property (nonatomic, assign) NSUInteger maximumNumberOfSelection; + ++ (BOOL)isAccessible; + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.m b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.m new file mode 100755 index 0000000..11ec6eb --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.m @@ -0,0 +1,405 @@ +// +// QBImagePickerController.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/30. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import "QBImagePickerController.h" +#import <AssetsLibrary/AssetsLibrary.h> + +// Views +#import "QBImagePickerGroupCell.h" +#import "QBAssetsCollectionViewLayout.h" + +// ViewControllers +#import "QBAssetsCollectionViewController.h" + +ALAssetsFilter * ALAssetsFilterFromQBImagePickerControllerFilterType(QBImagePickerControllerFilterType type) { + switch (type) { + case QBImagePickerControllerFilterTypeNone: + return [ALAssetsFilter allAssets]; + break; + + case QBImagePickerControllerFilterTypePhotos: + return [ALAssetsFilter allPhotos]; + break; + + case QBImagePickerControllerFilterTypeVideos: + return [ALAssetsFilter allVideos]; + break; + } +} + +@interface QBImagePickerController () <QBAssetsCollectionViewControllerDelegate> + +@property (nonatomic, strong, readwrite) ALAssetsLibrary *assetsLibrary; +@property (nonatomic, copy, readwrite) NSArray *assetsGroups; +@property (nonatomic, strong, readwrite) NSMutableOrderedSet *selectedAssetURLs; +@property (nonatomic, assign) BOOL firstShow; + +@end + +@implementation QBImagePickerController + ++ (BOOL)isAccessible +{ + return ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] && + [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum]); +} + +- (instancetype)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:UITableViewStylePlain]; + + if (self) { + [self setUpProperties]; + } + + return self; +} + +- (void)awakeFromNib +{ + [super awakeFromNib]; + + [self setUpProperties]; +} + +- (void)setUpProperties +{ + // Property settings + self.selectedAssetURLs = [NSMutableOrderedSet orderedSet]; + + self.groupTypes = @[ + @(ALAssetsGroupSavedPhotos), + @(ALAssetsGroupPhotoStream), + @(ALAssetsGroupAlbum) + ]; + self.filterType = QBImagePickerControllerFilterTypeNone; + self.showsCancelButton = YES; + + // View settings + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; + + // Create assets library instance + ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init]; + self.assetsLibrary = assetsLibrary; + + // Register cell classes + [self.tableView registerClass:[QBImagePickerGroupCell class] forCellReuseIdentifier:@"GroupCell"]; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // View controller settings + self.title = NSLocalizedStringFromTable(@"title", @"QBImagePickerController", nil); + self.firstShow = YES; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + // Load assets groups + [self loadAssetsGroupsWithTypes:self.groupTypes + completion:^(NSArray *assetsGroups) { + self.assetsGroups = assetsGroups; + [self.tableView reloadData]; + if (self.firstShow) { + self.firstShow = NO; +// [self pushToCollectionVCWithIndex:0]; + } + }]; + + // Validation + self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:self.selectedAssetURLs.count]; +} + + +#pragma mark - Accessors + +- (void)setShowsCancelButton:(BOOL)showsCancelButton +{ + _showsCancelButton = showsCancelButton; + + // Show/hide cancel button + if (showsCancelButton) { + UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel:)]; + [self.navigationItem setLeftBarButtonItem:cancelButton animated:NO]; + } else { + [self.navigationItem setLeftBarButtonItem:nil animated:NO]; + } +} + +- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection +{ + _allowsMultipleSelection = allowsMultipleSelection; + + // Show/hide done button + if (allowsMultipleSelection) { + UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)]; + [self.navigationItem setRightBarButtonItem:doneButton animated:NO]; + } else { + [self.navigationItem setRightBarButtonItem:nil animated:NO]; + } +} + + +#pragma mark - Actions + +- (void)done:(id)sender +{ + [self passSelectedAssetsToDelegate]; +} + +- (void)cancel:(id)sender +{ + // Delegate + if (self.delegate && [self.delegate respondsToSelector:@selector(qb_imagePickerControllerDidCancel:)]) { + [self.delegate qb_imagePickerControllerDidCancel:self]; + } +} + + +#pragma mark - Validating Selections + +- (BOOL)validateNumberOfSelections:(NSUInteger)numberOfSelections +{ + // Check the number of selected assets + NSUInteger minimumNumberOfSelection = MAX(1, self.minimumNumberOfSelection); + BOOL qualifiesMinimumNumberOfSelection = (numberOfSelections >= minimumNumberOfSelection); + + BOOL qualifiesMaximumNumberOfSelection = YES; + if (minimumNumberOfSelection <= self.maximumNumberOfSelection) { + qualifiesMaximumNumberOfSelection = (numberOfSelections <= self.maximumNumberOfSelection); + } + + return (qualifiesMinimumNumberOfSelection && qualifiesMaximumNumberOfSelection); +} + + +#pragma mark - Managing Assets + +- (void)loadAssetsGroupsWithTypes:(NSArray *)types completion:(void (^)(NSArray *assetsGroups))completion +{ + __block NSMutableArray *assetsGroups = [NSMutableArray array]; + __block NSUInteger numberOfFinishedTypes = 0; + + for (NSNumber *type in types) { + __weak typeof(self) weakSelf = self; + + [self.assetsLibrary enumerateGroupsWithTypes:[type unsignedIntegerValue] + usingBlock:^(ALAssetsGroup *assetsGroup, BOOL *stop) { + if (assetsGroup) { + // Filter the assets group + [assetsGroup setAssetsFilter:ALAssetsFilterFromQBImagePickerControllerFilterType(weakSelf.filterType)]; + + if (assetsGroup.numberOfAssets > 0) { + // Add assets group + [assetsGroups addObject:assetsGroup]; + } + } else { + numberOfFinishedTypes++; + } + + // Check if the loading finished + if (numberOfFinishedTypes == types.count) { + // Sort assets groups + NSArray *sortedAssetsGroups = [self sortAssetsGroups:(NSArray *)assetsGroups typesOrder:types]; + + // Call completion block + if (completion) { + completion(sortedAssetsGroups); + } + } + } failureBlock:^(NSError *error) { + NSLog(@"Error: %@", [error localizedDescription]); + }]; + } +} + +- (NSArray *)sortAssetsGroups:(NSArray *)assetsGroups typesOrder:(NSArray *)typesOrder +{ + NSMutableArray *sortedAssetsGroups = [NSMutableArray array]; + + for (ALAssetsGroup *assetsGroup in assetsGroups) { + if (sortedAssetsGroups.count == 0) { + [sortedAssetsGroups addObject:assetsGroup]; + continue; + } + + ALAssetsGroupType assetsGroupType = [[assetsGroup valueForProperty:ALAssetsGroupPropertyType] unsignedIntegerValue]; + NSUInteger indexOfAssetsGroupType = [typesOrder indexOfObject:@(assetsGroupType)]; + + for (NSInteger i = 0; i <= sortedAssetsGroups.count; i++) { + if (i == sortedAssetsGroups.count) { + [sortedAssetsGroups addObject:assetsGroup]; + break; + } + + ALAssetsGroup *sortedAssetsGroup = sortedAssetsGroups[i]; + ALAssetsGroupType sortedAssetsGroupType = [[sortedAssetsGroup valueForProperty:ALAssetsGroupPropertyType] unsignedIntegerValue]; + NSUInteger indexOfSortedAssetsGroupType = [typesOrder indexOfObject:@(sortedAssetsGroupType)]; + + if (indexOfAssetsGroupType < indexOfSortedAssetsGroupType) { + [sortedAssetsGroups insertObject:assetsGroup atIndex:i]; + break; + } + } + } + + return [sortedAssetsGroups copy]; +} + +- (void)passSelectedAssetsToDelegate +{ + // Load assets from URLs + __block NSMutableArray *assets = [NSMutableArray array]; + __block NSUInteger tryCount = 0; + + for (NSURL *selectedAssetURL in self.selectedAssetURLs) { + __weak typeof(self) weakSelf = self; + + // Success block + void (^selectAsset)(ALAsset *) = ^(ALAsset *asset) { + if (asset) { + [assets addObject:asset]; + } + // Check if the loading finished + if (tryCount == weakSelf.selectedAssetURLs.count) { + //NSLog(@"���������������������������%lu", (long)(tryCount - assets.count)); + // Delegate + if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(qb_imagePickerController:didSelectAssets:)]) { + [weakSelf.delegate qb_imagePickerController:weakSelf didSelectAssets:[assets copy]]; + } + } + }; + + [self.assetsLibrary assetForURL:selectedAssetURL resultBlock:^(ALAsset *asset) { + if (asset) { + tryCount++; + selectAsset(asset); + }else{ + // Search in the Photo Stream Album + [weakSelf.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupPhotoStream usingBlock:^(ALAssetsGroup *group, BOOL *stop) { + [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopG) { + if([result.defaultRepresentation.url isEqual:selectedAssetURL]) { + *stopG = YES; + *stop = YES; + tryCount++; + selectAsset(result); + }else if (index == 0){ + NSLog(@"���������"); + tryCount++;//��������������������� + selectAsset(nil); + } + }]; + } failureBlock:^(NSError *error) { + NSLog(@"Error: %@", [error localizedDescription]); + }]; + } + } failureBlock:^(NSError *error) { + NSLog(@"Error: %@", [error localizedDescription]); + }]; + } +} + + +#pragma mark - UITableViewDataSource + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return self.assetsGroups.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + QBImagePickerGroupCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GroupCell" forIndexPath:indexPath]; + + ALAssetsGroup *assetsGroup = self.assetsGroups[indexPath.row]; + cell.assetsGroup = assetsGroup; + + return cell; +} + + +#pragma mark - UITableViewDelegate + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return 86.0; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [self pushToCollectionVCWithIndex:indexPath.row]; +} + +- (void)pushToCollectionVCWithIndex:(NSInteger)index{ + if (index >= 0 && index < self.assetsGroups.count) { + QBAssetsCollectionViewController *assetsCollectionViewController = [[QBAssetsCollectionViewController alloc] initWithCollectionViewLayout:[QBAssetsCollectionViewLayout layout]]; + assetsCollectionViewController.imagePickerController = self; + assetsCollectionViewController.filterType = self.filterType; + assetsCollectionViewController.allowsMultipleSelection = self.allowsMultipleSelection; + assetsCollectionViewController.minimumNumberOfSelection = self.minimumNumberOfSelection; + assetsCollectionViewController.maximumNumberOfSelection = self.maximumNumberOfSelection; + + ALAssetsGroup *assetsGroup = self.assetsGroups[index]; + assetsCollectionViewController.delegate = self; + assetsCollectionViewController.assetsGroup = assetsGroup; + + for (NSURL *assetURL in self.selectedAssetURLs) { + [assetsCollectionViewController selectAssetHavingURL:assetURL]; + } + + [self.navigationController pushViewController:assetsCollectionViewController animated:YES]; + } +} + + +#pragma mark - QBAssetsCollectionViewControllerDelegate + +- (void)assetsCollectionViewController:(QBAssetsCollectionViewController *)assetsCollectionViewController didSelectAsset:(ALAsset *)asset +{ + if (self.allowsMultipleSelection) { + // Add asset URL + NSURL *assetURL = [asset valueForProperty:ALAssetPropertyAssetURL]; + [self.selectedAssetURLs addObject:assetURL]; + + // Validation + self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:self.selectedAssetURLs.count]; + } else { + // Delegate + if (self.delegate && [self.delegate respondsToSelector:@selector(qb_imagePickerController:didSelectAsset:)]) { + [self.delegate qb_imagePickerController:self didSelectAsset:asset]; + } + } +} + +- (void)assetsCollectionViewController:(QBAssetsCollectionViewController *)assetsCollectionViewController didDeselectAsset:(ALAsset *)asset +{ + if (self.allowsMultipleSelection) { + // Remove asset URL + NSURL *assetURL = [asset valueForProperty:ALAssetPropertyAssetURL]; + [self.selectedAssetURLs removeObject:assetURL]; + + // Validation + self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:self.selectedAssetURLs.count]; + } +} + +- (void)assetsCollectionViewControllerDidFinishSelection:(QBAssetsCollectionViewController *)assetsCollectionViewController +{ + [self passSelectedAssetsToDelegate]; +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.strings b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.strings new file mode 100755 index 0000000..dfc7cce --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.strings @@ -0,0 +1,18 @@ +/* + QBImagePickerController.strings + QBImagePickerControllerDemo + + Created by Tanaka Katsuma on 2014/01/01. + Copyright (c) 2014��� Katsuma Tanaka. All rights reserved. +*/ + +"title" = "������"; + +"format_photo" = "���%ld���������"; +"format_photos" = "���%ld���������"; +"format_video" = "%���ld���������"; +"format_videos" = "���%ld���������"; +"format_photo_and_video" = "%���ld���������, %ld���������"; +"format_photos_and_video" = "%���ld���������, %ld���������"; +"format_photo_and_videos" = "%���ld���������, %ld���������"; +"format_photos_and_videos" = "%���ld���������, %ld���������"; diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.h b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.h new file mode 100755 index 0000000..a6480ae --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.h @@ -0,0 +1,16 @@ +// +// QBImagePickerGroupCell.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/30. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import <AssetsLibrary/AssetsLibrary.h> + +@interface QBImagePickerGroupCell : UITableViewCell + +@property (nonatomic, strong) ALAssetsGroup *assetsGroup; + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.m b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.m new file mode 100755 index 0000000..c5bdac5 --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.m @@ -0,0 +1,76 @@ +// +// QBImagePickerGroupCell.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/30. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import "QBImagePickerGroupCell.h" + +// Views +#import "QBImagePickerThumbnailView.h" + +@interface QBImagePickerGroupCell () + +@property (nonatomic, strong) QBImagePickerThumbnailView *thumbnailView; +@property (nonatomic, strong) UILabel *nameLabel; +@property (nonatomic, strong) UILabel *countLabel; + +@end + +@implementation QBImagePickerGroupCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + // Cell settings + self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + + // Create thumbnail view + QBImagePickerThumbnailView *thumbnailView = [[QBImagePickerThumbnailView alloc] initWithFrame:CGRectMake(8, 4, 70, 74)]; + thumbnailView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; + + [self.contentView addSubview:thumbnailView]; + self.thumbnailView = thumbnailView; + + // Create name label + UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(8 + 70 + 18, 22, 180, 21)]; + nameLabel.font = [UIFont systemFontOfSize:17]; + nameLabel.textColor = [UIColor blackColor]; + nameLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth; + + [self.contentView addSubview:nameLabel]; + self.nameLabel = nameLabel; + + // Create count label + UILabel *countLabel = [[UILabel alloc] initWithFrame:CGRectMake(8 + 70 + 18, 46, 180, 15)]; + countLabel.font = [UIFont systemFontOfSize:12]; + countLabel.textColor = [UIColor blackColor]; + countLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth; + + [self.contentView addSubview:countLabel]; + self.countLabel = countLabel; + } + + return self; +} + + +#pragma mark - Accessors + +- (void)setAssetsGroup:(ALAssetsGroup *)assetsGroup +{ + _assetsGroup = assetsGroup; + + // Update thumbnail view + self.thumbnailView.assetsGroup = self.assetsGroup; + + // Update label + self.nameLabel.text = [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName]; + self.countLabel.text = [NSString stringWithFormat:@"%ld", (long)self.assetsGroup.numberOfAssets]; +} + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.h b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.h new file mode 100755 index 0000000..2b5eeaa --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.h @@ -0,0 +1,16 @@ +// +// QBImagePickerThumbnailView.h +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import <AssetsLibrary/AssetsLibrary.h> + +@interface QBImagePickerThumbnailView : UIView + +@property (nonatomic, strong) ALAssetsGroup *assetsGroup; + +@end diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.m b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.m new file mode 100755 index 0000000..ea05a6c --- /dev/null +++ b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.m @@ -0,0 +1,112 @@ +// +// QBImagePickerThumbnailView.m +// QBImagePickerController +// +// Created by Tanaka Katsuma on 2013/12/31. +// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved. +// + +#import "QBImagePickerThumbnailView.h" + +@interface QBImagePickerThumbnailView () + +@property (nonatomic, copy) NSArray *thumbnailImages; +@property (nonatomic, strong) UIImage *blankImage; + +@end + +@implementation QBImagePickerThumbnailView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + + if (self) { + self.backgroundColor = [UIColor clearColor]; + } + + return self; +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + return CGSizeMake(70.0, 74.0); +} + +- (void)drawRect:(CGRect)rect +{ + [super drawRect:rect]; + + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); + + if (self.thumbnailImages.count == 3) { + UIImage *thumbnailImage = [self.thumbnailImages firstObject]; + + CGRect thumbnailImageRect = CGRectMake(4.0, 0, 62.0, 62.0); + CGContextFillRect(context, thumbnailImageRect); + [thumbnailImage drawInRect:CGRectInset(thumbnailImageRect, 0.5, 0.5)]; + } + if (self.thumbnailImages.count >= 2) { + UIImage *thumbnailImage = self.thumbnailImages[1]; + + CGRect thumbnailImageRect = CGRectMake(2.0, 2.0, 66.0, 66.0); + CGContextFillRect(context, thumbnailImageRect); + [thumbnailImage drawInRect:CGRectInset(thumbnailImageRect, 0.5, 0.5)]; + } + if (self.thumbnailImages.count >= 1) { + UIImage *thumbnailImage = [self.thumbnailImages lastObject]; + + CGRect thumbnailImageRect = CGRectMake(0, 4.0, 70.0, 70.0); + CGContextFillRect(context, thumbnailImageRect); + [thumbnailImage drawInRect:CGRectInset(thumbnailImageRect, 0.5, 0.5)]; + } +} + + +#pragma mark - Accessors + +- (void)setAssetsGroup:(ALAssetsGroup *)assetsGroup +{ + _assetsGroup = assetsGroup; + + // Extract three thumbnail images + NSInteger thumbnailImagesCount = MIN(3, assetsGroup.numberOfAssets); + NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(assetsGroup.numberOfAssets-thumbnailImagesCount, thumbnailImagesCount)]; + NSMutableArray *thumbnailImages = [NSMutableArray array]; + [assetsGroup enumerateAssetsAtIndexes:indexes + options:0 + usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { + if (result) { + CGImageRef thumbnailImageRef = [result thumbnail]; + + if (thumbnailImageRef) { + [thumbnailImages addObject:[UIImage imageWithCGImage:thumbnailImageRef]]; + } else { + [thumbnailImages addObject:[self blankImage]]; + } + } + }]; + self.thumbnailImages = [thumbnailImages copy]; + + [self setNeedsDisplay]; +} + +- (UIImage *)blankImage +{ + if (_blankImage == nil) { + CGSize size = CGSizeMake(100.0, 100.0); + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); + + [[UIColor colorWithWhite:(240.0 / 255.0) alpha:1.0] setFill]; + UIRectFill(CGRectMake(0, 0, size.width, size.height)); + + _blankImage = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + } + + return _blankImage; +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Alpha.h b/camerademo/camerademo/demo/UIImage/UIImage+Alpha.h new file mode 100755 index 0000000..ba09684 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Alpha.h @@ -0,0 +1,40 @@ +// UIImage+Alpha.h +// Created by Trevor Harmon on 9/20/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +// Helper methods for adding an alpha layer to an image +#import <UIKit/UIKit.h> + +@interface UIImage (Alpha) +/** + * @brief ���������alpha������ + * + * @return ���������alpha������ + */ +- (BOOL)hasAlpha; +/** + * @brief ������������alpha������ ������alpha������ + * + * @return ������������alpha������ ������alpha������ + */ +- (UIImage *)imageWithAlpha; +/** + * @brief ������������������ + * + * @param borderSize ������������ + * + * @return ������������������������������ + */ +- (UIImage *)transparentBorderImage:(NSUInteger)borderSize; + + +//http://stackoverflow.com/questions/6521987/crop-uiimage-to-alpha?answertab=oldest#tab-top +/** + * @brief ������������������������������������ + * + * @return ������������������ + */ +- (UIImage *)trimmedBetterSize; + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Alpha.m b/camerademo/camerademo/demo/UIImage/UIImage+Alpha.m new file mode 100755 index 0000000..fba6259 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Alpha.m @@ -0,0 +1,234 @@ +// UIImage+Alpha.m +// Created by Trevor Harmon on 9/20/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +#import "UIImage+Alpha.h" + +// Private helper methods +@interface UIImage (AlphaPrivateMethods) +- (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size; +@end + +@implementation UIImage (Alpha) +/** + * @brief ���������alpha������ + * + * @return ���������alpha������ + */ +- (BOOL)hasAlpha { + CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage); + return (alpha == kCGImageAlphaFirst || + alpha == kCGImageAlphaLast || + alpha == kCGImageAlphaPremultipliedFirst || + alpha == kCGImageAlphaPremultipliedLast); +} +/** + * @brief ������������alpha������ ������alpha������ + * + * @return ������������alpha������ ������alpha������ + */ +- (UIImage *)imageWithAlpha { + if ([self hasAlpha]) { + return self; + } + + CGImageRef imageRef = self.CGImage; + size_t width = CGImageGetWidth(imageRef); + size_t height = CGImageGetHeight(imageRef); + + // The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error + CGContextRef offscreenContext = CGBitmapContextCreate(NULL, + width, + height, + 8, + 0, + CGImageGetColorSpace(imageRef), + kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); + + // Draw the image into the context and retrieve the new image, which will now have an alpha layer + CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef); + CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext); + UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha]; + + // Clean up + CGContextRelease(offscreenContext); + CGImageRelease(imageRefWithAlpha); + + return imageWithAlpha; +} + +// Returns a copy of the image with a transparent border of the given size added around its edges. +// If the image has no alpha layer, one will be added to it. +/** + * @brief ������������������ + * + * @param borderSize ������������ + * + * @return ������������������������������ + */ +- (UIImage *)transparentBorderImage:(NSUInteger)borderSize { + // If the image does not have an alpha layer, add one + UIImage *image = [self imageWithAlpha]; + + CGRect newRect = CGRectMake(0, 0, image.size.width + borderSize * 2, image.size.height + borderSize * 2); + + // Build a context that's the same dimensions as the new size + CGContextRef bitmap = CGBitmapContextCreate(NULL, + newRect.size.width, + newRect.size.height, + CGImageGetBitsPerComponent(self.CGImage), + 0, + CGImageGetColorSpace(self.CGImage), + CGImageGetBitmapInfo(self.CGImage)); + + // Draw the image in the center of the context, leaving a gap around the edges + CGRect imageLocation = CGRectMake(borderSize, borderSize, image.size.width, image.size.height); + CGContextDrawImage(bitmap, imageLocation, self.CGImage); + CGImageRef borderImageRef = CGBitmapContextCreateImage(bitmap); + + // Create a mask to make the border transparent, and combine it with the image + CGImageRef maskImageRef = [self newBorderMask:borderSize size:newRect.size]; + CGImageRef transparentBorderImageRef = CGImageCreateWithMask(borderImageRef, maskImageRef); + UIImage *transparentBorderImage = [UIImage imageWithCGImage:transparentBorderImageRef]; + + // Clean up + CGContextRelease(bitmap); + CGImageRelease(borderImageRef); + CGImageRelease(maskImageRef); + CGImageRelease(transparentBorderImageRef); + + return transparentBorderImage; +} +/** + * @brief ������������������������������������ + * + * @return ������������������ + */ +- (UIImage *)trimmedBetterSize { + + CGImageRef inImage = self.CGImage; + CFDataRef m_DataRef; + m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage)); + + UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef); + +// size_t width = CGImageGetWidth(inImage); +// size_t height = CGImageGetHeight(inImage); + CGFloat width = CGImageGetWidth(inImage); + CGFloat height = CGImageGetHeight(inImage); + CGPoint top,left,right,bottom; + + BOOL breakOut = NO; + for (int x = 0;breakOut==NO && x < width; x++) { + for (int y = 0; y < height; y++) { + int loc = x + (y * width); + loc *= 4; + if (m_PixelBuf[loc + 3] != 0) { + left = CGPointMake(x, y); + breakOut = YES; + break; + } + } + } + + breakOut = NO; + for (int y = 0;breakOut==NO && y < height; y++) { + + for (int x = 0; x < width; x++) { + + int loc = x + (y * width); + loc *= 4; + if (m_PixelBuf[loc + 3] != 0) { + top = CGPointMake(x, y); + breakOut = YES; + break; + } + + } + } + + breakOut = NO; + for (int y = height-1;breakOut==NO && y >= 0; y--) { + + for (int x = width-1; x >= 0; x--) { + + int loc = x + (y * width); + loc *= 4; + if (m_PixelBuf[loc + 3] != 0) { + bottom = CGPointMake(x, y); + breakOut = YES; + break; + } + + } + } + + breakOut = NO; + for (int x = width-1;breakOut==NO && x >= 0; x--) { + + for (int y = height-1; y >= 0; y--) { + + int loc = x + (y * width); + loc *= 4; + if (m_PixelBuf[loc + 3] != 0) { + right = CGPointMake(x, y); + breakOut = YES; + break; + } + + } + } + + + CGFloat scale = self.scale; + + CGRect cropRect = CGRectMake(left.x / scale, top.y/scale, (right.x - left.x)/scale, (bottom.y - top.y) / scale); + UIGraphicsBeginImageContextWithOptions( cropRect.size, + NO, + scale); + [self drawAtPoint:CGPointMake(-cropRect.origin.x, -cropRect.origin.y) + blendMode:kCGBlendModeCopy + alpha:1.]; + UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + CFRelease(m_DataRef); + return croppedImage; +} +#pragma mark - +#pragma mark Private helper methods + +// Creates a mask that makes the outer edges transparent and everything else opaque +// The size must include the entire mask (opaque part + transparent border) +// The caller is responsible for releasing the returned reference by calling CGImageRelease +- (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size { + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + + // Build a context that's the same dimensions as the new size + CGContextRef maskContext = CGBitmapContextCreate(NULL, + size.width, + size.height, + 8, // 8-bit grayscale + 0, + colorSpace, + kCGBitmapByteOrderDefault | kCGImageAlphaNone); + + // Start with a mask that's entirely transparent + CGContextSetFillColorWithColor(maskContext, [UIColor blackColor].CGColor); + CGContextFillRect(maskContext, CGRectMake(0, 0, size.width, size.height)); + + // Make the inner part (within the border) opaque + CGContextSetFillColorWithColor(maskContext, [UIColor whiteColor].CGColor); + CGContextFillRect(maskContext, CGRectMake(borderSize, borderSize, size.width - borderSize * 2, size.height - borderSize * 2)); + + // Get an image of the context + CGImageRef maskImageRef = CGBitmapContextCreateImage(maskContext); + + // Clean up + CGContextRelease(maskContext); + CGColorSpaceRelease(colorSpace); + + return maskImageRef; +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.h b/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.h new file mode 100755 index 0000000..95fa0d6 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.h @@ -0,0 +1,23 @@ +// +// UIImage+BetterFace.h +// bf +// +// Created by liuyan on 13-11-25. +// Copyright (c) 2013��� Croath. All rights reserved. +// +// https://github.com/croath/UIImageView-BetterFace +// a UIImageView category to let the picture-cutting with faces showing better + +#import <UIKit/UIKit.h> + +typedef NS_ENUM(NSUInteger, BFAccuracy) { + kBFAccuracyLow = 0, + kBFAccuracyHigh, +}; + +@interface UIImage (BetterFace) + +- (UIImage *)betterFaceImageForSize:(CGSize)size + accuracy:(BFAccuracy)accurary; + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.m b/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.m new file mode 100755 index 0000000..f776f71 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.m @@ -0,0 +1,111 @@ +// +// UIImage+BetterFace.m +// bf +// +// Created by liuyan on 13-11-25. +// Copyright (c) 2013��� Croath. All rights reserved. +// + +#import "UIImage+BetterFace.h" + +#define GOLDEN_RATIO (0.618) + +#ifdef BF_DEBUG +#define BFLog(format...) NSLog(format) +#else +#define BFLog(format...) +#endif + +@implementation UIImage (BetterFace) + +- (UIImage *)betterFaceImageForSize:(CGSize)size + accuracy:(BFAccuracy)accurary; +{ + NSArray *features = [UIImage _faceFeaturesInImage:self accuracy:accurary]; + + if ([features count]==0) { + BFLog(@"no faces"); + return nil; + } else { + BFLog(@"succeed %lu faces", (unsigned long)[features count]); + return [self _subImageForFaceFeatures:features + size:size]; + } +} + +- (UIImage *)_subImageForFaceFeatures:(NSArray *)faceFeatures size:(CGSize)size +{ + CGRect fixedRect = CGRectMake(MAXFLOAT, MAXFLOAT, 0, 0); + CGFloat rightBorder = 0, bottomBorder = 0; + for (CIFaceFeature *faceFeature in faceFeatures){ + CGRect oneRect = faceFeature.bounds; + oneRect.origin.y = size.height - oneRect.origin.y - oneRect.size.height; + + fixedRect.origin.x = MIN(oneRect.origin.x, fixedRect.origin.x); + fixedRect.origin.y = MIN(oneRect.origin.y, fixedRect.origin.y); + + rightBorder = MAX(oneRect.origin.x + oneRect.size.width, rightBorder); + bottomBorder = MAX(oneRect.origin.y + oneRect.size.height, bottomBorder); + } + + fixedRect.size.width = rightBorder - fixedRect.origin.x; + fixedRect.size.height = bottomBorder - fixedRect.origin.y; + + CGPoint fixedCenter = CGPointMake(fixedRect.origin.x + fixedRect.size.width / 2.0, + fixedRect.origin.y + fixedRect.size.height / 2.0); + CGPoint offset = CGPointZero; + CGSize finalSize = size; + if (size.width / size.height > self.size.width / self.size.height) { + //move horizonal + finalSize.height = self.size.height; + finalSize.width = size.width/size.height * finalSize.height; + fixedCenter.x = finalSize.width / size.width * fixedCenter.x; + fixedCenter.y = finalSize.width / size.width * fixedCenter.y; + + offset.x = fixedCenter.x - self.size.width * 0.5; + if (offset.x < 0) { + offset.x = 0; + } else if (offset.x + self.size.width > finalSize.width) { + offset.x = finalSize.width - self.size.width; + } + offset.x = - offset.x; + } else { + //move vertical + finalSize.width = self.size.width; + finalSize.height = size.height/size.width * finalSize.width; + fixedCenter.x = finalSize.width / size.width * fixedCenter.x; + fixedCenter.y = finalSize.width / size.width * fixedCenter.y; + + offset.y = fixedCenter.y - self.size.height * (1-GOLDEN_RATIO); + if (offset.y < 0) { + offset.y = 0; + } else if (offset.y + self.size.height > finalSize.height){ + offset.y = finalSize.height = self.size.height; + } + offset.y = - offset.y; + } + + CGRect finalRect = CGRectApplyAffineTransform(CGRectMake(offset.x, offset.y, finalSize.width, finalSize.height), + CGAffineTransformMakeScale(self.scale, self.scale)); + CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], finalRect); + UIImage *subImage = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; + CGImageRelease(imageRef); + + return subImage; +} + +#pragma mark - Util + ++ (NSArray *)_faceFeaturesInImage:(UIImage *)image accuracy:(BFAccuracy)accurary +{ + CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage]; + NSString *accuraryStr = (accurary == kBFAccuracyLow) ? CIDetectorAccuracyLow : CIDetectorAccuracyHigh; + + CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace + context:nil + options:@{CIDetectorAccuracy: accuraryStr}]; + + return [detector featuresInImage:ciImage]; +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Blur.h b/camerademo/camerademo/demo/UIImage/UIImage+Blur.h new file mode 100755 index 0000000..4f5f82b --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Blur.h @@ -0,0 +1,24 @@ +// +// UIImage+Blur.h +// IOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/6/5. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import <UIKit/UIKit.h> +FOUNDATION_EXPORT double ImageEffectsVersionNumber; +FOUNDATION_EXPORT const unsigned char ImageEffectsVersionString[]; +@interface UIImage (Blur) +- (UIImage *)lightImage; +- (UIImage *)extraLightImage; +- (UIImage *)darkImage; +- (UIImage *)tintedImageWithColor:(UIColor *)tintColor; + +- (UIImage *)blurredImageWithRadius:(CGFloat)blurRadius; +- (UIImage *)blurredImageWithSize:(CGSize)blurSize; +- (UIImage *)blurredImageWithSize:(CGSize)blurSize + tintColor:(UIColor *)tintColor + saturationDeltaFactor:(CGFloat)saturationDeltaFactor + maskImage:(UIImage *)maskImage; +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Blur.m b/camerademo/camerademo/demo/UIImage/UIImage+Blur.m new file mode 100755 index 0000000..70f4461 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Blur.m @@ -0,0 +1,281 @@ +// +// UIImage+Blur.m +// IOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/6/5. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import "UIImage+Blur.h" +@import Accelerate; +@implementation UIImage (Blur) +#pragma mark - +#pragma mark - Effects + +//| ---------------------------------------------------------------------------- +- (UIImage *)lightImage +{ + UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; + return [self blurredImageWithSize:CGSizeMake(60, 60) tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +//| ---------------------------------------------------------------------------- +- (UIImage *)extraLightImage +{ + UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; + return [self blurredImageWithSize:CGSizeMake(40, 40) tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +//| ---------------------------------------------------------------------------- +- (UIImage *)darkImage +{ + UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; + return [self blurredImageWithSize:CGSizeMake(40, 40) tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +//| ---------------------------------------------------------------------------- +- (UIImage *)tintedImageWithColor:(UIColor *)tintColor +{ + const CGFloat EffectColorAlpha = 0.6; + UIColor *effectColor = tintColor; + size_t componentCount = CGColorGetNumberOfComponents(tintColor.CGColor); + if (componentCount == 2) { + CGFloat b; + if ([tintColor getWhite:&b alpha:NULL]) { + effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; + } + } + else { + CGFloat r, g, b; + if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { + effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; + } + } + return [self blurredImageWithSize:CGSizeMake(20, 20) tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil]; +} + + +//| ---------------------------------------------------------------------------- +- (UIImage *)blurredImageWithRadius:(CGFloat)blurRadius +{ + return [self blurredImageWithSize:CGSizeMake(blurRadius, blurRadius)]; +} + + +//| ---------------------------------------------------------------------------- +- (UIImage *)blurredImageWithSize:(CGSize)blurSize +{ + return [self blurredImageWithSize:blurSize tintColor:nil saturationDeltaFactor:1.0 maskImage:nil]; +} + +#pragma mark - +#pragma mark - Implementation + +//| ---------------------------------------------------------------------------- +- (UIImage *)blurredImageWithSize:(CGSize)blurSize tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage +{ +#define ENABLE_BLUR 1 +#define ENABLE_SATURATION_ADJUSTMENT 1 +#define ENABLE_TINT 1 + + // Check pre-conditions. + if (self.size.width < 1 || self.size.height < 1) + { + NSLog(@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); + return nil; + } + if (!self.CGImage) + { + NSLog(@"*** error: inputImage must be backed by a CGImage: %@", self); + return nil; + } + if (maskImage && !maskImage.CGImage) + { + NSLog(@"*** error: effectMaskImage must be backed by a CGImage: %@", maskImage); + return nil; + } + + BOOL hasBlur = blurSize.width > __FLT_EPSILON__ || blurSize.height > __FLT_EPSILON__; + BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; + + CGImageRef inputCGImage = self.CGImage; + CGFloat inputImageScale = self.scale; + CGBitmapInfo inputImageBitmapInfo = CGImageGetBitmapInfo(inputCGImage); + CGImageAlphaInfo inputImageAlphaInfo = (inputImageBitmapInfo & kCGBitmapAlphaInfoMask); + + CGSize outputImageSizeInPoints = self.size; + CGRect outputImageRectInPoints = { CGPointZero, outputImageSizeInPoints }; + + // Set up output context. + BOOL useOpaqueContext; + if (inputImageAlphaInfo == kCGImageAlphaNone || inputImageAlphaInfo == kCGImageAlphaNoneSkipLast || inputImageAlphaInfo == kCGImageAlphaNoneSkipFirst) + useOpaqueContext = YES; + else + useOpaqueContext = NO; + UIGraphicsBeginImageContextWithOptions(outputImageRectInPoints.size, useOpaqueContext, inputImageScale); + CGContextRef outputContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(outputContext, 1.0, -1.0); + CGContextTranslateCTM(outputContext, 0, -outputImageRectInPoints.size.height); + + if (hasBlur || hasSaturationChange) + { + vImage_Buffer effectInBuffer; + vImage_Buffer scratchBuffer1; + + vImage_Buffer *inputBuffer; + vImage_Buffer *outputBuffer; + + vImage_CGImageFormat format = { + .bitsPerComponent = 8, + .bitsPerPixel = 32, + .colorSpace = NULL, + // (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little) + // requests a BGRA buffer. + .bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little, + .version = 0, + .decode = NULL, + .renderingIntent = kCGRenderingIntentDefault + }; + + vImage_Error e = vImageBuffer_InitWithCGImage(&effectInBuffer, &format, NULL, self.CGImage, kvImagePrintDiagnosticsToConsole); + if (e != kvImageNoError) + { + NSLog(@"*** error: vImageBuffer_InitWithCGImage returned error code %zi for inputImage: %@", e, self); + UIGraphicsEndImageContext(); + return nil; + } + + vImageBuffer_Init(&scratchBuffer1, effectInBuffer.height, effectInBuffer.width, format.bitsPerPixel, kvImageNoFlags); + inputBuffer = &effectInBuffer; + outputBuffer = &scratchBuffer1; + +#if ENABLE_BLUR + if (hasBlur) + { + CGFloat radiusX = [self gaussianBlurRadiusWithBlurRadius:blurSize.width * inputImageScale]; + CGFloat radiusY = [self gaussianBlurRadiusWithBlurRadius:blurSize.height * inputImageScale]; + + NSInteger tempBufferSize = vImageBoxConvolve_ARGB8888(inputBuffer, outputBuffer, NULL, 0, 0, radiusY, radiusX, NULL, kvImageGetTempBufferSize | kvImageEdgeExtend); + void *tempBuffer = malloc(tempBufferSize); + + vImageBoxConvolve_ARGB8888(inputBuffer, outputBuffer, tempBuffer, 0, 0, radiusY, radiusX, NULL, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(outputBuffer, inputBuffer, tempBuffer, 0, 0, radiusY, radiusX, NULL, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(inputBuffer, outputBuffer, tempBuffer, 0, 0, radiusY, radiusX, NULL, kvImageEdgeExtend); + + free(tempBuffer); + + vImage_Buffer *temp = inputBuffer; + inputBuffer = outputBuffer; + outputBuffer = temp; + } +#endif + +#if ENABLE_SATURATION_ADJUSTMENT + if (hasSaturationChange) + { + CGFloat s = saturationDeltaFactor; + // These values appear in the W3C Filter Effects spec: + // https://dvcs.w3.org/hg/FXTF/raw-file/default/filters/index.html#grayscaleEquivalent + // + CGFloat floatingPointSaturationMatrix[] = { + 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, + 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, + 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, + 0, 0, 0, 1, + }; + const int32_t divisor = 256; + NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); + int16_t saturationMatrix[matrixSize]; + for (NSUInteger i = 0; i < matrixSize; ++i) { + saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); + } + vImageMatrixMultiply_ARGB8888(inputBuffer, outputBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + + vImage_Buffer *temp = inputBuffer; + inputBuffer = outputBuffer; + outputBuffer = temp; + } +#endif + + CGImageRef effectCGImage; + if ( (effectCGImage = vImageCreateCGImageFromBuffer(inputBuffer, &format, &cleanupBuffer, NULL, kvImageNoAllocate, NULL)) == NULL ) { + effectCGImage = vImageCreateCGImageFromBuffer(inputBuffer, &format, NULL, NULL, kvImageNoFlags, NULL); + free(inputBuffer->data); + } + if (maskImage) { + // Only need to draw the base image if the effect image will be masked. + CGContextDrawImage(outputContext, outputImageRectInPoints, inputCGImage); + } + + // draw effect image + CGContextSaveGState(outputContext); + if (maskImage) + CGContextClipToMask(outputContext, outputImageRectInPoints, maskImage.CGImage); + CGContextDrawImage(outputContext, outputImageRectInPoints, effectCGImage); + CGContextRestoreGState(outputContext); + + // Cleanup + CGImageRelease(effectCGImage); + free(outputBuffer->data); + } + else + { + // draw base image + CGContextDrawImage(outputContext, outputImageRectInPoints, inputCGImage); + } + +#if ENABLE_TINT + // Add in color tint. + if (tintColor) + { + CGContextSaveGState(outputContext); + CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); + CGContextFillRect(outputContext, outputImageRectInPoints); + CGContextRestoreGState(outputContext); + } +#endif + + // Output image is ready. + UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return outputImage; +#undef ENABLE_BLUR +#undef ENABLE_SATURATION_ADJUSTMENT +#undef ENABLE_TINT +} + + +// A description of how to compute the box kernel width from the Gaussian +// radius (aka standard deviation) appears in the SVG spec: +// http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement +// +// For larger values of 's' (s >= 2.0), an approximation can be used: Three +// successive box-blurs build a piece-wise quadratic convolution kernel, which +// approximates the Gaussian kernel to within roughly 3%. +// +// let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) +// +// ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. +// +- (CGFloat)gaussianBlurRadiusWithBlurRadius:(CGFloat)blurRadius +{ + if (blurRadius - 2. < __FLT_EPSILON__) { + blurRadius = 2.; + } + uint32_t radius = floor((blurRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5) / 2); + radius |= 1; // force radius to be odd so that the three box-blur methodology works. + return radius; +} + + +//| ---------------------------------------------------------------------------- +// Helper function to handle deferred cleanup of a buffer. +// +void cleanupBuffer(void *userData, void *buf_data) +{ free(buf_data); } + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Capture.h b/camerademo/camerademo/demo/UIImage/UIImage+Capture.h new file mode 100755 index 0000000..36ccac3 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Capture.h @@ -0,0 +1,35 @@ +// +// UIImage+Capture.h +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/1/10. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface UIImage (Capture) +/** + * @brief ������������view��������� + * + * @param view ������view + * + * @return ������ + */ ++ (UIImage *)captureWithView:(UIView *)view; + +///��������������������������������� ++ (UIImage *)getImageWithSize:(CGRect)myImageRect FromImage:(UIImage *)bigImage; + +/** + * @author Jakey + * + * @brief ������������view��������������� ������������������������ + * + * @param aView ���������view + * @param maxWidth ������������ 0���view������������ + * + * @return ������ + */ ++ (UIImage *)screenshotWithView:(UIView *)aView limitWidth:(CGFloat)maxWidth; +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Capture.m b/camerademo/camerademo/demo/UIImage/UIImage+Capture.m new file mode 100755 index 0000000..e376c89 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Capture.m @@ -0,0 +1,105 @@ +// +// UIImage+Capture.m +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/1/10. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import "UIImage+Capture.h" +#import <QuartzCore/QuartzCore.h> +@implementation UIImage (Capture) +/** + * @brief ������������view��������� + * + * @param view ������view + * + * @return ������ + */ ++ (UIImage *)captureWithView:(UIView *)view +{ + UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [UIScreen mainScreen].scale); + // IOS7������������������ + if ([view respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) { + [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO]; + } else { // IOS7��������������� + [view.layer renderInContext:UIGraphicsGetCurrentContext()]; + } + + UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return screenshot; +} + ++ (UIImage *)getImageWithSize:(CGRect)myImageRect FromImage:(UIImage *)bigImage +{ + //������bigImage + //������myImageRect������������������ + CGImageRef imageRef = bigImage.CGImage; + CGImageRef subImageRef = CGImageCreateWithImageInRect(imageRef, myImageRect); + CGSize size; + size.width = CGRectGetWidth(myImageRect); + size.height = CGRectGetHeight(myImageRect); + UIGraphicsBeginImageContext(size); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextDrawImage(context, myImageRect, subImageRef); + UIImage* smallImage = [UIImage imageWithCGImage:subImageRef]; + CGImageRelease(subImageRef); + UIGraphicsEndImageContext(); + return smallImage; +} + +/** + * @author Jakey + * + * @brief ������������view��������������� ������������������������ + * + * @param aView ���������view + * @param maxWidth ������������ 0���view������������ + * + * @return ������ + */ ++ (UIImage *)screenshotWithView:(UIView *)aView limitWidth:(CGFloat)maxWidth{ + CGAffineTransform oldTransform = aView.transform; + + CGAffineTransform scaleTransform = CGAffineTransformIdentity; + if (!isnan(maxWidth) && maxWidth>0) { + CGFloat maxScale = maxWidth/CGRectGetWidth(aView.frame); + CGAffineTransform transformScale = CGAffineTransformMakeScale(maxScale, maxScale); + scaleTransform = CGAffineTransformConcat(oldTransform, transformScale); + + } + if(!CGAffineTransformEqualToTransform(scaleTransform, CGAffineTransformIdentity)){ + aView.transform = scaleTransform; + } + + CGRect actureFrame = aView.frame; //���������������������frame + CGRect actureBounds= aView.bounds;//CGRectApplyAffineTransform(); + + //begin + UIGraphicsBeginImageContextWithOptions(actureFrame.size, NO, 0.0); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSaveGState(context); + // CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1, -1); + CGContextTranslateCTM(context,actureFrame.size.width/2, actureFrame.size.height/2); + CGContextConcatCTM(context, aView.transform); + CGPoint anchorPoint = aView.layer.anchorPoint; + CGContextTranslateCTM(context, + -actureBounds.size.width * anchorPoint.x, + -actureBounds.size.height * anchorPoint.y); + if([aView respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) + { + [aView drawViewHierarchyInRect:aView.bounds afterScreenUpdates:NO]; + } + else + { + [aView.layer renderInContext:UIGraphicsGetCurrentContext()]; + } + UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + //end + aView.transform = oldTransform; + + return screenshot; +} +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Color.h b/camerademo/camerademo/demo/UIImage/UIImage+Color.h new file mode 100755 index 0000000..10fefa6 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Color.h @@ -0,0 +1,53 @@ +// +// UIImage+Color.h +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 14/12/15. +// Copyright (c) 2014��� www.skyfox.org. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface UIImage (Color) +/** + * @brief ������������������������������ + * + * @param color ������ + * + * @return ������������ + */ ++ (UIImage *)imageWithColor:(UIColor *)color; +/** + * @brief ��������������������������� + * + * @param point ��������� + * + * @return ������ + */ +- (UIColor *)colorAtPoint:(CGPoint )point; +//more accurate method ,colorAtPixel 1x1 pixel +/** + * @brief ������������������������ + * + * @param point ��������� + * + * @return ������ + */ +- (UIColor *)colorAtPixel:(CGPoint)point; +/** + * @brief ��������������������������������������� + * + * @return ������������������������ + */ +- (BOOL)hasAlphaChannel; + +/** + * @brief ��������������� + * + * @param sourceImage ������ + * + * @return ������������������ + */ ++ (UIImage*)covertToGrayImageFromImage:(UIImage*)sourceImage; + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Color.m b/camerademo/camerademo/demo/UIImage/UIImage+Color.m new file mode 100755 index 0000000..e005574 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Color.m @@ -0,0 +1,175 @@ +// +// UIImage+Color.m +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 14/12/15. +// Copyright (c) 2014��� www.skyfox.org. All rights reserved. +// + +#import "UIImage+Color.h" + +@implementation UIImage (Color) +/** + * @brief ������������������������������ + * + * @param color ������ + * + * @return ������������ + */ ++ (UIImage *)imageWithColor:(UIColor *)color { + CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); + UIGraphicsBeginImageContext(rect.size); + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextSetFillColorWithColor(context, [color CGColor]); + CGContextFillRect(context, rect); + + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return image; +} +/** + * @brief ��������������������������� + * + * @param point ��������� + * + * @return ������ + */ +- (UIColor *)colorAtPoint:(CGPoint )point +{ + if (point.x < 0 || point.y < 0) return nil; + + CGImageRef imageRef = self.CGImage; + NSUInteger width = CGImageGetWidth(imageRef); + NSUInteger height = CGImageGetHeight(imageRef); + if (point.x >= width || point.y >= height) return nil; + + unsigned char *rawData = malloc(height * width * 4); + if (!rawData) return nil; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + NSUInteger bytesPerPixel = 4; + NSUInteger bytesPerRow = bytesPerPixel * width; + NSUInteger bitsPerComponent = 8; + CGContextRef context = CGBitmapContextCreate(rawData, + width, + height, + bitsPerComponent, + bytesPerRow, + colorSpace, + kCGImageAlphaPremultipliedLast + | kCGBitmapByteOrder32Big); + if (!context) { + free(rawData); + return nil; + } + CGColorSpaceRelease(colorSpace); + CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); + CGContextRelease(context); + + int byteIndex = (bytesPerRow * point.y) + point.x * bytesPerPixel; + CGFloat red = (rawData[byteIndex] * 1.0) / 255.0; + CGFloat green = (rawData[byteIndex + 1] * 1.0) / 255.0; + CGFloat blue = (rawData[byteIndex + 2] * 1.0) / 255.0; + CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0; + + UIColor *result = nil; + result = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; + free(rawData); + return result; +} +/** + * @brief ������������������������ + * + * @param point ��������� + * + * @return ������ + */ +- (UIColor *)colorAtPixel:(CGPoint)point +{ + // Cancel if point is outside image coordinates + if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, self.size.width, self.size.height), point)) { + return nil; + } + + // Create a 1x1 pixel byte array and bitmap context to draw the pixel into. + // Reference: http://stackoverflow.com/questions/1042830/retrieving-a-pixel-alpha-value-for-a-uiimage + NSInteger pointX = trunc(point.x); + NSInteger pointY = trunc(point.y); + CGImageRef cgImage = self.CGImage; + NSUInteger width = self.size.width; + NSUInteger height = self.size.height; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + int bytesPerPixel = 4; + int bytesPerRow = bytesPerPixel * 1; + NSUInteger bitsPerComponent = 8; + unsigned char pixelData[4] = { 0, 0, 0, 0 }; + CGContextRef context = CGBitmapContextCreate(pixelData, + 1, + 1, + bitsPerComponent, + bytesPerRow, + colorSpace, + kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); + CGColorSpaceRelease(colorSpace); + CGContextSetBlendMode(context, kCGBlendModeCopy); + + // Draw the pixel we are interested in onto the bitmap context + CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height); + CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage); + CGContextRelease(context); + + // Convert color values [0..255] to floats [0.0..1.0] + CGFloat red = (CGFloat)pixelData[0] / 255.0f; + CGFloat green = (CGFloat)pixelData[1] / 255.0f; + CGFloat blue = (CGFloat)pixelData[2] / 255.0f; + CGFloat alpha = (CGFloat)pixelData[3] / 255.0f; + return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; +} +/** + * @brief ��������������������������������������� + * + * @return ������������������������ + */ +- (BOOL)hasAlphaChannel +{ + CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage); + return (alpha == kCGImageAlphaFirst || + alpha == kCGImageAlphaLast || + alpha == kCGImageAlphaPremultipliedFirst || + alpha == kCGImageAlphaPremultipliedLast); +} + +/** + * @brief ��������������� + * + * @param sourceImage ������ + * + * @return ������������������ + */ + ++ (UIImage*)covertToGrayImageFromImage:(UIImage*)sourceImage +{ + int width = sourceImage.size.width; + int height = sourceImage.size.height; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + CGContextRef context = CGBitmapContextCreate (nil,width,height,8,0,colorSpace,kCGImageAlphaNone); + CGColorSpaceRelease(colorSpace); + + if (context == NULL) { + return nil; + } + + CGContextDrawImage(context,CGRectMake(0, 0, width, height), sourceImage.CGImage); + CGImageRef contextRef = CGBitmapContextCreateImage(context); + UIImage *grayImage = [UIImage imageWithCGImage:contextRef]; + CGContextRelease(context); + CGImageRelease(contextRef); + + return grayImage; +} + + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+FX.h b/camerademo/camerademo/demo/UIImage/UIImage+FX.h new file mode 100755 index 0000000..1eacf3d --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+FX.h @@ -0,0 +1,56 @@ +// +// UIImage+FX.h +// +// Version 1.2.3 +// +// Created by Nick Lockwood on 31/10/2011. +// Copyright (c) 2011 Charcoal Design +// +// Distributed under the permissive zlib License +// Get the latest version from here: +// +// https://github.com/nicklockwood/FXImageView +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + +#import <UIKit/UIKit.h> + + +@interface UIImage (FX) + +- (UIImage *)imageCroppedToRect:(CGRect)rect; +- (UIImage *)imageScaledToSize:(CGSize)size; +- (UIImage *)imageScaledToFitSize:(CGSize)size; +- (UIImage *)imageScaledToFillSize:(CGSize)size; +- (UIImage *)imageCroppedAndScaledToSize:(CGSize)size + contentMode:(UIViewContentMode)contentMode + padToFit:(BOOL)padToFit; + +- (UIImage *)reflectedImageWithScale:(CGFloat)scale; +- (UIImage *)imageWithReflectionWithScale:(CGFloat)scale gap:(CGFloat)gap alpha:(CGFloat)alpha; +- (UIImage *)imageWithShadowColor:(UIColor *)color offset:(CGSize)offset blur:(CGFloat)blur; +- (UIImage *)imageWithCornerRadius:(CGFloat)radius; +- (UIImage *)imageWithAlpha:(CGFloat)alpha; +- (UIImage *)imageWithMask:(UIImage *)maskImage; + +- (UIImage *)maskImageFromImageAlpha; + + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+FX.m b/camerademo/camerademo/demo/UIImage/UIImage+FX.m new file mode 100755 index 0000000..904a1f3 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+FX.m @@ -0,0 +1,426 @@ +// +// UIImage+FX.m +// +// Version 1.2.3 +// +// Created by Nick Lockwood on 31/10/2011. +// Copyright (c) 2011 Charcoal Design +// +// Distributed under the permissive zlib License +// Get the latest version from here: +// +// https://github.com/nicklockwood/FXImageView +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + +#import "UIImage+FX.h" + +@implementation UIImage (FX) + +- (UIImage *)imageCroppedToRect:(CGRect)rect +{ + //create drawing context + UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0f); + + //draw + [self drawAtPoint:CGPointMake(-rect.origin.x, -rect.origin.y)]; + + //capture resultant image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return image + return image; +} + +- (UIImage *)imageScaledToSize:(CGSize)size +{ + //avoid redundant drawing + if (CGSizeEqualToSize(self.size, size)) + { + return self; + } + + //create drawing context + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f); + + //draw + [self drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)]; + + //capture resultant image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return image + return image; +} + +- (UIImage *)imageScaledToFitSize:(CGSize)size +{ + //calculate rect + CGFloat aspect = self.size.width / self.size.height; + if (size.width / aspect <= size.height) + { + return [self imageScaledToSize:CGSizeMake(size.width, size.width / aspect)]; + } + else + { + return [self imageScaledToSize:CGSizeMake(size.height * aspect, size.height)]; + } +} + +- (UIImage *)imageScaledToFillSize:(CGSize)size +{ + if (CGSizeEqualToSize(self.size, size)) + { + return self; + } + //calculate rect + CGFloat aspect = self.size.width / self.size.height; + if (size.width / aspect >= size.height) + { + return [self imageScaledToSize:CGSizeMake(size.width, size.width / aspect)]; + } + else + { + return [self imageScaledToSize:CGSizeMake(size.height * aspect, size.height)]; + } +} + +- (UIImage *)imageCroppedAndScaledToSize:(CGSize)size + contentMode:(UIViewContentMode)contentMode + padToFit:(BOOL)padToFit; +{ + //calculate rect + CGRect rect = CGRectZero; + switch (contentMode) + { + case UIViewContentModeScaleAspectFit: + { + CGFloat aspect = self.size.width / self.size.height; + if (size.width / aspect <= size.height) + { + rect = CGRectMake(0.0f, (size.height - size.width / aspect) / 2.0f, size.width, size.width / aspect); + } + else + { + rect = CGRectMake((size.width - size.height * aspect) / 2.0f, 0.0f, size.height * aspect, size.height); + } + break; + } + case UIViewContentModeScaleAspectFill: + { + CGFloat aspect = self.size.width / self.size.height; + if (size.width / aspect >= size.height) + { + rect = CGRectMake(0.0f, (size.height - size.width / aspect) / 2.0f, size.width, size.width / aspect); + } + else + { + rect = CGRectMake((size.width - size.height * aspect) / 2.0f, 0.0f, size.height * aspect, size.height); + } + break; + } + case UIViewContentModeCenter: + { + rect = CGRectMake((size.width - self.size.width) / 2.0f, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height); + break; + } + case UIViewContentModeTop: + { + rect = CGRectMake((size.width - self.size.width) / 2.0f, 0.0f, self.size.width, self.size.height); + break; + } + case UIViewContentModeBottom: + { + rect = CGRectMake((size.width - self.size.width) / 2.0f, size.height - self.size.height, self.size.width, self.size.height); + break; + } + case UIViewContentModeLeft: + { + rect = CGRectMake(0.0f, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height); + break; + } + case UIViewContentModeRight: + { + rect = CGRectMake(size.width - self.size.width, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height); + break; + } + case UIViewContentModeTopLeft: + { + rect = CGRectMake(0.0f, 0.0f, self.size.width, self.size.height); + break; + } + case UIViewContentModeTopRight: + { + rect = CGRectMake(size.width - self.size.width, 0.0f, self.size.width, self.size.height); + break; + } + case UIViewContentModeBottomLeft: + { + rect = CGRectMake(0.0f, size.height - self.size.height, self.size.width, self.size.height); + break; + } + case UIViewContentModeBottomRight: + { + rect = CGRectMake(size.width - self.size.width, size.height - self.size.height, self.size.width, self.size.height); + break; + } + default: + { + rect = CGRectMake(0.0f, 0.0f, size.width, size.height); + break; + } + } + + if (!padToFit) + { + //remove padding + if (rect.size.width < size.width) + { + size.width = rect.size.width; + rect.origin.x = 0.0f; + } + if (rect.size.height < size.height) + { + size.height = rect.size.height; + rect.origin.y = 0.0f; + } + } + + //avoid redundant drawing + if (CGSizeEqualToSize(self.size, size)) + { + return self; + } + + //create drawing context + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f); + + //draw + [self drawInRect:rect]; + + //capture resultant image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return image + return image; +} + ++ (CGImageRef)gradientMask +{ + static CGImageRef sharedMask = NULL; + if (sharedMask == NULL) + { + //create gradient mask + UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 256), YES, 0.0); + CGContextRef gradientContext = UIGraphicsGetCurrentContext(); + CGFloat colors[] = {0.0, 1.0, 1.0, 1.0}; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2); + CGPoint gradientStartPoint = CGPointMake(0, 0); + CGPoint gradientEndPoint = CGPointMake(0, 256); + CGContextDrawLinearGradient(gradientContext, gradient, gradientStartPoint, + gradientEndPoint, kCGGradientDrawsAfterEndLocation); + sharedMask = CGBitmapContextCreateImage(gradientContext); + CGGradientRelease(gradient); + CGColorSpaceRelease(colorSpace); + UIGraphicsEndImageContext(); + } + return sharedMask; +} + +- (UIImage *)reflectedImageWithScale:(CGFloat)scale +{ + //get reflection dimensions + CGFloat height = ceil(self.size.height * scale); + CGSize size = CGSizeMake(self.size.width, height); + CGRect bounds = CGRectMake(0.0f, 0.0f, size.width, size.height); + + //create drawing context + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f); + CGContextRef context = UIGraphicsGetCurrentContext(); + + //clip to gradient + CGContextClipToMask(context, bounds, [[self class] gradientMask]); + + //draw reflected image + CGContextScaleCTM(context, 1.0f, -1.0f); + CGContextTranslateCTM(context, 0.0f, -self.size.height); + [self drawInRect:CGRectMake(0.0f, 0.0f, self.size.width, self.size.height)]; + + //capture resultant image + UIImage *reflection = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return reflection image + return reflection; +} + +- (UIImage *)imageWithReflectionWithScale:(CGFloat)scale gap:(CGFloat)gap alpha:(CGFloat)alpha +{ + //get reflected image + UIImage *reflection = [self reflectedImageWithScale:scale]; + CGFloat reflectionOffset = reflection.size.height + gap; + + //create drawing context + UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.size.width, self.size.height + reflectionOffset * 2.0f), NO, 0.0f); + + //draw reflection + [reflection drawAtPoint:CGPointMake(0.0f, reflectionOffset + self.size.height + gap) blendMode:kCGBlendModeNormal alpha:alpha]; + + //draw image + [self drawAtPoint:CGPointMake(0.0f, reflectionOffset)]; + + //capture resultant image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return image + return image; +} + +- (UIImage *)imageWithShadowColor:(UIColor *)color offset:(CGSize)offset blur:(CGFloat)blur +{ + //get size + //CGSize border = CGSizeMake(fabsf(offset.width) + blur, fabsf(offset.height) + blur); + CGSize border = CGSizeMake(fabs(offset.width) + blur, fabs(offset.height) + blur); + + CGSize size = CGSizeMake(self.size.width + border.width * 2.0f, self.size.height + border.height * 2.0f); + + //create drawing context + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f); + CGContextRef context = UIGraphicsGetCurrentContext(); + + //set up shadow + CGContextSetShadowWithColor(context, offset, blur, color.CGColor); + + //draw with shadow + [self drawAtPoint:CGPointMake(border.width, border.height)]; + + //capture resultant image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return image + return image; +} + +- (UIImage *)imageWithCornerRadius:(CGFloat)radius +{ + //create drawing context + UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f); + CGContextRef context = UIGraphicsGetCurrentContext(); + + //clip image + CGContextBeginPath(context); + CGContextMoveToPoint(context, 0.0f, radius); + CGContextAddLineToPoint(context, 0.0f, self.size.height - radius); + CGContextAddArc(context, radius, self.size.height - radius, radius, M_PI, M_PI / 2.0f, 1); + CGContextAddLineToPoint(context, self.size.width - radius, self.size.height); + CGContextAddArc(context, self.size.width - radius, self.size.height - radius, radius, M_PI / 2.0f, 0.0f, 1); + CGContextAddLineToPoint(context, self.size.width, radius); + CGContextAddArc(context, self.size.width - radius, radius, radius, 0.0f, -M_PI / 2.0f, 1); + CGContextAddLineToPoint(context, radius, 0.0f); + CGContextAddArc(context, radius, radius, radius, -M_PI / 2.0f, M_PI, 1); + CGContextClip(context); + + //draw image + [self drawAtPoint:CGPointZero]; + + //capture resultant image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return image + return image; +} + +- (UIImage *)imageWithAlpha:(CGFloat)alpha +{ + //create drawing context + UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f); + + //draw with alpha + [self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha]; + + //capture resultant image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return image + return image; +} + +- (UIImage *)imageWithMask:(UIImage *)maskImage; +{ + //create drawing context + UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f); + CGContextRef context = UIGraphicsGetCurrentContext(); + + //apply mask + CGContextClipToMask(context, CGRectMake(0.0f, 0.0f, self.size.width, self.size.height), maskImage.CGImage); + + //draw image + [self drawAtPoint:CGPointZero]; + + //capture resultant image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + //return image + return image; +} + +- (UIImage *)maskImageFromImageAlpha +{ + //get dimensions + NSInteger width = CGImageGetWidth(self.CGImage); + NSInteger height = CGImageGetHeight(self.CGImage); + + //create alpha image + NSInteger bytesPerRow = ((width + 3) / 4) * 4; + void *data = calloc(bytesPerRow * height, sizeof(unsigned char *)); + CGContextRef context = CGBitmapContextCreate(data, width, height, 8, bytesPerRow, NULL, kCGImageAlphaOnly); + CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), self.CGImage); + + //invert alpha pixels + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + NSInteger index = y * bytesPerRow + x; + ((unsigned char *)data)[index] = 255 - ((unsigned char *)data)[index]; + } + } + + //create mask image + CGImageRef maskRef = CGBitmapContextCreateImage(context); + CGContextRelease(context); + UIImage *mask = [UIImage imageWithCGImage:maskRef]; + CGImageRelease(maskRef); + free(data); + + //return image + return mask; +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+FileName.h b/camerademo/camerademo/demo/UIImage/UIImage+FileName.h new file mode 100755 index 0000000..6e881f3 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+FileName.h @@ -0,0 +1,21 @@ +// +// UIImage+FileName.h +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 14/12/15. +// Copyright (c) 2014��� www.skyfox.org. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface UIImage (FileName) +/** + * @brief ������bundle��������������������������� + * + * @param name ��������� + * + * @return ������������������ + */ ++ (UIImage *)imageWithFileName:(NSString *)name; + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+FileName.m b/camerademo/camerademo/demo/UIImage/UIImage+FileName.m new file mode 100755 index 0000000..6a468ee --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+FileName.m @@ -0,0 +1,57 @@ +// +// UIImage+FileName.m +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 14/12/15. +// Copyright (c) 2014��� www.skyfox.org. All rights reserved. +// +#import "UIImage+FileName.h" + + +@implementation UIImage (FileName) +/** + * @brief ������bundle��������������������������� + * + * @param name ��������� + * + * @return ������������������ + */ ++ (UIImage *)imageWithFileName:(NSString *)name { + NSString *extension = @"png"; + + NSArray *components = [name componentsSeparatedByString:@"."]; + if ([components count] >= 2) { + NSUInteger lastIndex = components.count - 1; + extension = [components objectAtIndex:lastIndex]; + + name = [name substringToIndex:(name.length-(extension.length+1))]; + } + + // ���������Retina���������������������������������������Retina��������������������������������� + if ([UIScreen mainScreen].scale == 2.0) { + name = [name stringByAppendingString:@"@2x"]; + + NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:extension]; + if (path != nil) { + return [UIImage imageWithContentsOfFile:path]; + } + } + + if ([UIScreen mainScreen].scale == 3.0) { + name = [name stringByAppendingString:@"@3x"]; + + NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:extension]; + if (path != nil) { + return [UIImage imageWithContentsOfFile:path]; + } + } + + NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:extension]; + if (path) { + return [UIImage imageWithContentsOfFile:path]; + } + + return nil; +} + +@end diff --git a/test/SDWebImage/UIImage+GIF.h b/camerademo/camerademo/demo/UIImage/UIImage+GIF.h similarity index 100% copy from test/SDWebImage/UIImage+GIF.h copy to camerademo/camerademo/demo/UIImage/UIImage+GIF.h diff --git a/camerademo/camerademo/demo/UIImage/UIImage+GIF.m b/camerademo/camerademo/demo/UIImage/UIImage+GIF.m new file mode 100755 index 0000000..a703637 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+GIF.m @@ -0,0 +1,158 @@ +// +// UIImage+GIF.m +// LBGIFImage +// +// Created by Laurin Brandner on 06.01.12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "UIImage+GIF.h" +#import <ImageIO/ImageIO.h> + +@implementation UIImage (GIF) + ++ (UIImage *)sd_animatedGIFWithData:(NSData *)data { + if (!data) { + return nil; + } + + CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); + + size_t count = CGImageSourceGetCount(source); + + UIImage *animatedImage; + + if (count <= 1) { + animatedImage = [[UIImage alloc] initWithData:data]; + } + else { + NSMutableArray *images = [NSMutableArray array]; + + NSTimeInterval duration = 0.0f; + + for (size_t i = 0; i < count; i++) { + CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); + + duration += [self sd_frameDurationAtIndex:i source:source]; + + [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; + + CGImageRelease(image); + } + + if (!duration) { + duration = (1.0f / 10.0f) * count; + } + + animatedImage = [UIImage animatedImageWithImages:images duration:duration]; + } + + CFRelease(source); + + return animatedImage; +} + ++ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { + float frameDuration = 0.1f; + CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); + NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; + NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary]; + + NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; + if (delayTimeUnclampedProp) { + frameDuration = [delayTimeUnclampedProp floatValue]; + } + else { + + NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; + if (delayTimeProp) { + frameDuration = [delayTimeProp floatValue]; + } + } + + // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. + // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify + // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082> + // for more information. + + if (frameDuration < 0.011f) { + frameDuration = 0.100f; + } + + CFRelease(cfFrameProperties); + return frameDuration; +} + ++ (UIImage *)sd_animatedGIFNamed:(NSString *)name { + CGFloat scale = [UIScreen mainScreen].scale; + + if (scale > 1.0f) { + NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"]; + + NSData *data = [NSData dataWithContentsOfFile:retinaPath]; + + if (data) { + return [UIImage sd_animatedGIFWithData:data]; + } + + NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; + + data = [NSData dataWithContentsOfFile:path]; + + if (data) { + return [UIImage sd_animatedGIFWithData:data]; + } + + return [UIImage imageNamed:name]; + } + else { + NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; + + NSData *data = [NSData dataWithContentsOfFile:path]; + + if (data) { + return [UIImage sd_animatedGIFWithData:data]; + } + + return [UIImage imageNamed:name]; + } +} + +- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size { + if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) { + return self; + } + + CGSize scaledSize = size; + CGPoint thumbnailPoint = CGPointZero; + + CGFloat widthFactor = size.width / self.size.width; + CGFloat heightFactor = size.height / self.size.height; + CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor; + scaledSize.width = self.size.width * scaleFactor; + scaledSize.height = self.size.height * scaleFactor; + + if (widthFactor > heightFactor) { + thumbnailPoint.y = (size.height - scaledSize.height) * 0.5; + } + else if (widthFactor < heightFactor) { + thumbnailPoint.x = (size.width - scaledSize.width) * 0.5; + } + + NSMutableArray *scaledImages = [NSMutableArray array]; + + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); + + for (UIImage *image in self.images) { + [image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)]; + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + + [scaledImages addObject:newImage]; + } + + UIGraphicsEndImageContext(); + + return [UIImage animatedImageWithImages:scaledImages duration:self.duration]; +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Merge.h b/camerademo/camerademo/demo/UIImage/UIImage+Merge.h new file mode 100755 index 0000000..a7eeb5c --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Merge.h @@ -0,0 +1,21 @@ +// +// UIImage+Merge.h +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 14/12/30. +// Copyright (c) 2014��� www.skyfox.org. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface UIImage (Merge) +/** + * @brief ������������������ + * + * @param firstImage ������������ + * @param secondImage ������������ + * + * @return ��������������� + */ ++ (UIImage*)mergeImage:(UIImage*)firstImage withImage:(UIImage*)secondImage; +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Merge.m b/camerademo/camerademo/demo/UIImage/UIImage+Merge.m new file mode 100755 index 0000000..b3dc743 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Merge.m @@ -0,0 +1,35 @@ +// +// UIImage+Merge.m +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 14/12/30. +// Copyright (c) 2014��� www.skyfox.org. All rights reserved. +// + +#import "UIImage+Merge.h" + +@implementation UIImage (Merge) +/** + * @brief ������������������ + * + * @param firstImage ������������ + * @param secondImage ������������ + * + * @return ��������������� + */ ++ (UIImage*)mergeImage:(UIImage*)firstImage withImage:(UIImage*)secondImage { + CGImageRef firstImageRef = firstImage.CGImage; + CGFloat firstWidth = CGImageGetWidth(firstImageRef); + CGFloat firstHeight = CGImageGetHeight(firstImageRef); + CGImageRef secondImageRef = secondImage.CGImage; + CGFloat secondWidth = CGImageGetWidth(secondImageRef); + CGFloat secondHeight = CGImageGetHeight(secondImageRef); + CGSize mergedSize = CGSizeMake(MAX(firstWidth, secondWidth), MAX(firstHeight, secondHeight)); + UIGraphicsBeginImageContext(mergedSize); + [firstImage drawInRect:CGRectMake(0, 0, firstWidth, firstHeight)]; + [secondImage drawInRect:CGRectMake(0, 0, secondWidth, secondHeight)]; + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return image; +} +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Orientation.h b/camerademo/camerademo/demo/UIImage/UIImage+Orientation.h new file mode 100755 index 0000000..89a3fd9 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Orientation.h @@ -0,0 +1,69 @@ +// +// UIImage+Orientation.h +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/1/4. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import <UIKit/UIKit.h> +//CGFloat DegreesToRadiansForOrientation(CGFloat degrees) {return degrees * M_PI / 180;}; +//CGFloat RadiansToDegreesForOrientation(CGFloat radians) {return radians * 180/M_PI;}; +@interface UIImage (Orientation) +/** + * @brief ��������������������� + * + * @param srcImg ������ + * + * @return ������������������������ + */ ++ (UIImage *)fixOrientation:(UIImage *)srcImg; +/** + * @brief ������������ + * + * @param degrees ������ + * + * @return ��������������� + */ +- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees; + +/** + * @brief ������������ + * + * @param degrees ������ + * + * @return ��������������� + */ +- (UIImage *)imageRotatedByRadians:(CGFloat)radians; + +/** + * @brief ������������ + * + * @return ������������������ + */ +- (UIImage *)flipVertical; +/** + * @brief ������������ + * + * @return ������������������ + */ +- (UIImage *)flipHorizontal; + +/** + * @brief ��������������� + * + * @param degrees ������ + * + * @return ������ + */ ++(CGFloat)degreesToRadians:(CGFloat)degrees; +/** + * @brief ��������������� + * + * @param radians ������ + * + * @return ������ + */ ++(CGFloat)radiansToDegrees:(CGFloat)radians; + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Orientation.m b/camerademo/camerademo/demo/UIImage/UIImage+Orientation.m new file mode 100755 index 0000000..98a1a98 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Orientation.m @@ -0,0 +1,181 @@ +// +// UIImage+Orientation.m +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/1/4. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import "UIImage+Orientation.h" + +@implementation UIImage (Orientation) +/** + * @brief ��������������������� + * + * @param srcImg ������ + * + * @return ������������������������ + */ ++ (UIImage *)fixOrientation:(UIImage *)srcImg { + if (srcImg.imageOrientation == UIImageOrientationUp) return srcImg; + CGAffineTransform transform = CGAffineTransformIdentity; + switch (srcImg.imageOrientation) { + case UIImageOrientationDown: + case UIImageOrientationDownMirrored: + transform = CGAffineTransformTranslate(transform, srcImg.size.width, srcImg.size.height); + transform = CGAffineTransformRotate(transform, M_PI); + break; + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + transform = CGAffineTransformTranslate(transform, srcImg.size.width, 0); + transform = CGAffineTransformRotate(transform, M_PI_2); + break; + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + transform = CGAffineTransformTranslate(transform, 0, srcImg.size.height); + transform = CGAffineTransformRotate(transform, -M_PI_2); + break; + case UIImageOrientationUp: + case UIImageOrientationUpMirrored: + break; + } + switch (srcImg.imageOrientation) { + case UIImageOrientationUpMirrored: + case UIImageOrientationDownMirrored: + transform = CGAffineTransformTranslate(transform, srcImg.size.width, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + case UIImageOrientationLeftMirrored: + case UIImageOrientationRightMirrored: + transform = CGAffineTransformTranslate(transform, srcImg.size.height, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + case UIImageOrientationUp: + case UIImageOrientationDown: + case UIImageOrientationLeft: + case UIImageOrientationRight: + break; + } + CGContextRef ctx = CGBitmapContextCreate(NULL, srcImg.size.width, srcImg.size.height, + CGImageGetBitsPerComponent(srcImg.CGImage), 0, + CGImageGetColorSpace(srcImg.CGImage), + CGImageGetBitmapInfo(srcImg.CGImage)); + CGContextConcatCTM(ctx, transform); + switch (srcImg.imageOrientation) { + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + CGContextDrawImage(ctx, CGRectMake(0,0,srcImg.size.height,srcImg.size.width), srcImg.CGImage); + break; + default: + CGContextDrawImage(ctx, CGRectMake(0,0,srcImg.size.width,srcImg.size.height), srcImg.CGImage); + break; + } + CGImageRef cgimg = CGBitmapContextCreateImage(ctx); + UIImage *img = [UIImage imageWithCGImage:cgimg]; + CGContextRelease(ctx); + CGImageRelease(cgimg); + return img; +} + +- (UIImage *)flip:(BOOL)isHorizontal { + CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height); + UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0); + + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGContextClipToRect(ctx, rect); + if (isHorizontal) { + CGContextRotateCTM(ctx, M_PI); + CGContextTranslateCTM(ctx, -rect.size.width, -rect.size.height); + } + CGContextDrawImage(ctx, rect, self.CGImage); + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return image; +} +/** + * @brief ������������ + * + * @return ������������������ + */ +- (UIImage *)flipVertical { + return [self flip:NO]; +} +/** + * @brief ������������ + * + * @return ������������������ + */ +- (UIImage *)flipHorizontal { + return [self flip:YES]; +} +/** + * @brief ������������ + * + * @param degrees ������ + * + * @return ��������������� + */ +- (UIImage *)imageRotatedByRadians:(CGFloat)radians +{ + return [self imageRotatedByDegrees:[UIImage radiansToDegrees:radians]]; +} +/** + * @brief ������������ + * + * @param degrees ��� + * + * @return ��������������� + */ +- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees +{ + // calculate the size of the rotated view's containing box for our drawing space + UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)]; + CGAffineTransform t = CGAffineTransformMakeRotation([UIImage degreesToRadians:degrees]); + rotatedViewBox.transform = t; + CGSize rotatedSize = rotatedViewBox.frame.size; + + // Create the bitmap context + UIGraphicsBeginImageContext(rotatedSize); + CGContextRef bitmap = UIGraphicsGetCurrentContext(); + + // Move the origin to the middle of the image so we will rotate and scale around the center. + CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2); + + // // Rotate the image context + CGContextRotateCTM(bitmap, [UIImage degreesToRadians:degrees]); + + // Now, draw the rotated/scaled image into the context + CGContextScaleCTM(bitmap, 1.0, -1.0); + CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]); + + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return newImage; + +} + +/** + * @brief ��������������� + * + * @param degrees ������ + * + * @return ������ + */ ++(CGFloat)degreesToRadians:(CGFloat)degrees +{ + return degrees * M_PI / 180; +} +/** + * @brief ��������������� + * + * @param radians ������ + * + * @return ������ + */ ++(CGFloat)radiansToDegrees:(CGFloat)radians +{ + return radians * 180/M_PI; +} +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+PDF.h b/camerademo/camerademo/demo/UIImage/UIImage+PDF.h new file mode 100755 index 0000000..27db567 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+PDF.h @@ -0,0 +1,13 @@ +// +// UIImage+PDF.h +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/5/22. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import <UIKit/UIKit.h> + +@interface UIImage (PDF) + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+PDF.m b/camerademo/camerademo/demo/UIImage/UIImage+PDF.m new file mode 100755 index 0000000..e6ca42f --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+PDF.m @@ -0,0 +1,13 @@ +// +// UIImage+PDF.m +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/5/22. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import "UIImage+PDF.h" + +@implementation UIImage (PDF) + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.h b/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.h new file mode 100755 index 0000000..8d4d1f2 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.h @@ -0,0 +1,29 @@ +// +// UIImage+RemoteSize.h +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/1/27. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import <UIKit/UIKit.h> + +typedef void (^UIImageSizeRequestCompleted) (NSURL* imgURL, CGSize size); + +@interface UIImage (RemoteSize) +/** + * @brief ��������������������������� + * + * @param imgURL ������url + * @param completion ������������ + */ ++ (void)requestSizeNoHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion; +/** + * @brief ���header������������������������������ (���������������������) + * + * @param imgURL ������url + * @param completion ������������ + */ +//+ (void)requestSizeWithHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion; + +@end \ No newline at end of file diff --git a/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.m b/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.m new file mode 100755 index 0000000..82d4085 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.m @@ -0,0 +1,270 @@ +// +// UIImage+RemoteSize.m +// iOS-Categories (https://github.com/shaojiankui/iOS-Categories) +// +// Created by Jakey on 15/1/27. +// Copyright (c) 2015��� www.skyfox.org. All rights reserved. +// + +#import "UIImage+RemoteSize.h" + +#import <objc/runtime.h> + +static char *kSizeRequestDataKey = "NSURL.sizeRequestData"; +static char *kSizeRequestTypeKey = "NSURL.sizeRequestType"; +static char *kSizeRequestCompletionKey = "NSURL.sizeRequestCompletion"; + +typedef uint32_t dword; + +@interface NSURL (RemoteSize) +@property (nonatomic, strong) NSMutableData* sizeRequestData; +@property (nonatomic, strong) NSString* sizeRequestType; +@property (nonatomic, copy) UIImageSizeRequestCompleted sizeRequestCompletion; +@end + +@implementation NSURL (RemoteSize) + +- (void)setSizeRequestCompletion: (UIImageSizeRequestCompleted) block { + objc_setAssociatedObject(self, &kSizeRequestCompletionKey, block, OBJC_ASSOCIATION_COPY); +} + +- (UIImageSizeRequestCompleted)sizeRequestCompletion { + return objc_getAssociatedObject(self, &kSizeRequestCompletionKey); +} + +- (void)setSizeRequestData:(NSMutableData *)sizeRequestData { + objc_setAssociatedObject(self, &kSizeRequestDataKey, sizeRequestData, OBJC_ASSOCIATION_RETAIN); +} + +- (NSMutableData*)sizeRequestData { + return objc_getAssociatedObject(self, &kSizeRequestDataKey); +} + +- (void)setSizeRequestType:(NSString *)sizeRequestType { + objc_setAssociatedObject(self, &kSizeRequestTypeKey, sizeRequestType, OBJC_ASSOCIATION_RETAIN); +} + +- (NSString*)sizeRequestType { + return objc_getAssociatedObject(self, &kSizeRequestTypeKey); +} + +#pragma mark - NSURLConnectionDelegate +- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response { + [self.sizeRequestData setLength: 0]; //Redirected => reset data +} + +- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData *)data { + NSMutableData* receivedData = self.sizeRequestData; + + if( !receivedData ) { + receivedData = [NSMutableData data]; + self.sizeRequestData = receivedData; + } + + [receivedData appendData: data]; + + //Parse metadata + const unsigned char* cString = [receivedData bytes]; + const NSInteger length = [receivedData length]; + + const char pngSignature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + const char bmpSignature[2] = {66, 77}; + const char gifSignature[2] = {71, 73}; + const char jpgSignature[2] = {255, 216}; + + if(!self.sizeRequestType ) { + if( memcmp(pngSignature, cString, 8) == 0 ) { + self.sizeRequestType = @"PNG"; + } + else if( memcmp(bmpSignature, cString, 2) == 0 ) { + self.sizeRequestType = @"BMP"; + } + else if( memcmp(jpgSignature, cString, 2) == 0 ) { + self.sizeRequestType = @"JPG"; + } + else if( memcmp(gifSignature, cString, 2) == 0 ) { + self.sizeRequestType = @"GIF"; + } + } + + if( [self.sizeRequestType isEqualToString: @"PNG"] ) { + char type[5]; + int offset = 8; + + dword chunkSize = 0; + int chunkSizeSize = sizeof(chunkSize); + + if( offset+chunkSizeSize > length ) + return; + + memcpy(&chunkSize, cString+offset, chunkSizeSize); + chunkSize = OSSwapInt32(chunkSize); + offset += chunkSizeSize; + + if( offset + chunkSize > length ) + return; + + memcpy(&type, cString+offset, 4); type[4]='\0'; + offset += 4; + + if( strcmp(type, "IHDR") == 0 ) { //Should always be first + dword width = 0, height = 0; + memcpy(&width, cString+offset, 4); + offset += 4; + width = OSSwapInt32(width); + + memcpy(&height, cString+offset, 4); + offset += 4; + height = OSSwapInt32(height); + + if( self.sizeRequestCompletion ) { + self.sizeRequestCompletion(self, CGSizeMake(width, height)); + } + + self.sizeRequestCompletion = nil; + + [connection cancel]; + } + } + else if( [self.sizeRequestType isEqualToString: @"BMP"] ) { + int offset = 18; + dword width = 0, height = 0; + memcpy(&width, cString+offset, 4); + offset += 4; + + memcpy(&height, cString+offset, 4); + offset += 4; + + if( self.sizeRequestCompletion ) { + self.sizeRequestCompletion(self, CGSizeMake(width, height)); + } + + self.sizeRequestCompletion = nil; + + [connection cancel]; + } + else if( [self.sizeRequestType isEqualToString: @"JPG"] ) { + int offset = 4; + dword block_length = cString[offset]*256 + cString[offset+1]; + + while (offset<length) { + offset += block_length; + + if( offset >= length ) + break; + if( cString[offset] != 0xFF ) + break; + if( cString[offset+1] == 0xC0 || + cString[offset+1] == 0xC1 || + cString[offset+1] == 0xC2 || + cString[offset+1] == 0xC3 || + cString[offset+1] == 0xC5 || + cString[offset+1] == 0xC6 || + cString[offset+1] == 0xC7 || + cString[offset+1] == 0xC9 || + cString[offset+1] == 0xCA || + cString[offset+1] == 0xCB || + cString[offset+1] == 0xCD || + cString[offset+1] == 0xCE || + cString[offset+1] == 0xCF ) { + + dword width = 0, height = 0; + + height = cString[offset+5]*256 + cString[offset+6]; + width = cString[offset+7]*256 + cString[offset+8]; + + if( self.sizeRequestCompletion ) { + self.sizeRequestCompletion(self, CGSizeMake(width, height)); + } + + self.sizeRequestCompletion = nil; + + [connection cancel]; + + } + else { + offset += 2; + block_length = cString[offset]*256 + cString[offset+1]; + } + + } + } + else if( [self.sizeRequestType isEqualToString: @"GIF"] ) { + int offset = 6; + dword width = 0, height = 0; + memcpy(&width, cString+offset, 2); + offset += 2; + + memcpy(&height, cString+offset, 2); + offset += 2; + + if( self.sizeRequestCompletion ) { + self.sizeRequestCompletion(self, CGSizeMake(width, height)); + } + + self.sizeRequestCompletion = nil; + + [connection cancel]; + } +} + +-(void)connection:(NSURLConnection*)connection didFailWithError:(NSError *)error { + if( self.sizeRequestCompletion ) + self.sizeRequestCompletion(self, CGSizeZero); +} + +-(NSCachedURLResponse*)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { + return cachedResponse; +} + +- (void)connectionDidFinishLoading: (NSURLConnection *)connection { + // Basically, we failed to obtain the image size using metadata and the + // entire image was downloaded... + + if(!self.sizeRequestData.length) { + self.sizeRequestData = nil; + } + else { + //Try parse to UIImage + UIImage* image = [UIImage imageWithData: self.sizeRequestData]; + + if( self.sizeRequestCompletion && image) { + self.sizeRequestCompletion(self, [image size]); + return; + } + } + + self.sizeRequestCompletion(self, CGSizeZero); +} + +@end + +@implementation UIImage (RemoteSize) + ++ (void)requestSizeNoHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion{ + + if([imgURL isFileURL] ) { + //Load from file stream + } + else { + imgURL.sizeRequestCompletion = completion; + + NSURLRequest* request = [NSURLRequest requestWithURL:imgURL]; + NSURLConnection* conn = [NSURLConnection connectionWithRequest: request delegate: imgURL]; + [conn scheduleInRunLoop: [NSRunLoop mainRunLoop] forMode: NSDefaultRunLoopMode]; + [conn start]; + } +} + + ++ (void)requestSizeWithHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion{ +// NSURLRequest* request = [NSURLRequest requestWithURL:imgURL]; +// +// [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *resp, NSData *d, NSError *e) { +// NSLog(@"respone%@", [(NSHTTPURLResponse*)resp allHeaderFields]); +// +// +// }]; +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Resize.h b/camerademo/camerademo/demo/UIImage/UIImage+Resize.h new file mode 100755 index 0000000..64610b1 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Resize.h @@ -0,0 +1,21 @@ +// UIImage+Resize.h +// Created by Trevor Harmon on 8/5/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +// Extends the UIImage class to support resizing/cropping +#import <UIKit/UIKit.h> + +@interface UIImage (Resize) + +- (UIImage *)croppedImage:(CGRect)bounds; +- (UIImage *)thumbnailImage:(NSInteger)thumbnailSize + transparentBorder:(NSUInteger)borderSize + cornerRadius:(NSUInteger)cornerRadius + interpolationQuality:(CGInterpolationQuality)quality; +- (UIImage *)resizedImage:(CGSize)newSize + interpolationQuality:(CGInterpolationQuality)quality; +- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode + bounds:(CGSize)bounds + interpolationQuality:(CGInterpolationQuality)quality; +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Resize.m b/camerademo/camerademo/demo/UIImage/UIImage+Resize.m new file mode 100755 index 0000000..affbf31 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Resize.m @@ -0,0 +1,200 @@ +// UIImage+Resize.m +// Created by Trevor Harmon on 8/5/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +#import "UIImage+Resize.h" +#import "UIImage+RoundedCorner.h" +#import "UIImage+Alpha.h" + +// Private helper methods +@interface UIImage (ResizePrivateMethods) +- (UIImage *)resizedImage:(CGSize)newSize + transform:(CGAffineTransform)transform + drawTransposed:(BOOL)transpose + interpolationQuality:(CGInterpolationQuality)quality; +- (CGAffineTransform)transformForOrientation:(CGSize)newSize; +@end + +@implementation UIImage (Resize) + +// Returns a copy of this image that is cropped to the given bounds. +// The bounds will be adjusted using CGRectIntegral. +// This method ignores the image's imageOrientation setting. +- (UIImage *)croppedImage:(CGRect)bounds { + CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds); + UIImage *croppedImage = [UIImage imageWithCGImage:imageRef]; + CGImageRelease(imageRef); + return croppedImage; +} + +// Returns a copy of this image that is squared to the thumbnail size. +// If transparentBorder is non-zero, a transparent border of the given size will be added around the edges of the thumbnail. (Adding a transparent border of at least one pixel in size has the side-effect of antialiasing the edges of the image when rotating it using Core Animation.) +- (UIImage *)thumbnailImage:(NSInteger)thumbnailSize + transparentBorder:(NSUInteger)borderSize + cornerRadius:(NSUInteger)cornerRadius + interpolationQuality:(CGInterpolationQuality)quality { + UIImage *resizedImage = [self resizedImageWithContentMode:UIViewContentModeScaleAspectFill + bounds:CGSizeMake(thumbnailSize, thumbnailSize) + interpolationQuality:quality]; + + // Crop out any part of the image that's larger than the thumbnail size + // The cropped rect must be centered on the resized image + // Round the origin points so that the size isn't altered when CGRectIntegral is later invoked + CGRect cropRect = CGRectMake(round((resizedImage.size.width - thumbnailSize) / 2), + round((resizedImage.size.height - thumbnailSize) / 2), + thumbnailSize, + thumbnailSize); + UIImage *croppedImage = [resizedImage croppedImage:cropRect]; + + UIImage *transparentBorderImage = borderSize ? [croppedImage transparentBorderImage:borderSize] : croppedImage; + + return [transparentBorderImage roundedCornerImage:cornerRadius borderSize:borderSize]; +} + +// Returns a rescaled copy of the image, taking into account its orientation +// The image will be scaled disproportionately if necessary to fit the bounds specified by the parameter +- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality { + BOOL drawTransposed; + + switch (self.imageOrientation) { + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + drawTransposed = YES; + break; + + default: + drawTransposed = NO; + } + + return [self resizedImage:newSize + transform:[self transformForOrientation:newSize] + drawTransposed:drawTransposed + interpolationQuality:quality]; +} + +// Resizes the image according to the given content mode, taking into account the image's orientation +- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode + bounds:(CGSize)bounds + interpolationQuality:(CGInterpolationQuality)quality { + CGFloat horizontalRatio = bounds.width / self.size.width; + CGFloat verticalRatio = bounds.height / self.size.height; + CGFloat ratio; + + switch (contentMode) { + case UIViewContentModeScaleAspectFill: + ratio = MAX(horizontalRatio, verticalRatio); + break; + + case UIViewContentModeScaleAspectFit: + ratio = MIN(horizontalRatio, verticalRatio); + break; + + default: + [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %@", @(contentMode)]; + } + + CGSize newSize = CGSizeMake(round(self.size.width * ratio), round(self.size.height * ratio)); + + return [self resizedImage:newSize interpolationQuality:quality]; +} + +#pragma mark - +#pragma mark Private helper methods + +// Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size +// The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation +// If the new size is not integral, it will be rounded up +- (UIImage *)resizedImage:(CGSize)newSize + transform:(CGAffineTransform)transform + drawTransposed:(BOOL)transpose + interpolationQuality:(CGInterpolationQuality)quality { + CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height)); + CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width); + CGImageRef imageRef = self.CGImage; + + // Build a context that's the same dimensions as the new size + uint32_t bitmapInfo = CGImageGetBitmapInfo(imageRef); + if((bitmapInfo == kCGImageAlphaLast) || (bitmapInfo == kCGImageAlphaNone)) + bitmapInfo = kCGImageAlphaNoneSkipLast; + + + + CGContextRef bitmap = CGBitmapContextCreate(NULL, + newRect.size.width, + newRect.size.height, + CGImageGetBitsPerComponent(imageRef), + 0, + CGImageGetColorSpace(imageRef), + bitmapInfo); + + // Rotate and/or flip the image if required by its orientation + CGContextConcatCTM(bitmap, transform); + + // Set the quality level to use when rescaling + CGContextSetInterpolationQuality(bitmap, quality); + + // Draw into the context; this scales the image + CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef); + + // Get the resized image from the context and a UIImage + CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap); + UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; + + // Clean up + CGContextRelease(bitmap); + CGImageRelease(newImageRef); + + return newImage; +} + +// Returns an affine transform that takes into account the image orientation when drawing a scaled image +- (CGAffineTransform)transformForOrientation:(CGSize)newSize { + CGAffineTransform transform = CGAffineTransformIdentity; + + switch (self.imageOrientation) { + case UIImageOrientationDown: // EXIF = 3 + case UIImageOrientationDownMirrored: // EXIF = 4 + transform = CGAffineTransformTranslate(transform, newSize.width, newSize.height); + transform = CGAffineTransformRotate(transform, M_PI); + break; + + case UIImageOrientationLeft: // EXIF = 6 + case UIImageOrientationLeftMirrored: // EXIF = 5 + transform = CGAffineTransformTranslate(transform, newSize.width, 0); + transform = CGAffineTransformRotate(transform, M_PI_2); + break; + + case UIImageOrientationRight: // EXIF = 8 + case UIImageOrientationRightMirrored: // EXIF = 7 + transform = CGAffineTransformTranslate(transform, 0, newSize.height); + transform = CGAffineTransformRotate(transform, -M_PI_2); + break; + + default: + break; + } + + switch (self.imageOrientation) { + case UIImageOrientationUpMirrored: // EXIF = 2 + case UIImageOrientationDownMirrored: // EXIF = 4 + transform = CGAffineTransformTranslate(transform, newSize.width, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + + case UIImageOrientationLeftMirrored: // EXIF = 5 + case UIImageOrientationRightMirrored: // EXIF = 7 + transform = CGAffineTransformTranslate(transform, newSize.height, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + + default: + break; + } + + return transform; +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.h b/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.h new file mode 100755 index 0000000..f9d9803 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.h @@ -0,0 +1,10 @@ +// UIImage+RoundedCorner.h +// Created by Trevor Harmon on 9/20/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +// Extends the UIImage class to support making rounded corners +#import <UIKit/UIKit.h> +@interface UIImage (RoundedCorner) +- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize; +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.m b/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.m new file mode 100755 index 0000000..f917f2c --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.m @@ -0,0 +1,79 @@ +// UIImage+RoundedCorner.m +// Created by Trevor Harmon on 9/20/09. +// Free for personal or commercial use, with or without modification. +// No warranty is expressed or implied. + +#import "UIImage+RoundedCorner.h" +#import "UIImage+Alpha.h" + +// Private helper methods +@interface UIImage (RoundedCornerPrivateMethods) +- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight; +@end + +@implementation UIImage (RoundedCorner) + +// Creates a copy of this image with rounded corners +// If borderSize is non-zero, a transparent border of the given size will also be added +// Original author: Bj��rn S��llarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/ +- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize { + // If the image does not have an alpha layer, add one + UIImage *image = [self imageWithAlpha]; + + // Build a context that's the same dimensions as the new size + CGContextRef context = CGBitmapContextCreate(NULL, + image.size.width, + image.size.height, + CGImageGetBitsPerComponent(image.CGImage), + 0, + CGImageGetColorSpace(image.CGImage), + CGImageGetBitmapInfo(image.CGImage)); + + // Create a clipping path with rounded corners + CGContextBeginPath(context); + [self addRoundedRectToPath:CGRectMake(borderSize, borderSize, image.size.width - borderSize * 2, image.size.height - borderSize * 2) + context:context + ovalWidth:cornerSize + ovalHeight:cornerSize]; + CGContextClosePath(context); + CGContextClip(context); + + // Draw the image to the context; the clipping path will make anything outside the rounded rect transparent + CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage); + + // Create a CGImage from the context + CGImageRef clippedImage = CGBitmapContextCreateImage(context); + CGContextRelease(context); + + // Create a UIImage from the CGImage + UIImage *roundedImage = [UIImage imageWithCGImage:clippedImage]; + CGImageRelease(clippedImage); + + return roundedImage; +} + +#pragma mark - +#pragma mark Private helper methods + +// Adds a rectangular path to the given context and rounds its corners by the given extents +// Original author: Bj��rn S��llarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/ +- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight { + if (ovalWidth == 0 || ovalHeight == 0) { + CGContextAddRect(context, rect); + return; + } + CGContextSaveGState(context); + CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect)); + CGContextScaleCTM(context, ovalWidth, ovalHeight); + CGFloat fw = CGRectGetWidth(rect) / ovalWidth; + CGFloat fh = CGRectGetHeight(rect) / ovalHeight; + CGContextMoveToPoint(context, fw, fh/2); + CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); + CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); + CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); + CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); + CGContextClosePath(context); + CGContextRestoreGState(context); +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Vector.h b/camerademo/camerademo/demo/UIImage/UIImage+Vector.h new file mode 100755 index 0000000..9f93d41 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Vector.h @@ -0,0 +1,65 @@ +// +// UIImage+Vector.h +// UIImage+Vector +// +// Created by David Keegan on 8/7/13. +// Copyright (c) 2013 David Keegan All rights reserved. +// + + +/** + * @Author(������) David Keegan + * + * @URL(������) https://github.com/kgn/UIImage-Vector + * + * @Version(������) 20150620 + * + * @Requirements(������������) + * + * @Description(������) UIImage category for dealing with vector formats like PDF and icon fonts. + * @Usage(������) .. + */ + +#import <UIKit/UIKit.h> + +@interface UIImage(Vector) + +/** + Create a UIImage from an icon font. + @param font The icon font. + @param iconNamed The name of the icon in the font. + @param tintColor The tint color to use for the icon. Defaults to black. + @param clipToBounds If YES the image will be clipped to the pixel bounds of the icon. + @param fontSize The font size to draw the icon at. + @return The resulting image. + */ ++ (UIImage *)iconWithFont:(UIFont *)font named:(NSString *)iconNamed + withTintColor:(UIColor *)tintColor clipToBounds:(BOOL)clipToBounds forSize:(CGFloat)fontSize; + +/** + Create a UIImage from a PDF icon. + @param pdfNamed The name of the PDF file in the application's resources directory. + @param height The height of the resulting image, the width will be based on the aspect ratio of the PDF. + @return The resulting image. + */ ++ (UIImage *)imageWithPDFNamed:(NSString *)pdfNamed forHeight:(CGFloat)height; + +/** + Create a UIImage from a PDF icon. + @param pdfNamed The name of the PDF file in the application's resources directory. + @param tintColor The tint color to use for the icon. If nil no tint color will be used. + @param height The height of the resulting image, the width will be based on the aspect ratio of the PDF. + @return The resulting image. + */ ++ (UIImage *)imageWithPDFNamed:(NSString *)pdfNamed withTintColor:(UIColor *)tintColor forHeight:(CGFloat)height; + +/** + Create a UIImage from a PDF icon. + @param pdfFile The path of the PDF file. + @param tintColor The tint color to use for the icon. If nil no tint color will be used. + @param maxSize The maximum size the resulting image can be. The image will maintain it's aspect ratio and may not encumpas the full size. + @return The resulting image. + */ ++ (UIImage *)imageWithPDFFile:(NSString *)pdfFile withTintColor:(UIColor *)tintColor forSize:(CGSize)size; + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Vector.m b/camerademo/camerademo/demo/UIImage/UIImage+Vector.m new file mode 100755 index 0000000..e2d4af0 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+Vector.m @@ -0,0 +1,140 @@ +// +// UIImage+Vector.m +// UIImage+Vector +// +// Created by David Keegan on 8/7/13. +// Copyright (c) 2013 David Keegan All rights reserved. +// + +#import "UIImage+Vector.h" +#import <CoreText/CoreText.h> + +@implementation UIImage(Vector) + ++ (NSCache *)cache{ + static NSCache *cache = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + cache = [[NSCache alloc] init]; + }); + return cache; +} + ++ (UIImage *)iconWithFont:(UIFont *)font named:(NSString *)iconNamed withTintColor:(UIColor *)tintColor clipToBounds:(BOOL)clipToBounds forSize:(CGFloat)fontSize{ + NSString *identifier = [NSString stringWithFormat:@"%@%@%@%@%d%f", NSStringFromSelector(_cmd), font.fontName, tintColor, iconNamed, clipToBounds, fontSize]; + UIImage *image = [[self cache] objectForKey:identifier]; + if(image == nil){ + NSMutableAttributedString *ligature = [[NSMutableAttributedString alloc] initWithString:iconNamed]; + [ligature setAttributes:@{(NSString *)kCTLigatureAttributeName: @(2), + (NSString *)kCTFontAttributeName: font} + range:NSMakeRange(0, [ligature length])]; + + CGSize imageSize = [ligature size]; + imageSize.width = ceil(imageSize.width); + imageSize.height = ceil(imageSize.height); + if(!CGSizeEqualToSize(CGSizeZero, imageSize)){ + UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0); + [ligature drawAtPoint:CGPointZero]; + image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + if(tintColor){ + UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -imageSize.height); + CGContextClipToMask(context, (CGRect){.size=imageSize}, [image CGImage]); + [tintColor setFill]; + CGContextFillRect(context, (CGRect){.size=imageSize}); + image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wundeclared-selector" + if(clipToBounds && [image respondsToSelector:@selector(imageClippedToPixelBounds)]){ + image = [image performSelector:@selector(imageClippedToPixelBounds)]; + } + #pragma clang diagnostic pop + + [[self cache] setObject:image forKey:identifier]; + } + } + return image; +} + ++ (UIImage *)imageWithPDFNamed:(NSString *)pdfNamed forHeight:(CGFloat)height{ + return [self imageWithPDFNamed:pdfNamed withTintColor:nil forHeight:height]; +} + ++ (UIImage *)imageWithPDFNamed:(NSString *)pdfNamed withTintColor:(UIColor *)tintColor forHeight:(CGFloat)height{ + NSString *pdfFile = [[NSBundle mainBundle] pathForResource:pdfNamed ofType:@"pdf"]; + return [self imageWithPDFFile:pdfFile withTintColor:tintColor forSize:CGSizeMake(MAXFLOAT, height)]; +} + ++ (UIImage *)imageWithPDFFile:(NSString *)pdfFile withTintColor:(UIColor *)tintColor forSize:(CGSize)size{ + if(!pdfFile || CGSizeEqualToSize(size, CGSizeZero)){ + return nil; + } + + NSString *identifier = [NSString stringWithFormat:@"%@%@%@%@", NSStringFromSelector(_cmd), pdfFile, tintColor, NSStringFromCGSize(size)]; + UIImage *image = [[self cache] objectForKey:identifier]; + if(image){ + return image; + } + + NSURL *url = [NSURL fileURLWithPath:pdfFile]; + CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)url); + if(!pdf){ + return nil; + } + + CGPDFPageRef page1 = CGPDFDocumentGetPage(pdf, 1); + CGRect mediaRect = CGPDFPageGetBoxRect(page1, kCGPDFCropBox); + + CGSize imageSize = mediaRect.size; + if(imageSize.height < size.height && size.height != MAXFLOAT){ + imageSize.width = round(size.height/imageSize.height*imageSize.width); + imageSize.height = size.height; + } + if(imageSize.width < size.width && size.width != MAXFLOAT){ + imageSize.height = round(size.width/imageSize.width*imageSize.height); + imageSize.width = size.width; + } + + if(imageSize.height > size.height){ + imageSize.width = round(size.height/imageSize.height*imageSize.width); + imageSize.height = size.height; + } + if(imageSize.width > size.width){ + imageSize.height = round(size.width/imageSize.width*imageSize.height); + imageSize.width = size.width; + } + + UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0); + CGFloat scale = MIN(imageSize.width/mediaRect.size.width, imageSize.height/mediaRect.size.height); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -imageSize.height); + CGContextScaleCTM(context, scale, scale); + CGContextDrawPDFPage(context, page1); + CGPDFDocumentRelease(pdf); + image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + if(tintColor){ + UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -imageSize.height); + CGContextClipToMask(context, (CGRect){.size=imageSize}, [image CGImage]); + [tintColor setFill]; + CGContextFillRect(context, (CGRect){.size=imageSize}); + image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + + return image; +} + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.h b/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.h new file mode 100755 index 0000000..324d814 --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.h @@ -0,0 +1,32 @@ +#import <UIKit/UIKit.h> + +/** + UIImage (animatedGIF) + + This category adds class methods to `UIImage` to create an animated `UIImage` from an animated GIF. +*/ +@interface UIImage (animatedGIF) + +/* + UIImage *animation = [UIImage animatedImageWithAnimatedGIFData:theData]; + + I interpret `theData` as a GIF. I create an animated `UIImage` using the source images in the GIF. + + The GIF stores a separate duration for each frame, in units of centiseconds (hundredths of a second). However, a `UIImage` only has a single, total `duration` property, which is a floating-point number. + + To handle this mismatch, I add each source image (from the GIF) to `animation` a varying number of times to match the ratios between the frame durations in the GIF. + + For example, suppose the GIF contains three frames. Frame 0 has duration 3. Frame 1 has duration 9. Frame 2 has duration 15. I divide each duration by the greatest common denominator of all the durations, which is 3, and add each frame the resulting number of times. Thus `animation` will contain frame 0 3/3 = 1 time, then frame 1 9/3 = 3 times, then frame 2 15/3 = 5 times. I set `animation.duration` to (3+9+15)/100 = 0.27 seconds. +*/ ++ (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)theData; + +/* + UIImage *image = [UIImage animatedImageWithAnimatedGIFURL:theURL]; + + I interpret the contents of `theURL` as a GIF. I create an animated `UIImage` using the source images in the GIF. + + I operate exactly like `+[UIImage animatedImageWithAnimatedGIFData:]`, except that I read the data from `theURL`. If `theURL` is not a `file:` URL, you probably want to call me on a background thread or GCD queue to avoid blocking the main thread. +*/ ++ (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)theURL; + +@end diff --git a/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.m b/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.m new file mode 100755 index 0000000..f6bdf5f --- /dev/null +++ b/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.m @@ -0,0 +1,114 @@ +#import "UIImage+animatedGIF.h" +#import <ImageIO/ImageIO.h> + +#if __has_feature(objc_arc) +#define toCF (__bridge CFTypeRef) +#define fromCF (__bridge id) +#else +#define toCF (CFTypeRef) +#define fromCF (id) +#endif + +@implementation UIImage (animatedGIF) + +static int delayCentisecondsForImageAtIndex(CGImageSourceRef const source, size_t const i) { + int delayCentiseconds = 1; + CFDictionaryRef const properties = CGImageSourceCopyPropertiesAtIndex(source, i, NULL); + if (properties) { + CFDictionaryRef const gifProperties = CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); + CFRelease(properties); + if (gifProperties) { + CFNumberRef const number = CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime); + // Even though the GIF stores the delay as an integer number of centiseconds, ImageIO ���helpfully��� converts that to seconds for us. + delayCentiseconds = (int)lrint([fromCF number doubleValue] * 100); + } + } + return delayCentiseconds; +} + +static void createImagesAndDelays(CGImageSourceRef source, size_t count, CGImageRef imagesOut[count], int delayCentisecondsOut[count]) { + for (size_t i = 0; i < count; ++i) { + imagesOut[i] = CGImageSourceCreateImageAtIndex(source, i, NULL); + delayCentisecondsOut[i] = delayCentisecondsForImageAtIndex(source, i); + } +} + +static int sum(size_t const count, int const *const values) { + int theSum = 0; + for (size_t i = 0; i < count; ++i) { + theSum += values[i]; + } + return theSum; +} + +static int pairGCD(int a, int b) { + if (a < b) + return pairGCD(b, a); + while (true) { + int const r = a % b; + if (r == 0) + return b; + a = b; + b = r; + } +} + +static int vectorGCD(size_t const count, int const *const values) { + int gcd = values[0]; + for (size_t i = 1; i < count; ++i) { + // Note that after I process the first few elements of the vector, `gcd` will probably be smaller than any remaining element. By passing the smaller value as the second argument to `pairGCD`, I avoid making it swap the arguments. + gcd = pairGCD(values[i], gcd); + } + return gcd; +} + +static NSArray *frameArray(size_t const count, CGImageRef const images[count], int const delayCentiseconds[count], int const totalDurationCentiseconds) { + int const gcd = vectorGCD(count, delayCentiseconds); + size_t const frameCount = totalDurationCentiseconds / gcd; + UIImage *frames[frameCount]; + for (size_t i = 0, f = 0; i < count; ++i) { + UIImage *const frame = [UIImage imageWithCGImage:images[i]]; + for (size_t j = delayCentiseconds[i] / gcd; j > 0; --j) { + frames[f++] = frame; + } + } + return [NSArray arrayWithObjects:frames count:frameCount]; +} + +static void releaseImages(size_t const count, CGImageRef const images[count]) { + for (size_t i = 0; i < count; ++i) { + CGImageRelease(images[i]); + } +} + +static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) { + size_t const count = CGImageSourceGetCount(source); + CGImageRef images[count]; + int delayCentiseconds[count]; // in centiseconds + createImagesAndDelays(source, count, images, delayCentiseconds); + int const totalDurationCentiseconds = sum(count, delayCentiseconds); + NSArray *const frames = frameArray(count, images, delayCentiseconds, totalDurationCentiseconds); + UIImage *const animation = [UIImage animatedImageWithImages:frames duration:(NSTimeInterval)totalDurationCentiseconds / 100.0]; + releaseImages(count, images); + return animation; +} + +static UIImage *animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceRef source) { + if (source) { + UIImage *const image = animatedImageWithAnimatedGIFImageSource(source); + CFRelease(source); + return image; + } else { + return nil; + } +} + ++ (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)data { + return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF data, NULL)); +} + ++ (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)url { + return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL(toCF url, NULL)); +} + +@end diff --git a/camerademo/camerademo/main.m b/camerademo/camerademo/main.m new file mode 100644 index 0000000..27a8a02 --- /dev/null +++ b/camerademo/camerademo/main.m @@ -0,0 +1,16 @@ +// +// main.m +// camerademo +// +// Created by WindShan on 2017/2/21. +// Copyright �� 2017��� WindShan. All rights reserved. +// + +#import <UIKit/UIKit.h> +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/test/SDWebImage/MKAnnotationView+WebCache.h b/ios_share/SDWebImage/MKAnnotationView+WebCache.h similarity index 100% rename from test/SDWebImage/MKAnnotationView+WebCache.h rename to ios_share/SDWebImage/MKAnnotationView+WebCache.h diff --git a/test/SDWebImage/MKAnnotationView+WebCache.m b/ios_share/SDWebImage/MKAnnotationView+WebCache.m similarity index 100% rename from test/SDWebImage/MKAnnotationView+WebCache.m rename to ios_share/SDWebImage/MKAnnotationView+WebCache.m diff --git a/test/SDWebImage/NSData+ImageContentType.h b/ios_share/SDWebImage/NSData+ImageContentType.h similarity index 100% rename from test/SDWebImage/NSData+ImageContentType.h rename to ios_share/SDWebImage/NSData+ImageContentType.h diff --git a/test/SDWebImage/NSData+ImageContentType.m b/ios_share/SDWebImage/NSData+ImageContentType.m similarity index 100% rename from test/SDWebImage/NSData+ImageContentType.m rename to ios_share/SDWebImage/NSData+ImageContentType.m diff --git a/test/SDWebImage/SDImageCache.h b/ios_share/SDWebImage/SDImageCache.h similarity index 100% rename from test/SDWebImage/SDImageCache.h rename to ios_share/SDWebImage/SDImageCache.h diff --git a/test/SDWebImage/SDImageCache.m b/ios_share/SDWebImage/SDImageCache.m similarity index 100% rename from test/SDWebImage/SDImageCache.m rename to ios_share/SDWebImage/SDImageCache.m diff --git a/test/SDWebImage/SDWebImageCompat.h b/ios_share/SDWebImage/SDWebImageCompat.h similarity index 100% rename from test/SDWebImage/SDWebImageCompat.h rename to ios_share/SDWebImage/SDWebImageCompat.h diff --git a/test/SDWebImage/SDWebImageCompat.m b/ios_share/SDWebImage/SDWebImageCompat.m similarity index 100% rename from test/SDWebImage/SDWebImageCompat.m rename to ios_share/SDWebImage/SDWebImageCompat.m diff --git a/test/SDWebImage/SDWebImageDecoder.h b/ios_share/SDWebImage/SDWebImageDecoder.h similarity index 100% rename from test/SDWebImage/SDWebImageDecoder.h rename to ios_share/SDWebImage/SDWebImageDecoder.h diff --git a/test/SDWebImage/SDWebImageDecoder.m b/ios_share/SDWebImage/SDWebImageDecoder.m similarity index 100% rename from test/SDWebImage/SDWebImageDecoder.m rename to ios_share/SDWebImage/SDWebImageDecoder.m diff --git a/test/SDWebImage/SDWebImageDownloader.h b/ios_share/SDWebImage/SDWebImageDownloader.h similarity index 100% rename from test/SDWebImage/SDWebImageDownloader.h rename to ios_share/SDWebImage/SDWebImageDownloader.h diff --git a/test/SDWebImage/SDWebImageDownloader.m b/ios_share/SDWebImage/SDWebImageDownloader.m similarity index 100% rename from test/SDWebImage/SDWebImageDownloader.m rename to ios_share/SDWebImage/SDWebImageDownloader.m diff --git a/test/SDWebImage/SDWebImageDownloaderOperation.h b/ios_share/SDWebImage/SDWebImageDownloaderOperation.h similarity index 100% rename from test/SDWebImage/SDWebImageDownloaderOperation.h rename to ios_share/SDWebImage/SDWebImageDownloaderOperation.h diff --git a/test/SDWebImage/SDWebImageDownloaderOperation.m b/ios_share/SDWebImage/SDWebImageDownloaderOperation.m similarity index 100% rename from test/SDWebImage/SDWebImageDownloaderOperation.m rename to ios_share/SDWebImage/SDWebImageDownloaderOperation.m diff --git a/test/SDWebImage/SDWebImageManager.h b/ios_share/SDWebImage/SDWebImageManager.h similarity index 100% rename from test/SDWebImage/SDWebImageManager.h rename to ios_share/SDWebImage/SDWebImageManager.h diff --git a/test/SDWebImage/SDWebImageManager.m b/ios_share/SDWebImage/SDWebImageManager.m similarity index 100% rename from test/SDWebImage/SDWebImageManager.m rename to ios_share/SDWebImage/SDWebImageManager.m diff --git a/test/SDWebImage/SDWebImageOperation.h b/ios_share/SDWebImage/SDWebImageOperation.h similarity index 100% rename from test/SDWebImage/SDWebImageOperation.h rename to ios_share/SDWebImage/SDWebImageOperation.h diff --git a/test/SDWebImage/SDWebImagePrefetcher.h b/ios_share/SDWebImage/SDWebImagePrefetcher.h similarity index 100% rename from test/SDWebImage/SDWebImagePrefetcher.h rename to ios_share/SDWebImage/SDWebImagePrefetcher.h diff --git a/test/SDWebImage/SDWebImagePrefetcher.m b/ios_share/SDWebImage/SDWebImagePrefetcher.m similarity index 100% rename from test/SDWebImage/SDWebImagePrefetcher.m rename to ios_share/SDWebImage/SDWebImagePrefetcher.m diff --git a/test/SDWebImage/UIButton+WebCache.h b/ios_share/SDWebImage/UIButton+WebCache.h similarity index 100% rename from test/SDWebImage/UIButton+WebCache.h rename to ios_share/SDWebImage/UIButton+WebCache.h diff --git a/test/SDWebImage/UIButton+WebCache.m b/ios_share/SDWebImage/UIButton+WebCache.m similarity index 100% rename from test/SDWebImage/UIButton+WebCache.m rename to ios_share/SDWebImage/UIButton+WebCache.m diff --git a/test/SDWebImage/UIImage+GIF.h b/ios_share/SDWebImage/UIImage+GIF.h similarity index 100% rename from test/SDWebImage/UIImage+GIF.h rename to ios_share/SDWebImage/UIImage+GIF.h diff --git a/test/SDWebImage/UIImage+GIF.m b/ios_share/SDWebImage/UIImage+GIF.m similarity index 100% rename from test/SDWebImage/UIImage+GIF.m rename to ios_share/SDWebImage/UIImage+GIF.m diff --git a/test/SDWebImage/UIImage+MultiFormat.h b/ios_share/SDWebImage/UIImage+MultiFormat.h similarity index 100% rename from test/SDWebImage/UIImage+MultiFormat.h rename to ios_share/SDWebImage/UIImage+MultiFormat.h diff --git a/test/SDWebImage/UIImage+MultiFormat.m b/ios_share/SDWebImage/UIImage+MultiFormat.m similarity index 100% rename from test/SDWebImage/UIImage+MultiFormat.m rename to ios_share/SDWebImage/UIImage+MultiFormat.m diff --git a/test/SDWebImage/UIImage+WebP.h b/ios_share/SDWebImage/UIImage+WebP.h similarity index 100% rename from test/SDWebImage/UIImage+WebP.h rename to ios_share/SDWebImage/UIImage+WebP.h diff --git a/test/SDWebImage/UIImage+WebP.m b/ios_share/SDWebImage/UIImage+WebP.m similarity index 100% rename from test/SDWebImage/UIImage+WebP.m rename to ios_share/SDWebImage/UIImage+WebP.m diff --git a/test/SDWebImage/UIImageView+HighlightedWebCache.h b/ios_share/SDWebImage/UIImageView+HighlightedWebCache.h similarity index 100% rename from test/SDWebImage/UIImageView+HighlightedWebCache.h rename to ios_share/SDWebImage/UIImageView+HighlightedWebCache.h diff --git a/test/SDWebImage/UIImageView+HighlightedWebCache.m b/ios_share/SDWebImage/UIImageView+HighlightedWebCache.m similarity index 100% rename from test/SDWebImage/UIImageView+HighlightedWebCache.m rename to ios_share/SDWebImage/UIImageView+HighlightedWebCache.m diff --git a/test/SDWebImage/UIImageView+WebCache.h b/ios_share/SDWebImage/UIImageView+WebCache.h similarity index 100% rename from test/SDWebImage/UIImageView+WebCache.h rename to ios_share/SDWebImage/UIImageView+WebCache.h diff --git a/test/SDWebImage/UIImageView+WebCache.m b/ios_share/SDWebImage/UIImageView+WebCache.m similarity index 100% rename from test/SDWebImage/UIImageView+WebCache.m rename to ios_share/SDWebImage/UIImageView+WebCache.m diff --git a/test/SDWebImage/UIView+WebCacheOperation.h b/ios_share/SDWebImage/UIView+WebCacheOperation.h similarity index 100% rename from test/SDWebImage/UIView+WebCacheOperation.h rename to ios_share/SDWebImage/UIView+WebCacheOperation.h diff --git a/test/SDWebImage/UIView+WebCacheOperation.m b/ios_share/SDWebImage/UIView+WebCacheOperation.m similarity index 100% rename from test/SDWebImage/UIView+WebCacheOperation.m rename to ios_share/SDWebImage/UIView+WebCacheOperation.m diff --git a/test/test.xcodeproj/project.pbxproj b/ios_share/test.xcodeproj/project.pbxproj similarity index 98% rename from test/test.xcodeproj/project.pbxproj rename to ios_share/test.xcodeproj/project.pbxproj index 068bde7..a2033c0 100644 --- a/test/test.xcodeproj/project.pbxproj +++ b/ios_share/test.xcodeproj/project.pbxproj @@ -266,11 +266,12 @@ 7BC5DE8F1C609281005DAB56 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = "���������"; TargetAttributes = { 7BC5DE961C609281005DAB56 = { CreatedOnToolsVersion = 7.2; + DevelopmentTeam = VGXA77XL6T; }; 7BC5DEAF1C609281005DAB56 = { CreatedOnToolsVersion = 7.2; @@ -402,8 +403,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -445,8 +448,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -473,6 +478,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = VGXA77XL6T; INFOPLIST_FILE = test/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -485,6 +491,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = VGXA77XL6T; INFOPLIST_FILE = test/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -536,6 +543,7 @@ 7BC5DEBB1C609281005DAB56 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 7BC5DEBC1C609281005DAB56 /* Build configuration list for PBXNativeTarget "testUITests" */ = { isa = XCConfigurationList; @@ -544,6 +552,7 @@ 7BC5DEBE1C609281005DAB56 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/test/test.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios_share/test.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from test/test.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to ios_share/test.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate b/ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..fc6e3c6 --- /dev/null +++ b/ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate Binary files differ diff --git a/test/test.xcodeproj/project.xcworkspace/xcuserdata/bin.shen.xcuserdatad/UserInterfaceState.xcuserstate b/ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/bin.shen.xcuserdatad/UserInterfaceState.xcuserstate similarity index 100% rename from test/test.xcodeproj/project.xcworkspace/xcuserdata/bin.shen.xcuserdatad/UserInterfaceState.xcuserstate rename to ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/bin.shen.xcuserdatad/UserInterfaceState.xcuserstate Binary files differ diff --git a/test/test.xcodeproj/project.xcworkspace/xcuserdata/mb985.xcuserdatad/UserInterfaceState.xcuserstate b/ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/mb985.xcuserdatad/UserInterfaceState.xcuserstate similarity index 100% rename from test/test.xcodeproj/project.xcworkspace/xcuserdata/mb985.xcuserdatad/UserInterfaceState.xcuserstate rename to ios_share/test.xcodeproj/project.xcworkspace/xcuserdata/mb985.xcuserdatad/UserInterfaceState.xcuserstate Binary files differ diff --git a/ios_share/test.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/test.xcscheme b/ios_share/test.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/test.xcscheme new file mode 100644 index 0000000..7f891e5 --- /dev/null +++ b/ios_share/test.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/test.xcscheme @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0820" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7BC5DE961C609281005DAB56" + BuildableName = "test.app" + BlueprintName = "test" + ReferencedContainer = "container:test.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7BC5DEAF1C609281005DAB56" + BuildableName = "testUITests.xctest" + BlueprintName = "testUITests" + ReferencedContainer = "container:test.xcodeproj"> + </BuildableReference> + </TestableReference> + </Testables> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7BC5DE961C609281005DAB56" + BuildableName = "test.app" + BlueprintName = "test" + ReferencedContainer = "container:test.xcodeproj"> + </BuildableReference> + </MacroExpansion> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7BC5DE961C609281005DAB56" + BuildableName = "test.app" + BlueprintName = "test" + ReferencedContainer = "container:test.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "7BC5DE961C609281005DAB56" + BuildableName = "test.app" + BlueprintName = "test" + ReferencedContainer = "container:test.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/test/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/xcschememanagement.plist b/ios_share/test.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 100% copy from test/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/xcschememanagement.plist copy to ios_share/test.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/test/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/test.xcscheme b/ios_share/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/test.xcscheme similarity index 100% rename from test/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/test.xcscheme rename to ios_share/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/test.xcscheme diff --git a/test/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/xcschememanagement.plist b/ios_share/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 100% rename from test/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/xcschememanagement.plist rename to ios_share/test.xcodeproj/xcuserdata/bin.shen.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/test/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist similarity index 100% rename from test/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist rename to ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist diff --git a/test/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/test.xcscheme b/ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/test.xcscheme similarity index 100% rename from test/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/test.xcscheme rename to ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/test.xcscheme diff --git a/test/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/xcschememanagement.plist b/ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 100% rename from test/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/xcschememanagement.plist rename to ios_share/test.xcodeproj/xcuserdata/mb985.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/test/test/1.jpg b/ios_share/test/1.jpg similarity index 100% rename from test/test/1.jpg rename to ios_share/test/1.jpg Binary files differ diff --git a/test/test/2.jpg b/ios_share/test/2.jpg similarity index 100% rename from test/test/2.jpg rename to ios_share/test/2.jpg Binary files differ diff --git a/test/test/3.jpg b/ios_share/test/3.jpg similarity index 100% rename from test/test/3.jpg rename to ios_share/test/3.jpg Binary files differ diff --git a/test/test/4.jpg b/ios_share/test/4.jpg similarity index 100% rename from test/test/4.jpg rename to ios_share/test/4.jpg Binary files differ diff --git a/test/test/5.jpg b/ios_share/test/5.jpg similarity index 100% rename from test/test/5.jpg rename to ios_share/test/5.jpg Binary files differ diff --git a/test/test/6.jpg b/ios_share/test/6.jpg similarity index 100% rename from test/test/6.jpg rename to ios_share/test/6.jpg Binary files differ diff --git a/test/test/7.jpg b/ios_share/test/7.jpg similarity index 100% rename from test/test/7.jpg rename to ios_share/test/7.jpg Binary files differ diff --git a/test/test/AppDelegate.h b/ios_share/test/AppDelegate.h similarity index 100% rename from test/test/AppDelegate.h rename to ios_share/test/AppDelegate.h diff --git a/test/test/AppDelegate.m b/ios_share/test/AppDelegate.m similarity index 100% rename from test/test/AppDelegate.m rename to ios_share/test/AppDelegate.m diff --git a/test/test/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios_share/test/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from test/test/Assets.xcassets/AppIcon.appiconset/Contents.json rename to ios_share/test/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/test/test/Base.lproj/LaunchScreen.storyboard b/ios_share/test/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from test/test/Base.lproj/LaunchScreen.storyboard rename to ios_share/test/Base.lproj/LaunchScreen.storyboard diff --git a/ios_share/test/Base.lproj/Main.storyboard b/ios_share/test/Base.lproj/Main.storyboard new file mode 100644 index 0000000..2a40e2d --- /dev/null +++ b/ios_share/test/Base.lproj/Main.storyboard @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> + <device id="retina4_7" orientation="portrait"> + <adaptation id="fullscreen"/> + </device> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="tne-QT-ifu"> + <objects> + <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController"> + <layoutGuides> + <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> + <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> + </layoutGuides> + <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> + </objects> + </scene> + </scenes> +</document> diff --git a/test/test/Info.plist b/ios_share/test/Info.plist similarity index 100% rename from test/test/Info.plist rename to ios_share/test/Info.plist diff --git a/test/test/ViewController.h b/ios_share/test/ViewController.h similarity index 100% rename from test/test/ViewController.h rename to ios_share/test/ViewController.h diff --git a/test/test/ViewController.m b/ios_share/test/ViewController.m similarity index 100% rename from test/test/ViewController.m rename to ios_share/test/ViewController.m diff --git a/test/test/main.m b/ios_share/test/main.m similarity index 100% rename from test/test/main.m rename to ios_share/test/main.m diff --git a/test/testUITests/Info.plist b/ios_share/testUITests/Info.plist similarity index 100% rename from test/testUITests/Info.plist rename to ios_share/testUITests/Info.plist diff --git a/test/testUITests/testUITests.m b/ios_share/testUITests/testUITests.m similarity index 100% rename from test/testUITests/testUITests.m rename to ios_share/testUITests/testUITests.m -- Gitblit v1.8.0