简体   繁体   English

Java透明PNG到剪贴板

[英]Java transparent PNG to clipboard

I´m trying to copy a png file to clipboard within a program and maintain its alpha channel when pasted in another program (eg ms office, paint, photoshop). 我正在尝试将png文件复制到程序中的剪贴板,并在粘贴到另一个程序(例如ms office,paint,photoshop)时保持其alpha通道。 The problem is, that the alpha channel turns black in most of the programs. 问题是,在大多数程序中alpha通道变黑。 I've been searching the web for hours now and can't find a solution. 我一直在网上搜索几个小时,但找不到解决方案。 The Code I'm using: 我正在使用的代码:

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);
}

Is there any way to maintain the alpha channel in Java? 有没有办法在Java中维护alpha通道? I've tried converting the png to BufferedImage, Image, etc. and the pasting it to the clipboard, but nothing works. 我已经尝试将png转换为BufferedImage,Image等,并将其粘贴到剪贴板,但没有任何效果。

Is this right answer? 这是正确的答案吗? Have you tried this? 你试过这个吗?

    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;
  }
}

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

I'm not tried this myself and I'm not sure about that. 我自己也没试过,我不确定。 Hopefully you get right answer. 希望你得到正确的答案。

Here is a very simple, self contained example that works. 这是一个非常简单,自包含的例子。 Reading or creating the image is up to you. 阅读或创建图像取决于您。 This code just creates a red circle drawn on an alpha-type BufferedImage. 此代码只是在alpha类型的BufferedImage上创建一个红色圆圈。 When I paste it in any program that supports transparency, it shows correctly. 当我将其粘贴到任何支持透明度的程序中时,它会正确显示。 Hope it helps. 希望能帮助到你。

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;
            }
        };
    }
}

Assuming that OSDetector is working properly, I was able to get the OP's code to work out of the box on Windows Server 2008R2 64-bit running Oracle JDK 1.8.0_131. 假设OSDetector工作正常,我能够使OP的代码在运行Oracle JDK 1.8.0_131的64位Windows Server 2008R2上开箱即用。 The OP omitted the code for getBufferedImage() , however I suspect it was some variant of the version from this blog . OP省略了getBufferedImage()的代码,但我怀疑它是该博客版本的一些变体。

When I tested the code using the blog's version of getBufferedImage() on Windows (ignoring the OSDetector check), I was able to reproduce a variant of the issue where the entire image was black, which turned out to be a timing issue with the asynchronous calls to Image.getWidth() , Image.getHeight() , and Graphics.drawImage() , all of which return immediately and take an observer for async updates. 当我在Windows上使用博客版本的getBufferedImage()测试代码时(忽略OSDetector检查),我能够重现整个图像为黑色的问题的变体,这对异步的时间问题来说是个问题。调用Image.getWidth()Image.getHeight()Graphics.drawImage() ,所有这些都立即返回并带一个观察者进行异步更新。 The blog code passes null (no observer) for all of these invocations, and expects results to be returned immediately, which was not the case when I tested. 博客代码为所有这些调用传递null (无观察者),并期望立即返回结果,这在我测试时不是这种情况。

Once I modified getBufferedImage() to use callbacks, I reproduced the exact issue: alpha channels appear black. 一旦我修改了getBufferedImage()以使用回调,我就重现了确切的问题:alpha通道显示为黑色。 The reason for this behavior is that the image with the transparency is drawn onto a graphics context that defaults to a black canvas. 出现这种情况的原因是具有透明度的图像被绘制到默认为黑色画布的图形上下文中。 What you are seeing is exactly what you would see if you viewed the image on a web page with a black background. 如果您在黑色背景的网页上查看图像,您所看到的正是您所看到的。

To change this, I used a hint from this StackOverflow answer and painted the background white. 为了改变这种情况,我使用了StackOverflow答案的提示并将背景涂成了白色。

I used the ImageSelection implementation from this site , which simply wraps an Image instance in a Transferrable using DataFlavor.imageFlavor . 我使用了这个站点ImageSelection实现,它只是使用DataFlavor.imageFlavorImage实例包装在Transferrable中。

Ultimately for my tests, both the original image and the buffered image variants worked on Windows. 最终,对于我的测试,原始图像和缓冲图像变体都可以在Windows上运行。 Below is the code: 以下是代码:

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);
        });
    }
}

I hope this helps. 我希望这有帮助。 Best of luck. 祝你好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM