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