Java中生成指定字体的印章

文章目录

  • 1.引入字体
    • 2.Windows环境下
    • 3. Linux环境下
  • 生成印章
  • 测试类
  • 绘制方章
  • 测试类

1.引入字体

2.Windows环境下

在这里插入图片描述
在这里插入图片描述如果在Windows上安装JAVA环境时,没有安装单独的jre1.8.0_141的话。那么字体就只放到\jdk1.8.0_141\jre\lib\fonts目前下。

3. Linux环境下

cat /etc/profile
在这里插入图片描述
找到上方的JAVA_HOME路径
[root@iZ2zeddfx87fxxx4m4dlxu8dZ fonts]# pwd #进入以下目录下
/home/jdk/jdk1.8.0_181/jre/lib/fonts
[root@iZ2zeddfx87fxxx4m4dlxu8dZ fonts]# mkdir fallback #创建一个空目录,用于放置外部字体
在这里插入图片描述
然后执行
[root@iZ2zeddfx87fw4m4dlxu8dZ fallback]# mkfontscale #不知道不执行是否可以
[root@iZ2zeddfx87fw4m4dlxu8dZ fallback]# mkfontdir #这个必须执行
在这里插入图片描述
这样就在fallback目录下多出了两个文件。注意不执行上方的mkfontscale和mkfontdir。即使把字体放到了指定的fonts目录下了。在CentOS下使用字体也会找不到的。会使用其他默认字体代替。这一点和Window上的不同。
我们可以通过比较两者fonts目录下的文件可以发现。
在这里插入图片描述

生成印章

Seal类代码:

package cn.com.yuanquanyun.bjca_scan;

import lombok.Builder;
import lombok.Getter;
import org.springframework.util.ResourceUtils;

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.File;
import java.io.IOException;

@Getter
@Builder
public class Seal {
    // 起始位置
    private static final int INIT_BEGIN = 5;

    // 尺寸
    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[] draw(String imgFmt) throws Exception {
        if (borderSquare != null) {
            return draw2(imgFmt); // 画私章
        }

        //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);

        //3.画边线圆
        if (borderCircle != null) {
            drawCircle(g2d, borderCircle, INIT_BEGIN, INIT_BEGIN);
        } else {
            throw new Exception("BorderCircle can not null!");
        }

        int borderCircleWidth = borderCircle.getWidth();
        int borderCircleHeight = borderCircle.getHeight();

        //4.画内边线圆
        if (borderInnerCircle != null) {
            int x = INIT_BEGIN + borderCircleWidth - borderInnerCircle.getWidth();
            int y = INIT_BEGIN + borderCircleHeight - borderInnerCircle.getHeight();
            drawCircle(g2d, borderInnerCircle, x, y);
        }

        //5.画内环线圆
        if (innerCircle != null) {
            int x = INIT_BEGIN + borderCircleWidth - innerCircle.getWidth();
            int y = INIT_BEGIN + borderCircleHeight - innerCircle.getHeight();
            drawCircle(g2d, innerCircle, x, y);
        }

        //6.画弧形主文字
        if (borderCircleHeight != borderCircleWidth) {
            drawArcFont4Oval(g2d, borderCircle, mainFont, true);
        } else {
            drawArcFont4Circle(g2d, borderCircleHeight, mainFont, true);
        }

        //7.画弧形副文字
        if (borderCircleHeight != borderCircleWidth) {
            drawArcFont4Oval(g2d, borderCircle, viceFont, false);
        } else {
            drawArcFont4Circle(g2d, borderCircleHeight, viceFont, false);
        }

        //8.画中心字
        drawFont(g2d, (borderCircleWidth + INIT_BEGIN) * 2, (borderCircleHeight + INIT_BEGIN) * 2, centerFont);

        //9.画抬头文字
        drawFont(g2d, (borderCircleWidth + INIT_BEGIN) * 2, (borderCircleHeight + INIT_BEGIN) * 2, titleFont);

        g2d.dispose();

        //
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        boolean png = ImageIO.write(bi, imgFmt, outputStream);
        byte[] imgBytes = outputStream.toByteArray();
        outputStream.flush();
        outputStream.close();
        return imgBytes;
    }

    public byte[] draw(String pngPath,String imgFmt) throws Exception {//如果只是生成印章字节数组,不进行输出的话,传入的pngPath,无用
        byte[] imgBytes = draw(imgFmt);
        return imgBytes;
//        FileOutputStream fileOutputStream = new FileOutputStream(new File(pngPath));
//        fileOutputStream.write(imgBytes);
    }

    /**
     * 绘制圆弧形文字
     */
    private static void drawArcFont4Circle(Graphics2D g2d, int circleRadius, SealFont font, boolean isTop) throws IOException, FontFormatException {
        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);//默认从JRE中的fonts目录下读取
        //
        File file = new File("config/font/gzkzzt.ttf");//如果如CSDN上方描述的那样已经把字体放到jre下了。这里就不用写死指定了
//        System.out.println("已读取字体文件");
        Font f = Font.createFont(Font.TRUETYPE_FONT, file);
        f = f.deriveFont(style,size);

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

        //5.文字之间间距,默认动态调整
        double space;
        if (font.getSpace() != null) {
            space = font.getSpace();
        } else {
            if (textLen == 1) {
                space = 0;
            } else {
                space = rectangle.getWidth() / (textLen - 1) * 0.9;
            }
        }

        //6.距离外圈距离
        int margin = font.getMargin() == null ? INIT_BEGIN : font.getMargin();

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

        double fix = 0.04;
        if (isTop) {
            fix = 0.18;
        }
        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);
            }

            AffineTransform transform;
            if (!isTop) {
                transform = AffineTransform.getRotateInstance(Math.PI + Math.PI / 2 - theta);
            } else {
                transform = AffineTransform.getRotateInstance(Math.PI / 2 - theta + Math.toRadians(8));
            }
            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 drawArcFont4Oval(Graphics2D g2d, SealCircle sealCircle, SealFont font, boolean isTop) {
        if (font == null) {
            return;
        }
        float radiusX = sealCircle.getWidth();
        float radiusY = sealCircle.getHeight();
        float radiusWidth = radiusX + sealCircle.getLine();
        float radiusHeight = radiusY + sealCircle.getLine();

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

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

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

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

        //5.总的角跨度
        double totalArcAng = font.getSpace() * textLen;

        //6.从边线向中心的移动因子
        float minRat = 0.90f;

        double startAngle = isTop ? -90f - totalArcAng / 2f : 90f - totalArcAng / 2f;
        double step = 0.5;
        int alCount = (int) Math.ceil(totalArcAng / step) + 1;
        double[] angleArr = new double[alCount];
        double[] arcLenArr = new double[alCount];
        int num = 0;
        double accArcLen = 0.0;
        angleArr[num] = startAngle;
        arcLenArr[num] = accArcLen;
        num++;
        double angR = startAngle * Math.PI / 180.0;
        double lastX = radiusX * Math.cos(angR) + radiusWidth;
        double lastY = radiusY * Math.sin(angR) + radiusHeight;
        for (double i = startAngle + step; num < alCount; i += step) {
            angR = i * Math.PI / 180.0;
            double x = radiusX * Math.cos(angR) + radiusWidth, y = radiusY * Math.sin(angR) + radiusHeight;
            accArcLen += Math.sqrt((lastX - x) * (lastX - x) + (lastY - y) * (lastY - y));
            angleArr[num] = i;
            arcLenArr[num] = accArcLen;
            lastX = x;
            lastY = y;
            num++;
        }
        double arcPer = accArcLen / textLen;
        for (int i = 0; i < textLen; i++) {
            double arcL = i * arcPer + arcPer / 2.0;
            double ang = 0.0;
            for (int p = 0; p < arcLenArr.length - 1; p++) {
                if (arcLenArr[p] <= arcL && arcL <= arcLenArr[p + 1]) {
                    ang = (arcL >= ((arcLenArr[p] + arcLenArr[p + 1]) / 2.0)) ? angleArr[p + 1] : angleArr[p];
                    break;
                }
            }
            angR = (ang * Math.PI / 180f);
            Float x = radiusX * (float) Math.cos(angR) + radiusWidth;
            Float y = radiusY * (float) Math.sin(angR) + radiusHeight;
            double qxang = Math.atan2(radiusY * Math.cos(angR), -radiusX * Math.sin(angR));
            double fxang = qxang + Math.PI / 2.0;

            int subIndex = isTop ? i : textLen - 1 - i;
            String c = font.getText().substring(subIndex, subIndex + 1);

            //获取文字高宽
            FontMetrics fm = sun.font.FontDesignMetrics.getMetrics(f);
            int w = fm.stringWidth(c), h = fm.getHeight();

            if (isTop) {
                x += h * minRat * (float) Math.cos(fxang);
                y += h * minRat * (float) Math.sin(fxang);
                x += -w / 2f * (float) Math.cos(qxang);
                y += -w / 2f * (float) Math.sin(qxang);
            } else {
                x += (h * minRat) * (float) Math.cos(fxang);
                y += (h * minRat) * (float) Math.sin(fxang);
                x += w / 2f * (float) Math.cos(qxang);
                y += w / 2f * (float) Math.sin(qxang);
            }

            // 旋转
            AffineTransform affineTransform = new AffineTransform();
            affineTransform.scale(0.8, 1);
            if (isTop)
                affineTransform.rotate(Math.toRadians((fxang * 180.0 / Math.PI - 90)), 0, 0);
            else
                affineTransform.rotate(Math.toRadians((fxang * 180.0 / Math.PI + 180 - 90)), 0, 0);
            Font f2 = f.deriveFont(affineTransform);
            g2d.setFont(f2);
            g2d.drawString(c, x.intValue() + INIT_BEGIN, y.intValue() + 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() == null ? (55 - textLen * 2) : 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("\n");
        if (fontTexts.length > 1) {
            int y = 0;
            for (String fontText : fontTexts) {
                y += Math.abs(f.getStringBounds(fontText, context).getHeight());
            }
            //5.设置上边距
            float margin = INIT_BEGIN + (float) (circleHeight / 2 - y / 2);
            for (String fontText : fontTexts) {
                Rectangle2D rectangle2D = f.getStringBounds(fontText, context);
                g2d.drawString(fontText, (float) (circleWidth / 2 - rectangle2D.getCenterX()), margin);
                margin += Math.abs(rectangle2D.getHeight());
            }
        } else {
            Rectangle2D rectangle2D = f.getStringBounds(font.getText(), context);
            //5.设置上边距,默认在中心
            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);
        }
    }

    /**
     * 画圆
     */
    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);
    }

    /**
     * 画私章
     */
    public byte[] draw2(String imgFmt) throws Exception {
        if (mainFont == null || mainFont.getText().length() < 2 || mainFont.getText().length() > 4) {
            throw new IllegalArgumentException("请输入2-4个字");
        }

        int fixH = 18;
        int fixW = 2;

        //1.画布
        BufferedImage bi = new BufferedImage(size, size / 2, 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);

        //3.写签名
        int marginW = fixW + borderSquare;
        float marginH;
        FontRenderContext context = g2d.getFontRenderContext();
        Rectangle2D rectangle;
        Font f;

        if (mainFont.getText().length() == 2) {
            if (stamp != null && stamp.trim().length() > 0) {
                bi = drawThreeFont(bi, g2d, mainFont.append(stamp), borderSquare, size, fixH, fixW, true);
            } else {
                f = new Font(mainFont.getFamily(), Font.BOLD, mainFont.getSize());
                g2d.setFont(f);
                rectangle = f.getStringBounds(mainFont.getText().substring(0, 1), context);
                marginH = (float) (Math.abs(rectangle.getCenterY()) * 2 + marginW) + fixH - 4;
                g2d.drawString(mainFont.getText().substring(0, 1), marginW, marginH);
                marginW += Math.abs(rectangle.getCenterX()) * 2 + (mainFont.getSpace() == null ? INIT_BEGIN : mainFont.getSpace());
                g2d.drawString(mainFont.getText().substring(1), marginW, marginH);

                //拉伸
                BufferedImage nbi = new BufferedImage(size, size, bi.getType());
                Graphics2D ng2d = nbi.createGraphics();
                ng2d.setPaint(Color.RED);
                ng2d.drawImage(bi, 0, 0, size, size, null);

                //画正方形
                ng2d.setStroke(new BasicStroke(borderSquare));
                ng2d.drawRect(0, 0, size, size);
                ng2d.dispose();
                bi = nbi;
            }
        } else if (mainFont.getText().length() == 3) {
            if (stamp != null && stamp.trim().length() > 0) {
                bi = drawFourFont(bi, mainFont.append(stamp), borderSquare, size, fixH, fixW);
            } else {
                bi = drawThreeFont(bi, g2d, mainFont, borderSquare, size, fixH, fixW, false);
            }
        } else {
            bi = drawFourFont(bi, mainFont, borderSquare, size, fixH, fixW);
        }

        g2d.dispose();

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        boolean png = ImageIO.write(bi,imgFmt, outputStream);
        byte[] imgBytes = outputStream.toByteArray();
        outputStream.flush();
        outputStream.close();
        return imgBytes;
    }

    /**
     * 画三字
     */
    private static BufferedImage drawThreeFont(BufferedImage bi, Graphics2D g2d, SealFont font, int lineSize, int imageSize, int fixH, int fixW, boolean isWithYin) {
        fixH -= 9;
        int marginW = fixW + lineSize;
        //设置字体
        Font f = new Font(font.getFamily(), Font.BOLD, font.getSize());
        g2d.setFont(f);
        FontRenderContext context = g2d.getFontRenderContext();
        Rectangle2D rectangle = f.getStringBounds(font.getText().substring(0, 1), context);
        float marginH = (float) (Math.abs(rectangle.getCenterY()) * 2 + marginW) + fixH;
        int oldW = marginW;

        if (isWithYin) {
            g2d.drawString(font.getText().substring(2, 3), marginW, marginH);
            marginW += rectangle.getCenterX() * 2 + (font.getSpace() == null ? INIT_BEGIN : font.getSpace());
        } else {
            marginW += rectangle.getCenterX() * 2 + (font.getSpace() == null ? INIT_BEGIN : font.getSpace());
            g2d.drawString(font.getText().substring(0, 1), marginW, marginH);
        }

        //拉伸
        BufferedImage nbi = new BufferedImage(imageSize, imageSize, bi.getType());
        Graphics2D ng2d = nbi.createGraphics();
        ng2d.setPaint(Color.RED);
        ng2d.drawImage(bi, 0, 0, imageSize, imageSize, null);

        //画正方形
        ng2d.setStroke(new BasicStroke(lineSize));
        ng2d.drawRect(0, 0, imageSize, imageSize);
        ng2d.dispose();
        bi = nbi;

        g2d = bi.createGraphics();
        g2d.setPaint(Color.RED);
        g2d.setFont(f);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        if (isWithYin) {
            g2d.drawString(font.getText().substring(0, 1), marginW, marginH += fixH);
            rectangle = f.getStringBounds(font.getText(), context);
            marginH += Math.abs(rectangle.getHeight());
            g2d.drawString(font.getText().substring(1), marginW, marginH);
        } else {
            g2d.drawString(font.getText().substring(1, 2), oldW, marginH += fixH);
            rectangle = f.getStringBounds(font.getText(), context);
            marginH += Math.abs(rectangle.getHeight());
            g2d.drawString(font.getText().substring(2, 3), oldW, marginH);
        }
        return bi;
    }

    /**
     * 画四字
     */
    private static BufferedImage drawFourFont(BufferedImage bi, SealFont font, int lineSize, int imageSize, int fixH, int fixW) throws IOException, FontFormatException {
        int marginW = fixW + lineSize;
        //拉伸
        BufferedImage nbi = new BufferedImage(imageSize, imageSize, bi.getType());
        Graphics2D ng2d = nbi.createGraphics();
        ng2d.setPaint(Color.RED);
        ng2d.drawImage(bi, 0, 0, imageSize, imageSize, null);

        //画正方形
        ng2d.setStroke(new BasicStroke(lineSize));
        ng2d.drawRect(0, 0, imageSize, imageSize);
        ng2d.dispose();
        bi = nbi;

        Graphics2D g2d = bi.createGraphics();
        g2d.setPaint(Color.RED);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        FontRenderContext context = g2d.getFontRenderContext();

        //Font f = new Font(font.getFamily(), Font.BOLD, font.getSize());//默认读取JDK 下的font字体
        File file = new File("config/font/simsun.ttf");
        System.out.println("已读取字体文件");
        Font f = Font.createFont(Font.TRUETYPE_FONT, file);
        f = f.deriveFont(Font.BOLD, font.getSize());

        g2d.setFont(f);
        Rectangle2D rectangle = f.getStringBounds(font.getText().substring(0, 1), context);
        float marginH = (float) (Math.abs(rectangle.getCenterY()) * 2 + marginW) + fixH;

        g2d.drawString(font.getText().substring(2, 3), marginW, marginH);
        int oldW = marginW;
        marginW += Math.abs(rectangle.getCenterX()) * 2 + (font.getSpace() == null ? INIT_BEGIN : font.getSpace());

        g2d.drawString(font.getText().substring(0, 1), marginW, marginH);
        marginH += Math.abs(rectangle.getHeight());

        g2d.drawString(font.getText().substring(3, 4), oldW, marginH);

        g2d.drawString(font.getText().substring(1, 2), marginW, marginH);

        return bi;
    }


    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public SealFont getMainFont() {
        return mainFont;
    }

    public void setMainFont(SealFont mainFont) {
        this.mainFont = mainFont;
    }

    public SealFont getViceFont() {
        return viceFont;
    }

    public void setViceFont(SealFont viceFont) {
        this.viceFont = viceFont;
    }

    public SealFont getTitleFont() {
        return titleFont;
    }

    public void setTitleFont(SealFont titleFont) {
        this.titleFont = titleFont;
    }

    public SealFont getCenterFont() {
        return centerFont;
    }

    public void setCenterFont(SealFont centerFont) {
        this.centerFont = centerFont;
    }

    public SealCircle getBorderCircle() {
        return borderCircle;
    }

    public void setBorderCircle(SealCircle borderCircle) {
        this.borderCircle = borderCircle;
    }

    public SealCircle getBorderInnerCircle() {
        return borderInnerCircle;
    }

    public void setBorderInnerCircle(SealCircle borderInnerCircle) {
        this.borderInnerCircle = borderInnerCircle;
    }

    public SealCircle getInnerCircle() {
        return innerCircle;
    }

    public void setInnerCircle(SealCircle innerCircle) {
        this.innerCircle = innerCircle;
    }

    public Integer getBorderSquare() {
        return borderSquare;
    }

    public void setBorderSquare(Integer borderSquare) {
        this.borderSquare = borderSquare;
    }

    public String getStamp() {
        return stamp;
    }

    public void setStamp(String stamp) {
        this.stamp = stamp;
    }
}

SealCircle类:

package cn.com.yuanquanyun.bjca_scan;

import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class SealCircle {
    private Integer line;
    private Integer width;
    private Integer height;

    public Integer getLine() {
        return line;
    }

    public void setLine(Integer line) {
        this.line = line;
    }

    public Integer getWidth() {
        return width;
    }

    public void setWidth(Integer width) {
        this.width = width;
    }

    public Integer getHeight() {
        return height;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }
}

SealFont类:

package cn.com.yuanquanyun.bjca_scan;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class SealFont {
    private String text;
    private String family;
    private Integer size;
    private Boolean bold;
    private Double space;
    private Integer margin;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public void setFamily(String family) {
        this.family = family;
    }

    public Integer getSize() {
        return size;
    }

    public void setSize(Integer size) {
        this.size = size;
    }

    public void setBold(Boolean bold) {
        this.bold = bold;
    }

    public Double getSpace() {
        return space;
    }

    public void setSpace(Double space) {
        this.space = space;
    }

    public Integer getMargin() {
        return margin;
    }

    public void setMargin(Integer margin) {
        this.margin = margin;
    }

    public String getFamily() {
        return family == null ? "宋体" : family;
    }

    public boolean getBold() {
        return bold == null ? true : bold;
    }

    public SealFont append(String text) {
        this.text += text;
        return this;
    }

}

和印章生成相关的主要是以上这三个类。

测试类

public static void myTestCompanySeal() throws Exception {

        String mainText = "北京某某科技有限公司";
        String titleText = "合同专用章";
        String viceText = "0192834567";

        String keZhang = "公章刻章字体";//它会根据字体名称 去 jre下的font里去找这个字体。没有的话,会用默认字体。可以灵活控制Font的字体。上方的 Seal类中,采用的是读取本地的字体文件。而不是去jre 下的font里去找。两种方式都可以。
        String songTi = "宋体";//同上

        // 使用工具生成印章图片
        try {
            Seal.SealBuilder builder = Seal.builder();
            builder.size(432);
            builder.borderCircle(SealCircle.builder().line(10).width(210).height(210).build());

            if (mainText != null) {
                // 根据主文字长度,设置字体大小及边距
                int length = mainText.length();
                int size = 70;
                double space = 50;

                if (length > 0 && length <= 8) {
                    space = 70;
                } else if (length == 9) {
                    space = 60;
                } else if (length == 10) {
                    space = 55;
                } else if (length == 11) {
                    space = 50;
                } else if (length == 12) {
                    space = 45;
                } else if (length == 13) {
                    space = 40;
                } else if (length == 14) {
                    space = 40;
                } else if (length == 15) {
                    space = 37;
                } else if (length == 16) {
                    size = 65;
                    space = 35;
                } else if (length == 17) {
                    size = 65;
                    space = 35;
                } else if (length == 18) {
                    size = 63;
                    space = 33;
                } else if (length == 19) {
                    size = 61;
                    space = 31;
                } else if (length == 20) {
                    size = 60;
                    space = 30;
                } else if (length == 21) {
                    size = 58;
                    space = 29;
                } else if (length == 22) {
                    size = 56;
                    space = 28;
                } else if (length == 23) {
                    size = 54;
                    space = 27;
                } else if (length == 24) {
                    size = 54;
                    space = 27;
                } else if (length == 25) {
                    size = 52;
                    space = 26;
                } else {
                    size = 60 - (length - 20) * 2;
                    space = 30 - (length - 20) * 0.5;
                }

                builder.mainFont(SealFont.builder().text(mainText).family(keZhang).size(size).space(space).margin(10).build());
            }
            //
            builder.centerFont(SealFont.builder().family(songTi).text("★").size(140).build());
            //
            if (titleText != null) {
                builder.titleFont(SealFont.builder().family(keZhang).text(titleText).size(50).space(0.0).margin(100).build());
            }

            // 副文字 数字编号
            if (viceText != null) {
                builder.viceFont(SealFont.builder().family(songTi).text(viceText).size(30).space(20.0).margin(-10).build());
            }
            //
            Seal build = builder.build();
            byte[] draw = build.draw("png");

            FileUtil.writeBytes(draw, "C:\\Users\\Administrator\\Desktop\\seal.jpg");

        } catch (Exception e) {
            throw new CustomException("生成印章失败");
        }
    }
public static void main(String[] args) throws Exception {
//        myTestCompanySeal();//生成企业圆章
       // String legalName="王大拿";//三个字
        String legalName="王大拿印";//四个字
        String imgFmt = "png";
        String fontType = "宋体";
        makeLegalSeal(legalName,imgFmt,fontType);//生成个人私章
    }

效果:如下
请添加图片描述
测试私人印章类:

    private static byte[] makeLegalSeal(String legalName,String imgFmt,String fontType) throws Exception {
        // 加载刻章字体
//        String keZhang = "公章刻章字体";//这里的名字是字体名字,可以通过双击STXINGKA.ttf文件可以看到第一行的 字体名称: 公章刻章字体  华文行楷
        String keZhang = fontType;//这里的名字是字体名字,可以通过双击STXINGKA.ttf文件可以看到第一行的 字体名称: 公章刻章字体  华文行楷 "Lucida Bright"
        byte[] draw =Seal.builder()
                .size(300)
                .borderSquare(16)
                .mainFont(SealFont.builder().text(legalName).family(keZhang).size(120).build())
                .build()
                .draw(imgFmt);
        FileUtil.writeBytes(draw, "C:\\Users\\Administrator\\Desktop\\privateSeal.jpg");
        return draw;
    }

请添加图片描述
请添加图片描述

绘制方章

SquareSeal类:

package cn.com.yuanquanyun.utils.seal;

import cn.hutool.core.io.IoUtil;
import lombok.Builder;
import lombok.Getter;

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.File;
import java.io.FileOutputStream;

@Builder
@Getter
public class SquareSeal {
    // 起始位置
    private static final int INIT_BEGIN = 5;

    // 尺寸
    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[] draw() throws Exception {
        if (borderSquare != null) {
            return draw2(); // 画私章
        }

        //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);

        //3.画边线圆
        if (borderCircle != null) {
            drawCircle(g2d, borderCircle, INIT_BEGIN, INIT_BEGIN);
        } else {
            throw new Exception("BorderCircle can not null!");
        }

        int borderCircleWidth = borderCircle.getWidth();
        int borderCircleHeight = borderCircle.getHeight();

        //4.画内边线圆
        if (borderInnerCircle != null) {
            int x = INIT_BEGIN + borderCircleWidth - borderInnerCircle.getWidth();
            int y = INIT_BEGIN + borderCircleHeight - borderInnerCircle.getHeight();
            drawCircle(g2d, borderInnerCircle, x, y);
        }

        //5.画内环线圆
        if (innerCircle != null) {
            int x = INIT_BEGIN + borderCircleWidth - innerCircle.getWidth();
            int y = INIT_BEGIN + borderCircleHeight - innerCircle.getHeight();
            drawCircle(g2d, innerCircle, x, y);
        }

        //6.画弧形主文字
        if (borderCircleHeight != borderCircleWidth) {
            drawArcFont4Oval(g2d, borderCircle, mainFont, true);
        } else {
            drawArcFont4Circle(g2d, borderCircleHeight, mainFont, true);
        }

        //7.画弧形副文字
        if (borderCircleHeight != borderCircleWidth) {
            drawArcFont4Oval(g2d, borderCircle, viceFont, false);
        } else {
            drawArcFont4Circle(g2d, borderCircleHeight, viceFont, false);
        }

        //8.画中心字
        drawFont(g2d, (borderCircleWidth + INIT_BEGIN) * 2, (borderCircleHeight + INIT_BEGIN) * 2, centerFont);

        //9.画抬头文字
        drawFont(g2d, (borderCircleWidth + INIT_BEGIN) * 2, (borderCircleHeight + INIT_BEGIN) * 2, titleFont);

        g2d.dispose();

        //
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        boolean png = ImageIO.write(bi, "PNG", outputStream);
        byte[] imgBytes = outputStream.toByteArray();
        outputStream.flush();
        outputStream.close();
        return imgBytes;
    }

    public void draw(String pngPath) throws Exception {
        byte[] imgBytes = draw();
        FileOutputStream fileOutputStream = new FileOutputStream(new File(pngPath));
        fileOutputStream.write(imgBytes);
        IoUtil.close(fileOutputStream);
    }

    /**
     * 绘制圆弧形文字
     */
    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 (font.getSpace() != null) {
            space = font.getSpace();
        } else {
            if (textLen == 1) {
                space = 0;
            } else {
                space = rectangle.getWidth() / (textLen - 1) * 0.9;
            }
        }

        //6.距离外圈距离
        int margin = font.getMargin() == null ? INIT_BEGIN : font.getMargin();

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

        double fix = 0.04;
        if (isTop) {
            fix = 0.18;
        }
        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);
            }

            AffineTransform transform;
            if (!isTop) {
                transform = AffineTransform.getRotateInstance(Math.PI + Math.PI / 2 - theta);
            } else {
                transform = AffineTransform.getRotateInstance(Math.PI / 2 - theta + Math.toRadians(8));
            }
            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 drawArcFont4Oval(Graphics2D g2d, SealCircle sealCircle, SealFont font, boolean isTop) {
        if (font == null) {
            return;
        }
        float radiusX = sealCircle.getWidth();
        float radiusY = sealCircle.getHeight();
        float radiusWidth = radiusX + sealCircle.getLine();
        float radiusHeight = radiusY + sealCircle.getLine();

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

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

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

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

        //5.总的角跨度
        double totalArcAng = font.getSpace() * textLen;

        //6.从边线向中心的移动因子
        float minRat = 0.90f;

        double startAngle = isTop ? -90f - totalArcAng / 2f : 90f - totalArcAng / 2f;
        double step = 0.5;
        int alCount = (int) Math.ceil(totalArcAng / step) + 1;
        double[] angleArr = new double[alCount];
        double[] arcLenArr = new double[alCount];
        int num = 0;
        double accArcLen = 0.0;
        angleArr[num] = startAngle;
        arcLenArr[num] = accArcLen;
        num++;
        double angR = startAngle * Math.PI / 180.0;
        double lastX = radiusX * Math.cos(angR) + radiusWidth;
        double lastY = radiusY * Math.sin(angR) + radiusHeight;
        for (double i = startAngle + step; num < alCount; i += step) {
            angR = i * Math.PI / 180.0;
            double x = radiusX * Math.cos(angR) + radiusWidth, y = radiusY * Math.sin(angR) + radiusHeight;
            accArcLen += Math.sqrt((lastX - x) * (lastX - x) + (lastY - y) * (lastY - y));
            angleArr[num] = i;
            arcLenArr[num] = accArcLen;
            lastX = x;
            lastY = y;
            num++;
        }
        double arcPer = accArcLen / textLen;
        for (int i = 0; i < textLen; i++) {
            double arcL = i * arcPer + arcPer / 2.0;
            double ang = 0.0;
            for (int p = 0; p < arcLenArr.length - 1; p++) {
                if (arcLenArr[p] <= arcL && arcL <= arcLenArr[p + 1]) {
                    ang = (arcL >= ((arcLenArr[p] + arcLenArr[p + 1]) / 2.0)) ? angleArr[p + 1] : angleArr[p];
                    break;
                }
            }
            angR = (ang * Math.PI / 180f);
            Float x = radiusX * (float) Math.cos(angR) + radiusWidth;
            Float y = radiusY * (float) Math.sin(angR) + radiusHeight;
            double qxang = Math.atan2(radiusY * Math.cos(angR), -radiusX * Math.sin(angR));
            double fxang = qxang + Math.PI / 2.0;

            int subIndex = isTop ? i : textLen - 1 - i;
            String c = font.getText().substring(subIndex, subIndex + 1);

            //获取文字高宽
            FontMetrics fm = sun.font.FontDesignMetrics.getMetrics(f);
            int w = fm.stringWidth(c), h = fm.getHeight();

            if (isTop) {
                x += h * minRat * (float) Math.cos(fxang);
                y += h * minRat * (float) Math.sin(fxang);
                x += -w / 2f * (float) Math.cos(qxang);
                y += -w / 2f * (float) Math.sin(qxang);
            } else {
                x += (h * minRat) * (float) Math.cos(fxang);
                y += (h * minRat) * (float) Math.sin(fxang);
                x += w / 2f * (float) Math.cos(qxang);
                y += w / 2f * (float) Math.sin(qxang);
            }

            // 旋转
            AffineTransform affineTransform = new AffineTransform();
            affineTransform.scale(0.8, 1);
            if (isTop)
                affineTransform.rotate(Math.toRadians((fxang * 180.0 / Math.PI - 90)), 0, 0);
            else
                affineTransform.rotate(Math.toRadians((fxang * 180.0 / Math.PI + 180 - 90)), 0, 0);
            Font f2 = f.deriveFont(affineTransform);
            g2d.setFont(f2);
            g2d.drawString(c, x.intValue() + INIT_BEGIN, y.intValue() + 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 = 18;
        if (font.getSize() != null){
            size = font.getSize();
        }else {
            if (textLen > 13){
                size = 18 - (textLen - 13) < 12 ? 12 : 18 - (textLen - 13);
            }
        }

        //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("\n");
        if (fontTexts.length > 1) {//当文字是多行时的处理方式
            int y = 0;
            for (String fontText : fontTexts) {
                y += Math.abs(f.getStringBounds(fontText, context).getHeight());
            }
            //5.设置上边距
            float margin = INIT_BEGIN*5 + (float) (circleHeight / 2 - y / 2);
//            System.out.println("1.margin==="+margin);
            for (String fontText : fontTexts) {
                Rectangle2D rectangle2D = f.getStringBounds(fontText, context);
                g2d.drawString(fontText, (float) (circleWidth / 2 - rectangle2D.getCenterX()), margin);
                margin += Math.abs(rectangle2D.getHeight());
//                System.out.println("2.margin==="+margin);
            }
//            System.out.println("3.margin==="+margin);

        } else {//当文字是单行时的处理方式
            Rectangle2D rectangle2D = f.getStringBounds(font.getText(), context);
            //5.设置上边距,默认在中心
            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);
        }
    }

    /**
     * 画圆
     */
    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 drawRectangle(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.drawRect(x, y, 289, circle.getHeight() * 1);
    }

    /**
     * 画私章
     */
    public byte[] draw2() throws Exception {

        //1.画布
        BufferedImage bi = new BufferedImage(size, 106, 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);

        //3.画边线圆
        if (borderCircle != null) {
            drawRectangle(g2d, borderCircle, INIT_BEGIN, INIT_BEGIN);
        } else {
            throw new Exception("BorderCircle can not null!");
        }

        //4.画上行文字
        drawFont(g2d, INIT_BEGIN * 60, INIT_BEGIN * 5, mainFont);

        //5.画横向文字
        drawFont(g2d, INIT_BEGIN * 60, INIT_BEGIN * 20, viceFont);

        //5.画下行文字
        drawFont(g2d, INIT_BEGIN * 60, INIT_BEGIN * 5, titleFont);

        g2d.dispose();

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        boolean png = ImageIO.write(bi, "PNG", outputStream);
        byte[] imgBytes = outputStream.toByteArray();
        outputStream.flush();
        outputStream.close();
        return imgBytes;
    }

    /**
     * 画三字
     */
    private static BufferedImage drawThreeFont(BufferedImage bi, Graphics2D g2d, SealFont font, int lineSize, int imageSize, int fixH, int fixW, boolean isWithYin) {
        fixH -= 9;
        int marginW = fixW + lineSize;
        //设置字体
        Font f = new Font(font.getFamily(), Font.BOLD, font.getSize());
        g2d.setFont(f);
        FontRenderContext context = g2d.getFontRenderContext();
        Rectangle2D rectangle = f.getStringBounds(font.getText().substring(0, 1), context);
        float marginH = (float) (Math.abs(rectangle.getCenterY()) * 2 + marginW) + fixH;
        int oldW = marginW;

        if (isWithYin) {
            g2d.drawString(font.getText().substring(2, 3), marginW, marginH);
            marginW += rectangle.getCenterX() * 2 + (font.getSpace() == null ? INIT_BEGIN : font.getSpace());
        } else {
            marginW += rectangle.getCenterX() * 2 + (font.getSpace() == null ? INIT_BEGIN : font.getSpace());
            g2d.drawString(font.getText().substring(0, 1), marginW, marginH);
        }

        //拉伸
        BufferedImage nbi = new BufferedImage(imageSize, imageSize, bi.getType());
        Graphics2D ng2d = nbi.createGraphics();
        ng2d.setPaint(Color.RED);
        ng2d.drawImage(bi, 0, 0, imageSize, imageSize, null);

        //画正方形
        ng2d.setStroke(new BasicStroke(lineSize));
        ng2d.drawRect(0, 0, imageSize, imageSize);
        ng2d.dispose();
        bi = nbi;

        g2d = bi.createGraphics();
        g2d.setPaint(Color.RED);
        g2d.setFont(f);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        if (isWithYin) {
            g2d.drawString(font.getText().substring(0, 1), marginW, marginH += fixH);
            rectangle = f.getStringBounds(font.getText(), context);
            marginH += Math.abs(rectangle.getHeight());
            g2d.drawString(font.getText().substring(1), marginW, marginH);
        } else {
            g2d.drawString(font.getText().substring(1, 2), oldW, marginH += fixH);
            rectangle = f.getStringBounds(font.getText(), context);
            marginH += Math.abs(rectangle.getHeight());
            g2d.drawString(font.getText().substring(2, 3), oldW, marginH);
        }
        return bi;
    }

    /**
     * 画四字
     */
    private static BufferedImage drawFourFont(BufferedImage bi, SealFont font, int lineSize, int imageSize, int fixH, int fixW) {
        int marginW = fixW + lineSize;
        //拉伸
        BufferedImage nbi = new BufferedImage(imageSize, imageSize, bi.getType());
        Graphics2D ng2d = nbi.createGraphics();
        ng2d.setPaint(Color.RED);
        ng2d.drawImage(bi, 0, 0, imageSize, imageSize, null);

        //画正方形
        ng2d.setStroke(new BasicStroke(lineSize));
        ng2d.drawRect(0, 0, imageSize, imageSize);
        ng2d.dispose();
        bi = nbi;

        Graphics2D g2d = bi.createGraphics();
        g2d.setPaint(Color.RED);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        FontRenderContext context = g2d.getFontRenderContext();

        Font f = new Font(font.getFamily(), Font.BOLD, font.getSize());
        g2d.setFont(f);
        Rectangle2D rectangle = f.getStringBounds(font.getText().substring(0, 1), context);
        float marginH = (float) (Math.abs(rectangle.getCenterY()) * 2 + marginW) + fixH;

        g2d.drawString(font.getText().substring(2, 3), marginW, marginH);
        int oldW = marginW;
        marginW += Math.abs(rectangle.getCenterX()) * 2 + (font.getSpace() == null ? INIT_BEGIN : font.getSpace());
        g2d.drawString(font.getText().substring(0, 1), marginW, marginH);
        marginH += Math.abs(rectangle.getHeight());
        g2d.drawString(font.getText().substring(3, 4), oldW, marginH);
        g2d.drawString(font.getText().substring(1, 2), marginW, marginH);

        return bi;
    }
}

测试类

/**
     * 创建方形企业章
     *
     * @param companyName 企业名称:xxx企业
     * @param title       抬头:合同专用章
     * @param code        编号:1234567890123
     * @return
     * @throws Exception
     */
    public static byte[] makeCompanySquareSeal (String companyName, String title, String code) throws Exception {
        byte[] img = null;
        if(companyName.length() <= 19){
            img = SquareSeal.builder()
                    .size(300)
                    .borderCircle(SealCircle.builder().line(4).width(95).height(95).build())
                    .borderSquare(10)
                    .mainFont(SealFont.builder().text(companyName).space(12.0).margin(10).build())
                    .viceFont(SealFont.builder().text(title).size(16).space(15.0).margin(0).build())
                    .titleFont(SealFont.builder().text(code).size(12).space(9.0).margin(64).build())
                    .color(Color.RED)
                    .build()
                    .draw();
        }else {//支持印章字体换行操作
            int len = companyName.length();
            companyName = companyName.substring(0,19)+"\n"+companyName.substring(19,len);
            img = SquareSeal.builder()
                    .size(300)
                    .borderCircle(SealCircle.builder().line(4).width(95).height(95).build())
                    .borderSquare(10)
                    .mainFont(SealFont.builder().text(companyName).space(12.0).margin(10).build())
                    .viceFont(SealFont.builder().text(title).size(16).space(15.0).margin(10).build())//margin 越大viceFont位置越往下,margin 为0时,位于中间位置
                    .titleFont(SealFont.builder().text(code).size(12).space(9.0).margin(75).build()) //margin 越大titleFont位置越往下
                    .color(Color.RED)
                    .build()
                    .draw();
        }
        return img;
    }
     public static void main(String[] args) throws Exception {
        byte[] bytes = makeCompanySquareSeal("中国某某某股份有限公司某某某某分公司", "招标专用章", "1234567890123");
        System.out.println("data:image/png;base64,"+ Base64.encode(bytes));
    }

在这里插入图片描述
主文字超过19个字,就换行。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/148892.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《洛谷深入浅出进阶篇》 P1496火烧赤壁——初识离散化

上链接&#xff1a; P1496 火烧赤壁 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1496上题干&#xff1a; 有一组序列&#xff0c;[-2^31,2^31] &#xff0c; 现在给你n次操作&#xff0c;每一次操作给出两个整数l&#xff0c;r&#xff…

AM335x USB Boot详细说明

首先&#xff0c;要rev2.1的芯片才支持&#xff0c;以前的cpu有bug&#xff0c;无法使用usb boot 上位机需要uniflash&#xff0c; 以太网上截取的报文&#xff0c;可以进入第一阶段 AM335x自动从c:\am335x_flashtool\images目录下下载u-boot-spl-restore.bin http://process…

RFID技术在危险废物管理中的应用解决方案

一、背景介绍 随着我国经济的快速发展&#xff0c;轻纺、化工、制药、电子等行业的危险废物排放量逐年增加。然而&#xff0c;由于危险废弃物处理不当&#xff0c;可能导致大气、水体和土壤污染&#xff0c;对环境和人体健康造成严重威胁&#xff0c;制约了经济和健康的可持续…

Linux-查询目录下包含的目录数或文件数

1. 前置 1&#xff09;ls Linux最常用的命令之一&#xff0c;列出该目录下的包含内容。 -l&#xff1a;use a long listing format-以列表的形式展现 -R&#xff1a;list subdirectories recursively-递归列出子目录 2&#xff09;| 管道符 将上一条命令的输出&#xff…

调研了一下java常用的几个图片处理工具对Tiff文件的支持

ImageMagick 官网 https://imagemagick.org/&#xff0c; 支持多种格式。命令行工具很适合调试。功能很强大. 还有一款工具GraphicsMagick 是从ImageMagick的基础上研发出来的。 OpenCV 官网 https://opencv.org/ &#xff0c; github地址https://github.com/opencv/opencv&…

Springboot项目中打印SQL语句日志

在项目中我想查看自己的SQL语句是什么&#xff0c;就是如下图的内容&#xff1a; 方法一&#xff1a;&#xff08;我常用的&#xff09; 可以在项目中的.yml配置文件中添加如下内容&#xff1a; logging:level:com.uyun.bankbranchalert.mapper: debug其中com.uyun.bankbran…

如何挑选猫主食罐头?宠物店自用的5款猫主食罐头推荐!

临近双十二大促&#xff0c;是时候给家里的猫主子屯猫主食罐头了。许多铲屎官看大促的各种品牌宣传&#xff0c;看到眼花缭乱&#xff0c;不知道选哪些猫主食罐头好&#xff0c;胡乱选又怕踩坑。 猫罐头侠闪亮登场&#xff01;如何挑选猫主食罐头&#xff1f;作为经营宠物店7年…

开启核磁数据处理新篇章-MestReNova(MNOVA14)助您轻松解读科学界密码

在科学研究领域&#xff0c;核磁共振&#xff08;NMR&#xff09;技术被广泛应用于分析和解读化学物质的结构和性质。而MestReNova&#xff08;MNOVA14&#xff09;作为一款专业的核磁数据处理软件&#xff0c;凭借其强大的功能和易用性&#xff0c;已成为众多科研人员的首选工…

百度曹海涛:生成式AI正从“探索能力边界”向“推动应用落地”过渡

11月9日&#xff0c;以“星云棋布&#xff0c;步步为‘赢’”为主题的2023 IDC中国生态峰会在北京举办。会上&#xff0c;IDC中国区总裁霍锦洁女士的发表致辞。同时&#xff0c;IDC生态伙伴和行业领袖从多重维度分析了AI技术应用的发展&#xff0c;以及对于整体IT生态所产生的影…

【QT HTTP】使用QtNetwork模块制作基于HTTP请求的C/S架构

目录 0 引言1 HTTP基本知识1.1 请求类型1.2 HTTP请求报文格式1.3 HTTP响应报文格式1.4 拓展&#xff1a;GET vs POST 请求方法GET请求请求报文&#xff1a;响应报文 POST请求请求报文响应报文 其他注意事项示例&#xff1a;GET请求示例POST请求示例 2 实战2.1 QtNetwork模块介绍…

FPGA时序分析与约束(13)——I/O接口约束

一、概述 在应用了时钟约束后&#xff0c;所有寄存器到寄存器的路径都能定时。为了获得更加精准的FPGA外部时序信息&#xff0c;设计者需要为FPGA的I/O接口指定时序信息&#xff0c;一般时序工具只能获取FPGA器件内部的时序信息&#xff0c;对于FPGA器件引脚之外的时序信息&…

Feature Pyramid Networks for Object Detection(2017.4)

文章目录 Abstract1. Introduction3. Feature Pyramid NetworksBottom-up pathwayTop-down pathway and lateral connections 7. Conclusion FPN Abstract 特征金字塔是识别系统中检测不同尺度物体的基本组成部分。但最近的深度学习对象检测器避免了金字塔表示&#xff0c;部分…

Swift的Copy on Write 简称CoW

了解Copy on Write在Swift开发时非常重要&#xff0c;因为这是Swift Standard Library的一个基础特性。 值类型&#xff1a;struct&#xff0c;enum&#xff0c;和tuple&#xff0c;比如在调用函数时传递参数&#xff0c;就会发送副本拷贝 引用类型&#xff1a;class&#xff…

用户的生命周期

用户生命周期是指用户在产品使用过程中的状态变化&#xff0c;一般分为5个阶段&#xff0c;分别为引入期、成长期、成熟期、沉默期和流失期。用户生命周期能够反映不同阶段用户的状态&#xff0c;可根据用户的不同状态进行针对性运营。运营中常说的拉新、促活、留存就是基于用户…

SLAM中提到的相机位姿到底指什么?

不小心又绕进去了&#xff0c;所以掰一下。 以我个人最直观的理解&#xff0c;假设无旋转&#xff0c;相机在世界坐标系的(5,0,0)^T的位置上&#xff0c;所谓“位姿”&#xff0c;应该反映相机的位置&#xff0c;所以相机位姿应该如下&#xff1a; Eigen::Matrix4d T Eigen::M…

上位机模块之halcon绘制ROI与获取ROI,在hsmartwindow实现

在上位机中通常需要使用到绘制ROI模块或者获取已经绘制好的ROI区域的参数&#xff0c;在这里通过使用hsmartwindow窗体控件进行对ROI的绘制和获取。 先上代码&#xff1a; /// <summary>/// 创建ROI/// </summary>/// <param name"Win">传入HSmar…

Centos7安装frps作内网穿透--实现外部访问家里群晖

实现在外可访问家用群晖 需要在外界访问家里的局域网设备&#xff0c;正常情况是需要有公网IP&#xff0c;而IPV4作为家用&#xff0c;运营商基本不给&#xff0c;除非钞能力&#xff0c;IPV6可以用&#xff0c;但是有缺陷&#xff0c;需要互访的两端都是IPV6才能访问。选择fr…

Mysql删除占用事务的线程

参考&#xff1a;https://www.jianshu.com/p/dd0291391188 产生原因&#xff1a;这个问题的原因是在mysql中产生了事务A&#xff0c;执行了修改的语句&#xff0c;比如&#xff1a; update t1 set aget18 where id1;此时事务并未进行提交&#xff0c;事务B开始运行&#xff0c…

kubernetes集群编排(10)

目录 prometheus监控 部署prometheus 部署nginx监控实例 部署prometheus-adapter prometheus监控 部署prometheus 创建项目仓库并上传镜像 [rootk8s2 helm]# vim prometheus-values.yaml alertmanager:alertmanagerSpec:image:repository: prometheus/alertmanagertag: v0.24.0…