Merge pull request #35 from SDWebImage/project_encoding_max_file_size_advanced_api
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:
commit
ee7665e2b0
2
Cartfile
2
Cartfile
|
@ -1,2 +1,2 @@
|
|||
github "SDWebImage/SDWebImage" ~> 5.5
|
||||
github "SDWebImage/SDWebImage" ~> 5.7
|
||||
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"
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue