GPUImageMotionBlurFilter and images with transparency - ios

I'm trying to apply GPUImageMotionBlurFilter to a snapshot of UIView. I want to blur the top and bottom edges of the view too, so I'm leaving a transparent space (insetY) above and below the rect passed to drawViewHierarchyInRect:afterScreenUpdates:. GPUImage seems to ignore the transparency and acts like it was filled with a color a little lighter than -lightGrayColor.
Here's my code (it's in a method in UIView subclass):
CGFloat insetX = 0;
CGFloat insetY = 10;
CGRect snapshotFrame = CGRectInset(self.bounds, -insetX, -insetY);
UIGraphicsBeginImageContextWithOptions(snapshotFrame.size, NO, 0.0f);
[self drawViewHierarchyInRect:CGRectMake(insetX, insetY, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)) afterScreenUpdates:YES];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
GPUImageMotionBlurFilter *motionBlurFilter = [[GPUImageMotionBlurFilter alloc] init];
motionBlurFilter.blurAngle = 90;
motionBlurFilter.blurSize = 20.0f;
UIImage *blurredImage = [motionBlurFilter imageByFilteringImage:snapshotImage];
And here's what I'm getting:
snapshotImage:
blurredImage:
Is what I'm trying to do possible?

Related

iOS Mask Image size too high

I wasn't sure how to name this, sorry for the title.
I have an image that I want to fill more or less depending on a variable. For this, I created an image made of black and white (below). The goal is to use it as a mask and fill it the way I want, based on this documentation.
The issue: the image is drawn properly BUT its dimensions are way too high. I test it on iPhone 6+ with a #3x image, the image asset size is correct but the image that is returned by my function is way too big. When I put constraints on my UIImageView*, I only view part of the returned filled image; when I don't, the image is way too big. See below for a screenshot (iPhone 6+)
I subclassed a UIView with the following code:
- (void)drawRect:(CGRect)rect
{
CGFloat width = self.frame.size.width;
NSLog(#"%0.f", width);
CGFloat height = self.frame.size.height;
NSLog(#"%0.f", height);
CGFloat fillHeight = 0.9 * height;
NSLog(#"%0.f", fillHeight);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect fillRect = CGRectMake(0, height - fillHeight, width, fillHeight);
CGContextAddRect(context, fillRect);
CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);
CGContextFillRect(context, fillRect);
CGRect emptyRect = CGRectMake(0, 0, width, height - fillHeight);
CGContextAddRect(context, emptyRect);
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
CGContextFillRect(context, emptyRect);
}
- (UIImage *)renderAsImage
{
// setup context
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0); // use same scale factor as device
CGContextRef c = UIGraphicsGetCurrentContext();
// render view
[self.layer renderInContext:c];
// get reslting image
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
NSLog(#"result size = %d width, %d height", result.size.width, result.size.height);
UIGraphicsEndImageContext();
return result;
}
And in my ViewController:
- (void) setUpMaskedImage
{
// Image View set in Storyboard that will contain the final image. Bounds are set in Storyboard (constraints)
UIImageView* imageView = self.containingImageView;
// Custom View (see methods above) that will draw a rectangle filled with color
UIView* view = [[CustomView alloc] initWithFrame: imageView.frame];
// Mask Image used along with the custom view to create final view (see image above)
UIImage* maskImage = [UIImage imageNamed: #"maskImage"];
[view setNeedsDisplay];
UIImage* fillImage = [view renderAsImage];
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
UIImage* imageToDisplay = [UIImage imageWithCGImage:masked];
[imageView setImage:imageToDisplay];
}
I just don't get it. I used similar code elsewhere in my app and it works just fine. I will do a sample project soon if necessary.
Thank you!

Draw rotated and scaled UILabel text inside UIImage

I have one UIScrollView with a UIImageView inside from where I obtain a cropped UIImage (considering scale, offset, bounds,...). On the other hand, I have a UILabel which I can rotate, pinch and pan anywhere over the UIScrollView. The problem comes when I try to generate the final image with the label text inside (with it's original/equivalent position, rotation,...) on the cropped UIImage (bigger than screen size).
I've tried everything. This is my last attempt trying to position the text, but it's always misplaced.
// Compute rect to draw the text inside
CGSize imageSize = inImage.size;
NSDictionary *attr = #{NSForegroundColorAttributeName: fontColor, NSFontAttributeName: textFont};
CGSize textSize = [text sizeWithAttributes:attr];
CGRect textRect = CGRectMake(labelCenterPoint.x, labelCenterPoint.y, textSize.width, textSize.height);
// Create the image
UIGraphicsBeginImageContext(imageSize);
[inImage drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
// Rotate text from center
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM( context, 0.5f * textSize.width, 0.5f * textSize.height ) ;
CGContextRotateCTM(context, rotation);
[text drawInRect:CGRectIntegral(textRect) withAttributes:attr];
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
I think the problem is the textRect origin. Do I have to make the UILabel a subView of the UIScrollView too and make the textRect origin relative to the UIScrollView parameters? or am I missing something?. Is there a better way?.
Thanks in advance!.
Edit:
I have finally found an acceptable solution (although is not too much precise). I think the problem was about the two existing coordinate systems, so I tried a different approach:
// Calculate the relative position of the UILabel with respect
// to the ScrollView that contains the image
float xPosition = label.frame.origin.x - scrollView.frame.origin.x;
float yPosition = label.frame.origin.y - scrollView.frame.origin.y;
// Calculate the proportion to apply to the position
// (the image is bigger than screen)
float xProportion = image.frame.size.width / scrollView.frame.size.width;
float yProportion = image.frame.size.height / scrollView.frame.size.height;
UIImageView *testView = [[UIImageView alloc] initWithImage:image];
UILabel *tempLabel = [[UILabel alloc] initWithFrame:
CGRectMake((xPosition*xProportion),
(yPosition*yProportion),
label.frame.size.width*xProportion,
label.frame.size.height*yProportion)];
tempLabel.text = label.text;
tempLabel.font = [UIFont fontWithName:label.font.fontName
size:label.font.pointSize*3];
tempLabel.textColor = label.textColor;
tempLabel.textAlignment = NSTextAlignmentCenter;
tempLabel.transform = CGAffineTransformMakeRotation(rotation);
tempLabel.adjustsFontSizeToFitWidth = YES;
tempLabel.minimumScaleFactor = 0.05;
[testView addSubview:tempLabel];
UIGraphicsBeginImageContext(testView.image.size);
[testView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *imageWithText = UIGraphicsGetImageFromCurrentImageContext();
I hope this may help someone. All suggestions are welcome of course.

Image cropping issue in iOS

I am creating an iPhone app which has image cropping feature. In this, I am getting the photos from the UIImagePickerController and passing it for cropping. There it has a scrollview and the selected image will be added as a subview to the scrollview. And I am using a UIButton for selecting the area for cropping. User can move the button over the imageview and place it anywhere, and when click on CROP button, the area similar to the frame size of the button should be cropped from the imageview.
I used the following code, but it is not returning the actual image.
CGRect clippedRect = CGRectMake(self.scrollView.frame.origin.x+90, self.scrollView.frame.origin.y, self.scrollView.frame.size.width-180, self.scrollView.frame.size.height-220);
CGImageRef imageRef = CGImageCreateWithImageInRect([self.myPhoto CGImage], clippedRect);
UIImage *newImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
self.imageView.image = newImage;
also used
- (UIImage *)cropImage:(UIImage *)oldImage {
CGSize imageSize = self.cropFrame.frame.size;
UIGraphicsBeginImageContextWithOptions( CGSizeMake( imageSize.width, imageSize.height), NO, 0.);
[oldImage drawAtPoint:CGPointMake( xPosition, yPosition)
blendMode:kCGBlendModeCopy
alpha:1.];
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage;
}
but the result image is not the exact image as per the button frame. I am getting the image from another area.
Updated code
- (void)loadPhoto{
CGFloat w = self.myPhoto.size.width;
CGFloat h = self.myPhoto.size.height;
CGRect imageViewFrame = CGRectMake(0.0f, 0.0f, roundf(w / 2.0f), roundf(h / 2.0f));
self.scrollView.contentSize = imageViewFrame.size;
UIImageView *iv = [[UIImageView alloc] initWithFrame:imageViewFrame];
iv.contentMode = UIViewContentModeScaleAspectFit;
iv.image = self.myPhoto;
[self.view addSubview:iv];
self.imageView = iv;
[iv release];
}
CGRect crop;//= CGRectMake(10, 10, 360, 360);
crop.origin.x = self.cropFrame.frame.origin.x;
crop.origin.y = self.cropFrame.frame.origin.y;
crop.size.width = roundf(self.cropFrame.frame.size.width * 2.0f); //self.cropFrame.frame.size.width * 2;
crop.size.height = roundf(self.cropFrame.frame.size.height * 2.0f); //self.cropFrame.frame.size.height * 2;
NSLog(#"Rect: %#", NSStringFromCGRect(crop));
self.imageView.image = [self croppedImage:crop];
- (UIImage *)croppedImage:(CGRect)bounds {
CGImageRef imageRef = CGImageCreateWithImageInRect([self.imageView.image CGImage], bounds);
UIImage *croppedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:self.myPhoto.imageOrientation];
CGImageRelease(imageRef);
return croppedImage;
}
Please help to find a solution.
The iOS has a default feature for cropping images.Try this code.
picker.allowsEditing = YES;
and also check this controller for cropping..this is exactly the one you are looking for I think https://github.com/barrettj/BJImageCropper .Hope this helps you..
Since you are using a scrollView that allows the image to be scrolled, you need to adjust your crop rect to the scrollView's position:
float zoomScale = self.scrollView.zoomScale;
int cropX = (self.scrollView.contentOffset.x-imageView.frame.origin.x)/zoomScale;
int cropY = (self.scrollView.contentOffset.y-imageView.frame.origin.y)/zoomScale;
You could use this crop tool that I made. It essentially gives you an interface to allow the user to select the crop area. I think it is in line with that you are looking for.
https://github.com/nicholjs/BFCropInterface
Believing you have solve this problem. Me too had this when tried cropping functionality
Set image.size as the imageView.size & scrollView.contentSize. Below code will give the rect to crop
cropRect.origin = scrollView.contentOffset;
cropRect.size = scrollView.bounds.size;
cropRect.origin.x /= scrollView.zoomScale;
cropRect.origin.y /= scrollView.zoomScale;
cropRect.size.width /= scrollView.zoomScale;
cropRect.size.height /= scrollView.zoomScale;
If planning to show the full image first on visible rect. Setting the imageView.size & scrollView.contentSize to visible view size will give crop image of some other area. Instead try finding the zoom scale by
CGFloat dxWidth = viewCrop.frame.size.width / imageView.image.size.width;
CGFloat dxHeight = viewCrop.frame.size.height / imageView.image.size.height;
CGFloat zoomScale = fmaxf(dWidth, dHeight)
and apply (if by adding subView then after addSubView)
scrollView.minimumZoomScale = zoomScale; // to disable further zoom-out
[scrollView setZoomScale: zoomScale];

Create UIImage from shadowed view while retaining alpha?

I have a somewhat unusual problem. In my app, I am shadowing a UIImageView using basic Quartz2d layer shadowing. Here's my code:
imageView.layer.shadowOpacity = 1.0; // Pretty self explanatory
imageView.layer.shadowRadius = 8.0; // My softness
imageView.layer.shadowColor = [UIColor blackColor].CGColor; // Color of the shadow
imageView.layer.shadowOffset = CGSizeMake(0.0, 0.0); // Offset of the shadow
This produces a nice blur behind the image view. However, I am doing some animation with this view, and the constant recalculation of the shadowing during the transitions causes a very choppy transition. What I'd like to be able to do is create a UIImage or .png file out of the image view with the blur and its alpha intact. Here's what I've already tried:
UIGraphicsBeginImageContext(CGSizeMake(320, 396));
[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);
Since I have a shadow which "grows outside" of the image view, I can't just pass his size in the UIGraphicsBeginImageContext function. I set the correct size, but the resulting image doesn't save my alpha, instead it places a white background behind the shadow, which won't work for me because my real background is a wood texture. Also, the view isn't centered in the resulting file.
I'm pretty good with UIKit, but I'm a real noobie with Quartz 2d graphics, so if there's an obvious answer to this, send it anyway. :)
Try setting your UIImageView's backgroundColor to [UIColor clearColor] - this may enable your current solution to work.
imageView.backgroundColor = [UIColor clearColor];
UIGraphicsBeginImageContext(CGSizeMake(320, 396));
[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Source: Converting a CGLayer to a *transparent* UIImage and PNG file in CoreGraphics iphone
I've had this issue before too. My solution was not to do an image, but instead to set the shadow path to just the outline of the view you are animating.
[imageView setContentMode:UIViewContentModeScaleAspectFit];
imageView.layer.masksToBounds = NO;
imageView.layer.shadowOffset = CGSizeMake(5, 5);
imageView.layer.shadowRadius = 200;
imageView.layer.shadowOpacity = 0.5;
CGRect rect = [self rectFromImageView:imageView];
imageView.layer.shadowPath = [UIBezierPath bezierPathWithRect:rect].CGPath;
Which uses the following function which assumes the image is set to content mode aspect fit:
-(CGRect)rectFromImageView:(UIImageView *)iv {
CGRect rect = (CGRect){{0,0},iv.frame.size};
if (iv.image.size.width/iv.frame.size.width > iv.image.size.height/iv.frame.size.height) {
//rect.origin.x == 0
CGFloat sf = iv.frame.size.width/iv.image.size.width;
rect.size.height = sf*iv.image.size.height;
rect.origin.y = floor((iv.frame.size.height - rect.size.height)/2);
} else {
//rect.origin.y == 0;
CGFloat sf = iv.frame.size.height/iv.image.size.height;
rect.size.width = sf*iv.image.size.width;
rect.origin.x = floor((iv.frame.size.width - rect.size.width)/2);
}
return rect;
}
If your image is just set to fill then just using the imageView.bounds should be sufficient
Add shadow path to view like this
[view.layer setShadowPath:[[UIBezierPath bezierPathWithRect:view.bounds] CGPath]]; //add path
view.layer.shadowColor = [[UIColor blackColor] CGColor];
view.layer.shadowOffset = CGSizeMake(x, y);
view.layer.shadowRadius = rad;
view.layer.shadowOpacity = 0.2f;

How to crop UIImage on oval shape or circle shape?

Please give ideas for how to crop UIImage on oval shape or circle shape. Please share your ideas.
#import <QuartzCore/QuartzCore.h>
CALayer *imageLayer = YourImageview.layer;
[imageLayer setCornerRadius:5];
[imageLayer setBorderWidth:1];
[imageLayer setMasksToBounds:YES];
by increasing radius it will become more round-able.
As long as the image is a square, you can get a perfect circle by taking half the width as the corner radius:
[imageView.layer setCornerRadius:imageView.frame.size.width/2];
You also need to add
[imageView.layer setMasksToBounds:YES];
Swift 4.2
import QuartzCore
var imageLayer: CALayer? = YourImageview.layer
imageLayer?.cornerRadius = 5
imageLayer?.borderWidth = 1
imageLayer?.masksToBounds = true
I started looking into this a couple of weeks back. I tried all the suggestions here, none of which worked well. In the great tradition of RTFM I went and read Apple's documentation on Quartz 2D Programming and came up with this. Please try it out and let me know how you go.
The code could be fairly easily altered to crop to an elipse, or any other shape defined by a path.
Make sure you include Quartz 2D in your project.
#include <math.h>
+ (UIImage*)circularScaleAndCropImage:(UIImage*)image frame:(CGRect)frame {
// This function returns a newImage, based on image, that has been:
// - scaled to fit in (CGRect) rect
// - and cropped within a circle of radius: rectWidth/2
//Create the bitmap graphics context
UIGraphicsBeginImageContextWithOptions(CGSizeMake(frame.size.width, frame.size.height), NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
//Get the width and heights
CGFloat imageWidth = image.size.width;
CGFloat imageHeight = image.size.height;
CGFloat rectWidth = frame.size.width;
CGFloat rectHeight = frame.size.height;
//Calculate the scale factor
CGFloat scaleFactorX = rectWidth/imageWidth;
CGFloat scaleFactorY = rectHeight/imageHeight;
//Calculate the centre of the circle
CGFloat imageCentreX = rectWidth/2;
CGFloat imageCentreY = rectHeight/2;
// Create and CLIP to a CIRCULAR Path
// (This could be replaced with any closed path if you want a different shaped clip)
CGFloat radius = rectWidth/2;
CGContextBeginPath (context);
CGContextAddArc (context, imageCentreX, imageCentreY, radius, 0, 2*M_PI, 0);
CGContextClosePath (context);
CGContextClip (context);
//Set the SCALE factor for the graphics context
//All future draw calls will be scaled by this factor
CGContextScaleCTM (context, scaleFactorX, scaleFactorY);
// Draw the IMAGE
CGRect myRect = CGRectMake(0, 0, imageWidth, imageHeight);
[image drawInRect:myRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Include the following code in your UIView class replacing "monk2.png" with your own image name.
- (void)drawRect:(CGRect)rect {
UIImage *originalImage = [UIImage imageNamed:[NSString stringWithFormat:#"monk2.png"]];
CGFloat oImageWidth = originalImage.size.width;
CGFloat oImageHeight = originalImage.size.height;
// Draw the original image at the origin
CGRect oRect = CGRectMake(0, 0, oImageWidth, oImageHeight);
[originalImage drawInRect:oRect];
// Set the newRect to half the size of the original image
CGRect newRect = CGRectMake(0, 0, oImageWidth/2, oImageHeight/2);
UIImage *newImage = [self circularScaleAndCropImage:originalImage frame:newRect];
CGFloat nImageWidth = newImage.size.width;
CGFloat nImageHeight = newImage.size.height;
//Draw the scaled and cropped image
CGRect thisRect = CGRectMake(oImageWidth+10, 0, nImageWidth, nImageHeight);
[newImage drawInRect:thisRect];
}
To have imageView in oval shape is not difficult.
You can do the following
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:yourImageView.bounds];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = path.CGPath;
yourImageView.layer.mask = maskLayer;
If the rect passed to bezierPathWithOvalInRect is Square the image will be cropped to circle.
Swift Code
let path = UIBezierPath(ovalIn: yourImageView.bounds)
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
yourImageView.layer.mask = maskLayer
To make a RoundShape Image
Step1: in .h file
#property (strong, nonatomic) IBOutlet UIImageView *songImage;
Step2: in .m file
- (void)viewDidLoad
{
self.songImage.layer.cornerRadius = self.songImage.frame.size.width / 2;
self.songImage.clipsToBounds = YES;
//To give the Border and Border color of imageview
self.songImage.layer.borderWidth = 1.0f;
self.songImage.layer.borderColor = [UIColor colorWithRed:249/255.0f green:117/255.0f blue:44/255.0f alpha:1.0f].CGColor;
}
OR For Swift
cell.songImage.layer.cornerRadius = cell.songImage.frame.size.width / 2;
cell.songImage.clipsToBounds = true
//To give the Border and Border color of imageview
cell.songImage.layer.borderWidth = 1.0
cell.songImage.layer.borderColor = UIColor(red: 50.0/255, green: 150.0/255, blue: 65.0/255, alpha: 1.0).CGColor
After a long search I found the correct way to circle the image
Download the Support archive file from URL http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/
#import "UIImage+RoundedCorner.h"
#import "UIImage+Resize.h"
Following lines used to resize the image and convert in to round with radius
UIImage *mask = [UIImage imageNamed:#"mask.jpg"];
mask = [mask resizedImage:CGSizeMake(47, 47) interpolationQuality:kCGInterpolationHigh ];
mask = [mask roundedCornerImage:23.5 borderSize:1];
SWIFT
var vwImage = UIImageView(image: UIImage(named: "Btn_PinIt_Normal.png"))
vwImage.frame = CGRectMake(0, 0, 100, 100)
vwImage.layer.cornerRadius = vwImage.frame.size.width/2
If you only need a perfect circle, changing the shape of the UIImageView could help.
Simply add the QuartzCore framework to your project and add these lines of code somewhere in the lifecycle before the imageView is displayed:
#import <QuartzCore/QuartzCore.h>
.
.
.
//to crop your UIImageView to show only a circle
yourImageView.layer.cornerRadius = yourImageView.frame.size.width/2;
yourImageView.clipsToBounds = YES;
Check out CGImageCreateWithMask. Create a mask of your oval shape, then apply it to the image.
you should refer This ...
// Create the image from a png file
UIImage *image = [UIImage imageNamed:#"prgBinary.jpg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// Get size of current image
CGSize size = [image size];
// Frame location in view to show original image
[imageView setFrame:CGRectMake(0, 0, size.width, size.height)];
[[self view] addSubview:imageView];
[imageView release];
// Create rectangle that represents a cropped image
// from the middle of the existing image
CGRect rect = CGRectMake(size.width / 4, size.height / 4 ,
(size.width / 2), (size.height / 2)); //oval logic goes here
// Create bitmap image from original image data,
// using rectangle to specify desired crop area
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], rect);
UIImage *img = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
// Create and show the new image from bitmap data
imageView = [[UIImageView alloc] initWithImage:img];
[imageView setFrame:CGRectMake(0, 200, (size.width / 2), (size.height / 2))];
[[self view] addSubview:imageView];
[imageView release];
SWIFT 3 answer comes from #Mohammad Sadiq
let path = UIBezierPath.init(ovalIn: workingImgaeView.bounds)
let maskLayer = CAShapeLayer(layer: layer)
maskLayer.path = path.cgPath
workingImgaeView.layer.mask = maskLayer
This should work,
Try pasting below code in viewDidLoad().
self.myImage.layer.cornerRadius = self.myImage.frame.size.width / 2;
self.myImage.clipsToBounds = YES;

Resources