HMCL-dev/HMCL · error · PngIntegrityException
Unsupported disposeOp at frame
Error message
Unsupported disposeOp at frame
What it means
Thrown by ImageUtils.toImage as PngIntegrityException when an APNG frame's dispose_op is not 0 (NONE), 1 (BACKGROUND), or 2 (PREVIOUS) — the only operations defined by the APNG spec. Indicates a corrupt or invalid fcTL chunk.
Solutions
- Re-encode or re-download the APNG — valid files never contain dispose_op > 2
- Catch PngIntegrityException and use the PNG's static default image instead of the animation
- Validate fcTL fields at parse time and surface a clear 'corrupt APNG' error
- Run the file through apngcheck/ffmpeg to confirm integrity before decoding
Example fix
// before
Image anim = ImageUtils.createAnimationFromAPNGApngStream(stream);
// after
Image anim;
try {
anim = ImageUtils.createAnimationFromAPNGApngStream(stream);
} catch (PngIntegrityException e) {
anim = new Image(stream); // static fallback
} Defensive patterns
Strategy: try-catch
Validate before calling
if (control.disposeOp < 0 || control.disposeOp > 2) {
throw new IllegalArgumentException("Non-spec disposeOp: " + control.disposeOp);
} Type guard
static boolean hasKnownDisposeOp(PngFrameControl c) {
return c.disposeOp >= 0 && c.disposeOp <= 2; // NONE, BACKGROUND, PREVIOUS
} Try / catch
try {
animation = ImageUtils.toImage(sequence, ...);
} catch (PngIntegrityException e) {
animation = null;
useStaticFrame();
} Prevention
- Checksum-verify image assets after download
- Treat out-of-range chunk enum values as a corrupted-file signal
- Maintain a graceful static-image fallback for animations
- Sanity-check all fcTL fields immediately after chunk parsing
When it happens
Trigger: Decoding an APNG whose fcTL dispose_op byte holds a value > 2, typically from file corruption or a deliberately malformed image.
Common situations: Damaged downloads; corrupted game/resource-pack assets; adversarial PNG files in untrusted content.
Related errors
- Unsupported blendOp at frame
- Invalid first frame:
- Invalid frame control:
- acTL chunk length must be
- fctl chunk expected sequence
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/18aaf7823b295202.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/image/ImageUtils.java:699
durations[frameIndex] = durationsMills;
}
switch (control.disposeOp) {
case 0: // APNG_DISPOST_OP_NONE
System.arraycopy(currentFrameBuffer, 0, buffer, 0, currentFrameBuffer.length);
break;
case 1: // APNG_DISPOSE_OP_BACKGROUND
for (int row = 0; row < control.height; row++) {
int fromIndex = (control.yOffset + row) * width + control.xOffset;
Arrays.fill(buffer, fromIndex, fromIndex + control.width, 0);
}
break;
case 2: // APNG_DISPOSE_OP_PREVIOUS
// Do nothing, keep the previous frame.
break;
default:
throw new PngIntegrityException("Unsupported disposeOp " + control.disposeOp + " at frame " + frameIndex);
}
}
@Nullable PngAnimationControl animationControl = sequence.getAnimationControl();
int cycleCount;
if (animationControl != null) {
cycleCount = animationControl.numPlays();
if (cycleCount == 0)
cycleCount = Timeline.INDEFINITE;
} else {
cycleCount = Timeline.INDEFINITE;
}
if (doScale)
return new AnimationImageImpl(targetWidth, targetHeight, framePixels, durations, cycleCount);
else
return new AnimationImageImpl(width, height, framePixels, durations, cycleCount);
}View on GitHub (pinned to 24702dc5a0)