I´m trying to copy a png file to clipboard within a program and maintain its alpha channel when pasted in another program (e.g. ms office, paint, photoshop). The problem is, that the alpha channel turns black in most of the programs. 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? I've tried converting the png to BufferedImage, Image, etc. and the pasting it to the clipboard, but nothing works.
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. The OP omitted the code for getBufferedImage()
, however I suspect it was some variant of the version from this blog.
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. 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.
Once I modified getBufferedImage()
to use callbacks, I reproduced the exact issue: alpha channels appear black. 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.
I used the ImageSelection
implementation from this site, which simply wraps an Image
instance in a Transferrable
using DataFlavor.imageFlavor
.
Ultimately for my tests, both the original image and the buffered image variants worked on 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.
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
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. 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;
}
};
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With