Merge pull request #2936 from dreampiggy/feature_better_vector_support_pdf

Feature - better support for vector format detection, now PDF rasterized bitmap is built-in
This commit is contained in:
DreamPiggy 2020-02-26 16:02:20 +08:00 committed by GitHub
commit 5c3c40288f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 220 additions and 24 deletions

View File

@ -75,6 +75,7 @@
@"https://nokiatech.github.io/heif/content/images/ski_jump_1440x960.heic",
@"https://nokiatech.github.io/heif/content/image_sequences/starfield_animation.heic",
@"https://s2.ax1x.com/2019/11/01/KHYIgJ.gif",
@"https://raw.githubusercontent.com/icons8/flat-color-icons/master/pdf/stack_of_photos.pdf",
@"https://nr-platform.s3.amazonaws.com/uploads/platform/published_extension/branding_icon/275/AmazonS3.png",
@"http://via.placeholder.com/200x200.jpg",
nil];

View File

@ -23,6 +23,8 @@ static const SDImageFormat SDImageFormatTIFF = 3;
static const SDImageFormat SDImageFormatWebP = 4;
static const SDImageFormat SDImageFormatHEIC = 5;
static const SDImageFormat SDImageFormatHEIF = 6;
static const SDImageFormat SDImageFormatPDF = 7;
static const SDImageFormat SDImageFormatSVG = 8;
/**
NSData category about the image content type and UTI.

View File

@ -17,6 +17,7 @@
// Currently Image/IO does not support WebP
#define kSDUTTypeWebP ((__bridge CFStringRef)@"public.webp")
#define kSVGTagEnd @"</svg>"
@implementation NSData (ImageContentType)
@ -65,6 +66,24 @@
}
break;
}
case 0x25: {
if (data.length >= 4) {
//%PDF
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(1, 3)] encoding:NSASCIIStringEncoding];
if ([testString isEqualToString:@"PDF"]) {
return SDImageFormatPDF;
}
}
}
case 0x3C: {
if (data.length > 100) {
// Check end with SVG tag
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(data.length - 100, 100)] encoding:NSASCIIStringEncoding];
if ([testString containsString:kSVGTagEnd]) {
return SDImageFormatSVG;
}
}
}
}
return SDImageFormatUndefined;
}
@ -93,6 +112,12 @@
case SDImageFormatHEIF:
UTType = kSDUTTypeHEIF;
break;
case SDImageFormatPDF:
UTType = kUTTypePDF;
break;
case SDImageFormatSVG:
UTType = kUTTypeScalableVectorGraphics;
break;
default:
// default is kUTTypePNG
UTType = kUTTypePNG;
@ -120,6 +145,10 @@
imageFormat = SDImageFormatHEIC;
} else if (CFStringCompare(uttype, kSDUTTypeHEIF, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatHEIF;
} else if (CFStringCompare(uttype, kUTTypePDF, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatPDF;
} else if (CFStringCompare(uttype, kUTTypeScalableVectorGraphics, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatSVG;
} else {
imageFormat = SDImageFormatUndefined;
}

View File

@ -12,6 +12,7 @@
#import "SDImageCodersManager.h"
#import "SDImageFrame.h"
#import "UIImage+MemoryCacheCost.h"
#import "UIImage+Metadata.h"
#import "SDImageAssetManager.h"
#import "objc/runtime.h"
@ -298,3 +299,31 @@ static CGFloat SDImageScaleFromPath(NSString *string) {
}
@end
@implementation SDAnimatedImage (Metadata)
- (BOOL)sd_isAnimated {
return YES;
}
- (NSUInteger)sd_imageLoopCount {
return self.animatedImageLoopCount;
}
- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount {
return;
}
- (SDImageFormat)sd_imageFormat {
return self.animatedImageFormat;
}
- (void)setSd_imageFormat:(SDImageFormat)sd_imageFormat {
return;
}
- (BOOL)sd_isVector {
return NO;
}
@end

View File

@ -470,10 +470,10 @@
// NSImageView use a subview. We need this subview's layer for actual rendering.
// Why using this design may because of properties like `imageAlignment` and `imageScaling`, which it's not available for UIImageView.contentMode (it's impossible to align left and keep aspect ratio at the same time)
- (NSView *)imageView {
NSImageView *imageView = imageView = objc_getAssociatedObject(self, NSSelectorFromString(@"_imageView"));
NSImageView *imageView = imageView = objc_getAssociatedObject(self, SD_SEL_SPI(imageView));
if (!imageView) {
// macOS 10.14
imageView = objc_getAssociatedObject(self, NSSelectorFromString(@"_imageSubview"));
imageView = objc_getAssociatedObject(self, SD_SEL_SPI(imageSubview));
}
return imageView;
}

View File

@ -575,6 +575,10 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
if (image.sd_isAnimated) {
return NO;
}
// do not decode vector images
if (image.sd_isVector) {
return NO;
}
return YES;
}

View File

@ -14,6 +14,9 @@
#import "SDAnimatedImageRep.h"
#import "UIImage+ForceDecode.h"
// Specify DPI for vector format in CGImageSource, like PDF
static NSString * kSDCGImageSourceRasterizationDPI = @"kCGImageSourceRasterizationDPI";
@interface SDImageIOCoderFrame : NSObject
@property (nonatomic, assign) NSUInteger index; // Frame index (zero based)
@ -158,9 +161,33 @@
exifOrientation = kCGImagePropertyOrientationUp;
}
CFStringRef uttype = CGImageSourceGetType(source);
// Check vector format
BOOL isVector = NO;
if ([NSData sd_imageFormatFromUTType:uttype] == SDImageFormatPDF) {
isVector = YES;
}
CGImageRef imageRef;
if (thumbnailSize.width == 0 || thumbnailSize.height == 0 || (pixelWidth <= thumbnailSize.width && pixelHeight <= thumbnailSize.height)) {
imageRef = CGImageSourceCreateImageAtIndex(source, index, NULL);
if (thumbnailSize.width == 0 || thumbnailSize.height == 0 || pixelWidth == 0 || pixelHeight == 0 || (pixelWidth <= thumbnailSize.width && pixelHeight <= thumbnailSize.height)) {
NSDictionary *options;
if (isVector) {
if (thumbnailSize.width == 0 || thumbnailSize.height == 0) {
// Provide the default pixel count for vector images, simply just use the screen size
#if SD_WATCH
thumbnailSize = WKInterfaceDevice.currentDevice.screenBounds.size;
#elif SD_UIKIT
thumbnailSize = UIScreen.mainScreen.bounds.size;
#elif SD_MAC
thumbnailSize = NSScreen.mainScreen.frame.size;
#endif
}
CGFloat maxPixelSize = MAX(thumbnailSize.width, thumbnailSize.height);
NSUInteger DPIPerPixel = 2;
NSUInteger rasterizationDPI = maxPixelSize * DPIPerPixel;
options = @{kSDCGImageSourceRasterizationDPI : @(rasterizationDPI)};
}
imageRef = CGImageSourceCreateImageAtIndex(source, index, (__bridge CFDictionaryRef)options);
} else {
NSMutableDictionary *thumbnailOptions = [NSMutableDictionary dictionary];
thumbnailOptions[(__bridge NSString *)kCGImageSourceCreateThumbnailWithTransform] = @(preserveAspectRatio);
@ -179,21 +206,22 @@
thumbnailOptions[(__bridge NSString *)kCGImageSourceThumbnailMaxPixelSize] = @(maxPixelSize);
thumbnailOptions[(__bridge NSString *)kCGImageSourceCreateThumbnailFromImageIfAbsent] = @(YES);
imageRef = CGImageSourceCreateThumbnailAtIndex(source, index, (__bridge CFDictionaryRef)thumbnailOptions);
}
if (!imageRef) {
return nil;
}
if (thumbnailSize.width > 0 && thumbnailSize.height > 0) {
if (preserveAspectRatio) {
// kCGImageSourceCreateThumbnailWithTransform will apply EXIF transform as well, we should not apply twice
exifOrientation = kCGImagePropertyOrientationUp;
} else {
// `CGImageSourceCreateThumbnailAtIndex` take only pixel dimension, if not `preserveAspectRatio`, we should manual scale to the target size
if (imageRef) {
CGImageRef scaledImageRef = [SDImageCoderHelper CGImageCreateScaled:imageRef size:thumbnailSize];
CGImageRelease(imageRef);
imageRef = scaledImageRef;
}
CGImageRef scaledImageRef = [SDImageCoderHelper CGImageCreateScaled:imageRef size:thumbnailSize];
CGImageRelease(imageRef);
imageRef = scaledImageRef;
}
}
if (!imageRef) {
return nil;
}
#if SD_UIKIT || SD_WATCH
UIImageOrientation imageOrientation = [SDImageCoderHelper imageOrientationFromEXIFOrientation:exifOrientation];
@ -363,7 +391,7 @@
if (scaleFactor != nil) {
scale = MAX([scaleFactor doubleValue], 1);
}
image = [SDImageIOAnimatedCoder createFrameAtIndex:0 source:_imageSource scale:scale preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
image = [self.class createFrameAtIndex:0 source:_imageSource scale:scale preserveAspectRatio:_preserveAspectRatio thumbnailSize:_thumbnailSize];
if (image) {
image.sd_imageFormat = self.class.imageFormat;
}

View File

@ -195,6 +195,12 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
* Note if you use this when using the custom cache serializer, or using the transformer, we will also wait until the output image data written is finished.
*/
SDWebImageWaitStoreCache = 1 << 22,
/**
* We usually don't apply transform on vector images, because vector images supports dynamically changing to any size, rasterize to a fixed size will loss details. To modify vector images, you can process the vector data at runtime (such as modifying PDF tag / SVG element).
* Use this flag to transform them anyway.
*/
SDWebImageTransformVectorImage = 1 << 23,
};

View File

@ -332,7 +332,9 @@ static id<SDImageLoader> _defaultImageLoader;
id<SDImageTransformer> transformer = context[SDWebImageContextImageTransformer];
id<SDWebImageCacheSerializer> cacheSerializer = context[SDWebImageContextCacheSerializer];
BOOL shouldTransformImage = downloadedImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer;
BOOL shouldTransformImage = downloadedImage && transformer;
shouldTransformImage = shouldTransformImage && (!downloadedImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage));
shouldTransformImage = shouldTransformImage && (!downloadedImage.sd_isVector || (options & SDWebImageTransformVectorImage));
BOOL shouldCacheOriginal = downloadedImage && finished;
BOOL waitStoreCache = SD_OPTIONS_CONTAINS(options, SDWebImageWaitStoreCache);
@ -380,7 +382,9 @@ static id<SDImageLoader> _defaultImageLoader;
NSString *key = [self cacheKeyForURL:url context:context];
id<SDImageTransformer> transformer = context[SDWebImageContextImageTransformer];
id<SDWebImageCacheSerializer> cacheSerializer = context[SDWebImageContextCacheSerializer];
BOOL shouldTransformImage = originalImage && (!originalImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage)) && transformer;
BOOL shouldTransformImage = originalImage && transformer;
shouldTransformImage = shouldTransformImage && (!originalImage.sd_isAnimated || (options & SDWebImageTransformAnimatedImage));
shouldTransformImage = shouldTransformImage && (!originalImage.sd_isVector || (options & SDWebImageTransformVectorImage));
BOOL waitStoreCache = SD_OPTIONS_CONTAINS(options, SDWebImageWaitStoreCache);
// if available, store transformed image to cache
if (shouldTransformImage) {

View File

@ -28,12 +28,20 @@
/**
* UIKit:
* Check the `images` array property
* Check the `images` array property.
* AppKit:
* NSImage currently only support animated via GIF imageRep unlike UIImage. It will check the imageRep's frame count.
*/
@property (nonatomic, assign, readonly) BOOL sd_isAnimated;
/**
* UIKit:
* Check the `isSymbolImage` property. Also check the system PDF(iOS 11+) && SVG(iOS 13+) support.
* AppKit:
* NSImage supports PDF && SVG && EPS imageRep, check the imageRep class.
*/
@property (nonatomic, assign, readonly) BOOL sd_isVector;
/**
* The image format represent the original compressed image data format.
* If you don't manually specify a format, this information is retrieve from CGImage using `CGImageGetUTType`, which may return nil for non-CG based image. At this time it will return `SDImageFormatUndefined` as default value.

View File

@ -8,6 +8,7 @@
#import "UIImage+Metadata.h"
#import "NSImage+Compatibility.h"
#import "SDInternalMacros.h"
#import "objc/runtime.h"
@implementation UIImage (Metadata)
@ -32,6 +33,32 @@
return (self.images != nil);
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
- (BOOL)sd_isVector {
if (@available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)) {
// Xcode 11 supports symbol image, keep Xcode 10 compatible currently
SEL SymbolSelector = NSSelectorFromString(@"isSymbolImage");
if ([self respondsToSelector:SymbolSelector] && [self performSelector:SymbolSelector]) {
return YES;
}
// SVG
SEL SVGSelector = SD_SEL_SPI(CGSVGDocument);
if ([self respondsToSelector:SVGSelector] && [self performSelector:SVGSelector]) {
return YES;
}
}
if (@available(iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
// PDF
SEL PDFSelector = SD_SEL_SPI(CGPDFPage);
if ([self respondsToSelector:PDFSelector] && [self performSelector:PDFSelector]) {
return YES;
}
}
return NO;
}
#pragma clang diagnostic pop
#else
- (NSUInteger)sd_imageLoopCount {
@ -61,7 +88,7 @@
}
- (BOOL)sd_isAnimated {
BOOL isGIF = NO;
BOOL isAnimated = NO;
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil];
NSBitmapImageRep *bitmapImageRep;
@ -70,9 +97,24 @@
}
if (bitmapImageRep) {
NSUInteger frameCount = [[bitmapImageRep valueForProperty:NSImageFrameCount] unsignedIntegerValue];
isGIF = frameCount > 1 ? YES : NO;
isAnimated = frameCount > 1 ? YES : NO;
}
return isGIF;
return isAnimated;
}
- (BOOL)sd_isVector {
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
NSImageRep *imageRep = [self bestRepresentationForRect:imageRect context:nil hints:nil];
if ([imageRep isKindOfClass:[NSPDFImageRep class]]) {
return YES;
}
if ([imageRep isKindOfClass:[NSEPSImageRep class]]) {
return YES;
}
if ([NSStringFromClass(imageRep.class) hasSuffix:@"NSSVGImageRep"]) {
return YES;
}
return NO;
}
#endif

View File

@ -21,6 +21,18 @@
#define SD_OPTIONS_CONTAINS(options, value) (((options) & (value)) == (value))
#endif
#ifndef SD_CSTRING
#define SD_CSTRING(str) #str
#endif
#ifndef SD_NSSTRING
#define SD_NSSTRING(str) @(SD_CSTRING(str))
#endif
#ifndef SD_SEL_SPI
#define SD_SEL_SPI(name) NSSelectorFromString([NSString stringWithFormat:@"_%@", SD_NSSTRING(name)])
#endif
#ifndef weakify
#define weakify(...) \
sd_keywordify \

View File

@ -14,6 +14,9 @@
322241802272F808002429DB /* SDUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3222417E2272F808002429DB /* SDUtilsTests.m */; };
3226ECBB20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; };
3226ECBC20754F7700FAFACF /* SDWebImageTestDownloadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */; };
3234306223E2BAC800C290C8 /* TestImage.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 3234306123E2BAC800C290C8 /* TestImage.pdf */; };
3234306323E2BAC800C290C8 /* TestImage.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 3234306123E2BAC800C290C8 /* TestImage.pdf */; };
3234306423E2BAC800C290C8 /* TestImage.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 3234306123E2BAC800C290C8 /* TestImage.pdf */; };
323B8E1F20862322008952BE /* SDWebImageTestLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */; };
323B8E2020862322008952BE /* SDWebImageTestLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 323B8E1E20862322008952BE /* SDWebImageTestLoader.m */; };
324047442271956F007C53E1 /* TestEXIF.png in Resources */ = {isa = PBXBuildFile; fileRef = 324047432271956F007C53E1 /* TestEXIF.png */; };
@ -107,6 +110,7 @@
3222417E2272F808002429DB /* SDUtilsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDUtilsTests.m; sourceTree = "<group>"; };
3226ECB920754F7700FAFACF /* SDWebImageTestDownloadOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestDownloadOperation.h; sourceTree = "<group>"; };
3226ECBA20754F7700FAFACF /* SDWebImageTestDownloadOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestDownloadOperation.m; sourceTree = "<group>"; };
3234306123E2BAC800C290C8 /* TestImage.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = TestImage.pdf; sourceTree = "<group>"; };
323B8E1D20862322008952BE /* SDWebImageTestLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImageTestLoader.h; sourceTree = "<group>"; };
323B8E1E20862322008952BE /* SDWebImageTestLoader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDWebImageTestLoader.m; sourceTree = "<group>"; };
324047432271956F007C53E1 /* TestEXIF.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TestEXIF.png; sourceTree = "<group>"; };
@ -238,6 +242,7 @@
433BBBB81D7EF8260086B6E9 /* TestImage.png */,
327A418B211D660600495442 /* TestImage.heic */,
32905E63211D786E00460FCF /* TestImage.heif */,
3234306123E2BAC800C290C8 /* TestImage.pdf */,
327054E1206CEFF3006EA328 /* TestImageAnimated.apng */,
3297A09E23374D1600814590 /* TestImageAnimated.heic */,
);
@ -443,6 +448,7 @@
3299228B2365DC6C00EAFD97 /* TestImage.heic in Resources */,
329922872365DC6C00EAFD97 /* TestLoopCount.gif in Resources */,
3299228C2365DC6C00EAFD97 /* TestImage.heif in Resources */,
3234306423E2BAC800C290C8 /* TestImage.pdf in Resources */,
329922892365DC6C00EAFD97 /* TestImageLarge.jpg in Resources */,
3299228A2365DC6C00EAFD97 /* TestImage.png in Resources */,
329922842365DC6C00EAFD97 /* MonochromeTestImage.jpg in Resources */,
@ -461,6 +467,7 @@
32B99EA3203B31360017FD66 /* TestImage.gif in Resources */,
324047452271956F007C53E1 /* TestEXIF.png in Resources */,
32B99EA4203B31360017FD66 /* TestImage.jpg in Resources */,
3234306323E2BAC800C290C8 /* TestImage.pdf in Resources */,
32B99EA6203B31360017FD66 /* TestImage.png in Resources */,
3297A0A023374D1700814590 /* TestImageAnimated.heic in Resources */,
32B99EA2203B31360017FD66 /* MonochromeTestImage.jpg in Resources */,
@ -479,6 +486,7 @@
5F7F38AD1AE2A77A00B0E330 /* TestImage.jpg in Resources */,
32905E64211D786E00460FCF /* TestImage.heif in Resources */,
43828A451DA67F9900000E62 /* TestImageLarge.jpg in Resources */,
3234306223E2BAC800C290C8 /* TestImage.pdf in Resources */,
433BBBB71D7EF8200086B6E9 /* TestImage.gif in Resources */,
433BBBB91D7EF8260086B6E9 /* TestImage.png in Resources */,
3297A09F23374D1700814590 /* TestImageAnimated.heic in Resources */,

Binary file not shown.

View File

@ -156,22 +156,34 @@
withLocalImageURL:heicURL
supportsEncoding:supportsEncoding
encodingFormat:SDImageFormatHEIC
isAnimatedImage:isAnimatedImage];
isAnimatedImage:isAnimatedImage
isVectorImage:NO];
}
}
- (void)test17ThatPDFWorks {
NSURL *pdfURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImage" withExtension:@"pdf"];
[self verifyCoder:[SDImageIOCoder sharedCoder]
withLocalImageURL:pdfURL
supportsEncoding:NO
encodingFormat:SDImageFormatUndefined
isAnimatedImage:NO
isVectorImage:YES];
}
- (void)verifyCoder:(id<SDImageCoder>)coder
withLocalImageURL:(NSURL *)imageUrl
supportsEncoding:(BOOL)supportsEncoding
isAnimatedImage:(BOOL)isAnimated {
[self verifyCoder:coder withLocalImageURL:imageUrl supportsEncoding:supportsEncoding encodingFormat:SDImageFormatUndefined isAnimatedImage:isAnimated];
[self verifyCoder:coder withLocalImageURL:imageUrl supportsEncoding:supportsEncoding encodingFormat:SDImageFormatUndefined isAnimatedImage:isAnimated isVectorImage:NO];
}
- (void)verifyCoder:(id<SDImageCoder>)coder
withLocalImageURL:(NSURL *)imageUrl
supportsEncoding:(BOOL)supportsEncoding
encodingFormat:(SDImageFormat)encodingFormat
isAnimatedImage:(BOOL)isAnimated {
isAnimatedImage:(BOOL)isAnimated
isVectorImage:(BOOL)isVector {
NSData *inputImageData = [NSData dataWithContentsOfURL:imageUrl];
expect(inputImageData).toNot.beNil();
SDImageFormat inputImageFormat = [NSData sd_imageFormatForImageData:inputImageData];
@ -204,7 +216,18 @@ withLocalImageURL:(NSURL *)imageUrl
CGFloat pixelHeight = inputImage.size.height;
expect(pixelWidth).beGreaterThan(0);
expect(pixelHeight).beGreaterThan(0);
// check thumnail with scratch
// check vector format supports thumbnail with screen size
if (isVector) {
#if SD_UIKIT
CGFloat maxScreenSize = MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height);
#else
CGFloat maxScreenSize = MAX(NSScreen.mainScreen.frame.size.width, NSScreen.mainScreen.frame.size.height);
#endif
expect(pixelWidth).equal(maxScreenSize);
expect(pixelHeight).equal(maxScreenSize);
}
// check thumbnail with scratch
CGFloat thumbnailWidth = 50;
CGFloat thumbnailHeight = 50;
UIImage *thumbImage = [coder decodedImageWithData:inputImageData options:@{
@ -213,7 +236,7 @@ withLocalImageURL:(NSURL *)imageUrl
}];
expect(thumbImage).toNot.beNil();
expect(thumbImage.size).equal(CGSizeMake(thumbnailWidth, thumbnailHeight));
// check thumnail with aspect ratio limit
// check thumbnail with aspect ratio limit
thumbImage = [coder decodedImageWithData:inputImageData options:@{
SDImageCoderDecodeThumbnailPixelSize : @(CGSizeMake(thumbnailWidth, thumbnailHeight)),
SDImageCoderDecodePreserveAspectRatio : @(YES)