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

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

 更新時(shí)間:2026年01月08日 08:42:59   作者:專注寫bug  
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)根據(jù)圖片url下載圖片并動(dòng)態(tài)添加水印,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下

前言

為了一些數(shù)據(jù)安全性,需要將圖片打上自定義的水印。水印需要滿足下列設(shè)置。

  • 支持橫向或縱向。
  • 支持單挑或多條水印。
  • 支持自定義顏色配置。
  • 支持水印字體大小配置與透明度配置。

相關(guān)依賴

僅需要引入下列依賴。

<!-- 用于處理URL請(qǐng)求獲取圖片 -->
<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 水印顏色 取值來(lái)源 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);

            // 默認(rèn)演示使用,linux使用下面的代碼會(huì)加載失敗字體
            //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,"香蕉集團(tuán)的香蕉不拿拿愛(ài)吃香蕉香蕉集團(tuán)的香蕉不拿拿愛(ài)吃香蕉香蕉集團(tuán)的香蕉不拿拿愛(ài)吃香蕉",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");
    }
}

一些補(bǔ)充

1、使用okhttp下載時(shí)提示ssl證書校驗(yàn)失敗

通常證書合法,直接使用下列代碼即可進(jìn)行http請(qǐng)求和下載。

OkHttpClient client = new OkHttpClient();

如果需要忽略ssl校驗(yàn),可以自定義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)建一個(gè)信任所有證書的 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); // 忽略主機(jī)名驗(yàn)證

            return builder.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

2、windows正常,但發(fā)布生產(chǎn)linux水印亂碼

一般出現(xiàn)此類問(wèn)題的根源在于linux環(huán)境不存在對(duì)應(yīng)的字體文件。

windows環(huán)境使用下列代碼進(jìn)行測(cè)試即可。

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中進(jìn)行拷貝。

到此這篇關(guān)于Java實(shí)現(xiàn)根據(jù)圖片url下載圖片并動(dòng)態(tài)添加水印的文章就介紹到這了,更多相關(guān)Java根據(jù)圖片url下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IntelliJ IDEA之配置JDK的4種方式(小結(jié))

    IntelliJ IDEA之配置JDK的4種方式(小結(jié))

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

    SpringBoot集成EasyExcel實(shí)現(xiàn)Excel導(dǎo)入的方法

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

    springmvc Rest風(fēng)格介紹及實(shí)現(xiàn)代碼示例

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

    ResponseBodyAdvice的使用原理源碼解析

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

    Java多線程處理List問(wèn)題

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

    SpringBoot實(shí)現(xiàn)啟動(dòng)類的存放位置

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

    JAVA自定義注解使用指南

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

    Mybatis中如何設(shè)置sqlSession自動(dòng)提交

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

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

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

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

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

最新評(píng)論

临洮县| 石林| 策勒县| 平舆县| 明星| 永春县| 岳阳县| 右玉县| 前郭尔| 沙坪坝区| 彰武县| 呼伦贝尔市| 乌什县| 朝阳县| 阳春市| 鲜城| 且末县| 德兴市| 泗阳县| 麻城市| 河池市| 靖宇县| 沅陵县| 西青区| 乾安县| 榆社县| 芮城县| 巴里| 岳阳县| 周至县| 嘉祥县| 霍林郭勒市| 宿迁市| 巫溪县| 乌拉特后旗| 洛川县| 定安县| 合水县| 年辖:市辖区| 天水市| 盐亭县|