Advertisement
Guest User

UIImage+ImageEffects

a guest
Jul 26th, 2013
8,332
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //
  2. //  UIImage+ImageEffects.m
  3. //  AnimationExamples
  4. //
  5. //  Created by Timothy Patrick Johnson on 7/3/13.
  6. //  Copyright (c) 2013 Meister. All rights reserved.
  7. //
  8.  
  9. #import "UIImage+ImageEffects.h"
  10.  
  11. #import <Accelerate/Accelerate.h>
  12. #import <float.h>
  13.  
  14.  
  15. @implementation UIImage (ImageEffects)
  16.  
  17.  
  18. - (UIImage *)applyLightEffect
  19. {
  20.     UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
  21.     return [self applyBlurWithRadius:7 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
  22. }
  23.  
  24.  
  25. - (UIImage *)applyExtraLightEffect
  26. {
  27.     UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82];
  28.     return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
  29. }
  30.  
  31.  
  32. - (UIImage *)applyDarkEffect
  33. {
  34.     UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73];
  35.     return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
  36. }
  37.  
  38.  
  39. - (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor
  40. {
  41.     const CGFloat EffectColorAlpha = 0.6;
  42.     UIColor *effectColor = tintColor;
  43.     int componentCount = CGColorGetNumberOfComponents(tintColor.CGColor);
  44.     if (componentCount == 2) {
  45.         CGFloat b;
  46.         if ([tintColor getWhite:&b alpha:NULL]) {
  47.             effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
  48.         }
  49.     }
  50.     else {
  51.         CGFloat r, g, b;
  52.         if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
  53.             effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
  54.         }
  55.     }
  56.     return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil];
  57. }
  58.  
  59.  
  60. - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage
  61. {
  62.     // Check pre-conditions.
  63.     if (self.size.width < 1 || self.size.height < 1) {
  64.         NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
  65.         return nil;
  66.     }
  67.     if (!self.CGImage) {
  68.         NSLog (@"*** error: image must be backed by a CGImage: %@", self);
  69.         return nil;
  70.     }
  71.     if (maskImage && !maskImage.CGImage) {
  72.         NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage);
  73.         return nil;
  74.     }
  75.    
  76.     CGRect imageRect = { CGPointZero, self.size };
  77.     UIImage *effectImage = self;
  78.    
  79.     BOOL hasBlur = blurRadius > __FLT_EPSILON__;
  80.     BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__;
  81.     if (hasBlur || hasSaturationChange) {
  82.         UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
  83.         CGContextRef effectInContext = UIGraphicsGetCurrentContext();
  84.         CGContextScaleCTM(effectInContext, 1.0, -1.0);
  85.         CGContextTranslateCTM(effectInContext, 0, -self.size.height);
  86.         CGContextDrawImage(effectInContext, imageRect, self.CGImage);
  87.        
  88.         vImage_Buffer effectInBuffer;
  89.         effectInBuffer.data     = CGBitmapContextGetData(effectInContext);
  90.         effectInBuffer.width    = CGBitmapContextGetWidth(effectInContext);
  91.         effectInBuffer.height   = CGBitmapContextGetHeight(effectInContext);
  92.         effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext);
  93.        
  94.         UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
  95.         CGContextRef effectOutContext = UIGraphicsGetCurrentContext();
  96.         vImage_Buffer effectOutBuffer;
  97.         effectOutBuffer.data     = CGBitmapContextGetData(effectOutContext);
  98.         effectOutBuffer.width    = CGBitmapContextGetWidth(effectOutContext);
  99.         effectOutBuffer.height   = CGBitmapContextGetHeight(effectOutContext);
  100.         effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext);
  101.        
  102.         if (hasBlur) {
  103.             // A description of how to compute the box kernel width from the Gaussian
  104.             // radius (aka standard deviation) appears in the SVG spec:
  105.             // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
  106.             //
  107.             // For larger values of 's' (s >= 2.0), an approximation can be used: Three
  108.             // successive box-blurs build a piece-wise quadratic convolution kernel, which
  109.             // approximates the Gaussian kernel to within roughly 3%.
  110.             //
  111.             // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
  112.             //
  113.             // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel.
  114.             //
  115.             CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale];
  116.             NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5);
  117.             if (radius % 2 != 1) {
  118.                 radius += 1; // force radius to be odd so that the three box-blur methodology works.
  119.             }
  120.             vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
  121.             vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
  122.             vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend);
  123.         }
  124.         BOOL effectImageBuffersAreSwapped = NO;
  125.         if (hasSaturationChange) {
  126.             CGFloat s = saturationDeltaFactor;
  127.             CGFloat floatingPointSaturationMatrix[] = {
  128.                 0.0722 + 0.9278 * s,  0.0722 - 0.0722 * s,  0.0722 - 0.0722 * s,  0,
  129.                 0.7152 - 0.7152 * s,  0.7152 + 0.2848 * s,  0.7152 - 0.7152 * s,  0,
  130.                 0.2126 - 0.2126 * s,  0.2126 - 0.2126 * s,  0.2126 + 0.7873 * s,  0,
  131.                 0,                    0,                    0,  1,
  132.             };
  133.             const int32_t divisor = 256;
  134.             NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]);
  135.             int16_t saturationMatrix[matrixSize];
  136.             for (NSUInteger i = 0; i < matrixSize; ++i) {
  137.                 saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor);
  138.             }
  139.             if (hasBlur) {
  140.                 vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
  141.                 effectImageBuffersAreSwapped = YES;
  142.             }
  143.             else {
  144.                 vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
  145.             }
  146.         }
  147.         if (!effectImageBuffersAreSwapped)
  148.             effectImage = UIGraphicsGetImageFromCurrentImageContext();
  149.         UIGraphicsEndImageContext();
  150.        
  151.         if (effectImageBuffersAreSwapped)
  152.             effectImage = UIGraphicsGetImageFromCurrentImageContext();
  153.         UIGraphicsEndImageContext();
  154.     }
  155.    
  156.     // Set up output context.
  157.     UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
  158.     CGContextRef outputContext = UIGraphicsGetCurrentContext();
  159.     CGContextScaleCTM(outputContext, 1.0, -1.0);
  160.     CGContextTranslateCTM(outputContext, 0, -self.size.height);
  161.    
  162.     // Draw base image.
  163.     CGContextDrawImage(outputContext, imageRect, self.CGImage);
  164.    
  165.     // Draw effect image.
  166.     if (hasBlur) {
  167.         CGContextSaveGState(outputContext);
  168.         if (maskImage) {
  169.             CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
  170.         }
  171.         CGContextDrawImage(outputContext, imageRect, effectImage.CGImage);
  172.         CGContextRestoreGState(outputContext);
  173.     }
  174.    
  175.     // Add in color tint.
  176.     if (tintColor) {
  177.         CGContextSaveGState(outputContext);
  178.         CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
  179.         CGContextFillRect(outputContext, imageRect);
  180.         CGContextRestoreGState(outputContext);
  181.     }
  182.    
  183.     // Output image is ready.
  184.     UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
  185.     UIGraphicsEndImageContext();
  186.    
  187.     return outputImage;
  188. }
  189. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement