最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實現(xiàn)根據(jù)圖片url下載圖片并動態(tài)添加水印

 更新時間:2026年01月08日 08:42:59   作者:專注寫bug  
這篇文章主要為大家詳細介紹了如何使用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é))

    這篇文章主要介紹了IntelliJ IDEA之配置JDK的4種方式(小結(jié)),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-10-10
  • SpringBoot集成EasyExcel實現(xiàn)Excel導入的方法

    SpringBoot集成EasyExcel實現(xiàn)Excel導入的方法

    這篇文章主要介紹了SpringBoot集成EasyExcel實現(xiàn)Excel導入的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • springmvc Rest風格介紹及實現(xiàn)代碼示例

    springmvc Rest風格介紹及實現(xiàn)代碼示例

    這篇文章主要介紹了springmvc Rest風格介紹及實現(xiàn)代碼示例,rest風格簡潔,分享了HiddenHttpMethodFilter 的源碼,通過Spring4.0實現(xiàn)rest風格源碼及簡單錯誤分析,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • ResponseBodyAdvice的使用原理源碼解析

    ResponseBodyAdvice的使用原理源碼解析

    這篇文章主要為大家介紹了ResponseBodyAdvice的使用原理源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • Java多線程處理List問題

    Java多線程處理List問題

    這篇文章主要介紹了Java多線程處理List問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • SpringBoot實現(xiàn)啟動類的存放位置

    SpringBoot實現(xiàn)啟動類的存放位置

    這篇文章主要介紹了SpringBoot實現(xiàn)啟動類的存放位置,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • JAVA自定義注解使用指南

    JAVA自定義注解使用指南

    注解是一種特殊的接口,用于為Java代碼提供元數(shù)據(jù),它們不會直接影響代碼的執(zhí)行,但可以被編譯器、開發(fā)工具或運行時環(huán)境讀取和使用,本文給大家介紹JAVA自定義注解的相關(guān)知識,感興趣的朋友一起看看吧
    2025-11-11
  • Mybatis中如何設置sqlSession自動提交

    Mybatis中如何設置sqlSession自動提交

    在MyBatis中,默認情況下,獲取的SqlSession對象不會自動提交事務,這意味著在進行更新、刪除或插入等操作后,需要顯式調(diào)用commit方法來提交事務,但是,可以在獲取SqlSession時通過將openSession方法的參數(shù)設置為true
    2024-09-09
  • 利用Java實現(xiàn)網(wǎng)站聚合工具

    利用Java實現(xiàn)網(wǎng)站聚合工具

    互聯(lián)網(wǎng)上有數(shù)以萬億計的網(wǎng)站,每個網(wǎng)站大都具有一定的功能。搜索引擎雖然對互聯(lián)網(wǎng)上的部分網(wǎng)站建立了索引,但是其作為一個大而全的搜索系統(tǒng),無法很好的定位到一些特殊的需求。因此本文將介紹一個用java實現(xiàn)的網(wǎng)站數(shù)據(jù)聚合工具,需要的可以參考一下
    2022-01-01
  • Java實現(xiàn)視頻自定義裁剪功能

    Java實現(xiàn)視頻自定義裁剪功能

    這篇文章主要介紹了如何通過java實現(xiàn)視頻裁剪,可以將視頻按照自定義尺寸進行裁剪,文中的示例代碼簡潔易懂,感興趣的可以了解一下
    2022-01-01

最新評論

申扎县| 区。| 高密市| 突泉县| 兴山县| 甘洛县| 桂阳县| 梁河县| 当雄县| 阿图什市| 桂阳县| 进贤县| 苏州市| 兴安盟| 三原县| 招远市| 房山区| 五指山市| 繁昌县| 志丹县| 南平市| 共和县| 孙吴县| 西青区| 仁寿县| 文安县| 大邑县| 高碑店市| 平邑县| 承德县| 泗水县| 平顺县| 金湖县| 禹州市| 尖扎县| 邢台市| 磐安县| 芜湖县| 广丰县| 繁昌县| 商河县|