I want created a program that copies images from a folder into the clipboard, but the images become black.
After doing some research, I found this: Clipboard copy from outlook always has black background set when retrieved as image from Java clipboard object
There he says using image\x-emf fixes the problem. But I can't figure out how to get the TransferData from " new DataFlavor("image/x-emf") "
package Package1;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import javax.swing.ImageIcon;
/** Transferable image */
public class imageSelection implements Transferable {
private Image image;
/** Creates a transferable object that is an image.
* <p>imageSelection(Image)
* */
public imageSelection(Image image) {
this.image = image;
}
public DataFlavor[] getTransferDataFlavors() {
//DataFlavor[] BlackBackgroundImage = new DataFlavor[] { DataFlavor.imageFlavor }; // <--- Gives me a black background instead of transparent
DataFlavor[] transferData = null;
try {
transferData = new DataFlavor("image/x-emf"); // <---- How to get TransferData from this
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
error.displayError(e.getStackTrace(), "Error creating DataFlavor (mime type: image/x-emf)");
}
return transferData;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return DataFlavor.imageFlavor.equals(flavor);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (!DataFlavor.imageFlavor.equals(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return image;
}
}
Method call (where emojiLocation is the path to the image):
imageSelection imgSel = new imageSelection(new ImageIcon(emojiLocation).getImage());
Thanks in advance!
Solution:
return new DataFlavor[] { transferData }
Sorry for missing something so obvious.
This didn't lead me to other problems tho and didn't allow me to achieve a transparent image, so I made a new question in hope to solve this: Set clipboard to transparent image
Related
Fairly simple, I would like to copy an image into the system clipboard using java and be able to past what is currently in the clipboard into another application, such as word, google docs, etc. etc.
At the moment I've found the common
public static void setClipboard(Image image)
{
ImageTransferable imgSel = new ImageTransferable(image);
Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
c.setContents(imgSel, null);
}
static class ImageTransferable implements Transferable
{
private Image image;
public ImageTransferable (Image image)
{
this.image = image;
}
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException
{
if (isDataFlavorSupported(flavor))
{
return image;
}
else
{
throw new UnsupportedFlavorException(flavor);
}
}
public boolean isDataFlavorSupported (DataFlavor flavor)
{
return flavor == DataFlavor.imageFlavor;
}
public DataFlavor[] getTransferDataFlavors ()
{
return new DataFlavor[] { DataFlavor.imageFlavor };
}
}
Unfortunately this does not put the image into a clipboard in a paste-able state outside of the java program itself. I can get it to successfully pull from the clipboard (c) to paste the image programmatically in the java program itself but not into another window or application.
I did not test the pasted code but i tried to test another one, with some modification it works correctly for me and copy past an image in a given URL to the SystemClipboard :
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Paths;
import javax.imageio.ImageIO;
public class Test {
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;
}
}
public static void main(String[] args) throws IOException {
// put the url of your image
URL url = Paths.get("C:\\Users\\CTW\\Desktop\\oussama _pic.png").toUri().toURL();
// read an image from url
BufferedImage image = ImageIO.read(url);
// resize image to 300x150
Image scaledImage = image.getScaledInstance(300, 150, Image.SCALE_DEFAULT);
// set the image to the system clipboard
setClipboard(scaledImage);
// here open your Paint editor and click ctrl+v and you will see your image pasted there
}
}
Some code copied from here
I recently started to use multithreading in Java and I've run into a problem I assume is due to missing synchronization.
This is a ImageLoader I wrote:
package util;
import javax.swing.ImageIcon;
public class ImageLoader extends Thread {
private String file;
private ImageIcon icon;
public ImageLoader(String file) {
this.file = file;
}
#Override
public void run() {
ImageIcon icon = new ImageIcon(this.file);
this.icon = icon;
super.run();
}
public synchronized ImageIcon returnIcon() {
return this.icon;
}
}
I use this ImageLoader in my GUI-Class:
package gui;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import util.ImageLoader;
public class HauptGui extends JComponent {
public HauptGui() {
initUI();
}
private void initUI() {
int bilderAnzahl = 3;
this.setLayout(new GridLayout(1, 1));
JPanel bilderPanel = new JPanel(new GridLayout(bilderAnzahl, 1));
for (int i = 0; i < bilderAnzahl; i++) {
JLabel jbl = new JLabel();
ImageLoader loader = new ImageLoader("./Picture.jpg");
loader.start();
jbl.setIcon(loader.returnIcon());
jbl.setBorder(BorderFactory.createEtchedBorder());
jbl.setPreferredSize(new Dimension(200, 50));
bilderPanel.add(jbl);
}
JScrollPane scrPn = new JScrollPane(bilderPanel);
this.add(scrPn);
}
}
The Problem is that the returnIcon-Method of the ImageLoader gets called before the Thread calls the run-Method, therefore the ImageIcon is still null.
How do I synchronize this?
No, your problem has nothing to do with synchronization and all to do with simply requesting the image object before it has been created. The solution is to get the image object in a call-back, after it has completed its loading. A SwingWorker would work well in this situation, where you get the image object from the SwingWorker in the worker's done method by calling .get() on it, or you could use a PropertyChangeListener for your callback. See Lesson: Concurrency in Swing for the details on how to use SwingWorkers.
For example (code not tested)
public class ImageLoader2 extends SwingWorker<BufferedImage, Void> {
private String path = ""; /// String to resource path
public BufferedImage doInBackground() throws Exception {
return ImageIO.read(ImageLoader2.class.getResource(path));
}
}
and then run it like:
ImageLoader2 loader = new ImageLoader2();
loader.addPropertyChangeListener(pce -> {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
try {
BufferedImage img = loader.get();
ImageIcon icon = new ImageIcon(img);
// use icon here...
} catch catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
// handle exception here
}
}
});
loader.execute();
Side notes
you should almost never extend Thread.
Don't get the image as a File as you are doing but rather get it as a resource and use ImageIO.read(...) to do this
The resource path is relative to the class-path, not to the user's directory, and so it will likely be different from the path you use to get the image as a file.
I am creating a program that needs to copy an image to clipboard.
The problem is that the image has a transparent background and, whenever I copy it, the image comes out with a black background instead of transparent.
I tried lots of things since 2 days ago but none worked.
The class imageSelection is based on http://www.java2s.com/Tutorial/Java/0120__Development/SettinganimageontheclipboardwithacustomTransferableobjecttoholdtheimage.htm
package Package1;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
/** Transferable image */
public class imageSelection implements Transferable {
private Image image;
/** Creates a "transferable image" */
public imageSelection(Image image) {
this.image = image;
}
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] transferData = new DataFlavor[] { DataFlavor.imageFlavor }; // <--- Works but gives me a black background instead of transparent
/* I tried this (based on https://stackoverflow.com/questions/15977001/clipboard-copy-from-outlook-always-has-black-background-set-when-retrieved-as-im) but wasn't able to achieve any good result with it.
DataFlavor transferData = null;
try {
transferData = new DataFlavor(Image.class, null); // <---- How to get an object of the type DataFlavor[] from this ( DataFlavor("image/x-emf") is of the type DataFlavor, not DataFlavor[] )
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
error.displayError(e.getStackTrace(), "Error creating DataFlavor (mime type: image/x-emf)");
}
return new DataFlavor[] { transferData }
*/
return transferData;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return DataFlavor.imageFlavor.equals(flavor);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (!DataFlavor.imageFlavor.equals(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return image;
}
}
Call:
imageSelection imgSel = new imageSelection(new ImageIcon(emojiLocation).getImage());
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(imgSel, null);
Thanks
I am testing the contents by pasting it into Discord (chat app and it does support transparency, I made sure of that).
I am using jdk1.8.0_131.
I am using Windows 10 64bits fully updated.
If needed, full source code here: https://github.com/KingOffNothing/EmojiMenu-for-discord/tree/master/src/Package1
What the program does is change the clipboard to a selected image and then a program written in AHK will simulate the key press ctrl+v that pastes the image.
I was not able to exactly fix the transparency issue but was able to do a workaround (change transparent pixels to match the background's color)
private static BufferedImage fixTransparency(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
Color discordChatColor = new Color(54,57,62, 255);
for (int xx = 0; xx < width; xx++) {
for (int yy = 0; yy < height; yy++) {
Color originalColor = new Color(image.getRGB(xx, yy), true);
if (originalColor.getAlpha() == 0) {
image.setRGB(xx, yy, discordChatColor.getRGB());
}
}
}
return image;
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I am having trouble displaying an image on a JLabel. I have another class called ControlPanel which saves the image in the project folder. I had the methods which save the image in this class but for some reason, I was getting a NullPointerException. When I moved them in the other class everything started working properly. The actual image is a bufferedImage on which the user draws.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class GalleryPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private JLabel[] images;
private static final int MAX_IMAGES = 12;
private int currentImage;
public void init()
{
images = new JLabel[MAX_IMAGES];
setLayout(new GridLayout(3,4));
setBackground(Color.GRAY);
}
public void addImageToGallery(String fileName, String fileExtension)
{
if ( currentImage < images.length - 1)
{
ImageIcon icon = new ImageIcon(fileName + fileExtension);
images[currentImage] = new JLabel(icon, JLabel.CENTER);
add(images[currentImage]);
displayImage(currentImage);
currentImage++;
}
else
{
throw new ArrayIndexOutOfBoundsException("The gallery is full");
}
}
// display the doily image in the gallery
public void displayImage(int index)
{
images[index].setSize(300, 300);
add(images[index]);
}
public final int getMaxImages()
{
return MAX_IMAGES;
}
public Dimension getPreferredSize()
{
return new Dimension(380, 700);
}
}
those are the two methods in my other class which are responsible for saving the actual image
// Shows a dialog box which asks the user to choose a name for the file that he wants to save
public void saveImage(BufferedImage bufImage)
{
String fileName = JOptionPane.showInputDialog("Choose image name");
if (fileName != null)
{
if(fileName.equals(""))
{
fileName = "Untitled";
}
chooseImageFormat(bufImage, fileName);
}
}
//shows a dialog box which asks the user to select the file format of the image he would like to save
public void chooseImageFormat(BufferedImage bufImage, String fileName)
{
Object[] imageFormats = {"PNG", "JPEG"};
String userInput = (String) JOptionPane.showInputDialog(null, "Choose file format", "File Format Settings", JOptionPane.PLAIN_MESSAGE, null, imageFormats, "PNG");
String imageFormat = (userInput.equals("PNG")) ? "PNG" : "JPEG";
String fileExtension = (imageFormat.equals("PNG")) ? ".png" : ".jpg";
File file = new File(fileName + fileExtension );
try
{
ImageIO.write(bufImage, imageFormat, file);
}
catch (IOException e)
{
e.printStackTrace();
}
gallery.addImageToGallery(fileName, fileExtension);
}
I think you declare your gallery like this :
GalleryPanel gallery;
For that you get NullPointerException, so instead use this :
GalleryPanel gallery = new GalleryPanel();
EDIT
It worked but is there a way to not instantiate gallery like this?
You should to declare it and initialize it before you use it, there are another solution but you should to make many changes in your code, you have to make :
public static void addImageToGallery(String fileName, String fileExtension) {
You can call a static method like this
GalleryPanel.addImageToGallery(fileName, fileExtension);
But like i said, you should to make many changes.
Good luck.
In the following code, I call JOptionPane.showMessageDialog, inside a try/catch block. But when the error is caught, my JOptionPane is visible but without any message !!! Does someone knows why and how I can correct the problem ?
Regards
MyBoardJPannel.java
package experimentations.gui;
import java.awt.Graphics;
import java.awt.Image;
import java.io.InputStream;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class MyBoardPannel extends JPanel {
#Override
public void paint(Graphics grahics) {
if (imageToShow == null)
imageToShow = loadImage("sampleImage");
}
/**
* In fact, there are not any image in project => will go to catch clause.
* #param imageName
*/
private void loadImage(String imageName) {
InputStream imageStream = getClass().getResourceAsStream("/"+imageName+".png");
try {
imageToShow = ImageIO.read(imageStream);
}
catch (Exception e) {
String errorMessage = "Failed to load image "+imageName;
System.err.println(errorMessage);
JOptionPane.showMessageDialog(this, errorMessage,
"Image loading error", JOptionPane.ERROR_MESSAGE);
imageToShow = null;
System.exit(1);
}
}
private Image imageToShow;
}
JOptionPaneErrorShowing.java
package experimentations.gui;
import javax.swing.JFrame;
public class JOptionPaneErrorShowing extends JFrame {
public JOptionPaneErrorShowing(){
setTitle("JOptionPane experimentation");
setSize(300, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
add(new MyBoardPannel());
}
/**
* #param args
*/
public static void main(String[] args) {
new JOptionPaneErrorShowing().setVisible(true);
}
}
It's likely a Swing concurrency issue. But more importantly, you should never load an image from within a paint or paintComponent method, ever. Read it in the constructor or elsewhere but paint/paintComponent need to be lean and blazingly fast.
To solve your issue, consider reading in the image in SwingWorker object. If you call a JOptionPane from within the SwingWorker's doInBackground method though, be sure to call it on the Swing event thread, the EDT, using SwingUtilities.invokeLater(Runnable).
Also, you will hardly ever want to draw in a JPanel's paint method unless you are taking care of painting borders and children. Instead paint in a paintComponent method, and don't forget to call the super.paintComponent(g) method in that paintComponent override. You'll want to read the Swing graphics tutorials as this is all spelled out there.
For example:
import java.awt.Graphics;
import java.awt.Image;
import java.io.InputStream;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class MyBoardPannel extends JPanel {
protected static final String SAMPLE_IMAGE = "sampleImage";
Image imageToShow = null;
public MyBoardPannel() {
SwingWorker<Image, Void> mySW = new SwingWorker<Image, Void>() {
#Override
protected Image doInBackground() throws Exception {
return loadImage(SAMPLE_IMAGE);
}
#Override
protected void done() {
try {
imageToShow = get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
mySW.execute();
}
#Override
public void paintComponent(Graphics grahics) {
super.paintComponent(grahics);
if (imageToShow != null) {
grahics.drawImage(imageToShow, 0, 0, null);
}
}
private Image loadImage(String imageName) {
InputStream imageStream = getClass().getResourceAsStream(
"/" + imageName + ".png");
try {
return ImageIO.read(imageStream);
} catch (Exception e) {
final String errorMessage = "Failed to load image " + imageName;
System.err.println(errorMessage);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(MyBoardPannel.this, errorMessage,
"Image loading error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
});
}
return null;
}
}
I don't really know, but maybe your panel you use as parent of the JOptionPane (by passing this) is invisible or there is something else wrong. Try adding pack(); at the end of your JOptionPaneErrorShowing constructor.
What I know is that I had this problem when I was using an old Ubuntu and old Nvidia driver for my GPU, when the desktop effects were turned on (the Compiz Fusion of today. I don't know if it was already called Compiz, that long ago).
Aha! I found it, you are displaying the error inside the repaint method. Never do that! Load your image inside the constructor of the MyBoardPanel class and show error messages over there.