Skip to content

Java图片操作

这是一个简单的可以但不限于用于给添加图片或文字水印的工具类, 日后其他图片操作可以以此为基础进行增修

主要逻辑

  1. 获取图片的BufferedImage, 或者新建一个, 作为画布
  2. 新建Graphic图像并进行绘制, 可以绘制图像或文字或其他几何图案
  3. 绘制完成后将图像dispose

类似但不完全学习MyBatis-Plus的做法, 使用ComposeWrapper封装组合条件

java
package io.tomoto.util;

import javafx.util.Pair;
import lombok.*;
import lombok.experimental.Accessors;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * 图片组合工具类
 *
 * @author Tomoto
 * @version 1.0
 * @since 1.0 2022/4/7 11:47
 */
public class ImageComposeUtil {
    /**
     * 获取图片BufferedImage类型值
     *
     * @param imagePath 图片路径
     * @return BufferedImage
     */
    public static BufferedImage getBufferedImage(String imagePath) {
        // ImageIO.read(file) 会出现图片变红问题, 故不使用
        Image image = Toolkit.getDefaultToolkit().getImage(imagePath);
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }

        // 确保加载所有像素
        image = new ImageIcon(image).getImage();
        BufferedImage bimage;
        try {
            bimage = GraphicsEnvironment
                    .getLocalGraphicsEnvironment()
                    .getDefaultScreenDevice()
                    .getDefaultConfiguration()
                    .createCompatibleImage(
                            image.getWidth(null),
                            image.getHeight(null),
                            Transparency.OPAQUE);
        } catch (HeadlessException ignore) {
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }

        // 将图像绘制进BufferedImage
        Graphics g = bimage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }

    /**
     * 将图片导出为jpg格式文件
     *
     * @param outputPath 文件导出完整路径, 包含文件名
     * @param image      BufferedImage图片
     */
    public static void toJpg(String outputPath, BufferedImage image) {
        try {
            // 若使用JPEGImageEncoder进行图片输出, 在程序打包时会出现com.sun.image.codec.jpeg不存在的问题, 故不使用
            ImageIO.write(image, "jpg", new File(outputPath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 图片组合文字
     *
     * @param origin  原图路径
     * @param attach  文字数据
     * @param wrapper 组合条件
     * @return BufferedImage
     */
    public static BufferedImage composeText(String origin, String attach, ComposeWrapper wrapper) {
        BufferedImage originalImage = getBufferedImage(origin);
        return composeText(originalImage, attach, wrapper);
    }

    /**
     * 图片组合文字
     *
     * @param origin  原图
     * @param attach  文字数据
     * @param wrapper 组合条件
     * @return BufferedImage
     */
    public static BufferedImage composeText(BufferedImage origin, String attach, ComposeWrapper wrapper) {
        Pair<Integer, Integer> position = wrapper.getPosition();
        position = position == null ? new Pair<>(0, 0) : position;
        Font font = wrapper.getFont();
        Color color = wrapper.getColor();
        AffineTransform transform = wrapper.getTransform();

        Graphics2D graphics = origin.createGraphics();
        if (font != null) {
            graphics.setFont(font);
        } else {
            font = graphics.getFont();
        }
        if (color != null) {
            graphics.setColor(color);
        }
        if (transform != null) {
            graphics.setTransform(transform);
        }
        graphics.drawString(attach, position.getKey(), position.getValue() + font.getSize());
        graphics.dispose();
        return origin;
    }

    /**
     * 图片组合图片
     *
     * @param origin  原图路径
     * @param attach  附加图片路径
     * @param wrapper 组合条件
     * @return BufferedImage
     */
    public static BufferedImage composeImage(String origin, String attach, ComposeWrapper wrapper) {
        BufferedImage originalImage = getBufferedImage(origin);
        BufferedImage attachedImage = getBufferedImage(attach);
        return composeImage(originalImage, attachedImage, wrapper);
    }

    /**
     * 图片组合图片
     *
     * @param origin  原图
     * @param attach  附加图片
     * @param wrapper 组合条件
     * @return BufferedImage
     */
    public static BufferedImage composeImage(BufferedImage origin, BufferedImage attach, ComposeWrapper wrapper) {
        Pair<Integer, Integer> position = wrapper.getPosition();
        position = position == null ? new Pair<>(0, 0) : position;
        Pair<Integer, Integer> size = wrapper.getImageSize();
        size = size == null ? new Pair<>(attach.getWidth(), attach.getHeight()) : size;
        Composite composite = wrapper.getComposite();
        AffineTransform transform = wrapper.getTransform();

        Graphics2D graphics = origin.createGraphics();
        if (composite != null) {
            graphics.setComposite(composite);
        }
        if (transform != null) {
            graphics.setTransform(transform);
        }
        graphics.drawImage(attach, position.getKey(), position.getValue(), size.getKey(), size.getValue(), null);
        graphics.dispose();
        return origin;
    }

    /**
     * 组合条件封装
     */
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    @EqualsAndHashCode
    public static class ComposeWrapper {
        /**
         * 位置(x, y)
         * <p>
         * 默认为(0, 0)
         */
        private Pair<Integer, Integer> position = new Pair<>(0, 0);

        /**
         * 图片尺寸(width, height)
         */
        private Pair<Integer, Integer> imageSize;

        /**
         * 组合条件
         * <p>
         * 可用于设置透明度
         */
        private Composite composite;

        /**
         * 形变
         */
        private AffineTransform transform;

        /**
         * 字体
         * <p>
         * 仅对文字有效
         */
        private Font font;

        /**
         * 文字颜色
         * <p>
         * 仅对文字有效, 默认为黑色
         */
        private Color color = Color.BLACK;

        /**
         * 设置坐标
         *
         * @param x x
         * @param y y
         * @return this
         */
        public ComposeWrapper setPosition(Integer x, Integer y) {
            position = new Pair<>(x, y);
            return this;
        }

        /**
         * 设置尺寸
         *
         * @param width
         * @param height
         * @return this
         */
        public ComposeWrapper setImageSize(Integer width, Integer height) {
            imageSize = new Pair<>(width, height);
            return this;
        }

        /**
         * 设置透明度
         * <p>
         * 仅对图片有效, 文字透明度通过Font设置
         *
         * @param opacity 透明度
         * @return this
         */
        public ComposeWrapper setOpacity(Float opacity) {
            composite = AlphaComposite.SrcOver.derive(opacity);
            return this;
        }

        /**
         * 设置旋转角度
         * <p>
         * 此操作会将当前坐标作为锚点, 需要在设置坐标后再设置
         *
         * @param angle 角度
         * @return this
         */
        public ComposeWrapper setRotate(Double angle) {
            transform = new AffineTransform();
            transform.rotate(angle, position.getKey(), position.getValue());
            return this;
        }
    }

}