1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.tools;
|
---|
3 |
|
---|
4 | import java.awt.Dimension;
|
---|
5 | import java.awt.Graphics2D;
|
---|
6 | import java.awt.Image;
|
---|
7 | import java.awt.RenderingHints;
|
---|
8 | import java.awt.image.BufferedImage;
|
---|
9 | import java.util.function.Consumer;
|
---|
10 |
|
---|
11 | /**
|
---|
12 | * Determines how the image is sized/resized in {@link ImageResource#getImageIcon(Dimension, boolean, ImageResizeMode)}.
|
---|
13 | */
|
---|
14 | enum ImageResizeMode {
|
---|
15 |
|
---|
16 | /**
|
---|
17 | * Calculate proportional dimensions that best fit into the target width and height, retain aspect ratio
|
---|
18 | */
|
---|
19 | AUTO {
|
---|
20 | @Override
|
---|
21 | Dimension computeDimension(Dimension dim, Dimension icon) {
|
---|
22 | CheckParameterUtil.ensureThat((dim.width > 0 || dim.width == -1) && (dim.height > 0 || dim.height == -1),
|
---|
23 | () -> dim + " is invalid");
|
---|
24 | if (dim.width == -1 && dim.height == -1) {
|
---|
25 | return new Dimension(GuiSizesHelper.getSizeDpiAdjusted(icon.width), GuiSizesHelper.getSizeDpiAdjusted(icon.height));
|
---|
26 | } else if (dim.width == -1) {
|
---|
27 | return new Dimension(Math.max(1, icon.width * dim.height / icon.height), dim.height);
|
---|
28 | } else if (dim.height == -1) {
|
---|
29 | return new Dimension(dim.width, Math.max(1, icon.height * dim.width / icon.width));
|
---|
30 | } else if (icon.getWidth() / dim.getWidth() > icon.getHeight() / dim.getHeight()) {
|
---|
31 | return computeDimension(new Dimension(dim.width, -1), icon);
|
---|
32 | } else {
|
---|
33 | return computeDimension(new Dimension(-1, dim.height), icon);
|
---|
34 | }
|
---|
35 | }
|
---|
36 | },
|
---|
37 |
|
---|
38 | /**
|
---|
39 | * Calculate dimensions for the largest image that fit within the bounding box, retain aspect ratio
|
---|
40 | */
|
---|
41 | BOUNDED {
|
---|
42 | @Override
|
---|
43 | Dimension computeDimension(Dimension dim, Dimension icon) {
|
---|
44 | CheckParameterUtil.ensureThat((dim.width > 0 || dim.width == -1) && (dim.height > 0 || dim.height == -1),
|
---|
45 | () -> dim + " is invalid");
|
---|
46 | final int maxWidth = Math.min(dim.width, icon.width);
|
---|
47 | final int maxHeight = Math.min(dim.height, icon.height);
|
---|
48 | return AUTO.computeDimension(new Dimension(maxWidth, maxHeight), icon);
|
---|
49 | }
|
---|
50 | },
|
---|
51 |
|
---|
52 | /**
|
---|
53 | * Position an appropriately scaled image within the bounding box, retain aspect ratio
|
---|
54 | */
|
---|
55 | PADDED {
|
---|
56 | @Override
|
---|
57 | Dimension computeDimension(Dimension dim, Dimension icon) {
|
---|
58 | CheckParameterUtil.ensureThat(dim.width > 0 && dim.height > 0, () -> dim + " is invalid");
|
---|
59 | return dim;
|
---|
60 | }
|
---|
61 |
|
---|
62 | @Override
|
---|
63 | void prepareGraphics(Dimension icon, BufferedImage image, Graphics2D g) {
|
---|
64 | g.setClip(0, 0, image.getWidth(), image.getHeight());
|
---|
65 | final double scale = Math.min(image.getWidth() / icon.getWidth(), image.getHeight() / icon.getHeight());
|
---|
66 | g.translate((image.getWidth() - icon.getWidth() * scale) / 2, (image.getHeight() - icon.getHeight() * scale) / 2);
|
---|
67 | g.scale(scale, scale);
|
---|
68 | }
|
---|
69 | };
|
---|
70 |
|
---|
71 | /**
|
---|
72 | * Computes the dimension for the resulting image
|
---|
73 | * @param dim the desired image dimension
|
---|
74 | * @param icon the dimensions of the image to resize
|
---|
75 | * @return the dimension for the resulting image
|
---|
76 | */
|
---|
77 | abstract Dimension computeDimension(Dimension dim, Dimension icon);
|
---|
78 |
|
---|
79 | /**
|
---|
80 | * Creates a new buffered image and applies the rendering function
|
---|
81 | * @param dim the desired image dimension
|
---|
82 | * @param icon the dimensions of the image to resize
|
---|
83 | * @param renderer the rendering function
|
---|
84 | * @param sourceIcon the source icon to draw
|
---|
85 | * @return a new buffered image
|
---|
86 | * @throws IllegalArgumentException if renderer or sourceIcon is null
|
---|
87 | */
|
---|
88 | BufferedImage createBufferedImage(Dimension dim, Dimension icon, Consumer<Graphics2D> renderer, Image sourceIcon) {
|
---|
89 | final Dimension real = computeDimension(dim, icon);
|
---|
90 | final BufferedImage bufferedImage = new BufferedImage(real.width, real.height, BufferedImage.TYPE_INT_ARGB);
|
---|
91 | final Graphics2D g = bufferedImage.createGraphics();
|
---|
92 | g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
---|
93 | if (renderer != null) {
|
---|
94 | prepareGraphics(icon, bufferedImage, g);
|
---|
95 | renderer.accept(g);
|
---|
96 | } else if (sourceIcon != null) {
|
---|
97 | sourceIcon = sourceIcon.getScaledInstance(real.width, real.height, Image.SCALE_SMOOTH);
|
---|
98 | g.drawImage(sourceIcon, 0, 0, null);
|
---|
99 | } else {
|
---|
100 | throw new IllegalArgumentException("renderer or sourceIcon");
|
---|
101 | }
|
---|
102 | return bufferedImage;
|
---|
103 | }
|
---|
104 |
|
---|
105 | /**
|
---|
106 | * Prepares the graphics object for rendering the given image
|
---|
107 | * @param icon the dimensions of the image to resize
|
---|
108 | * @param image the image to render afterwards
|
---|
109 | * @param g graphics
|
---|
110 | */
|
---|
111 | void prepareGraphics(Dimension icon, BufferedImage image, Graphics2D g) {
|
---|
112 | g.setClip(0, 0, image.getWidth(), image.getHeight());
|
---|
113 | g.scale(image.getWidth() / icon.getWidth(), image.getHeight() / icon.getHeight());
|
---|
114 | }
|
---|
115 |
|
---|
116 | /**
|
---|
117 | * Returns a cache key for this mode and the given dimension
|
---|
118 | * @param dim the desired image dimension
|
---|
119 | * @return a cache key
|
---|
120 | */
|
---|
121 | int cacheKey(Dimension dim) {
|
---|
122 | return (ordinal() << 28) | ((dim.width & 0xfff) << 16) | (dim.height & 0xfff);
|
---|
123 | }
|
---|
124 |
|
---|
125 | }
|
---|