From a197fa1c21b79675c315b9e6429a6a44680ece28 Mon Sep 17 00:00:00 2001 From: Antti Kortetmaa Date: Wed, 23 Dec 2020 17:34:34 +0200 Subject: [PATCH 1/2] Fixed issue that caused WebP option that has been set to 0 to be ignored --- .../Classes/SDImageWebPCoder.m | 118 +++++++----------- Tests/SDWebImageWebPCoderTests.m | 33 ++++- 2 files changed, 75 insertions(+), 76 deletions(-) diff --git a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m index 207aa1c..b597108 100644 --- a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m +++ b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m @@ -884,6 +884,30 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio return webpData; } +- (int) getIntValueFor:(SDImageCoderOption) option + defaultValue:(int) defaultValue + options:(nullable SDImageCoderOptions *)options { + id value = [options objectForKey:option]; + if (value != nil) { + if ([value isKindOfClass: [NSNumber class]]) { + return [value intValue]; + } + } + return defaultValue; +} + +- (float) getFloatValueFor:(SDImageCoderOption) option + defaultValue:(float) defaultValue + options:(nullable SDImageCoderOptions *)options { + id value = [options objectForKey:option]; + if (value != nil) { + if ([value isKindOfClass: [NSNumber class]]) { + return [value floatValue]; + } + } + return defaultValue; +} + - (void) updateWebPOptionsToConfig:(WebPConfig * _Nonnull)config maxFileSize:(NSUInteger)maxFileSize options:(nullable SDImageCoderOptions *)options { @@ -891,80 +915,26 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio config->target_size = (int)maxFileSize; // Max filesize for output, 0 means use quality instead config->pass = maxFileSize > 0 ? 6 : 1; // Use 6 passes for file size limited encoding, which is the default value of `cwebp` command line config->lossless = 0; // Disable lossless encoding (If we need, can add new Encoding Options in future version) - - if ([options[SDImageCoderEncodeWebPMethod] intValue]) { - config->method = [options[SDImageCoderEncodeWebPMethod] intValue]; - } - if ([options[SDImageCoderEncodeWebPPass] intValue]) { - config->pass = [options[SDImageCoderEncodeWebPPass] intValue]; - } - if ([options[SDImageCoderEncodeWebPPreprocessing] intValue]) { - config->preprocessing = [options[SDImageCoderEncodeWebPPreprocessing] intValue]; - } - if ([options[SDImageCoderEncodeWebPThreadLevel] intValue]) { - config->thread_level = [options[SDImageCoderEncodeWebPThreadLevel] intValue]; - } else { - config->thread_level = 1; - } - if ([options[SDImageCoderEncodeWebPLowMemory] intValue]) { - config->low_memory = [options[SDImageCoderEncodeWebPLowMemory] intValue]; - } - - if ([options[SDImageCoderEncodeWebPTargetPSNR] floatValue]) { - config->target_PSNR = [options[SDImageCoderEncodeWebPTargetPSNR] floatValue]; - } - - if ([options[SDImageCoderEncodeWebPSegments] intValue]) { - config->segments = [options[SDImageCoderEncodeWebPSegments] intValue]; - } - - if ([options[SDImageCoderEncodeWebPSnsStrength] intValue]) { - config->sns_strength = [options[SDImageCoderEncodeWebPSnsStrength] intValue]; - } - - if ([options[SDImageCoderEncodeWebPFilterStrength] intValue]) { - config->filter_strength = [options[SDImageCoderEncodeWebPFilterStrength] intValue]; - } - - if ([options[SDImageCoderEncodeWebPFilterSharpness] intValue]) { - config->filter_sharpness = [options[SDImageCoderEncodeWebPFilterSharpness] intValue]; - } - - if ([options[SDImageCoderEncodeWebPFilterType] intValue]) { - config->filter_type = [options[SDImageCoderEncodeWebPFilterType] intValue]; - } - - if ([options[SDImageCoderEncodeWebPAutofilter] intValue]) { - config->autofilter = [options[SDImageCoderEncodeWebPAutofilter] intValue]; - } - - if ([options[SDImageCoderEncodeWebPAlphaCompression] intValue]) { - config->alpha_compression = [options[SDImageCoderEncodeWebPAlphaCompression] intValue]; - } - - if ([options[SDImageCoderEncodeWebPAlphaFiltering] intValue]) { - config->alpha_filtering = [options[SDImageCoderEncodeWebPAlphaFiltering] intValue]; - } - - if ([options[SDImageCoderEncodeWebPAlphaQuality] intValue]) { - config->alpha_quality = [options[SDImageCoderEncodeWebPAlphaQuality] intValue]; - } - - if ([options[SDImageCoderEncodeWebPShowCompressed] intValue]) { - config->show_compressed = [options[SDImageCoderEncodeWebPShowCompressed] intValue]; - } - - if ([options[SDImageCoderEncodeWebPPartitions] intValue]) { - config->partitions = [options[SDImageCoderEncodeWebPPartitions] intValue]; - } - - if ([options[SDImageCoderEncodeWebPPartitionLimit] intValue]) { - config->partition_limit = [options[SDImageCoderEncodeWebPPartitionLimit] intValue]; - } - - if ([options[SDImageCoderEncodeWebPUseSharpYuv] intValue]) { - config->use_sharp_yuv = [options[SDImageCoderEncodeWebPUseSharpYuv] intValue]; - } + + config->method = [self getIntValueFor: SDImageCoderEncodeWebPMethod defaultValue: config->method options:options]; + config->pass = [self getIntValueFor: SDImageCoderEncodeWebPPass defaultValue: config->pass options:options]; + config->preprocessing = [self getIntValueFor: SDImageCoderEncodeWebPPreprocessing defaultValue: config->preprocessing options:options]; + config->thread_level = [self getIntValueFor: SDImageCoderEncodeWebPThreadLevel defaultValue: 1 options:options]; + config->low_memory = [self getIntValueFor: SDImageCoderEncodeWebPLowMemory defaultValue: config->low_memory options:options]; + config->target_PSNR = [self getFloatValueFor: SDImageCoderEncodeWebPTargetPSNR defaultValue: config->target_PSNR options:options]; + config->segments = [self getIntValueFor: SDImageCoderEncodeWebPSegments defaultValue: config->segments options:options]; + config->sns_strength = [self getIntValueFor: SDImageCoderEncodeWebPSnsStrength defaultValue: config->sns_strength options:options]; + config->filter_strength = [self getIntValueFor: SDImageCoderEncodeWebPFilterStrength defaultValue: config->filter_strength options:options]; + config->filter_sharpness = [self getIntValueFor: SDImageCoderEncodeWebPFilterSharpness defaultValue: config->filter_sharpness options:options]; + config->filter_type = [self getIntValueFor: SDImageCoderEncodeWebPFilterType defaultValue: config->filter_type options:options]; + config->autofilter = [self getIntValueFor: SDImageCoderEncodeWebPAutofilter defaultValue: config->autofilter options:options]; + config->alpha_compression = [self getIntValueFor: SDImageCoderEncodeWebPAlphaCompression defaultValue: config->alpha_compression options:options]; + config->alpha_filtering = [self getIntValueFor: SDImageCoderEncodeWebPAlphaFiltering defaultValue: config->alpha_filtering options:options]; + config->alpha_quality = [self getIntValueFor: SDImageCoderEncodeWebPAlphaQuality defaultValue: config->alpha_quality options:options]; + config->show_compressed = [self getIntValueFor: SDImageCoderEncodeWebPShowCompressed defaultValue: config->show_compressed options:options]; + config->partitions = [self getIntValueFor: SDImageCoderEncodeWebPPartitions defaultValue: config->partitions options:options]; + config->partition_limit = [self getIntValueFor: SDImageCoderEncodeWebPPartitionLimit defaultValue: config->partition_limit options:options]; + config->use_sharp_yuv = [self getIntValueFor: SDImageCoderEncodeWebPUseSharpYuv defaultValue: config->use_sharp_yuv options:options]; } static void FreeImageData(void *info, const void *data, size_t size) { diff --git a/Tests/SDWebImageWebPCoderTests.m b/Tests/SDWebImageWebPCoderTests.m index 97ce68e..e47b5a5 100644 --- a/Tests/SDWebImageWebPCoderTests.m +++ b/Tests/SDWebImageWebPCoderTests.m @@ -219,7 +219,7 @@ const int64_t kAsyncTestTimeout = 5; WebPConfig config; WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, 0.2); - SDImageCoderOptions *options = @{ SDImageCoderEncodeWebPMethod: @1, + SDImageCoderOptions *options = @{ SDImageCoderEncodeWebPMethod: @0, SDImageCoderEncodeWebPPass: @2, SDImageCoderEncodeWebPPreprocessing: @3, SDImageCoderEncodeWebPThreadLevel: @4, @@ -241,7 +241,7 @@ const int64_t kAsyncTestTimeout = 5; [SDImageWebPCoder.sharedCoder updateWebPOptionsToConfig:&config maxFileSize:1200 options:options]; - expect(config.method).to.equal(1); + 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); @@ -260,7 +260,36 @@ const int64_t kAsyncTestTimeout = 5; expect(config.partitions).to.equal(17); expect(config.partition_limit).to.equal(18); expect(config.use_sharp_yuv).to.equal(19); +} +- (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); } @end From 415e6b6fc1685a05455d5820ee3aa9b14b9717ab Mon Sep 17 00:00:00 2001 From: Antti Kortetmaa Date: Thu, 24 Dec 2020 11:28:04 +0200 Subject: [PATCH 2/2] Changed methods getFloatValueFor and getIntValueFor as static C methods. --- .../Classes/SDImageWebPCoder.m | 83 +++++++++---------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m index b597108..5675170 100644 --- a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m +++ b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m @@ -884,30 +884,6 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio return webpData; } -- (int) getIntValueFor:(SDImageCoderOption) option - defaultValue:(int) defaultValue - options:(nullable SDImageCoderOptions *)options { - id value = [options objectForKey:option]; - if (value != nil) { - if ([value isKindOfClass: [NSNumber class]]) { - return [value intValue]; - } - } - return defaultValue; -} - -- (float) getFloatValueFor:(SDImageCoderOption) option - defaultValue:(float) defaultValue - options:(nullable SDImageCoderOptions *)options { - id value = [options objectForKey:option]; - if (value != nil) { - if ([value isKindOfClass: [NSNumber class]]) { - return [value floatValue]; - } - } - return defaultValue; -} - - (void) updateWebPOptionsToConfig:(WebPConfig * _Nonnull)config maxFileSize:(NSUInteger)maxFileSize options:(nullable SDImageCoderOptions *)options { @@ -916,31 +892,52 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio config->pass = maxFileSize > 0 ? 6 : 1; // Use 6 passes for file size limited encoding, which is the default value of `cwebp` command line config->lossless = 0; // Disable lossless encoding (If we need, can add new Encoding Options in future version) - config->method = [self getIntValueFor: SDImageCoderEncodeWebPMethod defaultValue: config->method options:options]; - config->pass = [self getIntValueFor: SDImageCoderEncodeWebPPass defaultValue: config->pass options:options]; - config->preprocessing = [self getIntValueFor: SDImageCoderEncodeWebPPreprocessing defaultValue: config->preprocessing options:options]; - config->thread_level = [self getIntValueFor: SDImageCoderEncodeWebPThreadLevel defaultValue: 1 options:options]; - config->low_memory = [self getIntValueFor: SDImageCoderEncodeWebPLowMemory defaultValue: config->low_memory options:options]; - config->target_PSNR = [self getFloatValueFor: SDImageCoderEncodeWebPTargetPSNR defaultValue: config->target_PSNR options:options]; - config->segments = [self getIntValueFor: SDImageCoderEncodeWebPSegments defaultValue: config->segments options:options]; - config->sns_strength = [self getIntValueFor: SDImageCoderEncodeWebPSnsStrength defaultValue: config->sns_strength options:options]; - config->filter_strength = [self getIntValueFor: SDImageCoderEncodeWebPFilterStrength defaultValue: config->filter_strength options:options]; - config->filter_sharpness = [self getIntValueFor: SDImageCoderEncodeWebPFilterSharpness defaultValue: config->filter_sharpness options:options]; - config->filter_type = [self getIntValueFor: SDImageCoderEncodeWebPFilterType defaultValue: config->filter_type options:options]; - config->autofilter = [self getIntValueFor: SDImageCoderEncodeWebPAutofilter defaultValue: config->autofilter options:options]; - config->alpha_compression = [self getIntValueFor: SDImageCoderEncodeWebPAlphaCompression defaultValue: config->alpha_compression options:options]; - config->alpha_filtering = [self getIntValueFor: SDImageCoderEncodeWebPAlphaFiltering defaultValue: config->alpha_filtering options:options]; - config->alpha_quality = [self getIntValueFor: SDImageCoderEncodeWebPAlphaQuality defaultValue: config->alpha_quality options:options]; - config->show_compressed = [self getIntValueFor: SDImageCoderEncodeWebPShowCompressed defaultValue: config->show_compressed options:options]; - config->partitions = [self getIntValueFor: SDImageCoderEncodeWebPPartitions defaultValue: config->partitions options:options]; - config->partition_limit = [self getIntValueFor: SDImageCoderEncodeWebPPartitionLimit defaultValue: config->partition_limit options:options]; - config->use_sharp_yuv = [self getIntValueFor: SDImageCoderEncodeWebPUseSharpYuv defaultValue: config->use_sharp_yuv options:options]; + config->method = GetIntValueForKey(options, SDImageCoderEncodeWebPMethod, config->method); + config->pass = GetIntValueForKey(options, SDImageCoderEncodeWebPPass, config->pass); + config->preprocessing = GetIntValueForKey(options, SDImageCoderEncodeWebPPreprocessing, config->preprocessing); + config->thread_level = GetIntValueForKey(options, SDImageCoderEncodeWebPThreadLevel, 1); + config->low_memory = GetIntValueForKey(options, SDImageCoderEncodeWebPLowMemory, config->low_memory); + config->target_PSNR = GetFloatValueForKey(options, SDImageCoderEncodeWebPTargetPSNR, config->target_PSNR); + config->segments = GetIntValueForKey(options, SDImageCoderEncodeWebPSegments, config->segments); + config->sns_strength = GetIntValueForKey(options, SDImageCoderEncodeWebPSnsStrength, config->sns_strength); + config->filter_strength = GetIntValueForKey(options, SDImageCoderEncodeWebPFilterStrength, config->filter_strength); + config->filter_sharpness = GetIntValueForKey(options, SDImageCoderEncodeWebPFilterSharpness, config->filter_sharpness); + config->filter_type = GetIntValueForKey(options, SDImageCoderEncodeWebPFilterType, config->filter_type); + config->autofilter = GetIntValueForKey(options, SDImageCoderEncodeWebPAutofilter, config->autofilter); + config->alpha_compression = GetIntValueForKey(options, SDImageCoderEncodeWebPAlphaCompression, config->alpha_compression); + config->alpha_filtering = GetIntValueForKey(options, SDImageCoderEncodeWebPAlphaFiltering, config->alpha_filtering); + config->alpha_quality = GetIntValueForKey(options, SDImageCoderEncodeWebPAlphaQuality, config->alpha_quality); + config->show_compressed = GetIntValueForKey(options, SDImageCoderEncodeWebPShowCompressed, config->show_compressed); + config->partitions = GetIntValueForKey(options, SDImageCoderEncodeWebPPartitions, config->partitions); + config->partition_limit = GetIntValueForKey(options, SDImageCoderEncodeWebPPartitionLimit, config->partition_limit); + config->use_sharp_yuv = GetIntValueForKey(options, SDImageCoderEncodeWebPUseSharpYuv, config->use_sharp_yuv); } static void FreeImageData(void *info, const void *data, size_t size) { free((void *)data); } +static int GetIntValueForKey(NSDictionary * _Nonnull dictionary, NSString * _Nonnull key, int defaultValue) { + id value = [dictionary objectForKey:key]; + if (value != nil) { + if ([value isKindOfClass: [NSNumber class]]) { + return [value intValue]; + } + } + return defaultValue; +} + +static float GetFloatValueForKey(NSDictionary * _Nonnull dictionary, NSString * _Nonnull key, float defaultValue) { + id value = [dictionary objectForKey:key]; + if (value != nil) { + if ([value isKindOfClass: [NSNumber class]]) { + return [value floatValue]; + } + } + return defaultValue; +} + + #pragma mark - SDAnimatedImageCoder - (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDImageCoderOptions *)options { if (!data) {