【问题标题】:How do I copy part of one image to another?如何将一张图像的一部分复制到另一张图像?
【发布时间】:2011-05-21 00:10:59
【问题描述】:

我想将一个图像的一部分复制到另一个较小的图像中:换句话说,复制一个子矩形。

我有一个用于源的 Graphics2D 对象,我可以为目标制作一个对象,并且我知道 targetGraphics2D.drawImage(Image img,....) ,但是我如何从 sourceGraphics2D 中获取该 img?


答案(根据 aioobe):源需要是 Image 而不是 Graphics2D。

Image.subImage()是获取源码相关部分的方法。

【问题讨论】:

  • 请注意 subImage() 不会复制底层图像数据,至少对于 BufferedImage。因此,如果您在通过 subImage() 获得的图像上绘制,您也会修改原始图像,而使用 target.createGraphics().drawImage(Image img, ...) 您实际上是在复制。

标签: java image graphics graphics2d image-clipping


【解决方案1】:

首先,关于 Andreas_D 回答的一些注意事项如下:

  • 他的代码依赖于sun.java2d.SunGraphics2D,这是一个内部且未记录的 OpenJDK 类。这意味着,虽然它可能在您的计算机上编译和运行,但如果您将代码分发给其他人,它可能可能会中断。有关详细讨论,请参阅official statement 关于此。

  • 代码依赖反射来撬开内部类,这本身就是代码异味。

  • 总而言之,他的方法是一个非常糟糕的做法(无论是在编程风格方面还是在帮助其他程序员正确使用 API 方面) p>


我如何从 sourceGraphics2D 获取该 img?

我怀疑你误解了Graphics2D 类的责任。

您使用Graphics2D 类来绘制一些东西。它能够在BufferedImage(如果您从缓冲图像中获得图形对象)、屏幕(如果您将其作为paintComponent 方法的参数)甚至打印机上绘图。所以换句话说,给定一个Graphics2D 对象,甚至可能不存在图像!

因此,您可能理解,Graphics2D API 不提供获取底层图像的方法。 (这种方法没有意义,图形对象可能正在将线条和文本传递给打印机!)

要获取子图像,您需要获取给定图形对象绘制的基础图像。

【讨论】:

  • 好的,我明白了。源需要是 Image 而不是 Graphics2D。那么 Image.subImage() 就是获取剪辑的方法。
  • 啊,来吧,总有办法的! (在这种情况下:“铅笔”会记住它所画的内容 ;-))
【解决方案2】:

如果我理解正确的话,W3Schools 有代码可以将图像的一部分放到画布上。如果您需要它作为另一张图片,您可以从该画布中获取它。

我有一个 20 高 x 200 宽的 PNG 图像,它有 10 个“单元格或框架” - 我用于动画并使用以下方法:

context.drawImage( img, sx, sy, swidth, sheight, x, y, width, height );

【讨论】:

    【解决方案3】:

    简短回答:是的,你可以

    在缓冲图像上创建的 Graphics2D 对象知道图像,但不愿意将其交还给您。如果您不介意使用反射,您可以窃取它(反射)。以下代码演示了该方法:

    public class Graphics2DReflector {
    
       public static void main(String[] args) {
         // prepare the Graphics2D - note, we don't keep a ref to the image!
         final Graphics2D g2d = 
              new BufferedImage(100,100,BufferedImage.TYPE_INT_RGB).createGraphics();
         g2d.drawString("Reflected", 10, 50);
    
    
         JFrame frame = new JFrame("Reflected Image");
         // one Panel to show the image only known by g2d
         frame.getContentPane().add(new Panel() {
           @Overwrite
           public void paint(Graphics g) {
             try {
               SurfaceData data = ((SunGraphics2D) g2d).surfaceData;
               Field bufImg = BufImgSurfaceData.class.getDeclaredField("bufImg");
               bufImg.setAccessible(true);
               BufferedImage image = (BufferedImage) bufImg.get(data);
               g.drawImage(image,0,0,null);
             } catch (Exception oops) {
               oops.printStackTrace();
             }
           }
         });
         frame.setSize(200,200);
         frame.setVisible();
       }
    }
    

    注意:这取决于某些 Sun/Oracle 类,可能不适用于所有 Java VM。至少它显示了一种方法,您可能必须检查实际的类才能获取字段。

    【讨论】:

    • 在同一答案中同时依赖 sun.* 包和反射.. 呵呵 ;) 您可能至少应该列出 Graphics2D 对象实际上 是的情况> SunGraphics2D?阅读Why Developers Should Not Write Programs That Call 'sun' Packages。
    • @aiobe - 嘿,这是一个 hack,我已经为这些限制添加了一般注释。你说ist不起作用,我只是回答:有可能。根本不便携,但并非不可能。
    【解决方案4】:

    正如 Aioobe 所说,您不会单独从 Graphics2D 获取图像。但是,如果您的 sourceGraphics2D 来自 Swing 组件,您可以尝试使用您自己的 Graphics2D 实例调用其绘制方法。从那里您可以复制有趣的子区域。

    这是一种 hack,但假设您使用的是 Swing 对象,它应该可以工作。

    class CopySwingPaintingSubRegion extends TheSourceType
    {
           private BufferedImage bufImg;
    
           public CopySwingPaintingSubRegion()
           {
              bufImg = new BufferedImage(...);
    
              //Draw the original image into our bufImg for copying
              super.paintComponent(bufImg.createGraphics());
           }
    
           public BufferedImage getSubImage(int x, int y, int w, int h)
           {
              return bufImg.getSubImage(x,y,w,h);
           }
    }
    

    【讨论】:

      猜你喜欢
      • 2023-04-03
      • 2019-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      • 2013-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多