Update the NSImage+Addtions to allow specify a image orientation when using `CGImage`. Update all the place we use

This commit is contained in:
DreamPiggy 2018-04-10 21:18:53 +08:00
parent acbdb8c374
commit 7d50d61b37
12 changed files with 103 additions and 44 deletions

View File

@ -32,7 +32,7 @@
self.imageView3.animates = YES;
self.imageView4.animates = YES;
self.imageView1.sd_imageIndicator = SDWebImageProgressIndicator.defaultIndicator;
[self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage001.jpg"]];
[self.imageView1 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/recurser/exif-orientation-examples/master/Landscape_2.jpg"] placeholderImage:nil options:SDWebImageProgressiveDownload];
[self.imageView2 sd_setImageWithURL:[NSURL URLWithString:@"https:raw.githubusercontent.com/onevcat/APNGKit/master/TestImages/APNG-cube.apng"]];
[self.imageView3 sd_setImageWithURL:[NSURL URLWithString:@"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif"]];
self.imageView4.wantsLayer = YES;

View File

@ -19,21 +19,23 @@ The underlying Core Graphics image object. This will actually `CGImageForPropose
*/
@property (nonatomic, readonly, nullable) CGImageRef CGImage;
/**
The scale factor of the image. This wil actually use image size, and its `CGImage`'s pixel size to calculate the scale factor. Should be greater than or equal to 1.0.
The scale factor of the image. This wil actually use bitmap representation's size and pixel size to calculate the scale factor. If failed, use the default value 1.0. Should be greater than or equal to 1.0.
*/
@property (nonatomic, readonly) CGFloat scale;
// These are convenience methods to make AppKit's `NSImage` match UIKit's `UIImage` behavior. The scale factor should be greater than or equal to 1.0.
/**
Returns an image object with the scale factor. The representation is created from the Core Graphics image object.
Returns an image object with the scale factor and orientation. The representation is created from the Core Graphics image object.
@note The difference between this and `initWithCGImage:size` is that `initWithCGImage:size` will create a `NSCGImageSnapshotRep` but not `NSBitmapImageRep` instance. And it will always `backingScaleFactor` as scale factor.
@note If the provided image orientation is not equal to Up orientation. This method will firstly rotate the CGImage to the correct orientation to work compatible with `NSImageView`.
@param cgImage A Core Graphics image object
@param scale The image scale factor
@param orientation The orientation of the image data
@return The image object
*/
- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale;
- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation;
/**
Returns an image object with the scale factor. The representation is created from the image data.
@ -49,8 +51,11 @@ The underlying Core Graphics image object. This will actually `CGImageForPropose
@interface NSBitmapImageRep (Additions)
// These method's function is the same as `NSImage`'s function. For `NSBitmapImageRep`.
- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale;
// These methods' function is the same as `NSImage`'s function. For `NSBitmapImageRep`.
@property (nonatomic, readonly) CGFloat scale;
- (nonnull instancetype)initWithCGImage:(nonnull CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation;
- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale;
@end

View File

@ -10,6 +10,9 @@
#if SD_MAC
#import "SDWebImageCoderHelper.h"
#import "objc/runtime.h"
@implementation NSImage (Additions)
- (CGImageRef)CGImage {
@ -20,21 +23,29 @@
- (CGFloat)scale {
CGFloat scale = 1;
CGFloat width = self.size.width;
if (width > 0) {
// Use CGImage to get pixel width, NSImageRep.pixelsWide may be double on Retina screen
NSUInteger pixelWidth = CGImageGetWidth(self.CGImage);
scale = pixelWidth / width;
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil];
NSBitmapImageRep *bitmapImageRep;
if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) {
bitmapImageRep = (NSBitmapImageRep *)imageRep;
}
if (bitmapImageRep) {
return bitmapImageRep.scale;
}
return scale;
}
- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale {
return [self initWithCGImage:cgImage scale:scale orientation:kCGImagePropertyOrientationUp];
}
- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation {
if (scale < 1) {
scale = 1;
}
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage scale:scale];
NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale);
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage scale:scale orientation:orientation];
NSSize size = imageRep.size;
self = [self initWithSize:size];
if (self) {
[self addRepresentation:imageRep];
@ -50,7 +61,7 @@
if (!imageRep) {
return nil;
}
NSSize size = NSMakeSize(imageRep.pixelsWide / scale, imageRep.pixelsHigh / scale);
NSSize size = imageRep.size;
self = [self initWithSize:size];
if (self) {
[self addRepresentation:imageRep];
@ -60,10 +71,47 @@
@end
@interface NSBitmapImageRep ()
@property (nonatomic, assign, readonly, nullable) CGImageSourceRef imageSource;
@end
@implementation NSBitmapImageRep (Additions)
- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale {
self = [self initWithCGImage:cgImage];
- (CGImageSourceRef)imageSource {
if (_tiffData) {
return (__bridge CGImageSourceRef)(_tiffData);
}
return NULL;
}
- (CGFloat)scale {
CGFloat scale = 1;
CGFloat width = self.size.width;
CGFloat height = self.size.height;
NSUInteger pixelWidth = self.pixelsWide;
NSUInteger pixelHeight = self.pixelsHigh;
if (width > 0 && height > 0) {
CGFloat widthScale = pixelWidth / width;
CGFloat heightScale = pixelHeight / height;
if (widthScale == heightScale && widthScale >= 1) {
// Protect for image object which custom the size.
scale = widthScale;
}
}
return scale;
}
- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(CGImagePropertyOrientation)orientation {
if (orientation != kCGImagePropertyOrientationUp) {
// This should be nonnull, until the memory is exhausted cause `CGBitmapContextCreate` failed.
cgImage = [SDWebImageCoderHelper imageRefCreateDecoded:cgImage orientation:orientation];
self = [self initWithCGImage:cgImage];
CGImageRelease(cgImage);
} else {
self = [self initWithCGImage:cgImage];
}
if (self) {
if (scale < 1) {
scale = 1;

View File

@ -310,7 +310,7 @@ static NSArray *SDBundlePreferredScales() {
return nil;
}
#if SD_MAC
self = [super initWithCGImage:image.CGImage scale:scale];
self = [super initWithCGImage:image.CGImage scale:scale orientation:kCGImagePropertyOrientationUp];
#else
self = [super initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
#endif

View File

@ -299,8 +299,8 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
}
#if SD_UIKIT || SD_WATCH
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:UIImageOrientationUp];
#elif SD_MAC
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale];
#else
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(partialImageRef);
}
@ -403,7 +403,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
CGImageRelease(imageRef);
}
#if SD_MAC
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale];
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale orientation:kCGImagePropertyOrientationUp];
#else
UIImage *image = [UIImage imageWithCGImage:newImageRef scale:_scale orientation:UIImageOrientationUp];
#endif

View File

@ -59,7 +59,7 @@
+ (BOOL)imageRefContainsAlpha:(_Nonnull CGImageRef)imageRef;
/**
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 CGImage by the provided CGImage. 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.
@ -69,7 +69,7 @@
+ (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.
Create a decoded CGImage by the provided CGImage and orientation. 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

View File

@ -183,7 +183,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
// NSBitmapImageRep need to manually change frame. "Good taste" API
[bitmapImageRep setProperty:NSImageCurrentFrame withValue:@(i)];
float frameDuration = [[bitmapImageRep valueForProperty:NSImageCurrentFrameDuration] floatValue];
NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapImageRep.CGImage scale:scale];
NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapImageRep.CGImage scale:scale orientation:kCGImagePropertyOrientationUp];
SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:frameImage duration:frameDuration];
[frames addObject:frame];
}

View File

@ -106,7 +106,7 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage *
#if SD_UIKIT || SD_WATCH
scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
#else
scaledImage = [[NSImage alloc] initWithCGImage:image.CGImage scale:scale];
scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
}
scaledImage.sd_isIncremental = image.sd_isIncremental;

View File

@ -236,8 +236,8 @@
}
#if SD_UIKIT || SD_WATCH
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:UIImageOrientationUp];
#elif SD_MAC
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale];
#else
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(partialImageRef);
}
@ -395,7 +395,7 @@
CGImageRelease(imageRef);
}
#if SD_MAC
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale];
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale orientation:kCGImagePropertyOrientationUp];
#else
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale orientation:UIImageOrientationUp];
#endif

View File

@ -16,6 +16,8 @@
size_t _width, _height;
#if SD_UIKIT || SD_WATCH
UIImageOrientation _orientation;
#else
CGImagePropertyOrientation _orientation;
#endif
CGImageSourceRef _imageSource;
NSUInteger _frameCount;
@ -136,6 +138,8 @@
// in didCompleteWithError.) So save it here and pass it on later.
#if SD_UIKIT || SD_WATCH
_orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)orientationValue];
#else
_orientation = (CGImagePropertyOrientation)orientationValue;
#endif
}
}
@ -177,8 +181,8 @@
}
#if SD_UIKIT || SD_WATCH
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation];
#elif SD_MAC
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale];
#else
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation];
#endif
CGImageRelease(partialImageRef);
}
@ -227,9 +231,11 @@
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
#if SD_UIKIT || SD_WATCH
NSInteger exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation];
[properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation];
CGImagePropertyOrientation exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation];
#else
CGImagePropertyOrientation exifOrientation = kCGImagePropertyOrientationUp;
#endif
[properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation];
double compressionQuality = 1;
if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) {
compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue];

View File

@ -131,7 +131,7 @@ dispatch_semaphore_signal(self->_lock);
#if SD_UIKIT || SD_WATCH
UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
#else
UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale];
UIImage *staticImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imageRef);
WebPDemuxDelete(demuxer);
@ -153,7 +153,7 @@ dispatch_semaphore_signal(self->_lock);
#if SD_UIKIT || SD_WATCH
UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
#else
UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale];
UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imageRef);
WebPDemuxReleaseIterator(&iter);
@ -184,7 +184,7 @@ dispatch_semaphore_signal(self->_lock);
#if SD_UIKIT || SD_WATCH
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
#else
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale];
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imageRef);
@ -289,7 +289,7 @@ dispatch_semaphore_signal(self->_lock);
#if SD_UIKIT || SD_WATCH
image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:UIImageOrientationUp];
#else
image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale];
image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(newImageRef);
CGContextRelease(canvas);
@ -680,7 +680,7 @@ static void FreeImageData(void *info, const void *data, size_t size) {
#if SD_UIKIT || SD_WATCH
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp];
#else
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale];
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imageRef);
} else {
@ -710,7 +710,7 @@ static void FreeImageData(void *info, const void *data, size_t size) {
#if SD_UIKIT || SD_WATCH
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp];
#else
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale];
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imageRef);
}

View File

@ -90,7 +90,7 @@ static UIImage * SDGraphicsGetImageFromCurrentImageContext(void) {
// Protect if x/y axis scale factor not equal
scale = [NSScreen mainScreen].backingScaleFactor;
}
NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale];
NSImage *image = [[NSImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp];
CGImageRelease(imageRef);
return image;
#endif
@ -322,7 +322,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma
#if SD_UIKIT || SD_WATCH
UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
#else
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale];
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imageRef);
return image;
@ -400,7 +400,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma
#if SD_UIKIT || SD_WATCH
UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation];
#else
UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale];
UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imgRef);
CGContextRelease(context);
@ -436,7 +436,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma
#if SD_UIKIT || SD_WATCH
UIImage *img = [UIImage imageWithCGImage:imgRef scale:self.scale orientation:self.imageOrientation];
#else
UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale];
UIImage *img = [[UIImage alloc] initWithCGImage:imgRef scale:self.scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imgRef);
return img;
@ -453,7 +453,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma
#if SD_UIKIT || SD_WATCH
return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:self.imageOrientation];
#else
return [[UIImage alloc] initWithCGImage:self.CGImage scale:self.scale];
return [[UIImage alloc] initWithCGImage:self.CGImage scale:self.scale orientation:kCGImagePropertyOrientationUp];
#endif
}
@ -670,7 +670,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma
#if SD_UIKIT || SD_WATCH
UIImage *outputImage = [UIImage imageWithCGImage:effectCGImage scale:self.scale orientation:self.imageOrientation];
#else
UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage scale:self.scale];
UIImage *outputImage = [[UIImage alloc] initWithCGImage:effectCGImage scale:self.scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(effectCGImage);
@ -695,7 +695,7 @@ static inline UIColor * SDGetColorFromPixel(Pixel_8888 pixel, CGBitmapInfo bitma
#if SD_UIKIT
UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
#else
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale];
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:self.scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(imageRef);