Swing:在图像组件中实现缩放功能的最佳方式
我创建了一个 SWING 组件 JImageEditor,它只显示图片。这个想法是为了进一步向组件添加更多功能。
我已经实现的一项功能是缩放。现在,这部分是在 PaintComponent() 方法中处理的。然而,不知何故,我怀疑这可能是一个坏主意,因为这意味着每次调用 PaintComponent() 时图像都会从原始大小缩放到当前的“缩放大小”。 PaintComponent 代码如下:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
int w = getWidth();
int h = getHeight();
double imageWidth = scale * image.getWidth();
double imageHeight = scale * image.getHeight();
double x = (w - imageWidth) / 2;
double y = (h - imageHeight) / 2;
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.scale(scale, scale);
g2.drawRenderedImage(image, at);
}
现在,我想到的替代方案是保留 BufferedImage 的两个实例,其中一个是原始实例,一个是当前“视图”。这样,每当调用 setScale() 方法时,我就可以处理实际的缩放/缩放,而不是在 PaintComponent() 中缩放。然而,缺点是我需要保留两个 BufferedImage 实例,这将导致更高的内存消耗,具体取决于图像大小。当然,不可能预测任何给定用户将使用该组件打开多大的图像。
我正在寻找的是,如果我的工作在正确的轨道上,则竖起大拇指;如果设计不好,则应考虑其他解决方案,则不要竖起大拇指。我感谢所有的意见,并将奖励所有启发我的答案:-)
I've create a SWING component JImageEditor which simply displays a picture. The idea is to add more functionality to the component further down the road.
One functionality which I've already implemented is zooming. Right now, this part is taken care of in the paintComponent() method. However, somehow I suspect that this might be a bad idea as this means the image will be scaled from the original size to the current "zoom size" each and every time paintComponent() is invoked. The paintComponent code goes as follows :
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
int w = getWidth();
int h = getHeight();
double imageWidth = scale * image.getWidth();
double imageHeight = scale * image.getHeight();
double x = (w - imageWidth) / 2;
double y = (h - imageHeight) / 2;
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.scale(scale, scale);
g2.drawRenderedImage(image, at);
}
Now, what I though of as an alternative was to keep two instances of BufferedImage where one is the original and one is the current "view". That way I could handle the actual zooming/scaling whenever the setScale() method is invoked, instead of scaling in paintComponent(). However, the drawback is that i need to keep two instances of BufferedImage which will lead to higher memory consumption depending on the image size. It is, of course, impossible to predict how large images any given user will open using the component.
What I'm looking for is either a thumbs up if I am on the right track with my work, or thumbs down If it's bad design and some other solution should be considered. I appreciate all input, and will reward all answers which enlightens me :-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我想说在你的paintComponent 中放置一个计时部分来测量它需要多长时间。从你现在拥有的东西中获取你的基本衡量标准。然后用额外的BufferedImage实现优化方法。比较测量值并选择较小的一个。我感觉你的直觉是正确的,每个绘画周期进行仿射变换都很慢,并且通过为缩放图像和源创建双缓冲区会更快。尽管我找不到任何东西可以证实或否认这一点,并且它可能会受到硬件加速的影响。
如果您将该代码部分提取到 ZoomableBufferedImage 类中,您可以轻松打开或关闭优化/未优化版本。 ZoomableBufferedImage 将保存对源图像的引用,并包含一个额外的缓冲图像,它可以在其中保留缩放版本。当您放大/缩小时,ZoomableBufferedImage 会根据其设置绘制或不绘制到缓冲区,然后在其绘制方法中它可以从缓冲区中绘制,也可以通过将 AffineTransform 应用于源并根据其设置进行绘制。
I'd say put a timing section in your paintComponent to measure how long it takes. Get your base measure from what you have now. Then implement the optimized method with the extra BufferedImage. Compare the measurements and pick the one that is smaller. I have a feeling your intuition is correct that doing the affine transform every paint cycle is slow, and by creating a double buffer for the scaled image and the source will be faster. Although I can't find any thing out there that confirms or denies this, and it could be affected by hardware acceleration.
If you extracted that section of code into a ZoomableBufferedImage class you could easily turn on or off the optimized/unoptimized versions. The ZoomableBufferedImage would hold a reference to the source image, and contain a extra buffered image that it can keep the scaled version in. As you zoom in/out the ZoomableBufferedImage draws to the buffer or not based on its settings, then in it's paint method it can draw either from the buffer or by applying the AffineTransform to the source and drawing that based on it's settings.