001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.extensions.markup.html.image.resource; 018 019import java.awt.Graphics2D; 020import java.awt.RenderingHints; 021import java.awt.image.BufferedImage; 022import java.io.ByteArrayInputStream; 023import java.io.IOException; 024import java.io.InputStream; 025import java.time.Instant; 026import javax.imageio.ImageIO; 027import org.apache.wicket.WicketRuntimeException; 028import org.apache.wicket.request.resource.DynamicImageResource; 029import org.apache.wicket.request.resource.IResource; 030import org.apache.wicket.response.ByteArrayResponse; 031import org.apache.wicket.util.io.IOUtils; 032import org.apache.wicket.util.lang.Args; 033 034/** 035 * Image resource that dynamically scales the given original resource to a thumbnail. It is scaled 036 * either using the given maxSize as width or height, depending on its shape. If both the width and 037 * height are less than maxSize, no scaling is performed. 038 * 039 * @author Eelco Hillenius 040 * @author Eugene Kamenev 041 */ 042 043public class ThumbnailImageResource extends DynamicImageResource 044{ 045 private static final long serialVersionUID = 1L; 046 047 /** the unscaled, original image resource. */ 048 private final IResource unscaledImageResource; 049 050 /** maximum size (width or height) for resize operation. */ 051 private final int maxSize; 052 053 /** the cached byte array of the thumbnail. */ 054 private transient byte[] thumbnail; 055 056 /** 057 * Construct. 058 * 059 * @param unscaledImageResource 060 * the unscaled, original image resource. Must be not null 061 * @param maxSize 062 * maximum size (width or height) for resize operation 063 */ 064 public ThumbnailImageResource(final IResource unscaledImageResource, final int maxSize) 065 { 066 Args.notNull(unscaledImageResource, "unscaledImageResource"); 067 068 this.unscaledImageResource = unscaledImageResource; 069 this.maxSize = maxSize; 070 } 071 072 /** 073 * @return The image data for this dynamic image 074 */ 075 @Override 076 protected byte[] getImageData(final Attributes attributes) 077 { 078 if (thumbnail == null) 079 { 080 final BufferedImage image = getScaledImageInstance(attributes); 081 thumbnail = toImageData(image); 082 setLastModifiedTime(Instant.now()); 083 } 084 return thumbnail; 085 } 086 087 /** 088 * get resized image instance. 089 * 090 * @param attributes 091 * 092 * @return BufferedImage 093 */ 094 protected BufferedImage getScaledImageInstance(final Attributes attributes) 095 { 096 InputStream is = null; 097 BufferedImage originalImage = null; 098 try 099 { 100 // read original image 101 ByteArrayResponse byteResponse = new ByteArrayResponse(); 102 Attributes dispatchAttributes = new Attributes(attributes.getRequest(), byteResponse, attributes.getParameters()); 103 unscaledImageResource.respond(dispatchAttributes); 104 is = new ByteArrayInputStream(byteResponse.getBytes()); 105 originalImage = ImageIO.read(is); 106 if (originalImage == null) 107 { 108 throw new IOException("Unable to read unscaled image"); 109 } 110 } 111 catch (IOException e) 112 { 113 throw new WicketRuntimeException(e); 114 } 115 finally 116 { 117 IOUtils.closeQuietly(is); 118 } 119 120 int originalWidth = originalImage.getWidth(); 121 int originalHeight = originalImage.getHeight(); 122 123 if ((originalWidth > maxSize) || (originalHeight > maxSize)) 124 { 125 final int newWidth; 126 final int newHeight; 127 128 if (originalWidth > originalHeight) 129 { 130 newWidth = maxSize; 131 newHeight = (maxSize * originalHeight) / originalWidth; 132 } 133 else 134 { 135 newWidth = (maxSize * originalWidth) / originalHeight; 136 newHeight = maxSize; 137 } 138 139 // http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html 140 BufferedImage dimg = new BufferedImage(newWidth, newHeight, originalImage.getType()); 141 Graphics2D g = dimg.createGraphics(); 142 try 143 { 144 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, 145 RenderingHints.VALUE_INTERPOLATION_BILINEAR); 146 g.drawImage(originalImage, 0, 0, newWidth, newHeight, 0, 0, originalWidth, 147 originalHeight, null); 148 } 149 finally 150 { 151 g.dispose(); 152 } 153 154 return dimg; 155 } 156 157 // no need for resizing 158 return originalImage; 159 } 160 161}