source: josm/trunk/src/org/openstreetmap/josm/tools/ImageWarp.java@ 11891

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

see #7427 - sonar - squid:S1226 - Method parameters, caught exceptions and foreach variables should not be reassigned

  • Property svn:eol-style set to native
File size: 5.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.awt.Color;
5import java.awt.Dimension;
6import java.awt.geom.Point2D;
7import java.awt.geom.Rectangle2D;
8import java.awt.image.BufferedImage;
9
10/**
11 * Image warping algorithm.
12 *
13 * Deforms an image geometrically according to a given transformation formula.
14 * @since 11858
15 */
16public class ImageWarp {
17
18 /**
19 * Transformation that translates the pixel coordinates.
20 */
21 public interface PointTransform {
22 Point2D transform(Point2D pt);
23 }
24
25 /**
26 * Interpolation method.
27 */
28 public enum Interpolation {
29 /**
30 * Nearest neighbor.
31 *
32 * Simplest possible method. Faster, but not very good quality.
33 */
34 NEAREST_NEIGHBOR(1),
35 /**
36 * Bilinear.
37 *
38 * Decent quality.
39 */
40 BILINEAR(2);
41
42 private final int margin;
43
44 private Interpolation(int margin) {
45 this.margin = margin;
46 }
47
48 /**
49 * Number of pixels to scan outside the source image.
50 * Used to get smoother borders.
51 * @return the margin
52 */
53 public int getMargin() {
54 return margin;
55 }
56 }
57
58 /**
59 * Warp an image.
60 * @param srcImg the original image
61 * @param targetDim dimension of the target image
62 * @param invTransform inverse transformation (translates pixel coordinates
63 * of the target image to pixel coordinates of the original image)
64 * @param interpolation the interpolation method
65 * @return the warped image
66 */
67 public static BufferedImage warp(BufferedImage srcImg, Dimension targetDim, PointTransform invTransform, Interpolation interpolation) {
68 BufferedImage imgTarget = new BufferedImage(targetDim.width, targetDim.height, BufferedImage.TYPE_INT_ARGB);
69 Rectangle2D srcRect = new Rectangle2D.Double(0, 0, srcImg.getWidth(), srcImg.getHeight());
70 for (int j = 0; j < imgTarget.getHeight(); j++) {
71 for (int i = 0; i < imgTarget.getWidth(); i++) {
72 Point2D srcCoord = invTransform.transform(new Point2D.Double(i, j));
73 if (isInside(srcCoord, srcRect, interpolation.getMargin())) {
74 int rgb;
75 switch (interpolation) {
76 case NEAREST_NEIGHBOR:
77 rgb = getColor((int) Math.round(srcCoord.getX()), (int) Math.round(srcCoord.getY()), srcImg).getRGB();
78 break;
79 case BILINEAR:
80 int x0 = (int) Math.floor(srcCoord.getX());
81 double dx = srcCoord.getX() - x0;
82 int y0 = (int) Math.floor(srcCoord.getY());
83 double dy = srcCoord.getY() - y0;
84 Color c00 = getColor(x0, y0, srcImg);
85 Color c01 = getColor(x0, y0 + 1, srcImg);
86 Color c10 = getColor(x0 + 1, y0, srcImg);
87 Color c11 = getColor(x0 + 1, y0 + 1, srcImg);
88 int red = (int) Math.round(
89 (c00.getRed() * (1-dx) + c10.getRed() * dx) * (1-dy) +
90 (c01.getRed() * (1-dx) + c11.getRed() * dx) * dy);
91 int green = (int) Math.round(
92 (c00.getGreen()* (1-dx) + c10.getGreen() * dx) * (1-dy) +
93 (c01.getGreen() * (1-dx) + c11.getGreen() * dx) * dy);
94 int blue = (int) Math.round(
95 (c00.getBlue()* (1-dx) + c10.getBlue() * dx) * (1-dy) +
96 (c01.getBlue() * (1-dx) + c11.getBlue() * dx) * dy);
97 int alpha = (int) Math.round(
98 (c00.getAlpha()* (1-dx) + c10.getAlpha() * dx) * (1-dy) +
99 (c01.getAlpha() * (1-dx) + c11.getAlpha() * dx) * dy);
100 rgb = new Color(red, green, blue, alpha).getRGB();
101 break;
102 default:
103 throw new AssertionError();
104 }
105 imgTarget.setRGB(i, j, rgb);
106 }
107 }
108 }
109 return imgTarget;
110 }
111
112 private static boolean isInside(Point2D p, Rectangle2D rect, double margin) {
113 return isInside(p.getX(), rect.getMinX(), rect.getMaxX(), margin) &&
114 isInside(p.getY(), rect.getMinY(), rect.getMaxY(), margin);
115 }
116
117 private static boolean isInside(double x, double xMin, double xMax, double margin) {
118 return x + margin >= xMin && x - margin <= xMax;
119 }
120
121 private static int clamp(int i, int max) {
122 if (i < 0) {
123 return 0;
124 } else if (i >= max) {
125 return max - 1;
126 } else {
127 return i;
128 }
129 }
130
131 private static Color getColor(int x, int y, BufferedImage img) {
132 // border strategy: continue with the color of the outermost pixel,
133 // but change alpha component to fully translucent
134 int a = clamp(x, img.getWidth());
135 int b = clamp(y, img.getHeight());
136 Color clr = new Color(img.getRGB(a, b));
137 if (a == x && b == y)
138 return clr;
139 // keep color components, but set transparency to 0
140 // (the idea is that border fades out and mixes with next tile)
141 return new Color(clr.getRed(), clr.getGreen(), clr.getBlue(), 0);
142 }
143}
Note: See TracBrowser for help on using the repository browser.