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
Related
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 have a file browser component in my app (TableView), and I load the icons of files via FileSystemView.getFileSystemView().getSystemIcon(). Now, this is quite slow as I also need to convert the icon to BufferedImage, and that to JavaFX Image. So I needed to push this all to background thread(s). I created an IconLoadingTask, that loads a single icon - and during updateItem() of TableView I push these IconLoadingTasks to ExecutorService. It works, but could be improved.
The problem I have is that if the folder has lots of icons, and the user quickly drags the scrollbar, lots of "redundant" icons are loaded, stalling the thread(s) and resulting in often not seeing the icons that matter at the time: the ones that are currently displayed in the TableView.
Anyone have ideas how to solve this issue? I was thinking of accessing the vertical scrollbar of TableView and listening to it (and perhaps only update after scroll has been released), but I'm not sure how to even access the scrollbar... and maybe there's a simpler solution that escapes me.
EDIT:
Well, well. I created a minimal, complete and verifiable example out of my Kotlin code into Java code, and I cannot reproduce the "effect" anymore. It appears to work now as I intended it to in the first place. So it seems I just have to figure what "extra" I am doing in my main application's code. Anyways, here's the apparently working sample code.
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class IconLoadTest extends Application {
public static class FileEntry {
public Path path;
private Image icon;
public FileEntry(Path path) {
this.path = path;
}
synchronized void setIcon(Image icon) {
this.icon = icon;
}
synchronized Image getIcon() {
return icon;
}
public void setPath(Path path) {
this.path = path;
}
public Path getPath() {
return path;
}
}
class MyTableCell extends TableCell<FileEntry, Path> {
#Override
protected void updateItem(Path item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
setGraphic(null);
return;
}
setText(item.getFileName().toString());
Image icon = dataMap.get(item).getIcon();
if (icon == null) {
setGraphic(null);
executor.execute(new IconLoadingTask(item));
} else {
setGraphic(new ImageView(icon));
}
}
}
class IconLoadingTask extends Task<Void> {
private Path path;
IconLoadingTask(Path path) {
this.path = path;
}
#Override
protected Void call() {
FileEntry entry = dataMap.get(path);
if (entry.icon != null) {
return null;
}
entry.setIcon(getIcon(path.toFile()));
// Refresh currently visible items
Platform.runLater(() -> table.refresh());
return null;
}
}
private TableView<FileEntry> table = new TableView<>();
// Table data
private HashMap<Path, FileEntry> dataMap = new HashMap<>();
private List<FileEntry> data = FXCollections.observableArrayList();
private ExecutorService executor = Executors.newFixedThreadPool(1);
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.getChildren().add(table);
TableColumn<FileEntry, Path> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(new PropertyValueFactory<>("path"));
table.getColumns().add(nameCol);
nameCol.setCellFactory(tableColumn -> new MyTableCell());
// Sort so that dirs come first
nameCol.setComparator((o1, o2) -> {
if (Files.isDirectory(o1) && !Files.isDirectory(o2)) {
return -1;
} else if (!Files.isDirectory(o1) && Files.isDirectory(o2)) {
return 1;
} else {
return o1.toString().toLowerCase().compareTo(o2.toString().toLowerCase());
}
});
// Set to a directory with lots of files (e.g. System32 on Windows)
String directory = "C:\\Windows\\System32\\";
// Load files from directory, and create entries for table
Path dir = Paths.get(directory);
List<Path> files = listContents(dir);
for (Path p : files) {
FileEntry entry = new FileEntry(p);
data.add(entry);
dataMap.put(p, entry);
}
table.setItems((ObservableList<FileEntry>) data);
// Sort
table.getSortOrder().add(table.getColumns().get(0));
table.sort();
// Display the app
Scene scene = new Scene(root, 600, 480);
primaryStage.setTitle("Icon Background Loading");
primaryStage.setScene(scene);
primaryStage.show();
}
// Gets directory contents
private static List<Path> listContents(Path directory) {
ArrayList<Path> paths = new ArrayList<>();
try {
Files.newDirectoryStream(directory).forEach(paths::add);
} catch (IOException ex) {
ex.printStackTrace();
}
return paths;
}
// Gets a system icon for a file
private static Image getIcon(File file) {
Icon ico = FileSystemView.getFileSystemView().getSystemIcon(file);
java.awt.Image awtImage = ((ImageIcon) ico).getImage();
BufferedImage bImg;
if (awtImage instanceof BufferedImage) {
bImg = (BufferedImage) awtImage;
} else {
bImg = new BufferedImage(
awtImage.getWidth(null),
awtImage.getHeight(null),
BufferedImage.TYPE_INT_ARGB
);
Graphics graphics = bImg.createGraphics();
graphics.drawImage(awtImage, 0, 0, null);
graphics.dispose();
}
return SwingFXUtils.toFXImage(bImg, null);
}
public static void main(String[] args) {
Application.launch(IconLoadTest.class, args);
}
}
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
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.