Upgrade the dependency to SDWebImage 5.7, supports the maxFileSize encoding options, as well as enabling the thread-encoding for speedup

This commit is contained in:
DreamPiggy 2020-04-07 16:59:59 +08:00
parent eb6e84f855
commit a62950d23f
5 changed files with 54 additions and 26 deletions

View File

@ -1,2 +1,2 @@
github "SDWebImage/SDWebImage" ~> 5.5
github "SDWebImage/SDWebImage" ~> 5.7
github "SDWebImage/libwebp-Xcode" ~> 1.0

View File

@ -1,2 +1,2 @@
github "SDWebImage/SDWebImage" "5.5.0"
github "SDWebImage/SDWebImage" "5.7.0"
github "SDWebImage/libwebp-Xcode" "1.1.0"

View File

@ -17,7 +17,7 @@ let package = Package(
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.5.0"),
.package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.7.0"),
.package(url: "https://github.com/SDWebImage/libwebp-Xcode.git", from: "1.1.0")
],
targets: [

View File

@ -27,7 +27,7 @@ This is a SDWebImage coder plugin to support WebP image.
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1',
'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src'
}
s.dependency 'SDWebImage/Core', '~> 5.5'
s.dependency 'SDWebImage/Core', '~> 5.7'
s.dependency 'libwebp', '~> 1.0'
end

View File

@ -609,12 +609,16 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
if (options[SDImageCoderEncodeCompressionQuality]) {
compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue];
}
NSUInteger maxFileSize = 0;
if (options[SDImageCoderEncodeMaxFileSize]) {
maxFileSize = [options[SDImageCoderEncodeMaxFileSize] unsignedIntegerValue];
}
NSArray<SDImageFrame *> *frames = [SDImageCoderHelper framesFromAnimatedImage:image];
BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue];
if (encodeFirstFrame || frames.count == 0) {
// for static single webp image
data = [self sd_encodedWebpDataWithImage:image.CGImage quality:compressionQuality];
data = [self sd_encodedWebpDataWithImage:image.CGImage quality:compressionQuality fileSize:maxFileSize];
} else {
// for animated webp image
WebPMux *mux = WebPMuxNew();
@ -623,7 +627,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
}
for (size_t i = 0; i < frames.count; i++) {
SDImageFrame *currentFrame = frames[i];
NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image.CGImage quality:compressionQuality];
NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image.CGImage quality:compressionQuality fileSize:maxFileSize];
int duration = currentFrame.duration * 1000;
WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes,
.bitstream.size = webpData.length,
@ -660,7 +664,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
return data;
}
- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef quality:(double)quality {
- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef quality:(double)quality fileSize:(NSUInteger)fileSize {
NSData *webpData;
if (!imageRef) {
return nil;
@ -704,7 +708,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
return nil;
}
uint8_t *rgba = NULL;
uint8_t *rgba = NULL; // RGBA Buffer managed by CFData, don't call `free` on it, instead call `CFRelease` on `dataRef`
// We could not assume that input CGImage's color mode is always RGB888/RGBA8888. Convert all other cases to target color mode using vImage
if (byteOrderNormal && ((alphaInfo == kCGImageAlphaNone) || (alphaInfo == kCGImageAlphaLast))) {
// If the input CGImage is already RGB888/RGBA8888
@ -758,34 +762,58 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
rgba = dest.data; // Converted buffer
bytesPerRow = dest.rowBytes; // Converted bytePerRow
CFRelease(dataRef);
dataRef = NULL;
CFRelease(dataRef); // Use CFData to manage bytes for free, the same code path for error handling
dataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, rgba, bytesPerRow * height, kCFAllocatorDefault);
}
uint8_t *data = NULL; // Output WebP data
float qualityFactor = quality * 100; // WebP quality is 0-100
// Encode RGB888/RGBA8888 buffer to WebP data
size_t size;
if (hasAlpha) {
size = WebPEncodeRGBA(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data);
} else {
size = WebPEncodeRGB(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data);
}
if (dataRef) {
CFRelease(dataRef); // free non-converted rgba buffer
dataRef = NULL;
} else {
free(rgba); // free converted rgba buffer
rgba = NULL;
// Using the libwebp advanced API: https://developers.google.com/speed/webp/docs/api#advanced_encoding_api
WebPConfig config;
WebPPicture picture;
WebPMemoryWriter writer;
if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, qualityFactor) ||
!WebPPictureInit(&picture)) {
// shouldn't happen, except if system installation is broken
CFRelease(dataRef);
return nil;
}
if (size) {
config.target_size = (int)fileSize; // Max filesize for output, 0 means use quality instead
config.thread_level = 1; // Thread encoding for fast
config.lossless = 0; // Disable lossless encoding (If we need, can add new Encoding Options in future version)
picture.use_argb = config.lossless; // Lossy encoding use YUV for internel bitstream
picture.width = (int)width;
picture.height = (int)height;
picture.writer = WebPMemoryWrite; // Output in memory data buffer
picture.custom_ptr = &writer;
WebPMemoryWriterInit(&writer);
int result;
if (hasAlpha) {
result = WebPPictureImportRGBA(&picture, rgba, (int)bytesPerRow);
} else {
result = WebPPictureImportRGB(&picture, rgba, (int)bytesPerRow);
}
if (!result) {
WebPMemoryWriterClear(&writer);
CFRelease(dataRef);
return nil;
}
result = WebPEncode(&config, &picture);
CFRelease(dataRef); // Free bitmap buffer
WebPPictureFree(&picture);
if (result) {
// success
webpData = [NSData dataWithBytes:data length:size];
}
if (data) {
WebPFree(data);
webpData = [NSData dataWithBytes:writer.mem length:writer.size];
} else {
// failed
webpData = nil;
}
WebPMemoryWriterClear(&writer);
return webpData;
}