第一种:阿里云对象存储oss服务提供java的SDK方式。
首先开通阿里云的对象存储oss服务(本地调用存储不收费,通过公网调用会产生费用,但是很低);
进入服务管理页面后,创建Bucket,
根据需求是否开通相关服务:
创建好Bucket,进入控制台,可以在这里管理相关文件:
可通过首页打开帮助文档:
文档中提供对图片处理的Java SDK,也有其他语言。也提供上传下载的SDK。
如图片缩放的一些参数值:
提供的SDK参考代码:
// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
String objectName = "<yourObjectName>";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 图片缩放。
String style = "image/resize,m_fixed,w_100,h_100";
GetObjectRequest request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
ossClient.getObject(request, new File("example-resize.jpg"));
// 图片裁剪。
style = "image/crop,w_100,h_100,x_100,y_100,r_1";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
ossClient.getObject(request, new File("example-crop.jpg"));
// 图片旋转。
style = "image/rotate,90";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
ossClient.getObject(request, new File("example-rotate.jpg"));
// 图片锐化。
style = "image/sharpen,100";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
ossClient.getObject(request, new File("example-sharpen.jpg"));
// 添加水印。
style = "image/watermark,text_SGVsbG8g5Zu-54mH5pyN5YqhIQ";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
ossClient.getObject(request, new File("example-watermark.jpg"));
// 图片格式转换。
style = "image/format,png";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
ossClient.getObject(request, new File("example-format.png"));
// 获取图片信息。
style = "image/info";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
ossClient.getObject(request, new File("example-info.txt"));
// 关闭OSSClient。
ossClient.shutdown();
写的一个demo仅供参考:
package com.vevor.research.imageService.service;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Formatter;
import java.util.List;
/**
* @author :lixinyu
* @version :M1.0
* @program :vevor-research
* @date :Created in 2020/9/10 9:50
* @description :oss存储,处理图片服务类
*/
@Slf4j
@Service
public class OssServiceImpl {
/**
*Endpoint以成都为例,其它Region请按实际情况填写。
*/
@Value("${aliyun.oss.endpoint}")
private String endpoint;
/**
* 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
*/
@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;
/**
* 个人账户bucket,用户技术调研及测试
*/
@Value("${aliyun.oss.bucketName}")
private String bucketName;
/**
* 本地测试上传及下载路径
*/
private final String filePath = "D:\\picture\\";
/**
* 本地图片上传至oss
*/
public void uploadLocalToOss() {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 创建PutObjectRequest对象。key为bucket里所要存储的文件名,可以指定文件夹
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, "vevor/black.png", new File(filePath+"black.png"));
// 如果需要上传时设置存储类型与访问权限,请参考以下示例代码。
ObjectMetadata metadata = new ObjectMetadata();
// 设置http头
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
// 设置文件读写权限权限,默认继承bucket权限
metadata.setObjectAcl(CannedAccessControlList.PublicRead);
putObjectRequest.setMetadata(metadata);
/*// 您的回调服务器地址,如http://oss-demo.aliyuncs.com:23450,回调服务器必须是公网IP
String callbackUrl = "http://61.185.225.102";
// 上传回调参数。
Callback callback = new Callback();
callback.setCallbackUrl(callbackUrl);
//(可选)设置回调请求消息头中Host的值,即您的服务器配置Host的值。
callback.setCallbackHost("oss-cn-hangzhou.aliyuncs.com");
// 设置发起回调时请求body的值。
callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},"
+ "\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},"
+ "\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
// 设置发起回调请求的Content-Type。
callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
// 设置发起回调请求的自定义参数,由Key和Value组成,Key必须以x:开始。
callback.addCallbackVar("x:var1", "value1");
callback.addCallbackVar("x:var2", "value2");
putObjectRequest.setCallback(callback);*/
// 上传文件
ossClient.putObject(putObjectRequest);
// 判断文件是否存在,也可用此方法判断上传是否成功
boolean flag = ossClient.doesObjectExist(bucketName, "vevor/black.png");
if (flag){
log.info("upload success");
}
} catch (ClientException ce) {
log.error("Error Message: " + ce.getMessage());
} finally {
// 关闭OSSClient。
ossClient.shutdown();
}
}
/**
* 自定义处理图片并保存至bucket同时下载至本地
*/
public JSONObject changeImageByFreeStyle() throws IOException {
// 当前bucket下的要处理的文件名。
String objectName = "black.png";
int index = objectName.lastIndexOf(".");
//获取图片去掉后缀(.jpg)的名字
String realName = objectName.substring(0,index);
//获取文件后缀
String extension = objectName.substring(index);
// 当前bucket下要存储的路径
String bucketPath = "vevor/";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 先判断文件是否存在,不存在则抛异常
boolean flag = ossClient.doesObjectExist(bucketName, objectName);
if (!flag){
throw new ClientException("文件不存在");
}
StringBuilder sbStyle = new StringBuilder();
Formatter styleFormatter = new Formatter(sbStyle);
// 自定义图片处理样式
String styleType = "image/resize,m_fixed,w_500,h_100";
String changeName = realName + "-change" + extension;
// 存储在oss上的图片路径
String targetImage = bucketPath + changeName;
// base64编码
styleFormatter.format("%s|sys/saveas,o_%s,b_%s", styleType,
BinaryUtil.toBase64String(targetImage.getBytes()),
BinaryUtil.toBase64String(bucketName.getBytes()));
// 创建ProcessObjectRequest对象,处理图片
ProcessObjectRequest request = new ProcessObjectRequest(bucketName, objectName, sbStyle.toString());
// 图片持久化处理,存储在当前bucket下
GenericResult processResult = ossClient.processObject(request);
// 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
GetObjectRequest objectRequest = new GetObjectRequest(bucketName, targetImage);
String localPath = filePath + "vevor\\";
ossClient.getObject(objectRequest,new File(checkFilePathAndName(localPath)+ changeName));
// 获取状态
String json = IOUtils.readStreamAsString(processResult.getResponse().getContent(), "UTF-8");
processResult.getResponse().getContent().close();
// 关闭OSSClient。
ossClient.shutdown();
JSONObject.parseObject(json);
return JSONObject.parseObject(json);
}
/**
* 下载bucket中的图片至本地
*/
public void download(){
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
String objectName = "vevor/qq-change.jpg";
// 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
String localPath = filePath + "vevor\\";
ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(checkFilePathAndName(localPath) + "qq-change.jpg"));
log.info("图片已下载至:{}" + localPath);
// 关闭OSSClient。
ossClient.shutdown();
}
/**
* 批量处理图片,通过列举文件实现批量操作并下载至本地
*/
public void batchImage(){
// 当前bucket下的文件夹名称
String keyPrefix = "batch-test/";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 列举文件。 如果不设置KeyPrefix,则列举存储空间下所有的文件。KeyPrefix,则列举包含指定前缀的文件。
ObjectListing objectListing = ossClient.listObjects(bucketName,keyPrefix);
List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
// 如果设置KeyPrefix,第一个文件为与KeyPrefix同名的路径,而不是文件,所以删除它
if (sums.get(0).getKey().equals(keyPrefix)){
sums.remove(0);
}
// 添加自定义样式。
String style = "image/resize,m_fixed,w_400,h_400";
String localPath = filePath + "batch\\";
for (OSSObjectSummary s : sums) {
// key为bucket中带文件夹前缀的文件名
GetObjectRequest request = new GetObjectRequest(bucketName, s.getKey());
request.setProcess(style);
String fileName = s.getKey().replace(keyPrefix,"");
// 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
ossClient.getObject(request, new File(checkFilePathAndName(localPath) + fileName));
}
// 关闭OSSClient。
ossClient.shutdown();
log.info("批量处理图片成功");
}
/**
* 添加文字或文字水印
*/
public void addWatermark(){
String objectName = "vevor/qq-change.jpg";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 先判断文件是否存在,不存在则抛异常
boolean flag = ossClient.doesObjectExist(bucketName, objectName);
if (!flag){
throw new ClientException("文件不存在");
}
// String watermark = "FORGED STEEL CONSTRUCTIO";
String watermark = "black-change.png";
String base64 = Base64.getEncoder().encodeToString(watermark.getBytes(StandardCharsets.UTF_8));
// 文字水印样式
// String style = "image/watermark,text_" + base64 + ",color_FFFFFF,size_30,g_center,x_0,y_0";
// 图片水印样式
String style = "image/watermark,image_" + base64 + ",g_south,x_0,y_0";
GetObjectRequest request = new GetObjectRequest(bucketName,objectName);
request.setProcess(style);
String localPath = filePath + "watermark\\";
// 处理完成后下载至本地
ossClient.getObject(request,new File(checkFilePathAndName(localPath) + "black-change.png"));
// 关闭OSSClient。
ossClient.shutdown();
}
/**
* 检查目录是否存在,不存在先创建,否则下载soo文件失败
* @param path 文件路径
* @return 文件路径
*/
private String checkFilePathAndName(String path){
File file = new File(path);
if (!file.exists()){
if (file.mkdir()){
log.info("文件目录已创建");
};
}
return path;
}
}
其中endpoint,accessKeyId,accessKeySecret在application.yml中配置着(这些密钥信息需要自己申请)。like this ↓:
aliyun:
oss:
endpoint: oss-cn-chengdu.aliyuncs.com # oss对外服务的访问域名
accessKeyId: LTAI4GG6tawYReHwYCxPtZmFz # 访问身份验证中用到用户标识
accessKeySecret: spOQQe34bhiEtMnf6TrSS272AakNz9a # 用户用于加密签名字符串和oss用来验证签名字符串的密钥
bucketName: lux-oss # oss的存储空间
policy:
expire: 300 # 签名有效期(S)
maxSize: 10 # 上传文件大小(M)
callback: http://XX(必须为公网ip):8080/aliyun/oss/callback # 文件上传成功后的回调地址
dir:
prefix: vevor/ # 上传文件夹路径前缀
其他操作可参考文档详情。
第二种方式:Java自带了图片处理类
具体实现参考自己写的一个Demo。
package com.vevor.research.imageService.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.IOException;
/**
* @author :lixinyu
* @version :M1.0
* @program :vevor-research
* @date :Created in 2020/9/11 9:59
* @description :java图片处理类,包括java图片处理,java图片水印,java图片切割,java图片缩放,java图片格式转换,java图片等比例缩小
* Image是一个抽象类,BufferedImage是其实现类,是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中
* (BufferedImage生成的图片在内存里有一个图像缓冲区,利用这个缓冲区我们可以很方便地操作这个图片),
* 提供获得绘图对象、图像缩放、选择图像平滑度等功能,通常用来做图片大小变换、图片变灰、设置透明不透明等。
*/
@Slf4j
@Service
public class ImageServiceImpl {
/**
* 缩放图像(按指定比例缩放)
* @param localImagePath 源图像文件地址
* @param scaleImagePath 缩放后的图像地址
* @param scaling 缩放比例
* @param flag 缩放选择:true 放大; false 缩小;
* @throws IOException IOException
*/
public void scaling(String localImagePath, String scaleImagePath, int scaling, boolean flag) throws IOException {
// 读入文件
BufferedImage localImage = ImageIO.read(new File(localImagePath));
if (ObjectUtils.isEmpty(localImage)){
throw new IllegalArgumentException("未找到图片");
}
// 得到源图宽
int width = localImage.getWidth();
// 得到源图长
int height = localImage.getHeight();
if (flag) {
// 放大
width = width * scaling;
height = height * scaling;
} else {
// 缩小
width = width / scaling;
height = height / scaling;
}
// 创建图像的缩放版本
Image image = localImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
// 构造一个预定义图像类型的BufferedImage
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图形2d
Graphics graphics = tag.getGraphics();
// 绘制缩小后的图
graphics.drawImage(image, 0, 0, null);
// 释放图形资源
graphics.dispose();
// 输出到文件流
boolean success = ImageIO.write(tag, "JPEG", new File(scaleImagePath));
if (!success){
throw new IIOException("缩放图片失败");
}
}
/**
* 缩放图像(按指定宽高缩放)
* @param localImagePath 源图像文件地址
* @param scaleImagePath 缩放后的图像地址
* @param width 缩放后的宽度
* @param height 缩放后的高度
* @throws IOException IOException
*/
public void scale1WithCustom(String localImagePath, String scaleImagePath, int width, int height) throws IOException {
// 读入文件
BufferedImage localImage = ImageIO.read(new File(localImagePath));
if (ObjectUtils.isEmpty(localImage)){
throw new IllegalArgumentException("未找到图片");
}
// 创建图像的缩放版本
Image image = localImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
// 构造一个预定义图像类型的BufferedImage
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图形2d
Graphics graphics = tag.getGraphics();
// 绘制缩小后的图
graphics.drawImage(image, 0, 0, null);
// 释放图形资源
graphics.dispose();
// 输出到文件流
boolean success = ImageIO.write(tag, "JPEG", new File(scaleImagePath));
if (!success){
throw new IIOException("缩放图片失败");
}
}
/**
* 缩放图像(按高度或者宽度比值缩放)
* @param localImagePath 源图像文件地址
* @param scaleImagePath 缩放后的图像地址
* @param height 缩放后的高度
* @param width 缩放后的宽度
* @param repair 比例不对时是否需要补白:true为补白; false为不补白;
* @throws IOException IOException
*/
public void scale1WithRatio(String localImagePath, String scaleImagePath, int width, int height, boolean repair) throws IOException {
// 缩放比例
double ratio;
BufferedImage localImage = ImageIO.read(new File(localImagePath));
if (ObjectUtils.isEmpty(localImage)){
throw new IllegalArgumentException("未找到图片");
}
// Image.SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的优先级比速度高 生成的图片质量比较好 但速度慢
Image image = localImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
// 计算比例
if ((localImage.getHeight() > height) || (localImage.getWidth() > width)) {
if (localImage.getHeight() > localImage.getWidth()) {
// 源图高比宽长,缩放比例为:缩放高度/源图高度
ratio = (new Integer(height)).doubleValue() / localImage.getHeight();
} else {
// 源图宽比高长,缩放比例为:缩放宽度/源图宽度
ratio = (new Integer(width)).doubleValue() / localImage.getWidth();
}
// AffineTransform是J2SE中非常重要的专门处理2D图像仿射变换的类,表示缩放变换的变换。ratio为width,height倍数
AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null);
// 转换源BufferedImage并将结果存储到目标BufferedImage。如果两个图像的颜色模型不匹配,则执行到目标颜色模型的颜色转换。
// 如果目标图像为空,使用源代码创建缓冲区映像,返回过滤后的缓冲区图像
image = op.filter(localImage, null);
}
if (repair) {
// 补白
// BufferedImage.TYPE_INT_RGB表示压缩为8位RGB颜色组件的图像
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 基于图片对象打开绘图
Graphics2D graphics = bufferedImage.createGraphics();
// 添加背景色
graphics.setColor(Color.white);
// 填充指定的图形
graphics.fillRect(0, 0, width, height);
// 根据宽度缩放规则绘图
if (width == image.getWidth(null)) {
graphics.drawImage(image, 0, (height - image.getHeight(null)) / 2,
image.getWidth(null), image.getHeight(null),
Color.white, null);
} else {
graphics.drawImage(image, (width - image.getWidth(null)) / 2, 0,
image.getWidth(null), image.getHeight(null),
Color.white, null);
}
// 释放图形资源
graphics.dispose();
image = bufferedImage;
}
boolean success = ImageIO.write((BufferedImage) image, "JPEG", new File(scaleImagePath));
if (!success){
throw new IIOException("缩放图片失败");
}
}
/**
* 图像切割(按指定起点坐标和宽高切割)
* @param localImagePath 源图像地址
* @param scaleImagePath 切片后的图像地址
* @param x 目标切片起点坐标X
* @param y 目标切片起点坐标Y
* @param width 目标切片宽度
* @param height 目标切片高度
* @throws IOException IOException
*/
public void cutImage(String localImagePath, String scaleImagePath, int x, int y, int width, int height) throws IOException {
// 读取源图像
BufferedImage localImage = ImageIO.read(new File(localImagePath));
if (ObjectUtils.isEmpty(localImage)){
throw new IllegalArgumentException("未找到图片");
}
// 源图宽度和高度
int localWidth = localImage.getHeight(null);
int localHeight = localImage.getWidth(null);
if (localWidth > 0 && localHeight > 0) {
// 创建图像的缩放版本
Image image = localImage.getScaledInstance(localWidth, localHeight, Image.SCALE_SMOOTH);
// 四个参数分别为图像起点坐标和宽高
// 即: CropImageFilter(int x,int y,int width,int height)
// 提取绝对矩形
ImageFilter filter = new CropImageFilter(x, y, width, height);
// 使用指定的图像生成器创建图像
Image img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), filter));
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics graphics = tag.getGraphics();
// 绘制切割后的图
graphics.drawImage(img, 0, 0, width, height, null);
graphics.dispose();
// 输出为文件
boolean success = ImageIO.write(tag, "JPEG", new File(scaleImagePath));
if (!success) {
throw new IIOException("切割图片失败");
}
}
}
/**
* 图像类型转换:如GIF->JPG、GIF->PNG、PNG->JPG、PNG->GIF(X)、BMP->PNG
* @param localImagePath 源图像地址
* @param convertImageFile 目标图像地址
* @throws IOException IOException
*/
public void convert(String localImagePath, String convertImageFile) throws IOException {
File file = new File(localImagePath);
if (ObjectUtils.isEmpty(file)){
throw new IllegalArgumentException("未找到图片");
}
// 判断文件是否有读取权限
if (file.canRead() && file.canWrite()){
BufferedImage image = ImageIO.read(file);
// formatName:包含格式非正式名称的 String:如JPG、JPEG、GIF等
boolean success = ImageIO.write(image, "jpg", new File(convertImageFile));
if (!success) {
throw new IIOException("切割图片失败");
}
} else {
throw new SecurityException("无权访问文件");
}
}
/**
* 给图片添加文字水印
* @param pressText 水印文字
* @param localImageFile 源图像地址
* @param markImageFile 目标图像地址
* @param fontName 水印的字体名称
* @param fontStyle 水印的字体样式(Font.BOLD / 36)
* @param color 水印的字体颜色
* @param fontSize 水印的字体大小
* @param x 修正值
* @param y 修正值
* @param alpha 透明度,必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字,值越小透明度越高
* @throws IOException IOException
*/
public void textWatermark(String pressText,
String localImageFile,
String markImageFile,
String fontName,
int fontStyle,
Color color,
int fontSize,
int x,
int y,
float alpha) throws IOException {
File localFile = new File(localImageFile);
if (ObjectUtils.isEmpty(localFile)){
throw new IllegalArgumentException("未找到图片");
}
Image src = ImageIO.read(localFile);
int width = src.getWidth(null);
int height = src.getHeight(null);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = image.createGraphics();
graphics.drawImage(src, 0, 0, width, height, null);
graphics.setColor(color);
graphics.setFont(new Font(fontName, fontStyle, fontSize));
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
// 在指定坐标绘制水印文字
graphics.drawString(pressText, (width - (getLength(pressText) * fontSize))
/ 2 + x, (height - fontSize) / 2 + y);
graphics.dispose();
boolean success = ImageIO.write(image, "jpg", new File(markImageFile));
if (!success) {
throw new IIOException("添加文字水印失败");
}
}
/**
* 给图片添加图片水印
* @param pressImg 水印图片
* @param localImagePath 源图像地址
* @param pressImageFile 目标图像地址
* @param x 修正值。 默认在中间
* @param y 修正值。 默认在中间
* @param alpha 透明度,必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字,值越小透明度越高
* @throws IOException IOException
*/
public void imageWatermark(String pressImg,
String localImagePath,
String pressImageFile,
int x,
int y,
float alpha) throws IOException {
File localFile = new File(localImagePath);
if (ObjectUtils.isEmpty(localFile)){
throw new IllegalArgumentException("未找到图片");
}
Image localImage = ImageIO.read(localFile);
int width = localImage.getWidth(null);
int height = localImage.getHeight(null);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = image.createGraphics();
graphics.drawImage(localImage, 0, 0, width, height, null);
// 水印文件
Image markImage = ImageIO.read(new File(pressImg));
if (ObjectUtils.isEmpty(markImage)){
throw new IllegalArgumentException("未找到水印图片");
}
int markImageWidth = markImage.getWidth(null);
int markImageHeight = markImage.getHeight(null);
// 将新像素与图形处理器上的现有像素组合
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
// 矩形图像原点为左上角,x,y=0,图片水印在源图中间
// x为原点在水平距离向右的修正值,x为原点在垂直距离向下的修正值
graphics.drawImage(markImage, x, y, markImageWidth, markImageHeight, null);
// 释放图形处理资源
graphics.dispose();
ImageIO.write(image, "jpg", new File(pressImageFile));
}
/**
* 计算text的长度(一个中文算两个字符)
* @param text 字符
* @return 字符长度
*/
private int getLength(String text) {
int length = 0;
for (int i = 0; i < text.length(); i++) {
if ((text.charAt(i) + "").getBytes().length > 1) {
length += 2;
} else {
length += 1;
}
}
return length / 2;
}
}