参照java程序员之旅<JSP开发技术详解> 卢汉鹏等编著 化学工业出版社出版 的讲解,做的。
而这个response依赖于ServletOutputStream。因此,要单独编写一个继承了ServletOutputStream的类:WaterMark_Output.java
这些编写好之后呢,需要配置web.xml文件:添加的内容如下
在入题前,我先表达一下自己对这本书的,憎恶。岂一个烂字了得得到的,错误一大片,代码也有问题。今天做的这个动态水印就是原书上代码出现Fatal ERROR!!!
好,不吐不快;说出来,我感觉好多了。但我更多的是希望,那些同志们,一定要谨慎对待这本书。
现在正是bla bla bla:
原理部分
添加水印的话,就是对图片进行操作,将水印对应的像素覆盖原始图片的特定区域。这里,我们使用JSP中的filter来进行处理。因为当一个文件被request 的时候,WEB容器(我的就是tomcat)会根据application的web.xml中的配置信息进行处理。我们配置了过滤器,过滤器就会首先对request和response进行处理。然后,把request,response交付给对应的controller去进一步处理。
具体内容
首先,编写对两个Image对象进行合并的类:ImageUtil.java
就是首先获取两个Image对象,然后开辟一个图片缓存区,先将原始图片写入缓存,然后将水印图片写入缓存的对应位置。最后返回这个缓存对象。
package test.watermarker;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Date: 13-7-10
* Time: 上午9:16
* To change this template use File | Settings | File Templates.
*/
public class ImageUtil {
/*
* @param imageData JPG file
* @param waterMarkFile waterMark file
* @return marked file
* @throws IOException
* */
public static byte[] waterMark (byte[] imageData, String waterMarkFile) throws IOException {
int paddingRight = 10;
int paddingBottom = 10;
Image image = new ImageIcon(imageData).getImage();
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);
Image waterMark = ImageIO.read(new File(waterMarkFile));
int waterMarkWidth = waterMark.getWidth(null);
int waterMarkHeight = waterMark.getHeight(null);
if (imageWidth < waterMarkWidth + 2 * paddingRight
|| imageHeight < waterMarkHeight + 2 * paddingBottom) {
return imageData;
}
BufferedImage bufferedImage = new BufferedImage(imageWidth,imageHeight,BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.createGraphics();
g.drawImage(image,0,0,imageWidth,imageHeight,null);
g.drawImage(waterMark,imageWidth - waterMarkWidth - paddingRight,imageHeight - waterMarkHeight - paddingBottom,waterMarkWidth,waterMarkHeight,null);
g.dispose();
ByteArrayOutputStream out = new ByteArrayOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(bufferedImage);
byte[] data = out.toByteArray();
out.close();
return data;
}
}
做动态水印的话,就是修改了response,这里我们单独做一个wrapper:Response_WaterMark.java
package test.watermarker;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Date: 13-7-10
* Time: 上午9:39
* To change this template use File | Settings | File Templates.
*/
public class Response_WaterMark extends HttpServletResponseWrapper {
private String waterMarkFile;
private String originalImageFile;
private HttpServletResponse response;
private WaterMark_Output waterMarkOutputStream;
public Response_WaterMark(HttpServletResponse response, String waterMarkFile, String imageOriginal) throws IOException {
super(response);
this.response = response;
this.waterMarkFile = waterMarkFile;
this.originalImageFile = imageOriginal;
waterMarkOutputStream = new WaterMark_Output();
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return waterMarkOutputStream;
}
@Override
public void flushBuffer() throws IOException {
waterMarkOutputStream.flush();
}
public void finishResponse() throws IOException{
//the original image data
File file = new File(originalImageFile);
if(file.exists() && file.canRead()){
System.out.println("all files can be read!!!bla bla bla");
BufferedImage imageaa = ImageIO.read(file);
ByteArrayOutputStream tmp = new ByteArrayOutputStream();
ImageIO.write(imageaa,"jpg",tmp);
byte[] imageData = tmp.toByteArray();
//the data after water marked
byte[] image = ImageUtil.waterMark(imageData,waterMarkFile);
response.setContentLength(image.length);
response.getOutputStream().write(image);
} else {
System.out.println("the original image file can NOT be read!!!bla bla bla");
BufferedImage waterMark = ImageIO.read(new File(waterMarkFile));
ByteArrayOutputStream tmp = new ByteArrayOutputStream();
ImageIO.write(waterMark,"jpg",tmp);
byte[] tmpImage = tmp.toByteArray();
response.setContentLength(tmpImage.length);
response.getOutputStream().write(tmpImage);
}
waterMarkOutputStream.close();
}
}
而这个response依赖于ServletOutputStream。因此,要单独编写一个继承了ServletOutputStream的类:WaterMark_Output.java
package test.watermarker;
import javax.servlet.ServletOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Date: 13-7-10
* Time: 上午9:32
* To change this template use File | Settings | File Templates.
*/
public class WaterMark_Output extends ServletOutputStream {
private ByteArrayOutputStream byteArrayOutputStream;
public WaterMark_Output() throws IOException {
byteArrayOutputStream = new ByteArrayOutputStream();
}
@Override
public void write(int b) throws IOException {
//To change body of implemented methods use File | Settings | File Templates.
byteArrayOutputStream.write(b);
}
@Override
public void close() throws IOException {
byteArrayOutputStream.close();
}
@Override
public void flush() throws IOException {
byteArrayOutputStream.flush();
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
byteArrayOutputStream.write(b, off, len);
}
@Override
public void write(byte[] b) throws IOException {
byteArrayOutputStream.write(b);
}
public ByteArrayOutputStream getByteArrayOutputStream(){
return byteArrayOutputStream;
}
}
最后,就是我们的filter了:Filter_Water.java
package test.watermarker;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Date: 13-7-10
* Time: 上午9:49
* To change this template use File | Settings | File Templates.
*/
public class Filter_Water implements Filter {
private String waterMarkFile;
@Override
public void init(FilterConfig config) throws ServletException {
String file = config.getInitParameter("waterMarkFile");
waterMarkFile = config.getServletContext().getRealPath(file);
System.out.println("the water MARK file is located in "+waterMarkFile);
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String imageOriginal = request.getRequestURI();
System.out.println("the original file is located in "+imageOriginal);
Response_WaterMark responseWaterMark = new Response_WaterMark(response,waterMarkFile,imageOriginal);
System.out.println("next will deal with image showed");
responseWaterMark.finishResponse();
chain.doFilter(request,responseWaterMark);
}
@Override
public void destroy() {
//To change body of implemented methods use File | Settings | File Templates.
}
}
这些编写好之后呢,需要配置web.xml文件:添加的内容如下
<!--Water Marker for image formated by JPEG-->
<filter>
<filter-name>waterMarker</filter-name>
<filter-class>test.watermarker.Filter_Water</filter-class>
<init-param>
<param-name>waterMarkFile</param-name>
<param-value>/waterMark.jpg</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>waterMarker</filter-name>
<url-pattern>*.jpg</url-pattern>
</filter-mapping>
其中,
waterMark.jpg是放在了webapp\ROOT\;这一点切记!!!ROOT是我的项目目录
即将被访问的图片test.jpg也是放在了我tomcat所在盘符的根目录下;这一点切记!!!
访问结果如下: