java 批量为图片添加图标水印和文字水印

    技术2023-12-04  104

    需求,给指定目录下面以.jpg结尾的文件,添加图标水印和文字水印

    文章目录

    一、基础版本二、企业升级内部版本三、依赖

    一、基础版本
    package com.gblfy.util; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; /** * java为图片添加图标水印和文字水印 * * @author gblfy * @version 1.0 * @explain 文字水印、图片水印 * @creationTime 2020/07/01 */ public class WaterMarkUtil { //水印图片路径 private static String WATER_MARKIMG_PATH = "D:" + File.separator + "1" + File.separator + "iconPath" + File.separator + "22.png"; //当前登陆操作员 采用全局变量 private static String operator; static { operator = "zhangsan"; } /** * 将指定图标(png图片)印刷到指定图片上 * <p> * 1.图标图片格式: * png * 2.坐标轴: * x轴决定左右位置 * y轴决定上下位置 * 3.坐标位置 * x值越大距离右越近,反之,x值越小距离左越近; * y值越大距离越往下,反之,y值越小距离越往上 * </p> * * @param pressImg 水印图片 * @param targetImg 源图片路径的目标文件 * @param x x坐标 * @param y y坐标 */ public final static void pressImage(String pressImg, String targetImg, int x, int y) { try { // 目标文件 File imageFile = new File(targetImg); Image src = ImageIO.read(imageFile); int wideth = src.getWidth(null); int height = src.getHeight(null); BufferedImage image = new BufferedImage(wideth, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.createGraphics(); g.drawImage(src, 0, 0, wideth, height, null); // 水印文件 File waterMarkImage = new File(pressImg); Image markImage = ImageIO.read(waterMarkImage); int weightMarkImage = markImage.getWidth(null); int heightMarkImage = markImage.getHeight(null); g.drawImage(markImage, x, y, weightMarkImage, heightMarkImage, null); // 水印结束 g.dispose(); FileOutputStream out = new FileOutputStream(targetImg); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(image); out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 打印文字水印图片 * <p> * 1.图标图片格式:png * 2.坐标轴: * x轴决定左右位置 * y轴决定上下位置 * 3.坐标位置 * x值越大距离右越近,反之,x值越小距离左越近; * y值越大距离越往下,反之,y值越小距离越往上 * </p> * * @param pressText 文字 * @param targetImg 目标图片 * @param fontName 字体名 * @param fontStyle 字体样式 * @param color 字体颜色 * @param fontSize 字体大小 * @param x 偏移量 * @param y 偏移量 */ public static void pressText(String pressText, String targetImg, String fontName, int fontStyle, Color color, int fontSize, int x, int y) { try { File imageFile = new File(targetImg); Image src = ImageIO.read(imageFile); int weidth = src.getWidth(null); int height = src.getHeight(null); BufferedImage image = new BufferedImage(weidth, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.createGraphics(); g.drawImage(src, 0, 0, weidth, height, null); g.setColor(color); g.setFont(new Font(fontName, fontStyle, fontSize)); g.drawString(pressText, x, y); g.dispose(); FileOutputStream out = new FileOutputStream(targetImg); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(image); out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 添加图标水印+文字水印 * * @param srcImgPath 需要处理的源图片路径 */ public static void iconAndTextWatermark(String srcImgPath) { // 1.添加图标水印 pressImage(WATER_MARKIMG_PATH, srcImgPath, 100, 500); System.out.println("--------------------添加图标水印 执行完成!--------------------"); String date = TimeUtil.getCurrentDate().toString(); String time = TimeUtil.getCurrentTime().toString(); // 2.添加文字水印 参数根据真实保单图片进行调整 pressText(operator, srcImgPath, "宋体", 0, Color.BLUE, 30, 540, 600); pressText(date, srcImgPath, "宋体", 0, Color.BLUE, 30, 540, 650); pressText(time, srcImgPath, "宋体", 0, Color.BLUE, 30, 540, 700); System.out.println("--------------------添加文字水印 执行完成!--------------------"); } /** * 对.jpg图片文件进行筛选 * <p> * 1.使用递归遍历目录下面的.jpg结尾图片文件 * 2.对筛选通过的文件调用水印文件处理 * </p> * * @param path * @return */ public static void getFileListNotReturn(String path) { File dir = new File(path); // 该文件目录下文件全部放入数组 File[] files = dir.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { String fileName = files[i].getName(); // 判断是文件还是文件夹 if (files[i].isDirectory()) { // 获取文件绝对路径 getFileListNotReturn(files[i].getAbsolutePath()); // 判断文件名是否以.jpg结尾 } else if (fileName.endsWith(".jpg")) { String strFileName = files[i].getAbsolutePath(); System.out.println("文件名:" + strFileName); //对符合条件的文件统一水印处理 iconAndTextWatermark(strFileName); } else { continue; } } } } //--------------------------------------------单元测试-------------------------------------------- public static void main(String[] args) { String srcImgPath = "D:\\1\\srcImgPath\\"; System.out.println("图片路径:" + srcImgPath); getFileListNotReturn(srcImgPath); } /** * 特别说明: * 如上面的效果展示的那样,要想将水印打印到图片指定位置,进行动态设置的话,需要:</p> *  第一,原图片大小;</p> *  第二,水印大小;</p> *  满足这两个条件才能将水印打印到图片的指定位置,也就是可以进行动态位移。&nbsp;</p> *  其中,图片水印可以进行动态设置,而文字水印则实现不了,因为我们无法获取文字水印的大小。</p> *  调试水印输出位置也是个细致活呀。</p> * 另外,水印的偏移量一般情况下均为正值,图片左上角为起点0,0,不同于数学上的Y轴,向下偏移用正值表示。 */ }
    二、企业升级内部版本

    根据图片的宽度(分辨率)和高度(分辨率),动态改变图标水印的宽度(分辨率)和高度(分辨率),适配所有的图片比例

    实现原理: 1.图标水印 找到图片宽度(分辨率)和高度(分辨率)和图标水印的宽度(分辨率)和高度(分辨率)的比例关系即可 2.文字水印同理: 找到文字水印宽度(分辨率)和高度(分辨率)和图标水印的宽度(分辨率)和高度(分辨率)的比例关系即可

    /** * 单证添加图标水印+文字水印 * <p> * 1.使用递归遍历目录下面的单证图片文件 * 2.对文件的不同元素,做不同处理 * 1>如果是文件夹就地柜处理 * 2>如果是文件就就进入处理范围 * 3.获取单证图片的宽度和高度 * 4.推算出新华水印图标的宽度和高度 * 5.调用水印处理和新方法 * </p> * * @param srcImgPath */ public void getImageParamsAndDeal(String srcImgPath) { File dir = new File(srcImgPath); // 该文件目录下文件全部放入数组 File[] files = dir.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { //文件的绝对路径 String absolutePath = files[i].getAbsolutePath(); // 判断是文件还是文件夹 if (files[i].isDirectory()) { // 文件元素是文件夹递归调用自己 getImageParamsAndDeal(absolutePath); } else { //对所有的单证图片进行统一处理 String strFileName = absolutePath; System.out.println("文件名:" + strFileName); // 获取每张图片的高度 和 宽度 File file = new File(strFileName); int[] imgWidth = getImgWidth(file); System.out.println("图片的宽度:" + imgWidth[0]); System.out.println("图片的高度:" + imgWidth[1]); //单证的宽度和高度 int picWidth = imgWidth[0]; int picHeight = imgWidth[1]; //新华水印图标的宽度和高度初始化 int picX = 0; int picY = 0; //新华水印图标的宽度和高度 double width = (imgWidth[0] - (picWidth * 0.71)) / 2; double height = (imgWidth[1] - (picHeight * 0.18)) / 2; //新华水印图标的宽度和高度 取整特殊处理 picX = (int) Math.floor(width); picY = (int) Math.floor(height); System.out.println("水印图标x:" + picX); System.out.println("水印图标y:" + picY); // 对符合条件的文件统一水印处理 iconAndTextWatermark(strFileName, picX, picY, picWidth, picHeight); } } } } /** * 获取图片宽度和高度 * * @param file 图片文件 * @return 宽度 */ public static int[] getImgWidth(File file) { InputStream is = null; BufferedImage src = null; int result[] = {0, 0}; try { is = new FileInputStream(file); src = javax.imageio.ImageIO.read(is); // 得到源图宽 result[0] = src.getWidth(null); // 得到源图高 result[1] = src.getHeight(null); is.close(); } catch (Exception e) { e.printStackTrace(); } return result; } /** * 添加图标水印+文字水印 * <p> * 1.新华图标水印和单证图片的比例关系 * 2.操作员文字水印和新华图标水印的比例关系 * 3.日期文字水印和新华图标水印的比例关系 * 4.时间文字水印和新华图标水印的比例关系 * </p> * * @param srcImgPath 需要处理的源图片路径 */ public static void iconAndTextWatermark(String srcImgPath, int picX, int picY, int picWidth, int picHeight) { File fromFile = new File(nclWaterFilePath); File toFile = new File(nclWaterTempFilePath); //判断生成水印图标的绝对路径路是否存在不存在就创建 if (!toFile.exists()) { toFile.mkdirs(); } // ImageUtil.resizePng(fromFile, toFile, (int) (1244 * 0.71), (int)(1684 * 0.18), false); resizePng(fromFile, toFile, (int) (picWidth * 0.71), (int) (picHeight * 0.18), false); // 1.添加图标水印 pressImage(nclWaterTempFilePath, srcImgPath, picX, picY); System.out.println("--------------------添加图标水印 执行完成!--------------------"); // 2.添加文字水印 参数根据真实保单图片进行调整 pressText(operator, srcImgPath, "宋体", 0, Color.BLUE, (int) (picHeight * 0.032), picX + (int) (picWidth * 0.57), picY + (int) (picHeight * 0.20)); pressText(PubFun.getCurrentDate(), srcImgPath, "宋体", 0, Color.BLUE, (int) (picHeight * 0.032), picX + (int) (picWidth * 0.57), picY + (int) (picHeight * 0.24)); pressText(PubFun.getCurrentTime(), srcImgPath, "宋体", 0, Color.BLUE, (int) (picHeight * 0.032), picX + (int) (picWidth * 0.57), picY + (int) (picHeight * 0.28)); // System.out.println("--------------------添加文字水印 执行完成!--------------------"); } /** * 将指定图标(png图片)印刷到指定图片上 * <p> * 1.图标图片格式: * png * 2.坐标轴: * x轴决定左右位置 * y轴决定上下位置 * 3.坐标位置 * x值越大距离右越近,反之,x值越小距离左越近; * y值越大距离越往下,反之,y值越小距离越往上 * </p> * * @param pressImg 水印图片 * @param targetImg 源图片路径的目标文件 * @param x x坐标 * @param y y坐标 */ public final static void pressImage(String pressImg, String targetImg, int x, int y) { try { // 目标文件 File imageFile = new File(targetImg); Image src = ImageIO.read(imageFile); int wideth = src.getWidth(null); int height = src.getHeight(null); BufferedImage image = new BufferedImage(wideth, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.createGraphics(); g.drawImage(src, 0, 0, wideth, height, null); // 水印文件 File waterMarkImage = new File(pressImg); Image markImage = ImageIO.read(waterMarkImage); int weightMarkImage = markImage.getWidth(null); int heightMarkImage = markImage.getHeight(null); g.drawImage(markImage, x, y, weightMarkImage, heightMarkImage, null); // 水印结束 g.dispose(); FileOutputStream out = new FileOutputStream(targetImg); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(image); out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 打印文字水印图片 * <p> * 1.图标图片格式: * png * 2.坐标轴: * x轴决定左右位置 * y轴决定上下位置 * 3.坐标位置 * x值越大距离右越近,反之,x值越小距离左越近; * y值越大距离越往下,反之,y值越小距离越往上 * </p> * * @param pressText 文字 * @param targetImg 目标图片 * @param fontName 字体名 * @param fontStyle 字体样式 * @param color 字体颜色 * @param fontSize 字体大小 * @param x 偏移量 * @param y 偏移量 */ public static void pressText(String pressText, String targetImg, String fontName, int fontStyle, Color color, int fontSize, int x, int y) { try { File imageFile = new File(targetImg); Image src = ImageIO.read(imageFile); int weidth = src.getWidth(null); int height = src.getHeight(null); BufferedImage image = new BufferedImage(weidth, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.createGraphics(); g.drawImage(src, 0, 0, weidth, height, null); g.setColor(color); g.setFont(new Font(fontName, fontStyle, fontSize)); g.drawString(pressText, x, y); g.dispose(); FileOutputStream out = new FileOutputStream(targetImg); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(image); out.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 任意压缩PNG图片 * <p> * 1.用于修改PNG水印图标的宽度(分辨率)和宽度(分辨率) * 2.动态适配单证图片宽度(分辨率)和宽度(分辨率) * * @param fromFile 源文件 * @param toFile 裁剪后的文件 * @param outputWidth 裁剪宽度 * @param outputHeight 裁剪高度 * @param proportion 是否是等比缩放 */ public static void resizePng(File fromFile, File toFile, int outputWidth, int outputHeight, boolean proportion) { try { BufferedImage bi2 = ImageIO.read(fromFile); int newWidth; int newHeight; // 判断是否是等比缩放 if (proportion) { // 为等比缩放计算输出的图片宽度及高度 double rate1 = ((double) bi2.getWidth(null)) / (double) outputWidth + 0.1; double rate2 = ((double) bi2.getHeight(null)) / (double) outputHeight + 0.1; // 根据缩放比率大的进行缩放控制 double rate = rate1 < rate2 ? rate1 : rate2; newWidth = (int) (((double) bi2.getWidth(null)) / rate); newHeight = (int) (((double) bi2.getHeight(null)) / rate); } else { // 输出的图片宽度 newWidth = outputWidth; // 输出的图片高度 newHeight = outputHeight; } BufferedImage to = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = to.createGraphics(); to = g2d.getDeviceConfiguration().createCompatibleImage(newWidth, newHeight, Transparency.TRANSLUCENT); g2d.dispose(); g2d = to.createGraphics(); @SuppressWarnings("static-access") Image from = bi2.getScaledInstance(newWidth, newHeight, bi2.SCALE_AREA_AVERAGING); g2d.drawImage(from, 0, 0, null); g2d.dispose(); ImageIO.write(to, "png", toFile); } catch (Exception e) { e.printStackTrace(); } }

    测试 只需要传递需要添加水印的目录即可

    public static void main(String[] args) { Bl bl=new Bl() //1.批量添加水印 bl.getImageParamsAndDeal(srcImgPath); }
    三、依赖
    jimi-1.0.jar jai_imageio.jar jai_core.jar jai_codec-1.1.3.jar
    Processed: 0.009, SQL: 9