Java中生成指定字体的印章

news2024/11/15 21:28:44

文章目录

  • 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个字,就换行。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11111

#include <iostream> #include <vector> #include <queue> #include <algorithm>using namespace std;// 边的结构体 struct Edge {int src, dest, weight;// 按照权重进行排序bool operator<(const Edge& other) const {return weight < ot…

win10资源管理器占用CPU过高导致卡顿

win10 打开几个文件夹后 资源管理器占用CPU 飙升&#xff0c;卡的很难受&#xff0c;网上找了几个办法 关闭 小娜&#xff0c;关闭搜索 什么的 都没明显改善&#xff0c;还有损招&#xff0c;重启资源管理器&#xff0c;重启一次 20多秒&#xff0c;要不了多长时间就会再次卡…

echarts实现不展示X轴Y轴轴线、刻度

今日工作中需要实现折线图的简图&#xff0c;就是只看个大概趋势不展示具体坐标&#xff0c;查阅了文档记录一下。 initCharts(_id, _name, yAxisData, _unit){if(this[_id]) this[_id].clear();this[_id] $echarts.init(document.getElementById(_id));const options {grid…

settings.json配置

settings.json配置 {"editor.tabSize": 2,"git.ignoreWindowsGit27Warning": true,"workbench.editor.untitled.hint": "hidden","security.workspace.trust.untrustedFiles": "open","[vue]": {"…

老师的保命大法

数字化高度发达的今天&#xff0c;成绩查询系统已经成为学校教育中不可或缺的一部分。不同于传统的成绩公布方式&#xff0c;成绩查询系统更加高效、便捷&#xff0c;同时也充分保障了每位学生的隐私&#xff0c;今天就来揭秘这个教师保命大法&#xff01; 1、代码查询法 对于…

docker内更新显卡cuda cudnn

当前docker使用的cuda为10.2&#xff0c;为保证服务器环境使用相同的cuda版本&#xff0c;需对cuda版本进行升级&#xff0c;时间长了忘记如何操作&#xff0c;此处记录一下&#xff1a; *docker内使用的cuda版本低于容器外的显卡驱动版本即可&#xff0c;此处不对显卡驱动进行…

HTML5学习系列之实用性标记

HTML5学习系列之实用性标记 前言实用性标记高亮显示进度刻度时间联系信息显示方向换行断点标注 总结 前言 学习记录 实用性标记 高亮显示 mark元素可以进行高亮显示。 <p><mark>我感冒了</mark></p>进度 progress指示某项任务的完成进度。 <p…

程序员兼职平台有哪些?这样写兼职简历让你收入直接飙升30k!

这是著名程序员兼职平台 “猿急送”的分享资料&#xff0c;猿急送2015年成立&#xff0c;国内最早最领先的程序员兼职平台&#xff0c;今天跟大家继续讲一下在程序员兼职平台里接单的一个重要问题&#xff1a;怎样写好个人兼职简历&#xff1f;&#xff08;想直接看主流程序员兼…

图形化探索:快速改造单实例为双主、MGR、读写分离等架

单机GreatSQL/MySQL调整架构为多副本复制的好处有哪些&#xff1f;为什么要调整&#xff1f; 性能优化&#xff1a;如果单个GreatSQL服务器的处理能力达到瓶颈&#xff0c;可能需要通过主从复制、双主复制或MGR&#xff0c;以及其他高可用方案等来提高整体性能。通过将读请求分…

SoftwareTest7 - JUnit 是个啥 ? 他跟 Selenium 有什么关系 ?

JUnit 是个啥 ? 他跟 Selenium 有什么关系 ? 一 . 相关注解1.1 Test1.2 BeforeEach1.3 BeforeAll1.4 AfterEach1.5 AfterAll 二 . 断言2.1 assertEquals2.2 assertNotEquals2.3 assertTrue / assertFalse : 断言结果为真/假2.4 assertNull / assertNotNull : 断言结果为空 / …

数据结构—内部排序(下)

文章目录 8.内部排序(下)(6).归并排序#1.先做合并#2.再来排序#3.代码实现#4.稳定性与时间复杂度分析 (7).快速排序#1.算法思想#2.代码实现#3.稳定性与时间复杂度分析 (8).基数排序#1.算法思想#2.稳定性和时间复杂度分析 小结 8.内部排序(下) (6).归并排序 那我们的时间复杂度还…

【评论送书】十本架构师成长和软件架构技术相关的好书(可以任选)

正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 参与规则 本次送书1~5本参与方式&#xff1a;关注博主、点赞、收藏、评论&#xff08;从评论区…

Maven:通过相对路径向jar中添加依赖项

问&#xff1a;我有一个专有的jar&#xff0c;我想把它作为一个依赖项添加到我的pom中。 但我不想把它添加到存储库中。原因是我希望常用的maven命令(如mvn compile等)能够开箱即用。(无需要求开发人员自己将其添加到某个存储库中)。 我希望jar在源代码控制中的第三方库中&…

idea菜单栏任务栏放缩比例修改

在编辑自定义VM选项中增加 -Dide.ui.scale0.8 参数 Help -> Edit Custom VM Options

Visual Studio Code配置c/c++环境

Visual Studio Code配置c/c环境 1.创建项目目录2.vscode打开项目目录3.项目中添加文件4.文件内容5.配置编译器6.配置构建任务7.配置调试设置 1.创建项目目录 d:\>mkdir d:\c语言项目\test012.vscode打开项目目录 3.项目中添加文件 4.文件内容 #include <iostream> u…

Linux C 编程入门 (GCC 和 Makefile的使用和编写)

Linux C 编程入门 在 Windows 下我们可以使用各种各样的 IDE 进行编程&#xff0c;比如强大的 Visual Studio。Ubuntu 下也有一些可以进行编程的工具&#xff0c;但是大多都只是编辑器&#xff0c;也就是只能进行代码编辑&#xff0c;如果要编译的话就需要用到 GCC 编译器&…

基于opencv+tensorflow+神经网络的智能银行卡卡号识别系统——深度学习算法应用(含python、模型源码)+数据集(二)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 训练集图片处理1&#xff09;数据加载2&#xff09;图像处理 2. 测试图片处理1&#xff09;图像读取2&#xff09;图像处理 相关其它博客工程源代码下载其它资料下载 前言 本项目基于从网络获取的多种银行卡数据…

AR贴纸特效SDK,无缝贴合的虚拟体验

增强现实&#xff08;AR&#xff09;技术已经成为了企业和个人开发者的新宠。它通过将虚拟元素与现实世界相结合&#xff0c;为用户提供了一种全新的交互体验。然而&#xff0c;如何将AR贴纸完美贴合在人脸的面部&#xff0c;同时支持多张人脸的检测和标点及特效添加&#xff0…

【Android 】android13 新权限获取 读写文件权限

android13 新权限获取 参考&#xff1a;Android 13(API 33)读写SD卡权限的调整适配 - Mr,Han - 博客园 android在 获取文件读写权限&#xff08;尤其是音视频、图片等等资源&#xff09;的权限获取逻辑更换了。 必须申请如下权限&#xff1a; public static final String READ…