I'm trying to make a simple photo editor with GPUImage
. I have two issues. One is that app keeps crashing whenever I slide the sliders for brightness or contrast a little ahead. On simulator i don't face these problems but then comes the second issue. The image turns in landscape orientation (I have no idea why) when memory low warning shows on console. Can anyone point me in the right direction? I read on forums, here and on github that many users are facing memory issues so maybe it's a memory leak in the library? I am new to iOS development so yeah I'd like you guys to be elaborate about it. p.s. i am using iphone 4s and ios 7
//The Action List
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
GPUImageFilter *selectedFilter;
//GPUImageBrightnessFilter *brightnessFilter;
//GPUImageContrastFilter *contrastFilter;
//GPUImageSaturationFilter *saturationFilter;
//sliderValue = 0.0;
bool choiceChecker = NO;
bool choiceChecker1 = NO;
bool choicechecker2 = NO;
//self.stepper.value = 0;
switch (buttonIndex) {
case 0:
selectedFilter = [[GPUImageGrayscaleFilter alloc] init];
break;
case 1:
selectedFilter = [[GPUImageSepiaFilter alloc] init];
break;
case 2:
selectedFilter = [[GPUImageSketchFilter alloc] init];
break;
case 3:
selectedFilter = [[GPUImagePixellateFilter alloc] init];
break;
case 4:
selectedFilter = [[GPUImageColorInvertFilter alloc] init];
break;
case 5:
selectedFilter = [[GPUImageToonFilter alloc] init];
break;
case 6:
selectedFilter = [[GPUImagePinchDistortionFilter alloc] init];
break;
case 7:
choiceChecker1 = YES;
break;
case 8:
choiceChecker = YES;
break;
case 9:
choicechecker2 = YES;
break;
case 10:
selectedFilter = [[GPUImageFilter alloc] init];
break;
default:
break;
}
//UIImage *selectedImage =
UIImage *filteredImage;
//for brightness
if(choiceChecker1 == YES)
{
self.brightnessSlider.hidden = NO;
self.contrastSlider.hidden = YES;
self.saturationSlider.hidden = YES;
[self.imageView setImage:originalImage];
NSLog(@"hello");
}
//for contrast
else if(choiceChecker == YES)
{
self.contrastSlider.hidden = NO;
self.brightnessSlider.hidden = YES;
self.saturationSlider.hidden = YES;
//[self.imageView setImage:originalImage];
}
//for saturation
else if(choicechecker2 == YES)
{
self.saturationSlider.hidden = NO;
self.brightnessSlider.hidden = YES;
self.contrastSlider.hidden = YES;
[self.imageView setImage:originalImage];
}
//for filters
else if (choiceChecker == NO && choiceChecker1 == NO && choicechecker2 == NO)
{
filteredImage = [selectedFilter imageByFilteringImage:originalImage];
[self.imageView setImage:filteredImage];
originalImage = filteredImage;
}
}
// Edited action listener for brightness slider (testView is a GPUImageView)
-(IBAction)BrightnessSlid:(UISlider *)slider {
sliderValue = self.brightnessSlider.value;
//self.contrastSlider.hidden = YES;
fx_image = [[GPUImagePicture alloc] initWithImage:originalImage];
[brightnessFilter setBrightness:sliderValue];
[fx_image addTarget:brightnessFilter];
[brightnessFilter useNextFrameForImageCapture];
[brightnessFilter forceProcessingAtSize:CGSizeMake(320.0, 519.0)];
[fx_image processImage];
[fx_image addTarget:testView];
[self.imageView addSubview:testView];
final_image = [brightnessFilter imageFromCurrentFramebuffer];
//originalImage = final_image;
}
The first thing that leaps out at me is your slider method, which is horribly inefficient. You're creating a new GPUImagePicture and resulting UIImage every single time that fires. You don't want to do that.
Instead, instantiate your GPUImagePicture once, target it to the appropriate filter once, and adjust values as needed in your slider. Have the output be targeted to a GPUImageView instead of a UIImageView. This will avoid wasteful image creation and destruction on every move of the slider, and will prevent expensive trips through Core Graphics at either end. By itself, that will save you a lot of memory and dramatically improve your slider preview performance.
You may also want to think about processing your image at a lower resolution, to match your output view's resolution. No need to process pixels you won't see. This can be done using -forceProcessingAtSize:
on your filter.
You'll need to remember to disconnect filters from the GPUImagePicture and GPUImageView when you swap them out, and to use -processImage
on the GPUImagePicture every time you want to update the preview image.