生成裂变海报

使用用户图像、昵称和邀请二维码,及企业logo、名称生成用户的分享裂变海报。
适用场景:拉新裂变活动,生成用户自己的分享裂变海报。

相关代码

ImageProcessException

public class ImageProcessException extends RuntimeException {
    public ImageProcessException() {
    }

    public ImageProcessException(String message) {
        super(message);
    }

    public ImageProcessException(String message, Throwable cause) {
        super(message, cause);
    }

    public ImageProcessException(Throwable cause) {
        super(cause);
    }

    public ImageProcessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

ImageUtils

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;

public class ImageUtils {

    /**
     * 读取本地图片
     *
     * @param imgPath 图片读取路径,示例:"D:\\test.png"
     */
    public static BufferedImage readFromLocal(String imgPath) {
        checkValue(imgPath, "imgPath == null!");
        try {
            return ImageIO.read(new File(imgPath));
        } catch (IOException e) {
            throw new ImageProcessException("读取本地图片出错", e);
        }
    }

    /**
     * 读取图片数据流
     */
    public static BufferedImage readFromStream(InputStream imgStream) {
        checkValue(imgStream, "imgStream == null!");
        try {
            return ImageIO.read(imgStream);
        } catch (IOException e) {
            throw new ImageProcessException("读取图片数据流出错", e);
        }
    }

    /**
     * 读取网络图片
     */
    public static BufferedImage readFromUrl(String imgUrl) {
        checkValue(imgUrl, "imgUrl == null!");
        try {
            URL url = new URL(imgUrl);
            return ImageIO.read(url);
        } catch (IOException e) {
            throw new ImageProcessException("读取网络图片出错", e);
        }
    }

    /**
     * 保存到本地
     *
     * @param imgPath 图片存储路径,示例:"D:\\test.png"
     */
    public static void writeToLocal(BufferedImage image, String imgPath) {
        checkValue(image, "image == null!");
        checkValue(imgPath, "imgPath == null!");

        int index = imgPath.lastIndexOf(".");
        if (index < 0){
            throw new ImageProcessException("图片没有设置保存格式后缀");
        }

        String suffix = imgPath.substring(index + 1);
        image = imageFormat(image, suffix);
        try {
            ImageIO.write(image, suffix, new File(imgPath));
        } catch (IOException e) {
            throw new ImageProcessException("图片保存到本地出错", e);
        }
    }

    /**
     * 保存为 byte数组
     *
     * @param formatName 图片格式,示例:png、jpg、jpeg 等
     */
    public static byte[] writeToBytes(BufferedImage image, String formatName) {
        checkValue(image, "image == null!");
        checkValue(formatName, "formatName == null!");

        image = imageFormat(image, formatName);
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ImageIO.write(image, formatName, os);
            return os.toByteArray();
        } catch (IOException e) {
            throw new ImageProcessException("图片保存为 byte 数组出错", e);
        }
    }

    /**
     * 保存到数据流
     *
     * @param formatName 图片格式,示例:png、jpg、jpeg 等
     */
    public static boolean writeToStream(BufferedImage image, String formatName, OutputStream os) {
        checkValue(image, "image == null!");
        checkValue(formatName, "formatName == null!");
        checkValue(os, "os == null!");

        image = imageFormat(image, formatName);
        try {
            return ImageIO.write(image, formatName, os);
        } catch (IOException e) {
            throw new ImageProcessException("图片保存到数据流出错", e);
        }
    }

    /**
     * 添加文字
     *
     * @param source    源图片
     * @param text      添加的文字
     * @param color     文字颜色
     * @param x         距离左上角的X偏移量
     * @param y         距离左上角的Y偏移量
     */
    public static void addText(final BufferedImage source, String text, Color color, Font font, int x, int y) {
        Graphics2D g = source.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
        g.setStroke(new BasicStroke(3));
        g.setColor(color);
        if (font != null) {
            g.setFont(font);
        }
        if (text != null) {
            g.translate(0, 0);
            g.drawString(text, x, y);
        }
        g.dispose();
    }
 
    /**
     * 添加图片
     *
     * @param source       源图片
     * @param addImage     添加的图片
     * @param alpha        透明度。0.0~1.0: 完全透明~完全不透明
     * @param x            距离左上角的X偏移量
     * @param y            距离左上角的Y偏移量
     */
    public static void addImage(final BufferedImage source, BufferedImage addImage, float alpha, int x, int y) {
        Graphics2D g2d = source.createGraphics();
        int width = addImage.getWidth();
        int height = addImage.getHeight();
        // 在图形和图像中实现混合和透明效果
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        g2d.drawImage(addImage, x, y, width, height, null);
        g2d.dispose();
    }

    /**
     *  图片尺寸调整
     *
     * @param source       源图片
     * @param width        宽
     * @param height       高
     */
    public static BufferedImage resizeImage(BufferedImage source, int width, int height){
        // 获取源图片透明度类型
        int type = source.getColorModel().getTransparency();
        int sourceWidth = source.getWidth();
        int sourceHeight = source.getHeight();
        BufferedImage image = new BufferedImage(width, height, type);
        Graphics2D graphics2d = image.createGraphics();
        // 抗锯齿
        graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 笔画归一化控制提示值 - 几何应归一化,以提高线条的均匀性或间距以及整体美感。
        graphics2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
        // 渲染提示值 - 选择渲染算法以优化输出质量。
        graphics2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        Image tmp = source.getScaledInstance(sourceWidth, sourceHeight, Image.SCALE_SMOOTH);
        graphics2d.drawImage(tmp, 0, 0, width, height, 0, 0, sourceWidth, sourceHeight, null);
        graphics2d.dispose();
        return image;
    }

    /**
     * 正方形图片转圆形
     * 
     * @param source       源图片
     * @param diameter     直径
     */
    public static BufferedImage convertCircular(BufferedImage source, int diameter){
        // 透明底的图片
        BufferedImage image = new BufferedImage(diameter, diameter, BufferedImage.TYPE_4BYTE_ABGR);
        Ellipse2D.Double shape = new Ellipse2D.Double(0, 0,diameter, diameter);
        Graphics2D g2 = image.createGraphics();
        g2.setClip(shape);
        // 抗锯齿
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 笔画归一化控制提示值 - 几何应归一化,以提高线条的均匀性或间距以及整体美感。
        g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
        // 渲染提示值 - 选择渲染算法以优化输出质量。
        g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        // 抖动提示值 - 渲染几何时不要抖动。
        g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
        g2.drawImage(source, 0, 0,diameter, diameter, null);
        // 设置颜色
        g2.setBackground(Color.green);
        g2.dispose();
        return image;
    }

    private static void checkValue(Object value, String errorMsg) {
        if (value == null) {
            throw new IllegalArgumentException(errorMsg);
        }
    }

    private static BufferedImage imageFormat(BufferedImage image, String formatName) {

        if (!formatName.equalsIgnoreCase("jpg") && !formatName.equalsIgnoreCase("jpeg")) {
            return image;
        }

        // 处理 jpg 和 jpeg 格式
        BufferedImage formatImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_BGR);
        Graphics g = formatImage.getGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return formatImage;
    }
}

测试

public class ImageUtilsTest {

    public static void main(String[] args) {
        ClassLoader loader = ImageUtilsTest.class.getClassLoader();
        BufferedImage image = readFromStream(loader.getResourceAsStream("海报模板.png"));
        image = resizeImage(image, 828, 1792);

        BufferedImage qrCodeImage = readFromStream(loader.getResourceAsStream("qrCode.png"));
        qrCodeImage = resizeImage(qrCodeImage, 150, 150);

        BufferedImage logoImage = readFromStream(loader.getResourceAsStream("logo.png"));
        logoImage = resizeImage(logoImage, 70, 70);

        BufferedImage userImage = readFromStream(loader.getResourceAsStream("用户图像.jpg"));
        userImage = convertCircular(userImage, userImage.getHeight());
        userImage = resizeImage(userImage, 70, 70);

        Font font = new Font("Microsoft YaHei UI Light", Font.BOLD, 26);
        addText(image,"测试",  new Color(0,0,0), font,131, 127);
        addText(image,"张三股份有限公司",  new Color(0,0,0),font,  560, 127);
        addImage(image, userImage, 1, 40, 80);
        addImage(image, logoImage, 1, 470, 80);
        addImage(image, qrCodeImage, 1,40, 1571);
        writeToLocal(image, getProjectPath() + File.separator + "Image-" + System.currentTimeMillis() +".jpeg");
    }

    private static String getProjectPath() {
        return System.getProperty("user.dir");
    }
}

测试结果

image-20211011134236062

posted @ 2021-10-17 16:31  crazy_dev  阅读(204)  评论(0编辑  收藏  举报