-
Notifications
You must be signed in to change notification settings - Fork 89
Expand file tree
/
Copy pathImage.java
More file actions
220 lines (181 loc) · 6.24 KB
/
Image.java
File metadata and controls
220 lines (181 loc) · 6.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
package nodebox.graphics;
import nodebox.util.MathUtils;
import javax.imageio.ImageIO;
import javax.management.RuntimeErrorException;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.*;
public class Image extends AbstractGrob {
private float x, y;
private float desiredWidth, desiredHeight;
private float alpha = 1.0F;
private BufferedImage image;
private static BufferedImage blankImage = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY);
public static final String BLANK_IMAGE = "__blank";
public Image() {
this(new File(BLANK_IMAGE));
}
public Image(File file) {
if (file == null || file.getPath().equals(BLANK_IMAGE)) {
image = blankImage;
} else {
try {
image = ImageIO.read(file);
} catch (IOException e) {
throw new RuntimeErrorException(null, "Could not read image " + file);
}
}
}
public Image(String fname) {
this(new File(fname));
}
public Image(String fname, float cx, float cy) {
this(new File(fname));
this.x = cx;
this.y = cy;
}
public Image(BufferedImage image) {
this.image = image;
}
public Image(Image other) {
super(other);
this.x = other.x;
this.y = other.y;
this.desiredWidth = other.desiredWidth;
this.desiredHeight = other.desiredHeight;
this.alpha = other.alpha;
this.image = other.image;
}
public static Image fromData(byte[] data) {
InputStream istream = new BufferedInputStream(new ByteArrayInputStream(data));
try {
return new Image(ImageIO.read(istream));
} catch (IOException e) {
throw new RuntimeErrorException(null, "Could not read image data.");
}
}
//// Attribute access ////
public float getOriginalWidth() {
if (image == null) return 0;
return image.getWidth();
}
public float getOriginalHeight() {
if (image == null) return 0;
return image.getHeight();
}
public float getWidth() {
return getOriginalWidth() * getScaleFactor();
}
public void setWidth(float width) {
this.desiredWidth = width;
}
public float getHeight() {
return getOriginalHeight() * getScaleFactor();
}
public void setHeight(float height) {
this.desiredHeight = height;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
}
public BufferedImage getAwtImage() {
return image;
}
public Size getSize() {
return new Size(image.getWidth(), image.getHeight());
}
//// Transformations ////
protected void setupTransform(Graphics2D g) {
saveTransform(g);
AffineTransform trans = g.getTransform();
trans.concatenate(getTransform().getAffineTransform());
g.setTransform(trans);
}
//// Grob support ////
public boolean isEmpty() {
return image == null || image.getWidth() == 0 || image.getHeight() == 0;
}
public Rect getBounds() {
if (image == null) return new Rect();
float factor = getScaleFactor();
float finalWidth = image.getWidth() * factor;
float finalHeight = image.getHeight() * factor;
return new Rect(x - finalWidth / 2, y - finalHeight / 2, finalWidth, finalHeight);
}
public float getScaleFactor() {
if (desiredWidth != 0 || desiredHeight != 0) {
float srcW = image.getWidth();
float srcH = image.getHeight();
if (desiredWidth != 0 && desiredHeight != 0) {
// Both width and height were given, constrain to smallest
return Math.min(desiredWidth / srcW, desiredHeight / srcH);
} else if (desiredWidth != 0) {
return desiredWidth / srcW;
} else {
return desiredHeight / srcH;
}
} else {
return 1;
}
}
public void draw(Graphics2D g) {
setupTransform(g);
// You can only position an image using an affine transformation.
// We use the transformation to translate the image to the specified
// position, and scale it according to the given width and height.
Transform imageTrans = new Transform();
// Move to the image position. Convert x, y, which are centered coordinates,
// to "real" coordinates.
float factor = getScaleFactor();
float finalWidth = image.getWidth() * factor;
float finalHeight = image.getHeight() * factor;
imageTrans.translate(x - finalWidth / 2, y - finalHeight / 2);
// Scaling only applies to image that have their desired width and/or height set.
// However, getScaleFactor return 1 if height/width are not set, in effect negating
// the effect of the scale.
imageTrans.scale(getScaleFactor());
float a = MathUtils.clamp(alpha);
Composite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) a);
Composite oldComposite = g.getComposite();
g.setComposite(composite);
g.drawRenderedImage(image, imageTrans.getAffineTransform());
g.setComposite(oldComposite);
restoreTransform(g);
}
public Image clone() {
return new Image(this);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Image)) return false;
Image other = (Image) obj;
return this.x == other.x
&& this.y == other.y
&& this.desiredWidth == other.desiredWidth
&& this.desiredHeight == other.desiredHeight
&& this.alpha == other.alpha
&& this.image.equals(other.image)
&& super.equals(other);
}
@Override
public String toString() {
return "<Image (" + getWidth() + ", " + getHeight() + ")>";
}
}