1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
|
17 |
|
|
18 |
|
|
19 |
|
|
20 |
|
package com.xpn.xwiki.plugin.image; |
21 |
|
|
22 |
|
import java.awt.Image; |
23 |
|
import java.awt.image.RenderedImage; |
24 |
|
import java.io.IOException; |
25 |
|
import java.io.OutputStream; |
26 |
|
import java.util.Arrays; |
27 |
|
|
28 |
|
import org.apache.commons.io.IOUtils; |
29 |
|
import org.apache.commons.lang3.StringUtils; |
30 |
|
import org.slf4j.Logger; |
31 |
|
import org.slf4j.LoggerFactory; |
32 |
|
import org.xwiki.cache.Cache; |
33 |
|
import org.xwiki.cache.CacheException; |
34 |
|
import org.xwiki.cache.CacheManager; |
35 |
|
import org.xwiki.cache.config.CacheConfiguration; |
36 |
|
import org.xwiki.cache.eviction.LRUEvictionConfiguration; |
37 |
|
|
38 |
|
import com.xpn.xwiki.XWikiContext; |
39 |
|
import com.xpn.xwiki.XWikiException; |
40 |
|
import com.xpn.xwiki.api.Api; |
41 |
|
import com.xpn.xwiki.doc.XWikiAttachment; |
42 |
|
import com.xpn.xwiki.plugin.XWikiDefaultPlugin; |
43 |
|
import com.xpn.xwiki.plugin.XWikiPluginInterface; |
44 |
|
import com.xpn.xwiki.web.Utils; |
45 |
|
|
46 |
|
|
47 |
|
@version |
48 |
|
@deprecated |
49 |
|
|
50 |
|
@Deprecated |
|
|
| 66.7% |
Uncovered Elements: 47 (141) |
Complexity: 45 |
Complexity Density: 0.47 |
|
51 |
|
public class ImagePlugin extends XWikiDefaultPlugin |
52 |
|
{ |
53 |
|
|
54 |
|
|
55 |
|
|
56 |
|
private static final Logger LOG = LoggerFactory.getLogger(ImagePlugin.class); |
57 |
|
|
58 |
|
|
59 |
|
|
60 |
|
|
61 |
|
@see |
62 |
|
|
63 |
|
private static final String PLUGIN_NAME = "image"; |
64 |
|
|
65 |
|
|
66 |
|
|
67 |
|
|
68 |
|
private Cache<XWikiAttachment> imageCache; |
69 |
|
|
70 |
|
|
71 |
|
|
72 |
|
|
73 |
|
private int capacity = 50; |
74 |
|
|
75 |
|
|
76 |
|
|
77 |
|
|
78 |
|
private float defaultQuality = 0.5f; |
79 |
|
|
80 |
|
|
81 |
|
|
82 |
|
|
83 |
|
private final ImageProcessor imageProcessor = Utils.getComponent(ImageProcessor.class); |
84 |
|
|
85 |
|
|
86 |
|
|
87 |
|
|
88 |
|
@param |
89 |
|
@param |
90 |
|
@param |
91 |
|
@see |
92 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (2) |
Complexity: 1 |
Complexity Density: 0.5 |
|
93 |
2 |
public ImagePlugin(String name, String className, XWikiContext context)... |
94 |
|
{ |
95 |
2 |
super(name, className, context); |
96 |
|
|
97 |
2 |
init(context); |
98 |
|
} |
99 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
100 |
0 |
@Override... |
101 |
|
public Api getPluginApi(XWikiPluginInterface plugin, XWikiContext context) |
102 |
|
{ |
103 |
0 |
return new ImagePluginAPI((ImagePlugin) plugin, context); |
104 |
|
} |
105 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
106 |
0 |
@Override... |
107 |
|
public String getName() |
108 |
|
{ |
109 |
0 |
return PLUGIN_NAME; |
110 |
|
} |
111 |
|
|
|
|
| 77.8% |
Uncovered Elements: 2 (9) |
Complexity: 3 |
Complexity Density: 0.43 |
|
112 |
2 |
@Override... |
113 |
|
public void init(XWikiContext context) |
114 |
|
{ |
115 |
2 |
super.init(context); |
116 |
|
|
117 |
2 |
initCache(context); |
118 |
|
|
119 |
2 |
String defaultQualityParam = context.getWiki().Param("xwiki.plugin.image.defaultQuality"); |
120 |
2 |
if (!StringUtils.isBlank(defaultQualityParam)) { |
121 |
2 |
try { |
122 |
2 |
this.defaultQuality = Math.max(0, Math.min(1, Float.parseFloat(defaultQualityParam.trim()))); |
123 |
|
} catch (NumberFormatException e) { |
124 |
0 |
LOG.warn("Failed to parse xwiki.plugin.image.defaultQuality configuration parameter. " |
125 |
|
+ "Using {} as the default image quality.", this.defaultQuality); |
126 |
|
} |
127 |
|
} |
128 |
|
} |
129 |
|
|
130 |
|
|
131 |
|
|
132 |
|
|
133 |
|
@param |
134 |
|
|
|
|
| 83.3% |
Uncovered Elements: 3 (18) |
Complexity: 6 |
Complexity Density: 0.43 |
|
135 |
4 |
private void initCache(XWikiContext context)... |
136 |
|
{ |
137 |
4 |
if (this.imageCache == null) { |
138 |
2 |
CacheConfiguration configuration = new CacheConfiguration(); |
139 |
|
|
140 |
2 |
configuration.setConfigurationId("xwiki.plugin.image"); |
141 |
|
|
142 |
|
|
143 |
2 |
LRUEvictionConfiguration lru = new LRUEvictionConfiguration(); |
144 |
2 |
configuration.put(LRUEvictionConfiguration.CONFIGURATIONID, lru); |
145 |
|
|
146 |
2 |
String capacityParam = context.getWiki().Param("xwiki.plugin.image.cache.capacity"); |
147 |
2 |
if (!StringUtils.isBlank(capacityParam) && StringUtils.isNumeric(capacityParam.trim())) { |
148 |
2 |
try { |
149 |
2 |
this.capacity = Integer.parseInt(capacityParam.trim()); |
150 |
|
} catch (NumberFormatException e) { |
151 |
0 |
LOG.warn(String.format( |
152 |
|
"Failed to parse xwiki.plugin.image.cache.capacity configuration parameter. " |
153 |
|
+ "Using %s as the cache capacity.", this.capacity), e); |
154 |
|
} |
155 |
|
} |
156 |
2 |
lru.setMaxEntries(this.capacity); |
157 |
|
|
158 |
2 |
try { |
159 |
2 |
this.imageCache = Utils.getComponent(CacheManager.class).createNewLocalCache(configuration); |
160 |
|
} catch (CacheException e) { |
161 |
0 |
LOG.error("Error initializing the image cache.", e); |
162 |
|
} |
163 |
|
} |
164 |
|
} |
165 |
|
|
|
|
| 0% |
Uncovered Elements: 5 (5) |
Complexity: 2 |
Complexity Density: 0.67 |
|
166 |
0 |
@Override... |
167 |
|
public void flushCache() |
168 |
|
{ |
169 |
0 |
if (this.imageCache != null) { |
170 |
0 |
this.imageCache.dispose(); |
171 |
|
} |
172 |
0 |
this.imageCache = null; |
173 |
|
} |
174 |
|
|
175 |
|
|
176 |
|
@inheritDoc |
177 |
|
|
178 |
|
|
179 |
|
|
180 |
|
|
181 |
|
|
182 |
|
|
183 |
|
@see |
184 |
|
|
|
|
| 81% |
Uncovered Elements: 4 (21) |
Complexity: 10 |
Complexity Density: 0.59 |
|
185 |
3 |
@Override... |
186 |
|
public XWikiAttachment downloadAttachment(XWikiAttachment attachment, XWikiContext context) |
187 |
|
{ |
188 |
3 |
if (!this.imageProcessor.isMimeTypeSupported(attachment.getMimeType(context))) { |
189 |
1 |
return attachment; |
190 |
|
} |
191 |
|
|
192 |
2 |
int height = -1; |
193 |
2 |
try { |
194 |
2 |
height = Integer.parseInt(context.getRequest().getParameter("height")); |
195 |
|
} catch (NumberFormatException e) { |
196 |
|
|
197 |
|
} |
198 |
|
|
199 |
2 |
int width = -1; |
200 |
2 |
try { |
201 |
2 |
width = Integer.parseInt(context.getRequest().getParameter("width")); |
202 |
|
} catch (NumberFormatException e) { |
203 |
|
|
204 |
|
} |
205 |
|
|
206 |
2 |
float quality = -1; |
207 |
2 |
try { |
208 |
2 |
quality = Float.parseFloat(context.getRequest().getParameter("quality")); |
209 |
|
} catch (NumberFormatException e) { |
210 |
|
|
211 |
|
} catch (NullPointerException e) { |
212 |
|
|
213 |
|
} |
214 |
|
|
215 |
|
|
216 |
2 |
if (height <= 0 && width <= 0 && quality < 0) { |
217 |
0 |
return attachment; |
218 |
|
} |
219 |
|
|
220 |
2 |
try { |
221 |
|
|
222 |
2 |
return downloadImage(attachment, width, height, quality, context); |
223 |
|
} catch (Exception e) { |
224 |
0 |
LOG.warn("Failed to transform image attachment.", e); |
225 |
0 |
return attachment; |
226 |
|
} |
227 |
|
} |
228 |
|
|
229 |
|
|
230 |
|
|
231 |
|
|
232 |
|
@param |
233 |
|
@param |
234 |
|
|
235 |
|
@param |
236 |
|
|
237 |
|
@param |
238 |
|
@param |
239 |
|
@return |
240 |
|
@throws |
241 |
|
|
|
|
| 91.7% |
Uncovered Elements: 1 (12) |
Complexity: 4 |
Complexity Density: 0.5 |
|
242 |
2 |
private XWikiAttachment downloadImage(XWikiAttachment image, int width, int height, float quality,... |
243 |
|
XWikiContext context) throws Exception |
244 |
|
{ |
245 |
2 |
initCache(context); |
246 |
|
|
247 |
2 |
boolean keepAspectRatio = Boolean.valueOf(context.getRequest().getParameter("keepAspectRatio")); |
248 |
|
|
249 |
2 |
XWikiAttachment thumbnail = (this.imageCache == null) |
250 |
|
? shrinkImage(image, width, height, keepAspectRatio, quality, context) |
251 |
|
: downloadImageFromCache(image, width, height, keepAspectRatio, quality, context); |
252 |
|
|
253 |
|
|
254 |
2 |
String fileName = thumbnail.getFilename(); |
255 |
2 |
String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(fileName, String.valueOf('.'))); |
256 |
2 |
if (thumbnail != image && !Arrays.asList("jpeg", "jpg", "png").contains(extension)) { |
257 |
|
|
258 |
1 |
thumbnail.setFilename(StringUtils.substringBeforeLast(fileName, ".") + ".png"); |
259 |
|
} |
260 |
2 |
return thumbnail; |
261 |
|
} |
262 |
|
|
263 |
|
|
264 |
|
|
265 |
|
|
266 |
|
@param |
267 |
|
@param |
268 |
|
|
269 |
|
@param |
270 |
|
|
271 |
|
@param |
272 |
|
@param |
273 |
|
@param |
274 |
|
@return |
275 |
|
@throws |
276 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (8) |
Complexity: 2 |
Complexity Density: 0.33 |
|
277 |
2 |
private XWikiAttachment downloadImageFromCache(XWikiAttachment image, int width, int height,... |
278 |
|
boolean keepAspectRatio, float quality, XWikiContext context) throws Exception |
279 |
|
{ |
280 |
2 |
String key = |
281 |
|
String.format("%s;%s;%s;%s;%s;%s", image.getId(), image.getVersion(), width, height, keepAspectRatio, |
282 |
|
quality); |
283 |
|
|
284 |
2 |
XWikiAttachment thumbnail = this.imageCache.get(key); |
285 |
2 |
if (thumbnail == null) { |
286 |
1 |
thumbnail = shrinkImage(image, width, height, keepAspectRatio, quality, context); |
287 |
1 |
this.imageCache.set(key, thumbnail); |
288 |
|
} |
289 |
2 |
return thumbnail; |
290 |
|
} |
291 |
|
|
292 |
|
|
293 |
|
|
294 |
|
|
295 |
|
|
296 |
|
@param |
297 |
|
@param |
298 |
|
|
299 |
|
@param |
300 |
|
|
301 |
|
@param |
302 |
|
|
303 |
|
|
304 |
|
@param |
305 |
|
@param |
306 |
|
@return |
307 |
|
@throws |
308 |
|
|
|
|
| 70% |
Uncovered Elements: 6 (20) |
Complexity: 4 |
Complexity Density: 0.25 |
|
309 |
1 |
private XWikiAttachment shrinkImage(XWikiAttachment attachment, int requestedWidth, int requestedHeight,... |
310 |
|
boolean keepAspectRatio, float requestedQuality, XWikiContext context) throws Exception |
311 |
|
{ |
312 |
1 |
Image image = this.imageProcessor.readImage(attachment.getContentInputStream(context)); |
313 |
|
|
314 |
|
|
315 |
1 |
int currentWidth = image.getWidth(null); |
316 |
1 |
int currentHeight = image.getHeight(null); |
317 |
1 |
int[] dimensions = |
318 |
|
reduceImageDimensions(currentWidth, currentHeight, requestedWidth, requestedHeight, keepAspectRatio); |
319 |
|
|
320 |
1 |
float quality = requestedQuality; |
321 |
1 |
if (quality < 0) { |
322 |
|
|
323 |
0 |
if (dimensions[0] == currentWidth && dimensions[1] == currentHeight) { |
324 |
0 |
return attachment; |
325 |
|
} |
326 |
0 |
quality = this.defaultQuality; |
327 |
|
} |
328 |
|
|
329 |
|
|
330 |
1 |
RenderedImage shrunkImage = this.imageProcessor.scaleImage(image, dimensions[0], dimensions[1]); |
331 |
|
|
332 |
|
|
333 |
1 |
XWikiAttachment thumbnail = (XWikiAttachment) attachment.clone(); |
334 |
1 |
thumbnail.loadContent(context); |
335 |
|
|
336 |
1 |
OutputStream acos = thumbnail.getAttachment_content().getContentOutputStream(); |
337 |
1 |
this.imageProcessor.writeImage(shrunkImage, |
338 |
|
attachment.getMimeType(context), |
339 |
|
quality, |
340 |
|
acos); |
341 |
|
|
342 |
1 |
IOUtils.closeQuietly(acos); |
343 |
|
|
344 |
1 |
return thumbnail; |
345 |
|
} |
346 |
|
|
347 |
|
|
348 |
|
|
349 |
|
|
350 |
|
|
351 |
|
|
352 |
|
|
353 |
|
|
354 |
|
@param |
355 |
|
@param |
356 |
|
@param |
357 |
|
|
358 |
|
@param |
359 |
|
|
360 |
|
@param |
361 |
|
|
362 |
|
|
363 |
|
@return |
364 |
|
|
|
|
| 41.4% |
Uncovered Elements: 17 (29) |
Complexity: 9 |
Complexity Density: 0.47 |
|
365 |
1 |
private int[] reduceImageDimensions(int currentWidth, int currentHeight, int requestedWidth, int requestedHeight,... |
366 |
|
boolean keepAspectRatio) |
367 |
|
{ |
368 |
1 |
double aspectRatio = (double) currentWidth / (double) currentHeight; |
369 |
|
|
370 |
1 |
int width = currentWidth; |
371 |
1 |
int height = currentHeight; |
372 |
|
|
373 |
1 |
if (requestedWidth <= 0 || requestedWidth >= currentWidth) { |
374 |
|
|
375 |
0 |
if (requestedHeight > 0 && requestedHeight < currentHeight) { |
376 |
|
|
377 |
0 |
width = (int) (requestedHeight * aspectRatio); |
378 |
0 |
height = requestedHeight; |
379 |
|
} |
380 |
1 |
} else if (requestedHeight <= 0 || requestedHeight >= currentHeight) { |
381 |
|
|
382 |
0 |
width = requestedWidth; |
383 |
0 |
height = (int) (requestedWidth / aspectRatio); |
384 |
1 |
} else if (keepAspectRatio) { |
385 |
|
|
386 |
0 |
width = requestedWidth; |
387 |
0 |
height = (int) (requestedWidth / aspectRatio); |
388 |
0 |
if (height > requestedHeight) { |
389 |
|
|
390 |
0 |
width = (int) (requestedHeight * aspectRatio); |
391 |
0 |
height = requestedHeight; |
392 |
|
} |
393 |
|
} else { |
394 |
|
|
395 |
1 |
width = requestedWidth; |
396 |
1 |
height = requestedHeight; |
397 |
|
} |
398 |
|
|
399 |
1 |
return new int[] { width, height }; |
400 |
|
} |
401 |
|
|
402 |
|
|
403 |
|
@param |
404 |
|
@param |
405 |
|
@return |
406 |
|
@throws |
407 |
|
@throws |
408 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
409 |
0 |
public int getWidth(XWikiAttachment attachment, XWikiContext context) throws IOException, XWikiException... |
410 |
|
{ |
411 |
0 |
return this.imageProcessor.readImage(attachment.getContentInputStream(context)).getWidth(null); |
412 |
|
} |
413 |
|
|
414 |
|
|
415 |
|
@param |
416 |
|
@param |
417 |
|
@return |
418 |
|
@throws |
419 |
|
@throws |
420 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
421 |
0 |
public int getHeight(XWikiAttachment attachment, XWikiContext context) throws IOException, XWikiException... |
422 |
|
{ |
423 |
0 |
return this.imageProcessor.readImage(attachment.getContentInputStream(context)).getHeight(null); |
424 |
|
} |
425 |
|
} |