内切椭圆文字

内切椭圆文字

标签(空格分隔): 图像处理


参考c# 绘制内切于椭圆的文字,求代码或思路#36实现java版本
实际效果文字在圆上不是完全均匀分布,靠近圆y轴的字间隔较大,靠近圆x轴字间隔较小

package com.bwjf.sks.test.common;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class YinZhangTest {

    /**
     * 
     * @param g2
     * @param font 字体
     * @param center 中心点
     * @param radiusX 椭圆x轴半径
     * @param radiusY 椭圆y轴半径
     * @param totalArcAng 总的角跨度
     * @param minRat 从边线向中心的移动因子
     * @param text 字符串
     * @param top true-上半部分,false-下半部分
     */
    private static void paintOneText(Graphics g2, Font font, Point center, float radiusX, float radiusY,
            float totalArcAng, float minRat, String text, boolean top) {
        double startAng = top ? -90F - totalArcAng / 2f : 90F - totalArcAng / 2f;
        double endAng = top ? -90f + totalArcAng / 2f : 90F + totalArcAng / 2f;
        int count = text.length();
        double step = 0.5;
        int alCount = (int) Math.ceil(totalArcAng / step) + 1;
        double[] angArr = new double[alCount];
        double[] arcLenArr = new double[alCount];
        int num = 0;
        double accArcLen = 0.0;
        angArr[num] = startAng;
        arcLenArr[num] = accArcLen;
        num++;
        double angR = startAng * Math.PI / 180.0;
        double lastX = radiusX * Math.cos(angR) + center.getX();
        double laxtY = radiusY * Math.sin(angR) + center.getY();
        for (double i = startAng + step; num < alCount; i += step) {
            angR = i * Math.PI / 180.0;
            double x = radiusX * Math.cos(angR) + center.getX(), y = radiusY * Math.sin(angR) + center.getY();
            accArcLen += Math.sqrt((lastX - x) * (lastX - x) + (laxtY - y) * (laxtY - y));
            angArr[num] = i;
            arcLenArr[num] = accArcLen;
            lastX = x;
            laxtY = y;
            num++;
        }
        double arcPer = accArcLen / count;
        //
        for (int i = 0; i < count; 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)) ? angArr[p + 1] : angArr[p];
                    break;
                }
            }
            angR = (ang * Math.PI / 180f);
            Float x = (float) (radiusX * (float) Math.cos(angR) + center.getX()),
                    y = (float) (radiusY * (float) Math.sin(angR) + center.getY());
            double qxang = Math.atan2(radiusY * Math.cos(angR), -radiusX * Math.sin(angR)),
                    fxang = qxang + Math.PI / 2.0;

            int subIndex = top ? i : text.length();
            String c = text.substring(subIndex, subIndex + 1);

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

            if (top) {
                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 + h) * (float) Math.cos(fxang);
                y += (h * minRat + h) * (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 (top)
                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 = font.deriveFont(affineTransform);
            g2.setFont(f2);
            g2.drawString(c, x.intValue(), y.intValue());

            // Matrix mat = g2.Transform;
            // g2.TranslateTransform(x, y);
            // if (top)
            // g2.RotateTransform((float) (fxang * 180.0 / Math.PI - 90));
            // else
            // g2.RotateTransform((float) (fxang * 180.0 / Math.PI + 180 - 90));
            // g2.TranslateTransform(-x, -y);
            // g2.DrawString(c, font, Brushes.Black, x, y);
            // g2.Transform = mat;
        }
    }

    /**
     * 画外层椭圆
     * 
     * @param g2d
     * @param x
     * @param y
     * @param width
     * @param height
     */
    private static void drawOval(Graphics2D g2d, int x, int y, int width, int height, int stroke) {
        g2d.setPaint(Color.red);
        g2d.setStroke(new BasicStroke(stroke));// 设置画笔的粗度
        g2d.drawOval(x, y, width, height);
        // 辅助画线椭圆
        // g2d.setStroke(new BasicStroke(1));
        // g2d.drawOval(44, 44, canvasWidth - 88, canvasHeight - 88);
    }

    /// <summary>
    /// 绘制印章
    /// 给定椭圆的中心,两个半径和文字所跨的角度来绘制。先求总的弧长,然后均分,每个字所占据的弧长相等。
    /// 难点在于如何求弧长和角度的对应关系,我采取的办法是先求出一个对应表:从最小角度到最大角度,每0.5度
    /// 递增,求出各段弧长累加即得到对应表。
    /// 由弧长查角度的时候,从表中找到该弧长所在的闭区间,就得到对应的角度
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public static void main(String[] args) {

        int radiusX = 200, radiusY = 130, stroke = 6;// x半径、y半径、stroke原线宽度
        Point center = new Point(radiusX + stroke, radiusY + stroke);// 中心点

        BufferedImage bi = new BufferedImage((radiusX + stroke) * 2, (radiusY + stroke) * 2,
                BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = bi.createGraphics();
        // 抗锯齿处理
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        Font font = new Font("仿宋", Font.BOLD, 26);

        drawOval(g2, (int) center.getX() - radiusX, (int) center.getY() - radiusY, radiusX * 2, radiusY * 2, stroke);
        paintOneText(g2, font, center, radiusX, radiusY, 180, 0.95f, "山西开天电子有限公司公司", true);
        // paintOneText(g2, font, center, radiusX, radiusY, 90, -0.05f, "发票专用章", false);

        g2.dispose();
        String path = "C://temp//123.png";
        try {
            ImageIO.write(bi, "png", new File(path));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }
}

猜你喜欢

转载自blog.csdn.net/zh350229319/article/details/82253073