Support libavif loop count by dreampiggy · Pull Request #69 · SDWebImage/SDWebImageAVIFCoder · GitHub
Skip to content

Support libavif loop count - #69

Merged
dreampiggy merged 5 commits into
masterfrom
feature/avif_loop_count
Feb 6, 2026
Merged

dreampiggy merged 5 commits into
masterfrom
feature/avif_loop_count

Conversation

@dreampiggy

@dreampiggy dreampiggy commented Feb 6, 2026 •

Copy link
Copy Markdown
Collaborator

This requires libavif 1.0.0+

This close #68

Summary by CodeRabbit

  • New Features

    • Improved AVIF encoding: better quality handling and optional thumbnail scaling for smaller outputs.
  • Bug Fixes

    • Animated AVIF images now respect their encoded loop counts, fixing playback/looping behavior.
  • Chores

    • Bumped package and pod versions and updated native dependencies for compatibility (libavif → 1.0.0, SDWebImage → 5.21.5, podspec → 0.12.0).

@coderabbitai

coderabbitai Bot commented Feb 6, 2026 •

Copy link
Copy Markdown

This requires libavif 1.0.0+
@dreampiggy
dreampiggy force-pushed the feature/avif_loop_count branch from f4c63cd to 634f480 Compare February 6, 2026 08:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m`:
- Around line 364-365: The assignment in the animated image initializer
improperly converts a signed int to NSUInteger: when setting _loopCount from
decoder->repetitionCount do the same guard used earlier for the
signed-to-unsigned issue: check if decoder->repetitionCount is negative and set
_loopCount to 0 in that case, otherwise safely cast/assign the non-negative
decoder->repetitionCount to the NSUInteger _loopCount; update the block that
sets _frameCount and _loopCount (referencing _frameCount, _loopCount, and
decoder->repetitionCount) to include this guard.
🧹 Nitpick comments (1)
SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m (1)

320-326: Pre-existing: deprecated quantizer fields should be migrated to quality/qualityAlpha.

libavif 1.0.0 deprecated avifEncoder's minQuantizer, maxQuantizer, minQuantizerAlpha, and maxQuantizerAlpha fields — quality and qualityAlpha should be used instead.

Since this PR bumps the minimum libavif to 1.0.0, these fields will still compile but may produce warnings and could be removed in a future release. Consider migrating in a follow-up.

Comment thread SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m`:
- Around line 338-351: The local variable scaledSize is being recomputed and
shadowed inside the if block; remove the inner "CGSize scaledSize" declaration
so the block uses the previously computed scaledSize from the call to
[SDImageCoderHelper
scaledSizeWithImageSize:scaleSize:preserveAspectRatio:shouldScaleUp:] and then
set encoder->scalingMode accordingly (assign scale.horizontal/vertical using
scaledSize and original width/height). Also replace the strict asserts
(assert(scaledSize.width < width); assert(scaledSize.height < height);) with
non-fatal checks (use <= or remove the asserts) to avoid debug aborts due to
floating-point rounding—ensure the code handles equality gracefully before
assigning encoder->scalingMode.
🧹 Nitpick comments (1)
SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m (1)

317-321: Consider clamping compressionQuality to [0.0, 1.0].

If the caller passes an out-of-range value via SDImageCoderEncodeCompressionQuality, the computed quality could exceed AVIF_QUALITY_BEST or go negative. A simple MIN(MAX(..., 0), 1) clamp would make this defensive.

🛡️ Suggested clamp
     double compressionQuality = 1;
     if (options[SDImageCoderEncodeCompressionQuality]) {
         compressionQuality = [options[SDImageCoderEncodeCompressionQuality] doubleValue];
     }
-    int quality = compressionQuality * (AVIF_QUALITY_BEST - AVIF_QUALITY_WORST);
+    compressionQuality = MAX(MIN(compressionQuality, 1.0), 0.0);
+    int quality = (int)(compressionQuality * (AVIF_QUALITY_BEST - AVIF_QUALITY_WORST));

Comment on lines +338 to +351

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Shadowed variable scaledSize on line 342 duplicates the computation from line 339.

Inside the if block, CGSize scaledSize is re-declared with the exact same expression already evaluated three lines above. This shadows the outer scaledSize and is dead/redundant code. Remove the inner declaration so the block uses the already-computed value.

Additionally, the assert on lines 343–344 uses strict <. With floating-point rounding in aspect-ratio-preserving scaling, one dimension could conceivably equal the original, causing a debug-mode abort. Consider <= or removing the asserts in favor of a graceful early-return.

🔧 Proposed fix — remove duplicate declaration
     // 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
-        CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize:CGSizeMake(width, height) scaleSize:maxPixelSize preserveAspectRatio:YES shouldScaleUp:NO];
-        assert(scaledSize.width < width);
-        assert(scaledSize.height < height);
+        assert(scaledSize.width <= width);
+        assert(scaledSize.height <= height);
         avifScalingMode scale;
         scale.horizontal.n = (int)scaledSize.width;
         scale.horizontal.d = (int)width;
🤖 Prompt for AI Agents
In `@SDWebImageAVIFCoder/Classes/SDImageAVIFCoder.m` around lines 338 - 351, The
local variable scaledSize is being recomputed and shadowed inside the if block;
remove the inner "CGSize scaledSize" declaration so the block uses the
previously computed scaledSize from the call to [SDImageCoderHelper
scaledSizeWithImageSize:scaleSize:preserveAspectRatio:shouldScaleUp:] and then
set encoder->scalingMode accordingly (assign scale.horizontal/vertical using
scaledSize and original width/height). Also replace the strict asserts
(assert(scaledSize.width < width); assert(scaledSize.height < height);) with
non-fatal checks (use <= or remove the asserts) to avoid debug aborts due to
floating-point rounding—ensure the code handles equality gracefully before
assigning encoder->scalingMode.

@dreampiggy
dreampiggy force-pushed the feature/avif_loop_count branch from 462a8bd to 6247df1 Compare February 6, 2026 09:16
@dreampiggy
dreampiggy force-pushed the feature/avif_loop_count branch from 6247df1 to 2b09dfc Compare February 6, 2026 09:18
@dreampiggy
dreampiggy merged commit 03252bd into master Feb 6, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

loopCount赋值问题

1 participant