Seal.java
10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
package com.lego.common.seal;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
/**
* @author GaoYongYi
* @date 2023/7/25 14:51
*/
@Data
public class Seal {
// 起始位置
private static final int INIT_BEGIN = 2;
// 尺寸
private Integer size;
// 颜色
private Color color;
// 主字
private SealFont mainFont;
// 副字
private SealFont viceFont;
// 抬头
private SealFont titleFont;
// 中心字
private SealFont centerFont;
// 边线圆
private SealCircle borderCircle;
// 内边线圆
private SealCircle borderInnerCircle;
// 内线圆
private SealCircle innerCircle;
// 边线框
private Integer borderSquare;
// 加字
private String stamp;
public byte[] drawPrivate(String text) throws IOException {
mainFont = SealFont.builder().text(text).build();
String[] fontTexts = text.split("");
int fixH = 18;
int fixW = 15;
//1.画布
BufferedImage bi = new BufferedImage((fixW * fontTexts.length) + 3, fixH + 3, BufferedImage.TYPE_4BYTE_ABGR);
//2.画笔
Graphics2D g2d = bi.createGraphics();
//2.1设置画笔颜色
g2d.setPaint(Color.RED);
//2.2抗锯齿设置
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//画边框
g2d.drawRect(1, 1, fixW * fontTexts.length, fixH);
//3.写签名
Font f = new Font(mainFont.getFamily(), Font.BOLD, fixW);
g2d.setFont(f);
//循环写字
for (int i = 0; i < fontTexts.length; i++) {
g2d.drawString(fontTexts[i], ((fixH - 3) * i) + 1 , fixW);
}
g2d.dispose();
ByteArrayOutputStream output = new ByteArrayOutputStream();
ImageIO.write(bi, "PNG", output);
return output.toByteArray();
}
/**
* 画公章
*/
public String draw(String surround, String subheading, String security) throws Exception {
if (StrUtil.isEmpty(surround)) {
return null;
}
if (size == null || size == 0) {
size = 300;
}
String pngPath = "E:\\templateFile\\test.png";
//1.画布
BufferedImage bi = new BufferedImage(size, size, BufferedImage.TYPE_4BYTE_ABGR);
//2.画笔
Graphics2D g2d = bi.createGraphics();
//2.1抗锯齿设置
//文本不抗锯齿,否则圆中心的文字会被拉长
RenderingHints hints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
//其他图形抗锯齿
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(hints);
//2.2设置背景透明度
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 0));
//2.3填充矩形
g2d.fillRect(0, 0, size, size);
//2.4重设透明度,开始画图
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 1));
//2.5设置画笔颜色
g2d.setPaint(color == null ? Color.RED : color);
if (borderCircle == null) {
borderCircle = SealCircle.builder().line(5).width(147).height(147).build();
}
if (mainFont == null) {
mainFont = SealFont.builder().text(surround).size(50).build();
}
//画圆
drawCircle(g2d, borderCircle, INIT_BEGIN, INIT_BEGIN);
int borderCircleWidth = borderCircle.getWidth();
int borderCircleHeight = borderCircle.getHeight();
SealFont centerFont = SealFont.builder().text("★").size(115).build();
//画五角形
drawFont(g2d, borderCircleWidth * 2, borderCircleHeight * 2, centerFont);
if (StrUtil.isNotBlank(subheading)) {
SealFont subheadingFont = SealFont.builder().text(subheading).size(28).space(8.0).margin(80).build();
drawFont(g2d, borderCircleWidth * 2, borderCircleHeight * 2, subheadingFont);
}
drawArcFont4Circle(g2d, borderCircleHeight, mainFont, true);
if (StrUtil.isNotBlank(security)) {
SealFont securityFont = SealFont.builder().text(security).size(25).build();
drawArcFont4Circle(g2d, borderCircleHeight, securityFont, false);
}
g2d.dispose();
ByteArrayOutputStream output = new ByteArrayOutputStream();
ImageIO.write(bi, "PNG", output);
//ImageIO.write(bi, "PNG", new File("E:\\templateFile\\test.png"));
return Base64.getEncoder().encodeToString(output.toByteArray());
}
/**
* 画圆
*/
private static void drawCircle(Graphics2D g2d, SealCircle circle, int x, int y) {
if (circle == null) {
return;
}
//1.圆线条粗细默认是圆直径的1/35
int lineSize = circle.getLine() == null ? circle.getHeight() * 2 / (35) : circle.getLine();
//2.画圆
g2d.setStroke(new BasicStroke(lineSize));
g2d.drawOval(x, y, circle.getWidth() * 2, circle.getHeight() * 2);
}
private static void drawArcFont4Circle(Graphics2D g2d, int circleRadius, SealFont font, boolean isTop) {
if (font == null) {
return;
}
//1.字体长度
int textLen = font.getText().length();
//2.字体大小,默认根据字体长度动态设定
int size = font.getSize() == null ? (55 - textLen * 2) : font.getSize();
//3.字体样式
int style = font.getBold() ? Font.BOLD : Font.PLAIN;
//4.构造字体
Font f = new Font(font.getFamily(), style, size);
FontRenderContext context = g2d.getFontRenderContext();
Rectangle2D rectangle = f.getStringBounds(font.getText(), context);
//5.文字之间间距,默认动态调整
double space;
if (textLen == 1) {
space = 0;
} else {
if (isTop) {
space = 360 * 0.7 / textLen * 1.7;
} else {
space = 360 * 0.3 / textLen * 1.7;
}
}
//7.写字
double newRadius = circleRadius + rectangle.getY();
double radianPerInterval = 2 * Math.asin(space / (2 * newRadius));
double fix = 0.06;
if (isTop) {
fix = 0.25;
}
double firstAngle;
if (!isTop) {
if (textLen % 2 == 1) {
firstAngle = Math.PI + Math.PI / 2 - (textLen - 1) * radianPerInterval / 2.0 - fix;
} else {
firstAngle = Math.PI + Math.PI / 2 - ((textLen / 2.0 - 0.5) * radianPerInterval) - fix;
}
} else {
if (textLen % 2 == 1) {
firstAngle = (textLen - 1) * radianPerInterval / 2.0 + Math.PI / 2 + fix;
} else {
firstAngle = (textLen / 2.0 - 0.5) * radianPerInterval + Math.PI / 2 + fix;
}
}
for (int i = 0; i < textLen; i++) {
double theta;
double thetaX;
double thetaY;
if (isTop) {
theta = firstAngle - i * radianPerInterval;
thetaX = newRadius * Math.sin(Math.PI / 2 - theta);
thetaY = newRadius * Math.cos(theta - Math.PI / 2);
} else {
theta = firstAngle + i * radianPerInterval;
thetaX = newRadius * Math.sin(Math.PI / 2 - theta);
thetaY = newRadius * Math.cos(theta - Math.PI / 2) - 17;
}
AffineTransform transform;
if (!isTop) {
transform = AffineTransform.getRotateInstance(Math.PI + Math.PI / 2 - theta);
} else {
transform = AffineTransform.getRotateInstance(Math.PI / 2 - theta + Math.toRadians(15));
}
Font f2 = f.deriveFont(transform);
g2d.setFont(f2);
g2d.drawString(font.getText().substring(i, i + 1), (float) (circleRadius + thetaX + INIT_BEGIN), (float) (circleRadius - thetaY + INIT_BEGIN));
}
}
/**
* 画文字
*/
private static void drawFont(Graphics2D g2d, int circleWidth, int circleHeight, SealFont font) {
if (font == null) {
return;
}
//1.字体长度
int textLen = font.getText().length();
//2.字体大小,默认根据字体长度动态设定
int size = font.getSize();
//3.字体样式
int style = font.getBold() ? Font.BOLD : Font.PLAIN;
//4.构造字体
Font f = new Font(font.getFamily(), style, size);
g2d.setFont(f);
FontRenderContext context = g2d.getFontRenderContext();
String[] fontTexts = font.getText().split("");
if (fontTexts.length > 1) {
//开始位置
double start = circleWidth / 4;
//写完所有字所需要位置
double need = circleWidth - (circleWidth / 4 * 2);
//每个字所需要位置
double wordProportion = circleWidth / 11;
//间隔位置
double spaceNeed = (need / fontTexts.length) - wordProportion;
double every = wordProportion + spaceNeed;
double step = start;
for (String fontText : fontTexts) {
Rectangle2D rectangle2D = f.getStringBounds(fontText, context);
float margin = font.getMargin() == null ?
(float) (circleHeight / 2 - rectangle2D.getCenterY()) :
(float) (circleHeight / 2 - rectangle2D.getCenterY()) + (float) font.getMargin();
g2d.drawString(fontText, (float) (step - rectangle2D.getCenterX()), margin);
step = step + every + ((wordProportion + spaceNeed) / fontTexts.length) + (circleWidth / fontTexts.length / 24);
}
} else {
Rectangle2D rectangle2D = f.getStringBounds(font.getText(), context);
//5.设置上边距,默认在中心report/personalResultRecord/list
float margin = font.getMargin() == null ?
(float) (circleHeight / 2 - rectangle2D.getCenterY()) :
(float) (circleHeight / 2 - rectangle2D.getCenterY()) + (float) font.getMargin();
g2d.drawString(font.getText(), (float) (circleWidth / 2 - rectangle2D.getCenterX()), margin);
}
}
}