Changeset 13191 in josm
- Timestamp:
- 2017-12-03T20:16:52+01:00 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java
r13186 r13191 23 23 import java.awt.geom.Rectangle2D; 24 24 import java.awt.image.BufferedImage; 25 import java.awt.image.ImageObserver; 25 26 import java.io.File; 26 27 … … 112 113 public static class VisRect extends Rectangle { 113 114 private final Rectangle init; 115 116 /** set when this {@code VisRect} is updated by a mouse drag operation and 117 * unset on mouse release **/ 118 public boolean isDragUpdate; 114 119 115 120 /** … … 125 130 } 126 131 132 /** 133 * Constructs a new {@code VisRect}. 134 * @param x the specified X coordinate 135 * @param y the specified Y coordinate 136 * @param width the width of the rectangle 137 * @param height the height of the rectangle 138 * @param peer share full bounds with this peer {@code VisRect} 139 */ 127 140 public VisRect(int x, int y, int width, int height, VisRect peer) { 128 141 super(x, y, width, height); … … 200 213 201 214 /** The thread that reads the images. */ 202 private class LoadImageRunnable implements Runnable { 215 private class LoadImageRunnable implements Runnable, ImageObserver { 203 216 204 217 private final File file; 205 218 private final int orientation; 219 private int width; 220 private int height; 206 221 207 222 LoadImageRunnable(File file, Integer orientation) { … … 211 226 212 227 @Override 228 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { 229 if (((infoflags & ImageObserver.WIDTH) == ImageObserver.WIDTH) && 230 ((infoflags & ImageObserver.HEIGHT) == ImageObserver.HEIGHT)) { 231 this.width = width; 232 this.height = height; 233 synchronized (this) { 234 this.notify(); 235 return false; 236 } 237 } 238 return true; 239 } 240 241 @Override 213 242 public void run() { 214 243 Image img = Toolkit.getDefaultToolkit().createImage(file.getPath()); 215 tracker.addImage(img, 1); 216 217 // Wait for the end of loading 218 while (!tracker.checkID(1, true)) { 219 if (this.file != ImageDisplay.this.file) { 220 // The file has changed 221 tracker.removeImage(img); 222 return; 223 } 224 try { 225 Thread.sleep(5); 226 } catch (InterruptedException e) { 227 Logging.warn("InterruptedException in "+getClass().getSimpleName()+" while loading image "+file.getPath()); 228 Thread.currentThread().interrupt(); 229 } 230 } 231 232 boolean error = tracker.isErrorID(1); 233 if (img.getWidth(null) < 0 || img.getHeight(null) < 0) { 234 error = true; 244 245 synchronized (this) { 246 width = -1; 247 img.getWidth(this); 248 img.getHeight(this); 249 250 while (width < 0) { 251 try { 252 this.wait(); 253 if (width < 0) { 254 errorLoading = true; 255 return; 256 } 257 } catch (InterruptedException e) { 258 e.printStackTrace(); 259 } 260 } 261 } 262 263 long allocatedMem = Runtime.getRuntime().totalMemory() - 264 Runtime.getRuntime().freeMemory(); 265 long mem = Runtime.getRuntime().maxMemory()-allocatedMem; 266 267 if (mem > ((long) width*height*4)*2) { 268 Logging.info("Loading {0} using default toolkit", file.getPath()); 269 tracker.addImage(img, 1); 270 271 // Wait for the end of loading 272 while (!tracker.checkID(1, true)) { 273 if (this.file != ImageDisplay.this.file) { 274 // The file has changed 275 tracker.removeImage(img); 276 return; 277 } 278 try { 279 Thread.sleep(5); 280 } catch (InterruptedException e) { 281 Logging.trace(e); 282 Logging.warn("InterruptedException in "+getClass().getSimpleName()+ 283 " while loading image "+file.getPath()); 284 Thread.currentThread().interrupt(); 285 } 286 } 287 if (tracker.isErrorID(1)) { 288 img = null; 289 System.gc(); 290 } 291 } else { 292 img = null; 293 } 294 295 if (img == null || width <= 0 || height <= 0) { 296 tracker.removeImage(img); 297 img = null; 235 298 } 236 299 … … 242 305 } 243 306 244 if (!error) { 307 if (img != null) { 308 boolean switchedDim = false; 309 if (ExifReader.orientationNeedsCorrection(orientation)) { 310 if (ExifReader.orientationSwitchesDimensions(orientation)) { 311 width = img.getHeight(null); 312 height = img.getWidth(null); 313 switchedDim = true; 314 } 315 final BufferedImage rot = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 316 final AffineTransform xform = ExifReader.getRestoreOrientationTransform(orientation, 317 img.getWidth(null), img.getHeight(null)); 318 final Graphics2D g = rot.createGraphics(); 319 g.drawImage(img, xform, null); 320 g.dispose(); 321 img.flush(); 322 img = rot; 323 } 324 245 325 ImageDisplay.this.image = img; 246 visibleRect = new VisRect(0, 0, img.getWidth(null), img.getHeight(null)); 247 248 final int w = (int) visibleRect.getWidth(); 249 final int h = (int) visibleRect.getHeight(); 250 251 if (ExifReader.orientationNeedsCorrection(orientation)) { 252 final int hh, ww; 253 if (ExifReader.orientationSwitchesDimensions(orientation)) { 254 ww = h; 255 hh = w; 256 } else { 257 ww = w; 258 hh = h; 259 } 260 final BufferedImage rot = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_RGB); 261 final AffineTransform xform = ExifReader.getRestoreOrientationTransform(orientation, w, h); 262 final Graphics2D g = rot.createGraphics(); 263 g.drawImage(image, xform, null); 264 g.dispose(); 265 266 visibleRect.setSize(ww, hh); 267 image.flush(); 268 ImageDisplay.this.image = rot; 269 } 326 visibleRect = new VisRect(0, 0, width, height); 327 328 Logging.info("Loaded {0} with dimensions {1}x{2} mem(prev-avail={3}m,taken={4}m) exifOrientationSwitchedDimension={5}", 329 file.getPath(), width, height, mem/1024/1024, width*height*4/1024/1024, switchedDim); 270 330 } 271 331 272 332 selectedRect = null; 273 errorLoading = error;333 errorLoading = (img == null); 274 334 } 275 335 tracker.removeImage(img); … … 474 534 if (mouseIsDragging(e)) { 475 535 Point p = comp2imgCoord(visibleRect, e.getX(), e.getY(), getSize()); 536 visibleRect.isDragUpdate = true; 476 537 visibleRect.x += mousePointInImg.x - p.x; 477 538 visibleRect.y += mousePointInImg.y - p.y; … … 504 565 @Override 505 566 public void mouseReleased(MouseEvent e) { 506 if (!mouseIsZoomSelecting(e) || selectedRect == null)507 return;508 509 567 File file; 510 568 Image image; … … 515 573 } 516 574 517 if (image == null) {575 if (image == null) 518 576 return; 519 } 520 521 int oldWidth = selectedRect.width; 522 int oldHeight = selectedRect.height; 523 524 // Check that the zoom doesn't exceed MAX_ZOOM:1 525 if (selectedRect.width < getSize().width / MAX_ZOOM.get()) { 526 selectedRect.width = (int) (getSize().width / MAX_ZOOM.get()); 527 } 528 if (selectedRect.height < getSize().height / MAX_ZOOM.get()) { 529 selectedRect.height = (int) (getSize().height / MAX_ZOOM.get()); 530 } 531 532 // Set the same ratio for the visible rectangle and the display area 533 int hFact = selectedRect.height * getSize().width; 534 int wFact = selectedRect.width * getSize().height; 535 if (hFact > wFact) { 536 selectedRect.width = hFact / getSize().height; 537 } else { 538 selectedRect.height = wFact / getSize().width; 539 } 540 541 // Keep the center of the selection 542 if (selectedRect.width != oldWidth) { 543 selectedRect.x -= (selectedRect.width - oldWidth) / 2; 544 } 545 if (selectedRect.height != oldHeight) { 546 selectedRect.y -= (selectedRect.height - oldHeight) / 2; 547 } 548 549 selectedRect.checkRectSize(); 550 selectedRect.checkRectPos(); 577 578 if (mouseIsDragging(e)) { 579 visibleRect.isDragUpdate = false; 580 } 581 582 if (mouseIsZoomSelecting(e) && selectedRect != null) { 583 int oldWidth = selectedRect.width; 584 int oldHeight = selectedRect.height; 585 586 // Check that the zoom doesn't exceed MAX_ZOOM:1 587 if (selectedRect.width < getSize().width / MAX_ZOOM.get()) { 588 selectedRect.width = (int) (getSize().width / MAX_ZOOM.get()); 589 } 590 if (selectedRect.height < getSize().height / MAX_ZOOM.get()) { 591 selectedRect.height = (int) (getSize().height / MAX_ZOOM.get()); 592 } 593 594 // Set the same ratio for the visible rectangle and the display area 595 int hFact = selectedRect.height * getSize().width; 596 int wFact = selectedRect.width * getSize().height; 597 if (hFact > wFact) { 598 selectedRect.width = hFact / getSize().height; 599 } else { 600 selectedRect.height = wFact / getSize().width; 601 } 602 603 // Keep the center of the selection 604 if (selectedRect.width != oldWidth) { 605 selectedRect.x -= (selectedRect.width - oldWidth) / 2; 606 } 607 if (selectedRect.height != oldHeight) { 608 selectedRect.y -= (selectedRect.height - oldHeight) / 2; 609 } 610 611 selectedRect.checkRectSize(); 612 selectedRect.checkRectPos(); 613 } 551 614 552 615 synchronized (ImageDisplay.this) { 553 616 if (file == ImageDisplay.this.file) { 554 ImageDisplay.this.visibleRect.setBounds(selectedRect); 555 } 556 } 557 selectedRect = null; 617 if (selectedRect == null) { 618 ImageDisplay.this.visibleRect = visibleRect; 619 } else { 620 ImageDisplay.this.visibleRect.setBounds(selectedRect); 621 selectedRect = null; 622 } 623 } 624 } 558 625 ImageDisplay.this.repaint(); 559 626 } … … 587 654 } 588 655 656 /** 657 * Sets a new source image to be displayed by this {@code ImageDisplay}. 658 * @param file new source image 659 * @param orientation orientation of new source (landscape, portrait, upside-down, etc.) 660 */ 589 661 public void setImage(File file, Integer orientation) { 590 662 synchronized (this) { … … 651 723 double scale = target.width / (double) r.width; // pixel ratio is 1:1 652 724 653 if (selectedRect == null && bilinLower < scale && scale < bilinUpper) { 654 BufferedImage bi = ImageProvider.toBufferedImage(image, r); 655 r.x = r.y = 0; 656 657 // See https://community.oracle.com/docs/DOC-983611 - The Perils of Image.getScaledInstance() 658 // Pre-scale image when downscaling by more than two times to avoid aliasing from default algorithm 659 image = ImageProvider.createScaledImage(bi, target.width, target.height, 660 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 661 r.width = target.width; 662 r.height = target.height; 725 if (selectedRect == null && !visibleRect.isDragUpdate && 726 bilinLower < scale && scale < bilinUpper) { 727 try { 728 BufferedImage bi = ImageProvider.toBufferedImage(image, r); 729 if (bi != null) { 730 r.x = r.y = 0; 731 732 // See https://community.oracle.com/docs/DOC-983611 - The Perils of Image.getScaledInstance() 733 // Pre-scale image when downscaling by more than two times to avoid aliasing from default algorithm 734 bi = ImageProvider.createScaledImage(bi, target.width, target.height, 735 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 736 r.width = target.width; 737 r.height = target.height; 738 image = bi; 739 } 740 } catch (OutOfMemoryError oom) { 741 // fall-back to the non-bilinear scaler 742 r.x = visibleRect.x; 743 r.y = visibleRect.y; 744 System.gc(); 745 } 663 746 } else { 664 747 // if target and r cause drawImage to scale image region to a tmp buffer exceeding … … 796 879 } 797 880 881 /** 882 * Make the current image either scale to fit inside this component, 883 * or show a portion of image (1:1), if the image size is larger than 884 * the component size. 885 */ 798 886 public void zoomBestFitOrOne() { 799 887 File file;
Note:
See TracChangeset
for help on using the changeset viewer.