在处理照片的时候,最多的情况就是对UIImage进行处理。虽然UIImage使用起来比较简单,但是我们在需要处理各种繁杂需求的时候,UIImage不是都提供了相关效果的实现。很多时候需要我们自己来实现比较复杂的处理。比如,相机拍摄的图片带有方向,有时候你会发现通过 CGImageGetWidth
,CGImageGetHeight
获取宽高相反,或者上传的图片,在安卓上方向不对,这时候就需要纠正图片的方向。因此,常备一些分类是很有必要的,以下在开发的过程中,一些常见的UIImage的处理分类。
判断图片是否有Alpha通道
- (BOOL)hasAlpha
{
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
return (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
}
获取图片的元数据
- (NSData *)ARGBData
{
CGContextRef cgctx = CreateARGBBitmapContextWithCGImage(self.CGImage);
if (cgctx == NULL) {
return nil;
}
size_t w = CGImageGetWidth(self.CGImage);
size_t h = CGImageGetHeight(self.CGImage);
CGRect rect = {{0,0},{w,h}};
CGContextDrawImage(cgctx, rect, self.CGImage);
void *data = CGBitmapContextGetData (cgctx);
CGContextRelease(cgctx);
if (!data) {
return nil;
}
size_t dataSize = 4 * w * h; // ARGB = 4 8-bit components
return [NSData dataWithBytes:data length:dataSize];
}
图片的某一点是否透明
- (BOOL)isPointTransparent:(CGPoint)point
{
NSData *rawData = [self ARGBData]; // See about caching this
if (rawData == nil) {
return NO;
}
size_t bitPerPoint = 4;//每个像素有4位
size_t bitPerRow = self.size.width * 4; //每一行的像素
NSUInteger index = point.x * bitPerPoint + (point.y * bitPerRow);
char *rawDataBytes = ( char *)[rawData bytes];
return rawDataBytes[index] == 0;
}
根据颜色生成图片
+ (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;
}
获取灰度图
- (UIImage *)grayImage
{
int width = self.size.width;
int height = self.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), self.CGImage);
CGImageRef contextRef = CGBitmapContextCreateImage(context);
UIImage *grayImage = [UIImage imageWithCGImage:contextRef];
CGContextRelease(context);
CGImageRelease(contextRef);
return grayImage;
}
取图片某像素点的颜色
- (UIColor *)colorAtPixel:(CGPoint)point
{
if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, self.size.width, self.size.height), point))
{
return nil;
}
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);
CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height);
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage);
CGContextRelease(context);
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];
}
圆角绘制
- (UIImage *)imageWithConrnerWithRadius:(CGFloat)radius sizeToFit:(CGSize)size
{
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContextWithOptions(rect.size, false, [UIScreen mainScreen].scale);
CGContextAddPath(UIGraphicsGetCurrentContext(), [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radius, radius)].CGPath);
CGContextClip(UIGraphicsGetCurrentContext());
[self drawInRect:rect];
CGContextDrawPath(UIGraphicsGetCurrentContext(), kCGPathFillStroke);
UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return output;
}
纠正图片的方向
- (UIImage *)fixOrientation
{
if (self.imageOrientation == UIImageOrientationUp) return self;
// 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 (self.imageOrientation)
{
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, 0, self.size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
break;
}
switch (self.imageOrientation)
{
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, self.size.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationUp:
case UIImageOrientationDown:
case UIImageOrientationLeft:
case UIImageOrientationRight:
break;
}
// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
CGImageGetBitsPerComponent(self.CGImage), 0,
CGImageGetColorSpace(self.CGImage),
CGImageGetBitmapInfo(self.CGImage));
CGContextConcatCTM(ctx, transform);
switch (self.imageOrientation)
{
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
break;
default:
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
break;
}
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
UIImage *img = [UIImage imageWithCGImage:cgimg];
CGContextRelease(ctx);
CGImageRelease(cgimg);
return img;
}
按给定的方向旋转图片
- (UIImage*)rotate:(UIImageOrientation)orient
{
CGRect bnds = CGRectZero;
UIImage* copy = nil;
CGContextRef ctxt = nil;
CGImageRef imag = self.CGImage;
CGRect rect = CGRectZero;
CGAffineTransform tran = CGAffineTransformIdentity;
rect.size.width = CGImageGetWidth(imag);
rect.size.height = CGImageGetHeight(imag);
bnds = rect;
switch (orient)
{
case UIImageOrientationUp:
return self;
case UIImageOrientationUpMirrored:
tran = CGAffineTransformMakeTranslation(rect.size.width, 0.0);
tran = CGAffineTransformScale(tran, -1.0, 1.0);
break;
case UIImageOrientationDown:
tran = CGAffineTransformMakeTranslation(rect.size.width,
rect.size.height);
tran = CGAffineTransformRotate(tran, M_PI);
break;
case UIImageOrientationDownMirrored:
tran = CGAffineTransformMakeTranslation(0.0, rect.size.height);
tran = CGAffineTransformScale(tran, 1.0, -1.0);
break;
case UIImageOrientationLeft:
bnds = swapWidthAndHeight(bnds);
tran = CGAffineTransformMakeTranslation(0.0, rect.size.width);
tran = CGAffineTransformRotate(tran, 3.0 * M_PI / 2.0);
break;
case UIImageOrientationLeftMirrored:
bnds = swapWidthAndHeight(bnds);
tran = CGAffineTransformMakeTranslation(rect.size.height,
rect.size.width);
tran = CGAffineTransformScale(tran, -1.0, 1.0);
tran = CGAffineTransformRotate(tran, 3.0 * M_PI / 2.0);
break;
case UIImageOrientationRight:
bnds = swapWidthAndHeight(bnds);
tran = CGAffineTransformMakeTranslation(rect.size.height, 0.0);
tran = CGAffineTransformRotate(tran, M_PI / 2.0);
break;
case UIImageOrientationRightMirrored:
bnds = swapWidthAndHeight(bnds);
tran = CGAffineTransformMakeScale(-1.0, 1.0);
tran = CGAffineTransformRotate(tran, M_PI / 2.0);
break;
default:
return self;
}
UIGraphicsBeginImageContext(bnds.size);
ctxt = UIGraphicsGetCurrentContext();
switch (orient)
{
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
CGContextScaleCTM(ctxt, -1.0, 1.0);
CGContextTranslateCTM(ctxt, -rect.size.height, 0.0);
break;
default:
CGContextScaleCTM(ctxt, 1.0, -1.0);
CGContextTranslateCTM(ctxt, 0.0, -rect.size.height);
break;
}
CGContextConcatCTM(ctxt, tran);
CGContextDrawImage(UIGraphicsGetCurrentContext(), rect, imag);
copy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return copy;
}
垂直翻转
- (UIImage *)flipVertical
{
return [self rotate:UIImageOrientationDownMirrored];
}
水平翻转
- (UIImage *)flipHorizontal
{
return [self rotate:UIImageOrientationUpMirrored];
}
将图片旋转一定弧度
- (UIImage *)imageRotatedByRadians:(CGFloat)radians
{
// 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(radians);
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, radians);
// 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;
}
将图片旋转一定角度
- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees
{
return [self imageRotatedByRadians:kDegreesToRadian(degrees)];
}
图片加马赛克
- (UIImage *)mosaicImageWithLevel:(int)level
{
CIContext *context = [CIContext contextWithOptions:nil];
CIFilter *filter= [CIFilter filterWithName:@"CIPixellate"];
CIImage *inputImage = [CIImage imageWithCGImage:self.CGImage];
CIVector *vector = [CIVector vectorWithX:self.size.width /2.0f Y:self.size.height /2.0f];
[filter setDefaults];
[filter setValue:vector forKey:@"inputCenter"];
[filter setValue:[NSNumber numberWithDouble:level] forKey:@"inputScale"];
[filter setValue:inputImage forKey:@"inputImage"];
CGImageRef cgiimage = [context createCGImage:filter.outputImage fromRect:filter.outputImage.extent];
UIImage *newImage = [UIImage imageWithCGImage:cgiimage scale:self.scale orientation:self.imageOrientation];
CGImageRelease(cgiimage);
return newImage;
}
图片混合裁剪
+ (UIImage *)clipImage:(UIImage *)aImage CGBlendMode:(int)type;
+ (UIImage *)clipImage:(UIImage *)image withRect:(CGRect)rect;
+ (UIImage *)cropImage:(UIImage *)image
frame:(CGRect)frame
angle:(NSInteger)angle
circularClip:(BOOL)circular;
+ (UIImage *)clipImage:(UIImage *)aImage CGBlendMode:(int)type
{
CGContextRef context = CreateRGBABitmapContextWithCGImage(aImage.CGImage);
if (context == NULL) {
return nil;
}
size_t w = CGImageGetWidth(aImage.CGImage);
size_t h = CGImageGetHeight(aImage.CGImage);
CGRect rect = {{0, 0}, {w, h}};
CGContextSetBlendMode(context, type);
CGContextDrawImage(context, rect, aImage.CGImage);
CGImageRef aCGImage = CGBitmapContextCreateImage(context);
UIImage *newImage = [UIImage imageWithCGImage:aCGImage];
CGImageRelease(aCGImage);
CGContextRelease(context);
return newImage;
}
+ (UIImage *)clipImage:(UIImage *)image withRect:(CGRect)rect
{
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, rect);
UIImage *tmpImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return tmpImage;
}
+ (UIImage *)cropImage:(UIImage *)image
frame:(CGRect)frame
angle:(NSInteger)angle
circularClip:(BOOL)circular
{
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image.CGImage);
BOOL hasAlpha = (alphaInfo == kCGImageAlphaFirst || alphaInfo == kCGImageAlphaLast ||
alphaInfo == kCGImageAlphaPremultipliedFirst || alphaInfo == kCGImageAlphaPremultipliedLast);
UIImage *croppedImage = nil;
UIGraphicsBeginImageContextWithOptions(frame.size, !hasAlpha && !circular, [UIScreen mainScreen].scale);
{
CGContextRef context = UIGraphicsGetCurrentContext();
if (circular) {
CGContextAddEllipseInRect(context, (CGRect){CGPointZero, frame.size});
CGContextClip(context);
}
//To conserve memory in not needing to completely re-render the image re-rotated,
//map the image to a view and then use Core Animation to manipulate its rotation
if (angle != 0) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.layer.minificationFilter = kCAFilterNearest;
imageView.layer.magnificationFilter = kCAFilterNearest;
imageView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, angle * (M_PI/180.0f));
CGRect rotatedRect = CGRectApplyAffineTransform(imageView.bounds, imageView.transform);
UIView *containerView = [[UIView alloc] initWithFrame:(CGRect){CGPointZero, rotatedRect.size}];
[containerView addSubview:imageView];
imageView.center = containerView.center;
CGContextTranslateCTM(context, -frame.origin.x, -frame.origin.y);
[containerView.layer renderInContext:context];
}
else {
CGContextTranslateCTM(context, -frame.origin.x, -frame.origin.y);
[image drawAtPoint:CGPointZero];
}
croppedImage = UIGraphicsGetImageFromCurrentImageContext();
}
UIGraphicsEndImageContext();
return [UIImage imageWithCGImage:croppedImage.CGImage scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
}
图片模糊
// 图片的高斯模糊
- (UIImage *)gaussianBlurImageWithLevel:(CGFloat)blur
{
CIImage *inputImage = [CIImage imageWithCGImage:self.CGImage];
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur" keysAndValues:kCIInputImageKey, inputImage, @"inputRadius", @(blur), nil];
CIImage *outputImage = filter.outputImage;
CGImageRef outImage = [[CIContext contextWithOptions:nil] createCGImage:outputImage
fromRect:[outputImage extent]];
UIImage *image = [UIImage imageWithCGImage:outImage];
CGImageRelease(outImage);
return image;
}
// Box Blur
+ (UIImage *)boxBlurImage:(UIImage *)image withLevel:(CGFloat)level
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 5.0 ) {
return nil;
}
CFAbsoluteTime t0 = CFAbsoluteTimeGetCurrent();
if ((level < 0.0f) || (level > 1.0f)) {
level = 0.5f;
}
int boxSize = (int)(level * 100);
boxSize -= (boxSize % 2) + 1;
CGImageRef img = image.CGImage;
vImage_Buffer inBuffer, outBuffer;
vImage_Error error;
void *pixelBuffer;
CGDataProviderRef inProvider = CGImageGetDataProvider(img);
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
inBuffer.width = CGImageGetWidth(img);
inBuffer.height = CGImageGetHeight(img);
inBuffer.rowBytes = CGImageGetBytesPerRow(img);
inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
outBuffer.data = pixelBuffer;
outBuffer.width = CGImageGetWidth(img);
outBuffer.height = CGImageGetHeight(img);
outBuffer.rowBytes = CGImageGetBytesPerRow(img);
error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL,
0, 0, boxSize, boxSize, NULL,
kvImageEdgeExtend);
if (error) {
NSLog(@"error from convolution %ld", error);
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(
outBuffer.data,
outBuffer.width,
outBuffer.height,
8,
outBuffer.rowBytes,
colorSpace,
CGImageGetBitmapInfo(image.CGImage));
CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
//clean
CGContextRelease(ctx);
CGColorSpaceRelease(colorSpace);
free(pixelBuffer);
CFRelease(inBitmapData);
CGImageRelease(imageRef);
CFAbsoluteTime t1 = CFAbsoluteTimeGetCurrent();
NSLog(@"boxBlurTime=%f", t1-t0);
return returnImage;
}
UIImage分类地址
UIImage的分类还有很多,这里只是列举了一部分,具体可到我的github上面查看
https://github.com/QinminiOS/GPUImage/tree/master/UIImage%2B
网友评论