// // 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