10

我正在尝试将 png 文件复制到程序中的剪贴板,并在粘贴到另一个程序(例如 ms office、paint、photoshop)时保持其 alpha 通道。问题是,大多数程序中的 alpha 通道都会变黑。我已经在网上搜索了几个小时,但找不到解决方案。我正在使用的代码:

setClipboard(Toolkit.getDefaultToolkit().getImage(parent.getSelectedPicturePath()));

public static void setClipboard(Image image) {
    ImageSelection imgSel;
if (OSDetector.isWindows()) {
    imgSel = new ImageSelection(image);
} else {
    imgSel = new ImageSelection(getBufferedImage(image));
}
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(imgSel, null);
}

有什么方法可以维护 Java 中的 alpha 通道?我尝试将 png 转换为 BufferedImage、Image 等并将其粘贴到剪贴板,但没有任何效果。

4

3 回答 3

2

假设它OSDetector工作正常,我能够让 OP 的代码在运行 Oracle JDK 1.8.0_131 的 Windows Server 2008R2 64 位上开箱即用。OP 省略了 的代码getBufferedImage(),但我怀疑它是此博客中版本的一些变体。

当我在 Windows 上使用博客的版本getBufferedImage()(忽略OSDetector检查)测试代码时,我能够重现整个图像为黑色的问题的变体,结果证明这是异步调用的时间问题Image.getWidth(), Image.getHeight(),和Graphics.drawImage(),所有这些都立即返回并采取观察者进行异步更新。博客代码通过null(无观察者)所有这些调用,并期望立即返回结果,而我测试时并非如此。

一旦我修改getBufferedImage()为使用回调,我重现了确切的问题:alpha 通道显示为黑色。这种行为的原因是具有透明度的图像被绘制到默认为黑色画布的图形上下文中。您所看到的正是您在具有黑色背景的网页上查看图像时所看到的。

为了改变这一点,我使用了这个 StackOverflow 答案的提示并将背景涂成白色。

我使用了这个站点ImageSelection的实现,它简单地将一个实例包装在using 中。ImageTransferrableDataFlavor.imageFlavor

最终,对于我的测试,原始图像和缓冲图像变体都可以在 Windows 上运行。下面是代码:

public static void getBufferedImage(Image image, Consumer<Image> imageConsumer) {

    image.getWidth((img, info, x, y, w, h) -> {
        if (info == ImageObserver.ALLBITS) {
            BufferedImage buffered = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2 = buffered.createGraphics();
            g2.setColor(Color.WHITE); // You choose the background color
            g2.fillRect(0, 0, w, h);
            if (g2.drawImage(img, 0, 0, w, h, (img2, info2, x2, y2, w2, h2) -> {
                if (info2 == ImageObserver.ALLBITS) {
                    g2.dispose();
                    imageConsumer.accept(img2);
                    return false;
                }
                return true;
            })) {
                g2.dispose();
                imageConsumer.accept(buffered);
            }
            return false;
        }
        return true;
    });
}

public static void setClipboard(Image image) {
    boolean testBuffered = true; // Both buffered and non-buffered worked for me
    if (!testBuffered) {
        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new ImageSelection(image), null);
    } else {
        getBufferedImage(image, (buffered) -> {
            ImageSelection imgSel = new ImageSelection(buffered);
            Toolkit.getDefaultToolkit().getSystemClipboard().setContents(imgSel, null);
        });
    }
}

我希望这有帮助。祝你好运。

于 2017-05-14T06:21:07.387 回答
1

这是正确的答案吗?你试过这个吗?

    public void doCopyToClipboardAction()
{
  // figure out which frame is in the foreground
  MetaFrame activeMetaFrame = null;
  for (MetaFrame mf : frames)
  {
    if (mf.isActive()) activeMetaFrame = mf;
  }
  // get the image from the current jframe
  Image image = activeMetaFrame.getCurrentImage();
  // place that image on the clipboard
  setClipboard(image);
}


// code below from exampledepot.com
//This method writes a image to the system clipboard.
//otherwise it returns null.
public static void setClipboard(Image image)
{
   ImageSelection imgSel = new ImageSelection(image);
   Toolkit.getDefaultToolkit().getSystemClipboard().setContents(imgSel, null);
}


// This class is used to hold an image while on the clipboard.
static class ImageSelection implements Transferable
{
  private Image image;

  public ImageSelection(Image image)
  {
    this.image = image;
  }

  // Returns supported flavors
  public DataFlavor[] getTransferDataFlavors()
  {
    return new DataFlavor[] { DataFlavor.imageFlavor };
  }

  // Returns true if flavor is supported
  public boolean isDataFlavorSupported(DataFlavor flavor)
  {
    return DataFlavor.imageFlavor.equals(flavor);
  }

  // Returns image
  public Object getTransferData(DataFlavor flavor)
      throws UnsupportedFlavorException, IOException
  {
    if (!DataFlavor.imageFlavor.equals(flavor))
    {
      throw new UnsupportedFlavorException(flavor);
    }
    return image;
  }
}

来源:http ://alvinalexander.com/java/java-copy-image-to-clipboard-example

我自己没有尝试过,对此我不确定。希望你得到正确的答案。

于 2017-05-08T09:54:03.760 回答
1

这是一个非常简单、自包含的示例。阅读或创建图像取决于您。这段代码只是创建了一个在 alpha 类型的 BufferedImage 上绘制的红色圆圈。当我将它粘贴到任何支持透明度的程序中时,它会正确显示。希望能帮助到你。

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.image.BufferedImage;
import java.io.IOException;

public class CopyImageToClipboard {
    public void createClipboardImageWithAlpha() {
        //Create a buffered image of the correct type, with alpha.
        BufferedImage image = new BufferedImage(600, 600, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();
        //Draw in the buffered image.
        g2d.setColor(Color.red);
        g2d.fillOval(10, 10, 580, 580);

        //Add the BufferedImage to the clipboard with transferable image flavor.
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        Transferable transferableImage = getTransferableImage(image);
        clipboard.setContents(transferableImage, null);
    }

    private Transferable getTransferableImage(final BufferedImage bufferedImage) {
        return new Transferable() {
            @Override
            public DataFlavor[] getTransferDataFlavors() {
                return new DataFlavor[] { DataFlavor.imageFlavor };
            }

            @Override
            public boolean isDataFlavorSupported(DataFlavor flavor) {
                return DataFlavor.imageFlavor.equals(flavor);
            }

            @Override
            public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                if (DataFlavor.imageFlavor.equals(flavor)) {
                    return bufferedImage;
                }
                return null;
            }
        };
    }
}
于 2017-05-10T21:53:23.163 回答