ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

图片处理工具类,添加水印,图片缩略图,合法性校验

2022-05-27 15:00:25  阅读:127  来源: 互联网

标签:return file 缩略图 校验 param File import new 图片


本文完全借鉴https://blog.csdn.net/qq_22174779/article/details/88199898

package xyz.guqing.imageutil;

import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.apache.commons.lang3.StringUtils;

import commons.CommonUtils;
/**
 * @ClassName:  ImageUtils   
 * @Description: 图片校验合法性工具类 
 * @author: guqing
 * @date:   2018年12月31日 下午4:05:37   
 *
 */
public class ImageUtils {
	
	/**
	 * 允许上传的图片后缀名
	 */
	private static final String[] IMAGE_TYPE = new String[]{".bmp", ".jpg", ".jpeg", ".gif", ".png"};
	

	/**
     * 按指定高度 等比例缩放图片
     * @param imageFile
     * @param destinationPath
     * @param newWidth 新图的宽度,宽度不建议小于400
     * @throws IOException
     */
    public static void zoomImageScale(File imageFile, String destinationPath, int newWidth) throws IOException {
         if(!imageFile.canRead())
             return;
        BufferedImage bufferedImage = ImageIO.read(imageFile);
        if (null == bufferedImage) 
            return;
        
        int originalWidth = bufferedImage.getWidth();
        int originalHeight = bufferedImage.getHeight();
        double scale = (double)originalWidth / (double)newWidth;    // 缩放的比例
        
        int newHeight =  (int)(originalHeight / scale);

        zoomImageUtils(imageFile, destinationPath, bufferedImage, newWidth, newHeight);
    }
    
	
	/**
     * 在原图片上添加水印
     * @param sourceImage 目标图片路径,如:F:/upload/testImageUtil.jpg
     * @param waterImg 水印图片路径,如:F:/upload/testImageUtil.jpg
     * @param x 水印图片距离目标图片左侧的偏移量,如果x<0, 则在正中间
     * @param y 水印图片距离目标图片上侧的偏移量,如果y<0, 则在正中间
     * @param alpha 透明度区间[0,1], 0为完全透明,1为完全不透明
     * @throws IOException
     */
    public static void addWaterMark(File sourceImage, File waterImg, int x, int y, float alpha) throws IOException {
        // 加载目标图片
        String ext = sourceImage.getAbsolutePath().substring(sourceImage.getAbsolutePath().lastIndexOf(".") + 1);
        Image image = ImageIO.read(sourceImage);
        int width = image.getWidth(null);
        int height = image.getHeight(null);
 
        // 将目标图片加载到内存。
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(image, 0, 0, width, height, null);
 
        // 加载水印图片。
        Image waterImage = ImageIO.read(waterImg);
        int width_1 = waterImage.getWidth(null);
        int height_1 = waterImage.getHeight(null);
        // 设置水印图片的透明度。
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
 
        // 设置水印图片的位置。
        int widthDiff = width - width_1;
        int heightDiff = height - height_1;
        if (x < 0) {
            x = widthDiff / 2;
        } else if (x > widthDiff) {
            x = widthDiff;
        }
        if (y < 0) {
            y = heightDiff / 2;
        } else if (y > heightDiff) {
            y = heightDiff;
        }
 
        // 将水印图片“画”在原有的图片的制定位置。
        g.drawImage(waterImage, x, y, width_1, height_1, null);
        // 关闭画笔。
        g.dispose();
 
        // 保存目标图片。
        ImageIO.write(bufferedImage, ext, sourceImage);
    }
    
    
    /**
	 * @Description: 将文件经hash打散后保存到picSourcePath路径
	 * @param: @param sourceFile 源文件流对象
	 * @param: @param destinationPath 目的存储路径,不需要带文件名,如:F:/upload/
	 * @param: @return
	 * @param: @throws IOException      
	 * @return: File      
	 * @throws
	 */
	public static File writeFilewWithHashBreak (File sourceFile,String destinationPathWithoutName) throws IOException {
		
		//拿到图片原始文件名称
		if(sourceFile == null){
			throw new RuntimeException("the file is null");
		}
		String originalFilename = sourceFile.getName();
		
		if(originalFilename == null || originalFilename.length()==0){
			return null;
		}
		//新的图片文件名称:uuid+原图片名称,直接使用uuid+后缀,有中文前端会乱码
		String newFileName = CommonUtils.uuid() + originalFilename.substring(originalFilename.lastIndexOf("."));//originalFilename;
		
		//使用hash打散目录
		String savePath = makeHashPath(originalFilename, destinationPathWithoutName);
		
		//新图片,hash打散的存储路径+文件名称
		File file = new File(savePath + File.separator + newFileName);
		
		//将内存中的数据写入磁盘
		transferTo(sourceFile,file);
		
		//上传成功返回文件名
		return file;
	}

	/**
	 * @Description: 校验上传的图片文件是否合法   
	 * @param: @param filePathWithName 将上传文件存储到磁盘后的绝对路径,如:F:/upload/test.jpg
	 * @param: @return 如果校验通过返回true,否则返回false
	 * @param: @throws Exception      
	 * @return: boolean
	 * @throws
	 */
	public static boolean isLegal(File filePathWithName) throws Exception{
		//先先查文件后缀名是否合法
		boolean checkSuffixFlag = checkSuffix(filePathWithName.getAbsolutePath());
		if(!checkSuffixFlag){
			//如果不合法删除本地文件
			deleteFile(filePathWithName.getAbsolutePath());
			return false;
		}
		
		//检查,参数:File imageFile
		boolean isImageFlag = isImageViaWithAndHeight(filePathWithName);
		if(!isImageFlag){
			//如果不合法删除本地文件
			deleteFile(filePathWithName.getAbsolutePath());
			return false;
		}
		
		return true;
	}
	

	/**
	 * @Description: 将文件保存到磁盘   
	 * @param: @param sourcefile 源文件,如:F:/upload/test1.jpg
	 * @param: @param destPath   目的文件地址,如:F:/upload/test2.jpg
	 * @return: void      
	 * @throws
	 */
	public static void transferTo(File sourcefile, File destPath) {
		BufferedInputStream bufferedInputStream = null;
		BufferedOutputStream bufferedOutputStream = null;
		try {
			bufferedInputStream = new BufferedInputStream(new FileInputStream(sourcefile));
			bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(destPath));
			
			byte[] buff = new byte[1024];
			int i = 0;
			while ((i = bufferedInputStream.read(buff)) != -1) {
				bufferedOutputStream.write(buff, 0, i);
				bufferedOutputStream.flush();//手动刷新该流的缓冲,立即将他们写入预期目标
	        }
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
            try {
                if (bufferedInputStream != null) {
                	bufferedInputStream.close();
                }
                if (bufferedOutputStream != null) {
                	bufferedOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
	}
	

    /**
     * @Description: 根据文件绝对路径删除文件   
     * @param: @param absolutePath 文件的绝对路径
     * @param: @return  无返回值
     * @throws
     */
    private static void deleteFile(String absolutePath) {
        File file = new File(absolutePath);
        // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
        if(file.exists() && file.isFile()) {
        	if (!file.delete()) {
        		throw new RuntimeException("文件删除失败,路径:"+absolutePath);
            }
        	
        }else {
        	throw new RuntimeException("文件不存在,路径:"+absolutePath);
        }
    }
	
	/**
	 * @Description: 为防止一个目录下面出现太多文件,要使用hash算法打散存储   
	 * @param: @param filename 文件名,要根据文件名生成存储目录
	 * @param: @param savePath  文件存储路径
	 * @param: @return  新的存储目录
	 * @return: String      
	 * @throws
	 */
	private static String makeHashPath(String filename, String savePath) {
		// 得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
		int hashcode = filename.hashCode();
		int dir1 = hashcode & 0xf; // 0--15
		int dir2 = (hashcode & 0xf0) >> 4; // 0-15
		// 构造新的保存目录,如upload\2\3,upload\3\5,使用当前系统的分割符,这样在不同的系统中就不会出问题
		String dir = savePath + File.separator + dir1 + File.separator + dir2;

		// File既可以代表文件也可以代表目录
		File file = new File(dir);
		
		// 如果目录不存在
		if (!file.exists()) {
			// 创建目录
			file.mkdirs();
		}
		return dir;
	}
	
	
	/**
	 * @Description: 校验文件的后缀名是否合法   
	 * @param: @param filename 文件名
	 * @param: @return  如果上传的文件名以IMAGE_TYPE结尾则返回true,否则返回false
	 * @return: boolean      
	 * @throws
	 */
	private static boolean checkSuffix(String filename){
		for(String type : IMAGE_TYPE) {
			if(StringUtils.endsWithIgnoreCase(filename, type)) {//忽略大小写
				//如果上传的文件名以IMAGE_TYPE结尾则返回true
				return true;
			}
		}
		//否则返回false
		return false;
	}
	
	/**
     * 通过读取文件并获取其width及height的方式
     * 来判断判断当前文件是否图片,这是一种非常简单的方式。
     * @param imageFile
     * @return 返回true则通过校验,否则不通过
     */
    private static boolean isImageViaWithAndHeight(File imageFile) {
        if (!imageFile.exists()) {
            return false;
        }
        Image img = null;
        try {
            img = ImageIO.read(imageFile);
            if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) {
                return false;
            }
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            img = null;
        }
    }
	
	/**
	 * @Description: 等比例缩放图片工具类   
	 * @param: @param imageFile 源
	 * @param: @param newPath 目的
	 * @param: @param bufferedImage 图片缓冲流
	 * @param: @param width 图片宽
	 * @param: @param height 图片的高
	 * @param: @throws IOException      
	 * @return: void      
	 * @throws
	 */
    private static void zoomImageUtils(File imageFile, String newPath, BufferedImage bufferedImage, int width, int height)
            throws IOException{
        
         String suffix = StringUtils.substringAfterLast(imageFile.getName(), ".");
        
         // 处理 png 背景变黑的问题
        if(suffix != null && (suffix.trim().toLowerCase().endsWith("png") || suffix.trim().toLowerCase().endsWith("gif"))){
            BufferedImage to= new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
            Graphics2D g2d = to.createGraphics(); 
            to = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT); 
            g2d.dispose(); 
            
            g2d = to.createGraphics(); 
            Image from = bufferedImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING); 
            g2d.drawImage(from, 0, 0, null);
            g2d.dispose(); 
            
            ImageIO.write(to, suffix, new File(newPath));
        }else{
            BufferedImage newImage = new BufferedImage(width, height, bufferedImage.getType());
            Graphics g = newImage.getGraphics();
            g.drawImage(bufferedImage, 0, 0, width, height, null);
            g.dispose();
            ImageIO.write(newImage, suffix, new File(newPath));
        }
    }
}

使用示例:

public class TestImageUtils {
	@Test
	public void test1() throws Exception{
		//File file = new File("F:/upload/testImageUtil.jpg");
		File file = new File("F:/upload/test3.jpg");
		File file2 = new File("F:/upload/无标题.png");
		
		//校验图片合法性,如果不合法会删除本地文件
		boolean isLegal = ImageUtils.isLegal(file);
		System.out.println(isLegal);
		
		//给图片添加水印,-1,-1表示水印居中对齐,0表示水印完全不透明,1表示完全透明
		//ImageUtils.addWaterMark(file, file2, -1, -1, 0.5f);
		
		//等比例缩放图片,实现图片缩略图,宽度不建议小于400
		ImageUtils.zoomImageScale(file, "F:/upload/test.jpg", 480);
		
		//将文件写到磁盘
		ImageUtils.transferTo(file, new File("F:/upload/test.jpg"));
		
		//将文件流经hash打散后写到磁盘
		ImageUtils.writeFilewWithHashBreak(file, "F:/upload/");
	}
}

工具类依赖:

commons-lang3-3.7.jar
CommonUtils.jar

标签:return,file,缩略图,校验,param,File,import,new,图片
来源: https://www.cnblogs.com/whtjyt/p/16317671.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有