成都高端网站建设公司哪家好,大连在哪个网站做网上核名,腾讯企点怎么用,怎么使用wordpress里的主题我的社交能力还不如5岁儿童和狗。 文章目录前言一、主要工具类总结前言
之前写过一些简单的图片压缩和图片加水印#xff1a;JAVA实现图片质量压缩和加水印
本次主要是针对图片加水印进行一个升级#xff0c;图片水印自定义#xff0c;自适应大小。
来#xff0c;先看几… 我的社交能力还不如5岁儿童和狗。 文章目录前言一、主要工具类总结前言
之前写过一些简单的图片压缩和图片加水印JAVA实现图片质量压缩和加水印
本次主要是针对图片加水印进行一个升级图片水印自定义自适应大小。
来先看几张不同分辨率的图片加过水印的效果
分辨率1702 x 1276 分辨率4000 x 3000 分辨率1080 x 1440 其实大家看右下角csdn自动给我图片加的水印就能发现4000*3000的图片几乎都看不到右下角的水印说明他这个水印不是自适应的。但是我左下角加的三张图片都是这么大根据图片自动变化大小。 提示以下是本篇文章正文内容下面案例可供参考
一、主要工具类
其中主要是进行了坐标点的计算通过拼接计算来确定各个水印的坐标点从而进行绘制。
其中进行了一部分封装 /*** 添加图片文字水印此方法不在考虑文字过长需要换行等情况** param targetImg 原图片路径需要是本地路径如是网络url需要单独更改* param x 水印x轴坐标* param y 水印y轴坐标* param fontSize 水印文字大小 英镑会根据图片分辨率自动放大和缩小只需要指定标准350像素的文字标准值即可* param c 水印文字颜色 例如Color.WHITE* param fontName 水印文字字体 例如宋体微软雅黑* param fontStyle 水印文字字体风格例如Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.* param alpha 水印文字透明度例如 1.0F,范围 0-1F* param text 水印文字*/public static void pressText(String targetImg, int x, int y, int fontSize, Color c, String fontName, int fontStyle, float alpha, String text) {try {// 读取原图片BufferedImage src ImageIO.read(new File(targetImg));// 获取原图的宽和高int width src.getWidth(null);int height src.getHeight(null);// 动态设置字体大小fontSize width height ? width / 350 * fontSize : height / 350 * fontSize;// 创建空图片指定宽高BufferedImage image new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 准备绘制图片Graphics2D g image.createGraphics();// 将原图绘制到此空图片上左上角为坐标起点0,0宽和高为原图大小g.drawImage(src, 0, 0, width, height, null);// 设置水印字体颜色.g.setColor(c);// 设置水印字体,Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.g.setFont(new Font(fontName, fontStyle, fontSize));// 透明度g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));/* 消除java.awt.Font字体的锯齿 */g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_ON);// 添加文字水印g.drawString(text, x, y);// 输出图像g.dispose();File f new File(targetImg);// 将加过水印的图片保存到指定文件ImageIO.write(image, targetImg.substring(targetImg.lastIndexOf(.) 1), f);} catch (Exception e) {log.error(水印添加失败{}, e.getMessage());}}中间还有一部分的坐标点计算感觉写的有点乱了没有梳理好仅供参考。
下面是整个工具类的代码
package com.example.demo.util;import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Week;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Date;/*** author GMaya* create 2023/2/22 9:44* Description 类描述: 图片相关的工具类*/
Slf4j
public class ImageUtils {/*** 图片加水印** param json 相关设置* param targetImg 要加水印的图片路径* param staticUrl 静态地址*/public static void pressTexts(JSONObject json, String targetImg, String staticUrl) {try {long l System.currentTimeMillis();// 读取原图片获取宽度和高度 TODO 使用BufferedImage中没有exif信息导致有exif的图片宽和高会读取错误需要进行修正。目前本地图片修正暂时没有处理。线上图片来源为阿里oss在链接后拼接自动修正参数即可?x-oss-processimage/auto-orient,1
// String uuu https://xxx-dev.oss-cn-shanghai.aliyuncs.com/upload/123123/aa/20230223/b811b496cff29f02f0fa5a994c66867e.jpg;
// String uuu https://xxx-dev.oss-cn-shanghai.aliyuncs.com/upload/123123/aa/20230223/b811b496cff29f02f0fa5a994c66867e.jpg?x-oss-processimage/auto-orient,1;
// URL url new URL(uuu);
// BufferedImage src ImgUtil.read(url);BufferedImage src ImgUtil.read(targetImg);int width src.getWidth(null);int height src.getHeight(null);log.info(原图宽{}高{},width,height);// 动态设置字体大小 , 以350像素9的基数大小设置int fontSize width height ? width / 350 * 9 : height / 350 * 9;BufferedImage image new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics2D g image.createGraphics();// 将原图绘制g.drawImage(src, 0, 0, width, height, null);// 设置水印字体颜色.g.setColor(Color.WHITE);// 设置水印字体,Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.g.setFont(new Font(微软雅黑, Font.PLAIN, fontSize));// 透明度
// g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.9f));// 消除java.awt.Font字体的锯齿g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_ON);// 比例int rat width height ? width / 350 : height / 350;BufferedImage readAddress ImgUtil.read(staticUrl address.png);BufferedImage readUserName ImgUtil.read(staticUrl userName.png);BufferedImage readCompanyName ImgUtil.read(staticUrl companyName.png);BufferedImage readFloor ImgUtil.read(staticUrl floor.png);int imageWidth rat * 6;int imageHeight rat * 7;// 计算各个坐标点int xx1 0; // 姓名图标int yy1 0; // 姓名图标int xx2 0; // 姓名int yy2 0; // 姓名int xx3 0; // 公司图标int yy3 0; // 公司图标int xx4 0; // 公司int yy4 0; // 公司int xx5 0; // 地址图标int yy5 0; // 地址图标int xx6 0; // 地址int yy6 0; // 地址int xx7 0; // 左侧竖线int yy7 0; // 左侧竖线int xx8 0; // 拍照标签int yy8 0; // 拍照标签int xx9 0; // logo图标int yy9 0; // logo图标int xx10 32; // 年月日坐标int yy10 0; // 年月日坐标int xx11 32; // 时分秒坐标int yy11 0; // 时分秒坐标int w12 0; // 底板宽 底板坐标点无需计算但是底板的宽高需要计算int h12 0; // 底板高int sd 0; // 标准差// 公共坐标计算点 xx为图标xxx为文字int xx 0;int yy 0;int xxx 0;int yyy 0;// 提前计算出各个坐标点for (int i 0; i 7; i) {if (i 0) {// 用户名称String userNameIsShow json.getStr(userNameIsShow);if (0.equals(userNameIsShow)) {// x轴默认距离左边16*比例xx1 10 * rat;yy1 height - (10 * rat) - imageHeight;xx xx1;yy yy1;xx2 10 * rat imageWidth (4 * rat);yy2 height - (10 * rat);xxx xx2;yyy yy2;}continue;}if (i 1) {// 公司名称String companyNameIsShow json.getStr(companyNameIsShow);if (0.equals(companyNameIsShow)) {// 如果公司展示则需要判断上一个用户字段是否展示如果展示和不展示xy轴坐标将不一样if (xx 0) {xx3 10 * rat;yy3 height - (10 * rat) - imageHeight;xx xx3;yy yy3;xx4 10 * rat imageWidth (4 * rat);yy4 height - (10 * rat);xxx xx4;yyy yy4;} else {xx3 xx;yy3 yy - (5 * rat) - imageHeight;yy yy3;xx4 xxx;yy4 yyy - (5 * rat) - fontSize;yyy yy4;}}continue;}if (i 2) {// 全部默认0是1否String addressIsShow json.getStr(addressIsShow);if (0.equals(addressIsShow)) {// 此处定义最高位置的地址即可换行的在真正生成时进行处理String address json.getStr(address);int maxLength 13;// 计算出地址的占用行数int i2 address.length() / maxLength (address.length() % maxLength 0 ? 0 : 1);if (xx 0) {// 公司和姓名都不展示xx5 10 * rat;yy5 height - 12 - (fontSize * i2);xx6 10 * rat imageWidth 10;yy6 height - (12 * (i2 1)) - (fontSize * (i2 1));xxx xx6;yyy yy6;continue;} else {xx5 xx;yy5 yy - 12 - (fontSize * i2);yy yy5;xx6 xxx;yy6 yyy - (12 * (i2 1)) - (fontSize * (i2 1));yyy yy6;}}}if (i 5) {// 时间控制String timeIsShow json.getStr(timeIsShow);if (0.equals(timeIsShow)) {xx10 xx;xx11 xx;if (xx 0) {yy10 height - (10 * rat);yy11 yy10 - fontSize - 8 * rat;}else{yy10 yyy - (8 * rat);yy11 yy10 - fontSize - 8 * rat;}yyy yy11;yy yy11;}continue;}if (i 6) {// 计算地图蒙版需要在所有坐标计算后在计算地图大小// 缩放比例int i1 width height ? width / 350 : height / 350;w12 readFloor.getWidth() * i1 / 3 * 2 ;String timeIsShow json.getStr(timeIsShow);if (0.equals(timeIsShow)) {h12 height - yyy (i1 * 18);continue;}String addressIsShow json.getStr(addressIsShow);String companyNameIsShow json.getStr(companyNameIsShow);String userNameIsShow json.getStr(userNameIsShow);if(0.equals(addressIsShow) || 0.equals(companyNameIsShow) ||0.equals(userNameIsShow)){h12 height - yyy - 6 30;}System.out.println(h12);continue;}}for (int i 0; i 6; i) {if (i 1) {// 优先绘制底板String addressIsShow json.getStr(addressIsShow);String companyNameIsShow json.getStr(companyNameIsShow);String userNameIsShow json.getStr(userNameIsShow);String timeIsShow json.getStr(timeIsShow);if (!0.equals(addressIsShow) !0.equals(companyNameIsShow) !0.equals(userNameIsShow) !0.equals(timeIsShow)) {// 如果所有的都关闭则无需添加底板和水印,直接跳出循环结束水印绘制。break;}g.drawImage(readFloor, 6 * rat, height - h12, w12, h12 - 6 * rat, null);continue;}if (i 2) {// 全部默认0是1否String userNameIsShow json.getStr(userNameIsShow);if (0.equals(userNameIsShow)) {String userName json.getStr(userName);g.drawImage(readUserName, xx1, yy1,imageWidth,imageHeight, null);g.drawString(userName, xx2, yy2);}continue;}if (i 3) {// 全部默认0是1否String companyNameIsShow json.getStr(companyNameIsShow);if (0.equals(companyNameIsShow)) {String companyName json.getStr(companyName);g.drawImage(readCompanyName, xx3, yy3,imageWidth,imageHeight, null);g.drawString(companyName, xx4, yy4);}continue;}if (i 4) {// 全部默认0是1否String addressIsShow json.getStr(addressIsShow);if (0.equals(addressIsShow)) {String address json.getStr(address);int maxLength 13;// 计算出地址的占用行数int i2 address.length() / maxLength (address.length() % maxLength 0 ? 0 : 1);int len 0;for (int j i2 - 1; j 0; j--) {int mlen maxLength * (j 1);len j * maxLength;if (mlen address.length()) {g.drawString(address.substring(len, mlen), xx6, yy6 (fontSize * (j 1)));} else {g.drawString(address.substring(len), xx6, yy6 (fontSize * (j 1)));}}// 图标g.drawImage(readAddress, xx5, yy5,imageWidth,imageHeight, null);}continue;}}// 输出图像g.dispose();File f new File(targetImg);ImageIO.write(image, targetImg.substring(targetImg.lastIndexOf(.) 1), f);// 如果年月日展示则进行坐标计算String timeIsShow json.getStr(timeIsShow);if (0.equals(timeIsShow)) {String s DateUtil.formatDate(new Date());Week week DateUtil.dayOfWeekEnum(new Date());// 文字水印为2023-02-22 星期三pressText(targetImg, xx10, yy10, 12, Color.WHITE, 微软雅黑, Font.PLAIN, 0.9F, s week.toChinese());String time DateUtil.format(new Date(), HH:mm:ss);pressText(targetImg, xx11, yy11, 18, Color.WHITE, 微软雅黑, Font.BOLD, 0.9F, time);}//花费毫秒数long ll System.currentTimeMillis();log.info(图片加水印耗时:{}{}, ll - l, ms);} catch (Exception e) {e.printStackTrace();}}/*** 添加图片文字水印此方法不在考虑文字过长需要换行等情况** param targetImg 原图片路径需要是本地路径如是网络url需要单独更改* param x 水印x轴坐标* param y 水印y轴坐标* param fontSize 水印文字大小 英镑会根据图片分辨率自动放大和缩小只需要指定标准350像素的文字标准值即可* param c 水印文字颜色 例如Color.WHITE* param fontName 水印文字字体 例如宋体微软雅黑* param fontStyle 水印文字字体风格例如Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.* param alpha 水印文字透明度例如 1.0F,范围 0-1F* param text 水印文字*/public static void pressText(String targetImg, int x, int y, int fontSize, Color c, String fontName, int fontStyle, float alpha, String text) {try {// 读取原图片BufferedImage src ImageIO.read(new File(targetImg));// 获取原图的宽和高int width src.getWidth(null);int height src.getHeight(null);// 动态设置字体大小fontSize width height ? width / 350 * fontSize : height / 350 * fontSize;// 创建空图片指定宽高BufferedImage image new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 准备绘制图片Graphics2D g image.createGraphics();// 将原图绘制到此空图片上左上角为坐标起点0,0宽和高为原图大小g.drawImage(src, 0, 0, width, height, null);// 设置水印字体颜色.g.setColor(c);// 设置水印字体,Font.PLAIN正常字体/BOLD加粗/ITALIC斜体.g.setFont(new Font(fontName, fontStyle, fontSize));// 透明度g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));/* 消除java.awt.Font字体的锯齿 */g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_ON);// 添加文字水印g.drawString(text, x, y);// 输出图像g.dispose();File f new File(targetImg);// 将加过水印的图片保存到指定文件ImageIO.write(image, targetImg.substring(targetImg.lastIndexOf(.) 1), f);} catch (Exception e) {log.error(水印添加失败{}, e.getMessage());}}/*** 计算文字长度一个中文按两个长度英文按一个长度计算** param text 文字* return*/public static int getLength(String text) {int length 0;for (int i 0; i text.length(); i) {if (new String(text.charAt(i) ).getBytes().length 1) {length 2;} else {length 1;}}return length / 2;}/*** 导出zip压缩包** param srcPath 要压缩的文件夹路径* param response 输出流*/public static void downloadZip(String srcPath, HttpServletResponse response) {// 将此目录打包成zipFile file ZipUtil.zip(srcPath);OutputStream toClient null;try {// 以流的形式下载文件。BufferedInputStream fis new BufferedInputStream(new FileInputStream(file.getPath()));byte[] buffer new byte[fis.available()];fis.read(buffer);fis.close();// 清空responseresponse.reset();toClient new BufferedOutputStream(response.getOutputStream());response.setCharacterEncoding(UTF-8);response.setContentType(application/zip);response.setHeader(Content-Disposition, attachment;filename file.getName());toClient.write(buffer);toClient.flush();} catch (Exception e) {log.error(下载zip压缩包过程发生异常:, e);} finally {if (toClient ! null) {try {toClient.close();} catch (IOException e) {log.error(zip包下载关流失败:, e);}}//删除改临时zip包(此zip包任何时候都不需要保留,因为源文件随时可以再次进行压缩生成zip包)file.delete();}}}
总结
其中通过ImageIO.read读取的图片是没有exif信息的这样就会导致有exif的图片读取后宽和高可能不准确最终生成的图片就是未旋转的看起来就是颠倒的。如果有谁有办法处理本地图片exif问题可以回复下。 让我学习学习。 如果使用的是阿里云oss地址在后面拼接参数即可 例如
String uuu https://xxx-dev.oss-cn-shanghai.aliyuncs.com/upload/123123/aa/20230223/b811b496cff29f02f0fa5a994c66867e.jpg;
String uuu https://xxx-dev.oss-cn-shanghai.aliyuncs.com/upload/123123/aa/20230223/b811b496cff29f02f0fa5a994c66867e.jpg?x-oss-processimage/auto-orient,1;在oss地址后面拼接?x-oss-processimage/auto-orient,1 即可。阿里云oss自适应传送门