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.request.resource; 018 019import java.awt.image.BufferedImage; 020import java.io.ByteArrayOutputStream; 021import java.io.IOException; 022import java.time.Instant; 023import javax.imageio.ImageIO; 024import javax.servlet.http.HttpServletResponse; 025import org.apache.wicket.WicketRuntimeException; 026import org.apache.wicket.util.lang.Args; 027 028/** 029 * Base class for dynamically generated ImageResources. 030 */ 031public abstract class DynamicImageResource extends AbstractResource 032{ 033 private static final long serialVersionUID = 1L; 034 035 /** The image type */ 036 private String format = "png"; 037 038 /** The last modified time of this resource */ 039 private Instant lastModifiedTime; 040 041 042 /** 043 * Construct. 044 */ 045 public DynamicImageResource() 046 { 047 } 048 049 /** 050 * Creates a dynamic resource from for the given locale 051 * 052 * @param format 053 * The image format ("png", "jpeg", etc) 054 */ 055 public DynamicImageResource(String format) 056 { 057 setFormat(format); 058 } 059 060 /** 061 * @return Returns the image format. 062 */ 063 public synchronized final String getFormat() 064 { 065 return format; 066 } 067 068 /** 069 * Sets the format of this resource 070 * 071 * @param format 072 * The format (jpg, png or gif..) 073 */ 074 public synchronized final void setFormat(String format) 075 { 076 Args.notNull(format, "format"); 077 this.format = format; 078 } 079 080 /** 081 * set the last modified time for this resource. 082 * 083 * @param time 084 */ 085 protected synchronized void setLastModifiedTime(Instant time) 086 { 087 lastModifiedTime = time; 088 } 089 090 /** 091 * @param image 092 * The image to turn into data 093 * @return The image data for this dynamic image 094 */ 095 protected byte[] toImageData(final BufferedImage image) 096 { 097 try 098 { 099 // Create output stream 100 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 101 102 // Write image using any matching ImageWriter 103 ImageIO.write(image, format, out); 104 105 // Return the image data 106 return out.toByteArray(); 107 } 108 catch (IOException e) 109 { 110 throw new WicketRuntimeException("Unable to convert dynamic image to stream", e); 111 } 112 } 113 114 /** 115 * Get image data for our dynamic image resource. If the subclass regenerates the data, it 116 * should set the {@link DynamicImageResource#setLastModifiedTime(Instant)} when it does so. This 117 * ensures that image caching works correctly. 118 * 119 * @param attributes 120 * the context bringing the request, response and the parameters 121 * 122 * @return The image data for this dynamic image. {@code null} means there is no image and 404 123 * (Not found) response will be return. 124 */ 125 protected abstract byte[] getImageData(Attributes attributes); 126 127 protected void configureResponse(final ResourceResponse response, final Attributes attributes) 128 { 129 } 130 131 @Override 132 protected ResourceResponse newResourceResponse(final Attributes attributes) 133 { 134 final ResourceResponse response = new ResourceResponse(); 135 136 if (lastModifiedTime != null) 137 { 138 response.setLastModified(lastModifiedTime); 139 } 140 else 141 { 142 response.setLastModified(Instant.now()); 143 } 144 145 if (response.dataNeedsToBeWritten(attributes)) 146 { 147 response.setContentDisposition(ContentDisposition.INLINE); 148 149 final byte[] imageData = getImageData(attributes); 150 if (imageData == null) 151 { 152 response.setError(HttpServletResponse.SC_NOT_FOUND); 153 } 154 else 155 { 156 response.setContentType("image/" + getFormat()); 157 response.setWriteCallback(new WriteCallback() 158 { 159 @Override 160 public void writeData(final Attributes attributes) 161 { 162 attributes.getResponse().write(imageData); 163 } 164 }); 165 166 configureResponse(response, attributes); 167 } 168 } 169 170 return response; 171 } 172}