Java實現(xiàn)根據(jù)圖片url下載圖片并動態(tài)添加水印
前言
為了一些數(shù)據(jù)安全性,需要將圖片打上自定義的水印。水印需要滿足下列設置。
- 支持橫向或縱向。
- 支持單挑或多條水印。
- 支持自定義顏色配置。
- 支持水印字體大小配置與透明度配置。
相關(guān)依賴
僅需要引入下列依賴。
<!-- 用于處理URL請求獲取圖片 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.11.0</version>
</dependency>
完整代碼
package img;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Objects;
import java.util.UUID;
/**
* 變量控制水印
*/
public class WaterMarkExample {
private static BufferedImage getBufferedImageByUrl(String imageUrl) throws IOException {
// 從URL獲取圖片
byte[] imageBytes = getImageBytesFromUrl(imageUrl);
BufferedImage image = ImageIO.read(new java.io.ByteArrayInputStream(imageBytes));
return image;
}
private static byte[] getImageBytesFromUrl(String imageUrl) throws IOException {
OkHttpClient client = UnsafeOkHttpClient.getUnsafeClient();
Request request = new Request.Builder()
.url(imageUrl)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().bytes();
}
}
private static byte[] convertImageToBytes(BufferedImage image) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "png", bos);
return bos.toByteArray();
}
/**
* 圖片追加水印
* @param image 原始圖片信息
* @param watermarkText 水印文字
* @param fontFilePath 字體文件
* @param isItalic 是否字體為斜體
* @param isSkew 水印是否傾斜
* @param isMultiLine 水印行數(shù)是否為多行
* @param waterMarkLineSize 水印行數(shù)
* @param waterMarkFontSize 水印字體大小
* @param alpha 透明度 [0,1]
* @param waterMarkColor 水印顏色 取值來源 java.awt.Color
* @return
*/
private static BufferedImage addWatermark(BufferedImage image, String watermarkText, String fontFilePath,
boolean isItalic, boolean isSkew, boolean isMultiLine,int waterMarkLineSize,float waterMarkFontSize,float alpha,Color waterMarkColor) {
BufferedImage watermarkedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = watermarkedImage.createGraphics();
g2d.drawImage(image, 0, 0, null);
try {
// 指定字體文件
Font customFont = Font.createFont(Font.TRUETYPE_FONT, new File(fontFilePath));
int fontStyle = isItalic? Font.ITALIC : Font.PLAIN;
Font derivedFont = customFont.deriveFont(fontStyle, waterMarkFontSize);
// 默認演示使用,linux使用下面的代碼會加載失敗字體
//g2d.setFont(new Font("微軟雅黑", isItalic? Font.ITALIC : Font.PLAIN, 30));
g2d.setFont(derivedFont);
} catch (FontFormatException | IOException e) {
e.printStackTrace();
g2d.setFont(new Font("Arial", isItalic? Font.ITALIC : Font.PLAIN, 30));
}
// 水印的顏色
g2d.setColor(waterMarkColor);
AlphaComposite alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
g2d.setComposite(alphaComposite);
// 圖片的尺寸
int stringWidth = g2d.getFontMetrics().stringWidth(watermarkText);
int stringHeight = g2d.getFontMetrics().getHeight();
if (isMultiLine) {
// 多行
if (isSkew) {
// 旋轉(zhuǎn)角度
double rotationAngle = Math.toRadians(-45);
int xStep = stringWidth + 50;
int yStep = stringHeight + 50;
for (int y = 0; y < image.getHeight(); y += yStep) {
for (int x = 0; x < image.getWidth(); x += xStep) {
AffineTransform oldTransform = g2d.getTransform();
g2d.rotate(rotationAngle, x + stringWidth / 2, y + stringHeight / 2);
g2d.drawString(watermarkText, x, y);
g2d.setTransform(oldTransform);
}
}
} else {
waterMarkLineSize = Objects.isNull(waterMarkLineSize) ? 1:waterMarkLineSize;
int x = (image.getWidth() - stringWidth) / 2;
int y = (image.getHeight() - stringHeight) / 2;
for (int i = 0; i < waterMarkLineSize; i++) {
g2d.drawString(watermarkText, x, y + i * (stringHeight + 20));
}
}
} else {
// 單行
if (isSkew) {
double rotationAngle = Math.toRadians(-45);
int x = (image.getWidth() - stringWidth) / 2;
int y = (image.getHeight() - stringHeight) / 2;
AffineTransform oldTransform = g2d.getTransform();
g2d.rotate(rotationAngle, x + stringWidth / 2, y + stringHeight / 2);
g2d.drawString(watermarkText, x, y);
g2d.setTransform(oldTransform);
} else {
int x = (image.getWidth() - stringWidth) / 2;
int y = (image.getHeight() - stringHeight) / 2;
g2d.drawString(watermarkText, x, y);
}
}
g2d.dispose();
return watermarkedImage;
}
public static void saveImage(byte[] imageBytes, String filePath) throws IOException {
Path path = Path.of(filePath);
Files.write(path, imageBytes, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
}
public static void main(String[] args) throws IOException {
String imageUrl = "https://i-blog.csdnimg.cn/direct/d102cabed76c4cd9b74b9469f42a4353.png";
BufferedImage bufferedImageByUrl = getBufferedImageByUrl(imageUrl);
String fontFilePath = System.getProperty("user.dir")+"/fill2word"+"/font/simfang.ttf";
BufferedImage bufferedImage = addWatermark(bufferedImageByUrl,"香蕉集團的香蕉不拿拿愛吃香蕉香蕉集團的香蕉不拿拿愛吃香蕉香蕉集團的香蕉不拿拿愛吃香蕉",fontFilePath,
false,false,true,3,50,0.3f,Color.blue);
byte[] watermarkedImageBytes = convertImageToBytes(bufferedImage);
String out_file_base_path = "doc/"+ UUID.randomUUID();
System.out.println(out_file_base_path);
saveImage(watermarkedImageBytes,out_file_base_path+".png");
}
}
一些補充
1、使用okhttp下載時提示ssl證書校驗失敗
通常證書合法,直接使用下列代碼即可進行http請求和下載。
OkHttpClient client = new OkHttpClient();
如果需要忽略ssl校驗,可以自定義OkHttpClient,如下所示:
import okhttp3.OkHttpClient;
import javax.net.ssl.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class UnsafeOkHttpClient {
public static OkHttpClient getUnsafeClient() {
try {
// 創(chuàng)建一個信任所有證書的 TrustManager
final X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
// 獲取 SSLContext 并初始化
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{trustManager}, new java.security.SecureRandom());
// 創(chuàng)建忽略證書的 SSLSocketFactory
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// 構(gòu)建 OkHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, trustManager);
builder.hostnameVerifier((hostname, session) -> true); // 忽略主機名驗證
return builder.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
2、windows正常,但發(fā)布生產(chǎn)linux水印亂碼
一般出現(xiàn)此類問題的根源在于linux環(huán)境不存在對應的字體文件。
windows環(huán)境使用下列代碼進行測試即可。
Graphics2D g2d = watermarkedImage.createGraphics();
g2d.drawImage(image, 0, 0, null);
// windows環(huán)境正常
g2d.setFont(new Font("微軟雅黑", isItalic? Font.ITALIC : Font.PLAIN, 30));
g2d.setFont(derivedFont);
但如果需要指定特定的字體文件,可以使用如下寫法。
Graphics2D g2d = watermarkedImage.createGraphics(); g2d.drawImage(image, 0, 0, null); // linux 環(huán)境指定特定的字體文件 Font customFont = Font.createFont(Font.TRUETYPE_FONT, new File(fontFilePath)); int fontStyle = isItalic? Font.ITALIC : Font.PLAIN; Font derivedFont = customFont.deriveFont(fontStyle, waterMarkFontSize); g2d.setFont(derivedFont);
字體文件可以從windows系統(tǒng)的C:\Windows\Fonts中進行拷貝。
到此這篇關(guān)于Java實現(xiàn)根據(jù)圖片url下載圖片并動態(tài)添加水印的文章就介紹到這了,更多相關(guān)Java根據(jù)圖片url下載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IntelliJ IDEA之配置JDK的4種方式(小結(jié))
這篇文章主要介紹了IntelliJ IDEA之配置JDK的4種方式(小結(jié)),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-10-10
SpringBoot集成EasyExcel實現(xiàn)Excel導入的方法
這篇文章主要介紹了SpringBoot集成EasyExcel實現(xiàn)Excel導入的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
springmvc Rest風格介紹及實現(xiàn)代碼示例
這篇文章主要介紹了springmvc Rest風格介紹及實現(xiàn)代碼示例,rest風格簡潔,分享了HiddenHttpMethodFilter 的源碼,通過Spring4.0實現(xiàn)rest風格源碼及簡單錯誤分析,具有一定參考價值,需要的朋友可以了解下。2017-11-11

