Changeset 10142 in josm for trunk/src/org/openstreetmap/josm/gui/layer
- Timestamp:
- 2016-04-12T23:08:55+02:00 (8 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/gui/layer
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
r10001 r10142 259 259 } 260 260 261 @Override 262 public void setSharpenLevel(double sharpenLevel) { 263 super.setSharpenLevel(sharpenLevel); 264 redraw(); 265 } 266 267 @Override 268 public void setColorfulness(double colorfulness) { 269 super.setColorfulness(colorfulness); 270 redraw(); 271 } 272 261 273 /** 262 274 * Marks layer as needing redraw on offset change -
trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java
r9983 r10142 9 9 import java.awt.Component; 10 10 import java.awt.GridBagLayout; 11 import java.awt.Rectangle; 12 import java.awt.RenderingHints; 11 13 import java.awt.Transparency; 12 14 import java.awt.event.ActionEvent; 15 import java.awt.geom.Point2D; 16 import java.awt.geom.Rectangle2D; 13 17 import java.awt.image.BufferedImage; 14 18 import java.awt.image.BufferedImageOp; 19 import java.awt.image.ColorModel; 15 20 import java.awt.image.ConvolveOp; 21 import java.awt.image.DataBuffer; 22 import java.awt.image.DataBufferByte; 16 23 import java.awt.image.Kernel; 17 24 import java.awt.image.LookupOp; … … 70 77 71 78 protected GammaImageProcessor gammaImageProcessor = new GammaImageProcessor(); 79 protected SharpenImageProcessor sharpenImageProcessor = new SharpenImageProcessor(); 80 protected ColorfulImageProcessor collorfulnessImageProcessor = new ColorfulImageProcessor(); 72 81 73 82 private final ImageryAdjustAction adjustAction = new ImageryAdjustAction(this); … … 87 96 icon = ImageProvider.get("imagery_small"); 88 97 } 89 addImageProcessor(c reateSharpener(PROP_SHARPEN_LEVEL.get()));98 addImageProcessor(collorfulnessImageProcessor); 90 99 addImageProcessor(gammaImageProcessor); 100 addImageProcessor(sharpenImageProcessor); 101 sharpenImageProcessor.setSharpenLevel(1 + PROP_SHARPEN_LEVEL.get() / 2f); 91 102 } 92 103 … … 233 244 } 234 245 235 public ImageProcessor createSharpener(int sharpenLevel) {236 final Kernel kernel;237 if (sharpenLevel == 1) {238 kernel = new Kernel(3, 3, new float[]{-0.25f, -0.5f, -0.25f, -0.5f, 4, -0.5f, -0.25f, -0.5f, -0.25f});239 } else if (sharpenLevel == 2) {240 kernel = new Kernel(3, 3, new float[]{-0.5f, -1, -0.5f, -1, 7, -1, -0.5f, -1, -0.5f});241 } else {242 return null;243 }244 BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);245 return createImageProcessor(op, false);246 }247 248 246 /** 249 247 * An image processor which adjusts the gamma value of an image. … … 301 299 302 300 /** 301 * Sharpens or blurs the image, depending on the sharpen value. 302 * <p> 303 * A positive sharpen level means that we sharpen the image. 304 * <p> 305 * A negative sharpen level let's us blur the image. -1 is the most useful value there. 306 * 307 * @author Michael Zangl 308 */ 309 public static class SharpenImageProcessor implements ImageProcessor { 310 private float sharpenLevel = 0; 311 private ConvolveOp op; 312 313 private static float[] KERNEL_IDENTITY = new float[] { 314 0, 0, 0, 315 0, 1, 0, 316 0, 0, 0 317 }; 318 319 private static float[] KERNEL_BLUR = new float[] { 320 1f / 16, 2f / 16, 1f / 16, 321 2f / 16, 4f / 16, 2f / 16, 322 1f / 16, 2f / 16, 1f / 16 323 }; 324 325 private static float[] KERNEL_SHARPEN = new float[] { 326 -.5f, -1f, -.5f, 327 -1f, 7, -1f, 328 -.5f, -1f, -.5f 329 }; 330 331 /** 332 * Gets the current sharpen level. 333 * @return The level. 334 */ 335 public float getSharpenLevel() { 336 return sharpenLevel; 337 } 338 339 /** 340 * Sets the sharpening level. 341 * @param sharpenLevel The level. Clamped to be positive or 0. 342 */ 343 public void setSharpenLevel(float sharpenLevel) { 344 if (sharpenLevel < 0) { 345 this.sharpenLevel = 0; 346 } else { 347 this.sharpenLevel = sharpenLevel; 348 } 349 350 if (this.sharpenLevel < 0.95) { 351 op = generateMixed(this.sharpenLevel, KERNEL_IDENTITY, KERNEL_BLUR); 352 } else if (this.sharpenLevel > 1.05) { 353 op = generateMixed(this.sharpenLevel - 1, KERNEL_SHARPEN, KERNEL_IDENTITY); 354 } else { 355 op = null; 356 } 357 } 358 359 private ConvolveOp generateMixed(float aFactor, float[] a, float[] b) { 360 if (a.length != 9 || b.length != 9) { 361 throw new IllegalArgumentException("Illegal kernel array length."); 362 } 363 float[] values = new float[9]; 364 for (int i = 0; i < values.length; i++) { 365 values[i] = aFactor * a[i] + (1 - aFactor) * b[i]; 366 } 367 return new ConvolveOp(new Kernel(3, 3, values), ConvolveOp.EDGE_NO_OP, null); 368 } 369 370 @Override 371 public BufferedImage process(BufferedImage image) { 372 if (op != null) { 373 return op.filter(image, null); 374 } else { 375 return image; 376 } 377 } 378 379 @Override 380 public String toString() { 381 return "SharpenImageProcessor [sharpenLevel=" + sharpenLevel + "]"; 382 } 383 } 384 385 /** 386 * Adds or removes the colorfulness of the image. 387 * 388 * @author Michael Zangl 389 */ 390 public static class ColorfulImageProcessor implements ImageProcessor { 391 private ColorfulFilter op = null; 392 private double colorfulness = 1; 393 394 /** 395 * Gets the colorfulness value. 396 * @return The value 397 */ 398 public double getColorfulness() { 399 return colorfulness; 400 } 401 402 /** 403 * Sets the colorfulness value. Clamps it to 0+ 404 * @param colorfulness The value 405 */ 406 public void setColorfulness(double colorfulness) { 407 if (colorfulness < 0) { 408 this.colorfulness = 0; 409 } else { 410 this.colorfulness = colorfulness; 411 } 412 413 if (this.colorfulness < .95 || this.colorfulness > 1.05) { 414 op = new ColorfulFilter(this.colorfulness); 415 } else { 416 op = null; 417 } 418 } 419 420 @Override 421 public BufferedImage process(BufferedImage image) { 422 if (op != null) { 423 return op.filter(image, null); 424 } else { 425 return image; 426 } 427 } 428 429 @Override 430 public String toString() { 431 return "ColorfulImageProcessor [colorfulness=" + colorfulness + "]"; 432 } 433 } 434 435 private static class ColorfulFilter implements BufferedImageOp { 436 private final double colorfulness; 437 438 /** 439 * Create a new colorful filter. 440 * @param colorfulness The colorfulness as defined in the {@link ColorfulImageProcessor} class. 441 */ 442 ColorfulFilter(double colorfulness) { 443 this.colorfulness = colorfulness; 444 } 445 446 @Override 447 public BufferedImage filter(BufferedImage src, BufferedImage dest) { 448 if (src.getWidth() == 0 || src.getHeight() == 0) { 449 return src; 450 } 451 452 if (dest == null) { 453 dest = createCompatibleDestImage(src, null); 454 } 455 DataBuffer srcBuffer = src.getRaster().getDataBuffer(); 456 DataBuffer destBuffer = dest.getRaster().getDataBuffer(); 457 if (!(srcBuffer instanceof DataBufferByte) || !(destBuffer instanceof DataBufferByte)) { 458 Main.trace("Cannot apply color filter: Images do not use DataBufferByte."); 459 return src; 460 } 461 462 int type = src.getType(); 463 if (type != dest.getType()) { 464 Main.trace("Cannot apply color filter: Src / Dest differ in type (" + type + "/" + dest.getType() + ")"); 465 return src; 466 } 467 int redOffset, greenOffset, blueOffset, alphaOffset = 0; 468 switch (type) { 469 case BufferedImage.TYPE_3BYTE_BGR: 470 blueOffset = 0; 471 greenOffset = 1; 472 redOffset = 2; 473 break; 474 case BufferedImage.TYPE_4BYTE_ABGR: 475 case BufferedImage.TYPE_4BYTE_ABGR_PRE: 476 blueOffset = 1; 477 greenOffset = 2; 478 redOffset = 3; 479 break; 480 case BufferedImage.TYPE_INT_ARGB: 481 case BufferedImage.TYPE_INT_ARGB_PRE: 482 redOffset = 0; 483 greenOffset = 1; 484 blueOffset = 2; 485 alphaOffset = 3; 486 break; 487 default: 488 Main.trace("Cannot apply color filter: Source image is of wrong type (" + type + ")."); 489 return src; 490 } 491 doFilter((DataBufferByte) srcBuffer, (DataBufferByte) destBuffer, redOffset, greenOffset, blueOffset, 492 alphaOffset, src.getAlphaRaster() != null); 493 return dest; 494 } 495 496 private void doFilter(DataBufferByte src, DataBufferByte dest, int redOffset, int greenOffset, int blueOffset, 497 int alphaOffset, boolean hasAlpha) { 498 byte[] srcPixels = src.getData(); 499 byte[] destPixels = dest.getData(); 500 if (srcPixels.length != destPixels.length) { 501 Main.trace("Cannot apply color filter: Source/Dest lengths differ."); 502 return; 503 } 504 int entries = hasAlpha ? 4 : 3; 505 for (int i = 0; i < srcPixels.length; i += entries) { 506 int r = srcPixels[i + redOffset] & 0xff; 507 int g = srcPixels[i + greenOffset] & 0xff; 508 int b = srcPixels[i + blueOffset] & 0xff; 509 float luminosity = r * .21f + g * .72f + b * .07f; 510 destPixels[i + redOffset] = mix(r, luminosity); 511 destPixels[i + greenOffset] = mix(g, luminosity); 512 destPixels[i + blueOffset] = mix(b, luminosity); 513 if (hasAlpha) { 514 destPixels[i + alphaOffset] = srcPixels[i + alphaOffset]; 515 } 516 } 517 } 518 519 private byte mix(int color, float luminosity) { 520 int val = (int) (colorfulness * color + (1 - colorfulness) * luminosity); 521 if (val < 0) { 522 return 0; 523 } else if (val > 0xff) { 524 return (byte) 0xff; 525 } else { 526 return (byte) val; 527 } 528 } 529 530 @Override 531 public Rectangle2D getBounds2D(BufferedImage src) { 532 return new Rectangle(src.getWidth(), src.getHeight()); 533 } 534 535 @Override 536 public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { 537 return new BufferedImage(src.getWidth(), src.getHeight(), src.getType()); 538 } 539 540 @Override 541 public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { 542 return (Point2D) srcPt.clone(); 543 } 544 545 @Override 546 public RenderingHints getRenderingHints() { 547 return null; 548 } 549 550 } 551 552 /** 303 553 * Returns the currently set gamma value. 304 554 * @return the currently set gamma value … … 314 564 public void setGamma(double gamma) { 315 565 gammaImageProcessor.setGamma(gamma); 566 } 567 568 /** 569 * Gets the current sharpen level. 570 * @return The sharpen level. 571 */ 572 public double getSharpenLevel() { 573 return sharpenImageProcessor.getSharpenLevel(); 574 } 575 576 /** 577 * Sets the sharpen level for the layer. 578 * <code>1</code> means no change in sharpness. 579 * Values in range 0..1 blur the image. 580 * Values above 1 are used to sharpen the image. 581 * @param sharpenLevel The sharpen level. 582 */ 583 public void setSharpenLevel(double sharpenLevel) { 584 sharpenImageProcessor.setSharpenLevel((float) sharpenLevel); 585 } 586 587 /** 588 * Gets the colorfulness of this image. 589 * @return The colorfulness 590 */ 591 public double getColorfulness() { 592 return collorfulnessImageProcessor.getColorfulness(); 593 } 594 595 /** 596 * Sets the colorfulness of this image. 597 * 0 means grayscale. 598 * 1 means normal colorfulness. 599 * Values greater than 1 are allowed. 600 * @param colorfulness The colorfulness. 601 */ 602 public void setColorfulness(double colorfulness) { 603 collorfulnessImageProcessor.setColorfulness(colorfulness); 316 604 } 317 605
Note:
See TracChangeset
for help on using the changeset viewer.