java Graphics2D 画图
平时出图都是前端画图的,本次画图是对响应时间有要求,所有给后端提的需求。这里就给出一个demo 还有列出其中遇到的几个小问题
1 首先列出结果图
2 遇到的问题
1 这是两张图片覆盖的。
coverImage 方法
2 覆盖图是圆角矩形,但是四个角的底色要和底图保持一致
需要先fillRect 填充相应的底色。
3 覆盖图的文字显示问题, 因为是介绍,不确定字体的多少 自动换行 多行文字 自动计算高度 我这个是标题最多2行 介绍最多3行(在方法里面都是参数)。
drawString 该方法从网上找的 自己改造了下
4 font 字体的问题 和 Color颜色的问题
font字体 从C:\Windows\Fonts 中找对应的字体就行 Font font3 = new Font("苹方-简", Font.BOLD, 28); 但是记得如果是奇葩字体 比如我这个要求苹果的字体 一定要把字体上传到linux服务器 否咋 测试或生成 文字就会变成 “口口”
Color 颜色 java api 不能识别 #CC00FF 只能识别 Color.getHSBColor(153,153,153)
https://www.sioe.cn/yingyong/yanse-rgb-16/ 这个百度颜色转化 就出来了
5 推荐一个好使的颜色取色器
链接:https://pan.baidu.com/s/1gxLTOIysfYQLlSWdMFmYpQ
提取码:se9s
3 main 代码
public static void main(String[] args) throws Exception {
int picWid=660;
int picHeight1=269;
int picHeight2=531;
BufferedImage BufImage = new BufferedImage(picWid, picHeight1+picHeight2, BufferedImage.TYPE_INT_RGB);// RGB形式
Graphics2D g = BufImage.createGraphics();
g.drawRect(0,0,picWid,picHeight1);//画线框
g.setColor(Color.red);
g.fillRect(0,0,picWid,picHeight1);//是用预定的颜色填充一个矩形
g.drawRect(0,picHeight1,picWid,picHeight2);//画线框
g.setColor(Color.white);
g.fillRect(0,picHeight1,picWid,picHeight2);//是用预定的颜色填充一个矩形
// 设置圆形头像
BufferedImage headImage = ImageIO.read(new URL("https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKu4BoQkiauW80hPgpeLZSVkHXVDVY1iaQkicNj5UjY5w1DDqZqk6GnfedKPthqxdE4qK2K2wCUTMoUw/132"));
headImage=convertCircular(headImage);
// 获取小程序码
BufferedImage qrCodeImage = ImageIO.read(new URL("https://sxhw-1251808348.cos.ap-beijing.myqcloud.com/xcxqrcode/2020- 04/af12e742bcf7662706f2c0153f0e82d8.jpg"));
// 设置各组件位置
//设置头像
g.drawImage(headImage, 48, 32, 80, 80, null);
//小程序码
g.drawImage(qrCodeImage, 30, 620, 160, 160, null);
//写字
g.setColor(Color.white);
Font font2 = new Font("苹方-简", Font.BOLD, 24);
g.setFont(font2);
g.drawString("丁一江", 148, 53);
//写字
g.setColor(Color.white);
Font font3 = new Font("苹方-简", Font.BOLD, 28);
g.setFont(font3);
g.drawString("我的团购活动正在火热进行~", 148, 90);
//写字
g.setColor(Color.black);
Font font4 = new Font("苹方-简", Font.BOLD, 32);
g.setFont(font4);
g.drawString("长按识别下程序码", 210, 677);
//写字
g.setColor(Color.getHSBColor(153,153,153));
Font font5 = new Font("苹方-简", Font.BOLD, 24);
g.setFont(font5);
g.drawString("立即抢购好物", 210, 730);
//覆盖层数据
BufferedImage realImg = new BufferedImage(620, 456, BufferedImage.TYPE_INT_RGB);// RGB形式
Graphics2D real2D = realImg.createGraphics();
// real2D.drawRect(0,0,710,100);//画线框
//解决 圆角矩形 4个角黑色 先填充颜色 在画矩形
real2D.setColor(Color.red);
real2D.fillRect(0,0,620,125);//是用预定的颜色填充一个矩形
//real2D.drawRect(0,100,710,400);//画线框
real2D.setColor(Color.white);
real2D.fillRect(0,125,620,331);//是用预定的颜色填充一个矩形
real2D.setColor(Color.white);
real2D.fillRoundRect(0, 0, 620, 456,40, 40);
//商品介绍
String groupName="商品标题test-商品标题test-商品标题test-商品标题test-商品标题test-商品标题test-商品标题test-商品标题test-商品标题test";
String groupDetail="商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test-商品详情test";
String price="商品团购价:¥5-¥28.8";
//写字
real2D.setColor(Color.black);
Font font6 = new Font("苹方-简", Font.BOLD, 28);
int height=drawString(real2D,font6,groupName,578,20,40,30,2);
//写字
real2D.setColor(Color.gray);
Font font7 = new Font("苹方-简", Font.BOLD, 20);
height=drawString(real2D,font7,groupDetail,578,20,height+20,30,3);
//写字
real2D.setColor(Color.red);
Font font8 = new Font("苹方-简", Font.BOLD, 28);
height=drawString(real2D,font8,price,578,20,height+40,30,1);
// 商品图片
List<String> imgList=new ArrayList<String>();
imgList.add("https://sxhw-1251808348.cos.ap-beijing.myqcloud.com/prod-image/2020-04/22824b828c39aec9396fe345cc2d8cb0.jpg");
imgList.add("https://sxhw-1251808348.cos.ap-beijing.myqcloud.com/prod-image/2020-04/3c4dbfef1fbe4c8ae092e0efc79ecb8c.jpg");
imgList.add("https://sxhw-1251808348.cos.ap-beijing.myqcloud.com/prod-image/2020-04/0a5774763ea977d5421b08b8204a0ed7.jpg");
for(int i=0;i<imgList.size();i++) {
String imgUrl=imgList.get(i);
BufferedImage posterBufImage = ImageIO.read(new URL(imgUrl));
real2D.drawImage(posterBufImage, 180*i+(i+1)*20, height, 180, 179, null);
}
// 两张图片覆盖
BufImage = coverImage(BufImage, realImg, 20, 144, 620, 456);
// g.setColor(Color.blue);
ImageIO.write(BufImage, "png", new File("D:\\1111test\\demo31.png"));
}
/**
* 文字超出限定长度自动换行
*
* @param g 画布
* @param font 字体样式
* @param text 文字
* @param widthLength 最大长度 (多少长度后需要换行)
* @param x 文字位置坐标 x
* @param y 文字位置坐标 Y
* @param yn 每次换行偏移多少pt
* showLine 显示行数 文字可能过多 我们只显示showLine行文字
*/
private static int drawString(Graphics2D g, Font font, String text1, int widthLength, int x, int y, int yn,int showLine) {
FontMetrics fg = g.getFontMetrics(font);
List<String> ls = new ArrayList<>();
getListText(fg, text1, widthLength, ls);
g.setFont(font);
for (int i = 0; i < ls.size(); i++) {
if(i==showLine) {
break;
}
if (i == 0) {
g.drawString(ls.get(i), x, y);
} else {
g.drawString(ls.get(i), x, y + i*yn);
}
}
int height=fg.getHeight();
if(ls.size()<=showLine) {
y=y+height*ls.size();
}else {
y=y+height*showLine;
}
return y;
}
/**
* 递归 切割字符串
* @param fg
* @param text
* @param widthLength
* @param ls
*/
private static void getListText(FontMetrics fg, String text, int widthLength, List<String> ls) {
String ba = text;
boolean b = true;
int i = 1;
while (b) {
if (fg.stringWidth(text) > widthLength) {
text = text.substring(0, text.length() - 1);
i++;
} else {
b = false;
}
}
if (i != 1) {
ls.add(ba.substring(0, ba.length() - i));
getListText(fg, ba.substring(ba.length() - i), widthLength, ls);
} else {
ls.add(text);
}
}
//覆盖图片方法
public static BufferedImage coverImage(BufferedImage baseBufferedImage, BufferedImage coverBufferedImage, int x, int y, int width, int height) throws Exception{
// 创建Graphics2D对象,用在底图对象上绘图
Graphics2D g2d = baseBufferedImage.createGraphics();
// 绘制
g2d.drawImage(coverBufferedImage, x, y, width, height, null);
g2d.dispose();// 释放图形上下文使用的系统资源
return baseBufferedImage;
}
/**
* 传入的图像必须是正方形的 才会 圆形 如果是长方形的比例则会变成椭圆的
*
* @param url
* 用户头像地址
* @return
* @throws IOException
*/
public static BufferedImage convertCircular(BufferedImage bi1) throws IOException {
// BufferedImage bi1 = ImageIO.read(new File(url));
// 这种是黑色底的
// BufferedImage bi2 = new BufferedImage(bi1.getWidth(), bi1.getHeight(), BufferedImage.TYPE_INT_RGB);
// 透明底的图片
BufferedImage bi2 = new BufferedImage(bi1.getWidth(), bi1.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, bi1.getWidth(), bi1.getHeight());
Graphics2D g2 = bi2.createGraphics();
g2.setClip(shape);
// 使用 setRenderingHint 设置抗锯齿
g2.drawImage(bi1, 0, 0, null);
// 设置颜色
g2.setBackground(Color.green);
g2.dispose();
return bi2;
}