diff --git a/README.md b/README.md index 5f5b77263..a9b117872 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,9 @@ For example, an application that takes in live video from the camera, converts t - **GPUImageRotationFilter**: This lets you rotate an image left or right by 90 degrees, or flip it horizontally or vertically +- **GPUImageCropFilter**: This crops an image to a specific region, then passes only that region on to the next stage in the filter +- *cropRegion*: A rectangular area to crop out of the image, normalized to coordinates from 0.0 - 1.0. The (0.0, 0.0) position is in the upper left of the image. + - **GPUImageSharpenFilter**: Sharpens the image - *sharpness*: The sharpness adjustment to apply (-4.0 - 4.0, with 0.0 as the default) diff --git a/examples/FilterShowcase/FilterShowcase/ShowcaseFilterListController.m b/examples/FilterShowcase/FilterShowcase/ShowcaseFilterListController.m index 1d0ec171b..d4439624a 100644 --- a/examples/FilterShowcase/FilterShowcase/ShowcaseFilterListController.m +++ b/examples/FilterShowcase/FilterShowcase/ShowcaseFilterListController.m @@ -67,6 +67,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N case GPUIMAGE_EXPOSURE: cell.textLabel.text = @"Exposure"; break; case GPUIMAGE_SHARPEN: cell.textLabel.text = @"Sharpen"; break; case GPUIMAGE_GAMMA: cell.textLabel.text = @"Gamma"; break; + case GPUIMAGE_CROP: cell.textLabel.text = @"Crop"; break; case GPUIMAGE_COLORINVERT: cell.textLabel.text = @"Color invert"; break; case GPUIMAGE_SEPIA: cell.textLabel.text = @"Sepia tone"; break; case GPUIMAGE_PIXELLATE: cell.textLabel.text = @"Pixellate"; break; diff --git a/examples/FilterShowcase/FilterShowcase/ShowcaseFilterViewController.h b/examples/FilterShowcase/FilterShowcase/ShowcaseFilterViewController.h index c691b5023..0904e6355 100644 --- a/examples/FilterShowcase/FilterShowcase/ShowcaseFilterViewController.h +++ b/examples/FilterShowcase/FilterShowcase/ShowcaseFilterViewController.h @@ -1,7 +1,7 @@ #import #import "GPUImage.h" -typedef enum { GPUIMAGE_SATURATION, GPUIMAGE_CONTRAST, GPUIMAGE_BRIGHTNESS, GPUIMAGE_EXPOSURE, GPUIMAGE_SHARPEN, GPUIMAGE_GAMMA, GPUIMAGE_SEPIA, GPUIMAGE_COLORINVERT, GPUIMAGE_PIXELLATE, GPUIMAGE_SOBELEDGEDETECTION, GPUIMAGE_SKETCH, GPUIMAGE_TOON, GPUIMAGE_KUWAHARA, GPUIMAGE_VIGNETTE, GPUIMAGE_GAUSSIAN, GPUIMAGE_GAUSSIAN_SELECTIVE, GPUIMAGE_FASTBLUR, GPUIMAGE_SWIRL, GPUIMAGE_DISSOLVE, GPUIMAGE_MULTIPLY, GPUIMAGE_OVERLAY, GPUIMAGE_LIGHTEN, GPUIMAGE_DARKEN, GPUIMAGE_COLORBURN, GPUIMAGE_COLORDODGE, GPUIMAGE_SCREENBLEND, GPUIMAGE_DIFFERENCEBLEND, GPUIMAGE_EXCLUSIONBLEND, GPUIMAGE_HARDLIGHTBLEND, GPUIMAGE_SOFTLIGHTBLEND, GPUIMAGE_CUSTOM, GPUIMAGE_FILECONFIG, GPUIMAGE_NUMFILTERS} GPUImageShowcaseFilterType; +typedef enum { GPUIMAGE_SATURATION, GPUIMAGE_CONTRAST, GPUIMAGE_BRIGHTNESS, GPUIMAGE_EXPOSURE, GPUIMAGE_SHARPEN, GPUIMAGE_CROP, GPUIMAGE_GAMMA, GPUIMAGE_SEPIA, GPUIMAGE_COLORINVERT, GPUIMAGE_PIXELLATE, GPUIMAGE_SOBELEDGEDETECTION, GPUIMAGE_SKETCH, GPUIMAGE_TOON, GPUIMAGE_KUWAHARA, GPUIMAGE_VIGNETTE, GPUIMAGE_GAUSSIAN, GPUIMAGE_GAUSSIAN_SELECTIVE, GPUIMAGE_FASTBLUR, GPUIMAGE_SWIRL, GPUIMAGE_DISSOLVE, GPUIMAGE_MULTIPLY, GPUIMAGE_OVERLAY, GPUIMAGE_LIGHTEN, GPUIMAGE_DARKEN, GPUIMAGE_COLORBURN, GPUIMAGE_COLORDODGE, GPUIMAGE_SCREENBLEND, GPUIMAGE_DIFFERENCEBLEND, GPUIMAGE_EXCLUSIONBLEND, GPUIMAGE_HARDLIGHTBLEND, GPUIMAGE_SOFTLIGHTBLEND, GPUIMAGE_CUSTOM, GPUIMAGE_FILECONFIG, GPUIMAGE_NUMFILTERS} GPUImageShowcaseFilterType; @interface ShowcaseFilterViewController : UIViewController { diff --git a/examples/FilterShowcase/FilterShowcase/ShowcaseFilterViewController.m b/examples/FilterShowcase/FilterShowcase/ShowcaseFilterViewController.m index 781bdf81f..b90dba579 100644 --- a/examples/FilterShowcase/FilterShowcase/ShowcaseFilterViewController.m +++ b/examples/FilterShowcase/FilterShowcase/ShowcaseFilterViewController.m @@ -150,6 +150,17 @@ - (void)setupFilter; filter = [[GPUImageGammaFilter alloc] init]; }; break; + case GPUIMAGE_CROP: + { + self.title = @"Crop"; + self.filterSettingsSlider.hidden = NO; + + [self.filterSettingsSlider setMinimumValue:0.3]; + [self.filterSettingsSlider setMaximumValue:1.0]; + [self.filterSettingsSlider setValue:0.5]; + + filter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.0, 0.0, 0.5, 0.5)]; + }; break; case GPUIMAGE_SOBELEDGEDETECTION: { self.title = @"Edge Detection"; @@ -382,6 +393,7 @@ - (IBAction)updateFilterFromSlider:(id)sender; case GPUIMAGE_GAUSSIAN: [(GPUImageGaussianBlurFilter *)filter setBlurSize:[(UISlider*)sender value]]; break; case GPUIMAGE_FASTBLUR: [(GPUImageFastBlurFilter *)filter setBlurPasses:round([(UISlider*)sender value])]; break; case GPUIMAGE_GAUSSIAN_SELECTIVE: [(GPUImageGaussianSelectiveBlurFilter *)filter setExcludeCircleRadius:[(UISlider*)sender value]]; break; + case GPUIMAGE_CROP: [(GPUImageCropFilter *)filter setCropRegion:CGRectMake(0.0, 0.0, [(UISlider*)sender value], [(UISlider*)sender value])]; break; default: break; } } diff --git a/examples/SimpleImageFilter/SimpleImageFilter/SimpleImageViewController.m b/examples/SimpleImageFilter/SimpleImageFilter/SimpleImageViewController.m index 0f7adb700..b441462ba 100644 --- a/examples/SimpleImageFilter/SimpleImageFilter/SimpleImageViewController.m +++ b/examples/SimpleImageFilter/SimpleImageFilter/SimpleImageViewController.m @@ -62,8 +62,13 @@ - (void)setupImageFilteringToDisk; UIImage *inputImage = [UIImage imageNamed:@"Lambeau.jpg"]; GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:inputImage]; -// GPUImageSepiaFilter *stillImageFilter = [[GPUImageSepiaFilter alloc] init]; - GPUImageSketchFilter *stillImageFilter = [[GPUImageSketchFilter alloc] init]; + GPUImageSepiaFilter *stillImageFilter = [[GPUImageSepiaFilter alloc] init]; +// GPUImageSketchFilter *stillImageFilter = [[GPUImageSketchFilter alloc] init]; + + // There's a problem with the Kuwahara filter where it doesn't finish rendering before the image is extracted from it. + // It looks like it only gets through certain tiles before glReadPixels() is called. Odd. +// GPUImageKuwaharaFilter *stillImageFilter = [[GPUImageKuwaharaFilter alloc] init]; +// stillImageFilter.radius = 9; [stillImageSource addTarget:stillImageFilter]; [stillImageSource processImage]; diff --git a/framework/GPUImage.xcodeproj/project.pbxproj b/framework/GPUImage.xcodeproj/project.pbxproj index a62a56c8d..4a566733f 100644 --- a/framework/GPUImage.xcodeproj/project.pbxproj +++ b/framework/GPUImage.xcodeproj/project.pbxproj @@ -96,6 +96,8 @@ BCB6B8771504234A0041703B /* GPUImageSoftLightBlendFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BCB6B86F1504234A0041703B /* GPUImageSoftLightBlendFilter.m */; }; BCB6B8BB1505BF940041703B /* GPUImageTextureOutput.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB6B8B91505BF940041703B /* GPUImageTextureOutput.h */; }; BCB6B8BC1505BF940041703B /* GPUImageTextureOutput.m in Sources */ = {isa = PBXBuildFile; fileRef = BCB6B8BA1505BF940041703B /* GPUImageTextureOutput.m */; }; + BCB6B9041507CA8D0041703B /* GPUImageCropFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BCB6B9021507CA8C0041703B /* GPUImageCropFilter.h */; }; + BCB6B9051507CA8D0041703B /* GPUImageCropFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BCB6B9031507CA8C0041703B /* GPUImageCropFilter.m */; }; BCC93A0F1501D1BF00958B26 /* GPUImageFastBlurFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BCC93A0D1501D1BF00958B26 /* GPUImageFastBlurFilter.h */; }; BCC93A101501D1BF00958B26 /* GPUImageFastBlurFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC93A0E1501D1BF00958B26 /* GPUImageFastBlurFilter.m */; }; BCC93A1E1501E42F00958B26 /* GPUImageTwoPassFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = BCC93A1C1501E42E00958B26 /* GPUImageTwoPassFilter.h */; }; @@ -216,6 +218,8 @@ BCB6B86F1504234A0041703B /* GPUImageSoftLightBlendFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageSoftLightBlendFilter.m; path = Source/GPUImageSoftLightBlendFilter.m; sourceTree = SOURCE_ROOT; }; BCB6B8B91505BF940041703B /* GPUImageTextureOutput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageTextureOutput.h; path = Source/GPUImageTextureOutput.h; sourceTree = SOURCE_ROOT; }; BCB6B8BA1505BF940041703B /* GPUImageTextureOutput.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageTextureOutput.m; path = Source/GPUImageTextureOutput.m; sourceTree = SOURCE_ROOT; }; + BCB6B9021507CA8C0041703B /* GPUImageCropFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageCropFilter.h; path = Source/GPUImageCropFilter.h; sourceTree = SOURCE_ROOT; }; + BCB6B9031507CA8C0041703B /* GPUImageCropFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageCropFilter.m; path = Source/GPUImageCropFilter.m; sourceTree = SOURCE_ROOT; }; BCC93A0D1501D1BF00958B26 /* GPUImageFastBlurFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageFastBlurFilter.h; path = Source/GPUImageFastBlurFilter.h; sourceTree = SOURCE_ROOT; }; BCC93A0E1501D1BF00958B26 /* GPUImageFastBlurFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPUImageFastBlurFilter.m; path = Source/GPUImageFastBlurFilter.m; sourceTree = SOURCE_ROOT; }; BCC93A1C1501E42E00958B26 /* GPUImageTwoPassFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPUImageTwoPassFilter.h; path = Source/GPUImageTwoPassFilter.h; sourceTree = SOURCE_ROOT; }; @@ -391,6 +395,8 @@ children = ( BCB5E85314E63BBB00701302 /* GPUImageRotationFilter.h */, BCB5E85414E63BBB00701302 /* GPUImageRotationFilter.m */, + BCB6B9021507CA8C0041703B /* GPUImageCropFilter.h */, + BCB6B9031507CA8C0041703B /* GPUImageCropFilter.m */, BCB6B835150400030041703B /* GPUImageSharpenFilter.h */, BCB6B836150400030041703B /* GPUImageSharpenFilter.m */, BCC93A0D1501D1BF00958B26 /* GPUImageFastBlurFilter.h */, @@ -536,6 +542,7 @@ BCB6B8741504234A0041703B /* GPUImageHardLightBlendFilter.h in Headers */, BCB6B8761504234A0041703B /* GPUImageSoftLightBlendFilter.h in Headers */, BCB6B8BB1505BF940041703B /* GPUImageTextureOutput.h in Headers */, + BCB6B9041507CA8D0041703B /* GPUImageCropFilter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -682,6 +689,7 @@ BCB6B8751504234A0041703B /* GPUImageHardLightBlendFilter.m in Sources */, BCB6B8771504234A0041703B /* GPUImageSoftLightBlendFilter.m in Sources */, BCB6B8BC1505BF940041703B /* GPUImageTextureOutput.m in Sources */, + BCB6B9051507CA8D0041703B /* GPUImageCropFilter.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/framework/Source/GPUImage.h b/framework/Source/GPUImage.h index 80b44273b..6ac1f2560 100644 --- a/framework/Source/GPUImage.h +++ b/framework/Source/GPUImage.h @@ -45,3 +45,4 @@ #import "GPUImageDifferenceBlendFilter.h" #import "GPUImageHardLightBlendFilter.h" #import "GPUImageSoftLightBlendFilter.h" +#import "GPUImageCropFilter.h" \ No newline at end of file diff --git a/framework/Source/GPUImageCropFilter.h b/framework/Source/GPUImageCropFilter.h new file mode 100644 index 000000000..42265841c --- /dev/null +++ b/framework/Source/GPUImageCropFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +@interface GPUImageCropFilter : GPUImageFilter +{ +} + +// The crop region is the rectangle within the image to crop. It is normalized to a coordinate space from 0.0 to 1.0, with 0.0, 0.0 being the upper left corner of the image +@property(readwrite, nonatomic) CGRect cropRegion; + +// Initialization and teardown +- (id)initWithCropRegion:(CGRect)newCropRegion; + +@end diff --git a/framework/Source/GPUImageCropFilter.m b/framework/Source/GPUImageCropFilter.m new file mode 100644 index 000000000..d184443be --- /dev/null +++ b/framework/Source/GPUImageCropFilter.m @@ -0,0 +1,77 @@ +#import "GPUImageCropFilter.h" + +NSString *const kGPUImageCropFragmentShaderString = SHADER_STRING +( + varying highp vec2 textureCoordinate; + + uniform sampler2D inputImageTexture; + + void main() + { + gl_FragColor = texture2D(inputImageTexture, textureCoordinate); + } +); + +@implementation GPUImageCropFilter + +@synthesize cropRegion = _cropRegion; + +#pragma mark - +#pragma mark Initialization and teardown + +- (id)initWithCropRegion:(CGRect)newCropRegion; +{ + if (!(self = [super initWithFragmentShaderFromString:kGPUImageCropFragmentShaderString])) + { + return nil; + } + + self.cropRegion = newCropRegion; + + return self; +} + +- (id)init; +{ + if (!(self = [self initWithCropRegion:CGRectMake(0.0, 0.0, 1.0, 1.0)])) + { + return nil; + } + + return self; +} + +#pragma mark - +#pragma mark GPUImageInput + +//- (void)setInputSize:(CGSize)newSize; +//{ +// CGSize croppedSize; +// croppedSize.width = newSize.width * _cropRegion.size.width; +// croppedSize.height = newSize.height * _cropRegion.size.height; +// +// inputTextureSize = croppedSize; +//} +// +- (void)newFrameReady; +{ + static const GLfloat cropSquareVertices[] = { + -1.0f, -1.0f, + 1.0f, -1.0f, + -1.0f, 1.0f, + 1.0f, 1.0f, + }; + + GLfloat cropTextureCoordinates[] = { + _cropRegion.origin.x, _cropRegion.origin.y, + CGRectGetMaxX(_cropRegion), _cropRegion.origin.y, + _cropRegion.origin.x, CGRectGetMaxY(_cropRegion), + CGRectGetMaxX(_cropRegion), CGRectGetMaxY(_cropRegion), + }; + + [self renderToTextureWithVertices:cropSquareVertices textureCoordinates:cropTextureCoordinates sourceTexture:filterSourceTexture]; + + [self informTargetsAboutNewFrame]; +} + +@end diff --git a/framework/Source/GPUImageFilter.m b/framework/Source/GPUImageFilter.m index 4c9fbf80b..8ea006ff1 100644 --- a/framework/Source/GPUImageFilter.m +++ b/framework/Source/GPUImageFilter.m @@ -113,7 +113,7 @@ - (UIImage *)imageFromCurrentlyProcessedOutput; { [GPUImageOpenGLESContext useImageProcessingContext]; [self setOutputFBO]; - + CGSize currentFBOSize = [self sizeOfFBO]; NSUInteger totalBytesForImage = (int)currentFBOSize.width * (int)currentFBOSize.height * 4; diff --git a/framework/Source/GPUImageSobelEdgeDetectionFilter.m b/framework/Source/GPUImageSobelEdgeDetectionFilter.m index efd421eb1..58f8aeedb 100644 --- a/framework/Source/GPUImageSobelEdgeDetectionFilter.m +++ b/framework/Source/GPUImageSobelEdgeDetectionFilter.m @@ -138,7 +138,6 @@ - (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString; - (void)setupFilterForSize:(CGSize)filterFrameSize; { - NSLog(@"Setting up Sobel filter for size: %f, %f", filterFrameSize.width, filterFrameSize.height); if (!hasOverriddenImageSizeFactor) { _imageWidthFactor = filterFrameSize.width;