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:
parent
eb6e84f855
commit
a62950d23f
2
Cartfile
2
Cartfile
|
@ -1,2 +1,2 @@
|
||||||
github "SDWebImage/SDWebImage" ~> 5.5
|
github "SDWebImage/SDWebImage" ~> 5.7
|
||||||
github "SDWebImage/libwebp-Xcode" ~> 1.0
|
github "SDWebImage/libwebp-Xcode" ~> 1.0
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
github "SDWebImage/SDWebImage" "5.5.0"
|
github "SDWebImage/SDWebImage" "5.7.0"
|
||||||
github "SDWebImage/libwebp-Xcode" "1.1.0"
|
github "SDWebImage/libwebp-Xcode" "1.1.0"
|
||||||
|
|
|
@ -17,7 +17,7 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
// Dependencies declare other packages that this package depends on.
|
// Dependencies declare other packages that this package depends on.
|
||||||
// .package(url: /* package url */, from: "1.0.0"),
|
// .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")
|
.package(url: "https://github.com/SDWebImage/libwebp-Xcode.git", from: "1.1.0")
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
|
|
|
@ -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',
|
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1',
|
||||||
'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src'
|
'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'
|
s.dependency 'libwebp', '~> 1.0'
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -609,12 +609,16 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
||||||
if (options[SDImageCoderEncodeCompressionQuality]) {
|
if (options[SDImageCoderEncodeCompressionQuality]) {
|
||||||
compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue];
|
compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue];
|
||||||
}
|
}
|
||||||
|
NSUInteger maxFileSize = 0;
|
||||||
|
if (options[SDImageCoderEncodeMaxFileSize]) {
|
||||||
|
maxFileSize = [options[SDImageCoderEncodeMaxFileSize] unsignedIntegerValue];
|
||||||
|
}
|
||||||
NSArray<SDImageFrame *> *frames = [SDImageCoderHelper framesFromAnimatedImage:image];
|
NSArray<SDImageFrame *> *frames = [SDImageCoderHelper framesFromAnimatedImage:image];
|
||||||
|
|
||||||
BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue];
|
BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue];
|
||||||
if (encodeFirstFrame || frames.count == 0) {
|
if (encodeFirstFrame || frames.count == 0) {
|
||||||
// for static single webp image
|
// for static single webp image
|
||||||
data = [self sd_encodedWebpDataWithImage:image.CGImage quality:compressionQuality];
|
data = [self sd_encodedWebpDataWithImage:image.CGImage quality:compressionQuality fileSize:maxFileSize];
|
||||||
} else {
|
} else {
|
||||||
// for animated webp image
|
// for animated webp image
|
||||||
WebPMux *mux = WebPMuxNew();
|
WebPMux *mux = WebPMuxNew();
|
||||||
|
@ -623,7 +627,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < frames.count; i++) {
|
for (size_t i = 0; i < frames.count; i++) {
|
||||||
SDImageFrame *currentFrame = frames[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;
|
int duration = currentFrame.duration * 1000;
|
||||||
WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes,
|
WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes,
|
||||||
.bitstream.size = webpData.length,
|
.bitstream.size = webpData.length,
|
||||||
|
@ -660,7 +664,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
||||||
return data;
|
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;
|
NSData *webpData;
|
||||||
if (!imageRef) {
|
if (!imageRef) {
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -704,7 +708,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
||||||
return nil;
|
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
|
// 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 (byteOrderNormal && ((alphaInfo == kCGImageAlphaNone) || (alphaInfo == kCGImageAlphaLast))) {
|
||||||
// If the input CGImage is already RGB888/RGBA8888
|
// If the input CGImage is already RGB888/RGBA8888
|
||||||
|
@ -758,34 +762,58 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
||||||
|
|
||||||
rgba = dest.data; // Converted buffer
|
rgba = dest.data; // Converted buffer
|
||||||
bytesPerRow = dest.rowBytes; // Converted bytePerRow
|
bytesPerRow = dest.rowBytes; // Converted bytePerRow
|
||||||
CFRelease(dataRef);
|
CFRelease(dataRef); // Use CFData to manage bytes for free, the same code path for error handling
|
||||||
dataRef = NULL;
|
dataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, rgba, bytesPerRow * height, kCFAllocatorDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *data = NULL; // Output WebP data
|
|
||||||
float qualityFactor = quality * 100; // WebP quality is 0-100
|
float qualityFactor = quality * 100; // WebP quality is 0-100
|
||||||
// Encode RGB888/RGBA8888 buffer to WebP data
|
// Encode RGB888/RGBA8888 buffer to WebP data
|
||||||
size_t size;
|
// Using the libwebp advanced API: https://developers.google.com/speed/webp/docs/api#advanced_encoding_api
|
||||||
if (hasAlpha) {
|
WebPConfig config;
|
||||||
size = WebPEncodeRGBA(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data);
|
WebPPicture picture;
|
||||||
} else {
|
WebPMemoryWriter writer;
|
||||||
size = WebPEncodeRGB(rgba, (int)width, (int)height, (int)bytesPerRow, qualityFactor, &data);
|
|
||||||
}
|
if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, qualityFactor) ||
|
||||||
if (dataRef) {
|
!WebPPictureInit(&picture)) {
|
||||||
CFRelease(dataRef); // free non-converted rgba buffer
|
// shouldn't happen, except if system installation is broken
|
||||||
dataRef = NULL;
|
CFRelease(dataRef);
|
||||||
} else {
|
return nil;
|
||||||
free(rgba); // free converted rgba buffer
|
|
||||||
rgba = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// success
|
||||||
webpData = [NSData dataWithBytes:data length:size];
|
webpData = [NSData dataWithBytes:writer.mem length:writer.size];
|
||||||
}
|
} else {
|
||||||
if (data) {
|
// failed
|
||||||
WebPFree(data);
|
webpData = nil;
|
||||||
}
|
}
|
||||||
|
WebPMemoryWriterClear(&writer);
|
||||||
|
|
||||||
return webpData;
|
return webpData;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue