由于是前后端交互,就先给大家介绍一下这个模块的设计思路。

       首先前台使用uploader让用户选择图片上传并回显(可以参考我的《uploader.js上传与回显》),而我们实现的这个加水印的功能需要在回显前完成,并把水印后的图片存储在某个位置,假设我们先存储在本地磁盘。


思路:简单理解一下这个过程

        1. 后台正确接收到了multipartFile图片对象

        2. 获取一系列路径用于读取和存储,如原图绝对路径,水印标识的存储位置,原图加水印后的存储路径

        3. 通过ImageIO将原图加载成BufferedImage对象

        4. 通过ImageHelper和Graphics在原图某个区域添加水印

        5.返回一个8位RGB颜色分量的图像对象(已添加水印)

        6. ImageIO把这个对象写入到磁盘中


业务代码部分

public Map<String, Object> uploadSYImage(HttpServletRequest request,MultipartFile imageFile, String oldsaveName) {
		//oldsaveName是原图源文件名不带扩展名
		String imgCDNURL = "";
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			//原图绝对路径
			String realPath = request.getSession().getServletContext().getRealPath("/");
			//相对路径,保存结果图
			String resourcePath = "uploadtemp/images/";
			//传入的图片不能为空
			if (imageFile != null) {
				//扩展名
				String suffix = "";
				//媒体类型必须是二进制的,这种类型规定一次只能提交一个文件,且必须是流或字节数组的形式,多用于传图片
				if (imageFile.getContentType().equals("application/octet-stream")) {
					//原图的源文件名
					String name = imageFile.getOriginalFilename();
					if (null != name) {
						//从源文件名中截取扩展名
						Integer num = name.indexOf(".");
						suffix = name.substring(num, name.length());
					}
				}
				//判断上传的图片格式是否合规,这个视情况而定,不需要可以不加,文末有FileUploadUtil的代码可供参考
				if (FileUploadUtil.allowUpload(imageFile.getContentType()) || FileUploadUtil.allowSuffix(suffix)) {
					//给结果图取名
					String fileName = FileUploadUtil.rename(imageFile.getOriginalFilename());
					int end = fileName.lastIndexOf(".");
					//saveName会作为结果图存储路径的一部分
					String saveName = fileName.substring(0, end);
					//创建文件
					File dir = new File(realPath + resourcePath);
					if (!dir.exists()) {
						dir.mkdirs();
					}
					//returnFile为用户上传的原图文件
					File returnFile = new File(dir, oldsaveName + "_src.jpg");
					imageFile.transferTo(returnFile);
					//将原图存入到map中
					map.put("file", returnFile);
					//图片加水印,把未加水印的换成结果图,名称不变
					//获取水印logo图,稍后会把这张水印logo图绘入到原图上
					String syUrl = realPath + "res/images/waterImg.png";
					//把logo图加载成对象
					BufferedImage logoImage = ImageIO.read(new File(syUrl));
					//加载原图
					BufferedImage pressTo = ImageIO.read(new File(returnFile.getPath()));
					//ImageHelper在原图右下角添加水印logo
					BufferedImage targetImg = ImageHelper.pressOnRightBottom(pressTo, logoImage);
					
					//给结果图创建路径
					String srcImagePath = realPath + resourcePath + saveName;
					File file = new File(srcImagePath + "_src.jpg");
					file.createNewFile();
					//根据targetImg的长宽返回一个具有合成整数像素的8位RGB颜色分量的图像,意思就是把原来的targetImg像素调成8位的,方便存储和后期滤镜处理(降低清晰度)
					BufferedImage rgbImage = new BufferedImage(targetImg.getWidth(), targetImg.getHeight(),
							BufferedImage.TYPE_INT_RGB);
					rgbImage.createGraphics().drawImage(targetImg, 0, 0, null, null);

					//生成结果图文件
					ImageIO.write(rgbImage, "jpg", new File(srcImagePath + "_src.jpg"));

					log.info("uploadHeadImage upload to cdn start! ");
					//上传图片
					imgCDNURL = imageUpload(file);
					map.put("waterImg", imgCDNURL);
					log.info("uploadHeadImage upload to cdn end! ");
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return map;
	}


自定义FileUploadUtil工具类,验证用户上传图片的格式是否合规


public class FileUploadUtil {
    public static final List<String> ALLOW_TYPES = Arrays.asList(
            "image/jpg","image/jpeg","image/png","image/gif","image/x-png","image/pjpeg"
    );
    public static final List<String> ALLOW_SUFFIX = Arrays.asList(
    		".jpg",".jpeg",".png",".gif",".x-png",".pjpeg"
    		);
//文件重命名
    public static String rename(String fileName){
        int i = fileName.lastIndexOf(".");
        String str = fileName.substring(i);
        return new Date().getTime()+""+ new Random().nextInt(99999999) +str;
    }
//校验文件类型是否是被允许的
    public static boolean allowUpload(String postfix){
        return ALLOW_TYPES.contains(postfix);
    }
//校验文件后缀是否是被允许的
    public static boolean allowSuffix(String suffix){
    	return ALLOW_SUFFIX.contains(suffix);
    }
}


ImageHelper:通过Graphics类实现在原图上添加水印logo

import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;

public class ImageHelper {
	
	
	/*
	 * 根据尺寸图片居中裁剪
	 */
	 public static void cutCenterImage(String src,String dest,int w,int h) throws IOException{ 
		 Iterator<?> iterator = ImageIO.getImageReadersByFormatName("jpg"); 
         ImageReader reader = (ImageReader)iterator.next(); 
         InputStream in=new FileInputStream(src);
         ImageInputStream iis = ImageIO.createImageInputStream(in); 
         reader.setInput(iis, true); 
         ImageReadParam param = reader.getDefaultReadParam(); 
         int imageIndex = 0; 
         Rectangle rect = new Rectangle((reader.getWidth(imageIndex)-w)/2, (reader.getHeight(imageIndex)-h)/2, w, h);  
         param.setSourceRegion(rect); 
         BufferedImage bi = reader.read(0,param);   
         ImageIO.write(bi, "jpg", new File(dest));           
  
	 }
	 
	/*
	 * 图片裁剪二分之一
	 */
	 public static void cutHalfImage(String src,String dest) throws IOException{ 
		 Iterator<?> iterator = ImageIO.getImageReadersByFormatName("jpg"); //getImageReadersByFormatName("jpg")
         ImageReader reader = (ImageReader)iterator.next(); 
         InputStream in=new FileInputStream(src);
         ImageInputStream iis = ImageIO.createImageInputStream(in); 
         reader.setInput(iis, true); 
         ImageReadParam param = reader.getDefaultReadParam(); 
         int imageIndex = 0; 
         int width = reader.getWidth(imageIndex)/2; 
         int height = reader.getHeight(imageIndex)/2; 
         Rectangle rect = new Rectangle(width/2, height/2, width, height); 
         param.setSourceRegion(rect); 
         BufferedImage bi = reader.read(0,param);   
         ImageIO.write(bi, "jpg", new File(dest));   
	 }
	 
	/*
	 * 图片裁剪
	 */
    public static BufferedImage cutImage(InputStream target,int x,int y,int w,int h) throws IOException{ 
    	   Iterator<ImageReader> iterator = ImageIO.getImageReadersByFormatName("jpg");//getImageReadersByFormatName("jpg")
           ImageReader reader = iterator.next();
           ImageInputStream iis = ImageIO.createImageInputStream(target); 
           reader.setInput(iis, true); 
           ImageReadParam param = reader.getDefaultReadParam(); 
           Rectangle rect = new Rectangle(x,y,w,h);  
           param.setSourceRegion(rect);
           BufferedImage bi = reader.read(0,param);
           return bi;
    }

    /*
     * 图片缩放320*320 240*192 560*400 120*96
     */
    public static void zoomImage(String src,String dest,int w,int h) throws Exception {
		double wr=0,hr=0;
		File srcFile = new File(src);
		File destFile = new File(dest);
		BufferedImage bufImg = ImageIO.read(srcFile);
		Image itemp = bufImg.getScaledInstance(w, h, Image.SCALE_SMOOTH);
		wr=w*1.0/bufImg.getWidth();
		hr=h*1.0/bufImg.getHeight();
		AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(wr, hr), null);
		itemp = ato.filter(bufImg, null);
		try {
			ImageIO.write((BufferedImage) itemp,dest.substring(dest.lastIndexOf(".")+1), destFile);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
    
    /*
     * 图片缩放
     */
    public static BufferedImage zoomImage(BufferedImage bufImg,int w,int h){
		double wr=0,hr=0;
		bufImg.getScaledInstance(w, h, Image.SCALE_SMOOTH);
		wr=w*1.0/bufImg.getWidth();
		hr=h*1.0/bufImg.getHeight();
		AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(wr, hr), null);
		bufImg = ato.filter(bufImg, null);
		return bufImg;
	}
	public static void pressImage(String pressImg1,String logo, String targetImg,
            int x, int y) {
        try {
        	File file1 = new File(pressImg1);
//        	BufferedImage image = pressImage(ImageIO.read(file1),ImageIO.read(new File(logo)),x,y);
        	BufferedImage image = pressOnRightBottom(ImageIO.read(file1),ImageIO.read(new File(logo)));
			ImageIO.write(image,file1.getName().replaceAll("^[^\\.]+\\.", "") ,new File(targetImg)) ;//ImageIO.write(image, "jpg",new File(targetImg)) ;
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
	/**
	 * 把图片印刷到图片上
	 * 
	 * @param targetImg
	 *            -- 水印文件
	 * @param logoImg
	 *            -- 目标文件
	 * @param x
	 *            --x坐标
	 * @param y
	 *            --y坐标
	 * @return 
	 * @return
	 */
    public final static BufferedImage pressImage(BufferedImage pressImg1,BufferedImage pressImg2,
            int x, int y) {
        try {
            //目标文件
            int wideth = pressImg1.getWidth();
            int height = pressImg1.getHeight();
            
            Graphics g =pressImg1.getGraphics();
            if(g==null){
            	pressImg1.createGraphics();
            }else{
            	g.drawImage(pressImg1, 0, 0, wideth, height, null);
            }
 
            //水印文件
            int wideth_biao = pressImg2.getWidth(null);//获得水印图真实宽度,无图返回-1
            int height_biao = pressImg2.getHeight(null);//获得水印图真实高度,无图返回-1
            
            x=x>0?x:(x+wideth-wideth_biao);
            y=y>0?y:(y+height-height_biao);
            
            g.drawImage(pressImg2, x,  y, wideth_biao, height_biao, null);
            //水印文件结束
            g.dispose();
        } catch (Exception e) {
            e.printStackTrace();
        }
		return pressImg1;
    }
    
    public final static BufferedImage pressOnRightBottom(BufferedImage pressTo,BufferedImage logoImage){
    	
    	//目标文件
        int wideth = pressTo.getWidth();
        int height = pressTo.getHeight();

        //水印文件
        int wideth_biao = logoImage.getWidth();
        int height_biao = logoImage.getHeight();
        
    	return pressImage(pressTo,logoImage,(int)((wideth-wideth_biao)*0.95),(int)((height-height_biao)*0.95));
    }
    
    public static void main(String[] args) throws Exception {

		 //覆盖到目标上
		 pressImage("d:/0001.jpg","d:/0002.jpg","d:/0003.jpg",
				 	328,82);

	}
    public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage)image;
         }
     
        // This code ensures that all the pixels in the image are loaded
         image = new ImageIcon(image).getImage();
     
        // Determine if the image has transparent pixels; for this method's
        // implementation, see e661 Determining If an Image Has Transparent Pixels
        //boolean hasAlpha = hasAlpha(image);
     
        // Create a buffered image with a format that's compatible with the screen
         BufferedImage bimage = null;
         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {

            int transparency = Transparency.OPAQUE;

     
             GraphicsDevice gs = ge.getDefaultScreenDevice();
             GraphicsConfiguration gc = gs.getDefaultConfiguration();
             bimage = gc.createCompatibleImage(
                 image.getWidth(null), image.getHeight(null), transparency);
         } catch (HeadlessException e) {
         }
     
        if (bimage == null) {

            int type = BufferedImage.TYPE_INT_RGB;

             bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
         }
     

         Graphics g = bimage.createGraphics();

         g.drawImage(image, 0, 0, null);
         g.dispose();
     
        return bimage;
     }     
    
}