import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.imageio.ImageIO; public class SealUtils { private static final int CANVAS_SIZE = 300; // 画布宽 private static final String FONT_FAMILY = "宋体"; // 字体 //private static final String FOOT_TXT = "电子签约专用章";// 底部文字 private static final String FOOT_TXT = "我家特有章";// 底部文字 private static final String STAR = "★"; private static int STAR_SIZE = (int) (CANVAS_SIZE / 3.2); // 五角星大小 private static int FOOT_FONT_SIZE = CANVAS_SIZE / 12; // 底部文字大小 /** * 根据companyName获得合同专用章 * @param companyName * @return */ public static BufferedImage genSealImage(String companyName) { BufferedImage bi = new BufferedImage(CANVAS_SIZE, CANVAS_SIZE, BufferedImage.TYPE_4BYTE_ABGR); Graphics2D g2d = bi.createGraphics(); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 0)); g2d.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 1)); int circleRadius = CANVAS_SIZE / 2 - 10; drawCicle(g2d, circleRadius); drawStar(g2d, circleRadius); drawFootText(g2d, circleRadius); drwaHeadText(companyName, g2d, circleRadius); g2d.dispose(); return bi; } public static void main(String[] args) { try { String name="我的印章"; byte[] img= SealUtils.genSealData(name); byte2File(img,"E:\\生成电子章\\",name+".png"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 辅助方法,byte数组保存为本地文件 * @param buf * @param filePath * @param fileName */ private static void byte2File(byte[] buf, String filePath, String fileName) { BufferedOutputStream bos = null; FileOutputStream fos = null; File file = null; try { File dir = new File(filePath); if (!dir.exists()) { dir.mkdirs(); } file = new File(filePath + File.separator + fileName); fos = new FileOutputStream(file); bos = new BufferedOutputStream(fos); bos.write(buf); } catch (Exception e) { e.printStackTrace(); } finally { if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 根据companyName获得合同专用章 * * @param companyName * @return * @throws IOException */ public static byte[] genSealData(String companyName) throws IOException { BufferedImage image = genSealImage(companyName); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); try { ImageIO.write(image, "png", outStream); } catch (IOException e) { throw e; } finally { try { outStream.close(); } catch (IOException e) { } } byte[] imageData = outStream.toByteArray(); return imageData; } /** * 弧形绘制顶部名称 * * @param companyName * @param g2d * @param circleRadius */ private static void drwaHeadText(String companyName, Graphics2D g2d, int circleRadius) { int companyNameLen = companyName.length(); int headFontSize; if (companyNameLen < 8) { // 字体根据画布大小微调出来的 headFontSize = 47; } else { headFontSize = 43 - (companyNameLen - 8) * 2; } Font f; FontRenderContext context; Rectangle2D rectangle; f = new Font(FONT_FAMILY, Font.PLAIN, headFontSize); context = g2d.getFontRenderContext(); rectangle = f.getStringBounds(companyName, context); double interval; // 文字之间间距 if (companyNameLen == 1) { interval = 0; } else { interval = rectangle.getWidth() / (companyNameLen - 1) * 0.9; } double newRadius = circleRadius + rectangle.getY() - 10; // bounds.getY()是负数,这样可以将弧形文字固定在圆内了。-10目的是离圆环稍远一点 double radianPerInterval = 2 * Math.asin(interval / (2 * newRadius)); // 每个间距对应的角度 // 第一个元素的角度 double firstAngle; if (companyNameLen % 2 == 1) { firstAngle = (companyNameLen - 1) * radianPerInterval / 2.0 + Math.PI / 2 + 0.18; // 0.18是浮点计算误差,如果文字不对称,可以微调 } else { firstAngle = (companyNameLen / 2.0 - 1) * radianPerInterval + radianPerInterval / 2.0 + Math.PI / 2 + 0.18; } for (int i = 0; i < companyNameLen; i++) { double theta = firstAngle - i * radianPerInterval; double thetaX = newRadius * Math.sin(Math.PI / 2 - theta); // 小小的trick,将【0,pi】区间变换到[pi/2,-pi/2]区间 double thetaY = newRadius * Math.cos(theta - Math.PI / 2); // 同上类似,这样处理就不必再考虑正负的问题了 AffineTransform transform = AffineTransform.getRotateInstance(Math.PI / 2 - theta); Font f2 = f.deriveFont(transform); g2d.setFont(f2); g2d.drawString(companyName.substring(i, i + 1), (float) (circleRadius + thetaX + 10), (float) (circleRadius - thetaY + 10)); } } /** * 画底部文字 * * @param g2d * @param circleRadius */ private static void drawFootText(Graphics2D g2d, int circleRadius) { Font f; FontRenderContext context; Rectangle2D rectangle; f = new Font(FONT_FAMILY, Font.BOLD, FOOT_FONT_SIZE); context = g2d.getFontRenderContext(); rectangle = f.getStringBounds(FOOT_TXT, context); int a = 10 * CANVAS_SIZE / 350; // 底部文字距中心的距离,这是调出来的 g2d.setFont(f); g2d.drawString(FOOT_TXT, (float) (circleRadius + a - rectangle.getCenterX()), (float) (circleRadius * 1.5 + a - rectangle.getCenterY())); } /** * 画中心的 ★ * * @param g2d * @param circleRadius */ private static void drawStar(Graphics2D g2d, int circleRadius) { Font f = new Font(FONT_FAMILY, Font.PLAIN, STAR_SIZE); FontRenderContext context = g2d.getFontRenderContext(); Rectangle2D rectangle = f.getStringBounds(STAR, context); g2d.setFont(f); g2d.drawString(STAR, (float) (circleRadius + 10 - rectangle.getCenterX()), (float) (circleRadius + 10 - rectangle.getCenterY())); } /** * 画外圈圆 * * @param g2d * @param circleRadius */ private static void drawCicle(Graphics2D g2d, int circleRadius) { g2d.setPaint(Color.red); int lineSize = circleRadius * 2 / (35); // 圆线条粗细是圆直径的1/35 g2d.setStroke(new BasicStroke(lineSize)); Shape circle = new Arc2D.Double(10, 10, circleRadius * 2, circleRadius * 2, 0, 360, Arc2D.OPEN); g2d.draw(circle); } }