Changeset 13127 in josm
- Timestamp:
- 2017-11-19T00:10:41+01:00 (7 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplay.java
r13038 r13127 26 26 27 27 import javax.swing.JComponent; 28 28 import javax.swing.SwingUtilities; 29 30 import org.openstreetmap.josm.data.preferences.BooleanProperty; 31 import org.openstreetmap.josm.data.preferences.DoubleProperty; 29 32 import org.openstreetmap.josm.spi.preferences.Config; 33 import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent; 34 import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener; 30 35 import org.openstreetmap.josm.tools.ExifReader; 31 36 import org.openstreetmap.josm.tools.ImageProvider; … … 37 42 * Offers basic mouse interaction (zoom, drag) and on-screen text. 38 43 */ 39 public class ImageDisplay extends JComponent {44 public class ImageDisplay extends JComponent implements PreferenceChangedListener { 40 45 41 46 /** The file that is currently displayed */ … … 50 55 /** The rectangle (in image coordinates) of the image that is visible. This rectangle is calculated 51 56 * each time the zoom is modified */ 52 private RectanglevisibleRect;57 private VisRect visibleRect; 53 58 54 59 /** When a selection is done, the rectangle of the selection (in image coordinates) */ 55 private RectangleselectedRect;60 private VisRect selectedRect; 56 61 57 62 /** The tracker to load the images */ … … 60 65 private String osdText; 61 66 62 private static final int DRAG_BUTTON = Config.getPref().getBoolean("geoimage.agpifo-style-drag-and-zoom", false) ? 1 : 3; 63 private static final int ZOOM_BUTTON = DRAG_BUTTON == 1 ? 3 : 1; 67 private static final BooleanProperty AGPIFO_STYLE2 = 68 new BooleanProperty("geoimage.agpifo-style-drag-and-zoom", false); 69 private static int DRAG_BUTTON; 70 private static int ZOOM_BUTTON; 71 72 /** Alternative to mouse wheel zoom; esp. handy if no mouse wheel is present **/ 73 private static final BooleanProperty ZOOM_ON_CLICK = 74 new BooleanProperty("geoimage.use-mouse-clicks-to-zoom", true); 75 76 /** Zoom factor when click or wheel zooming **/ 77 private static final DoubleProperty ZOOM_STEP = 78 new DoubleProperty("geoimage.zoom-step-factor", 3 / 2.0); 79 80 /** Maximum zoom allowed **/ 81 private static final DoubleProperty MAX_ZOOM = 82 new DoubleProperty("geoimage.maximum-zoom-scale", 2.0); 83 84 /** Use bilinear filtering **/ 85 private static final BooleanProperty BILIN_DOWNSAMP = 86 new BooleanProperty("geoimage.bilinear-downsampling-progressive", true); 87 private static final BooleanProperty BILIN_UPSAMP = 88 new BooleanProperty("geoimage.bilinear-upsampling", false); 89 private static double BILIN_UPPER; 90 private static double BILIN_LOWER; 91 92 @Override 93 public void preferenceChanged(PreferenceChangeEvent e) { 94 if (e == null || 95 e.getKey().equals(AGPIFO_STYLE2.getKey())) 96 { 97 DRAG_BUTTON = AGPIFO_STYLE2.get() ? 1 : 3; 98 ZOOM_BUTTON = DRAG_BUTTON == 1 ? 3 : 1; 99 } 100 if (e == null || 101 e.getKey().equals(MAX_ZOOM.getKey()) || 102 e.getKey().equals(BILIN_DOWNSAMP.getKey()) || 103 e.getKey().equals(BILIN_UPSAMP.getKey())) 104 { 105 BILIN_UPPER = (BILIN_UPSAMP.get() ? 2*MAX_ZOOM.get() : (BILIN_DOWNSAMP.get() ? 0.5 : 0)); 106 BILIN_LOWER = (BILIN_DOWNSAMP.get() ? 0 : 1); 107 } 108 } 109 110 /** Manage the visible rectangle of an image with full bounds stored in init. **/ 111 public static class VisRect extends Rectangle { 112 private final Rectangle init; 113 114 public VisRect(int x, int y, int width, int height) { 115 super(x, y, width, height); 116 init = new Rectangle(this); 117 } 118 119 public VisRect(int x, int y, int width, int height, VisRect peer) { 120 super(x, y, width, height); 121 init = peer.init; 122 } 123 124 public VisRect(VisRect v) { 125 super(v); 126 init = v.init; 127 } 128 129 public VisRect() { 130 this(0, 0, 0, 0); 131 } 132 133 public boolean isFullView() { 134 return init.equals(this); 135 } 136 137 public boolean isFullView1D() { 138 return (init.x == x && init.width == width) 139 || (init.y == y && init.height == height); 140 } 141 142 public void reset() { 143 setBounds(init); 144 } 145 146 public void checkRectPos() { 147 if (x < 0) { 148 x = 0; 149 } 150 if (y < 0) { 151 y = 0; 152 } 153 if (x + width > init.width) { 154 x = init.width - width; 155 } 156 if (y + height > init.height) { 157 y = init.height - height; 158 } 159 } 160 161 public void checkRectSize() { 162 if (width > init.width) { 163 width = init.width; 164 } 165 if (height > init.height) { 166 height = init.height; 167 } 168 } 169 170 public void checkPointInside(Point p) { 171 if (p.x < x) { 172 p.x = x; 173 } 174 if (p.x > x + width) { 175 p.x = x + width; 176 } 177 if (p.y < y) { 178 p.y = y; 179 } 180 if (p.y > y + height) { 181 p.y = y + height; 182 } 183 } 184 } 64 185 65 186 /** The thread that reads the images. */ … … 108 229 if (!error) { 109 230 ImageDisplay.this.image = img; 110 visibleRect = new Rectangle(0, 0, img.getWidth(null), img.getHeight(null));231 visibleRect = new VisRect(0, 0, img.getWidth(null), img.getHeight(null)); 111 232 112 233 final int w = (int) visibleRect.getWidth(); … … 144 265 private class ImgDisplayMouseListener implements MouseListener, MouseWheelListener, MouseMotionListener { 145 266 146 private boolean mouseIsDragging; 147 private long lastTimeForMousePoint; 267 private MouseEvent lastMouseEvent; 148 268 private Point mousePointInImg; 149 269 150 /** Zoom in and out, trying to preserve the point of the image that was under the mouse cursor 151 * at the same place */ 152 @Override 153 public void mouseWheelMoved(MouseWheelEvent e) { 270 private boolean mouseIsDragging(MouseEvent e) { 271 return (DRAG_BUTTON == 1 && SwingUtilities.isLeftMouseButton(e)) || 272 (DRAG_BUTTON == 2 && SwingUtilities.isMiddleMouseButton(e)) || 273 (DRAG_BUTTON == 3 && SwingUtilities.isRightMouseButton(e)); 274 } 275 276 private boolean mouseIsZoomSelecting(MouseEvent e) { 277 return (ZOOM_BUTTON == 1 && SwingUtilities.isLeftMouseButton(e)) || 278 (ZOOM_BUTTON == 2 && SwingUtilities.isMiddleMouseButton(e)) || 279 (ZOOM_BUTTON == 3 && SwingUtilities.isRightMouseButton(e)); 280 } 281 282 private boolean isAtMaxZoom(Rectangle visibleRect) { 283 return (visibleRect.width == (int) (getSize().width / MAX_ZOOM.get()) || 284 visibleRect.height == (int) (getSize().height / MAX_ZOOM.get())); 285 } 286 287 private void mouseWheelMovedImpl(int x, int y, int rotation, boolean refreshMousePointInImg) { 154 288 File file; 155 289 Image image; 156 RectanglevisibleRect;290 VisRect visibleRect; 157 291 158 292 synchronized (ImageDisplay.this) { … … 162 296 } 163 297 164 mouseIsDragging = false;165 298 selectedRect = null; 166 299 … … 168 301 return; 169 302 170 // Calculate the mouse cursor position in image coordinates, so that we can center the zoom 171 // on that mouse position. 172 // To avoid issues when the user tries to zoom in on the image borders, this point is not calculated 173 // again if there was less than 1.5seconds since the last event. 174 if (e.getWhen() - lastTimeForMousePoint > 1500 || mousePointInImg == null) { 175 lastTimeForMousePoint = e.getWhen(); 176 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY(), getSize()); 177 } 178 179 // Applicate the zoom to the visible rectangle in image coordinates 180 if (e.getWheelRotation() > 0) { 181 visibleRect.width = visibleRect.width * 3 / 2; 182 visibleRect.height = visibleRect.height * 3 / 2; 303 // Calculate the mouse cursor position in image coordinates to center the zoom. 304 if (refreshMousePointInImg) 305 mousePointInImg = comp2imgCoord(visibleRect, x, y, getSize()); 306 307 // Apply the zoom to the visible rectangle in image coordinates 308 if (rotation > 0) { 309 visibleRect.width = (int) (visibleRect.width * ZOOM_STEP.get()); 310 visibleRect.height = (int) (visibleRect.height * ZOOM_STEP.get()); 183 311 } else { 184 visibleRect.width = visibleRect.width * 2 / 3;185 visibleRect.height = visibleRect.height * 2 / 3;186 } 187 188 // Check that the zoom doesn't exceed 2:1189 if (visibleRect.width < getSize().width / 2) {190 visibleRect.width = getSize().width / 2;191 } 192 if (visibleRect.height < getSize().height / 2) {193 visibleRect.height = getSize().height / 2;312 visibleRect.width = (int) (visibleRect.width / ZOOM_STEP.get()); 313 visibleRect.height = (int) (visibleRect.height / ZOOM_STEP.get()); 314 } 315 316 // Check that the zoom doesn't exceed MAX_ZOOM:1 317 if (visibleRect.width < getSize().width / MAX_ZOOM.get()) { 318 visibleRect.width = (int) (getSize().width / MAX_ZOOM.get()); 319 } 320 if (visibleRect.height < getSize().height / MAX_ZOOM.get()) { 321 visibleRect.height = (int) (getSize().height / MAX_ZOOM.get()); 194 322 } 195 323 … … 204 332 205 333 // The size of the visible rectangle is limited by the image size. 206 checkVisibleRectSize(image, visibleRect);334 visibleRect.checkRectSize(); 207 335 208 336 // Set the position of the visible rectangle, so that the mouse cursor doesn't move on the image. 209 337 Rectangle drawRect = calculateDrawImageRectangle(visibleRect, getSize()); 210 visibleRect.x = mousePointInImg.x + ((drawRect.x - e.getX()) * visibleRect.width) / drawRect.width;211 visibleRect.y = mousePointInImg.y + ((drawRect.y - e.getY()) * visibleRect.height) / drawRect.height;338 visibleRect.x = mousePointInImg.x + ((drawRect.x - x) * visibleRect.width) / drawRect.width; 339 visibleRect.y = mousePointInImg.y + ((drawRect.y - y) * visibleRect.height) / drawRect.height; 212 340 213 341 // The position is also limited by the image size 214 checkVisibleRectPos(image, visibleRect);342 visibleRect.checkRectPos(); 215 343 216 344 synchronized (ImageDisplay.this) { … … 220 348 } 221 349 ImageDisplay.this.repaint(); 350 } 351 352 /** Zoom in and out, trying to preserve the point of the image that was under the mouse cursor 353 * at the same place */ 354 @Override 355 public void mouseWheelMoved(MouseWheelEvent e) { 356 boolean refreshMousePointInImg = false; 357 358 // To avoid issues when the user tries to zoom in on the image borders, this 359 // point is not recalculated as long as e occurs at roughly the same position. 360 if (lastMouseEvent == null || mousePointInImg == null || 361 ((lastMouseEvent.getX()-e.getX())*(lastMouseEvent.getX()-e.getX()) 362 +(lastMouseEvent.getY()-e.getY())*(lastMouseEvent.getY()-e.getY()) > 4*4)) { 363 lastMouseEvent = e; 364 refreshMousePointInImg = true; 365 } 366 367 mouseWheelMovedImpl(e.getX(), e.getY(), e.getWheelRotation(), refreshMousePointInImg); 222 368 } 223 369 … … 228 374 File file; 229 375 Image image; 230 RectanglevisibleRect;376 VisRect visibleRect; 231 377 232 378 synchronized (ImageDisplay.this) { … … 239 385 return; 240 386 241 if (e.getButton() != DRAG_BUTTON) 242 return; 387 if (ZOOM_ON_CLICK.get()) { 388 // click notions are less coherent than wheel, refresh mousePointInImg on each click 389 lastMouseEvent = null; 390 391 if (mouseIsZoomSelecting(e) && !isAtMaxZoom(visibleRect)) { 392 // zoom in if clicked with the zoom button 393 mouseWheelMovedImpl(e.getX(), e.getY(), -1, true); 394 return; 395 } 396 if (mouseIsDragging(e)) { 397 // zoom out if clicked with the drag button 398 mouseWheelMovedImpl(e.getX(), e.getY(), 1, true); 399 return; 400 } 401 } 243 402 244 403 // Calculate the translation to set the clicked point the center of the view. … … 249 408 visibleRect.y += click.y - center.y; 250 409 251 checkVisibleRectPos(image, visibleRect);410 visibleRect.checkRectPos(); 252 411 253 412 synchronized (ImageDisplay.this) { … … 263 422 @Override 264 423 public void mousePressed(MouseEvent e) { 265 if (image == null) {266 mouseIsDragging = false;267 selectedRect = null;268 return;269 }270 271 424 Image image; 272 RectanglevisibleRect;425 VisRect visibleRect; 273 426 274 427 synchronized (ImageDisplay.this) { … … 280 433 return; 281 434 282 if (e.getButton() == DRAG_BUTTON) { 435 selectedRect = null; 436 437 if (mouseIsDragging(e) || mouseIsZoomSelecting(e)) 283 438 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY(), getSize()); 284 mouseIsDragging = true;285 selectedRect = null;286 } else if (e.getButton() == ZOOM_BUTTON) {287 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY(), getSize());288 checkPointInVisibleRect(mousePointInImg, visibleRect);289 mouseIsDragging = false;290 selectedRect = new Rectangle(mousePointInImg.x, mousePointInImg.y, 0, 0);291 ImageDisplay.this.repaint();292 } else {293 mouseIsDragging = false;294 selectedRect = null;295 }296 439 } 297 440 298 441 @Override 299 442 public void mouseDragged(MouseEvent e) { 300 if (!mouseIsDragging && selectedRect == null)443 if (!mouseIsDragging(e) && !mouseIsZoomSelecting(e)) 301 444 return; 302 445 303 446 File file; 304 447 Image image; 305 RectanglevisibleRect;448 VisRect visibleRect; 306 449 307 450 synchronized (ImageDisplay.this) { … … 311 454 } 312 455 313 if (image == null) { 314 mouseIsDragging = false; 315 selectedRect = null; 456 if (image == null) 316 457 return; 317 } 318 319 if (mouseIsDragging) { 458 459 if (mouseIsDragging(e)) { 320 460 Point p = comp2imgCoord(visibleRect, e.getX(), e.getY(), getSize()); 321 461 visibleRect.x += mousePointInImg.x - p.x; 322 462 visibleRect.y += mousePointInImg.y - p.y; 323 checkVisibleRectPos(image, visibleRect);463 visibleRect.checkRectPos(); 324 464 synchronized (ImageDisplay.this) { 325 465 if (ImageDisplay.this.file == file) { … … 328 468 } 329 469 ImageDisplay.this.repaint(); 330 331 } else if (selectedRect != null) { 470 } 471 472 if (mouseIsZoomSelecting(e)) { 332 473 Point p = comp2imgCoord(visibleRect, e.getX(), e.getY(), getSize()); 333 checkPointInVisibleRect(p, visibleRect);334 Rectangle rect = new Rectangle(474 visibleRect.checkPointInside(p); 475 VisRect selectedRect = new VisRect( 335 476 p.x < mousePointInImg.x ? p.x : mousePointInImg.x, 336 477 p.y < mousePointInImg.y ? p.y : mousePointInImg.y, 337 478 p.x < mousePointInImg.x ? mousePointInImg.x - p.x : p.x - mousePointInImg.x, 338 p.y < mousePointInImg.y ? mousePointInImg.y - p.y : p.y - mousePointInImg.y); 339 checkVisibleRectSize(image, rect); 340 checkVisibleRectPos(image, rect); 341 ImageDisplay.this.selectedRect = rect; 479 p.y < mousePointInImg.y ? mousePointInImg.y - p.y : p.y - mousePointInImg.y, 480 visibleRect); 481 selectedRect.checkRectSize(); 482 selectedRect.checkRectPos(); 483 ImageDisplay.this.selectedRect = selectedRect; 342 484 ImageDisplay.this.repaint(); 343 485 } … … 347 489 @Override 348 490 public void mouseReleased(MouseEvent e) { 349 if (!mouseIs Dragging &&selectedRect == null)491 if (!mouseIsZoomSelecting(e) || selectedRect == null) 350 492 return; 351 493 … … 359 501 360 502 if (image == null) { 361 mouseIsDragging = false;362 selectedRect = null;363 503 return; 364 504 } 365 505 366 if (mouseIsDragging) { 367 mouseIsDragging = false; 368 369 } else if (selectedRect != null) { 370 int oldWidth = selectedRect.width; 371 int oldHeight = selectedRect.height; 372 373 // Check that the zoom doesn't exceed 2:1 374 if (selectedRect.width < getSize().width / 2) { 375 selectedRect.width = getSize().width / 2; 376 } 377 if (selectedRect.height < getSize().height / 2) { 378 selectedRect.height = getSize().height / 2; 379 } 380 381 // Set the same ratio for the visible rectangle and the display area 382 int hFact = selectedRect.height * getSize().width; 383 int wFact = selectedRect.width * getSize().height; 384 if (hFact > wFact) { 385 selectedRect.width = hFact / getSize().height; 386 } else { 387 selectedRect.height = wFact / getSize().width; 388 } 389 390 // Keep the center of the selection 391 if (selectedRect.width != oldWidth) { 392 selectedRect.x -= (selectedRect.width - oldWidth) / 2; 393 } 394 if (selectedRect.height != oldHeight) { 395 selectedRect.y -= (selectedRect.height - oldHeight) / 2; 396 } 397 398 checkVisibleRectSize(image, selectedRect); 399 checkVisibleRectPos(image, selectedRect); 400 401 synchronized (ImageDisplay.this) { 402 if (file == ImageDisplay.this.file) { 403 ImageDisplay.this.visibleRect = selectedRect; 404 } 405 } 406 selectedRect = null; 407 ImageDisplay.this.repaint(); 408 } 506 int oldWidth = selectedRect.width; 507 int oldHeight = selectedRect.height; 508 509 // Check that the zoom doesn't exceed MAX_ZOOM:1 510 if (selectedRect.width < getSize().width / MAX_ZOOM.get()) { 511 selectedRect.width = (int) (getSize().width / MAX_ZOOM.get()); 512 } 513 if (selectedRect.height < getSize().height / MAX_ZOOM.get()) { 514 selectedRect.height = (int) (getSize().height / MAX_ZOOM.get()); 515 } 516 517 // Set the same ratio for the visible rectangle and the display area 518 int hFact = selectedRect.height * getSize().width; 519 int wFact = selectedRect.width * getSize().height; 520 if (hFact > wFact) { 521 selectedRect.width = hFact / getSize().height; 522 } else { 523 selectedRect.height = wFact / getSize().width; 524 } 525 526 // Keep the center of the selection 527 if (selectedRect.width != oldWidth) { 528 selectedRect.x -= (selectedRect.width - oldWidth) / 2; 529 } 530 if (selectedRect.height != oldHeight) { 531 selectedRect.y -= (selectedRect.height - oldHeight) / 2; 532 } 533 534 selectedRect.checkRectSize(); 535 selectedRect.checkRectPos(); 536 537 synchronized (ImageDisplay.this) { 538 if (file == ImageDisplay.this.file) { 539 ImageDisplay.this.visibleRect.setBounds(selectedRect); 540 } 541 } 542 selectedRect = null; 543 ImageDisplay.this.repaint(); 409 544 } 410 545 … … 422 557 public void mouseMoved(MouseEvent e) { 423 558 // Do nothing 424 }425 426 private void checkPointInVisibleRect(Point p, Rectangle visibleRect) {427 if (p.x < visibleRect.x) {428 p.x = visibleRect.x;429 }430 if (p.x > visibleRect.x + visibleRect.width) {431 p.x = visibleRect.x + visibleRect.width;432 }433 if (p.y < visibleRect.y) {434 p.y = visibleRect.y;435 }436 if (p.y > visibleRect.y + visibleRect.height) {437 p.y = visibleRect.y + visibleRect.height;438 }439 559 } 440 560 } … … 448 568 addMouseWheelListener(mouseListener); 449 569 addMouseMotionListener(mouseListener); 570 Config.getPref().addPreferenceChangeListener(this); 571 preferenceChanged(null); 450 572 } 451 573 … … 454 576 this.file = file; 455 577 image = null; 456 selectedRect = null;457 578 errorLoading = false; 458 579 } … … 476 597 Image image; 477 598 File file; 478 RectanglevisibleRect;599 VisRect visibleRect; 479 600 boolean errorLoading; 480 601 … … 511 632 (int) ((size.height - noImageSize.getHeight()) / 2)); 512 633 } else { 634 Rectangle r = new Rectangle(visibleRect); 513 635 Rectangle target = calculateDrawImageRectangle(visibleRect, size); 514 // See https://community.oracle.com/docs/DOC-983611 - The Perils of Image.getScaledInstance() 515 // Pre-scale image when downscaling by more than two times to avoid aliasing from default algorithm 516 if (selectedRect == null && (target.width < visibleRect.width/2 || target.height < visibleRect.height/2)) { 517 BufferedImage buffImage = ImageProvider.toBufferedImage(image); 518 g.drawImage(ImageProvider.createScaledImage(buffImage, target.width, target.height, RenderingHints.VALUE_INTERPOLATION_BILINEAR), 519 target.x, target.y, target.x + target.width, target.y + target.height, 520 visibleRect.x, visibleRect.y, visibleRect.x + target.width, visibleRect.y + target.height, 521 null); 636 double scale = target.width / (double) r.width; // pixel ratio is 1:1 637 638 if (selectedRect == null && BILIN_LOWER < scale && scale < BILIN_UPPER) { 639 BufferedImage bi = ImageProvider.toBufferedImage(image, r); 640 r.x = r.y = 0; 641 642 // See https://community.oracle.com/docs/DOC-983611 - The Perils of Image.getScaledInstance() 643 // Pre-scale image when downscaling by more than two times to avoid aliasing from default algorithm 644 image = ImageProvider.createScaledImage(bi, target.width, target.height, 645 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 646 r.width = target.width; 647 r.height = target.height; 522 648 } else { 523 g.drawImage(image, 524 target.x, target.y, target.x + target.width, target.y + target.height, 525 visibleRect.x, visibleRect.y, visibleRect.x + visibleRect.width, visibleRect.y + visibleRect.height, 526 null); 527 } 649 // if target and r cause drawImage to scale image region to a tmp buffer exceeding 650 // its bounds, it will silently fail; crop with r first in such cases 651 // (might be impl. dependent, exhibited by openjdk 1.8.0_151) 652 if (scale*(r.x+r.width) > Short.MAX_VALUE || scale*(r.y+r.height) > Short.MAX_VALUE) { 653 image = ImageProvider.toBufferedImage(image, r); 654 r.x = r.y = 0; 655 } 656 } 657 658 g.drawImage(image, 659 target.x, target.y, target.x + target.width, target.y + target.height, 660 r.x, r.y, r.x + r.width, r.y + r.height, null); 661 528 662 if (selectedRect != null) { 529 663 Point topLeft = img2compCoord(visibleRect, selectedRect.x, selectedRect.y, size); … … 577 711 } 578 712 579 static Point img2compCoord( RectanglevisibleRect, int xImg, int yImg, Dimension compSize) {713 static Point img2compCoord(VisRect visibleRect, int xImg, int yImg, Dimension compSize) { 580 714 Rectangle drawRect = calculateDrawImageRectangle(visibleRect, compSize); 581 715 return new Point(drawRect.x + ((xImg - visibleRect.x) * drawRect.width) / visibleRect.width, … … 583 717 } 584 718 585 static Point comp2imgCoord( RectanglevisibleRect, int xComp, int yComp, Dimension compSize) {719 static Point comp2imgCoord(VisRect visibleRect, int xComp, int yComp, Dimension compSize) { 586 720 Rectangle drawRect = calculateDrawImageRectangle(visibleRect, compSize); 587 return new Point(visibleRect.x + ((xComp - drawRect.x) * visibleRect.width) / drawRect.width, 588 visibleRect.y + ((yComp - drawRect.y) * visibleRect.height) / drawRect.height); 721 Point p = new Point( 722 ((xComp - drawRect.x) * visibleRect.width), 723 ((yComp - drawRect.y) * visibleRect.height)); 724 p.x += (((p.x % drawRect.width) << 1) >= drawRect.width) ? drawRect.width : 0; 725 p.y += (((p.y % drawRect.height) << 1) >= drawRect.height) ? drawRect.height : 0; 726 p.x = visibleRect.x + p.x / drawRect.width; 727 p.y = visibleRect.y + p.y / drawRect.height; 728 return p; 589 729 } 590 730 … … 594 734 } 595 735 596 static Rectangle calculateDrawImageRectangle(RectanglevisibleRect, Dimension compSize) {736 static VisRect calculateDrawImageRectangle(VisRect visibleRect, Dimension compSize) { 597 737 return calculateDrawImageRectangle(visibleRect, new Rectangle(0, 0, compSize.width, compSize.height)); 598 738 } … … 605 745 * @return the part of compRect with the same width/height ratio as the image 606 746 */ 607 static Rectangle calculateDrawImageRectangle(RectangleimgRect, Rectangle compRect) {747 static VisRect calculateDrawImageRectangle(VisRect imgRect, Rectangle compRect) { 608 748 int x = 0; 609 749 int y = 0; … … 622 762 } 623 763 } 624 return new Rectangle(x + compRect.x, y + compRect.y, w, h); 764 765 // overscan to prevent empty edges when zooming in to zoom scales > 2:1 766 if (w > imgRect.width && h > imgRect.height && !imgRect.isFullView1D()) { 767 if (wFact != hFact) { 768 if (wFact > hFact) { 769 w = compRect.width; 770 x = 0; 771 h = wFact / imgRect.width; 772 y = (compRect.height - h) / 2; 773 } else { 774 h = compRect.height; 775 y = 0; 776 w = hFact / imgRect.height; 777 x = (compRect.width - w) / 2; 778 } 779 } 780 } 781 782 return new VisRect(x + compRect.x, y + compRect.y, w, h, imgRect); 625 783 } 626 784 … … 628 786 File file; 629 787 Image image; 630 RectanglevisibleRect;788 VisRect visibleRect; 631 789 632 790 synchronized (this) { … … 641 799 if (visibleRect.width != image.getWidth(null) || visibleRect.height != image.getHeight(null)) { 642 800 // The display is not at best fit. => Zoom to best fit 643 visibleRect = new Rectangle(0, 0, image.getWidth(null), image.getHeight(null)); 644 801 visibleRect.reset(); 645 802 } else { 646 803 // The display is at best fit => zoom to 1:1 647 804 Point center = getCenterImgCoord(visibleRect); 648 visibleRect = new Rectangle(center.x - getWidth() / 2, center.y - getHeight() / 2,805 visibleRect.setBounds(center.x - getWidth() / 2, center.y - getHeight() / 2, 649 806 getWidth(), getHeight()); 650 checkVisibleRectPos(image, visibleRect); 807 visibleRect.checkRectSize(); 808 visibleRect.checkRectPos(); 651 809 } 652 810 … … 658 816 repaint(); 659 817 } 660 661 static void checkVisibleRectPos(Image image, Rectangle visibleRect) {662 if (visibleRect.x < 0) {663 visibleRect.x = 0;664 }665 if (visibleRect.y < 0) {666 visibleRect.y = 0;667 }668 if (visibleRect.x + visibleRect.width > image.getWidth(null)) {669 visibleRect.x = image.getWidth(null) - visibleRect.width;670 }671 if (visibleRect.y + visibleRect.height > image.getHeight(null)) {672 visibleRect.y = image.getHeight(null) - visibleRect.height;673 }674 }675 676 static void checkVisibleRectSize(Image image, Rectangle visibleRect) {677 if (visibleRect.width > image.getWidth(null)) {678 visibleRect.width = image.getWidth(null);679 }680 if (visibleRect.height > image.getHeight(null)) {681 visibleRect.height = image.getHeight(null);682 }683 }684 818 } -
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java
r12856 r13127 21 21 import org.openstreetmap.josm.data.cache.JCSCacheManager; 22 22 import org.openstreetmap.josm.gui.MainApplication; 23 import org.openstreetmap.josm.gui.layer.geoimage.ImageDisplay.VisRect; 23 24 import org.openstreetmap.josm.spi.preferences.Config; 24 25 import org.openstreetmap.josm.tools.ExifReader; … … 141 142 142 143 Rectangle targetSize = ImageDisplay.calculateDrawImageRectangle( 143 new Rectangle(0, 0, ww, hh),144 new VisRect(0, 0, ww, hh), 144 145 new Rectangle(0, 0, maxSize, maxSize)); 145 146 BufferedImage scaledBI = new BufferedImage(targetSize.width, targetSize.height, BufferedImage.TYPE_INT_RGB); -
trunk/src/org/openstreetmap/josm/tools/ImageProvider.java
r13038 r13127 12 12 import java.awt.Image; 13 13 import java.awt.Point; 14 import java.awt.Rectangle; 14 15 import java.awt.RenderingHints; 15 16 import java.awt.Toolkit; … … 1421 1422 if (w > targetWidth) { 1422 1423 w /= 2; 1423 if (w < targetWidth) {1424 w = targetWidth;1425 }1424 } 1425 if (w < targetWidth) { 1426 w = targetWidth; 1426 1427 } 1427 1428 if (h > targetHeight) { 1428 1429 h /= 2; 1429 if (h < targetHeight) {1430 h = targetHeight;1431 }1430 } 1431 if (h < targetHeight) { 1432 h = targetHeight; 1432 1433 } 1433 1434 BufferedImage tmp = new BufferedImage(w, h, type); … … 1976 1977 } 1977 1978 } 1979 1980 /** 1981 * Converts an {@link Rectangle} area of {@link Image} to a {@link BufferedImage} instance. 1982 * @param image image to convert 1983 * @param crop_area rectangle to crop image with 1984 * @return a {@code BufferedImage} instance for the cropped area of {@code Image}. 1985 * @since 13127 1986 */ 1987 public static BufferedImage toBufferedImage(Image image, Rectangle crop_area) { 1988 BufferedImage buffImage = null; 1989 1990 Rectangle r = new Rectangle(image.getWidth(null), image.getHeight(null)); 1991 if (r.intersection(crop_area).equals(crop_area)) { 1992 buffImage = new BufferedImage(crop_area.width, crop_area.height, BufferedImage.TYPE_INT_ARGB); 1993 Graphics2D g2 = buffImage.createGraphics(); 1994 g2.drawImage(image, 1995 0, 0, crop_area.width, crop_area.height, 1996 crop_area.x, crop_area.y, 1997 crop_area.x + crop_area.width, crop_area.y + crop_area.height, 1998 null); 1999 g2.dispose(); 2000 } 2001 return buffImage; 2002 } 1978 2003 } -
trunk/test/unit/org/openstreetmap/josm/gui/layer/geoimage/ImageDisplayTest.java
r11539 r13127 9 9 import org.junit.Rule; 10 10 import org.junit.Test; 11 import org.openstreetmap.josm.gui.layer.geoimage.ImageDisplay.VisRect; 11 12 import org.openstreetmap.josm.testutils.JOSMTestRules; 12 13 … … 30 31 public void testCalculateDrawImageRectangle() { 31 32 assertEquals(new Rectangle(), 32 ImageDisplay.calculateDrawImageRectangle(new Rectangle(), new Dimension()));33 ImageDisplay.calculateDrawImageRectangle(new VisRect(), new Dimension())); 33 34 assertEquals(new Rectangle(0, 0, 10, 5), 34 ImageDisplay.calculateDrawImageRectangle(new Rectangle(0, 0, 10, 5), new Dimension(10, 5)));35 ImageDisplay.calculateDrawImageRectangle(new VisRect(0, 0, 10, 5), new Dimension(10, 5))); 35 36 assertEquals(new Rectangle(0, 0, 10, 5), 36 ImageDisplay.calculateDrawImageRectangle(new Rectangle(0, 0, 20, 10), new Dimension(10, 5)));37 ImageDisplay.calculateDrawImageRectangle(new VisRect(0, 0, 20, 10), new Dimension(10, 5))); 37 38 assertEquals(new Rectangle(0, 0, 20, 10), 38 ImageDisplay.calculateDrawImageRectangle(new Rectangle(0, 0, 10, 5), new Dimension(20, 10)));39 ImageDisplay.calculateDrawImageRectangle(new VisRect(0, 0, 10, 5), new Dimension(20, 10))); 39 40 assertEquals(new Rectangle(5, 0, 24, 12), 40 ImageDisplay.calculateDrawImageRectangle(new Rectangle(0, 0, 10, 5), new Dimension(35, 12)));41 ImageDisplay.calculateDrawImageRectangle(new VisRect(0, 0, 10, 5), new Dimension(35, 12))); 41 42 assertEquals(new Rectangle(0, 1, 8, 4), 42 ImageDisplay.calculateDrawImageRectangle(new Rectangle(0, 0, 10, 5), new Dimension(8, 6)));43 ImageDisplay.calculateDrawImageRectangle(new VisRect(0, 0, 10, 5), new Dimension(8, 6))); 43 44 } 44 45 }
Note:
See TracChangeset
for help on using the changeset viewer.