图片添加水印

最近学习了下Java实现图片添加水印,包括文字水印和图片水印,单图片添加水印和多图片批量添加水印等。下面简单总结下开发过程:
1.首先搭建框架,这里使用的是struts2框架,允许一次上传多个图片,可以将原图和添加过水印的图片对比展示。
web.xml中的配置文件:

<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

struts.xml配置文件:

<struts>
    <!--设置开发模式,请求后缀的配置 -->
    <constant name="struts.action.extension" value="action" />
    <!--设置编码形式为UTF-8 -->
    <constant name="struts.i18n.encoding" value="UTF-8" />
    <!--省略其他配置信息 -->
    <constant name="struts.multipart.maxSize" value="1073741824" />

    <!-- 设置上传文件的临时文件夹 -->
    <constant name="struts.multipart.saveDir" value="/tmpUpload" />

    <package name="default" extends="struts-default">
        <action name="watermark" class="com.watermark.WaterMarkAction" method="watermark">
            <param name="uploadPath">/images</param>
            <result name="success">watermark.jsp</result>
        </action>
    </package>

</struts>

2.实现图片添加水印的实现思路是:
①创建缓存图片对象;
②创建Java绘图工具类;
③使用绘图工具对象将原图绘制到缓存图片对象;
④使用绘图工具将水印(文字/图片)绘制到缓存图片对象;
⑤创建图像编码工具类;
⑥使用图像编码工具类,输出缓存图像到目标图片文件。

3.给单个图片添加文字水印

public interface MarkService {

    public static final String MARK_TEXT = "Byron";
    public static final String FONT_NAME = "微软雅黑";
    public static final int FONT_STYLE = Font.BOLD; //黑体
    public static final int FONT_SIZE = 20;         //文字大小
    public static final Color FONT_COLOR = Color.red;//文字颜色

    public static final int X = 10;  //文字坐标
    public static final int Y = 10;

    public static float ALPHA = 0.3F; //文字水印透明度 

    public static final String LOGO = "logo.gif";   //图片形式的水印

    public String watermark(File image,String imageFileName,String uploadPath,String realUploadPath);

}
/*
 * 实现添加单个文字水印
 */
public class TextMarkService implements MarkService{

    @Override
    public String watermark(File image, String imageFileName,
            String uploadPath, String realUploadPath) {

        String logoFileName = "logo_"+imageFileName; //定义目标文件输出的名称
        OutputStream os = null;

        try {
            //1 创建图片缓存对象
            Image image2 = ImageIO.read(image); //解码原图
            int width = image2.getWidth(null);  //获取原图的宽度
            int height = image2.getHeight(null);//获取原图的高度
            BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);   //图像颜色的设置

            //2 创建Java绘图工具对象
            Graphics2D g = bufferedImage.createGraphics();

            //3 使用绘图工具对象将原图绘制到缓存图片对象
            g.drawImage(image2, 0, 0, width, height, null);

            //4 使用绘图工具对象将水印(文字/图片)绘制到缓存图片
            g.setFont(new Font(FONT_NAME,FONT_STYLE,FONT_SIZE));
            g.setColor(FONT_COLOR);

            //获取文字水印的宽度和高度值
            int width1 = FONT_SIZE*getTextLength(MARK_TEXT);//文字水印宽度
            int height1= FONT_SIZE;                         //文字水印高度

            //计算原图和文字水印的宽度和高度之差
            int widthDiff = width - width1;     //宽度之差
            int heightDiff= height - height1;   //高度之差

            int x = X;  //横坐标
            int y = Y;  //纵坐标

            //保证文字水印在右下方显示
            if(x > widthDiff){
                x = widthDiff;  
            }
            if(y > heightDiff){
                y = heightDiff; 
            }

            //水印透明度的设置
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,ALPHA));
            //绘制文字
            g.drawString(MARK_TEXT, x, y + FONT_SIZE);
            //释放工具
            g.dispose();

            //创建文件输出流,指向最终的目标文件
            os = new FileOutputStream(realUploadPath+"/"+logoFileName); 

            //5 创建图像文件编码工具类
            JPEGImageEncoder en = JPEGCodec.createJPEGEncoder(os);

            //6 使用图像编码工具类,输出缓存图像到目标文件
            en.encode(bufferedImage);

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(os!=null){
                try {
                    os.close(); //关闭流
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
        return uploadPath+"/"+logoFileName;
    }

    //文本长度的处理:文字水印的中英文字符的宽度转换
    public int getTextLength(String text){
        int length = text.length();
        for(int i=0;i<text.length();i++){
            String s = String.valueOf(text.charAt(i));
            if(s.getBytes().length>1){  //中文字符
                length++;
            }
        }
        length = length%2 == 0?length/2:length/2+1;  //中文和英文字符的转换
        return length;
    }

}

4.新建一个index.jsp页面和水印添加成功后的watermark.jsp
index.jsp页面:

<body>
    <h4>上传图片</h4>
    <hr />
    <form name="form1" action="${pageContext.request.contextPath}/watermark.action"
        method="post" enctype="multipart/form-data">
        <input type="file" name="image" /><br /> 
        <input type="file" name="image" /><br /> 
        <input type="file" name="image" /><br /> 
        <input type="file" name="image" /><br /> 
        <input type="file" name="image" /><br /><br /> 
        <input type="submit" value="上传图片" />
    </form>
    <hr />
</body>

效果如下:
这里写图片描述

watermark.jsp页面:

<body>
    <table width="99%" align="center">

  <tr>
    <td width="50%" align="center">
        <img src=${pageContext.request.contextPath }<s:property value="picInfo.imageURL"/> width="550" />
    </td>
    <td width="50%" align="center">
        <img src=${pageContext.request.contextPath }<s:property value="picInfo.logoImageURL"/> width="550" />
    </td>
  </tr>
    </table>
</body>

5.WaterMarkAction处理类

package com.watermark;

import java.io.File;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

/**
 * 
 * description:控制器
 * @author Byron
 * 
 */
public class WaterMarkAction extends ActionSupport {

    private File image; // 单个图片上传
    private String imageFileName;
    private PicInfo picInfo = new PicInfo(); // 创建数据模型

    private String uploadPath; // 文件上传的相对路径,要在struts.xml文件中配置

    /*
     * 请求处理方法:负责接收图片上传以及水印添加的请求
     */
    public String watermark() throws Exception {

        /*
         * 单个图片上传处理逻辑
         */
        // 文件上传的绝对路径是基于相对路径获取的
        String realUploadPath = ServletActionContext.getServletContext()
                .getRealPath(uploadPath);

        UploadService uploadService = new UploadService();

        // 调用uploadService来完成图片上传
        picInfo.setImageURL(uploadService.uploadImage(image, imageFileName,
                uploadPath, realUploadPath));

        MarkService markService = new TextMarkService(); // 创建上传单个图片添加文字水印服务

        // 将上传好之后图片的路径保存到数据变量中,会将picInfo变量返回到watermark.jsp页面中
        picInfo.setLogoImageURL(markService.watermark(image, imageFileName,
                uploadPath, realUploadPath));

        return SUCCESS;
    }

    public File getImage() {
        return image;
    }

    public String getImageFileName() {
        return imageFileName;
    }

    public void setImageFileName(String imageFileName) {
        this.imageFileName = imageFileName;
    }

    public void setImage(File image) {
        this.image = image;
    }

    public String getUploadPath() {
        return uploadPath;
    }

    public void setUploadPath(String uploadPath) {
        this.uploadPath = uploadPath;
    }

    public PicInfo getPicInfo() {
        return picInfo;
    }

    public void setPicInfo(PicInfo picInfo) {
        this.picInfo = picInfo;
    }

}

效果如下:
这里写图片描述

6.给图片添加多个文字水印,新建一个添加多文字水印的服务类

/*
 * 实现添加多个文字水印
 */
public class MoreTextMarkService implements MarkService{

    @Override
    public String watermark(File image, String imageFileName,
            String uploadPath, String realUploadPath) {

        String logoFileName = "logo_"+imageFileName;    //定义目标文件输出的名称
        OutputStream os = null;

        try {
            //1 创建图片缓存对象
            Image image2 = ImageIO.read(image);

            int width = image2.getWidth(null);
            int height = image2.getHeight(null);

            BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);

            //2 创建Java绘图工具对象
            Graphics2D g = bufferedImage.createGraphics();

            //3 使用绘图工具对象将原图绘制到缓存图片对象
            g.drawImage(image2, 0, 0, width, height, null);

            //4 使用绘图工具对象将水印(文字/图片)绘制到缓存图片
            g.setFont(new Font(FONT_NAME,FONT_STYLE,FONT_SIZE));
            g.setColor(FONT_COLOR);

            int width1 = FONT_SIZE*getTextLength(MARK_TEXT);//文字水印宽度
            int height1= FONT_SIZE;                         //文字水印高度

            //透明度的设置
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,ALPHA));

            //旋转图片(30°)
            g.rotate(Math.toRadians(30),bufferedImage.getWidth()/2,bufferedImage.getHeight()/2);

            //设置水印的坐标
            int x= -width/2;
            int y= -height/2;

            while(x < width*1.5){
                y = -height/2;
                while(y < height*1.5){
                    g.drawString(MARK_TEXT,x,y);
                    y += height1 + 50;
                }
                x += width1 + 50;   //水印之间的间隔设为50
            }

            //释放工具
            g.dispose();

            //最终目标文件
            os = new FileOutputStream(realUploadPath+"/"+logoFileName); 

            //5 创建图像文件编码工具类
            JPEGImageEncoder en = JPEGCodec.createJPEGEncoder(os);

            //6 使用图像编码工具类,输出缓存图像到目标文件
            en.encode(bufferedImage);

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(os!=null){
                try {
                    os.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
        return uploadPath+"/"+logoFileName;
    }

    //处理文字水印的中英文字符的宽度转换
    public int getTextLength(String text){
        int length = text.length();
        for(int i=0;i<text.length();i++){
            String s = String.valueOf(text.charAt(i));
            if(s.getBytes().length>1){  //中文字符
                length++;
            }
        }
        length = length%2 == 0?length/2:length/2+1;  //中文和英文字符的转换
        return length;
    }

然后修改WaterMarkAction 中 markService为:

 MarkService markService = new MoreTextMarkService();   //创建上传多个图片添加文字水印服务

效果如下:
这里写图片描述

7.批量上传图片添加多个文字水印,修改WaterMarkAction

package com.watermark;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

/**
 * 
 * description:控制器
 * @author Byron
 * 
 */
public class WaterMarkAction extends ActionSupport {

    private File[] image;  // 多个图片上传
    private String[] imageFileName;
    private List<PicInfo> picInfo = new ArrayList<PicInfo>();

    private String uploadPath; // 文件上传的相对路径,struts.xml文件中配置

    /*
     * 请求处理方法:负责接收图片上传以及水印添加的请求
     */
    public String watermark() throws Exception {

        /*
         * 批量添加文字水印
         */
        String realUploadPath = ServletActionContext.getServletContext()
                .getRealPath(uploadPath);

        UploadService uploadService = new UploadService();

        // 创建水印服务类
        MarkService markService = new MoreTextMarkService();

        // 判断是否为多图片上传
        if (image != null && image.length > 0) {
            for (int i = 0; i < image.length; i++) {
                PicInfo pi = new PicInfo();

                pi.setImageURL(uploadService.uploadImage(image[i], imageFileName[i],
                        uploadPath, realUploadPath));

                // 水印添加操作
                pi.setLogoImageURL(markService.watermark(image[i], imageFileName[i],
                        uploadPath, realUploadPath));
                // 将有水印的图片添加的picInfo数组中
                picInfo.add(pi);
            }
        }
        return SUCCESS;
    }


    public File[] getImage() {
        return image;
    }

    public void setImage(File[] image) {
        this.image = image;
    }

    public String[] getImageFileName() {
        return imageFileName;
    }

    public void setImageFileName(String[] imageFileName) {
        this.imageFileName = imageFileName;
    }

    public String getUploadPath() {
        return uploadPath;
    }

    public void setUploadPath(String uploadPath) {
        this.uploadPath = uploadPath;
    }

    public List<PicInfo> getPicInfo() {
        return picInfo;
    }

    public void setPicInfo(List<PicInfo> picInfo) {
        this.picInfo = picInfo;
    }


}

效果如下:
这里写图片描述

8.下面介绍如何给图片添加多个图片水印:
首先创建一个服务类:

/*
 * 实现添加多个图片水印
 */
public class MoreImageMarkService implements MarkService{

    @Override
    public String watermark(File image, String imageFileName,
            String uploadPath, String realUploadPath) {

        String logoFileName = "logo_"+imageFileName;    //定义目标文件输出的名称
        OutputStream os = null;

        try {
            //1 创建图片缓存对象
            Image image2 = ImageIO.read(image);

            int width = image2.getWidth(null);
            int height = image2.getHeight(null);

            BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);

            //2 创建Java绘图工具对象
            Graphics2D g = bufferedImage.createGraphics();

            //3 使用绘图工具对象将原图绘制到缓存图片对象
            g.drawImage(image2, 0, 0, width, height, null);

            //4 使用绘图工具对象将水印(文字/图片)绘制到缓存图片

            String logoPath = realUploadPath + "/" + LOGO;
            File logo = new File(logoPath);

            Image logoImage = ImageIO.read(logo);

            int width1 = logoImage.getWidth(null);
            int height1= logoImage.getHeight(null);

            //透明度的设置
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,ALPHA));

            //旋转图片(30°)
            g.rotate(Math.toRadians(30),bufferedImage.getWidth()/2,bufferedImage.getHeight()/2);

            int x= -width/2;
            int y= -height/2;

            while(x < width*1.5){
                y = -height/2;
                while(y < height*1.5){
                    g.drawImage(logoImage,x,y,null);
                    y+=height1+50;
                }
                x+= width1 + 50;
            }
            g.dispose();

            //创建文件输出流,指向最终的目标文件
            os = new FileOutputStream(realUploadPath+"/"+logoFileName); 

            //5 创建图像文件编码工具类
            JPEGImageEncoder en = JPEGCodec.createJPEGEncoder(os);

            //6 使用图像编码工具类,输出缓存图像到目标文件
            en.encode(bufferedImage);

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(os!=null){
                try {
                    os.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
        return uploadPath+"/"+logoFileName;
    }

}

然后修改WaterMarkAction:

package com.watermark;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

/**
 * 
 * description:控制器
 * @author Byron
 * 
 */
public class WaterMarkAction extends ActionSupport {

    private File[] image;  // 多个图片上传
    private String[] imageFileName;
    private List<PicInfo> picInfo = new ArrayList<PicInfo>();

    private String uploadPath; // 文件上传的相对路径,要在struts.xml文件中配置

    /*
     * 请求处理方法:负责接收图片上传以及水印添加的请求
     */
    public String watermark() throws Exception {

        /*
         * 批量添加图片水印
         */
        String realUploadPath = ServletActionContext.getServletContext()
                .getRealPath(uploadPath);

        UploadService uploadService = new UploadService();

        // 创建水印服务类
        MarkService markService = new MoreImageMarkService();

        // 判断是否为多图片上传
        if (image != null && image.length > 0) {
            for (int i = 0; i < image.length; i++) {
                PicInfo pi = new PicInfo();

                pi.setImageURL(uploadService.uploadImage(image[i], imageFileName[i],
                        uploadPath, realUploadPath));

                // 水印添加操作
                pi.setLogoImageURL(markService.watermark(image[i], imageFileName[i],
                        uploadPath, realUploadPath));
                // 将有水印的图片添加的picInfo数组中
                picInfo.add(pi);
            }
        }
        return SUCCESS;
    }


    public File[] getImage() {
        return image;
    }

    public void setImage(File[] image) {
        this.image = image;
    }

    public String[] getImageFileName() {
        return imageFileName;
    }

    public void setImageFileName(String[] imageFileName) {
        this.imageFileName = imageFileName;
    }

    public String getUploadPath() {
        return uploadPath;
    }

    public void setUploadPath(String uploadPath) {
        this.uploadPath = uploadPath;
    }

    public List<PicInfo> getPicInfo() {
        return picInfo;
    }

    public void setPicInfo(List<PicInfo> picInfo) {
        this.picInfo = picInfo;
    }


}

效果如下:
这里写图片描述

参考项目源码可前往github下载:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值