Seal.java 10.5 KB
package com.lego.common.seal;

import cn.hutool.core.util.StrUtil;
import lombok.Data;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;

/**
 * @author GaoYongYi
 * @date 2023/7/25 14:51
 */

@Data
public class Seal {
    // 起始位置
    private static final int INIT_BEGIN = 2;

    // 尺寸
    private Integer size;
    // 颜色
    private Color color;
    // 主字
    private SealFont mainFont;
    // 副字
    private SealFont viceFont;
    // 抬头
    private SealFont titleFont;
    // 中心字
    private SealFont centerFont;
    // 边线圆
    private SealCircle borderCircle;
    // 内边线圆
    private SealCircle borderInnerCircle;
    // 内线圆
    private SealCircle innerCircle;
    // 边线框
    private Integer borderSquare;
    // 加字
    private String stamp;

    public byte[] drawPrivate(String text) throws IOException {
        mainFont = SealFont.builder().text(text).build();
        String[] fontTexts = text.split("");
        int fixH = 18;
        int fixW = 15;

        //1.画布
        BufferedImage bi = new BufferedImage((fixW * fontTexts.length) + 3, fixH + 3, BufferedImage.TYPE_4BYTE_ABGR);
        //2.画笔
        Graphics2D g2d = bi.createGraphics();
        //2.1设置画笔颜色
        g2d.setPaint(Color.RED);
        //2.2抗锯齿设置
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        //画边框
        g2d.drawRect(1, 1, fixW * fontTexts.length, fixH);
        //3.写签名
        Font f = new Font(mainFont.getFamily(), Font.BOLD, fixW);
        g2d.setFont(f);
        //循环写字
        for (int i = 0; i < fontTexts.length; i++) {
            g2d.drawString(fontTexts[i], ((fixH - 3) * i) + 1 , fixW);
        }
        g2d.dispose();
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ImageIO.write(bi, "PNG", output);
        return output.toByteArray();


    }


    /**
     * 画公章
     */
    public String draw(String surround, String subheading, String security) throws Exception {
        if (StrUtil.isEmpty(surround)) {
            return null;
        }
        if (size == null || size == 0) {
            size = 300;
        }
        String pngPath = "E:\\templateFile\\test.png";
        //1.画布
        BufferedImage bi = new BufferedImage(size, size, BufferedImage.TYPE_4BYTE_ABGR);

        //2.画笔
        Graphics2D g2d = bi.createGraphics();

        //2.1抗锯齿设置
        //文本不抗锯齿,否则圆中心的文字会被拉长
        RenderingHints hints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        //其他图形抗锯齿
        hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHints(hints);

        //2.2设置背景透明度
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 0));

        //2.3填充矩形
        g2d.fillRect(0, 0, size, size);

        //2.4重设透明度,开始画图
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 1));

        //2.5设置画笔颜色
        g2d.setPaint(color == null ? Color.RED : color);
        if (borderCircle == null) {
            borderCircle = SealCircle.builder().line(5).width(147).height(147).build();
        }
        if (mainFont == null) {
            mainFont = SealFont.builder().text(surround).size(50).build();
        }
        //画圆
        drawCircle(g2d, borderCircle, INIT_BEGIN, INIT_BEGIN);
        int borderCircleWidth = borderCircle.getWidth();
        int borderCircleHeight = borderCircle.getHeight();
        SealFont centerFont = SealFont.builder().text("★").size(115).build();
        //画五角形
        drawFont(g2d, borderCircleWidth * 2, borderCircleHeight * 2, centerFont);
        if (StrUtil.isNotBlank(subheading)) {
            SealFont subheadingFont = SealFont.builder().text(subheading).size(28).space(8.0).margin(80).build();
            drawFont(g2d, borderCircleWidth * 2, borderCircleHeight * 2, subheadingFont);
        }
        drawArcFont4Circle(g2d, borderCircleHeight, mainFont, true);
        if (StrUtil.isNotBlank(security)) {
            SealFont securityFont = SealFont.builder().text(security).size(25).build();
            drawArcFont4Circle(g2d, borderCircleHeight, securityFont, false);
        }


        g2d.dispose();
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        ImageIO.write(bi, "PNG", output);
        //ImageIO.write(bi, "PNG", new File("E:\\templateFile\\test.png"));

        return Base64.getEncoder().encodeToString(output.toByteArray());
    }

    /**
     * 画圆
     */
    private static void drawCircle(Graphics2D g2d, SealCircle circle, int x, int y) {
        if (circle == null) {
            return;
        }

        //1.圆线条粗细默认是圆直径的1/35
        int lineSize = circle.getLine() == null ? circle.getHeight() * 2 / (35) : circle.getLine();

        //2.画圆
        g2d.setStroke(new BasicStroke(lineSize));
        g2d.drawOval(x, y, circle.getWidth() * 2, circle.getHeight() * 2);
    }

    private static void drawArcFont4Circle(Graphics2D g2d, int circleRadius, SealFont font, boolean isTop) {
        if (font == null) {
            return;
        }

        //1.字体长度
        int textLen = font.getText().length();

        //2.字体大小,默认根据字体长度动态设定
        int size = font.getSize() == null ? (55 - textLen * 2) : font.getSize();

        //3.字体样式
        int style = font.getBold() ? Font.BOLD : Font.PLAIN;

        //4.构造字体
        Font f = new Font(font.getFamily(), style, size);

        FontRenderContext context = g2d.getFontRenderContext();
        Rectangle2D rectangle = f.getStringBounds(font.getText(), context);

        //5.文字之间间距,默认动态调整
        double space;

        if (textLen == 1) {
            space = 0;
        } else {
            if (isTop) {
                space = 360 * 0.7 / textLen * 1.7;
            } else {
                space = 360 * 0.3 / textLen * 1.7;
            }
        }

        //7.写字
        double newRadius = circleRadius + rectangle.getY();
        double radianPerInterval = 2 * Math.asin(space / (2 * newRadius));

        double fix = 0.06;
        if (isTop) {
            fix = 0.25;
        }
        double firstAngle;
        if (!isTop) {
            if (textLen % 2 == 1) {
                firstAngle = Math.PI + Math.PI / 2 - (textLen - 1) * radianPerInterval / 2.0 - fix;
            } else {
                firstAngle = Math.PI + Math.PI / 2 - ((textLen / 2.0 - 0.5) * radianPerInterval) - fix;
            }
        } else {
            if (textLen % 2 == 1) {
                firstAngle = (textLen - 1) * radianPerInterval / 2.0 + Math.PI / 2 + fix;
            } else {
                firstAngle = (textLen / 2.0 - 0.5) * radianPerInterval + Math.PI / 2 + fix;
            }
        }

        for (int i = 0; i < textLen; i++) {
            double theta;
            double thetaX;
            double thetaY;

            if (isTop) {
                theta = firstAngle - i * radianPerInterval;
                thetaX = newRadius * Math.sin(Math.PI / 2 - theta);
                thetaY = newRadius * Math.cos(theta - Math.PI / 2);
            } else {
                theta = firstAngle + i * radianPerInterval;
                thetaX = newRadius * Math.sin(Math.PI / 2 - theta);
                thetaY = newRadius * Math.cos(theta - Math.PI / 2) - 17;
            }


            AffineTransform transform;
            if (!isTop) {
                transform = AffineTransform.getRotateInstance(Math.PI + Math.PI / 2 - theta);
            } else {
                transform = AffineTransform.getRotateInstance(Math.PI / 2 - theta + Math.toRadians(15));
            }
            Font f2 = f.deriveFont(transform);
            g2d.setFont(f2);
            g2d.drawString(font.getText().substring(i, i + 1), (float) (circleRadius + thetaX + INIT_BEGIN), (float) (circleRadius - thetaY + INIT_BEGIN));
        }
    }

    /**
     * 画文字
     */
    private static void drawFont(Graphics2D g2d, int circleWidth, int circleHeight, SealFont font) {
        if (font == null) {
            return;
        }

        //1.字体长度
        int textLen = font.getText().length();

        //2.字体大小,默认根据字体长度动态设定
        int size = font.getSize();

        //3.字体样式
        int style = font.getBold() ? Font.BOLD : Font.PLAIN;

        //4.构造字体
        Font f = new Font(font.getFamily(), style, size);
        g2d.setFont(f);

        FontRenderContext context = g2d.getFontRenderContext();
        String[] fontTexts = font.getText().split("");
        if (fontTexts.length > 1) {
            //开始位置
            double start = circleWidth / 4;
            //写完所有字所需要位置
            double need = circleWidth - (circleWidth / 4 * 2);
            //每个字所需要位置
            double wordProportion = circleWidth / 11;
            //间隔位置
            double spaceNeed = (need / fontTexts.length) - wordProportion;
            double every = wordProportion + spaceNeed;

            double step = start;
            for (String fontText : fontTexts) {
                Rectangle2D rectangle2D = f.getStringBounds(fontText, context);
                float margin = font.getMargin() == null ?
                    (float) (circleHeight / 2 - rectangle2D.getCenterY()) :
                    (float) (circleHeight / 2 - rectangle2D.getCenterY()) + (float) font.getMargin();
                g2d.drawString(fontText, (float) (step - rectangle2D.getCenterX()), margin);
                step = step + every + ((wordProportion + spaceNeed) / fontTexts.length) + (circleWidth / fontTexts.length / 24);
            }
        } else {
            Rectangle2D rectangle2D = f.getStringBounds(font.getText(), context);
            //5.设置上边距,默认在中心report/personalResultRecord/list
            float margin = font.getMargin() == null ?
                (float) (circleHeight / 2 - rectangle2D.getCenterY()) :
                (float) (circleHeight / 2 - rectangle2D.getCenterY()) + (float) font.getMargin();
            g2d.drawString(font.getText(), (float) (circleWidth / 2 - rectangle2D.getCenterX()), margin);
        }
    }
}