The description
I deal with 2 view controllers. The first one is camera(powered by GPUImage lib) and the second one is controller where I can crop taken image(again by crop filter from GPUImage).Let's name them camera and cropper respectively. My cropper is pretty simple: it consists of UICollectionView with thumbnails and UIScrollView where the selected image from collection view is cropped. The code
Camera.m
-(void)viewDidLoad{
self.videoCamera = [[GPUImageStillCamera alloc] init];
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
self.cameraView = [[GPUImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - self.bottomView.frame.size.height)];
[self.view addSubview:self.cameraView];
self.currentFilter = [[GPUImageGammaFilter alloc] init];
[self.videoCamera addTarget:self.currentFilter];
[self.currentFilter addTarget:self.cameraView];
[self.videoCamera startCameraCapture];
self.focusRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(focus:)];
[self.cameraView addGestureRecognizer:self.focusRecognizer];
[self prepareCameraUI];
[self performSelector:@selector(hideBar) withObject:nil afterDelay:0.4];
}
-(void)viewDidAppear:(BOOL)animated{
self.cropper = [self.storyboard instantiateViewControllerWithIdentifier:@"CropperController"];
self.cropper.transitionFromCamera = YES;
self.cropper.thumbnails = [NSMutableArray array];
self.cropper.originalImages = [NSMutableArray array];
[self prepareFilters];
}
-(void)dealloc{
NSLog(@"dealloc of camera");
[self.videoCamera stopCameraCapture];
[self.videoCamera removeAllTargets];
[self.currentFilter removeAllTargets];
}
-(void)viewWillDisappear:(BOOL)animated{
NSLog(@"camera disappered");
self.cropper = nil;
}
- (IBAction)snap {
__unsafe_unretained CameraController *weakSelf = self;
[self.videoCamera capturePhotoAsImageProcessedUpToFilter:self.currentFilter withCompletionHandler:^(UIImage *processedImage, NSError *error){
[weakSelf.cropper.originalImages addObject:processedImage];
NSLog(@"processedImage.size %@",NSStringFromCGSize(processedImage.size));
NSLog(@"processedImage.oreientation %i",processedImage.imageOrientation);
}];
}
- (IBAction)donePressed {
if(!self.cropper.originalImages.count == 0){
[self.navigationController pushViewController:self.cropper animated:YES];
}
}
-(IBAction)cancelPicker:(id)sender{
[self dismissViewControllerAnimated:YES completion:^{[self.navigationController setViewControllers:@[]];
}];
}
Cropper.m
@import GPUImage;
@interface CropperController ()<WYPopoverControllerDelegate>
{
ContactsViewController *rootVc;
int indexOfSelectedPhoto;
WYPopoverController *popover;
}
@property (weak, nonatomic) IBOutlet UICollectionView *imagesCollectionView;
@property (weak, nonatomic) IBOutlet UIScrollView *cropArea;
@property (weak, nonatomic) IBOutlet UIView *bar;
@property UIImageView *originalImageView;
@property (weak, nonatomic) IBOutlet UIButton *forwardButton;
@property (weak, nonatomic) IBOutlet UILabel *titleOfABar;
@property (weak, nonatomic) IBOutlet UIButton *backButton;
@property (weak, nonatomic) IBOutlet UIView *shadowBorderView;
@property NSIndexPath *previousIndexPath;
@end
@implementation CropperController
- (void)viewDidLoad {
[super viewDidLoad];
rootVc = (ContactsViewController*)[[[[UIApplication sharedApplication] delegate]window]rootViewController];
[rootVc setHideStatusBar:NO];
[rootVc setStatusBarStyle:UIStatusBarStyleDefault];
[rootVc setNeedsStatusBarAppearanceUpdate];
UIImage *originalImage = self.originalImages[0];
self.originalImageView = [[UIImageView alloc] initWithImage:originalImage];
self.originalImageView.clipsToBounds = YES;
[self.originalImageView setFrame:CGRectMake(0,0,originalImage.size.width,originalImage.size.height)];
[self.cropArea addSubview:self.originalImageView];
self.cropArea.contentSize = self.originalImageView.frame.size;
self.previousIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
}
-(void)prepareThumbnails{
for (UIImage *image in self.originalImages){
[self.thumbnails addObject:[UIImage imageWithData:UIImageJPEGRepresentation(image, 0.2)]];
}
[self.imagesCollectionView reloadData];
[self.imagesCollectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionLeft];
}
-(void)dealloc{
NSLog(@"deallocated cropper");
[self.originalImages removeAllObjects];
[self.thumbnails removeAllObjects];
self.originalImages = nil;
self.thumbnails = nil;
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[rootVc setStatusBarStyle:UIStatusBarStyleLightContent];
[rootVc setNeedsStatusBarAppearanceUpdate];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self prepareThumbnails];
}
- (IBAction)backToCamera:(id)sender {
[self.navigationController popToRootViewControllerAnimated:YES];
}
- (IBAction)cancelCropper:(UIBarButtonItem *)sender {
[self.navigationController popViewControllerAnimated:YES];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
CGFloat widthRatio = self.cropArea.frame.size.width/self.originalImageView.bounds.size.width;
CGFloat heightRatio = self.cropArea.frame.size.height/self.originalImageView.bounds.size.height;
CGFloat minScale = fmax(widthRatio, heightRatio);
self.cropArea.minimumZoomScale = minScale;
self.cropArea.maximumZoomScale = minScale;
self.cropArea.zoomScale = minScale;
}
-(void)updateScales{
CGFloat widthRatio = self.cropArea.frame.size.width/self.originalImageView.bounds.size.width;
CGFloat heightRatio = self.cropArea.frame.size.height/self.originalImageView.bounds.size.height;
CGFloat minScale = fmax(widthRatio, heightRatio);
self.cropArea.minimumZoomScale = minScale;
self.cropArea.maximumZoomScale = minScale;
self.cropArea.zoomScale = minScale;
}
-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return self.originalImageView;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
__weak CropperController *weakSelf = self;
if(self.previousIndexPath!=indexPath){
UIImage *originalImage = weakSelf.originalImages[indexPath.item];
weakSelf.originalImageView.image = originalImage;
weakSelf.originalImageView.frame = CGRectMake(0,0,originalImage.size.width,originalImage.size.height);
[weakSelf updateScales];
weakSelf.previousIndexPath = indexPath;
}
UICollectionViewCell *cell = [self.imagesCollectionView cellForItemAtIndexPath:indexPath];
[cell.contentView bringSubviewToFront:[cell.contentView viewWithTag:1]];
indexOfSelectedPhoto = indexPath.item;
}
-(IBAction)cropOriginalImage:(id)sender{
NSIndexPath *indexPath = [self.imagesCollectionView indexPathsForSelectedItems][0];
UIImage *image = self.originalImages[indexPath.item];
NSLog(@"orientation %i",image.imageOrientation);
NSLog(@"bounds %@",NSStringFromCGRect(self.cropArea.bounds));
CGRect rect;
if(image.size.width<image.size.height){
rect = CGRectMake(self.cropArea.bounds.origin.x/320, self.cropArea.bounds.origin.y/426.5,1,image.size.width/image.size.height);
NSLog(@"rect 1 %@",NSStringFromCGRect(rect));
}
else{
rect = CGRectMake(self.cropArea.bounds.origin.x/426.5, self.cropArea.bounds.origin.y/320,image.size.height/image.size.width,1);
NSLog(@"rect 2 %@",NSStringFromCGRect(rect));
}
GPUImageCropFilter *filter = [[GPUImageCropFilter alloc] initWithCropRegion:rect];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
UIImage *img = [filter imageByFilteringImage:image];
NSLog(@"image cropped %@",NSStringFromCGSize(img.size));
[self saveImageToDisk:img];
});
}
-(void)saveImageToDisk:(UIImage*)image{
NSLog(@"saving");
@autoreleasepool {
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"/Photos/SELF"];
if (![manager fileExistsAtPath:dataPath])
[manager createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:nil];
NSString *pathComponent = [NSString stringWithFormat:@"/%i",[manager contentsOfDirectoryAtPath:dataPath error:nil].count];
NSString *imagePath = [dataPath stringByAppendingPathComponent:pathComponent];
NSData *imgData = UIImageJPEGRepresentation(image,1);
NSLog(@"imagePath %@",imagePath);
[imgData writeToFile:imagePath atomically:YES];
}
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return self.originalImages.count;
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [self.imagesCollectionView dequeueReusableCellWithReuseIdentifier:@"imageToEdit" forIndexPath:indexPath];
UIImageView *thumbnailView = (UIImageView*)[cell viewWithTag:4];
NSLog(@"thumbnailView.imag %@",thumbnailView.image);
if(!(thumbnailView.image)){[self configureCell:cell];NSLog(@"configuring");}
thumbnailView.contentMode = UIViewContentModeScaleAspectFill;
UIImage *img = self.originalImages[indexPath.item];
thumbnailView.image = [img thumbnailImage:cell.frame.size.width transparentBorder:0 cornerRadius:0 interpolationQuality:kCGInterpolationMedium];
if(indexPath.item == indexOfSelectedPhoto){
[cell.contentView bringSubviewToFront:[cell.contentView viewWithTag:1]];
}else{
[cell.contentView sendSubviewToBack:[cell.contentView viewWithTag:1]];
}
return cell;
}
-(void)configureCell:(UICollectionViewCell*)cell{
cell.layer.masksToBounds = NO;
cell.layer.shadowOpacity = 1;
cell.layer.shadowOffset = CGSizeMake(2,2);
cell.layer.shadowColor = [UIColor lightGrayColor].CGColor;
cell.layer.borderWidth = 2;
cell.layer.borderColor = [UIColor whiteColor].CGColor;
cell.layer.shadowPath = [UIBezierPath bezierPathWithRect:cell.bounds].CGPath;
}
The Problem
The problem is that every time Cropper appears I have a memory spike of 40 mb per photo. So, by loading, 5 photos I get 200 mb spike and memory warning. And this memory does not get released when I dismiss navigation controller or pop Cropper. The navigation controller presented modally. I assume that the problem is in collection view or in presenting/dismissing controllers. BTW when I dismiss nav controller from cropper it is not deallocated.What are your thoughts?
0 comments:
Post a Comment