java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java根据图片url下载

Java实现根据图片url下载图片并动态添加水印

作者:专注写bug

这篇文章主要为大家详细介绍了如何使用Java实现根据图片url下载图片并动态添加水印,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

前言

为了一些数据安全性,需要将图片打上自定义的水印。水印需要满足下列设置。

相关依赖

仅需要引入下列依赖。

<!-- 用于处理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 水印行数是否为多行
     * @param waterMarkLineSize 水印行数
     * @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) {
                // 旋转角度
                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 {
            // 创建一个信任所有证书的 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());
            // 创建忽略证书的 SSLSocketFactory
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            // 构建 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正常,但发布生产linux水印乱码

一般出现此类问题的根源在于linux环境不存在对应的字体文件

windows环境使用下列代码进行测试即可。

Graphics2D g2d = watermarkedImage.createGraphics();
g2d.drawImage(image, 0, 0, null);
// windows环境正常
g2d.setFont(new Font("微软雅黑", isItalic? Font.ITALIC : Font.PLAIN, 30));
g2d.setFont(derivedFont);

但如果需要指定特定的字体文件,可以使用如下写法。

Graphics2D g2d = watermarkedImage.createGraphics();
g2d.drawImage(image, 0, 0, null);

// linux 环境指定特定的字体文件
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系统的C:\Windows\Fonts中进行拷贝。

到此这篇关于Java实现根据图片url下载图片并动态添加水印的文章就介绍到这了,更多相关Java根据图片url下载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文