HMCL-dev/HMCL · error · PngIntegrityException
Invalid first frame:
Error message
Invalid first frame:
What it means
Thrown by ImageUtils.toImage (APNG animation decoder) as a PngIntegrityException when the first APNG frame is not a full-size frame: its x/y offset is non-zero or its width/height differ from the PNG canvas dimensions. APNG spec requires frame 0 to cover the whole canvas.
Solutions
- Re-encode the APNG with a spec-compliant tool (ffmpeg, apngasm) so the first frame covers the full canvas
- Fall back to decoding the PNG as a static image (default image) when APNG decoding fails
- Catch PngIntegrityException and substitute a placeholder/static frame
- Validate the APNG with apngdis/apngcheck before feeding it to the decoder
Example fix
// before
Image image = ImageUtils.createAnimationFromAPNGApngStream(stream); // throws on bad first frame
// after
try {
image = ImageUtils.createAnimationFromAPNGApngStream(stream);
} catch (PngIntegrityException e) {
image = ImageUtils.scale(new Image(stream), width, height); // static fallback
} Defensive patterns
Strategy: try-catch
Validate before calling
// Parse fcTL of first frame before decoding
PngFrameControl first = frames.get(0).control();
boolean ok = first.xOffset == 0 && first.yOffset == 0
&& first.width == canvasWidth && first.height == canvasHeight;
if (!ok) { /* use static default image instead of animation */ } Try / catch
try {
image = ImageUtils.createAnimationFromAPNGApngStream(stream);
} catch (PngIntegrityException e) {
image = staticFallbackImage;
} Prevention
- Re-encode APNGs with ffmpeg/apngasm rather than hand-editing chunks
- Treat APNG decode failures as 'use default image' events, not crashes
- Validate third-party APNG assets once at build/import time
- Never reorder or insert fcTL chunks manually
When it happens
Trigger: Decoding an APNG whose fcTL for frame index 0 declares xOffset/yOffset != 0 or a frame smaller than the IHDR canvas — i.e. a non-conformant APNG produced by a broken encoder.
Common situations: Malformed APNGs from buggy encoders or hand-edited PNG chunks; files that had fcTL chunks reordered or inserted incorrectly; multi-part images stitched by tools that ignored APNG constraints.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid frame control:
- Received tRNS data length is invalid. Should be >1 && <
- Unsupported blendOp at frame
- Unsupported disposeOp at frame
- acTL chunk length must be
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/274aa8225ca09fce.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/ui/image/ImageUtils.java:594
boolean doScale,
int targetWidth, int targetHeight) throws PngException {
final int width = sequence.header.width;
final int height = sequence.header.height;
List<Argb8888BitmapSequence.Frame> frames = sequence.getAnimationFrames();
var framePixels = new int[frames.size()][];
var durations = new int[framePixels.length];
int[] buffer = new int[Math.multiplyExact(width, height)];
for (int frameIndex = 0; frameIndex < frames.size(); frameIndex++) {
var frame = frames.get(frameIndex);
PngFrameControl control = frame.control();
if (frameIndex == 0 && (
control.xOffset != 0 || control.yOffset != 0
|| control.width != width || control.height != height)) {
throw new PngIntegrityException("Invalid first frame: " + control);
}
if (control.xOffset < 0 || control.yOffset < 0
|| width < 0 || height < 0
|| control.xOffset + control.width > width
|| control.yOffset + control.height > height
|| control.delayNumerator < 0 || control.delayDenominator < 0
) {
throw new PngIntegrityException("Invalid frame control: " + control);
}
int[] currentFrameBuffer = buffer.clone();
if (control.blendOp == 0) {
for (int row = 0; row < control.height; row++) {
System.arraycopy(frame.bitmap().array(),
row * control.width,
currentFrameBuffer,
(control.yOffset + row) * width + control.xOffset,View on GitHub (pinned to 24702dc5a0)