Changeset 10547 in josm for trunk/src/org/openstreetmap
- Timestamp:
- 2016-07-17T13:07:14+02:00 (8 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/gui
- Files:
-
- 5 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java
r10428 r10547 29 29 import org.openstreetmap.josm.gui.layer.Layer; 30 30 import org.openstreetmap.josm.gui.layer.Layer.LayerAction; 31 import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings; 31 32 import org.openstreetmap.josm.tools.GBC; 32 33 import org.openstreetmap.josm.tools.ImageProvider; … … 307 308 * 308 309 * @author Michael Zangl 309 * @see Imagery Layer#setGamma(double)310 * @see ImageryFilterSettings#setGamma(double) 310 311 */ 311 312 private class GammaFilterSlider extends FilterSlider<ImageryLayer> { … … 321 322 @Override 322 323 protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) { 323 double gamma = ((ImageryLayer) usedLayers.iterator().next()).get Gamma();324 double gamma = ((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getGamma(); 324 325 setRealValue(mapGammaToInterval(gamma)); 325 326 } … … 327 328 @Override 328 329 protected void applyValueToLayer(ImageryLayer layer) { 329 layer. setGamma(mapIntervalToGamma(getRealValue()));330 layer.getFilterSettings().setGamma(mapIntervalToGamma(getRealValue())); 330 331 } 331 332 … … 366 367 * 367 368 * @author Michael Zangl 368 * @see Imagery Layer#setSharpenLevel(double)369 * @see ImageryFilterSettings#setSharpenLevel(double) 369 370 */ 370 371 private class SharpnessSlider extends FilterSlider<ImageryLayer> { … … 380 381 @Override 381 382 protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) { 382 setRealValue(((ImageryLayer) usedLayers.iterator().next()).get SharpenLevel());383 setRealValue(((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getSharpenLevel()); 383 384 } 384 385 385 386 @Override 386 387 protected void applyValueToLayer(ImageryLayer layer) { 387 layer. setSharpenLevel(getRealValue());388 layer.getFilterSettings().setSharpenLevel(getRealValue()); 388 389 } 389 390 … … 403 404 * 404 405 * @author Michael Zangl 405 * @see Imagery Layer#setColorfulness(double)406 * @see ImageryFilterSettings#setColorfulness(double) 406 407 */ 407 408 private class ColorfulnessSlider extends FilterSlider<ImageryLayer> { … … 417 418 @Override 418 419 protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) { 419 setRealValue(((ImageryLayer) usedLayers.iterator().next()).get Colorfulness());420 setRealValue(((ImageryLayer) usedLayers.iterator().next()).getFilterSettings().getColorfulness()); 420 421 } 421 422 422 423 @Override 423 424 protected void applyValueToLayer(ImageryLayer layer) { 424 layer. setColorfulness(getRealValue());425 layer.getFilterSettings().setColorfulness(getRealValue()); 425 426 } 426 427 -
trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
r10545 r10547 82 82 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 83 83 import org.openstreetmap.josm.gui.dialogs.LayerListPopup; 84 import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings.FilterChangeListener; 84 85 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 85 86 import org.openstreetmap.josm.gui.util.GuiHelper; … … 99 100 */ 100 101 public abstract class AbstractTileSourceLayer<T extends AbstractTMSTileSource> extends ImageryLayer 101 implements ImageObserver, TileLoaderListener, ZoomChangeListener {102 implements ImageObserver, TileLoaderListener, ZoomChangeListener, FilterChangeListener { 102 103 private static final String PREFERENCE_PREFIX = "imagery.generic"; 103 104 … … 175 176 setBackgroundLayer(true); 176 177 this.setVisible(true); 178 getFilterSettings().addFilterChangeListener(this); 179 } 180 181 @Override 182 public void filterChanged() { 183 redraw(); 177 184 } 178 185 … … 261 268 needRedraw = true; 262 269 if (isVisible()) Main.map.repaint(); 263 }264 265 @Override266 public void setGamma(double gamma) {267 super.setGamma(gamma);268 redraw();269 }270 271 @Override272 public void setSharpenLevel(double sharpenLevel) {273 super.setSharpenLevel(sharpenLevel);274 redraw();275 }276 277 @Override278 public void setColorfulness(double colorfulness) {279 super.setColorfulness(colorfulness);280 redraw();281 270 } 282 271 … … 1208 1197 1209 1198 private final class MapWrappingTileSet extends TileSet { 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1199 private MapWrappingTileSet(EastNorth topLeft, EastNorth botRight, int zoom) { 1200 this(getShiftedLatLon(topLeft), getShiftedLatLon(botRight), zoom); 1201 } 1202 1203 private MapWrappingTileSet(LatLon topLeft, LatLon botRight, int zoom) { 1204 super(topLeft, botRight, zoom); 1205 double centerLon = getShiftedLatLon(Main.map.mapView.getCenter()).lon(); 1206 1207 if (topLeft.lon() > centerLon) { 1208 x0 = tileSource.getTileXMin(zoom); 1209 } 1210 if (botRight.lon() < centerLon) { 1211 x1 = tileSource.getTileXMax(zoom); 1212 } 1213 sanitize(); 1214 } 1226 1215 } 1227 1216 … … 1236 1225 * @param zoom zoom level 1237 1226 */ 1238 pr ivateTileSet(EastNorth topLeft, EastNorth botRight, int zoom) {1227 protected TileSet(EastNorth topLeft, EastNorth botRight, int zoom) { 1239 1228 this(getShiftedLatLon(topLeft), getShiftedLatLon(botRight), zoom); 1240 1229 } … … 1246 1235 * @param zoom zoom level 1247 1236 */ 1248 pr ivateTileSet(LatLon topLeft, LatLon botRight, int zoom) {1237 protected TileSet(LatLon topLeft, LatLon botRight, int zoom) { 1249 1238 this.zoom = zoom; 1250 1239 if (zoom == 0) … … 1260 1249 sanitize(); 1261 1250 1262 }1263 1264 private TileSet(Tile topLeft, Tile botRight, int zoom) {1265 1251 } 1266 1252 -
trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
r10467 r10547 9 9 import java.awt.Component; 10 10 import java.awt.GridBagLayout; 11 import java.awt.Rectangle;12 import java.awt.RenderingHints;13 import java.awt.Transparency;14 11 import java.awt.event.ActionEvent; 15 import java.awt.geom.Point2D;16 import java.awt.geom.Rectangle2D;17 12 import java.awt.image.BufferedImage; 18 13 import java.awt.image.BufferedImageOp; 19 import java.awt.image.ColorModel;20 import java.awt.image.ConvolveOp;21 import java.awt.image.DataBuffer;22 import java.awt.image.DataBufferByte;23 import java.awt.image.Kernel;24 import java.awt.image.LookupOp;25 import java.awt.image.ShortLookupTable;26 14 import java.util.ArrayList; 27 15 import java.util.List; … … 46 34 import org.openstreetmap.josm.data.preferences.IntegerProperty; 47 35 import org.openstreetmap.josm.gui.MenuScroller; 36 import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings; 48 37 import org.openstreetmap.josm.gui.widgets.UrlLabel; 49 38 import org.openstreetmap.josm.tools.GBC; … … 76 65 protected double dy; 77 66 78 protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor();79 protected SharpenImageProcessor sharpenImageProcessor = new SharpenImageProcessor();80 protected ColorfulImageProcessor collorfulnessImageProcessor = new ColorfulImageProcessor();81 82 67 private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this); 68 69 private final ImageryFilterSettings filterSettings = new ImageryFilterSettings(); 83 70 84 71 /** … … 96 83 icon = ImageProvider.get("imagery_small"); 97 84 } 98 addImageProcessor(collorfulnessImageProcessor);99 addImageProcessor(gammaImageProcessor);100 addImageProcessor(sharpenImageProcessor);101 sharpenImageProcessor.setSharpenLevel(1 + PROP_SHARPEN_LEVEL.get() / 2f);85 for (ImageProcessor processor : filterSettings.getProcessors()) { 86 addImageProcessor(processor); 87 } 88 filterSettings.setSharpenLevel(1 + PROP_SHARPEN_LEVEL.get() / 2f); 102 89 } 103 90 … … 259 246 260 247 /** 261 * An image processor which adjusts the gamma value of an image. 262 */ 263 public static class GammaImageProcessor implements ImageProcessor { 264 private double gamma = 1; 265 final short[] gammaChange = new short[256]; 266 private final LookupOp op3 = new LookupOp( 267 new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange}), null); 268 private final LookupOp op4 = new LookupOp( 269 new ShortLookupTable(0, new short[][]{gammaChange, gammaChange, gammaChange, gammaChange}), null); 270 271 /** 272 * Returns the currently set gamma value. 273 * @return the currently set gamma value 274 */ 275 public double getGamma() { 276 return gamma; 277 } 278 279 /** 280 * Sets a new gamma value, {@code 1} stands for no correction. 281 * @param gamma new gamma value 282 */ 283 public void setGamma(double gamma) { 284 this.gamma = gamma; 285 for (int i = 0; i < 256; i++) { 286 gammaChange[i] = (short) (255 * Math.pow(i / 255., gamma)); 287 } 288 } 289 290 @Override 291 public BufferedImage process(BufferedImage image) { 292 if (gamma == 1) { 293 return image; 294 } 295 try { 296 final int bands = image.getRaster().getNumBands(); 297 if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 3) { 298 return op3.filter(image, null); 299 } else if (image.getType() != BufferedImage.TYPE_CUSTOM && bands == 4) { 300 return op4.filter(image, null); 301 } 302 } catch (IllegalArgumentException ignore) { 303 Main.trace(ignore); 304 } 305 final int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; 306 final BufferedImage to = new BufferedImage(image.getWidth(), image.getHeight(), type); 307 to.getGraphics().drawImage(image, 0, 0, null); 308 return process(to); 309 } 310 311 @Override 312 public String toString() { 313 return "GammaImageProcessor [gamma=" + gamma + ']'; 314 } 315 } 316 317 /** 318 * Sharpens or blurs the image, depending on the sharpen value. 319 * <p> 320 * A positive sharpen level means that we sharpen the image. 321 * <p> 322 * A negative sharpen level let's us blur the image. -1 is the most useful value there. 323 * 324 * @author Michael Zangl 325 */ 326 public static class SharpenImageProcessor implements ImageProcessor { 327 private float sharpenLevel; 328 private ConvolveOp op; 329 330 private static float[] KERNEL_IDENTITY = new float[] { 331 0, 0, 0, 332 0, 1, 0, 333 0, 0, 0 334 }; 335 336 private static float[] KERNEL_BLUR = new float[] { 337 1f / 16, 2f / 16, 1f / 16, 338 2f / 16, 4f / 16, 2f / 16, 339 1f / 16, 2f / 16, 1f / 16 340 }; 341 342 private static float[] KERNEL_SHARPEN = new float[] { 343 -.5f, -1f, -.5f, 344 -1f, 7, -1f, 345 -.5f, -1f, -.5f 346 }; 347 348 /** 349 * Gets the current sharpen level. 350 * @return The level. 351 */ 352 public float getSharpenLevel() { 353 return sharpenLevel; 354 } 355 356 /** 357 * Sets the sharpening level. 358 * @param sharpenLevel The level. Clamped to be positive or 0. 359 */ 360 public void setSharpenLevel(float sharpenLevel) { 361 if (sharpenLevel < 0) { 362 this.sharpenLevel = 0; 363 } else { 364 this.sharpenLevel = sharpenLevel; 365 } 366 367 if (this.sharpenLevel < 0.95) { 368 op = generateMixed(this.sharpenLevel, KERNEL_IDENTITY, KERNEL_BLUR); 369 } else if (this.sharpenLevel > 1.05) { 370 op = generateMixed(this.sharpenLevel - 1, KERNEL_SHARPEN, KERNEL_IDENTITY); 371 } else { 372 op = null; 373 } 374 } 375 376 private ConvolveOp generateMixed(float aFactor, float[] a, float[] b) { 377 if (a.length != 9 || b.length != 9) { 378 throw new IllegalArgumentException("Illegal kernel array length."); 379 } 380 float[] values = new float[9]; 381 for (int i = 0; i < values.length; i++) { 382 values[i] = aFactor * a[i] + (1 - aFactor) * b[i]; 383 } 384 return new ConvolveOp(new Kernel(3, 3, values), ConvolveOp.EDGE_NO_OP, null); 385 } 386 387 @Override 388 public BufferedImage process(BufferedImage image) { 389 if (op != null) { 390 return op.filter(image, null); 391 } else { 392 return image; 393 } 394 } 395 396 @Override 397 public String toString() { 398 return "SharpenImageProcessor [sharpenLevel=" + sharpenLevel + ']'; 399 } 400 } 401 402 /** 403 * Adds or removes the colorfulness of the image. 404 * 405 * @author Michael Zangl 406 */ 407 public static class ColorfulImageProcessor implements ImageProcessor { 408 private ColorfulFilter op; 409 private double colorfulness = 1; 410 411 /** 412 * Gets the colorfulness value. 413 * @return The value 414 */ 415 public double getColorfulness() { 416 return colorfulness; 417 } 418 419 /** 420 * Sets the colorfulness value. Clamps it to 0+ 421 * @param colorfulness The value 422 */ 423 public void setColorfulness(double colorfulness) { 424 if (colorfulness < 0) { 425 this.colorfulness = 0; 426 } else { 427 this.colorfulness = colorfulness; 428 } 429 430 if (this.colorfulness < .95 || this.colorfulness > 1.05) { 431 op = new ColorfulFilter(this.colorfulness); 432 } else { 433 op = null; 434 } 435 } 436 437 @Override 438 public BufferedImage process(BufferedImage image) { 439 if (op != null) { 440 return op.filter(image, null); 441 } else { 442 return image; 443 } 444 } 445 446 @Override 447 public String toString() { 448 return "ColorfulImageProcessor [colorfulness=" + colorfulness + ']'; 449 } 450 } 451 452 private static class ColorfulFilter implements BufferedImageOp { 453 private final double colorfulness; 454 455 /** 456 * Create a new colorful filter. 457 * @param colorfulness The colorfulness as defined in the {@link ColorfulImageProcessor} class. 458 */ 459 ColorfulFilter(double colorfulness) { 460 this.colorfulness = colorfulness; 461 } 462 463 @Override 464 public BufferedImage filter(BufferedImage src, BufferedImage dest) { 465 if (src.getWidth() == 0 || src.getHeight() == 0) { 466 return src; 467 } 468 469 if (dest == null) { 470 dest = createCompatibleDestImage(src, null); 471 } 472 DataBuffer srcBuffer = src.getRaster().getDataBuffer(); 473 DataBuffer destBuffer = dest.getRaster().getDataBuffer(); 474 if (!(srcBuffer instanceof DataBufferByte) || !(destBuffer instanceof DataBufferByte)) { 475 Main.trace("Cannot apply color filter: Images do not use DataBufferByte."); 476 return src; 477 } 478 479 int type = src.getType(); 480 if (type != dest.getType()) { 481 Main.trace("Cannot apply color filter: Src / Dest differ in type (" + type + '/' + dest.getType() + ')'); 482 return src; 483 } 484 int redOffset, greenOffset, blueOffset, alphaOffset = 0; 485 switch (type) { 486 case BufferedImage.TYPE_3BYTE_BGR: 487 blueOffset = 0; 488 greenOffset = 1; 489 redOffset = 2; 490 break; 491 case BufferedImage.TYPE_4BYTE_ABGR: 492 case BufferedImage.TYPE_4BYTE_ABGR_PRE: 493 blueOffset = 1; 494 greenOffset = 2; 495 redOffset = 3; 496 break; 497 case BufferedImage.TYPE_INT_ARGB: 498 case BufferedImage.TYPE_INT_ARGB_PRE: 499 redOffset = 0; 500 greenOffset = 1; 501 blueOffset = 2; 502 alphaOffset = 3; 503 break; 504 default: 505 Main.trace("Cannot apply color filter: Source image is of wrong type (" + type + ")."); 506 return src; 507 } 508 doFilter((DataBufferByte) srcBuffer, (DataBufferByte) destBuffer, redOffset, greenOffset, blueOffset, 509 alphaOffset, src.getAlphaRaster() != null); 510 return dest; 511 } 512 513 private void doFilter(DataBufferByte src, DataBufferByte dest, int redOffset, int greenOffset, int blueOffset, 514 int alphaOffset, boolean hasAlpha) { 515 byte[] srcPixels = src.getData(); 516 byte[] destPixels = dest.getData(); 517 if (srcPixels.length != destPixels.length) { 518 Main.trace("Cannot apply color filter: Source/Dest lengths differ."); 519 return; 520 } 521 int entries = hasAlpha ? 4 : 3; 522 for (int i = 0; i < srcPixels.length; i += entries) { 523 int r = srcPixels[i + redOffset] & 0xff; 524 int g = srcPixels[i + greenOffset] & 0xff; 525 int b = srcPixels[i + blueOffset] & 0xff; 526 double luminosity = r * .21d + g * .72d + b * .07d; 527 destPixels[i + redOffset] = mix(r, luminosity); 528 destPixels[i + greenOffset] = mix(g, luminosity); 529 destPixels[i + blueOffset] = mix(b, luminosity); 530 if (hasAlpha) { 531 destPixels[i + alphaOffset] = srcPixels[i + alphaOffset]; 532 } 533 } 534 } 535 536 private byte mix(int color, double luminosity) { 537 int val = (int) (colorfulness * color + (1 - colorfulness) * luminosity); 538 if (val < 0) { 539 return 0; 540 } else if (val > 0xff) { 541 return (byte) 0xff; 542 } else { 543 return (byte) val; 544 } 545 } 546 547 @Override 548 public Rectangle2D getBounds2D(BufferedImage src) { 549 return new Rectangle(src.getWidth(), src.getHeight()); 550 } 551 552 @Override 553 public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { 554 return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); 555 } 556 557 @Override 558 public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { 559 return (Point2D) srcPt.clone(); 560 } 561 562 @Override 563 public RenderingHints getRenderingHints() { 564 return null; 565 } 566 567 } 568 569 /** 570 * Returns the currently set gamma value. 571 * @return the currently set gamma value 572 */ 573 public double getGamma() { 574 return gammaImageProcessor.getGamma(); 575 } 576 577 /** 578 * Sets a new gamma value, {@code 1} stands for no correction. 579 * @param gamma new gamma value 580 */ 581 public void setGamma(double gamma) { 582 gammaImageProcessor.setGamma(gamma); 583 } 584 585 /** 586 * Gets the current sharpen level. 587 * @return The sharpen level. 588 */ 589 public double getSharpenLevel() { 590 return sharpenImageProcessor.getSharpenLevel(); 591 } 592 593 /** 594 * Sets the sharpen level for the layer. 595 * <code>1</code> means no change in sharpness. 596 * Values in range 0..1 blur the image. 597 * Values above 1 are used to sharpen the image. 598 * @param sharpenLevel The sharpen level. 599 */ 600 public void setSharpenLevel(double sharpenLevel) { 601 sharpenImageProcessor.setSharpenLevel((float) sharpenLevel); 602 } 603 604 /** 605 * Gets the colorfulness of this image. 606 * @return The colorfulness 607 */ 608 public double getColorfulness() { 609 return collorfulnessImageProcessor.getColorfulness(); 610 } 611 612 /** 613 * Sets the colorfulness of this image. 614 * 0 means grayscale. 615 * 1 means normal colorfulness. 616 * Values greater than 1 are allowed. 617 * @param colorfulness The colorfulness. 618 */ 619 public void setColorfulness(double colorfulness) { 620 collorfulnessImageProcessor.setColorfulness(colorfulness); 248 * Gets the settings for the filter that is applied to this layer. 249 * @return The filter settings. 250 * @since 10547 251 */ 252 public ImageryFilterSettings getFilterSettings() { 253 return filterSettings; 621 254 } 622 255 -
trunk/src/org/openstreetmap/josm/gui/widgets/ButtonColumn.java
r10542 r10547 40 40 public ButtonColumn(Action action, String buttonName) { 41 41 this(action); 42 this.buttonName 42 this.buttonName = buttonName; 43 43 } 44 44
Note:
See TracChangeset
for help on using the changeset viewer.