1

What I want my app to do:

1 - Select an area of Image and get the coordinates. This code below should do this:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;

public class ScreenCaptureRectangle {

Rectangle captureRect;

ScreenCaptureRectangle(final BufferedImage screen) {
    final BufferedImage screenCopy = new BufferedImage(
            screen.getWidth(),
            screen.getHeight(),
            screen.getType());
    final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
    JScrollPane screenScroll = new JScrollPane(screenLabel);

    screenScroll.setPreferredSize(new Dimension(
            (int)(screen.getWidth()/3),
            (int)(screen.getHeight()/3)));

    JPanel panel = new JPanel(new BorderLayout());
    panel.add(screenScroll, BorderLayout.CENTER);

    final JLabel selectionLabel = new JLabel(
            "Drag a rectangle in the screen shot!");
    panel.add(selectionLabel, BorderLayout.SOUTH);

    repaint(screen, screenCopy);
    screenLabel.repaint();

    screenLabel.addMouseMotionListener(new MouseMotionAdapter() {

        Point start = new Point();

        @Override
        public void mouseMoved(MouseEvent me) {
            start = me.getPoint();
            repaint(screen, screenCopy);
            selectionLabel.setText("Start Point: " + start);
            screenLabel.repaint();
        }

        @Override
        public void mouseDragged(MouseEvent me) {
            Point end = me.getPoint();
            captureRect = new Rectangle(start,
                    new Dimension(end.x-start.x, end.y-start.y));
            repaint(screen, screenCopy);
            screenLabel.repaint();
            selectionLabel.setText("Rectangle: " + captureRect);
        }
    });

    JOptionPane.showMessageDialog(null, panel);

    System.out.println("Rectangle of interest: " + captureRect);
}

public void repaint(BufferedImage orig, BufferedImage copy) {
    Graphics2D g = copy.createGraphics();
    g.drawImage(orig,0,0, null);
    if (captureRect!=null) {
        g.setColor(Color.RED);
        g.draw(captureRect);
        g.setColor(new Color(255,255,255,150));
        g.fill(captureRect);
    }
    g.dispose();
}

public static void main(String[] args) throws Exception {
    Robot robot = new Robot();
    final Dimension screenSize = Toolkit.getDefaultToolkit().
            getScreenSize();
    final BufferedImage screen = robot.createScreenCapture(
            new Rectangle(screenSize));

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            new ScreenCaptureRectangle(screen);
        }
    });
}
}

2 - get the coordinates and use it on getSubimage method.

double w  = captureRect.getWidth();
double h  = captureRect.getHeight();
double x  = captureRect.getX();
double y  = captureRect.getY();

int W = (int) w;
int H = (int) h;
int X = (int) x;
int Y = (int) y;

BufferedImage selectImg = screen.getSubimage(x, y, w, h);

3 - this code create a new image file and copy the imageselected.

BufferedImage img = new BufferedImage ( 5000, 5000, BufferedImage.TYPE_INT_RGB );
img.createGraphics().drawImage(selectImg, 0, 0, null);
File final_image = new File("C:/Final.jpg");
ImageIO.write(img, "jpeg", final_image);

The idea of app is:
- Select an area of the image.
- Copy that image and paste in other file. ( when I pressed any button )
- The program will continue run until I press another button.
- Every image that I copy the program will paste it beside the last one.

I think I am near to the solution. Can any one help me to "connect the parts" ?

fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • *"when i pressed any bottom"* - do you mean "button"? – MadProgrammer Oct 28 '14 at 02:46
  • *"Every image that I copy the program will paste it beside the last one"* - I assume this means on the screen or do you mean the files should be named in sequence? – MadProgrammer Oct 28 '14 at 02:59
  • Yes, you are right. It menans on the same screen. I wanted only one image file. Thank you very much. I am trying to understand what you did but it is perfect – Marco Vinicius Oct 28 '14 at 04:00

2 Answers2

3

Start by taking a look at:

You need to take the concepts you have and rework them into a coherent workable solution. That is, provide functionality between the areas you need (selecting a region and saving the file) so that they work cleanly together...

The following example takes a screenshot, allows you to select an area, click save and the file will be saved. The example checks to see how many files are already in the current directory and increments the count by 1 so you are not overwriting the existing files...

Select my world

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ScreenImage {

    public static void main(String[] args) {
        new ScreenImage();
    }

    public ScreenImage() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                try {
                    Robot robot = new Robot();
                    final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
                    final BufferedImage screen = robot.createScreenCapture(new Rectangle(screenSize));

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane(screen));
                    frame.setSize(400, 400);
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (AWTException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage master;

        public TestPane(BufferedImage image) {
            this.master = image;
            setLayout(new BorderLayout());
            final ImagePane imagePane = new ImagePane(image);
            add(new JScrollPane(imagePane));

            JButton btnSave = new JButton("Save");
            add(btnSave, BorderLayout.SOUTH);

            btnSave.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        BufferedImage img = imagePane.getSubImage();
                        master = append(master, img);
                        File save = new File("Capture.png");
                        ImageIO.write(master, "png", save);
                        imagePane.clearSelection();
                        JOptionPane.showMessageDialog(TestPane.this, save.getName() + " was saved", "Saved", JOptionPane.INFORMATION_MESSAGE);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                        JOptionPane.showMessageDialog(TestPane.this, "Failed to save capture", "Error", JOptionPane.ERROR_MESSAGE);
                    }
                }

                public BufferedImage append(BufferedImage master, BufferedImage sub) {

                    // Create a new image which can hold both background and the
                    // new image...
                    BufferedImage newImage = new BufferedImage(
                                    master.getWidth() + sub.getWidth(),
                                    Math.max(master.getHeight(), sub.getHeight()),
                                    BufferedImage.TYPE_INT_ARGB);
                    // Get new image's Graphics context
                    Graphics2D g2d = newImage.createGraphics();
                    // Draw the old background
                    g2d.drawImage(master, 0, 0, null);
                    // Position and paint the new sub image...
                    int y = (newImage.getHeight() - sub.getHeight()) / 2;
                    g2d.drawImage(sub, master.getWidth(), y, null);
                    g2d.dispose();

                    return newImage;

                }

            });

        }

    }

    public class ImagePane extends JPanel {

        private BufferedImage background;
        private Rectangle selection;

        public ImagePane(BufferedImage img) {
            background = img;
            MouseAdapter ma = new MouseAdapter() {

                private Point clickPoint;

                @Override
                public void mousePressed(MouseEvent e) {
                    clickPoint = e.getPoint();
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    Point dragPoint = e.getPoint();

                    int x = Math.min(clickPoint.x, dragPoint.x);
                    int y = Math.min(clickPoint.y, dragPoint.y);
                    int width = Math.abs(clickPoint.x - dragPoint.x);
                    int height = Math.abs(clickPoint.y - dragPoint.y);

                    selection = new Rectangle(x, y, width, height);
                    repaint();

                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

        public void clearSelection() {
            selection = null;
            repaint();
        }

        public BufferedImage getSubImage() {

            BufferedImage img = null;
            if (selection != null) {

                img = background.getSubimage(selection.x, selection.y, selection.width, selection.height);

            }
            return img;

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(background.getWidth(), background.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - background.getWidth()) / 2;
            int y = (getHeight() - background.getHeight()) / 2;
            g2d.drawImage(background, x, y, this);
            if (selection != null) {
                Color stroke = UIManager.getColor("List.selectionBackground");
                Color fill = new Color(stroke.getRed(), stroke.getGreen(), stroke.getBlue(), 128);
                g2d.setColor(fill);
                g2d.fill(selection);
                g2d.setColor(stroke);
                g2d.draw(selection);
            }
            g2d.dispose();
        }

    }

}

So apart from rendering the selection the hardest part would be generating the resulting image...

Basically, this done by creating a new BufferedImage and painting the old image and the new, sub, image together.

public BufferedImage append(BufferedImage master, BufferedImage sub) {

    // Create a new image which can hold both background and the
    // new image...
    BufferedImage newImage = new BufferedImage(
                    master.getWidth() + sub.getWidth(),
                    Math.max(master.getHeight(), sub.getHeight()),
                    BufferedImage.TYPE_INT_ARGB);
    // Get new image's Graphics context
    Graphics2D g2d = newImage.createGraphics();
    // Draw the old background
    g2d.drawImage(master, 0, 0, null);
    // Position and paint the new sub image...
    int y = (newImage.getHeight() - sub.getHeight()) / 2;
    g2d.drawImage(sub, master.getWidth(), y, null);
    g2d.dispose();

    return newImage;

}

The example replaces the previous (master) image with the one created here, so it will constantly be appending new images to the end of it...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thank you again. I tried to study the topics that you indicated but they are all in english and it`s more difficult to understand. For biggeners do you indicate the book [Java: How to program - Deitel] ? (there is a portuguese version) – Marco Vinicius Oct 28 '14 at 04:15
  • I'll try and update the example soon, to copy the image back to the screen. The book you're not reading isn't helping you. No one book will tell you everything. But try and get one that is reasonably up-to-date as the API has gone through some changes recently ;) – MadProgrammer Oct 28 '14 at 04:21
  • haha You are right. I'll study more programming. Just to clarify the idea: The program should paste every selected area of the image in another file image. One beside the other. The idea is to concatenate images just like we do with strings. (: – Marco Vinicius Oct 28 '14 at 04:33
  • So you don't want the new clips added to the screen/UI as well? Just to the file? – MadProgrammer Oct 28 '14 at 04:42
  • @MadProgrammer may program all the features you wanted, however, imho, it would be better if you can try it first, Marco. with the current answer, as you said, you are close to the final solution. – Yohanes Khosiawan 许先汉 Oct 28 '14 at 04:46
  • @YohanesKhosiawan许先汉 Agreed, but given the fact that each of the code snippets that the OP provided are actually snippets from other answers on SO, I thought it worth while to also provide some workflow guidance ;) – MadProgrammer Oct 28 '14 at 04:51
  • both of our answers already did, but since you are willing to implement further, it's okay. – Yohanes Khosiawan 许先汉 Oct 28 '14 at 04:52
  • @MadProgrammer Hello, mad. Sorry to bother you again with this project. (*) But i'm racking my brain with this. I started a new topic to organize all the ideas: http://stackoverflow.com/questions/26621889/concatenate-images-java-h-e-l-p – Marco Vinicius Oct 29 '14 at 02:36
0

You need more listeners for button pressed and released.. some lines in the mouseMoved also better placed in mousePressed.
You would want to update your captureRect when you release the mouse (in mouseReleased method).
Then you just write it to the file. You may adjust other things according to your needs.

And for clarity maybe it's better to add a save button into your UI.

public class ScreenCaptureRectangle {

    Rectangle captureRect;
    Point start = new Point();
    SimpleDateFormat sdf;

    ScreenCaptureRectangle(final BufferedImage screen) {
        sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        final BufferedImage screenCopy = new BufferedImage(
                screen.getWidth(),
                screen.getHeight(),
                screen.getType());
        final JLabel screenLabel = new JLabel(new ImageIcon(screenCopy));
        JScrollPane screenScroll = new JScrollPane(screenLabel);

        screenScroll.setPreferredSize(new Dimension(
                (int) (screen.getWidth() / 3),
                (int) (screen.getHeight() / 3)));

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(screenScroll, BorderLayout.CENTER);
        JButton btnSave = new JButton("SAVE");
        btnSave.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                double w = captureRect.getWidth();
                double h = captureRect.getHeight();
                double x = captureRect.getX();
                double y = captureRect.getY();

                int W = (int) w;
                int H = (int) h;
                int X = (int) x;
                int Y = (int) y;

                BufferedImage selectImg = screen.getSubimage(X, Y, W, H);
                try {
                    String fName = generateFileName();
                    if (fName != null) {
                        File f = new File(fName);
                        if (f.createNewFile()) {
                            ImageIO.write(selectImg, "jpg", f);
                        }
                    }
                } catch (IOException ex) {
                    Logger.getLogger(ScreenCaptureRectangle.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        panel.add(btnSave, BorderLayout.AFTER_LAST_LINE);

        final JLabel selectionLabel = new JLabel(
                "Drag a rectangle in the screen shot!");
        panel.add(selectionLabel, BorderLayout.SOUTH);

        repaint(screen, screenCopy);
        screenLabel.repaint();

        screenLabel.addMouseMotionListener(new MouseMotionAdapter() {

            @Override
            public void mouseDragged(MouseEvent me) {
                Point end = me.getPoint();
                captureRect = new Rectangle(start,
                        new Dimension(end.x - start.x, end.y - start.y));
                repaint(screen, screenCopy);
                screenLabel.repaint();
                selectionLabel.setText("Rectangle: " + captureRect);
            }

        });

        screenLabel.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent me) {
                start = me.getPoint();
                repaint(screen, screenCopy);
                selectionLabel.setText("Start Point: " + start);
                screenLabel.repaint();
            }

            @Override
            public void mouseReleased(MouseEvent me) {
                int endX = me.getX();
                int endY = me.getY();
                if (endX > start.x && endY > start.y) {
                    captureRect = new Rectangle(start.x, start.y, endX-start.x, endY-start.y);
                    System.out.println("Rectangle of interest: " + captureRect);
                }
            }

        });

        JOptionPane.showMessageDialog(null, panel);
    }

    private String generateFileName() {
        return new StringBuilder("screencrop_").append(sdf.format(new Date())).append(".jpg").toString();
    }

    public void repaint(BufferedImage orig, BufferedImage copy) {
        Graphics2D g = copy.createGraphics();
        g.drawImage(orig, 0, 0, null);
        if (captureRect != null) {
            g.setColor(Color.RED);
            g.draw(captureRect);
            g.setColor(new Color(255, 255, 255, 150));
            g.fill(captureRect);
        }
        g.dispose();
    }

    public static void main(String[] args) throws Exception {
        Robot robot = new Robot();
        final Dimension screenSize = Toolkit.getDefaultToolkit().
                getScreenSize();
        final BufferedImage screen = robot.createScreenCapture(
                new Rectangle(screenSize));

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ScreenCaptureRectangle(screen);
            }
        });
    }
}
  • Thank you, Yohanes. It is really good. Sorry about my bad english. what i tried to say is: put all the selected area on the same file image. one beside the other. – Marco Vinicius Oct 28 '14 at 04:23
  • my suggestion is: make a `List` of `Rectangles`, and add a button `Capture`. Every time you click `Capture`, you shall add a new `Rectangle` of the selection to the `List`. And when you hit button `Save`, you shall iterate those rectangles and get the total size (it will depend on how you want to combine them), and draw each subimage in one single `BufferedImage` like you want. When you face more problem(s) when you tried this, please ask again later (in a new post would be better I think). Good luck! – Yohanes Khosiawan 许先汉 Oct 28 '14 at 04:34
  • Hi, Yohanes. I did what you said but list has a limited length. So i found this code: [code] ArrayList al = new ArrayList(); al.add(new Rectangle(x, y, w, h)); [/code] But it is not working. Can you help me ? – Marco Vinicius Oct 28 '14 at 23:57
  • I found you on facebook. Can we talk there ? or in email ? it's easier – Marco Vinicius Oct 28 '14 at 23:58