diff --git a/Cartfile b/Cartfile
index bd1a409..8cb2ebe 100644
--- a/Cartfile
+++ b/Cartfile
@@ -1,2 +1,2 @@
github "SDWebImage/SDWebImage" ~> 5.10
-github "SDWebImage/libavif-Xcode" >= 0.11.2-rc1
\ No newline at end of file
+github "SDWebImage/libavif-Xcode" >= 1.0.0
\ No newline at end of file
diff --git a/Package.resolved b/Package.resolved
index f464b7f..afa585d 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/SDWebImage/libaom-Xcode.git",
"state": {
"branch": null,
- "revision": "482cafbebbc5f32378b82339b7580761fab4fd23",
- "version": "2.0.2"
+ "revision": "b00c20d10f13608c7579aad1f849e0f815d4d3a8",
+ "version": "3.0.0"
}
},
{
@@ -15,8 +15,8 @@
"repositoryURL": "https://github.com/SDWebImage/libavif-Xcode.git",
"state": {
"branch": null,
- "revision": "28be85d8693b8bc2ea3a4d323caf652e740b4683",
- "version": "0.9.1"
+ "revision": "0dc978b08b9bf8b7d1b505f1cb15218e8f637a6c",
+ "version": "1.0.0"
}
},
{
@@ -24,8 +24,8 @@
"repositoryURL": "https://github.com/SDWebImage/libvmaf-Xcode.git",
"state": {
"branch": null,
- "revision": "26544e92506764862358ce2198ddab9af7685ed5",
- "version": "2.2.0"
+ "revision": "41db5dc11d05c02d1aca7de0b572a068f528c37c",
+ "version": "2.3.1"
}
},
{
@@ -33,8 +33,8 @@
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
"state": {
"branch": null,
- "revision": "a6b6e44eadf0d39250c10a7cc0e3b91d0bdb0e94",
- "version": "5.10.4"
+ "revision": "36e79ba485e9bb4d3cd4e3318908866dac5e7b51",
+ "version": "5.21.5"
}
}
]
diff --git a/Package.swift b/Package.swift
index 6198bb4..0bcaeac 100644
--- a/Package.swift
+++ b/Package.swift
@@ -18,7 +18,7 @@ let package = Package(
// 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.10.0"),
- .package(url: "https://github.com/SDWebImage/libavif-Xcode.git", from: "0.11.0")
+ .package(url: "https://github.com/SDWebImage/libavif-Xcode.git", from: "1.0.0")
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
diff --git a/README.md b/README.md
index 6dfd1b8..ae206e1 100644
--- a/README.md
+++ b/README.md
@@ -267,6 +267,24 @@ let avifData = SDImageAVIFCoder.shared.encodedData(with: image, format: .avif, o
let lossyAVIFData = SDImageAVIFCoder.shared.encodedData(with: image, format: .avif, options: [.encodeCompressionQuality: 0.1]) // [0, 1] compression quality
```
+### Thumbnail Encoding (0.12.0+)
+
++ Objective-C
+
+```objective-c
+// AVIF image thumbnail encoding
+UIImage *image;
+NSData *thumbnailAVIFData = [[SDImageAVIFCoder sharedCoder] encodedDataWithImage:image format:SDImageFormatAVIF options:@{SDImageCoderEncodeMaxPixelSize : @(CGSizeMake(200, 200))}]; // encoding max pixel size
+```
+
++ Swift
+
+```swift
+// AVIF image thumbnail encoding
+let image: UIImage
+let thumbnailAVIFData = SDImageAVIFCoder.shared.encodedData(with: image, format: .AVIF, options: [.encodeMaxPixelSize: CGSize(width: 200, height: 200)]) // encoding max pixel size
+```
+
## Screenshot
diff --git a/SDWebImageAVIFCoder.podspec b/SDWebImageAVIFCoder.podspec
index e90b0fc..ebca2d1 100644
--- a/SDWebImageAVIFCoder.podspec
+++ b/SDWebImageAVIFCoder.podspec
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'SDWebImageAVIFCoder'
- s.version = '0.11.1'
+ s.version = '0.12.0'
s.summary = 'A SDWebImage coder plugin to support AVIF(AV1 Image File Format) image'
# This description is used to generate tags and improve search results.
@@ -40,6 +40,6 @@ Which is built based on the open-sourced libavif codec.
}
s.dependency 'SDWebImage', '~> 5.10'
- s.dependency 'libavif/core', '>= 0.11.0'
+ s.dependency 'libavif/core', '>= 1.0.0'
s.libraries = 'c++'
end
diff --git a/SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m b/SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m
index d413328..6d3bd5f 100644
--- a/SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m
+++ b/SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m
@@ -182,6 +182,11 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(SDImageCoderOptions *)
// Animated image
NSMutableArray *frames = [NSMutableArray array];
+ // if repetitionCount is a non-negative integer `n`, then the image sequence should be played back `n + 1` times.
+ int loopCount = decoder->repetitionCount + 1;
+ if (loopCount < 0) {
+ loopCount = 0;
+ }
while (avifDecoderNextImage(decoder) == AVIF_RESULT_OK) {
@autoreleasepool {
CGImageRef originImageRef = SDCreateCGImageFromAVIF(decoder->image);
@@ -209,7 +214,7 @@ - (UIImage *)decodedImageWithData:(NSData *)data options:(SDImageCoderOptions *)
avifDecoderDestroy(decoder);
UIImage *animatedImage = [SDImageCoderHelper animatedImageWithFrames:frames];
- animatedImage.sd_imageLoopCount = 0;
+ animatedImage.sd_imageLoopCount = loopCount;
animatedImage.sd_imageFormat = SDImageFormatAVIF;
return animatedImage;
@@ -305,24 +310,62 @@ - (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image format:(SDIm
avifImageRGBToYUV(avif, &rgb);
free(dest.data);
- NSData *iccProfile = (__bridge_transfer NSData *)CGColorSpaceCopyICCProfile([SDImageCoderHelper colorSpaceGetDeviceRGB]);
-
- avifImageSetProfileICC(avif, (uint8_t *)iccProfile.bytes, iccProfile.length);
+ // We must prefer the input CGImage's color space, which may contains ICC profile
+ CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef);
+ // We only supports RGB colorspace, filter the un-supported one (like Monochrome, CMYK, etc)
+ if (CGColorSpaceGetModel(colorSpace) != kCGColorSpaceModelRGB) {
+ // Ignore and convert, we don't know how to encode this colorspace directlly to WebP
+ // This may cause little visible difference because of colorpsace conversion
+ colorSpace = NULL;
+ }
+ if (!colorSpace) {
+ colorSpace = [SDImageCoderHelper colorSpaceGetDeviceRGB];
+ }
+ // Add ICC profile if present
+ CFDataRef iccData = NULL;
+ if (colorSpace) {
+ if (@available(iOS 10, tvOS 10, macOS 10.12, watchOS 3, *)) {
+ iccData = CGColorSpaceCopyICCData(colorSpace);
+ }
+ }
+ if (iccData && CFDataGetLength(iccData) > 0) {
+ avifImageSetProfileICC(avif, CFDataGetBytePtr(iccData), CFDataGetLength(iccData));
+ }
double compressionQuality = 1;
if (options[SDImageCoderEncodeCompressionQuality]) {
compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue];
}
- int rescaledQuality = AVIF_QUANTIZER_WORST_QUALITY - (int)((compressionQuality) * AVIF_QUANTIZER_WORST_QUALITY);
+ int quality = compressionQuality * (AVIF_QUALITY_BEST - AVIF_QUALITY_WORST);
+ CGSize maxPixelSize = CGSizeZero;
+ NSValue *maxPixelSizeValue = options[SDImageCoderEncodeMaxPixelSize];
+ if (maxPixelSizeValue != nil) {
+#if SD_MAC
+ maxPixelSize = maxPixelSizeValue.sizeValue;
+#else
+ maxPixelSize = maxPixelSizeValue.CGSizeValue;
+#endif
+ }
avifRWData raw = AVIF_DATA_EMPTY;
avifEncoder *encoder = avifEncoderCreate();
encoder->codecChoice = codecChoice;
- encoder->minQuantizer = rescaledQuality;
- encoder->maxQuantizer = rescaledQuality;
- encoder->minQuantizerAlpha = rescaledQuality;
- encoder->maxQuantizerAlpha = rescaledQuality;
+ encoder->quality = quality;
+ encoder->qualityAlpha = quality;
encoder->maxThreads = 2;
+ // Check if need to scale pixel size
+ CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize:CGSizeMake(width, height) scaleSize:maxPixelSize preserveAspectRatio:YES shouldScaleUp:NO];
+ if (!CGSizeEqualToSize(scaledSize, CGSizeMake(width, height))) {
+ // Thumbnail Encoding
+ assert(scaledSize.width <= width);
+ assert(scaledSize.height <= height);
+ avifScalingMode scale;
+ scale.horizontal.n = (int)scaledSize.width;
+ scale.horizontal.d = (int)width;
+ scale.vertical.n = (int)scaledSize.height;
+ scale.vertical.d = (int)height;
+ encoder->scalingMode = scale;
+ }
avifResult result = avifEncoderWrite(encoder, avif, &raw);
avifImageDestroy(avif);
@@ -361,7 +404,11 @@ - (instancetype)initWithAnimatedImageData:(NSData *)data options:(SDImageCoderOp
}
// TODO: Optimize the performance like WebPCoder (frame meta cache, etc)
_frameCount = decoder->imageCount;
- _loopCount = 0;
+ int loopCount = decoder->repetitionCount + 1;
+ if (loopCount < 0) {
+ loopCount = 0;
+ }
+ _loopCount = loopCount;
_hasAnimation = decoder->imageCount > 1;
CGFloat scale = 1;
NSNumber *scaleFactor = options[SDImageCoderDecodeScaleFactor];