My application lets the user uploads an image, draw rectangles on top of it for annotation, and attach comments to that annotated region. I want to develop a save feature in such a way that when the user clicks on the save button, the app will save the annotations and the comments associated with the image (if the user made any). If the user exits the application and opens it again, and uploads a previously annotated/saved image, the app will display/redraw rectangles accordingly with comments still intact.
Since I'm saving multiple rectangles and comments, I'm having trouble figuring out how to properly achieve this behavior.
(NOTE: I don't want to save the rectangles and comments with the image to a file, instead I'm looking for the behavior where the app saves just the rectangles and the comments, with some sort of reference to the original image file, such as the name). I have provided my code below for clarity.
Model.java:
public class Model {
Annotator annotator;
Box selectedBox;
public Model() {
annotator = new Annotator();
}
public void setAnnotator(Annotator a) { annotator = a; }
public Annotator getAnnotator() { return annotator; }
public void setSelectedBox(Box b) { selectedBox = b; }
public Box getSelectedBox() { return selectedBox; }
public void clearSelectedBox() { selectedBox = null; }
}
Box.java:
public class Box {
int bWidth, bHeight, bX, bY;
String bImageName, bComment = "";
public boolean isSelected = false;
Color foreground;
Rectangle rectangle;
public Box(int width, int height) {
bWidth = width;
bHeight = height;
}
public Box(Color foreground, Rectangle rectangle) {
this.foreground = foreground;
this.rectangle = rectangle;
}
public void setImageName(String imageName) { bImageName = imageName; }
public String getImageName() { return bImageName; }
public void setComment(String comment) { bComment = comment; }
public String getComment() { return bComment; }
public void setX(int x) { bX = x; }
public int getX() { return bX; }
public void setY(int y) { bY = y; }
public int getY() { return bY; }
public Color getForeground()
{
return foreground;
}
public void setForeground(Color foreground)
{
this.foreground = foreground;
}
public Rectangle getRectangle()
{
return rectangle;
}
}
DrawingArea.java:
public class DrawingArea extends JPanel implements BoxSelectionListener
{
private final static int AREA_SIZE = 490;
private BufferedImage image =
new BufferedImage(AREA_SIZE, AREA_SIZE, BufferedImage.TYPE_INT_ARGB);
private Rectangle shape;
public ArrayList<Box> rectangles = new ArrayList<Box>();
Model model;
//public String imageName = ""; // this will store the image/file name
public DrawingArea(Model m)
{
setBackground(Color.WHITE);
this.model = m;
MyMouseListener ml = new MyMouseListener();
addMouseListener(ml);
addMouseMotionListener(ml);
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// Custom code to support painting from the BufferedImage
if (image != null)
{
g.drawImage(image, 0, 0, null);
}
Color foreground = g.getColor();
for (Box b : rectangles)
{
g.setColor( b.getForeground() );
Rectangle r = b.getRectangle();
g.drawRect(r.x, r.y, r.width, r.height);
}
// Paint the Rectangle as the mouse is being dragged
if (shape != null)
{
Graphics2D g2d = (Graphics2D)g;
g2d.draw( shape );
}
}
public void addRectangle(Rectangle rectangle, Color color)
{
// Draw the Rectangle onto the BufferedImage
Box b = new Box(color, rectangle);
rectangles.add( b );
repaint();
}
public void loadImage() // I'm assuming this is where the logic needs to go for loading from file
{
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(null);
File f = chooser.getSelectedFile();
ImageAnnotator.ImageName.setText(f.getName()); // here I'm saving the name of image/file
try {
image = scaleImage(490, 490, ImageIO.read(new File(f.getAbsolutePath())));
} catch (Exception ex) {
ex.printStackTrace();
}
Graphics2D g2d = (Graphics2D)image.getGraphics();
g2d.setColor(Color.BLACK);
repaint();
}
public void saveImage() {
// save rectangles and attached comments
}
class MyMouseListener extends MouseInputAdapter
{
private Point startPoint;
public void mousePressed(MouseEvent e) {
// Mark the clip point
startPoint = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
// Only create the shape when dragging starts
if (shape == null) {
shape = new Rectangle();
}
int x = Math.min(startPoint.x, e.getX());
int y = Math.min(startPoint.y, e.getY());
int width = Math.abs(startPoint.x - e.getX());
int height = Math.abs(startPoint.y - e.getY());
shape.setBounds(x, y, width, height);
repaint();
}
public void mouseReleased(MouseEvent e) {
if (shape != null) {
if (shape.width != 0 || shape.height != 0) {
addRectangle(shape, e.getComponent().getForeground());
ImageAnnotator.btnNewButton.setVisible(true);
ImageAnnotator.textPane.setVisible(true);
}
} else {
for (Box b : rectangles) {
if (b.getRectangle().contains(e.getPoint())) {
didSelect(b);
repaint();
}
else
b.setForeground(Color.black);
repaint();
b.isSelected = false;
}
}
startPoint = null;
shape = null;
}
}
}