UIImage+Resize.m 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // UIImage+Resize.m
  2. // Created by Trevor Harmon on 8/5/09.
  3. // Free for personal or commercial use, with or without modification.
  4. // No warranty is expressed or implied.
  5. #import "UIImage+Resize.h"
  6. #import "UIImage+RoundedCorner.h"
  7. #import "UIImage+Alpha.h"
  8. // Private helper methods
  9. @interface UIImage (PrivateRoundedCorner)
  10. - (UIImage *)resizedImage:(CGSize)newSize
  11. transform:(CGAffineTransform)transform
  12. drawTransposed:(BOOL)transpose
  13. interpolationQuality:(CGInterpolationQuality)quality;
  14. - (CGAffineTransform)transformForOrientation:(CGSize)newSize;
  15. @end
  16. @implementation UIImage (Resize)
  17. // Returns a copy of this image that is cropped to the given bounds.
  18. // The bounds will be adjusted using CGRectIntegral.
  19. // This method ignores the image's imageOrientation setting.
  20. - (UIImage *)croppedImage:(CGRect)bounds {
  21. CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
  22. UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
  23. CGImageRelease(imageRef);
  24. return croppedImage;
  25. }
  26. // Returns a copy of this image that is squared to the thumbnail size.
  27. // If transparentBorder is non-zero, a transparent border of the given size will be added around the edges of the thumbnail. (Adding a transparent border of at least one pixel in size has the side-effect of antialiasing the edges of the image when rotating it using Core Animation.)
  28. - (UIImage *)thumbnailImage:(NSInteger)thumbnailSize
  29. transparentBorder:(NSUInteger)borderSize
  30. cornerRadius:(NSUInteger)cornerRadius
  31. interpolationQuality:(CGInterpolationQuality)quality {
  32. UIImage *resizedImage = [self resizedImageWithContentMode:UIViewContentModeScaleAspectFill
  33. bounds:CGSizeMake(thumbnailSize, thumbnailSize)
  34. interpolationQuality:quality];
  35. // Crop out any part of the image that's larger than the thumbnail size
  36. // The cropped rect must be centered on the resized image
  37. // Round the origin points so that the size isn't altered when CGRectIntegral is later invoked
  38. CGRect cropRect = CGRectMake(round((resizedImage.size.width - thumbnailSize) / 2),
  39. round((resizedImage.size.height - thumbnailSize) / 2),
  40. thumbnailSize,
  41. thumbnailSize);
  42. UIImage *croppedImage = [resizedImage croppedImage:cropRect];
  43. UIImage *transparentBorderImage = borderSize ? [croppedImage transparentBorderImage:borderSize] : croppedImage;
  44. return [transparentBorderImage roundedCornerImage:cornerRadius borderSize:borderSize];
  45. }
  46. // Returns a rescaled copy of the image, taking into account its orientation
  47. // The image will be scaled disproportionately if necessary to fit the bounds specified by the parameter
  48. - (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
  49. BOOL drawTransposed;
  50. switch (self.imageOrientation) {
  51. case UIImageOrientationLeft:
  52. case UIImageOrientationLeftMirrored:
  53. case UIImageOrientationRight:
  54. case UIImageOrientationRightMirrored:
  55. drawTransposed = YES;
  56. break;
  57. default:
  58. drawTransposed = NO;
  59. }
  60. return [self resizedImage:newSize
  61. transform:[self transformForOrientation:newSize]
  62. drawTransposed:drawTransposed
  63. interpolationQuality:quality];
  64. }
  65. // Resizes the image according to the given content mode, taking into account the image's orientation
  66. - (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode
  67. bounds:(CGSize)bounds
  68. interpolationQuality:(CGInterpolationQuality)quality {
  69. CGFloat horizontalRatio = bounds.width / self.size.width;
  70. CGFloat verticalRatio = bounds.height / self.size.height;
  71. CGFloat ratio;
  72. switch (contentMode) {
  73. case UIViewContentModeScaleAspectFill:
  74. ratio = MAX(horizontalRatio, verticalRatio);
  75. break;
  76. case UIViewContentModeScaleAspectFit:
  77. ratio = MIN(horizontalRatio, verticalRatio);
  78. break;
  79. default:
  80. [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %d", (int)contentMode];
  81. }
  82. CGSize newSize = CGSizeMake(roundf(self.size.width * ratio), roundf(self.size.height * ratio));
  83. return [self resizedImage:newSize interpolationQuality:quality];
  84. }
  85. #pragma mark -
  86. #pragma mark Private helper methods
  87. // Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size
  88. // The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation
  89. // If the new size is not integral, it will be rounded up
  90. - (UIImage *)resizedImage:(CGSize)newSize
  91. transform:(CGAffineTransform)transform
  92. drawTransposed:(BOOL)transpose
  93. interpolationQuality:(CGInterpolationQuality)quality {
  94. CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
  95. CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
  96. CGImageRef imageRef = self.CGImage;
  97. // Build a context that's the same dimensions as the new size
  98. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  99. CGContextRef bitmap = CGBitmapContextCreate(NULL,
  100. newRect.size.width,
  101. newRect.size.height,
  102. 8,
  103. 0,
  104. colorSpace,
  105. (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
  106. // Rotate and/or flip the image if required by its orientation
  107. CGContextConcatCTM(bitmap, transform);
  108. // Set the quality level to use when rescaling
  109. CGContextSetInterpolationQuality(bitmap, quality);
  110. // Draw into the context; this scales the image
  111. CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef);
  112. // Get the resized image from the context and a UIImage
  113. CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
  114. UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
  115. // Clean up
  116. CGContextRelease(bitmap);
  117. CGImageRelease(newImageRef);
  118. CGColorSpaceRelease(colorSpace);
  119. return newImage;
  120. }
  121. // Returns an affine transform that takes into account the image orientation when drawing a scaled image
  122. - (CGAffineTransform)transformForOrientation:(CGSize)newSize {
  123. CGAffineTransform transform = CGAffineTransformIdentity;
  124. switch (self.imageOrientation) {
  125. case UIImageOrientationDown: // EXIF = 3
  126. case UIImageOrientationDownMirrored: // EXIF = 4
  127. transform = CGAffineTransformTranslate(transform, newSize.width, newSize.height);
  128. transform = CGAffineTransformRotate(transform, M_PI);
  129. break;
  130. case UIImageOrientationLeft: // EXIF = 6
  131. case UIImageOrientationLeftMirrored: // EXIF = 5
  132. transform = CGAffineTransformTranslate(transform, newSize.width, 0);
  133. transform = CGAffineTransformRotate(transform, M_PI_2);
  134. break;
  135. case UIImageOrientationRight: // EXIF = 8
  136. case UIImageOrientationRightMirrored: // EXIF = 7
  137. transform = CGAffineTransformTranslate(transform, 0, newSize.height);
  138. transform = CGAffineTransformRotate(transform, -M_PI_2);
  139. break;
  140. default:
  141. break;
  142. }
  143. switch (self.imageOrientation) {
  144. case UIImageOrientationUpMirrored: // EXIF = 2
  145. case UIImageOrientationDownMirrored: // EXIF = 4
  146. transform = CGAffineTransformTranslate(transform, newSize.width, 0);
  147. transform = CGAffineTransformScale(transform, -1, 1);
  148. break;
  149. case UIImageOrientationLeftMirrored: // EXIF = 5
  150. case UIImageOrientationRightMirrored: // EXIF = 7
  151. transform = CGAffineTransformTranslate(transform, newSize.height, 0);
  152. transform = CGAffineTransformScale(transform, -1, 1);
  153. break;
  154. default:
  155. break;
  156. }
  157. return transform;
  158. }
  159. @end