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 package info.magnolia.templating.jsp.taglib;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.HierarchyManager;
38 import info.magnolia.cms.core.ItemType;
39 import info.magnolia.cms.util.NodeDataUtil;
40 import info.magnolia.context.MgnlContext;
41 import info.magnolia.jcr.util.NodeTypes;
42 import info.magnolia.repository.RepositoryConstants;
43
44 import java.awt.Graphics2D;
45 import java.awt.Image;
46 import java.awt.image.BufferedImage;
47 import java.io.File;
48 import java.io.FileNotFoundException;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.util.Calendar;
52
53 import javax.imageio.ImageIO;
54 import javax.jcr.AccessDeniedException;
55 import javax.jcr.PathNotFoundException;
56 import javax.jcr.RepositoryException;
57 import javax.servlet.jsp.JspException;
58 import javax.servlet.jsp.JspWriter;
59
60 import org.slf4j.LoggerFactory;
61 import org.slf4j.Logger;
62
63 import org.tldgen.annotations.BodyContent;
64 import org.tldgen.annotations.Tag;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 @Tag(name="scaleImage", bodyContent=BodyContent.EMPTY)
87
88 public class ScaleImageTag extends BaseImageTag {
89 private static final Logger log = LoggerFactory.getLogger(ScaleImageTag.class);
90
91
92
93
94 private static final String TEMP_IMAGE_NAME = "tmp-img";
95
96
97
98
99 private static final String PROPERTIES_EXTENSION_VALUE = "PNG";
100
101
102
103
104 private int maxHeight = 0;
105
106
107
108
109 private int maxWidth = 0;
110
111
112
113
114
115
116 private boolean allowOversize = true;
117
118
119
120
121 private String imageContentNodeName;
122
123
124
125
126 private String parentNodeDataName;
127
128
129
130
131
132 public void setMaxHeight(int maxHeight) {
133 this.maxHeight = maxHeight;
134 }
135
136
137
138
139
140 public void setMaxWidth(int maxWidth) {
141 this.maxWidth = maxWidth;
142 }
143
144
145
146
147
148 public void setAllowOversize(boolean allowOversize) {
149 this.allowOversize = allowOversize;
150 }
151
152
153
154
155
156 @Override
157 public void setParentContentNodeName(String parentContentNodeName) {
158 this.parentContentNodeName = parentContentNodeName;
159 }
160
161
162
163
164
165 public void setParentNodeDataName(String parentNodeDataName) {
166 this.parentNodeDataName = parentNodeDataName;
167 }
168
169
170
171
172
173 @Override
174 public void setImageContentNodeName(String imageContentNodeName) {
175 this.imageContentNodeName = imageContentNodeName;
176 }
177
178 @Override
179 public void doTag() throws JspException {
180
181 Content parentContentNode;
182 Content imageContentNode;
183 JspWriter out = this.getJspContext().getOut();
184
185 try {
186
187
188 if ((this.parentContentNodeName == null) || (this.parentContentNodeName.equals(""))) {
189 parentContentNode = MgnlContext.getAggregationState().getCurrentContent();
190 }
191 else {
192 HierarchyManager hm = MgnlContext.getHierarchyManager(RepositoryConstants.WEBSITE);
193
194
195 if (this.parentContentNodeName.startsWith("/")) {
196 parentContentNode = hm.getContent(this.parentContentNodeName);
197 }
198 else {
199 String handle = MgnlContext.getAggregationState().getCurrentContentNode().getPath();
200 parentContentNode = hm.getContent(handle + "/" + this.parentContentNodeName);
201 }
202 }
203
204
205 if (parentContentNode.hasContent(this.imageContentNodeName)) {
206 imageContentNode = parentContentNode.getContent(this.imageContentNodeName);
207 }
208 else {
209
210 imageContentNode = parentContentNode.createContent(this.imageContentNodeName, ItemType.CONTENTNODE);
211 parentContentNode.save();
212 }
213
214
215 if (!imageContentNode.hasNodeData(this.parentNodeDataName) || rescale(parentContentNode, imageContentNode)) {
216 this.createImageNodeData(parentContentNode, imageContentNode);
217 }
218
219 StringBuffer handle = new StringBuffer(imageContentNode.getHandle());
220 handle.append("/");
221 handle.append(getFilename());
222 out.write(handle.toString());
223 }
224 catch (PathNotFoundException e) {
225 log.error("PathNotFoundException occured in ScaleImage tag: {}", e.getMessage(), e);
226 }
227 catch (AccessDeniedException e) {
228 log.error("AccessDeniedException occured in ScaleImage tag: {}", e.getMessage(), e);
229 }
230 catch (RepositoryException e) {
231 log.error("RepositoryException occured in ScaleImage tag: {}", e.getMessage(), e);
232 }
233 catch (FileNotFoundException e) {
234 log.error("FileNotFoundException occured in ScaleImage tag: {}", e.getMessage(), e);
235 }
236 catch (IOException e) {
237 log.error("IOException occured in ScaleImage tag: {}", e.getMessage(), e);
238 }
239 this.cleanUp();
240 }
241
242
243
244
245
246
247
248
249 protected boolean rescale(Content parentContentNode, Content imageContentNode) {
250
251 try {
252 Calendar parentModified = NodeTypes.LastModified.getLastModified(parentContentNode.getJCRNode());
253 Calendar imageModified = NodeTypes.LastModified.getLastModified(imageContentNode.getJCRNode());
254
255 if (parentModified.after(imageModified)) {
256 return true;
257 }
258 } catch (RepositoryException e) {
259
260 return true;
261 }
262
263 int originalHeight = (int) imageContentNode.getNodeData("maxHeight").getLong();
264 int originalWidth = (int) imageContentNode.getNodeData("maxWidth").getLong();
265
266 return originalHeight != maxHeight || originalWidth != maxWidth;
267 }
268
269
270
271
272 public void cleanUp() {
273 this.parentNodeDataName = null;
274 this.imageContentNodeName = null;
275 this.maxWidth = 0;
276 this.maxHeight = 0;
277 }
278
279
280
281
282
283 private void createImageNodeData(Content parentContentNode, Content imageContentNode) throws PathNotFoundException,
284 RepositoryException, IOException {
285
286
287 InputStream oriImgStr = parentContentNode.getNodeData(this.parentNodeDataName).getStream();
288 BufferedImage oriImgBuff = ImageIO.read(oriImgStr);
289 oriImgStr.close();
290
291 File newImgFile = this.scaleImage(oriImgBuff);
292
293 NodeDataUtil.getOrCreate(imageContentNode, "maxHeight").setValue(maxHeight);
294 NodeDataUtil.getOrCreate(imageContentNode, "maxWidth").setValue(maxWidth);
295
296 createImageNode(newImgFile, imageContentNode);
297
298 newImgFile.delete();
299 }
300
301
302
303
304
305
306 private File scaleImage(BufferedImage oriImgBuff) throws IOException {
307
308 int oriWidth = oriImgBuff.getWidth();
309 int oriHeight = oriImgBuff.getHeight();
310
311 double scaleFactor = this.scaleFactor(oriWidth, oriHeight);
312
313 int newWidth = new Double(oriWidth * scaleFactor).intValue();
314 int newHeight = new Double(oriHeight * scaleFactor).intValue();
315
316 Image newImg = oriImgBuff.getScaledInstance(newWidth, newHeight, Image.SCALE_AREA_AVERAGING);
317 BufferedImage newImgBuff = new BufferedImage(
318 newImg.getWidth(null),
319 newImg.getHeight(null),
320 BufferedImage.TYPE_INT_RGB);
321 Graphics2D g = newImgBuff.createGraphics();
322 g.drawImage(newImg, 0, 0, null);
323 g.dispose();
324
325 File newImgFile = File.createTempFile(TEMP_IMAGE_NAME, PROPERTIES_EXTENSION_VALUE);
326
327 ImageIO.write(newImgBuff, PROPERTIES_EXTENSION_VALUE, newImgFile);
328
329 return newImgFile;
330 }
331
332
333
334
335
336
337
338 private double scaleFactor(int originalWidth, int originalHeight) {
339 double scaleFactor;
340
341 int scaleWidth = this.maxWidth;
342 int scaleHeight = this.maxHeight;
343
344 if (!this.allowOversize) {
345 scaleWidth = Math.min(this.maxWidth, originalWidth);
346 scaleHeight = Math.min(this.maxHeight, originalHeight);
347 }
348
349 if (scaleWidth <= 0 && scaleHeight <= 0) {
350
351 scaleFactor = 1;
352 }
353 else if (scaleWidth <= 0) {
354
355 scaleFactor = (double) scaleHeight / (double) originalHeight;
356 }
357 else if (scaleHeight <= 0) {
358
359 scaleFactor = (double) scaleWidth / (double) originalWidth;
360 }
361 else {
362
363 double scaleFactorWidth = (double) scaleWidth / (double) originalWidth;
364 double scaleFactorHeight = (double) scaleHeight / (double) originalHeight;
365 scaleFactor = Math.min(scaleFactorWidth, scaleFactorHeight);
366 }
367 return scaleFactor;
368 }
369
370 @Override
371 protected String getFilename() {
372 return this.parentNodeDataName;
373 }
374 }