source: josm/trunk/src/org/openstreetmap/josm/gui/layer/imagery/ColorfulImageProcessor.java@ 10547

Last change on this file since 10547 was 10547, checked in by Don-vip, 8 years ago

fix #13159 - Move image processors out of imagery layer (patch by michael2402) - gsoc-core + fix checkstyle violations

  • Property svn:eol-style set to native
File size: 6.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer.imagery;
3
4import java.awt.Rectangle;
5import java.awt.RenderingHints;
6import java.awt.geom.Point2D;
7import java.awt.geom.Rectangle2D;
8import java.awt.image.BufferedImage;
9import java.awt.image.BufferedImageOp;
10import java.awt.image.ColorModel;
11import java.awt.image.DataBuffer;
12import java.awt.image.DataBufferByte;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.gui.layer.ImageProcessor;
16
17/**
18 * Adds or removes the colorfulness of the image.
19 *
20 * @author Michael Zangl
21 * @since 10547
22 */
23public class ColorfulImageProcessor implements ImageProcessor {
24 private ColorfulFilter op;
25 private double colorfulness = 1;
26
27 /**
28 * Gets the colorfulness value.
29 * @return The value
30 */
31 public double getColorfulness() {
32 return colorfulness;
33 }
34
35 /**
36 * Sets the colorfulness value. Clamps it to 0+
37 * @param colorfulness The value
38 */
39 public void setColorfulness(double colorfulness) {
40 if (colorfulness < 0) {
41 this.colorfulness = 0;
42 } else {
43 this.colorfulness = colorfulness;
44 }
45
46 if (this.colorfulness < .95 || this.colorfulness > 1.05) {
47 op = new ColorfulFilter(this.colorfulness);
48 } else {
49 op = null;
50 }
51 }
52
53 @Override
54 public BufferedImage process(BufferedImage image) {
55 if (op != null) {
56 return op.filter(image, null);
57 } else {
58 return image;
59 }
60 }
61
62 @Override
63 public String toString() {
64 return "ColorfulImageProcessor [colorfulness=" + colorfulness + ']';
65 }
66
67 static class ColorfulFilter implements BufferedImageOp {
68 private final double colorfulness;
69
70 /**
71 * Create a new colorful filter.
72 * @param colorfulness The colorfulness as defined in the {@link ColorfulImageProcessor} class.
73 */
74 ColorfulFilter(double colorfulness) {
75 this.colorfulness = colorfulness;
76 }
77
78 @Override
79 public BufferedImage filter(BufferedImage src, BufferedImage dest) {
80 if (src.getWidth() == 0 || src.getHeight() == 0) {
81 return src;
82 }
83
84 if (dest == null) {
85 dest = createCompatibleDestImage(src, null);
86 }
87 DataBuffer srcBuffer = src.getRaster().getDataBuffer();
88 DataBuffer destBuffer = dest.getRaster().getDataBuffer();
89 if (!(srcBuffer instanceof DataBufferByte) || !(destBuffer instanceof DataBufferByte)) {
90 Main.trace("Cannot apply color filter: Images do not use DataBufferByte.");
91 return src;
92 }
93
94 int type = src.getType();
95 if (type != dest.getType()) {
96 Main.trace("Cannot apply color filter: Src / Dest differ in type (" + type + '/' + dest.getType() + ')');
97 return src;
98 }
99 int redOffset, greenOffset, blueOffset, alphaOffset = 0;
100 switch (type) {
101 case BufferedImage.TYPE_3BYTE_BGR:
102 blueOffset = 0;
103 greenOffset = 1;
104 redOffset = 2;
105 break;
106 case BufferedImage.TYPE_4BYTE_ABGR:
107 case BufferedImage.TYPE_4BYTE_ABGR_PRE:
108 blueOffset = 1;
109 greenOffset = 2;
110 redOffset = 3;
111 break;
112 case BufferedImage.TYPE_INT_ARGB:
113 case BufferedImage.TYPE_INT_ARGB_PRE:
114 redOffset = 0;
115 greenOffset = 1;
116 blueOffset = 2;
117 alphaOffset = 3;
118 break;
119 default:
120 Main.trace("Cannot apply color filter: Source image is of wrong type (" + type + ").");
121 return src;
122 }
123 doFilter((DataBufferByte) srcBuffer, (DataBufferByte) destBuffer, redOffset, greenOffset, blueOffset,
124 alphaOffset, src.getAlphaRaster() != null);
125 return dest;
126 }
127
128 private void doFilter(DataBufferByte src, DataBufferByte dest, int redOffset, int greenOffset, int blueOffset,
129 int alphaOffset, boolean hasAlpha) {
130 byte[] srcPixels = src.getData();
131 byte[] destPixels = dest.getData();
132 if (srcPixels.length != destPixels.length) {
133 Main.trace("Cannot apply color filter: Source/Dest lengths differ.");
134 return;
135 }
136 int entries = hasAlpha ? 4 : 3;
137 for (int i = 0; i < srcPixels.length; i += entries) {
138 int r = srcPixels[i + redOffset] & 0xff;
139 int g = srcPixels[i + greenOffset] & 0xff;
140 int b = srcPixels[i + blueOffset] & 0xff;
141 double luminosity = r * .21d + g * .72d + b * .07d;
142 destPixels[i + redOffset] = mix(r, luminosity);
143 destPixels[i + greenOffset] = mix(g, luminosity);
144 destPixels[i + blueOffset] = mix(b, luminosity);
145 if (hasAlpha) {
146 destPixels[i + alphaOffset] = srcPixels[i + alphaOffset];
147 }
148 }
149 }
150
151 private byte mix(int color, double luminosity) {
152 int val = (int) (colorfulness * color + (1 - colorfulness) * luminosity);
153 if (val < 0) {
154 return 0;
155 } else if (val > 0xff) {
156 return (byte) 0xff;
157 } else {
158 return (byte) val;
159 }
160 }
161
162 @Override
163 public Rectangle2D getBounds2D(BufferedImage src) {
164 return new Rectangle(src.getWidth(), src.getHeight());
165 }
166
167 @Override
168 public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
169 return new BufferedImage(src.getWidth(), src.getHeight(), src.getType());
170 }
171
172 @Override
173 public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
174 return (Point2D) srcPt.clone();
175 }
176
177 @Override
178 public RenderingHints getRenderingHints() {
179 return null;
180 }
181 }
182}
Note: See TracBrowser for help on using the repository browser.