Skip to contentPackage: ViewerPanel$1
ViewerPanel$1
name | instruction | branch | complexity | line | method |
---|
{...} |
|
|
|
|
|
Coverage
1: /*
2: * *********************************************************************************************************************
3: *
4: * Mistral: open source imaging engine
5: * http://tidalwave.it/projects/mistral
6: *
7: * Copyright (C) 2003 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *********************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
12: * the License. You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/mistral-src
23: * git clone https://github.com/tidalwave-it/mistral-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.mistral.example.viewer;
28:
29: import java.text.MessageFormat;
30: import java.io.IOException;
31: import java.awt.BorderLayout;
32: import javax.swing.DefaultComboBoxModel;
33: import it.tidalwave.image.EditableImage;
34: import it.tidalwave.image.Quality;
35: import it.tidalwave.image.metadata.Directory;
36: import it.tidalwave.image.metadata.EXIF;
37: import it.tidalwave.image.metadata.MakerNote;
38: import it.tidalwave.image.render.AnimatedScaleController;
39: import it.tidalwave.image.render.DragPanningController;
40: import it.tidalwave.image.render.MouseClickZoomingController;
41: import it.tidalwave.image.render.MouseWheelZoomingController;
42: import it.tidalwave.image.render.RotationController;
43: import it.tidalwave.image.render.ScaleController;
44: import it.tidalwave.image.render.event.EditableImageRendererAdapter;
45: import it.tidalwave.image.render.event.EditableImageRendererEvent;
46: import it.tidalwave.image.render.event.EditableImageRendererListener;
47: import it.tidalwave.mistral.example.AbstractViewerPanel;
48:
49: /***********************************************************************************************************************
50: *
51: * @author Fabrizio Giudici
52: *
53: **********************************************************************************************************************/
54: public class ViewerPanel extends AbstractViewerPanel
55: {
56: private static final DefaultComboBoxModel QUALITY_MODEL = new DefaultComboBoxModel()
57: {{
58: addElement(Quality.FASTEST);
59: addElement(Quality.INTERMEDIATE);
60: addElement(Quality.BEST);
61: }};
62:
63: private final ScaleController scaleController = new AnimatedScaleController(imageRenderer);
64:
65: private final RotationController rotationController = new RotationController(imageRenderer);
66:
67: private final MouseClickZoomingController mouseClickZoomingController =
68: new MouseClickZoomingController(scaleController);
69:
70: /**
71: * The zooming controller that runs with the mouse wheel.
72: */
73: private final MouseWheelZoomingController mouseWheelZoomingController =
74: new MouseWheelZoomingController(scaleController);
75:
76: private final DragPanningController panningController = new DragPanningController(imageRenderer);
77:
78: private final CropOverlay cropOverlay = new CropOverlay();
79:
80: /*******************************************************************************************************************
81: *
82: *
83: ******************************************************************************************************************/
84: private final EditableImageRendererListener scaleListener = new EditableImageRendererAdapter()
85: {
86: private static final String PHOTO_SIZE_PATTERN = "{0,number,#####}x{1,number,#####}x{2,number,##}";
87:
88: private static final String SCALE_PATTERN = "{0,number,percent}";
89:
90: @Override
91: public void scaleChanged (final EditableImageRendererEvent event)
92: {
93: final var image = imageRenderer.getImage();
94: final var width = image.getWidth();
95: final var height = image.getHeight();
96: final var depth = image.getBitsPerPixel();
97: lbSize.setText(MessageFormat.format(PHOTO_SIZE_PATTERN, width, height, depth));
98: lbScaleValue.setText(MessageFormat.format(SCALE_PATTERN, imageRenderer.getScale()));
99: }
100:
101: @Override
102: public void angleChanged (final EditableImageRendererEvent event)
103: {
104: lbAngleValue.setText("" + imageRenderer.getAngle());
105: }
106: };
107:
108: /*******************************************************************************************************************
109: *
110: *
111: ******************************************************************************************************************/
112: public ViewerPanel()
113: throws IOException
114: {
115: initComponents();
116: cbQuality.setModel(QUALITY_MODEL);
117: cbQuality.setSelectedItem(Quality.INTERMEDIATE);
118: imageRenderer.setOptimizedImageEnabled(true);
119: imageRenderer.addImageRendererListener(scaleListener);
120: // imageRenderer.setScaledImageCachingEnabled(true); FIXME - doesn't work
121: pnViewer.setLayout(new BorderLayout());
122: pnViewer.add(imageRenderer, BorderLayout.CENTER);
123: mouseClickZoomingController.setClickCountToZoom(2);
124: mouseClickZoomingController.setEnabled(true);
125: mouseWheelZoomingController.setEnabled(true);
126: panningController.setEnabled(true);
127: imageRenderer.addOverlay(cropOverlay);
128: loadImage("20030701-0043.jpg");
129: }
130:
131: /*******************************************************************************************************************
132: *
133: *
134: ******************************************************************************************************************/
135: @Override
136: protected void onImageLoaded (final EditableImage image)
137: {
138: final Directory exifDirectory = image.getMetadata(EXIF.class).get();
139: final Directory makerNoteDirectory = image.getMetadata(MakerNote.class).get();
140: final var exif = createTable(exifDirectory);
141: final var makerNote = createTable(makerNoteDirectory);
142: lbMetadata.setText(exif);
143: scaleController.fitToView();
144: }
145:
146: /*******************************************************************************************************************
147: *
148: *
149: ******************************************************************************************************************/
150: private String createTable (final Directory directory)
151: {
152: final var sb = new StringBuilder();
153: sb.append("<html>");
154:
155: if (directory != null)
156: {
157: sb.append("<table>");
158:
159: for (final var code : directory.getTagCodes())
160: {
161: final var tagName = directory.getTagInfo(code).get().getName();
162: final var tagValue = directory.getRaw(code);
163: sb.append("<tr><td>");
164: sb.append(Integer.toString(code));
165: sb.append("</td><td>");
166: sb.append(tagName);
167: sb.append("</td><td>");
168: sb.append(tagValue);
169: sb.append("</td></tr>");
170: }
171:
172: sb.append("</table>");
173: }
174:
175: sb.append("</html>");
176: return sb.toString();
177: }
178:
179: /*******************************************************************************************************************
180: *
181: * This method is called from within the constructor to
182: * initialize the form.
183: * WARNING: Do NOT modify this code. The content of this method is
184: * always regenerated by the Form Editor.
185: *
186: ******************************************************************************************************************/
187: // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
188: private void initComponents()
189: {
190:
191: pnStatusBar = new javax.swing.JPanel();
192: lbScale = new javax.swing.JLabel();
193: lbScaleValue = new javax.swing.JLabel();
194: lbSize = new javax.swing.JLabel();
195: lbAngle = new javax.swing.JLabel();
196: lbAngleValue = new javax.swing.JLabel();
197: pnViewer = new javax.swing.JPanel();
198: spMetadata = new javax.swing.JScrollPane();
199: lbMetadata = new javax.swing.JLabel();
200: pnToolBar = new javax.swing.JPanel();
201: btZoomIn = new javax.swing.JButton();
202: btActualPixels = new javax.swing.JButton();
203: btZoomOut = new javax.swing.JButton();
204: btFitToWindow = new javax.swing.JButton();
205: slRotation = new javax.swing.JSlider();
206: cbCrop = new javax.swing.JCheckBox();
207: btResetRotation = new javax.swing.JButton();
208: lbQuality = new javax.swing.JLabel();
209: cbQuality = new javax.swing.JComboBox();
210: cbScrollBars = new javax.swing.JCheckBox();
211:
212: pnStatusBar.setBorder(javax.swing.BorderFactory.createEmptyBorder(4, 4, 4, 4));
213:
214: lbScale.setText("Scale:");
215:
216: lbScaleValue.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
217: lbScaleValue.setText("0%");
218:
219: lbSize.setText(" ");
220:
221: lbAngle.setText("Angle:");
222:
223: lbAngleValue.setText("0");
224:
225: final var pnStatusBarLayout = new org.jdesktop.layout.GroupLayout(pnStatusBar);
226: pnStatusBar.setLayout(pnStatusBarLayout);
227: pnStatusBarLayout.setHorizontalGroup(
228: pnStatusBarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
229: .add(pnStatusBarLayout.createSequentialGroup()
230: .add(lbSize,
231: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
232: 181,
233: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
234: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
235: .add(lbScale)
236: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
237: .add(lbScaleValue,
238: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
239: 54,
240: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
241: .add(24, 24, 24)
242: .add(lbAngle)
243: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
244: .add(lbAngleValue)
245: .addContainerGap(460, Short.MAX_VALUE))
246: );
247: pnStatusBarLayout.setVerticalGroup(
248: pnStatusBarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
249: .add(pnStatusBarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
250: .add(lbScale)
251: .add(lbSize)
252: .add(lbScaleValue)
253: .add(lbAngleValue)
254: .add(lbAngle))
255: );
256:
257: final var pnViewerLayout = new org.jdesktop.layout.GroupLayout(pnViewer);
258: pnViewer.setLayout(pnViewerLayout);
259: pnViewerLayout.setHorizontalGroup(
260: pnViewerLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
261: .add(0, 631, Short.MAX_VALUE)
262: );
263: pnViewerLayout.setVerticalGroup(
264: pnViewerLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
265: .add(0, 308, Short.MAX_VALUE)
266: );
267:
268: spMetadata.setMinimumSize(new java.awt.Dimension(200, 8));
269:
270: lbMetadata.setFont(new java.awt.Font("Lucida Grande", 0, 8)); // NOI18N
271: lbMetadata.setVerticalAlignment(javax.swing.SwingConstants.TOP);
272: spMetadata.setViewportView(lbMetadata);
273:
274: pnToolBar.setBorder(javax.swing.BorderFactory.createEmptyBorder(4, 4, 4, 4));
275:
276: btZoomIn.setIcon(new javax.swing.ImageIcon(getClass().getResource(
277: "/it/tidalwave/mistral/example/viewer/icons/viewmag+.png"))); // NOI18N
278: btZoomIn.addActionListener(this::btZoomInActionPerformed);
279:
280: btActualPixels.setIcon(new javax.swing.ImageIcon(getClass().getResource(
281: "/it/tidalwave/mistral/example/viewer/icons/viewmag1.png"))); // NOI18N
282: btActualPixels.addActionListener(this::btActualPixelsActionPerformed);
283:
284: btZoomOut.setIcon(new javax.swing.ImageIcon(getClass().getResource(
285: "/it/tidalwave/mistral/example/viewer/icons/viewmag-.png"))); // NOI18N
286: btZoomOut.addActionListener(this::btZoomOutActionPerformed);
287:
288: btFitToWindow.setIcon(new javax.swing.ImageIcon(getClass().getResource(
289: "/it/tidalwave/mistral/example/viewer/icons/viewmagfit.png"))); // NOI18N
290: btFitToWindow.addActionListener(this::btFitToWindowActionPerformed);
291:
292: slRotation.setFont(new java.awt.Font("Lucida Grande", 0, 8)); // NOI18N
293: slRotation.setMajorTickSpacing(90);
294: slRotation.setMaximum(180);
295: slRotation.setMinimum(-180);
296: slRotation.setMinorTickSpacing(10);
297: slRotation.setPaintTicks(true);
298: slRotation.addChangeListener(this::slRotationStateChanged);
299:
300: cbCrop.setText("Crop");
301: cbCrop.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
302: cbCrop.setMargin(new java.awt.Insets(0, 0, 0, 0));
303: cbCrop.addChangeListener(this::cbCropStateChanged);
304:
305: btResetRotation.setText("Level");
306: btResetRotation.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
307: btResetRotation.addActionListener(this::btResetRotationActionPerformed);
308:
309: lbQuality.setText("Quality:");
310:
311: cbQuality.addActionListener(this::cbQualityActionPerformed);
312:
313: cbScrollBars.setText("Scroll bars");
314: cbScrollBars.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
315: cbScrollBars.setMargin(new java.awt.Insets(0, 0, 0, 0));
316: cbScrollBars.addActionListener(this::cbScrollBarsActionPerformed);
317:
318: final var pnToolBarLayout = new org.jdesktop.layout.GroupLayout(pnToolBar);
319: pnToolBar.setLayout(pnToolBarLayout);
320: pnToolBarLayout.setHorizontalGroup(
321: pnToolBarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
322: .add(pnToolBarLayout.createSequentialGroup()
323: .add(btZoomIn)
324: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
325: .add(btZoomOut)
326: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
327: .add(btFitToWindow)
328: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
329: .add(btActualPixels)
330: .add(10, 10, 10)
331: .add(cbScrollBars)
332: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
333: .add(slRotation,
334: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
335: 143,
336: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
337: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
338: .add(btResetRotation)
339: .add(18, 18, 18)
340: .add(lbQuality)
341: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
342: .add(cbQuality,
343: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
344: 145,
345: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
346: .add(11, 11, 11)
347: .add(cbCrop)
348: .addContainerGap(144, Short.MAX_VALUE))
349: );
350: pnToolBarLayout.setVerticalGroup(
351: pnToolBarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
352: .add(pnToolBarLayout.createSequentialGroup()
353: .add(pnToolBarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
354: .add(pnToolBarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
355: .add(btZoomIn,
356: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
357: 21,
358: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
359: .add(btZoomOut,
360: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
361: 21,
362: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
363: .add(btFitToWindow,
364: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
365: 21,
366: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
367: .add(btActualPixels,
368: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
369: 21,
370: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
371: .add(cbScrollBars))
372: .add(slRotation,
373: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
374: 21,
375: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
376: .add(pnToolBarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
377: .add(btResetRotation,
378: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
379: 21,
380: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
381: .add(cbQuality,
382: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
383: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
384: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
385: .add(cbCrop)
386: .add(lbQuality)))
387: .addContainerGap())
388: );
389:
390: final var layout = new org.jdesktop.layout.GroupLayout(this);
391: this.setLayout(layout);
392: layout.setHorizontalGroup(
393: layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
394: .add(pnStatusBar,
395: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
396: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
397: Short.MAX_VALUE)
398: .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
399: .add(pnViewer,
400: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
401: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
402: Short.MAX_VALUE)
403: .add(4, 4, 4)
404: .add(spMetadata,
405: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
406: 200,
407: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
408: .add(org.jdesktop.layout.GroupLayout.TRAILING,
409: pnToolBar,
410: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
411: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
412: Short.MAX_VALUE)
413: );
414: layout.setVerticalGroup(
415: layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
416: .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
417: .add(pnToolBar,
418: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
419: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
420: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
421: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
422: .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
423: .add(pnViewer,
424: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
425: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
426: Short.MAX_VALUE)
427: .add(spMetadata,
428: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
429: 308,
430: Short.MAX_VALUE))
431: .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
432: .add(pnStatusBar,
433: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
434: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
435: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
436: );
437: }// </editor-fold>//GEN-END:initComponents
438:
439: private void cbScrollBarsActionPerformed (final java.awt.event.ActionEvent evt)
440: {//GEN-FIRST:event_cbScrollBarsActionPerformed
441: imageRenderer.setScrollBarsVisible(cbScrollBars.isSelected());
442: }//GEN-LAST:event_cbScrollBarsActionPerformed
443:
444: private void cbQualityActionPerformed (final java.awt.event.ActionEvent evt)
445: {//GEN-FIRST:event_cbQualityActionPerformed
446: final var quality = (Quality)cbQuality.getSelectedItem();
447: imageRenderer.setScaleQuality(quality);
448: imageRenderer.setRotateQuality(quality);
449: repaint();
450: }//GEN-LAST:event_cbQualityActionPerformed
451:
452: private void btResetRotationActionPerformed (final java.awt.event.ActionEvent evt)
453: {//GEN-FIRST:event_btResetRotationActionPerformed
454: slRotation.setValue(0);
455: }//GEN-LAST:event_btResetRotationActionPerformed
456:
457: private void cbCropStateChanged (final javax.swing.event.ChangeEvent evt)
458: {//GEN-FIRST:event_cbCropStateChanged
459: cropOverlay.setVisible(cbCrop.isSelected());
460: imageRenderer.repaint();
461: }//GEN-LAST:event_cbCropStateChanged
462:
463: private void slRotationStateChanged (final javax.swing.event.ChangeEvent evt)
464: {//GEN-FIRST:event_slRotationStateChanged
465: rotationController.setAngle(slRotation.getValue());
466: }//GEN-LAST:event_slRotationStateChanged
467:
468: private void btFitToWindowActionPerformed (final java.awt.event.ActionEvent event)//GEN-FIRST:event_btFitToWindowActionPerformed
469: {//GEN-HEADEREND:event_btFitToWindowActionPerformed
470: scaleController.fitToView();
471: }//GEN-LAST:event_btFitToWindowActionPerformed
472:
473: private void btActualPixelsActionPerformed (final java.awt.event.ActionEvent event)//GEN-FIRST:event_btActualPixelsActionPerformed
474: {//GEN-HEADEREND:event_btActualPixelsActionPerformed
475: scaleController.showActualPixels();
476: }//GEN-LAST:event_btActualPixelsActionPerformed
477:
478: private void btZoomOutActionPerformed (final java.awt.event.ActionEvent event)//GEN-FIRST:event_btZoomOutActionPerformed
479: {//GEN-HEADEREND:event_btZoomOutActionPerformed
480: scaleController.zoomOut();
481: }//GEN-LAST:event_btZoomOutActionPerformed
482:
483: private void btZoomInActionPerformed (final java.awt.event.ActionEvent event)//GEN-FIRST:event_btZoomInActionPerformed
484: {//GEN-HEADEREND:event_btZoomInActionPerformed
485: scaleController.zoomIn();
486: }//GEN-LAST:event_btZoomInActionPerformed
487:
488: // Variables declaration - do not modify//GEN-BEGIN:variables
489: private javax.swing.JButton btActualPixels;
490: private javax.swing.JButton btFitToWindow;
491: private javax.swing.JButton btResetRotation;
492: private javax.swing.JButton btZoomIn;
493: private javax.swing.JButton btZoomOut;
494: private javax.swing.JCheckBox cbCrop;
495: private javax.swing.JComboBox cbQuality;
496: private javax.swing.JCheckBox cbScrollBars;
497: private javax.swing.JLabel lbAngle;
498: private javax.swing.JLabel lbAngleValue;
499: private javax.swing.JLabel lbMetadata;
500: private javax.swing.JLabel lbQuality;
501: private javax.swing.JLabel lbScale;
502: private javax.swing.JLabel lbScaleValue;
503: private javax.swing.JLabel lbSize;
504: private javax.swing.JPanel pnStatusBar;
505: private javax.swing.JPanel pnToolBar;
506: private javax.swing.JPanel pnViewer;
507: private javax.swing.JSlider slRotation;
508: private javax.swing.JScrollPane spMetadata;
509: // End of variables declaration//GEN-END:variables
510: }