123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- //
- // UIImage+YMCameraManager.m
- // MSYOUPAI
- //
- // Created by YoMi on 2024/3/17.
- // Copyright © 2024 MS. All rights reserved.
- //
- #import "UIImage+YMCameraManager.h"
- @implementation UIImage (YMCameraManager)
- // This method ignores the image's imageOrientation setting.
- - (UIImage *)croppedImage:(CGRect)bounds {
- CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
- UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
- CGImageRelease(imageRef);
- return croppedImage;
- }
- - (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
- BOOL drawTransposed;
- CGAffineTransform transform = CGAffineTransformIdentity;
-
- if([[[UIDevice currentDevice]systemVersion]floatValue] >= 5.0) {
- drawTransposed = YES;
- }
- else {
- switch(self.imageOrientation) {
- case UIImageOrientationLeft:
- case UIImageOrientationLeftMirrored:
- case UIImageOrientationRight:
- case UIImageOrientationRightMirrored:
- drawTransposed = YES;
- break;
- default:
- drawTransposed = NO;
- }
-
- transform = [self transformForOrientation:newSize];
- }
- transform = [self transformForOrientation:newSize];
- return [self resizedImage:newSize transform:transform drawTransposed:drawTransposed interpolationQuality:quality];
- }
- // Resizes the image according to the given content mode, taking into account the image's orientation
- - (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode
- bounds:(CGSize)bounds
- interpolationQuality:(CGInterpolationQuality)quality {
- CGFloat horizontalRatio = bounds.width / self.size.width;
- CGFloat verticalRatio = bounds.height / self.size.height;
- CGFloat ratio;
-
- switch(contentMode) {
- case UIViewContentModeScaleAspectFill:
- ratio = MAX(horizontalRatio, verticalRatio);
- break;
-
- case UIViewContentModeScaleAspectFit:
- ratio = MIN(horizontalRatio, verticalRatio);
- break;
-
- default:
- [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %ld", (long)contentMode];
- }
-
- CGSize newSize = CGSizeMake(self.size.width * ratio, self.size.height * ratio);
-
- return [self resizedImage:newSize interpolationQuality:quality];
- }
- #pragma mark - fix orientation
- - (UIImage *)fixOrientation {
-
- // No-op if the orientation is already correct
- 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:
- // Grr...
- 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;
- }
-
- // And now we just create a new UIImage from the drawing context
- CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
- UIImage *img = [UIImage imageWithCGImage:cgimg];
- CGContextRelease(ctx);
- CGImageRelease(cgimg);
- return img;
- }
- - (UIImage *)rotatedByDegrees:(CGFloat)degrees
- {
- // 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(DegreesToRadians(degrees));
- rotatedViewBox.transform = t;
- CGSize rotatedSize = rotatedViewBox.frame.size;
- // 传入的View.frame.size是0的话,直接返回nil,防止 UIGraphicsBeginImageContext() 传入0,导致崩溃
- if (CGSizeEqualToSize(rotatedSize, CGSizeZero)) {
- return nil;
- }
- // 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, DegreesToRadians(degrees));
-
- // 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;
-
-
- }
- #pragma mark - Private helper methods
- // Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size
- // The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation
- // If the new size is not integral, it will be rounded up
- - (UIImage *)resizedImage:(CGSize)newSize
- transform:(CGAffineTransform)transform
- drawTransposed:(BOOL)transpose
- interpolationQuality:(CGInterpolationQuality)quality {
- CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
- CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
- CGImageRef imageRef = self.CGImage;
-
- // Fix for a colorspace / transparency issue that affects some types of
- // images. See here: http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/comment-page-2/#comment-39951
-
- CGContextRef bitmap = CGBitmapContextCreate(NULL,
- newRect.size.width,
- newRect.size.height,
- 8,
- 0,
- CGImageGetColorSpace(imageRef),
- kCGImageAlphaNoneSkipLast);
-
- // Rotate and/or flip the image if required by its orientation
- CGContextConcatCTM(bitmap, transform);
-
- // Set the quality level to use when rescaling
- CGContextSetInterpolationQuality(bitmap, quality);
-
- // Draw into the context; this scales the image
- CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef);
-
- // Get the resized image from the context and a UIImage
- CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
- UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
-
- // Clean up
- CGContextRelease(bitmap);
- CGImageRelease(newImageRef);
-
- return newImage;
- }
- // Returns an affine transform that takes into account the image orientation when drawing a scaled image
- - (CGAffineTransform)transformForOrientation:(CGSize)newSize {
- CGAffineTransform transform = CGAffineTransformIdentity;
-
- switch(self.imageOrientation) {
- case UIImageOrientationDown: // EXIF = 3
- case UIImageOrientationDownMirrored: // EXIF = 4
- transform = CGAffineTransformTranslate(transform, newSize.width, newSize.height);
- transform = CGAffineTransformRotate(transform, M_PI);
- break;
-
- case UIImageOrientationLeft: // EXIF = 6
- case UIImageOrientationLeftMirrored: // EXIF = 5
- transform = CGAffineTransformTranslate(transform, newSize.width, 0);
- transform = CGAffineTransformRotate(transform, M_PI_2);
- break;
-
- case UIImageOrientationRight: // EXIF = 8
- case UIImageOrientationRightMirrored: // EXIF = 7
- transform = CGAffineTransformTranslate(transform, 0, newSize.height);
- transform = CGAffineTransformRotate(transform, -M_PI_2);
- break;
- default:
- break;
- }
-
- switch(self.imageOrientation) {
- case UIImageOrientationUpMirrored: // EXIF = 2
- case UIImageOrientationDownMirrored: // EXIF = 4
- transform = CGAffineTransformTranslate(transform, newSize.width, 0);
- transform = CGAffineTransformScale(transform, -1, 1);
- break;
-
- case UIImageOrientationLeftMirrored: // EXIF = 5
- case UIImageOrientationRightMirrored: // EXIF = 7
- transform = CGAffineTransformTranslate(transform, newSize.height, 0);
- transform = CGAffineTransformScale(transform, -1, 1);
- break;
- default:
- break;
- }
-
- return transform;
- }
- @end
|