-
Notifications
You must be signed in to change notification settings - Fork 775
优化 APNG 支持 #4230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
优化 APNG 支持 #4230
Conversation
…eCanvas.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…eCanvas.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…eCanvas.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…eCanvas.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…eAnimationImage.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…eCanvas.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors the APNG (Animated PNG) support system to optimize image handling for animated images. The changes replace the old interface-based animation system with a new class-based approach and introduce specialized BGRA pre-multiplied pixel handling for better animation performance.
Key changes:
- Converts
AnimationImage
from interface to abstract class with built-in animation timeline management - Introduces new BGRA pre-multiplied pixel format classes for more efficient animation frame handling
- Replaces the old APNG processing logic in
ImageUtils
with a new director-based approach
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
File | Description |
---|---|
AnimationImage.java |
Converted from interface to abstract class with animation timeline management |
AnimationFrame.java |
New interface defining animation frame duration contract |
BgraPreCanvas.java |
New canvas class for BGRA pre-multiplied pixel operations |
BgraPreFrame.java |
New animation frame implementation extending BgraPreCanvas |
BgraPreAnimationImage.java |
New animation image implementation using BGRA pre-multiplied format |
AnimationImageImpl.java |
Refactored to extend new AnimationImage base class |
BgraPreBitmapDirector.java |
New director class for processing APNG files into BGRA format |
Argb8888Director.java |
Added exception handling to receiveFrameImage method |
ImageUtils.java |
Simplified APNG loading by replacing complex logic with director pattern |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
import java.util.Arrays; | ||
import java.util.Objects; | ||
|
||
public class BgraPreCanvas { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argbToPre method lacks documentation explaining what 'pre' means and the purpose of the alpha premultiplication calculation.
public class BgraPreCanvas { | |
public class BgraPreCanvas { | |
/** | |
* Converts an ARGB color value to its premultiplied alpha ("pre") form. | |
* <p> | |
* In premultiplied alpha format, the red, green, and blue color components are | |
* each multiplied by the alpha component and divided by 255. This is commonly | |
* used in image compositing to simplify blending calculations and improve performance. | |
* <p> | |
* For example, if the original color is (A, R, G, B), the premultiplied color is | |
* (A, R * A / 255, G * A / 255, B * A / 255). | |
* | |
* @param argb the original ARGB color value (with 8 bits per channel) | |
* @return the color value in premultiplied alpha format | |
*/ |
Copilot uses AI. Check for mistakes.
ByteArray.setIntLE(pixels, targetIndex, resultArgbPre); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The toString() method override simply calls super.toString() without adding any value. This override should either provide meaningful information about the canvas state or be removed.
Copilot uses AI. Check for mistakes.
@Override | ||
public Argb8888ScanlineProcessor receiveFrameControl(PngFrameControl control) { | ||
//throw new IllegalStateException("TODO up to here"); | ||
//return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out code should be removed. These TODO comments and dead code lines make the codebase harder to maintain.
//return null; |
Copilot uses AI. Check for mistakes.
//return null; | ||
currentFrame = control; | ||
|
||
//System.out.println("Frame: "+control); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug print statement should be removed from production code.
//System.out.println("Frame: "+control); |
Copilot uses AI. Check for mistakes.
|
||
@Override | ||
public void receiveDefaultImage(Argb8888Bitmap bitmap) { | ||
// this.bitmapSequence.receiveDefaultImage(bitmap); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out code should be removed to keep the codebase clean.
// this.bitmapSequence.receiveDefaultImage(bitmap); |
Copilot uses AI. Check for mistakes.
|
||
//System.out.println("Frame: "+control); | ||
|
||
return scanlineProcessor.cloneWithNewBitmap(header.adjustFor(control)); // TODO: is this going to be a problem? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO comment indicates uncertainty about potential issues. This should be investigated and resolved or properly documented if the concern is valid.
return scanlineProcessor.cloneWithNewBitmap(header.adjustFor(control)); // TODO: is this going to be a problem? | |
// It is safe to clone the scanline processor with a new bitmap for each frame, | |
// as cloneWithNewBitmap creates an independent processor instance for the frame's region. | |
return scanlineProcessor.cloneWithNewBitmap(header.adjustFor(control)); |
Copilot uses AI. Check for mistakes.
@Override | ||
public Image getResult() { | ||
if (doScale) { | ||
throw new UnsupportedOperationException("TODO"); // TODO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scaling functionality is not implemented but the method can be called when doScale is true. This will cause runtime failures when users request scaled images.
throw new UnsupportedOperationException("TODO"); // TODO | |
// Scale each frame to the target size | |
List<BgraPreFrame> scaledFrames = new ArrayList<>(animationFrames.size()); | |
for (BgraPreFrame frame : animationFrames) { | |
scaledFrames.add(scaleFrame(frame, targetWidth, targetHeight)); | |
} | |
int cycleCount; | |
if (animationControl != null) { | |
cycleCount = animationControl.numPlays; | |
if (cycleCount == 0) | |
cycleCount = Timeline.INDEFINITE; | |
} else | |
cycleCount = Timeline.INDEFINITE; | |
return new BgraPreAnimationImage(targetWidth, targetHeight, cycleCount, List.copyOf(scaledFrames)); |
Copilot uses AI. Check for mistakes.
目前还无法工作,待修复。