Add helper method in coder helper to create decoded CGImage to specify orientation. The existing method just call with Up orientation

This commit is contained in:
DreamPiggy 2018-04-10 20:44:26 +08:00
parent b9ec481edf
commit acbdb8c374
2 changed files with 87 additions and 1 deletions

View File

@ -61,12 +61,23 @@
/** /**
Create a decoded image by the provided image. This follows The Create Rule and you are response to call release after usage. Create a decoded image by the provided image. This follows The Create Rule and you are response to call release after usage.
It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView. It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView.
@note This actually call `imageRefCreateDecoded:orientation` with the Up orientation.
@param imageRef The CGImage @param imageRef The CGImage
@return A new created decoded image @return A new created decoded image
*/ */
+ (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef CF_RETURNS_RETAINED; + (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef CF_RETURNS_RETAINED;
/**
Create a decoded image by the provided image. This follows The Create Rule and you are response to call release after usage.
It will detect whether image contains alpha channel, then create a new bitmap context with the same size of image, and draw it. This can ensure that the image do not need extra decoding after been set to the imageView.
@param imageRef The CGImage
@param orientation The image orientation.
@return A new created decoded image
*/
+ (CGImageRef _Nullable)imageRefCreateDecoded:(_Nonnull CGImageRef)imageRef orientation:(CGImagePropertyOrientation)orientation CF_RETURNS_RETAINED;
/** /**
Return the decoded image by the provided image. This one unlike `imageRefCreateDecoded:`, will not decode the image which contains alpha channel or animated image Return the decoded image by the provided image. This one unlike `imageRefCreateDecoded:`, will not decode the image which contains alpha channel or animated image
@param image The image to be decoded @param image The image to be decoded

View File

@ -248,13 +248,16 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
} }
+ (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef { + (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef {
return [self imageRefCreateDecoded:imageRef orientation:kCGImagePropertyOrientationUp];
}
+ (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef orientation:(CGImagePropertyOrientation)orientation {
if (!imageRef) { if (!imageRef) {
return NULL; return NULL;
} }
size_t width = CGImageGetWidth(imageRef); size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef); size_t height = CGImageGetHeight(imageRef);
if (width == 0 || height == 0) return NULL; if (width == 0 || height == 0) return NULL;
CGRect rect = CGRectMake(0, 0, width, height);
BOOL hasAlpha = [self imageRefContainsAlpha:imageRef]; BOOL hasAlpha = [self imageRefContainsAlpha:imageRef];
// iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]` // iOS prefer BGRA8888 (premultiplied) or BGRX8888 bitmapInfo for screen rendering, which is same as `UIGraphicsBeginImageContext()` or `- [CALayer drawInContext:]`
// Through you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage` // Through you can use any supported bitmapInfo (see: https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB ) and let Core Graphics reorder it when you call `CGContextDrawImage`
@ -265,6 +268,25 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
if (!context) { if (!context) {
return NULL; return NULL;
} }
// Apply transform
CGAffineTransform transform = SDCGContextTransformFromOrientation(orientation, CGSizeMake(width, height));
CGRect rect;
switch (orientation) {
case kCGImagePropertyOrientationLeft:
case kCGImagePropertyOrientationLeftMirrored:
case kCGImagePropertyOrientationRight:
case kCGImagePropertyOrientationRightMirrored: {
// These orientation should swap width & height
rect = CGRectMake(0, 0, height, width);
}
break;
default: {
rect = CGRectMake(0, 0, width, height);
}
break;
}
CGContextConcatCTM(context, transform);
CGContextDrawImage(context, rect, imageRef); CGContextDrawImage(context, rect, imageRef);
CGImageRef newImageRef = CGBitmapContextCreateImage(context); CGImageRef newImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context); CGContextRelease(context);
@ -546,7 +568,60 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
return shouldScaleDown; return shouldScaleDown;
} }
#endif
static CGAffineTransform SDCGContextTransformFromOrientation(CGImagePropertyOrientation orientation, CGSize size) {
// Inspiration from @libfeihu
// 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 (orientation) {
case kCGImagePropertyOrientationDown:
case kCGImagePropertyOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, size.width, size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case kCGImagePropertyOrientationLeft:
case kCGImagePropertyOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case kCGImagePropertyOrientationRight:
case kCGImagePropertyOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, 0, size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
case kCGImagePropertyOrientationUp:
case kCGImagePropertyOrientationUpMirrored:
break;
}
switch (orientation) {
case kCGImagePropertyOrientationUpMirrored:
case kCGImagePropertyOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, size.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case kCGImagePropertyOrientationLeftMirrored:
case kCGImagePropertyOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, size.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case kCGImagePropertyOrientationUp:
case kCGImagePropertyOrientationDown:
case kCGImagePropertyOrientationLeft:
case kCGImagePropertyOrientationRight:
break;
}
return transform;
}
#if SD_UIKIT || SD_WATCH
static NSUInteger gcd(NSUInteger a, NSUInteger b) { static NSUInteger gcd(NSUInteger a, NSUInteger b) {
NSUInteger c; NSUInteger c;
while (a != 0) { while (a != 0) {