Changeset 1704 in josm for trunk/src/org/openstreetmap
- Timestamp:
- 2009-06-27T11:46:17+02:00 (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/GeoImageLayer.java
r1590 r1704 25 25 import java.awt.event.MouseEvent; 26 26 import java.awt.image.BufferedImage; 27 import java.awt.image.ImageObserver; 27 28 import java.io.File; 28 29 import java.io.IOException; 30 import java.lang.ref.SoftReference; 29 31 import java.text.ParseException; 30 32 import java.text.SimpleDateFormat; … … 34 36 import java.util.Date; 35 37 import java.util.LinkedList; 38 import java.util.List; 39 import java.util.WeakHashMap; 36 40 37 41 import javax.swing.BorderFactory; … … 52 56 import javax.swing.JToggleButton; 53 57 import javax.swing.JViewport; 58 import javax.swing.ScrollPaneConstants; 54 59 import javax.swing.border.BevelBorder; 55 60 import javax.swing.border.Border; … … 67 72 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 68 73 import org.openstreetmap.josm.gui.dialogs.LayerListPopup; 74 import org.openstreetmap.josm.gui.layer.GeoImageLayer.ImageLoader.ImageLoadedListener; 69 75 import org.openstreetmap.josm.tools.DateParser; 70 76 import org.openstreetmap.josm.tools.ExifReader; … … 79 85 public class GeoImageLayer extends Layer { 80 86 81 private static final class ImageEntry implements Comparable<ImageEntry> { 82 File image; 87 /** 88 * Allows to load and scale images. Loaded images are kept in cache (using soft reference). Both 89 * synchronous and asynchronous loading is supported 90 * 91 */ 92 public static class ImageLoader implements ImageObserver { 93 94 public static class Entry { 95 final File file; 96 final int width; 97 final int height; 98 final int maxSize; 99 private final ImageLoadedListener listener; 100 101 volatile Image scaledImage; 102 103 104 public Entry(File file, int width, int height, int maxSize, ImageLoadedListener listener) { 105 this.file = file; 106 this.height = height; 107 this.width = width; 108 this.maxSize = maxSize; 109 this.listener = listener; 110 } 111 } 112 113 public interface ImageLoadedListener { 114 void imageLoaded(); 115 } 116 117 private final List<ImageLoader.Entry> queue = new ArrayList<ImageLoader.Entry>(); 118 private final WeakHashMap<File, SoftReference<Image>> loadedImageCache = new WeakHashMap<File, SoftReference<Image>>(); 119 private ImageLoader.Entry currentEntry; 120 121 private Image getOrLoadImage(File file) { 122 SoftReference<Image> cachedImageRef = loadedImageCache.get(file); 123 if (cachedImageRef != null) { 124 Image cachedImage = cachedImageRef.get(); 125 if (cachedImage != null) { 126 return cachedImage; 127 } 128 } 129 return Toolkit.getDefaultToolkit().createImage(currentEntry.file.getAbsolutePath()); 130 } 131 132 private BufferedImage createResizedCopy(Image originalImage, 133 int scaledWidth, int scaledHeight) 134 { 135 BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB); 136 Graphics2D g = scaledBI.createGraphics(); 137 while (!g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null)) 138 { 139 try { 140 Thread.sleep(10); 141 } catch(InterruptedException ie) {} 142 } 143 g.dispose(); 144 return scaledBI; 145 } 146 private void loadImage() { 147 if (currentEntry != null) { 148 return; 149 } 150 while (!queue.isEmpty()) { 151 currentEntry = queue.get(0); 152 queue.remove(0); 153 154 Image newImage = getOrLoadImage(currentEntry.file); 155 if (newImage.getWidth(this) == -1) { 156 break; 157 } else { 158 finishImage(newImage, currentEntry); 159 currentEntry = null; 160 } 161 } 162 } 163 164 private void finishImage(Image img, ImageLoader.Entry entry) { 165 loadedImageCache.put(entry.file, new SoftReference<Image>(img)); 166 if (entry.maxSize != -1) { 167 int w = img.getWidth(null); 168 int h = img.getHeight(null); 169 if (w>h) { 170 h = Math.round(entry.maxSize*((float)h/w)); 171 w = entry.maxSize; 172 } else { 173 w = Math.round(entry.maxSize*((float)w/h)); 174 h = entry.maxSize; 175 } 176 entry.scaledImage = createResizedCopy(img, w, h); 177 } else if (entry.width != -1 && entry.height != -1) { 178 entry.scaledImage = createResizedCopy(img, entry.width, entry.height); 179 } else { 180 entry.scaledImage = img; 181 } 182 if (entry.listener != null) { 183 entry.listener.imageLoaded(); 184 } 185 } 186 187 public synchronized ImageLoader.Entry loadImage(File file, int width, int height, int maxSize, ImageLoadedListener listener) { 188 ImageLoader.Entry e = new Entry(file, width, height, maxSize, listener); 189 queue.add(e); 190 loadImage(); 191 return e; 192 } 193 194 public Image waitForImage(File file, int width, int height) { 195 return waitForImage(file, width, height, -1); 196 } 197 198 public Image waitForImage(File file, int maxSize) { 199 return waitForImage(file, -1, -1, maxSize); 200 } 201 202 public Image waitForImage(File file) { 203 return waitForImage(file, -1, -1, -1); 204 } 205 206 private synchronized Image waitForImage(File file, int width, int height, int maxSize) { 207 ImageLoader.Entry entry; 208 if (currentEntry != null && currentEntry.file.equals(file)) { 209 entry = currentEntry; 210 } else { 211 entry = new Entry(file, width, height, maxSize, null); 212 queue.add(0, entry); 213 } 214 loadImage(); 215 216 while (true) { 217 if (entry.scaledImage != null) { 218 return entry.scaledImage; 219 } 220 try { 221 wait(); 222 } catch (InterruptedException e) {} 223 } 224 } 225 226 public synchronized boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { 227 if ((infoflags & ImageObserver.ALLBITS) != 0) { 228 finishImage(img, currentEntry); 229 currentEntry = null; 230 loadImage(); 231 notifyAll(); 232 } 233 return true; 234 } 235 } 236 237 private static final int ICON_SIZE = 16; 238 private static ImageLoader imageLoader = new ImageLoader(); 239 240 private static final class ImageEntry implements Comparable<ImageEntry>, ImageLoadedListener { 241 242 private static final Image EMPTY_IMAGE = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY); 243 244 final File image; 245 ImageLoader.Entry icon; 246 83 247 Date time; 84 248 LatLon coor; 85 249 EastNorth pos; 86 Icon icon; 250 251 public ImageEntry(File image) { 252 this.image = image; 253 icon = imageLoader.loadImage(image, ICON_SIZE, ICON_SIZE, -1, this); 254 } 255 87 256 public int compareTo(ImageEntry image) { 88 257 return time.compareTo(image.time); 258 } 259 260 public Image getIcon() { 261 if (icon.scaledImage == null) { 262 return EMPTY_IMAGE; 263 } else { 264 return icon.scaledImage; 265 } 266 } 267 268 public void imageLoaded() { 269 Main.map.mapView.repaint(); 89 270 } 90 271 } … … 109 290 for (Collection<WayPoint> segment : trk.trackSegs) { 110 291 for (WayPoint p : segment) { 111 if (!p.attr.containsKey("time")) 112 throw new IOException(tr("No time for point {0} x {1}",p.latlon.lat(),p.latlon.lon())); 113 Date d = null; 114 try { 115 d = DateParser.parse((String) p.attr.get("time")); 116 } catch (ParseException e) { 117 throw new IOException(tr("Cannot read time \"{0}\" from point {1} x {2}",p.attr.get("time"),p.latlon.lat(),p.latlon.lon())); 292 if (!p.attr.containsKey("time")) 293 throw new IOException(tr("No time for point {0} x {1}",p.latlon.lat(),p.latlon.lon())); 294 Date d = null; 295 try { 296 d = DateParser.parse((String) p.attr.get("time")); 297 } catch (ParseException e) { 298 throw new IOException(tr("Cannot read time \"{0}\" from point {1} x {2}",p.attr.get("time"),p.latlon.lat(),p.latlon.lon())); 299 } 300 gps.add(new TimedPoint(d, p.eastNorth)); 118 301 } 119 gps.add(new TimedPoint(d, p.eastNorth)); 120 } 121 } 302 } 122 303 } 123 304 … … 137 318 Main.pleaseWaitDlg.progress.setValue(i++); 138 319 139 ImageEntry e = new ImageEntry( );320 ImageEntry e = new ImageEntry(f); 140 321 try { 141 322 e.time = ExifReader.readTime(f); … … 145 326 if (e.time == null) 146 327 continue; 147 e.image = f;148 e.icon = loadScaledImage(f, 16);149 328 150 329 data.add(e); … … 172 351 private static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); 173 352 private MouseAdapter mouseAdapter; 174 private int currentImage;353 private ImageViewerDialog imageViewerDialog; 175 354 176 355 public static final class GpsTimeIncorrect extends Exception { … … 226 405 continue; 227 406 Point p = Main.map.mapView.getPoint(e.pos); 228 Rectangle r = new Rectangle(p.x- e.icon.getIconWidth()/2, p.y-e.icon.getIconHeight()/2, e.icon.getIconWidth(), e.icon.getIconHeight());407 Rectangle r = new Rectangle(p.x-ICON_SIZE/2, p.y-ICON_SIZE/2, ICON_SIZE, ICON_SIZE); 229 408 if (r.contains(ev.getPoint())) { 230 409 showImage(i-1); … … 246 425 } 247 426 427 private class ImageViewerDialog { 428 429 private int currentImage; 430 private ImageEntry currentImageEntry; 431 432 private final JDialog dlg; 433 private final JButton nextButton; 434 private final JButton prevButton; 435 private final JToggleButton scaleToggle; 436 private final JToggleButton centerToggle; 437 private final JViewport imageViewport; 438 private final JLabel imageLabel; 439 440 private class ImageAction implements ActionListener { 441 442 private final int offset; 443 444 public ImageAction(int offset) { 445 this.offset = offset; 446 } 447 448 public void actionPerformed(ActionEvent e) { 449 showImage(currentImage + offset); 450 } 451 452 } 453 454 public ImageViewerDialog(ImageEntry firstImage) { 455 final JPanel p = new JPanel(new BorderLayout()); 456 imageLabel = new JLabel(new ImageIcon(imageLoader.waitForImage(firstImage.image, 580))); 457 final JScrollPane scroll = new JScrollPane(imageLabel); 458 scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 459 scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 460 imageViewport = scroll.getViewport(); 461 p.add(scroll, BorderLayout.CENTER); 462 463 scaleToggle = new JToggleButton(ImageProvider.get("dialogs", "zoom-best-fit")); 464 nextButton = new JButton(ImageProvider.get("dialogs", "next")); 465 prevButton = new JButton(ImageProvider.get("dialogs", "previous")); 466 centerToggle = new JToggleButton(ImageProvider.get("dialogs", "centreview")); 467 468 JPanel p2 = new JPanel(); 469 p2.add(prevButton); 470 p2.add(scaleToggle); 471 p2.add(centerToggle); 472 p2.add(nextButton); 473 p.add(p2, BorderLayout.SOUTH); 474 final JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE); 475 dlg = pane.createDialog(Main.parent, ""); 476 scaleToggle.addActionListener(new ImageAction(0)); 477 scaleToggle.setSelected(true); 478 centerToggle.addActionListener(new ImageAction(0)); 479 480 nextButton.setActionCommand("Next"); 481 prevButton.setActionCommand("Previous"); 482 nextButton.setMnemonic(KeyEvent.VK_RIGHT); 483 prevButton.setMnemonic(KeyEvent.VK_LEFT); 484 scaleToggle.setMnemonic(KeyEvent.VK_F); 485 centerToggle.setMnemonic(KeyEvent.VK_C); 486 nextButton.setToolTipText("Show next image"); 487 prevButton.setToolTipText("Show previous image"); 488 centerToggle.setToolTipText("Centre image location in main display"); 489 scaleToggle.setToolTipText("Scale image to fit"); 490 491 prevButton.addActionListener(new ImageAction(-1)); 492 nextButton.addActionListener(new ImageAction(1)); 493 centerToggle.setSelected(false); 494 495 dlg.addComponentListener(new ComponentListener() { 496 boolean ignoreEvent = true; 497 public void componentHidden(ComponentEvent e) {} 498 public void componentMoved(ComponentEvent e) {} 499 public void componentResized(ComponentEvent ev) { 500 // we ignore the first resize event, as the picture is scaled already on load: 501 if (scaleToggle.getModel().isSelected() && !ignoreEvent) { 502 imageLabel.setIcon(new ImageIcon(imageLoader.waitForImage(currentImageEntry.image, 503 Math.max(imageViewport.getWidth(), imageViewport.getHeight())))); 504 } 505 ignoreEvent = false; 506 } 507 public void componentShown(ComponentEvent e) {} 508 509 }); 510 dlg.setModal(false); 511 dlg.setResizable(true); 512 dlg.pack(); 513 } 514 515 public void showImage(int index) { 516 dlg.setVisible(true); 517 dlg.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 518 519 if (index < 0) { 520 index = 0; 521 } else if (index >= data.size() - 1) { 522 index = data.size() - 1; 523 } 524 525 currentImage = index; 526 currentImageEntry = data.get(currentImage); 527 528 prevButton.setEnabled(currentImage > 0); 529 nextButton.setEnabled(currentImage < data.size() - 1); 530 531 if (scaleToggle.getModel().isSelected()) 532 imageLabel.setIcon(new ImageIcon(imageLoader.waitForImage(currentImageEntry.image, 533 Math.max(imageViewport.getWidth(), imageViewport.getHeight())))); 534 else 535 imageLabel.setIcon(new ImageIcon(imageLoader.waitForImage(currentImageEntry.image))); 536 537 if (centerToggle.getModel().isSelected()) 538 Main.map.mapView.zoomTo(currentImageEntry.pos, Main.map.mapView.getScale()); 539 540 dlg.setTitle(currentImageEntry.image + 541 " (" + currentImageEntry.coor.toDisplayString() + ")"); 542 dlg.setCursor(Cursor.getDefaultCursor()); 543 } 544 545 } 546 248 547 private void showImage(int i) { 249 currentImage = i; 250 final JPanel p = new JPanel(new BorderLayout()); 251 final ImageEntry e = data.get(currentImage); 252 if (!(e.image.exists() && e.image.canRead())) 253 { 254 JOptionPane.showMessageDialog(Main.parent, 255 tr("Image with path {0} does not exist or is not readable.", e.image), 256 tr("Warning"), JOptionPane.WARNING_MESSAGE); 257 return; 258 } 259 final JScrollPane scroll = new JScrollPane(new JLabel(loadScaledImage(e.image, 580))); 260 final JViewport vp = scroll.getViewport(); 261 p.add(scroll, BorderLayout.CENTER); 262 263 final JToggleButton scale = new JToggleButton(ImageProvider.get("dialogs", "zoom-best-fit")); 264 final JButton next = new JButton(ImageProvider.get("dialogs", "next")); 265 final JButton prev = new JButton(ImageProvider.get("dialogs", "previous")); 266 final JToggleButton cent = new JToggleButton(ImageProvider.get("dialogs", "centreview")); 267 268 JPanel p2 = new JPanel(); 269 p2.add(prev); 270 p2.add(scale); 271 p2.add(cent); 272 p2.add(next); 273 prev.setEnabled(currentImage>0?true:false); 274 next.setEnabled(currentImage<data.size()-1?true:false); 275 p.add(p2, BorderLayout.SOUTH); 276 final JOptionPane pane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE); 277 final JDialog dlg = pane.createDialog(Main.parent, e.image+" ("+e.coor.toDisplayString()+")"); 278 scale.addActionListener(new ActionListener(){ 279 public void actionPerformed(ActionEvent ev) { 280 p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 281 if (scale.getModel().isSelected()) 282 ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight()))); 283 else 284 ((JLabel)vp.getView()).setIcon(new ImageIcon(e.image.getPath())); 285 p.setCursor(Cursor.getDefaultCursor()); 286 } 287 }); 288 scale.setSelected(true); 289 cent.addActionListener(new ActionListener(){ 290 public void actionPerformed(ActionEvent ev) { 291 final ImageEntry e = data.get(currentImage); 292 if (cent.getModel().isSelected()) 293 Main.map.mapView.zoomTo(e.pos, Main.map.mapView.getScale()); 294 } 295 }); 296 297 ActionListener nextprevAction = new ActionListener(){ 298 public void actionPerformed(ActionEvent ev) { 299 p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 300 if (ev.getActionCommand().equals("Next")) { 301 currentImage++; 302 if(currentImage>=data.size()-1) next.setEnabled(false); 303 prev.setEnabled(true); 304 } else { 305 currentImage--; 306 if(currentImage<=0) prev.setEnabled(false); 307 next.setEnabled(true); 308 } 309 310 final ImageEntry e = data.get(currentImage); 311 if (scale.getModel().isSelected()) 312 ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight()))); 313 else 314 ((JLabel)vp.getView()).setIcon(new ImageIcon(e.image.getPath())); 315 dlg.setTitle(e.image+" ("+e.coor.toDisplayString()+")"); 316 if (cent.getModel().isSelected()) 317 Main.map.mapView.zoomTo(e.pos, Main.map.mapView.getScale()); 318 p.setCursor(Cursor.getDefaultCursor()); 319 } 320 }; 321 next.setActionCommand("Next"); 322 prev.setActionCommand("Previous"); 323 next.setMnemonic(KeyEvent.VK_RIGHT); 324 prev.setMnemonic(KeyEvent.VK_LEFT); 325 scale.setMnemonic(KeyEvent.VK_F); 326 cent.setMnemonic(KeyEvent.VK_C); 327 next.setToolTipText("Show next image"); 328 prev.setToolTipText("Show previous image"); 329 cent.setToolTipText("Centre image location in main display"); 330 scale.setToolTipText("Scale image to fit"); 331 332 prev.addActionListener(nextprevAction); 333 next.addActionListener(nextprevAction); 334 cent.setSelected(false); 335 336 dlg.addComponentListener(new ComponentListener() { 337 boolean ignoreEvent = true; 338 public void componentHidden(ComponentEvent e) {} 339 public void componentMoved(ComponentEvent e) {} 340 public void componentResized(ComponentEvent ev) { 341 // we ignore the first resize event, as the picture is scaled already on load: 342 if (scale.getModel().isSelected() && !ignoreEvent) { 343 ((JLabel)vp.getView()).setIcon(loadScaledImage(e.image, Math.max(vp.getWidth(), vp.getHeight()))); 344 } 345 ignoreEvent = false; 346 } 347 public void componentShown(ComponentEvent e) {} 348 349 }); 350 dlg.setModal(false); 351 dlg.setVisible(true); 352 dlg.setResizable(true); 548 if (imageViewerDialog == null) { 549 imageViewerDialog = new ImageViewerDialog(data.get(i)); 550 } 551 imageViewerDialog.showImage(i); 353 552 } 354 553 … … 372 571 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 373 572 ImageEntry e = (ImageEntry)value; 374 setIcon( e.icon);573 setIcon(new ImageIcon(e.getIcon())); 375 574 setText(e.image.getName()+" ("+dateFormat.format(new Date(e.time.getTime()+(delta+gpstimezone)))+")"); 376 575 if (e.pos == null) … … 402 601 403 602 @Override public void paint(Graphics g, MapView mv) { 404 boolean clickedFound = false; 405 for (ImageEntry e : data) { 603 int clickedIndex = -1; 604 605 // First select beveled icon (for cases where are more icons on the same spot) 606 Point mousePosition = mv.getMousePosition(); 607 if (mousePosition != null && mousePressed) { 608 for (int i = data.size() - 1; i >= 0; i--) { 609 ImageEntry e = data.get(i); 610 if (e.pos == null) { 611 continue; 612 } 613 614 Point p = mv.getPoint(e.pos); 615 Rectangle r = new Rectangle(p.x-ICON_SIZE / 2, p.y-ICON_SIZE / 2, ICON_SIZE, ICON_SIZE); 616 if (r.contains(mousePosition)) { 617 clickedIndex = i; 618 break; 619 } 620 } 621 } 622 623 for (int i = 0; i < data.size(); i++) { 624 ImageEntry e = data.get(i); 406 625 if (e.pos != null) { 407 626 Point p = mv.getPoint(e.pos); 408 Rectangle r = new Rectangle(p.x- e.icon.getIconWidth()/2, p.y-e.icon.getIconHeight()/2, e.icon.getIconWidth(), e.icon.getIconHeight());409 e.icon.paintIcon(mv, g, r.x, r.y);627 Rectangle r = new Rectangle(p.x-ICON_SIZE / 2, p.y-ICON_SIZE / 2, ICON_SIZE, ICON_SIZE); 628 g.drawImage(e.getIcon(), r.x, r.y, null); 410 629 Border b = null; 411 Point mousePosition = mv.getMousePosition(); 412 if (mousePosition == null) 413 continue; // mouse outside the whole window 414 if (!clickedFound && mousePressed && r.contains(mousePosition)) { 630 if (i == clickedIndex) { 415 631 b = BorderFactory.createBevelBorder(BevelBorder.LOWERED); 416 clickedFound = true; 417 } else 632 } else { 418 633 b = BorderFactory.createBevelBorder(BevelBorder.RAISED); 634 } 419 635 Insets inset = b.getBorderInsets(mv); 420 636 r.grow((inset.top+inset.bottom)/2, (inset.left+inset.right)/2); … … 477 693 lastTP = tp; 478 694 } 479 if (e.pos != null) 480 e.coor = Main.proj.eastNorth2latlon(e.pos); 695 if (e.pos == null) { 696 e.pos = gps.getLast().pos; 697 } 698 e.coor = Main.proj.eastNorth2latlon(e.pos); 481 699 } 482 700 } … … 496 714 JPanel p = new JPanel(new GridBagLayout()); 497 715 p.add(new JLabel(tr("Image")), GBC.eol()); 498 p.add(new JLabel( loadScaledImage(f, 300)), GBC.eop());716 p.add(new JLabel(new ImageIcon(imageLoader.waitForImage(f, 300))), GBC.eop()); 499 717 p.add(new JLabel(tr("Enter shown date (mm/dd/yyyy HH:MM:SS)")), GBC.eol()); 500 718 JTextField gpsText = new JTextField(dateFormat.format(new Date(exifDate.getTime()+delta))); … … 531 749 } 532 750 533 private static Icon loadScaledImage(File f, int maxSize) {534 Image img = Toolkit.getDefaultToolkit().createImage(f.getPath());535 while (img.getWidth(null) < 0 || img.getHeight(null) < 0) {536 try {537 Thread.sleep(10);538 } catch(InterruptedException ie) {}539 }540 int w = img.getWidth(null);541 int h = img.getHeight(null);542 if (w>h) {543 h = Math.round(maxSize*((float)h/w));544 w = maxSize;545 } else {546 w = Math.round(maxSize*((float)w/h));547 h = maxSize;548 }549 return new ImageIcon(createResizedCopy(img, w, h));550 }551 552 private static BufferedImage createResizedCopy(Image originalImage,553 int scaledWidth, int scaledHeight)554 {555 BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);556 Graphics2D g = scaledBI.createGraphics();557 while (!g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null))558 {559 try {560 Thread.sleep(10);561 } catch(InterruptedException ie) {}562 }563 g.dispose();564 return scaledBI;565 }566 751 }
Note:
See TracChangeset
for help on using the changeset viewer.