source: josm/trunk/test/unit/org/openstreetmap/josm/tools/ImageProviderTest.java@ 16810

Last change on this file since 16810 was 16810, checked in by simon04, 4 years ago

fix #19551 - Add ImageProviderTest.testTicket19551 (patch by taylor.smock)

  • Property svn:eol-style set to native
File size: 12.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
5import static org.junit.Assert.assertEquals;
6import static org.junit.Assert.assertFalse;
7import static org.junit.Assert.assertNotNull;
8import static org.junit.Assert.assertTrue;
9import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
10
11import java.awt.Color;
12import java.awt.Dimension;
13import java.awt.Graphics;
14import java.awt.GraphicsEnvironment;
15import java.awt.GridLayout;
16import java.awt.Image;
17import java.awt.Point;
18import java.awt.Toolkit;
19import java.awt.Transparency;
20import java.awt.event.MouseEvent;
21import java.awt.event.MouseListener;
22import java.awt.image.BufferedImage;
23import java.io.File;
24import java.io.IOException;
25import java.util.Arrays;
26import java.util.Collections;
27import java.util.List;
28import java.util.logging.Handler;
29import java.util.logging.LogRecord;
30import java.util.logging.Logger;
31
32import javax.swing.ImageIcon;
33import javax.swing.JFrame;
34import javax.swing.JPanel;
35
36import org.junit.Before;
37import org.junit.BeforeClass;
38import org.junit.Ignore;
39import org.junit.Rule;
40import org.junit.Test;
41import org.openstreetmap.josm.JOSMFixture;
42import org.openstreetmap.josm.TestUtils;
43import org.openstreetmap.josm.data.coor.LatLon;
44import org.openstreetmap.josm.data.osm.Node;
45import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset;
46import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets;
47import org.openstreetmap.josm.gui.tagging.presets.items.Key;
48import org.openstreetmap.josm.testutils.JOSMTestRules;
49import org.xml.sax.SAXException;
50
51import com.kitfox.svg.SVGConst;
52
53import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
54
55/**
56 * Unit tests of {@link ImageProvider} class.
57 */
58public class ImageProviderTest {
59
60 /**
61 * Setup test.
62 */
63 @Rule
64 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
65 public JOSMTestRules test = new JOSMTestRules();
66
67 private static final class LogHandler14319 extends Handler {
68 boolean failed;
69
70 @Override
71 public void publish(LogRecord record) {
72 if ("Could not load image: https://host-in-the-trusted-network.com/test.jpg".equals(record.getMessage())) {
73 failed = true;
74 }
75 }
76
77 @Override
78 public void flush() {
79 }
80
81 @Override
82 public void close() throws SecurityException {
83 }
84 }
85
86 /**
87 * Setup test.
88 */
89 @BeforeClass
90 public static void setUp() {
91 JOSMFixture.createUnitTestFixture().init();
92 }
93
94 @Before
95 public void resetPixelDensity() {
96 GuiSizesHelper.setPixelDensity(1.0f);
97 }
98
99 /**
100 * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/9984">#9984</a>
101 * @throws IOException if an error occurs during reading
102 */
103 @Test
104 public void testTicket9984() throws IOException {
105 File file = new File(TestUtils.getRegressionDataFile(9984, "tile.png"));
106 assertEquals(Transparency.TRANSLUCENT, ImageProvider.read(file, true, true).getTransparency());
107 assertEquals(Transparency.TRANSLUCENT, ImageProvider.read(file, false, true).getTransparency());
108 long expectedTransparency = Utils.getJavaVersion() < 11 ? Transparency.OPAQUE : Transparency.TRANSLUCENT;
109 assertEquals(expectedTransparency, ImageProvider.read(file, false, false).getTransparency());
110 assertEquals(expectedTransparency, ImageProvider.read(file, true, false).getTransparency());
111 }
112
113 /**
114 * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/10030">#10030</a>
115 * @throws IOException if an error occurs during reading
116 */
117 @Test
118 public void testTicket10030() throws IOException {
119 File file = new File(TestUtils.getRegressionDataFile(10030, "tile.jpg"));
120 BufferedImage img = ImageProvider.read(file, true, true);
121 assertNotNull(img);
122 }
123
124 /**
125 * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/14319">#14319</a>
126 * @throws IOException if an error occurs during reading
127 */
128 @Test
129 @SuppressFBWarnings(value = "LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE")
130 public void testTicket14319() throws IOException {
131 LogHandler14319 handler = new LogHandler14319();
132 Logger.getLogger(SVGConst.SVG_LOGGER).addHandler(handler);
133 ImageIcon img = new ImageProvider(
134 new File(TestUtils.getRegressionDataDir(14319)).getAbsolutePath(), "attack.svg").get();
135 assertNotNull(img);
136 assertFalse(handler.failed);
137 }
138
139 /**
140 * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/19551">#19551</a>
141 * @throws SAXException If the type cannot be set (shouldn't throw)
142 */
143 @Test
144 public void testTicket19551() throws SAXException {
145 TaggingPreset badPreset = new TaggingPreset();
146 badPreset.setType("node,way,relation,closedway");
147 Key key = new Key();
148 key.key = "amenity";
149 key.value = "fuel";
150 badPreset.data.add(key);
151 TaggingPreset goodPreset = new TaggingPreset();
152 goodPreset.setType("node,way,relation,closedway");
153 goodPreset.data.add(key);
154 goodPreset.iconName = "stop";
155 TaggingPresets.addTaggingPresets(Arrays.asList(goodPreset, badPreset));
156 Node node = new Node(LatLon.ZERO);
157 node.put("amenity", "fuel");
158 assertDoesNotThrow(() -> ImageProvider.getPadded(node, ImageProvider.ImageSizes.MAP.getImageDimension(), Collections.emptyList()));
159 }
160
161 /**
162 * Test fetching an image using {@code wiki://} protocol.
163 */
164 @Test
165 public void testWikiProtocol() {
166 // https://commons.wikimedia.org/wiki/File:OpenJDK_logo.svg
167 assertNotNull(ImageProvider.get("wiki://OpenJDK_logo.svg"));
168 }
169
170 /**
171 * Test fetching an image using {@code data:} URL.
172 */
173 @Test
174 public void testDataUrl() {
175 // Red dot image, taken from https://en.wikipedia.org/wiki/Data_URI_scheme#HTML
176 assertNotNull(ImageProvider.get("data:image/png;base64," +
177 "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4"+
178 "//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="));
179 }
180
181 /**
182 * Test getting a bounded icon given some UI scaling configured.
183 */
184 @Test
185 public void testGetImageIconBounded() {
186 int scale = 2;
187 GuiSizesHelper.setPixelDensity(scale);
188
189 ImageProvider imageProvider = new ImageProvider("open").setOptional(true);
190 ImageResource resource = imageProvider.getResource();
191 Dimension iconDimension = ImageProvider.ImageSizes.SMALLICON.getImageDimension();
192 ImageIcon icon = resource.getImageIconBounded(iconDimension);
193 Image image = icon.getImage();
194 List<Image> resolutionVariants = HiDPISupport.getResolutionVariants(image);
195 if (resolutionVariants.size() > 1) {
196 assertEquals(2, resolutionVariants.size());
197 int expectedVirtualWidth = ImageProvider.ImageSizes.SMALLICON.getVirtualWidth();
198 assertEquals(expectedVirtualWidth * scale, resolutionVariants.get(0).getWidth(null));
199 assertEquals((int) Math.round(expectedVirtualWidth * scale * HiDPISupport.getHiDPIScale()),
200 resolutionVariants.get(1).getWidth(null));
201 }
202 }
203
204 /**
205 * Test getting an image for a crosshair cursor.
206 */
207 @Test
208 public void testGetCursorImageForCrosshair() {
209 if (GraphicsEnvironment.isHeadless()) {
210 // TODO mock Toolkit.getDefaultToolkit().getBestCursorSize()
211 return;
212 }
213 Point hotSpot = new Point();
214 Image image = ImageProvider.getCursorImage("crosshair", null, hotSpot);
215 assertCursorDimensionsCorrect(new Point.Double(10.0, 10.0), image, hotSpot);
216 }
217
218 /**
219 * Test getting an image for a custom cursor with overlay.
220 */
221 @Test
222 public void testGetCursorImageWithOverlay() {
223 testCursorImageWithOverlay(1.0f); // normal case
224 testCursorImageWithOverlay(1.5f); // user has configured a GUI scale of 1.5 in the JOSM advanced preferences
225 }
226
227 private void testCursorImageWithOverlay(float guiScale) {
228 if (GraphicsEnvironment.isHeadless()) {
229 // TODO mock Toolkit.getDefaultToolkit().getBestCursorSize()
230 return;
231 }
232 GuiSizesHelper.setPixelDensity(guiScale);
233 Point hotSpot = new Point();
234 Image image = ImageProvider.getCursorImage("normal", "selection", hotSpot);
235 assertCursorDimensionsCorrect(new Point.Double(3.0, 2.0), image, hotSpot);
236 BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getWidth(null), TYPE_INT_ARGB);
237 bufferedImage.getGraphics().drawImage(image, 0, 0, null);
238
239 // check that the square of 1/4 size right lower to the center has some non-emtpy pixels
240 boolean nonEmptyPixelExistsRightLowerToCenter = false;
241 for (int x = image.getWidth(null) / 2; x < image.getWidth(null) * 3 / 4; ++x) {
242 for (int y = image.getHeight(null) / 2; y < image.getWidth(null) * 3 / 4; ++y) {
243 if (bufferedImage.getRGB(x, y) != 0)
244 nonEmptyPixelExistsRightLowerToCenter = true;
245 }
246 }
247 assertTrue(nonEmptyPixelExistsRightLowerToCenter);
248 }
249
250 private void assertCursorDimensionsCorrect(Point.Double originalHotspot, Image image, Point hotSpot) {
251 int originalCursorSize = ImageProvider.CURSOR_SIZE_HOTSPOT_IS_RELATIVE_TO;
252 Dimension bestCursorSize = Toolkit.getDefaultToolkit().getBestCursorSize(originalCursorSize, originalCursorSize);
253 Image bestCursorImage = HiDPISupport.getResolutionVariant(image, bestCursorSize.width, bestCursorSize.height);
254 int bestCursorImageWidth = bestCursorImage.getWidth(null);
255 assertEquals((int) Math.round(bestCursorSize.getWidth()), bestCursorImageWidth);
256 int bestCursorImageHeight = bestCursorImage.getHeight(null);
257 assertEquals((int) Math.round(bestCursorSize.getHeight()), bestCursorImageHeight);
258 assertEquals(originalHotspot.x / originalCursorSize * bestCursorImageWidth, hotSpot.x, 1 /* at worst one pixel off */);
259 assertEquals(originalHotspot.y / originalCursorSize * bestCursorImageHeight, hotSpot.y, 1 /* at worst one pixel off */);
260 }
261
262
263 /**
264 * Test getting a cursor
265 */
266 @Ignore("manual execution only, as the look of the cursor cannot be checked automatedly")
267 @Test
268 public void testGetCursor() throws InterruptedException {
269 JFrame frame = new JFrame();
270 frame.setSize(500, 500);
271 frame.setLayout(new GridLayout(2, 2));
272 JPanel leftUpperPanel = new JPanel(), rightUpperPanel = new JPanel(), leftLowerPanel = new JPanel(), rightLowerPanel = new JPanel();
273 leftUpperPanel.setBackground(Color.DARK_GRAY);
274 rightUpperPanel.setBackground(Color.DARK_GRAY);
275 leftLowerPanel.setBackground(Color.DARK_GRAY);
276 rightLowerPanel.setBackground(Color.DARK_GRAY);
277 frame.add(leftUpperPanel);
278 frame.add(rightUpperPanel);
279 frame.add(leftLowerPanel);
280 frame.add(rightLowerPanel);
281
282 leftUpperPanel.setCursor(ImageProvider.getCursor("normal", "select_add")); // contains diagonal sensitive to alpha blending
283 rightUpperPanel.setCursor(ImageProvider.getCursor("crosshair", "joinway")); // combination of overlay and hotspot not top left
284 leftLowerPanel.setCursor(ImageProvider.getCursor("hand", "parallel_remove")); // reasonably nice bitmap cursor
285 rightLowerPanel.setCursor(ImageProvider.getCursor("rotate", null)); // ugly bitmap cursor, cannot do much here
286
287 frame.setVisible(true);
288
289 // hover over the four quadrant to observe different cursors
290
291 // draw red dot at hotspot when clicking
292 frame.addMouseListener(new MouseListener() {
293 @Override
294 public void mouseClicked(MouseEvent e) {
295 Graphics graphics = frame.getGraphics();
296 graphics.setColor(Color.RED);
297 graphics.drawRect(e.getX(), e.getY(), 1, 1);
298 }
299
300 @Override
301 public void mousePressed(MouseEvent e) { }
302
303 @Override
304 public void mouseReleased(MouseEvent e) { }
305
306 @Override
307 public void mouseEntered(MouseEvent e) { }
308
309 @Override
310 public void mouseExited(MouseEvent e) { }
311 });
312 Thread.sleep(9000); // test would time out after 10s
313 }
314}
Note: See TracBrowser for help on using the repository browser.