How to take a screenshot of a JPanel with robot? - java

This is how I can make a screenshot of a whole JFrame
Rectangle screenRect = cap.getBounds();
File docfile = new File("image");
BufferedImage capture = new Robot().createScreenCapture(screenRect);
ImageIO.write(capture, "png", file);
with cap being a JFrame. But when I use a JPanel for cap, I get a partly screenshot of my desktop, not only of the JPanel, what I actually want.

It may help:
/**
* Perform a screen capture of a JPanel to a Buffered Image
*
* #param panel - Panel to screen copy
* #return BufferedImage
*
* #throws AWTException - if the platform configuration does not allow low-level
* input control. This exception is always thrown when
* GraphicsEnvironment.isHeadless() returns true
*/
public static BufferedImage printScreen(JPanel panel) throws AWTException {
Point p = panel.getLocationOnScreen();
Dimension dim = panel.getSize();
Rectangle rect = new Rectangle(p, dim);
Robot robot = new Robot();
return robot.createScreenCapture(rect);
}

Related

PDFbox 1.7.0 - How to keep existing image while adding new one with PDFBox?

I'm using PDFBox 1.7.0 (I do not have a choice for the version due to old version in production server). I am trying to add an image to an existing PDF which has already a logo.
When I add the new image, the old one disappears like it is replaced.
// Use for convert mm to dots
// ... 72 dots per inch
static final int DEFAULT_USER_SPACE_UNIT_DPI = 72;
// ... mm -> inch -> dots
static final float MM_TO_UNITS = 1 / (10 * 2.54f) * DEFAULT_USER_SPACE_UNIT_DPI;
/**
* Add a given image to a specific page of a PDF
* #param document PDF document to manipulate
* #param input image inputStream
* #param pdfpage page number to target
* #param x image position (en mm)
* #param y image position (en mm)
* #param width max width of the image (mm)
* #param height max height of the image (en mm)
* #param opacity opacity level of the image (fraction)
*/
void addImageToPage (PDDocument document, InputStream input, int pdfpage, int x, int y, int width, int height, float opacity) throws IOException {
if (input != null) {
// Convert inputstream to usable BufferedImage
BufferedImage tmp_image = ImageIO.read (input);
// User TYPE_4BYTE_ABGR to fix PDFBox issue with transparent PNG
BufferedImage image = new BufferedImage (tmp_image.getWidth(), tmp_image.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
// Prepare the image
image.createGraphics().drawRenderedImage (tmp_image, null);
PDXObjectImage ximage = new PDPixelMap (document, image);
// Resize the image
int iWidth = ximage.getWidth();
int iHeight = ximage.getHeight();
if (width / height > iWidth / iHeight) {
ximage.setWidth (Math.round (width * MM_TO_UNITS));
ximage.setHeight (Math.round ((iHeight * width / iWidth) * MM_TO_UNITS));
} else {
ximage.setWidth (Math.round ((iWidth * height / iHeight) * MM_TO_UNITS));
ximage.setHeight (Math.round (height * MM_TO_UNITS));
}
// Retrieve the page to update
PDPage page = (PDPage)document.getDocumentCatalog().getAllPages().get (pdfpage);
PDResources resources = page.findResources();
// Get graphics states
Map graphicsStates = resources.getGraphicsStates();
if (graphicsStates == null) {
graphicsStates = new HashMap();
}
// Set graphics states configurations
PDExtendedGraphicsState extendedGraphicsState = new PDExtendedGraphicsState();
// Set the opacity of the image
extendedGraphicsState.setNonStrokingAlphaConstant (opacity);
graphicsStates.put ("TransparentState", extendedGraphicsState);
// Restore graphics states
resources.setGraphicsStates (graphicsStates);
// Retrieve the content stream
PDPageContentStream contentStream = new PDPageContentStream (document, page, true, true);
// Activate transparency options
contentStream.appendRawCommands ("/TransparentState gs\n");
contentStream.endMarkedContentSequence();
// Insert image
contentStream.drawImage (
ximage,
(float) x * MM_TO_UNITS,
(float) y * MM_TO_UNITS
);
// close the stream
contentStream.close();
}
}
I expected to have the new image within the page, but the existing image inside the page has disappeared instead of the new one.
Example of used PDF : http://www.mediafire.com/folder/g6p7c2b5ob1c7/PDFBox_issue
There are several bugs in 1.7... one I mentioned in a comment (turns out it doesn't affect you), the other one is that the resources does some caching but isn't managed properly… long story short, you need to save and restore your xobject resources like this:
Map<String, PDXObject> xObjectsMap = page.getResources().getXObjects(); // save xobjects
…
PDXObjectImage ximage = new PDPixelMap (document, image);
String imgName = page.getResources().addXObject(ximage, "Im");
cs.drawImage(ximage, 0, 0); // bug happens here, old xobjects gets lost
xObjectsMap.put(imgName, ximage);
page.getResources().setXObjects(xObjectsMap); // restore xobjects
This is really just a workaround… there may be more bad surprises coming. You should not use old versions. They no longer spark joy. You should thank them for their service and then let them go without guilt.
Ok. I have given up trying to use PDFbox 1.7 for this part of the development. It requirement to many fixes to implements few things. It is not really maintainable for the future works. Thanks to everyone for the hints and helps.

GifSequenceWriter Creating White Gif

I need to split an image into separate slides and compile them into a .gif, but the .gif ends up being plain white. Each slide is 32x32 pixels and they are stacked horizontally with no spaces between them. I used the class GifSequenceWriter with my code:
/**
* #param args the command line arguments
* #throws java.io.IOException
*/
public static void main(String[] args) throws IOException {
String image = "Image.png";
BufferedImage entireSelection = ImageIO.read(new File(image));
int numOfSlides = entireSelection.getHeight()/32;
BufferedImage[] slides = new BufferedImage[numOfSlides];
for(int i = 0; i<numOfSlides; i++){
slides[i] = entireSelection.getSubimage(0,i*32, 32, 32);
}
createGif(slides);
}
private static void createGif(BufferedImage[] slides) throws IOException {
ImageOutputStream output = new FileImageOutputStream(new File("FinalGif.gif"));
GifSequenceWriter writer = new GifSequenceWriter(output, slides[0].getType() ,1,false);
for (BufferedImage slide : slides) {
writer.writeToSequence(slide);
}
writer.close();
output.close();
}
I have read on how to use the Writer and I cannot figure out what I am doing wrong.
I was using a .png that had partial transparency which made everything completely transparent. I just removed the transparency which fixed everything

OpenCV object detection contour position

I've used openCV library to detect objects of specific colours. The detection of the colour can be changed by playing around with the saturation and hue. My issue is to get the x and y position of the contours that are shown in the view.
Consider the following image. I need to get the position of the yellow lined contours.
Code:
public class ObjRecognitionController {
// FXML camera button
#FXML
private Button cameraButton;
// the FXML area for showing the current frame
#FXML
private ImageView originalFrame;
// the FXML area for showing the mask
#FXML
private ImageView maskImage;
// the FXML area for showing the output of the morphological operations
#FXML
private ImageView morphImage;
// FXML slider for setting HSV ranges
#FXML
private Slider hueStart;
#FXML
private Slider hueStop;
#FXML
private Slider saturationStart;
#FXML
private Slider saturationStop;
#FXML
private Slider valueStart;
#FXML
private Slider valueStop;
// FXML label to show the current values set with the sliders
#FXML
private Label hsvCurrentValues;
// a timer for acquiring the video stream
private ScheduledExecutorService timer;
// the OpenCV object that performs the video capture
private VideoCapture capture = new VideoCapture();
// a flag to change the button behavior
private boolean cameraActive;
// property for object binding
private ObjectProperty<String> hsvValuesProp;
/**
* The action triggered by pushing the button on the GUI
*/
#FXML
private void startCamera()
{
// bind a text property with the string containing the current range of
// HSV values for object detection
hsvValuesProp = new SimpleObjectProperty<>();
this.hsvCurrentValues.textProperty().bind(hsvValuesProp);
// set a fixed width for all the image to show and preserve image ratio
this.imageViewProperties(this.originalFrame, 400);
this.imageViewProperties(this.maskImage, 200);
this.imageViewProperties(this.morphImage, 200);
if (!this.cameraActive)
{
// start the video capture
this.capture.open(0);
// is the video stream available?
if (this.capture.isOpened())
{
this.cameraActive = true;
// grab a frame every 33 ms (30 frames/sec)
Runnable frameGrabber = new Runnable() {
#Override
public void run()
{
Image imageToShow = grabFrame();
originalFrame.setImage(imageToShow);
}
};
this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
// update the button content
this.cameraButton.setText("Stop Camera");
}
else
{
// log the error
System.err.println("Failed to open the camera connection...");
}
}
else
{
// the camera is not active at this point
this.cameraActive = false;
// update again the button content
this.cameraButton.setText("Start Camera");
// stop the timer
try
{
this.timer.shutdown();
this.timer.awaitTermination(33, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e)
{
// log the exception
System.err.println("Exception in stopping the frame capture, trying to release the camera now... " + e);
}
// release the camera
this.capture.release();
}
}
/**
* Get a frame from the opened video stream (if any)
*
* #return the {#link Image} to show
*/
private Image grabFrame()
{
// init everything
Image imageToShow = null;
Mat frame = new Mat();
// check if the capture is open
if (this.capture.isOpened())
{
try
{
// read the current frame
this.capture.read(frame);
// if the frame is not empty, process it
if (!frame.empty())
{
// init
Mat blurredImage = new Mat();
Mat hsvImage = new Mat();
Mat mask = new Mat();
Mat morphOutput = new Mat();
// remove some noise
Imgproc.blur(frame, blurredImage, new Size(7, 7));
// convert the frame to HSV
Imgproc.cvtColor(blurredImage, hsvImage, Imgproc.COLOR_BGR2HSV);
// get thresholding values from the UI
// remember: H ranges 0-180, S and V range 0-255
Scalar minValues = new Scalar(this.hueStart.getValue(), this.saturationStart.getValue(),
this.valueStart.getValue());
Scalar maxValues = new Scalar(this.hueStop.getValue(), this.saturationStop.getValue(),
this.valueStop.getValue());
// show the current selected HSV range
String valuesToPrint = "Hue range: " + minValues.val[0] + "-" + maxValues.val[0]
+ "\tSaturation range: " + minValues.val[1] + "-" + maxValues.val[1] + "\tValue range: "
+ minValues.val[2] + "-" + maxValues.val[2];
this.onFXThread(this.hsvValuesProp, valuesToPrint);
// threshold HSV image to select tennis balls
Core.inRange(hsvImage, minValues, maxValues, mask);
// show the partial output
this.onFXThread(this.maskImage.imageProperty(), this.mat2Image(mask));
// morphological operators
// dilate with large element, erode with small ones
Mat dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(24, 24));
Mat erodeElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(12, 12));
Imgproc.erode(mask, morphOutput, erodeElement);
Imgproc.erode(mask, morphOutput, erodeElement);
Imgproc.dilate(mask, morphOutput, dilateElement);
Imgproc.dilate(mask, morphOutput, dilateElement);
// show the partial output
this.onFXThread(this.morphImage.imageProperty(), this.mat2Image(morphOutput));
// find the tennis ball(s) contours and show them
frame = this.findAndDrawBalls(morphOutput, frame);
// convert the Mat object (OpenCV) to Image (JavaFX)
imageToShow = mat2Image(frame);
}
}
catch (Exception e)
{
// log the (full) error
System.err.print("ERROR");
e.printStackTrace();
}
}
return imageToShow;
}
/**
* Given a binary image containing one or more closed surfaces, use it as a
* mask to find and highlight the objects contours
*
* #param maskedImage
* the binary image to be used as a mask
* #param frame
* the original {#link Mat} image to be used for drawing the
* objects contours
* #return the {#link Mat} image with the objects contours framed
*/
private Mat findAndDrawBalls(Mat maskedImage, Mat frame) {
// init
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
// find contours
Imgproc.findContours(maskedImage, contours, hierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE);
// if any contour exist...
if (hierarchy.size().height > 0 && hierarchy.size().width > 0) {
// for each contour, display it in yellow
for (int idx = 0; idx >= 0; idx = (int) hierarchy.get(0, idx)[0]) {
Imgproc.drawContours(frame, contours, idx, new Scalar(0, 255, 255));
}
}
return frame;
}
/**
* Set typical {#link ImageView} properties: a fixed width and the
* information to preserve the original image ration
*
* #param image
* the {#link ImageView} to use
* #param dimension
* the width of the image to set
*/
private void imageViewProperties(ImageView image, int dimension) {
// set a fixed width for the given ImageView
image.setFitWidth(dimension);
// preserve the image ratio
image.setPreserveRatio(true);
}
/**
* Convert a {#link Mat} object (OpenCV) in the corresponding {#link Image}
* for JavaFX
*
* #param frame
* the {#link Mat} representing the current frame
* #return the {#link Image} to show
*/
private Image mat2Image(Mat frame) {
// create a temporary buffer
MatOfByte buffer = new MatOfByte();
// encode the frame in the buffer, according to the PNG format
Imgcodecs.imencode(".png", frame, buffer);
// build and return an Image created from the image encoded in the
// buffer
return new Image(new ByteArrayInputStream(buffer.toArray()));
}
/**
* Generic method for putting element running on a non-JavaFX thread on the
* JavaFX thread, to properly update the UI
*
* #param property
* a {#link ObjectProperty}
* #param value
* the value to set for the given {#link ObjectProperty}
*/
private <T> void onFXThread(final ObjectProperty<T> property, final T value)
{
Platform.runLater(new Runnable() {
#Override
public void run()
{
property.set(value);
}
});
}
}
You can get the bounded rectangle with boundingRect() function of OpenCV
Rect rect = Imgproc.boundingRect(contours.get(idx));
Now you can get the x and y positions by rect.x and rect.y
Then you can draw the rect on image mat
Imgproc.rectangle(mat, rect.tl(), rect.br(), color, THICKNESS=1 or 2 ...);

take snapshot of full JFrame and Jframe only [duplicate]

This question already has an answer here:
Swing: Obtain Image of JFrame
(1 answer)
Closed 7 years ago.
Heys guys, I've developped a code to take a screen shot of my whole screen, but I want it to take the screen shot of only the things inside my Jframe. Ill be using it to print the image later on by the way. And one of the main problem is, the mouse also comes inside the snapshot. I don't want the mouse or the two buttons at the bottom. I can just change visi of buttons but what should be done for mouse and inside Jframe only shot? Here is my code it takes screen shot of whole screen.
try{
Thread.sleep(1000);
Toolkit tk = Toolkit.getDefaultToolkit(); //Toolkit class returns the default toolkit
Dimension d = tk.getScreenSize();
//Dimension class object stores width & height of the toolkit screen
// toolkit.getScreenSize() determines the size of the screen
Rectangle rec = new Rectangle(0, 0, d.width, d.height);
//Creates a Rectangle with screen dimensions,
Robot ro = new Robot(); //to capture the screen image
BufferedImage img = ro.createScreenCapture(rec);
File f;
f = new File("myimage.jpg"); // File class is used to write the above generated buffered image to a file
ImageIO.write(img, "jpg", f);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
IMHO it is better to make an image of your component (a JFrame is also a Component):
BufferedImage img = new BufferedImage(yourComponent.getWidth(), yourComponent.getHeight(), BufferedImage.TYPE_INT_RGB);
yourComponent.paint(img.getGraphics());
File outputfile = new File("saved.png");
ImageIO.write(img, "png", outputfile);

How to select a portion of an image and save just that portion to a file

I am taking a screenshot of the current screen then saving the image. I want to open that image up and be able to select a box of a certain element or whatever it is i want the pic to be of and to be able to in turn save that smaller selected image to
a file. Please help.
RemoteControlConfiguration config = new RemoteControlConfiguration();
config.setPort(4447);
SeleniumServer server = new SeleniumServer(config);
try{
// TODO Auto-generated method stub
server.start();
DefaultSelenium selenium = new DefaultSelenium("localhost", 4447, "*firefox", "http://www.google.com/");
selenium.start();
selenium.open("http://www.google.com/");
selenium.waitForPageToLoad("10000");
selenium.windowMaximize();
BufferedImage image1 = Screenshot("screen1.jpg");
//selenium.type("q", "Hello world");
Thread.sleep(2000);
BufferedImage image2 = Screenshot("screen2.jpg");
public static BufferedImage Screenshot(String fileName) throws Exception
{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Rectangle screenRectangle = new Rectangle(screenSize);
Robot robot = new Robot();
BufferedImage image = robot.createScreenCapture(screenRectangle);
File file = new File(fileName);
ImageIO.write(image, "jpg", file);
return image;
}
Assuming you know the coordinates of your new bounds, create a new BufferedImage with the new size, create a graphics object for your new image, and paint the big image on this graphics object, specifying negative values for the x,y. The source image is bigger than the destination, so only the bits that fit within the destination will be written. Then you save out the smaller one using ImageIO.write()
EDIT
Thanks to Andrew Thompson for the suggestion to use subImage
BufferedImage image1 = Screenshot("screen1.jpg");
BufferedImage subImage = image1.getSubImage(x, y, width, height);

Categories