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.
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
@return A new created decoded image
*/
+ (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
@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 {
return [self imageRefCreateDecoded:imageRef orientation:kCGImagePropertyOrientationUp];
}
+ (CGImageRef)imageRefCreateDecoded:(CGImageRef)imageRef orientation:(CGImagePropertyOrientation)orientation {
if (!imageRef) {
return NULL;
}
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
if (width == 0 || height == 0) return NULL;
CGRect rect = CGRectMake(0, 0, width, height);
BOOL hasAlpha = [self imageRefContainsAlpha:imageRef];
// 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`
@ -265,6 +268,25 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
if (!context) {
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);
CGImageRef newImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
@ -546,7 +568,60 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
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) {
NSUInteger c;
while (a != 0) {