Merge pull request #42 from SDWebImage/feature_webp_encoding_max_pixel_size
Feature WebP Encoding max pixel size (Thumbnail Encoding)
This commit is contained in:
commit
75af1fa89c
|
@ -609,6 +609,15 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
|||
if (options[SDImageCoderEncodeCompressionQuality]) {
|
||||
compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue];
|
||||
}
|
||||
CGSize maxPixelSize = CGSizeZero;
|
||||
NSValue *maxPixelSizeValue = options[SDImageCoderEncodeMaxPixelSize];
|
||||
if (maxPixelSizeValue != nil) {
|
||||
#if SD_MAC
|
||||
maxPixelSize = maxPixelSizeValue.sizeValue;
|
||||
#else
|
||||
maxPixelSize = maxPixelSizeValue.CGSizeValue;
|
||||
#endif
|
||||
}
|
||||
NSUInteger maxFileSize = 0;
|
||||
if (options[SDImageCoderEncodeMaxFileSize]) {
|
||||
maxFileSize = [options[SDImageCoderEncodeMaxFileSize] unsignedIntegerValue];
|
||||
|
@ -618,7 +627,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
|||
BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue];
|
||||
if (encodeFirstFrame || frames.count == 0) {
|
||||
// for static single webp image
|
||||
data = [self sd_encodedWebpDataWithImage:image.CGImage quality:compressionQuality fileSize:maxFileSize];
|
||||
data = [self sd_encodedWebpDataWithImage:image.CGImage quality:compressionQuality maxPixelSize:maxPixelSize maxFileSize:maxFileSize];
|
||||
} else {
|
||||
// for animated webp image
|
||||
WebPMux *mux = WebPMuxNew();
|
||||
|
@ -627,7 +636,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 fileSize:maxFileSize];
|
||||
NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image.CGImage quality:compressionQuality maxPixelSize:maxPixelSize maxFileSize:maxFileSize];
|
||||
int duration = currentFrame.duration * 1000;
|
||||
WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes,
|
||||
.bitstream.size = webpData.length,
|
||||
|
@ -664,7 +673,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
|||
return data;
|
||||
}
|
||||
|
||||
- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef quality:(double)quality fileSize:(NSUInteger)fileSize {
|
||||
- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef quality:(double)quality maxPixelSize:(CGSize)maxPixelSize maxFileSize:(NSUInteger)maxFileSize {
|
||||
NSData *webpData;
|
||||
if (!imageRef) {
|
||||
return nil;
|
||||
|
@ -780,11 +789,11 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
|||
return nil;
|
||||
}
|
||||
|
||||
config.target_size = (int)fileSize; // Max filesize for output, 0 means use quality instead
|
||||
config.pass = fileSize > 0 ? 6 : 1; // Use 6 passes for file size limited encoding, which is the default value of `cwebp` command line
|
||||
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.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.use_argb = 0; // Lossy encoding use YUV for internel bitstream
|
||||
picture.width = (int)width;
|
||||
picture.height = (int)height;
|
||||
picture.writer = WebPMemoryWrite; // Output in memory data buffer
|
||||
|
@ -803,9 +812,21 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
|
|||
return nil;
|
||||
}
|
||||
|
||||
// Check if need to scale pixel size
|
||||
if (maxPixelSize.width > 0 && maxPixelSize.height > 0 && width > maxPixelSize.width && height > maxPixelSize.height) {
|
||||
CGSize scaledSize = SDCalculateThumbnailSize(CGSizeMake(width, height), YES, maxPixelSize);
|
||||
result = WebPPictureRescale(&picture, scaledSize.width, scaledSize.height);
|
||||
if (!result) {
|
||||
WebPMemoryWriterClear(&writer);
|
||||
WebPPictureFree(&picture);
|
||||
CFRelease(dataRef);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
result = WebPEncode(&config, &picture);
|
||||
CFRelease(dataRef); // Free bitmap buffer
|
||||
WebPPictureFree(&picture);
|
||||
CFRelease(dataRef); // Free bitmap buffer
|
||||
|
||||
if (result) {
|
||||
// success
|
||||
|
|
|
@ -262,8 +262,8 @@ const int64_t kAsyncTestTimeout = 5;
|
|||
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) <= 1);
|
||||
expect(ABS(thumbImage.size.height - thumbnailPixelSize.height) <= 1);
|
||||
expect(ABS(thumbImage.size.width - thumbnailPixelSize.width)).beLessThanOrEqualTo(1);
|
||||
expect(ABS(thumbImage.size.height - thumbnailPixelSize.height)).beLessThanOrEqualTo(1);
|
||||
|
||||
|
||||
if (supportsEncoding) {
|
||||
|
@ -282,6 +282,25 @@ const int64_t kAsyncTestTimeout = 5;
|
|||
#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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue