本文主要是介绍java实现图片水印添加并自动上传七牛云,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
图片左下角水印添加
满足需求:可以对不同类型尺寸的照片、图片进行水印的添加,实现尺寸自适应添加水印。
水印效果
代码实现
Controller
package com.wlh.zetc.restore.controller;import cn.hutool.core.date.DateUtil;
import com.alibaba.nacos.client.utils.TenantUtil;
import com.wlh.zetc.admin.api.feign.RemoteTenantService;
import com.wlh.zetc.common.core.util.R;
import com.wlh.zetc.common.data.tenant.TenantBroker;
import com.wlh.zetc.common.data.tenant.TenantContextHolder;
import com.wlh.zetc.restore.service.QiniuService;
import com.wlh.zetc.restore.utils.ComplexWatermarkUtils;
import com.wlh.zetc.restore.utils.TextUtils;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;/*** 七牛云存储** @author wanghailin* @date 2024-03-12 10:19:56*/
@Controller
@RequestMapping("/qiniu" )
@Tag(description = "file" , name = "七牛云文件存储" )
@AllArgsConstructor
//@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class QiniuController
{private final QiniuService qiniuService;private final ComplexWatermarkUtils complexWatermarkUtils;/**** @param file* @param location* @param latitudeLongitude* @param remarks* @param weather* @param watermark 0:不添加水印 1:添加水印 2:添加水印但是不添加天气、位置、经纬度* @return* @throws IOException*/@PostMapping("/image/upload")@ResponseBodypublic R uploadImage(@RequestParam(value = "file", required = false) MultipartFile file,@RequestParam(value = "location", required = false) String location,@RequestParam(value = "latitudeLongitude", required = false) String latitudeLongitude,@RequestParam(value = "remarks", required = false) String remarks,@RequestParam(value = "weather", required = false) String weather,@RequestParam(value = "watermark", required = false,defaultValue = "1") Integer watermark) throws IOException {MultipartFile multipartFile = null;if (watermark != null && watermark.equals(0)){multipartFile = file;}else {multipartFile = complexWatermarkUtils.addComplexWatermark(file, DateUtil.now(), location, weather,latitudeLongitude,remarks,watermark);}System.out.println(multipartFile.getSize());if(!multipartFile.isEmpty()){InputStream in = multipartFile.getInputStream();String filename = multipartFile.getOriginalFilename();String project = "project"+ TenantContextHolder.getTenantId()+"/";try{String key = project+ TextUtils.generateFileName(filename);String imageUrl = qiniuService.uploadImage2qiniu(in,key);if(imageUrl!=null){HashMap<String, String> map = new HashMap<>();String privateDownloadUrl = qiniuService.getPrivateDownloadUrl(imageUrl);map.put("url",imageUrl);map.put("accessibleUrl",privateDownloadUrl);return R.ok(map).setMsg("上传成功");}}catch(IllegalArgumentException e){e.printStackTrace();}}return R.failed("上传失败");}@DeleteMapping("/image/delete")@ResponseBodypublic R deleteImage(@RequestParam("image")String imageUrl){boolean deleted = qiniuService.deleteImageFromQiniu(imageUrl);if(deleted){return R.ok(null,"删除成功");}return R.failed("删除失败");}@GetMapping("/image/download")@ResponseBodypublic R downloadImage(@RequestParam("image")String imageUrl){try {String privateDownloadUrl = qiniuService.getPrivateDownloadUrl(imageUrl);Map<String, String> map = new HashMap<>();map.put("url",privateDownloadUrl);return R.ok().setData(map);} catch (UnsupportedEncodingException e) {e.printStackTrace();}return R.ok();}
}
Utils
package com.wlh.zetc.restore.utils;import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.wlh.zetc.admin.api.entity.SysTenant;
import com.wlh.zetc.admin.api.feign.RemoteTenantService;
import com.wlh.zetc.admin.api.feign.RemoteUserService;
import com.wlh.zetc.common.core.util.R;
import com.wlh.zetc.common.data.tenant.TenantContextHolder;
import com.wlh.zetc.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;/*** 至农水印处理工具类** @author wanghailin* @date 2024-03-18 10:49:33*/
@Service
@AllArgsConstructor
public class ComplexWatermarkUtils {private final RemoteTenantService tenantService;//水印图片地址private static String watermarkImageURL = "https://qiniu.zjshjkj.com/logo/zhinong12.png";//水印添加public MultipartFile addComplexWatermark(MultipartFile file, String time, String location, String weather, String latitudeLongitude, String remarks,Integer watermark) {try {//MultipartFile multipartFile = correctImg(file);BufferedImage srcImg = null;srcImg = ImgUtil.read(file.getInputStream());Graphics2D g2d = srcImg.createGraphics();g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);int watermarkAreaHeight = (int) (srcImg.getHeight() * 0.10);int watermarkAreaWide = (int) (srcImg.getWidth() * 0.01);BufferedImage watermarkImage = ImgUtil.read(getWatermarkImage(watermarkImageURL).getInputStream());int scaledWatermarkWidth = watermarkImage.getWidth() * watermarkAreaHeight / watermarkImage.getHeight();Image scale = ImgUtil.scale(watermarkImage, scaledWatermarkWidth, watermarkAreaHeight);int x = watermarkAreaWide;int y = watermarkAreaHeight * 7 - watermarkAreaHeight / 2;g2d.drawImage(scale, x, y, null);//获取当前项目名称R tenant = tenantService.getByTenantId(TenantContextHolder.getTenantId());SysTenant project = (SysTenant) tenant.getData();// 设置较大字体属性,仅用于 projectNameint projectNameFontSize = watermarkAreaHeight / 3;Font projectNameFont = new Font("宋体", Font.BOLD, projectNameFontSize);g2d.setFont(projectNameFont);g2d.setColor(Color.WHITE);// 将 projectName 分割为多行文本if(StringUtils.isNotEmpty(project.getName())){List<String> projectNameLines =splitTextToLines(project.getName(), 20);int projectNameY = y + watermarkAreaHeight +projectNameFontSize;for (String line : projectNameLines) {g2d.drawString(line, x, projectNameY);projectNameY += g2d.getFontMetrics().getHeight();}// 设置文本属性,根据水印区域大小调整字体大小int fontSize = watermarkAreaHeight / 5;Font font = new Font("宋体", Font.BOLD, fontSize);g2d.setFont(font);FontMetrics metrics = g2d.getFontMetrics(font);int textHeight = metrics.getHeight();// 绘制黄色竖杠g2d.setColor(Color.YELLOW);int barX = x;int barY = projectNameY - watermarkAreaHeight / 3; // 根据 projectName 的最终位置调整if(watermark.equals(2)){g2d.fillRect(barX, barY, textHeight /4, textHeight * 2 + 5 * 3);}else {g2d.fillRect(barX, barY, textHeight /4, textHeight * 5 + 5 * 3);}g2d.setColor(Color.WHITE);int textX = barX + watermarkAreaWide ;int textY = barY + textHeight;if(!StringUtils.isNotEmpty(remarks)){remarks = "";}if(watermark.equals(2)){String[] texts = new String[]{"时 间:"+time, "备 注:"+remarks};for (String text : texts) {g2d.drawString(text, textX, textY);textY += textHeight + 5;}}else {String[] texts = new String[]{"时 间:"+time, "地 点:"+location, "天 气:"+weather, "经纬度:"+latitudeLongitude, "备 注:"+remarks};for (String text : texts) {g2d.drawString(text, textX, textY);textY += textHeight + 5;}}}g2d.dispose();ByteArrayOutputStream baos = new ByteArrayOutputStream();try {ImageIO.write(srcImg, "png", baos);} catch (Exception e) {e.printStackTrace();return null;}MultipartFile resultFile = new MockMultipartFile(file.getName(), file.getOriginalFilename(), file.getContentType(), baos.toByteArray());IoUtil.close(baos);return resultFile;} catch (IOException e) {e.printStackTrace();return null;}}//文件下载public static MultipartFile getWatermarkImage(String fileUrl) {try {URL url = new URL(fileUrl);HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();httpURLConnection.setRequestMethod("GET");httpURLConnection.connect();String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);String contentType = httpURLConnection.getContentType();InputStream inputStream = httpURLConnection.getInputStream();ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len;while ((len = inputStream.read(buffer)) > -1) {baos.write(buffer, 0, len);}baos.flush();MultipartFile multipartFile = new MockMultipartFile(fileName, fileName, contentType, baos.toByteArray());inputStream.close();baos.close();return multipartFile;} catch (Exception e) {e.printStackTrace();return null;}}//图片矫正public static MultipartFile correctImg(MultipartFile srcFile) {File outFile = new File(srcFile.getName());try (FileOutputStream fos = new FileOutputStream(outFile)) {int angle = getAngle(srcFile);if (angle != 90 && angle != 270) {// todo 不需要旋转,直接返回return srcFile;} else {BufferedImage srcImg = ImageIO.read(srcFile.getInputStream());int imgWidth = srcImg.getHeight();int imgHeight = srcImg.getWidth();double centerWidth = ((double) imgWidth) / 2;double centerHeight = ((double) imgHeight) / 2;BufferedImage targetImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);Graphics2D g = targetImg.createGraphics();g.rotate(Math.toRadians(angle), centerWidth, centerHeight);g.drawImage(srcImg, (imgWidth - srcImg.getWidth()) / 2, (imgHeight - srcImg.getHeight()) / 2, null);g.rotate(Math.toRadians(-angle), centerWidth, centerHeight);g.dispose();// 输出图片ImageIO.write(targetImg, "jpg", fos);ByteArrayOutputStream baos = new ByteArrayOutputStream();try {ImgUtil.write(srcImg, srcFile.getContentType(), baos);} catch (Exception e) {e.printStackTrace();return null;}MultipartFile resultFile = new MockMultipartFile(srcFile.getName(), srcFile.getOriginalFilename(), srcFile.getContentType(), baos.toByteArray());IoUtil.close(baos);return resultFile;}} catch (Exception e) {e.printStackTrace();return null;}}//角度判断private static int getAngle(MultipartFile file) throws Exception {Metadata metadata = ImageMetadataReader.readMetadata(file.getInputStream());for (Directory directory : metadata.getDirectories()) {for (Tag tag : directory.getTags()) {if ("Orientation".equals(tag.getTagName())) {String orientation = tag.getDescription();if (orientation.contains("90")) {return 90;} else if (orientation.contains("180")) {return 180;} else if (orientation.contains("270")) {return 270;}}}}return 0;}// 辅助方法:将文本分割为多行private static List<String> splitTextToLines(String text, int maxCharsPerLine) {List<String> lines = new ArrayList<>();for (int start = 0; start < text.length(); start += maxCharsPerLine) {int end = Math.min(start + maxCharsPerLine, text.length());lines.add(text.substring(start, end));}return lines;}
}
七牛云service
package com.wlh.zetc.restore.service;import java.io.InputStream;
import java.io.UnsupportedEncodingException;/*** 七牛文件存储** @author wanghailin* @date 2024-03-12 10:21:35*/
public interface QiniuService {String uploadImage2qiniu(InputStream in, String key);boolean deleteImageFromQiniu(String key);String getPrivateDownloadUrl(String fileName) throws UnsupportedEncodingException;}
七牛云impl
package com.wlh.zetc.restore.service.impl;import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.*;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.wlh.zetc.restore.properties.QiniuProperties;
import com.wlh.zetc.restore.service.QiniuService;
import com.wlh.zetc.restore.utils.TextUtils;
import io.netty.channel.unix.Unix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;/*** 七牛文件存储** @author wanghailin* @date 2024-03-12 10:21:35*/
@Service
public class QiniuServiceImpl implements QiniuService
{private final String domain;private final String bucketName;private final String ak;private final String sk;// 七牛文件上传管理器private final Configuration cfg;private final Auth auth;@Autowiredpublic QiniuServiceImpl(QiniuProperties oss){this.ak = oss.getAccessKey();this.sk = oss.getSecretKey();this.domain = oss.getDomain(); // CDN域名this.bucketName = oss.getBucketName();// //构造一个带指定 Region 对象的配置类cfg = new Configuration(Zone.zone0());auth = Auth.create(ak,sk);}/*** 上传图片到七牛云* @return 图片url* */@Overridepublic String uploadImage2qiniu(InputStream in, String key){try {UploadManager uploadManager = new UploadManager(cfg);// 根据命名空间生成的上传tokenString upToken = auth.uploadToken(bucketName);Response response = uploadManager.put(in,key,upToken,null, null);//解析上传成功的结果DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);//System.out.println(putRet.key);//System.out.println(putRet.hash);//return String.format("http://%s/%s",this.domain,putRet.key);return putRet.key;} catch (QiniuException ex) {Response r = ex.response;System.err.println(r.toString());try {System.err.println(r.bodyString());} catch (QiniuException ex2) {//ignore}}return null;}/*** 删除图片* */@Overridepublic boolean deleteImageFromQiniu(String imageUrl){BucketManager bucketManager = new BucketManager(auth, cfg);try {String key= TextUtils.getKey(imageUrl);Response response = bucketManager.delete(bucketName,key);return response.isOK();} catch (QiniuException ex) {//如果遇到异常,说明删除失败System.err.println(ex.code());System.err.println(ex.response.toString());}return false;}/*** 获取文件下载路径** @param fileName* @return* @throws UnsupportedEncodingException*/public String getPrivateDownloadUrl(String fileName) throws UnsupportedEncodingException {//文件https访问配置DownloadUrl url = new DownloadUrl(domain, true, fileName);//DownloadUrl url = new DownloadUrl(domain, false, fileName);long expireInSeconds = 3600;//1小时,可以自定义链接过期时间long deadline = System.currentTimeMillis()/1000 + expireInSeconds;Auth auth = Auth.create(ak, sk);String urlString = null;try {urlString = url.buildURL(auth, deadline);} catch (QiniuException e) {throw new RuntimeException(e);}return urlString;}
}
七牛云配置类
package com.wlh.zetc.restore.properties;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/*** 七牛文件存储** @author wanghailin* @date 2024-03-12 10:21:35*/
@Component
@ConfigurationProperties(prefix = "oss.qiniu")
@Data
public class QiniuProperties
{private String domain; // CDN域名private String accessKey; // ACCESS_KEYprivate String secretKey; // SECRET_KEYprivate String bucketName; // 空间名称
}
七牛云配置yml
oss:qiniu:domain: qiniu.znkj0215.com # 访问域名(正式访问域名地址) 暂未配置https
# domain: qiniu.iswhl.com # 访问域名(测试访问域名地址) 已配置httpsaccessKey: APlM_0fW1A_PRS5bQ92rdGf9oSW-5q9mZK3Tv6yk # 公钥secretKey: Ri2eN9h4htBjZa8J8n_7QBfsAAvM_Arz5_CLqWth # 私钥bucketName: zhinonggengdi #存储空间名称
这篇关于java实现图片水印添加并自动上传七牛云的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!