I have a java swing project I have been working on that involves parsing text data and then displaying graphical representations through local image files. I want the user to be able to copy the images displayed so that they can be pasted into other programs (such as Microsoft Word). It doesn't even need to happen like that, just any way I can make .jpg files copied so the user can paste them elsewhere. There would be a long chain of images, so just copying and pasting one at a time is not a possibility. Please help!
So, I threw this together really quickly and it works just fine for me.
Basically, you should be able to "export" just about any java.awt.Image based image, including BufferedImage
Updated, now with improved stiching...
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageTransfer {
public static void main(String[] args) {
try {
BufferedImage left = ImageIO.read(new File("left"));
BufferedImage right = ImageIO.read(new File("right"));
BufferedImage img = new BufferedImage(
left.getWidth() + right.getWidth(),
Math.max(left.getHeight(), right.getHeight()),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.drawImage(left, 0, (img.getHeight() - left.getHeight()) / 2, null);
g2d.drawImage(right, left.getWidth(), (img.getHeight() - right.getHeight()) / 2, null);
g2d.dispose();
final Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
cb.setContents(new ImageTransferable(img), new ClipboardOwner() {
#Override
public void lostOwnership(Clipboard clipboard, Transferable contents) {
System.out.println("You Lose");
}
});
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static class ImageTransferable implements Transferable {
private BufferedImage img;
public ImageTransferable(BufferedImage img) {
this.img = img;
}
#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 (!isDataFlavorSupported(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return img;
}
}
}
Note, while I loaded the image from a file, the image could be created dynamically in memory as well and it should work just fine...
Take a look at Writing/Saving an Image, Reading/Loading an Image and Drag and Drop and Data Transfer for more details
Related
I've been searching for a solution to accessing a built-in webcam from a java or javaFX application. I've seen loads of other posts pointing to OpenCV and JavaCV, Sarxos's library and quite a few others.
I've run into difficulties such as newer versions of OpenCV not working with older code posted on various sites and newer code that uses OpenCV 3.0 is hard to find or doesn't do what I need, which is simply a customer application which saves an image taken from the web cam to a variable (or file).
Hope someone can point me in the right direction.
Thanks in advance
You're in luck. I toyed around with OpenCV last weekend and ran into the same problems as you. Here's an example about how to do it. The example opens the camera, uses an AnimationTimer (a bit overkill, but was a quick solution for prototyping) to grab a mat image periodically, converts the mat image to a JavaFX image, performs face detection and paints it on a canvas.
Here's what you need:
Download OpenCV, e. g. in my case the windows version. Rename the opencv-3.0.0.exe to opencv-3.0.0.exe.zip and open it. Extract the contents of build/java.
Create a new JavaFX project. Put the jar and dlls into a lib folder, e. g.:
lib/opencv-300.jar
lib/x64/opencv_java300.dll
Add the jar to your build path.
In your src folder create a path opencv/data/lbpcascades and put the file lbpcascade_frontalface.xml in there (found in etc/lbpcascades). That's only for face detection, you can uncomment the code in case you don't need it.
Create the application class, code:
import java.io.ByteArrayInputStream;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
public class Camera extends Application {
private static final int SCENE_W = 640;
private static final int SCENE_H = 480;
CascadeClassifier faceDetector;
VideoCapture videoCapture;
Canvas canvas;
GraphicsContext g2d;
Stage stage;
AnimationTimer timer;
#Override
public void start(Stage stage) {
this.stage = stage;
initOpenCv();
canvas = new Canvas(SCENE_W, SCENE_H);
g2d = canvas.getGraphicsContext2D();
g2d.setStroke(Color.GREEN);
Group group = new Group(canvas);
Scene scene = new Scene(group, SCENE_W, SCENE_H);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
timer = new AnimationTimer() {
Mat mat = new Mat();
#Override
public void handle(long now) {
videoCapture.read(mat);
List<Rectangle2D> rectList = detectFaces(mat);
Image image = mat2Image(mat);
g2d.drawImage(image, 0, 0);
for (Rectangle2D rect : rectList) {
g2d.strokeRect(rect.getMinX(), rect.getMinY(), rect.getWidth(), rect.getHeight());
}
}
};
timer.start();
}
public List<Rectangle2D> detectFaces(Mat mat) {
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale( mat, faceDetections);
System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));
List<Rectangle2D> rectList = new ArrayList<>();
for (Rect rect : faceDetections.toArray()) {
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
rectList.add(new Rectangle2D(x, y, w, h));
}
return rectList;
}
private void initOpenCv() {
setLibraryPath();
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
videoCapture = new VideoCapture();
videoCapture.open(0);
System.out.println("Camera open: " + videoCapture.isOpened());
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
timer.stop();
videoCapture.release();
System.out.println("Camera released");
}
});
faceDetector = new CascadeClassifier(getOpenCvResource(getClass(), "/opencv/data/lbpcascades/lbpcascade_frontalface.xml"));
}
public static Image mat2Image(Mat mat) {
MatOfByte buffer = new MatOfByte();
Imgcodecs.imencode(".png", mat, buffer);
return new Image(new ByteArrayInputStream(buffer.toArray()));
}
private static void setLibraryPath() {
try {
System.setProperty("java.library.path", "lib/x64");
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
public static String getOpenCvResource(Class<?> clazz, String path) {
try {
return Paths.get( clazz.getResource(path).toURI()).toString();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
launch(args);
}
}
Of course you can do whatever you wish (e. g. saving) with the JavaFX image once you have it.
for sarxos, pseudo code, i can't publish whole class:
import com.sleepingdumpling.jvideoinput.Device;
import com.sleepingdumpling.jvideoinput.VideoFrame;
import com.sleepingdumpling.jvideoinput.VideoInput;
Device choosenDevice;
for (Device device : VideoInput.getVideoDevices()) {
// select your choosenDevice webcam here
if (isMyWebcam(device)) {
choosenDevice = device;
break;
}
}
// eg. VideoInput(640,480,25,choosenDevice );
VideoInput videoInput = new VideoInput(frameWidth, frameHeigth,
frameRate, choosenDevice );
VideoFrame vf = null;
while (grabFrames) {
vf = videoInput.getNextFrame(vf);
if (vf != null) {
frameReceived(vf.getRawData());
// or vf.getBufferedImage();
}
}
videoInput.stopSession();
I have this png file and converted it to jpg image.
As you can see, some pixels around the circles are not as smooth as the circles in the png image.
I have this code to convert png to jpeg. How do I update the code so that I can remove the noise around the circles.
BufferedImage bufferedJpgImage = new BufferedImage(inputPngImage.getWidth(null),
inputPngImage.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedImage.createGraphics();
g.drawImage(inputPngImage, 0, 0, bufferedJpgImage.getWidth(), bufferedJpgImage.getHeight(), Color.WHITE, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bufferedJpgImage, "jpg", out);
Jpeg uses a lossy compression algorithm, this means that the physical image data is modified in order to reduce the image size.
You can set the compression level through ImageIO, it's a little messy, but it should provide you the control you need.
So based the answer from Setting jpg compression level with ImageIO in Java, you could do something like:
The left is the original BufferedImage and the right is the resulting JPEG
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.spi.ServiceRegistry;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
try {
BufferedImage original = ImageIO.read(...);
BufferedImage bufferedJpgImage = new BufferedImage(original.getWidth(null),
original.getHeight(null),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = bufferedJpgImage.createGraphics();
g.drawImage(original, 0, 0, original.getWidth(), original.getHeight(), Color.WHITE, null);
g.dispose();
File jpg = new File("tmp.jpg");
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
write(bufferedJpgImage, baos);
try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())) {
BufferedImage image = ImageIO.read(bais);
JPanel panel = new JPanel();
panel.add(new JLabel(new ImageIcon(original)));
panel.add(new JLabel(new ImageIcon(image)));
JOptionPane.showMessageDialog(null, panel);
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static void write(BufferedImage capture, OutputStream to) throws IOException {
// use IIORegistry to get the available services
IIORegistry registry = IIORegistry.getDefaultInstance();
// return an iterator for the available ImageWriterSpi for jpeg images
Iterator<ImageWriterSpi> services = registry.getServiceProviders(ImageWriterSpi.class,
new ServiceRegistry.Filter() {
#Override
public boolean filter(Object provider) {
if (!(provider instanceof ImageWriterSpi)) {
return false;
}
ImageWriterSpi writerSPI = (ImageWriterSpi) provider;
String[] formatNames = writerSPI.getFormatNames();
for (int i = 0; i < formatNames.length; i++) {
if (formatNames[i].equalsIgnoreCase("JPEG")) {
return true;
}
}
return false;
}
},
true);
//...assuming that servies.hasNext() == true, I get the first available service.
ImageWriterSpi writerSpi = services.next();
ImageWriter writer = writerSpi.createWriterInstance();
// specifies where the jpg image has to be written
writer.setOutput(ImageIO.createImageOutputStream(to));
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);
// writes the file with given compression level
// from your JPEGImageWriteParam instance
writer.write(null, new IIOImage(capture, null, null), jpegParams);
}
}
You need to make sure you're managing your resources properly, closing or disposing of them when you have finished with them
What you are seeing is a natural consequence of JPEG compression in non-photographic images. JPEG relies on people not being able to notice small graduations in photographic images. When there is an abrupt change from one color to another, you get the artifacts you see.
You can reduce this effect by quantization table selection (quality settings in most encoders) and not sampling the Cb and Cr components at a lower rate than Y.
However, for an image like what you are showing, you are better off sticking with PNG.
I am working on a computer vision project and somewhere in a process an endless loop happens. It seems that my image data is being corrupted.
In past, I used to save debug results on the disk using this method:
public static boolean saveToPath(String path, BufferedImage image) {
File img = new File(path);
try {
ImageIO.write(image, "png", new File(path));
} catch (IOException ex) {
System.err.println("Failed to save image as '"+path+"'. Error:"+ex);
return false;
}
return true;
}
The problem is that once loops are used and the error is somewhere inbetween, I need to see many images. So basically, I'd like a method that would be defined like this:
/** Displays image on the screen and stops the execution until the window with image is closed.
*
* #param image image to be displayed
*/
public static void printImage(BufferedImage image) {
???
}
And could be called in a loop or any function to show be the actual image, effectively behaving like a break point. Because while multithreading is very good in production code, blocking functions are much better for debugging.
You can code something like this. In this example, the image file has to be in the same directory as the source code.
Here's the image displayed in a dialog. You left click the OK button to continue processing.
If the image is bigger than your screen, scroll bars will appear to let you see the whole image.
In your code, since you already have the Image, you can just copy and paste the displayImage method.
package com.ggl.testing;
import java.awt.Image;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class DisplayImage {
public DisplayImage() {
displayImage(getImage());
}
private Image getImage() {
try {
return ImageIO.read(getClass().getResourceAsStream(
"StockMarket.png"));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public void displayImage(Image image) {
JLabel label = new JLabel(new ImageIcon(image));
JPanel panel = new JPanel();
panel.add(label);
JScrollPane scrollPane = new JScrollPane(panel);
JOptionPane.showMessageDialog(null, scrollPane);
}
public static void main(String[] args) {
new DisplayImage();
}
}
I am new to swing. I was trying the game tutorial by wilchit sombat on making of packman. I cannot view the BufferedImage. Here is the code which overrides some methods from the game engine.
package game.packman;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.Game.Engine.Game;
import org.Game.Engine.GameApplication;
public class PackMan extends Game {
public static void main(String args[]) {
GameApplication.start(new PackMan());
}
BufferedImage packman;
public PackMan() {
title = "PACKMAN";
width = height = 400;
try {
packman = ImageIO.read(new File("images/pacmanimg.xcf"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void init() {
// TODO Auto-generated method stub
}
#Override
public void update() {
// TODO Auto-generated method stub
}
#Override
public void draw(Graphics g) {
g.drawImage(packman, 100, 100, null);
}
}
Image I/O has built-in support for GIF, PNG, JPEG, BMP, and WBMP. Image I/O is also extensible so that developers or administrators can "plug-in" support for additional formats. For example, plug-ins for TIFF and JPEG 2000 are separately available.
So, it seems that XCF: native image format of the GIMP image-editing program, is not supported by ImageIO.
Reference:
Reading/Loading an Image
Check size of the image packman after loaing
packman = ImageIO.read(new File("images/pacmanimg.xcf"));
It's 0 width/height if the image is not loaded.
Anyway it's better to place the image in your classpath and use getResourceAsStream() to load it through ImageIO. In opposite case when you pack your code in a jar you need to resolve working with files and relative paths problem.
I need to get the background image from a PowerPoint slide using java. I am aware of the Apache POI project. I can find material for getting text and shapes from the slides, but not the actual background. Does anyone have any suggestions?
EDIT: I have creaked the following code using the suggested link. This code seems to grab the contents of the slide, but not exactly the background. The resulting images are white for the background.
I tried it with this PowerPoint
package PowerPointProcessing;
import Logging.LogRunner;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.model.Background;
import org.apache.poi.hslf.model.Fill;
import org.apache.poi.hslf.model.Shape;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.usermodel.SlideShow;
/**
*
* #author dvargo
*/
public class PPI
{
Dimension pageSize;
public Slide[] theSlides;
public PPI(String powerPointFilePath)
{
SlideShow ppt = null;
//open the presentation
try
{
ppt = new SlideShow(new HSLFSlideShow(powerPointFilePath));
}
catch(Exception e)
{
LogRunner.getLogger().severe("Could not open the powerpoint presentation");
return;
}
//get all the slides
theSlides = ppt.getSlides();
//see how many slides there are
int numberOfSlides = theSlides.length;
pageSize = ppt.getPageSize();
}
public BufferedImage getBackground(Slide theSlide)
{
Background background;
background = theSlide.getBackground();
Fill f = background.getFill();
Color color = f.getForegroundColor();
Shape[] theShapes = theSlide.getShapes();
BufferedImage img = new BufferedImage(pageSize.width, pageSize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setPaint(color);
graphics.fill(new Rectangle2D.Float(0, 0, pageSize.width, pageSize.height));
theSlide.draw(graphics);
return img;
}
public static void main(String[] args) {
PPI ppi = new PPI("C:\\Documents and Settings\\dvargo\\Desktop\\Cludder\\a.ppt");
int count= 0;
for (Slide currSlide : ppi.theSlides)
{
BufferedImage img = ppi.getBackground(currSlide);
try
{
ImageIO.write(img, "jpeg", new File("C:\\Documents and Settings\\dvargo\\Desktop\\ppt\\" + count + ".jpeg"));
}
catch (IOException ex)
{
Logger.getLogger(PPI.class.getName()).log(Level.SEVERE, null, ex);
}
count++;
}
}
}
Looking at the code from this question:
Extracting images from pptx with apache poi
Looks like it should be something like:
Background background = slides[current].getBackground();
Fill f = background.getFill();
Color color = f.getForegroundColor();