-
Notifications
You must be signed in to change notification settings - Fork 90
/
Copy pathSDWebImageWebPCoderTests.m
515 lines (459 loc) · 24 KB
/
SDWebImageWebPCoderTests.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@import Foundation;
@import XCTest;
#import <SDWebImage/SDWebImage.h>
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
#import <Expecta/Expecta.h>
#import <objc/runtime.h>
#if __has_include("webp/decode.h") && __has_include("webp/encode.h") && __has_include("webp/demux.h") && __has_include("webp/mux.h")
#import "webp/decode.h"
#import "webp/encode.h"
#import "webp/demux.h"
#import "webp/mux.h"
#elif __has_include(<libwebp/decode.h>) && __has_include(<libwebp/encode.h>) && __has_include(<libwebp/demux.h>) && __has_include(<libwebp/mux.h>)
#import <libwebp/decode.h>
#import <libwebp/encode.h>
#import <libwebp/demux.h>
#import <libwebp/mux.h>
#else
@import libwebp;
#endif
const int64_t kAsyncTestTimeout = 5;
@interface SDWebImageWebPCoderTests : XCTestCase
@end
@interface SDWebImageWebPCoderTests (Helpers)
- (void)verifyCoder:(id<SDImageCoder>)coder
withLocalImageURL:(NSURL *)imageUrl
supportsEncoding:(BOOL)supportsEncoding
isAnimatedImage:(BOOL)isAnimated;
@end
@interface SDWebPCoderFrame : NSObject
@property (nonatomic, assign) NSUInteger index; // Frame index (zero based)
@property (nonatomic, assign) NSUInteger blendFromIndex; // The nearest previous frame index which blend mode is WEBP_MUX_BLEND
@end
@interface SDImageWebPCoder ()
- (void) updateWebPOptionsToConfig:(WebPConfig * _Nonnull)config
maxFileSize:(NSUInteger)maxFileSize
options:(nullable SDImageCoderOptions *)options;
@end
@implementation SDWebImageWebPCoderTests
+ (void)setUp {
[SDImageCache.sharedImageCache clearMemory];
[SDImageCache.sharedImageCache clearDiskOnCompletion:nil];
[[SDImageCodersManager sharedManager] addCoder:[SDImageWebPCoder sharedCoder]];
}
+ (void)tearDown {
[[SDImageCodersManager sharedManager] removeCoder:[SDImageWebPCoder sharedCoder]];
}
- (void)test01ThatWEBPWorks {
XCTestExpectation *expectation = [self expectationWithDescription:@"WEBP"];
NSURL *imageURL = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery3/1_webp_ll.png"];
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
if (image && data && !error && finished) {
[expectation fulfill];
} else {
XCTFail(@"Something went wrong");
}
}];
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
}
- (void)test02ThatProgressiveWebPWorks {
XCTestExpectation *expectation = [self expectationWithDescription:@"Progressive WebP download"];
NSURL *imageURL = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery3/3_webp_ll.png"];
[[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:SDWebImageDownloaderProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
if (image && data && !error && finished) {
[expectation fulfill];
} else if (finished) {
XCTFail(@"Something went wrong");
} else {
// progressive updates
}
}];
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
}
- (void)test11ThatStaticWebPCoderWorks {
NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"];
[self verifyCoder:[SDImageWebPCoder sharedCoder]
withLocalImageURL:staticWebPURL
supportsEncoding:YES
isAnimatedImage:NO];
}
- (void)test12ThatAnimatedWebPCoderWorks {
NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"webp"];
[self verifyCoder:[SDImageWebPCoder sharedCoder]
withLocalImageURL:animatedWebPURL
supportsEncoding:YES
isAnimatedImage:YES];
}
- (void)test21UIImageWebPCategory {
// Test invalid image data
UIImage *image = [UIImage sd_imageWithWebPData:nil];
XCTAssertNil(image);
// Test valid image data
NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"];
NSData *data = [NSData dataWithContentsOfURL:staticWebPURL];
image = [UIImage sd_imageWithWebPData:data];
XCTAssertNotNil(image);
}
- (void)test31AnimatedImageViewSetAnimatedImageWEBP {
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageAnimated" withExtension:@"webp"];
NSData *animatedImageData = [NSData dataWithContentsOfURL:animatedWebPURL];
SDAnimatedImage *image = [SDAnimatedImage imageWithData:animatedImageData];
imageView.image = image;
XCTAssertNotNil(imageView.image);
}
- (void)test32AnimatedImageViewCategoryProgressive {
XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"];
SDAnimatedImageView *imageView = [SDAnimatedImageView new];
NSURL *testURL = [NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"];
NSString *key = [SDWebImageManager.sharedManager cacheKeyForURL:testURL];
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:key];
[SDImageCache.sharedImageCache removeImageFromDiskForKey:key];
[imageView sd_setImageWithURL:testURL placeholderImage:nil options:SDWebImageProgressiveLoad progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = imageView.image;
// Progressive image may be nil when download data is not enough
if (image) {
XCTAssertTrue(image.sd_isIncremental);
// XCTAssertTrue([image conformsToProtocol:@protocol(SDAnimatedImage)]);
}
});
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
XCTAssertNil(error);
XCTAssertNotNil(image);
XCTAssertTrue([image isKindOfClass:[SDAnimatedImage class]]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kAsyncTestTimeout handler:nil];
}
- (void)test33AnimatedImageBlendMethod {
// Test the optimization for blend and disposal method works without problem
NSURL *animatedWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageBlendAnimated" withExtension:@"webp"];
NSData *data = [NSData dataWithContentsOfURL:animatedWebPURL];
SDImageWebPCoder *coder = [[SDImageWebPCoder alloc] initWithAnimatedImageData:data options:nil];
XCTAssertNotNil(coder);
/**
This WebP image frames info is below:
Canvas size: 400 x 400
Features present: animation transparency
Background color : 0xFF000000 Loop Count : 0
Number of frames: 12
No.: width height alpha x_offset y_offset duration dispose blend image_size compression
1: 400 400 no 0 0 70 none no 5178 lossless
2: 400 400 yes 0 0 70 none yes 1386 lossless
3: 400 400 yes 0 0 70 none yes 1472 lossless
4: 400 394 yes 0 6 70 none yes 3212 lossless
5: 371 394 yes 0 6 70 none yes 1888 lossless
6: 394 382 yes 6 6 70 none yes 3346 lossless
7: 400 388 yes 0 0 70 none yes 3786 lossless
8: 394 383 yes 0 0 70 none yes 1858 lossless
9: 394 394 yes 0 6 70 none yes 3794 lossless
10: 372 394 yes 22 6 70 none yes 3458 lossless
11: 400 400 no 0 0 70 none no 5270 lossless
12: 320 382 yes 0 6 70 none yes 2506 lossless
*/
NSArray<SDWebPCoderFrame *> *frames = [coder valueForKey:@"_frames"];
XCTAssertEqual(frames.count, 12);
for (SDWebPCoderFrame *frame in frames) {
switch (frame.index) {
// frame: 11 blend == no, means clear the canvas
case 10:
case 11:
XCTAssertEqual(frame.blendFromIndex, 10);
break;
default:
XCTAssertEqual(frame.blendFromIndex, 0);
break;
}
}
}
- (void)test34StaticImageNotCreateCGContext {
NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"];
NSData *data = [NSData dataWithContentsOfURL:staticWebPURL];
SDImageWebPCoder *coder = [[SDImageWebPCoder alloc] initWithAnimatedImageData:data options:nil];
XCTAssertTrue(coder.animatedImageFrameCount == 0);
UIImage *image = [coder animatedImageFrameAtIndex:0];
XCTAssertNil(image);
Ivar ivar = class_getInstanceVariable(coder.class, "_canvas");
CGContextRef canvas = ((CGContextRef (*)(id, Ivar))object_getIvar)(coder, ivar);
XCTAssert(canvas == NULL);
}
- (void)test45WebPEncodingMaxFileSize {
NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"];
NSData *data = [NSData dataWithContentsOfURL:staticWebPURL];
UIImage *image = [UIImage sd_imageWithWebPData:data];
NSData *dataWithNoLimit = [SDImageWebPCoder.sharedCoder encodedDataWithImage:image format:SDImageFormatWebP options:nil];
XCTAssertNotNil(dataWithNoLimit);
NSUInteger maxFileSize = 8192;
NSData *dataWithLimit = [SDImageWebPCoder.sharedCoder encodedDataWithImage:image format:SDImageFormatWebP options:@{SDImageCoderEncodeMaxFileSize : @(maxFileSize)}];
XCTAssertNotNil(dataWithLimit);
XCTAssertGreaterThan(dataWithNoLimit.length, dataWithLimit.length);
XCTAssertGreaterThan(dataWithNoLimit.length, maxFileSize);
XCTAssertLessThanOrEqual(dataWithLimit.length, maxFileSize);
}
- (void)test46WebPEncodingMonochrome {
CGSize size = CGSizeMake(512, 512);
SDGraphicsImageRendererFormat *format = [[SDGraphicsImageRendererFormat alloc] init];
format.scale = 1;
SDGraphicsImageRenderer *renderer = [[SDGraphicsImageRenderer alloc] initWithSize:size format:format];
UIColor *monochromeColor = UIColor.clearColor;
UIImage *monochromeImage = [renderer imageWithActions:^(CGContextRef ctx) {
[monochromeColor setFill];
CGContextFillRect(ctx, CGRectMake(0, 0, size.width, size.height));
}];
XCTAssert(monochromeImage);
NSData *data = [SDImageWebPCoder.sharedCoder encodedDataWithImage:monochromeImage format:SDImageFormatWebP options:nil];
XCTAssert(data);
}
- (void)test22ThatForceDecodePolicyAlways {
XCTestExpectation *expectation = [self expectationWithDescription:@"Always policy with WebP image (libwebp) should force-decode"];
NSURL *url = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery/4.webp"];
[SDWebImageManager.sharedManager loadImageWithURL:url options:SDWebImageFromLoaderOnly context:@{SDWebImageContextImageCoder : SDImageWebPCoder.sharedCoder, SDWebImageContextImageForceDecodePolicy : @(SDImageForceDecodePolicyAlways)} progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
expect(image).notTo.beNil();
expect(image.sd_isDecoded).beTruthy();
CGImageRef cgImage = image.CGImage;
CGColorSpaceRef colorspace = CGImageGetColorSpace(cgImage);
expect(colorspace).equal([SDImageCoderHelper colorSpaceGetDeviceRGB]);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:5 handler:nil];
}
- (void)testWebPDecodeDoesNotTriggerCACopyImage {
NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestColorspaceStatic" withExtension:@"webp"];
NSData *data = [NSData dataWithContentsOfURL:staticWebPURL];
UIImage *image = [SDImageWebPCoder.sharedCoder decodedImageWithData:data options:@{SDImageCoderDecodeThumbnailPixelSize: @(CGSizeMake(1023, 680))}]; // 1023 * 4 need aligned to 4096
CGImageRef cgImage = [image CGImage];
size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
XCTAssertEqual(bytesPerRow, 4096);
CGColorSpaceRef colorspace = CGImageGetColorSpace(cgImage);
if (@available(iOS 10.0, macOS 10.6, *)) {
NSString *colorspaceName = (__bridge_transfer NSString *)CGColorSpaceCopyName(colorspace);
#if SD_MAC
XCTAssertEqual(colorspace, NSScreen.mainScreen.colorSpace.CGColorSpace, @"Color space is not screen");
#else
XCTAssertEqual(colorspaceName, (__bridge NSString *)kCGColorSpaceSRGB, @"Color space is not sRGB");
} else {
// Fallback on earlier versions
}
#endif
}
- (void)testEncodingSettings {
WebPConfig config;
WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, 0.2);
SDImageCoderOptions *options = @{ SDImageCoderEncodeWebPMethod: @0,
SDImageCoderEncodeWebPPass: @2,
SDImageCoderEncodeWebPPreprocessing: @3,
SDImageCoderEncodeWebPThreadLevel: @4,
SDImageCoderEncodeWebPLowMemory: @5,
SDImageCoderEncodeWebPTargetPSNR: @6,
SDImageCoderEncodeWebPSegments: @7,
SDImageCoderEncodeWebPSnsStrength: @8,
SDImageCoderEncodeWebPFilterStrength: @9,
SDImageCoderEncodeWebPFilterSharpness: @10,
SDImageCoderEncodeWebPFilterType: @11,
SDImageCoderEncodeWebPAutofilter: @12,
SDImageCoderEncodeWebPAlphaCompression: @13,
SDImageCoderEncodeWebPAlphaFiltering: @14,
SDImageCoderEncodeWebPAlphaQuality: @15,
SDImageCoderEncodeWebPShowCompressed: @16,
SDImageCoderEncodeWebPPartitions: @17,
SDImageCoderEncodeWebPPartitionLimit: @18,
SDImageCoderEncodeWebPUseSharpYuv: @19,
SDImageCoderEncodeWebPLossless: @1 };
[SDImageWebPCoder.sharedCoder updateWebPOptionsToConfig:&config maxFileSize:1200 options:options];
expect(config.method).to.equal(0);
expect(config.pass).to.equal(2);
expect(config.preprocessing).to.equal(3);
expect(config.thread_level).to.equal(4);
expect(config.low_memory).to.equal(5);
expect(config.target_PSNR).to.equal(6);
expect(config.segments).to.equal(7);
expect(config.sns_strength).to.equal(8);
expect(config.filter_strength).to.equal(9);
expect(config.filter_sharpness).to.equal(10);
expect(config.filter_type).to.equal(11);
expect(config.autofilter).to.equal(12);
expect(config.alpha_compression).to.equal(13);
expect(config.alpha_filtering).to.equal(14);
expect(config.alpha_quality).to.equal(15);
expect(config.show_compressed).to.equal(16);
expect(config.partitions).to.equal(17);
expect(config.partition_limit).to.equal(18);
expect(config.use_sharp_yuv).to.equal(19);
expect(config.lossless).to.equal(1);
}
- (void)testEncodingSettingsDefaultValue {
// Ensure that default value is used for values that haven't been defined in options.
WebPConfig config;
WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, 0.2);
SDImageCoderOptions *options = @{
SDImageCoderEncodeWebPThreadLevel: @4,
SDImageCoderEncodeWebPTargetPSNR: @6.9
};
[SDImageWebPCoder.sharedCoder updateWebPOptionsToConfig:&config maxFileSize:1200 options:options];
expect(config.method).to.equal(4);
expect(config.target_PSNR).to.equal(6.9);
}
- (void)testEncodingSettingsIncorrectType {
// Ensure that default value is used if incorrect type of value is given as option.
WebPConfig config;
WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, 0.2);
SDImageCoderOptions *options = @{
SDImageCoderEncodeWebPMethod: @"Foo"
};
[SDImageWebPCoder.sharedCoder updateWebPOptionsToConfig:&config maxFileSize:1200 options:options];
expect(config.method).to.equal(4);
}
- (void)testEncodingGrayscaleImage {
NSURL *grayscaleImageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageGrayscale" withExtension:@"jpg"];
NSData *grayscaleImageData = [NSData dataWithContentsOfURL:grayscaleImageURL];
UIImage *grayscaleImage = [[UIImage alloc] initWithData:grayscaleImageData];
expect(grayscaleImage).notTo.beNil();
NSData *webpData = [SDImageWebPCoder.sharedCoder encodedDataWithImage:grayscaleImage format:SDImageFormatWebP options:nil];
expect(webpData).notTo.beNil();
UIImage *decodedImage = [UIImage sd_imageWithData:webpData];
expect(decodedImage).notTo.beNil();
// Sample to verify that encoded WebP image's color is correct.
// The wrong case before bugfix is that each column color will repeats 3 times.
CGPoint point1 = CGPointMake(271, 764);
CGPoint point2 = CGPointMake(round(point1.x + decodedImage.size.width / 3), point1.y);
UIColor *color1 = [decodedImage sd_colorAtPoint:point1];
UIColor *color2 = [decodedImage sd_colorAtPoint:point2];
CGFloat r1, r2;
CGFloat g1, g2;
CGFloat b1, b2;
[color1 getRed:&r1 green:&g1 blue:&b1 alpha:nil];
[color2 getRed:&r2 green:&g2 blue:&b2 alpha:nil];
expect(255 * r1).notTo.equal(255 * r2);
expect(255 * g1).notTo.equal(255 * g2);
expect(255 * b1).notTo.equal(255 * b2);
}
- (void)testWebPEncodingWithICCProfile {
// Test transcoding
NSString *jpegPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"TestColorspaceBefore" ofType:@"jpeg"];
NSData *jpegData = [NSData dataWithContentsOfFile:jpegPath];
UIImage *jpegImage = [[UIImage alloc] initWithData:jpegData];
NSData *webpData = [[SDImageWebPCoder sharedCoder] encodedDataWithImage:jpegImage format:SDImageFormatWebP options:nil];
// Re-decode to pick color
UIImage *webpImage = [[SDImageWebPCoder sharedCoder] decodedImageWithData:webpData options:nil];
CGPoint point1 = CGPointMake(310, 70);
UIColor *color1 = [webpImage sd_colorAtPoint:point1];
CGFloat r1;
CGFloat g1;
CGFloat b1;
#if SD_UIKIT
[color1 getRed:&r1 green:&g1 blue:&b1 alpha:nil];
expect(255 * r1).beCloseToWithin(0, 5);
expect(255 * g1).beCloseToWithin(38, 5);
expect(255 * b1).beCloseToWithin(135, 5);
#else
@try {
[color1 getRed:&r1 green:&g1 blue:&b1 alpha:nil];
}
@catch (NSException *exception) {}
expect(255 * r1).beCloseToWithin(0, 5);
#endif
}
@end
@implementation SDWebImageWebPCoderTests (Helpers)
- (void)verifyCoder:(id<SDImageCoder>)coder
withLocalImageURL:(NSURL *)imageUrl
supportsEncoding:(BOOL)supportsEncoding
isAnimatedImage:(BOOL)isAnimated {
SDImageFormat encodingFormat = SDImageFormatWebP;
NSData *inputImageData = [NSData dataWithContentsOfURL:imageUrl];
expect(inputImageData).toNot.beNil();
SDImageFormat inputImageFormat = [NSData sd_imageFormatForImageData:inputImageData];
expect(inputImageFormat).toNot.equal(SDImageFormatUndefined);
// 1 - check if we can decode - should be true
expect([coder canDecodeFromData:inputImageData]).to.beTruthy();
// 2 - decode from NSData to UIImage and check it
UIImage *inputImage = [coder decodedImageWithData:inputImageData options:nil];
expect(inputImage).toNot.beNil();
if (isAnimated) {
// 2a - check images count > 0 (only for animated images)
expect(inputImage.sd_isAnimated).to.beTruthy();
// 2b - check image size and scale for each frameImage (only for animated images)
#if SD_UIKIT
CGSize imageSize = inputImage.size;
CGFloat imageScale = inputImage.scale;
[inputImage.images enumerateObjectsUsingBlock:^(UIImage * frameImage, NSUInteger idx, BOOL * stop) {
expect(imageSize).to.equal(frameImage.size);
expect(imageScale).to.equal(frameImage.scale);
}];
#endif
}
// 3 - check thumbnail decoding
CGFloat pixelWidth = inputImage.size.width;
CGFloat pixelHeight = inputImage.size.height;
expect(pixelWidth).beGreaterThan(0);
expect(pixelHeight).beGreaterThan(0);
// check thumnail with scratch
CGFloat thumbnailWidth = 50;
CGFloat thumbnailHeight = 50;
UIImage *thumbImage = [coder decodedImageWithData:inputImageData options:@{
SDImageCoderDecodeThumbnailPixelSize : @(CGSizeMake(thumbnailWidth, thumbnailHeight)),
SDImageCoderDecodePreserveAspectRatio : @(NO)
}];
expect(thumbImage).toNot.beNil();
expect(thumbImage.size).equal(CGSizeMake(thumbnailWidth, thumbnailHeight));
// check thumnail with aspect ratio limit
thumbImage = [coder decodedImageWithData:inputImageData options:@{
SDImageCoderDecodeThumbnailPixelSize : @(CGSizeMake(thumbnailWidth, thumbnailHeight)),
SDImageCoderDecodePreserveAspectRatio : @(YES)
}];
expect(thumbImage).toNot.beNil();
CGFloat ratio = pixelWidth / pixelHeight;
CGFloat thumbnailRatio = thumbnailWidth / thumbnailHeight;
CGSize thumbnailPixelSize;
if (ratio > thumbnailRatio) {
thumbnailPixelSize = CGSizeMake(thumbnailWidth, round(thumbnailWidth / ratio));
} else {
thumbnailPixelSize = CGSizeMake(round(thumbnailHeight * ratio), thumbnailHeight);
}
// Image/IO's thumbnail API does not always use round to preserve precision, we check ABS <= 1
expect(ABS(thumbImage.size.width - thumbnailPixelSize.width)).beLessThanOrEqualTo(1);
expect(ABS(thumbImage.size.height - thumbnailPixelSize.height)).beLessThanOrEqualTo(1);
if (supportsEncoding) {
// 4 - check if we can encode to the original format
if (encodingFormat == SDImageFormatUndefined) {
encodingFormat = inputImageFormat;
}
expect([coder canEncodeToFormat:encodingFormat]).to.beTruthy();
// 5 - encode from UIImage to NSData using the inputImageFormat and check it
NSData *outputImageData = [coder encodedDataWithImage:inputImage format:encodingFormat options:nil];
expect(outputImageData).toNot.beNil();
UIImage *outputImage = [coder decodedImageWithData:outputImageData options:nil];
expect(outputImage.size).to.equal(inputImage.size);
expect(outputImage.scale).to.equal(inputImage.scale);
#if SD_UIKIT
expect(outputImage.images.count).to.equal(inputImage.images.count);
#endif
// check max pixel size encoding with scratch
CGFloat maxWidth = 50;
CGFloat maxHeight = 50;
CGFloat maxRatio = maxWidth / maxHeight;
CGSize maxPixelSize;
if (ratio > maxRatio) {
maxPixelSize = CGSizeMake(maxWidth, round(maxWidth / ratio));
} else {
maxPixelSize = CGSizeMake(round(maxHeight * ratio), maxHeight);
}
NSData *outputMaxImageData = [coder encodedDataWithImage:inputImage format:encodingFormat options:@{SDImageCoderEncodeMaxPixelSize : @(CGSizeMake(maxWidth, maxHeight))}];
UIImage *outputMaxImage = [coder decodedImageWithData:outputMaxImageData options:nil];
// Image/IO's thumbnail API does not always use round to preserve precision, we check ABS <= 1
expect(ABS(outputMaxImage.size.width - maxPixelSize.width)).beLessThanOrEqualTo(1);
expect(ABS(outputMaxImage.size.height - maxPixelSize.height)).beLessThanOrEqualTo(1);
#if SD_UIKIT
expect(outputMaxImage.images.count).to.equal(inputImage.images.count);
#endif
}
}
@end