Bonjour à tous,
Je crée actuellement un éditeur d'image en Java...
Actuellement, il est possible de dessiner sur un panel avec la souris (comme on dessine sur une feuille avec un crayon)...Sur ce panel est dessinée une image qu'on peut éditer...Mon but final est de créer une sorte de "Paint"...
Avant d'aller plus loin, je me suis dit qu'il serait bon d'implémenter les actions "Undo" et "Redo"...et c'est à ce niveau que j'ai actuellement un problème...
Mon éditeur se compose actuellement de 3 classes :
- DrawPanel.java
Cette classe est un panel sur lequel on dessine des images (BufferedImage)...Les 2 champs principaux de cette classe sont :
- "historic" : une ArrayList contenant des BufferedImage. ce champ permet de garder l'historique des modifications faites sur l'image.
- "currentIndexImage" : index dans l'ArrayList de l'image courante .
- ImageEditor.java
Cette classe est une JFrame contenant le DrawPanel (voir ci-dessus), un JLabel donnant les coordonnées de la souris dans le DrawPanel, et les 2 boutons "Undo" et "Redo"...
- Main.java
Permet de lancer le programme
Afin de cerner mon problème, je vous demande de lancer l'éditeur, de dessiner 3, 4 traits et d'utiliser les boutons undo et redo...Vous constaterez rapidemment qu'il est impossible de revenir à l'image initiale...et que lorsqu'on se trouve sur la dernière image, il faut cliquer deux fois sur "Undo" pour enlever la dernière modification...
A première vue, ca a l'air d'un compteur qui s'incrémente ou se décrémente mal, mais je ne vois pas d'où vient mon erreur! Je vous joins donc le code des 3 classes ainsi qu'une image de Test...
J'attends vos réponses avec impatience...Merci
DrawPanel.java
ImageEditor.java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.util.ArrayList; import javax.swing.ImageIcon; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class DrawPanel extends JPanel { private static int currentIndexImage = 0; // Historic of the images private ArrayList<BufferedImage> historic = new ArrayList<BufferedImage>(); private Dimension preferredSize; /** * Constructors */ public DrawPanel() { } public DrawPanel(ImageIcon image) { BufferedImage newImg = new BufferedImage(image.getIconWidth(), image.getIconHeight(),BufferedImage.TYPE_INT_RGB); Graphics g = newImg.createGraphics(); g.drawImage(image.getImage(),0,0,null); historic.add(newImg); g.dispose(); } /** * Set the new image to the panel and add it in the historic */ public void setImage(BufferedImage image) { BufferedImage newImg = new BufferedImage(image.getWidth(), image.getHeight(),BufferedImage.TYPE_INT_RGB); Graphics g = newImg.createGraphics(); g.drawImage(image,0,0,null); currentIndexImage++; historic.add(newImg); g.dispose(); //repaint(); } /** * @return the image used for painting the background of this panel */ public BufferedImage getImage() { //System.out.println("Set Image Get = " + currentIndexImage); return historic.get(currentIndexImage); } public BufferedImage getPrevImage() { currentIndexImage--; return getImage(); } public BufferedImage getNextImage() { currentIndexImage++; return getImage(); } public boolean isFirstImage() { return currentIndexImage == 0; } public boolean isLastImage() { return currentIndexImage == historic.size()-1; } public void setPreferredSize(Dimension pref) { preferredSize = pref; super .setPreferredSize(pref); } public Dimension getPreferredSize() { BufferedImage img = historic.get(currentIndexImage); if (preferredSize == null && img != null) { //it has not been explicitly set, so return the width/height of the image int width = img.getWidth(null); int height = img.getHeight(null); if (width == - 1|| height == -1) { return super .getPreferredSize(); } return new Dimension(width, height); } else { return super .getPreferredSize(); } } /** * Overriden to paint the image on the panel */ protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; BufferedImage img = historic.get(currentIndexImage); if (img != null) { final int imgWidth = img.getWidth(null); final int imgHeight = img.getHeight(null); if (imgWidth == -1 || imgHeight == -1) { //image hasn't completed loading, return return; } Insets insets = getInsets(); final int pw = getWidth() - insets.left - insets.right; final int ph = getHeight() - insets.top - insets.bottom; Rectangle clipRect = g2.getClipBounds(); int imageX = (pw - imgWidth) /2 + insets.left; int imageY = (ph - imgHeight) /2 + insets.top; Rectangle r = SwingUtilities.computeIntersection( imageX, imageY, imgWidth, imgHeight, clipRect); if (r.x ==0 && r.y ==0 && (r.width ==0 || r.height ==0 )) { return; } // I have my new clipping rectangle "r" in clipRect space. //It is therefore the new clipRect. clipRect = r; // since I have the intersection, all I need to do is adjust the //x & y values for the image int txClipX = clipRect.x - imageX; int txClipY = clipRect.y - imageY; int txClipW = clipRect.width; int txClipH = clipRect.height; g2.drawImage(img, clipRect.x, clipRect.y, clipRect.x + clipRect.width, clipRect.y + clipRect.height, txClipX, txClipY, txClipX + txClipW, txClipY + txClipH, null); } } }
Main.java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327 import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; public class ImageEditor extends JFrame implements ActionListener ,MouseListener, MouseMotionListener { /* Current mouse coordinates */ private int mousex = 0; private int mousey = 0; /* Previous mouse coordinates */ private int prevx = 0; private int prevy = 0; /* Initial state flags for operation */ private boolean initialPen = true; /* Primitive status & color variables */ private Color redColor = new Color(255,0,0); /* Assorted status values for different variables */ private JTextField mouseStatusBar = new JTextField(10); /* Labels for operation and color fields */ private JLabel cursorLabel = new JLabel(" Cursor:"); private JButton undoButton = new JButton("Undo"); private JButton redoButton = new JButton("Redo"); /* Sub panels of the main frame */ private JPanel statusPanel = new JPanel(new GridLayout(1,4,0,0)); private DrawPanel drawPanel = new DrawPanel(new ImageIcon("C:/smile.PNG")); private JPanel statusAndColorPanel = new JPanel(new GridLayout(2,1)); private BufferedImage bi; public void init() { setTitle("ImagEditor v.1"); setLayout(new BorderLayout()); setSize(350, 350); /* Add label and cursor text field */ statusPanel.add(cursorLabel); statusPanel.add(mouseStatusBar); statusPanel.add(undoButton); statusPanel.add(redoButton); // Add undo and redo buttons to actionListener undoButton.addActionListener(this); redoButton.addActionListener(this); /* Set not editable */ mouseStatusBar.setEditable(false); statusAndColorPanel.add(statusPanel); // InteralFrame containing the panel displaying the image JInternalFrame maFrame = new JInternalFrame(); maFrame.setVisible(true); maFrame.setLayout(new BorderLayout()); JPanel centerPanel = new JPanel(); centerPanel.add(maFrame); drawPanel.addMouseListener(this); drawPanel.addMouseMotionListener(this); maFrame.add(drawPanel,BorderLayout.CENTER); maFrame.pack(); // Place panel in the frame add(statusAndColorPanel, "North"); add(centerPanel, "Center"); this.setVisible(true); pack(); } /** * Draw a line from the previous mouse coordinates * to the current mouse coordinates */ private void dessinePen(Graphics g) { g.drawLine(prevx,prevy,mousex,mousey); g.dispose(); drawPanel.repaint(); } /* Method will emulate a pen style graphic. by drawing a line from the previous mouse corrdinates to the current mouse coordinates. Note: In initial attempt the previous mouse coordinates are set to the current mouse coordinates so as not to begin the pen graphic from an unwanted arbitrary point. */ public void penOperation(MouseEvent e) { bi = drawPanel.getImage(); Graphics g = bi.createGraphics(); g.setColor(redColor); // In initial state setup default values for mouse coordinates if (initialPen) { setGraphicalDefaults(e); initialPen = false; dessinePen(g); } // Make sure that the mouse has actually moved from its previous position. if (mouseHasMoved(e)) { // set mouse coordinates to current mouse position mousex = e.getX(); mousey = e.getY(); dessinePen(g); // Set the current mouse coordinates to previous mouse coordinates for next time prevx = mousex; prevy = mousey; } } /** * Implement actionPerformed method */ public void actionPerformed(ActionEvent e) { if (e.getSource() == undoButton) { undoOperation(); } if (e.getSource() == redoButton) { redoOperation(); } } public void undoOperation() { if (!drawPanel.isFirstImage()) { BufferedImage bi = drawPanel.getPrevImage(); Graphics g = drawPanel.getGraphics(); g.drawImage(bi,0,0,null); g.dispose(); drawPanel.repaint(); } else { System.out.println("Première Image"); } //drawPanel.testAll(); } public void redoOperation() { if (!drawPanel.isLastImage()) { BufferedImage bi = drawPanel.getNextImage(); Graphics g = drawPanel.getGraphics(); g.drawImage(bi,0,0,null); g.dispose(); drawPanel.repaint(); } else { System.out.println("Dernière Image"); } } /* Method determines weather the mouse has moved from its last recorded position. If mouse has deviated from previous position, the value returned will be true, otherwise the value that is returned will be false. */ public boolean mouseHasMoved(MouseEvent e) { return (mousex != e.getX() || mousey != e.getY()); } /* Method sets all the drawing varibles to the default state which is the current position of the mouse cursor Also the height and width varibles are zeroed off. */ public void setGraphicalDefaults(MouseEvent e) { mousex = e.getX(); mousey = e.getY(); prevx = e.getX(); prevy = e.getY(); } /* Method will be activated when mouse is being dragged. depending on what operation is the opstatus, the switch statement will call the relevent operation */ public void mouseDragged(MouseEvent e) { updateMouseCoordinates(e); penOperation(e); } /* Method will be activated when mouse has been release from pressed \ mode. At this stage the method will call the finalization routines for the current operation. */ public void mouseReleased(MouseEvent e) { /* Update current mouse coordinates to screen */ updateMouseCoordinates(e); releasedPen(); } /* Method will be activated when mouse enters the applet area. This method will then update the current mouse x and coordinates on the screen. */ public void mouseEntered(MouseEvent e) { updateMouseCoordinates(e); } /* Method is invoked when mouse has been released and current operation is Pen */ public void releasedPen() { initialPen = true; bi = drawPanel.getImage(); drawPanel.setImage(bi); //drawPanel.repaint(); } /* Method displays the mouse coordinates x and y values and updates the mouse status bar with the new values. */ public void updateMouseCoordinates(MouseEvent e) { String xCoor =""; String yCoor =""; if (e.getX() < 0) xCoor = "0"; else { xCoor = String.valueOf(e.getX()); } if (e.getY() < 0) xCoor = "0"; else { yCoor = String.valueOf(e.getY()); } mouseStatusBar.setText("x:"+xCoor+" y:"+yCoor); } /* Method updates mouse coordinates if mouse has been clicked */ public void mouseClicked(MouseEvent e) { updateMouseCoordinates(e); } /* Method updates mouse coordinates if mouse has exited the frame */ public void mouseExited(MouseEvent e) { updateMouseCoordinates(e); } /* Method updates mouse coordinates if mouse has moved */ public void mouseMoved(MouseEvent e) { updateMouseCoordinates(e); } /* Method updates mouse coordinates if mouse has been pressed */ public void mousePressed(MouseEvent e) { updateMouseCoordinates(e); } }
L'image de Test
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 public class Main { /** * @param args */ public static void main(String[] args) { ImageEditor sc = new ImageEditor(); sc.setDefaultCloseOperation(ImageEditor.EXIT_ON_CLOSE); sc.init(); } }
![]()
Partager