java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
文章目录
- 先看成品
- 前言
- 一、项目目录结构
- 一、海报制作PosterUtil.java工具类
- 1. 描述
- 2. 代码
- 二、测试生成海报
- 1. 描述
- 2. 直接上代码
- 四、其他测试
- 1. Test1_CreateImage 测试创建图片
- a、代码
- b、效果
- 2. Test2_CreateEcharts 创建echarts图
- a、代码
- b、效果
- 3. Test3_HeadImageToCircle 创建圆形头像
- a、代码
- b、效果
先看成品
做成海报样品如下:(第二个是java后端使用echarts生成)
海报原模板如下:
前言
刚做的微信小程序,用户说要加个海报功能,而且是
用java在后端生成
,直接返回给前端一个URL, 就有点费劲啦,以前没整过,然后开始研究,用了三天的时间把样品做出来了,先送上来给大家看看,除了二维码是真的,其余都是假的,也请大家不要乱搞哦,菜鸟在这里谢过啦。java 整合echarts
用了一天时间,也是比较费心呢。代码都上传到GitHub了,这里仅仅是贴出来主要部分,GitHub传送门:https://github.com/fengfanli/draw_poster_echarts
问题总结
总博客:java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
文字换行算法详解
,传送门:java制作海报一:java使用Graphics2D 在图片上写字,文字换行算法详解头像切割成圆形方法详解
,传送门:java制作海报二:java使用Graphics2D 在图片上合成另一个照片,并将照片切割成头像,头像切割成圆形方法详解获取微信二维码详情
,传送门:java制作海报三:获取微信二维码详情,并改变大小,合成到海报(另一张图片)上java BufferedImage 转 InputStream
和png 图片合成到模板(另一个图片)上时,透明部分变成了黑色
,传送门:java制作海报四:java BufferedImage 转 InputStream 上传至OSS。png 图片合成到模板(另一个图片)上时,透明部分变成了黑色java 整合echarts 画出 折线图
,传送门:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题
,传送门:java制作海报六:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题项目部署到linux下中文不显示,echarts图上的中文也不显示问题
,传送门:java制作海报七:java Graphics2D 合成图片 在 linux下中文不显示,echarts图上的中文也不显示问题
一、项目目录结构
运行 Main_CreatePosterAndEchart
类 可以直接生成。注意一下 OSS ,我这里给删除了一点,可以注释掉,生成保存到本地。
一、海报制作PosterUtil.java工具类
1. 描述
里面是制作海报的工具类,手写了一些方法,比如:写文字方法(里面包括了换行算法)、画图片方法、头像切割成圆形方法、保存到本地方法、改变图片的大小方法等等。
2. 代码
package com.feng.posterUtils;import sun.font.FontDesignMetrics;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;/*** @ClassName PictorialUtils* @Description TODO* @Author fengfanli* @Date 2021/3/29 16:48* @Version 1.0*/
public class PosterUtil {/*** @return java.awt.image.BufferedImage* @Author fengfanli* @Description //TODO 初始化背景模板* @Date 9:55 2021/3/30* @Param [path]**/public static BufferedImage drawInit(String path, InputStream inputStream) throws Exception {BufferedImage canvas = null;if (path != null) {URL url = new URL(path);canvas = ImageIO.read(url);}if (inputStream != null) {canvas = ImageIO.read(inputStream);}return canvas;}/*** @return java.awt.image.BufferedImage* @Author fengfanli* @Description //TODO 初始化模板并改变宽度和高度* @Date 9:56 2021/3/30* @Param [path, width, height]**/public static BufferedImage drawInitAndChangeSize(String path, InputStream inputStream, int width, int height) throws Exception {BufferedImage canvas = null;if (path != null) {URL url = new URL(path);canvas = ImageIO.read(url);}if (inputStream != null) {canvas = ImageIO.read(inputStream);}canvas = changeSize(canvas, width, height);return canvas;}/*** @return java.awt.image.BufferedImage* @Author fengfanli* @Description // TODO 改变宽度和高度:先画一个空白的图,再将需要改变大小的图 画上去,再限制大小* @Date 9:56 2021/3/30* @Param [originalImage, width, height]**/public static BufferedImage changeSize(BufferedImage originalImage, int width, int height) {// 抗锯齿BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // originalImage.getType() 改为 BufferedImage.TYPE_INT_RGBGraphics2D g2d = image.createGraphics();image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.OPAQUE);g2d = image.createGraphics();g2d.drawImage(originalImage, 0, 0, width, height, null);g2d.dispose();return image;}/*** @return java.awt.image.BufferedImage* @Author fengfanli* @Description //TODO 在背景模板上放置 image* @Date 9:57 2021/3/30* @Param [canvas, logo, logoX, logoY]**/public static void drawImage(BufferedImage canvas, BufferedImage logo, int logoX, int logoY) {Graphics2D g2d = canvas.createGraphics();//g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1));g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g2d.drawImage(logo, logoX, logoY, null);g2d.dispose();}/*** @return java.awt.image.BufferedImage* @Author fengfanli* @Description //TODO 画图 改变背景颜色,并改变大小(原图片先生成,合成时在缩小)* TODO 重点1 :图片合成时会出现失真的情况。* TODO 合成方案有两种:a、原图片先缩小,在合成(会失真)* TODO b、原图片先生成,合成时在缩小(会好点)* @Date 9:57 2021/3/30* @Param [canvas, logo, logoX, logoY]**/public static void drawImageAndChangeBackgroundColorAndChangeSize(BufferedImage canvas, BufferedImage logo, Integer logoX, Integer logoY, Integer width, Integer height) throws IOException {Graphics2D g2d = canvas.createGraphics();// 解决png透明图片会变黑的问题(画一个新图片,然后合成,记得透明度)Graphics2D graphics = logo.createGraphics();BufferedImage compatibleImage = null;compatibleImage = graphics.getDeviceConfiguration().createCompatibleImage(logo.getWidth(null), logo.getHeight(null), BufferedImage.TYPE_INT_RGB);// 下面这行也可以代替上面这行//BufferedImage compatibleImage = new BufferedImage(image.getWidth(), image.getHeight(), Transparency.TRANSLUCENT);graphics = compatibleImage.createGraphics();graphics.drawImage(logo, 0, 0, logo.getWidth(null), logo.getHeight(null), null);graphics.dispose();// 合成图片g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);g2d.drawImage(compatibleImage, logoX, logoY, width, height, null);g2d.dispose();}/*** @return void* @Author fengfanli* @Description //TODO 画图 改变背景颜色* TODO 重点1 :png图片合成到另一个图片时,透明地带出现黑色情况, 原因:Graphics2D 创建图片背景为黑色* @Date 16:31 2021/4/8* @Param [canvas, logo, logoX, logoY]**/public static void drawImageAndChangeBackgroundColor(BufferedImage canvas, BufferedImage logo, Integer logoX, Integer logoY) throws IOException {Graphics2D g2d = canvas.createGraphics();// 解决png透明图片会变黑的问题(画一个新图片,然后合成,记得透明度)Graphics2D graphics = logo.createGraphics();BufferedImage compatibleImage = graphics.getDeviceConfiguration().createCompatibleImage(logo.getWidth(null), logo.getHeight(null), Transparency.TRANSLUCENT);// 下面这行也可以代替上面这行//BufferedImage compatibleImage = new BufferedImage(image.getWidth(), image.getHeight(), Transparency.TRANSLUCENT);graphics = compatibleImage.createGraphics();graphics.drawImage(logo, 0, 0, null);graphics.dispose();// 合成图片g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);g2d.drawImage(compatibleImage, logoX, logoY, null);g2d.dispose();}/*** @return java.awt.Graphics2D* @Author fengfanli* @Description //TODO 在背景模板上写字,注意 需要换行算法* @Date 9:58 2021/3/30* @Param [bufferedImage, words, wordsFont, fontSize, wordsX, wordsY, wordsWidth, wordsHeight]**/public static void drawWords(BufferedImage bufferedImage, String words, Boolean isAddFontSpace, String wordsFont, int fontSize, int wordsX,int wordsY, int wordsWidth, int wordsHeight) {Graphics2D g2d = bufferedImage.createGraphics();// 抗锯齿 添加文字g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); // VALUE_TEXT_ANTIALIAS_ON 改为 VALUE_TEXT_ANTIALIAS_LCD_HRGBg2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g2d.getDeviceConfiguration().createCompatibleImage(wordsWidth, wordsHeight, Transparency.TRANSLUCENT);Font font = new Font(wordsFont, Font.BOLD, fontSize);g2d.setFont(font);Color color = new Color(51, 51, 51);g2d.setColor(color);// 换行算法drawWordAndLineFeed(g2d, font, words, wordsX, wordsY, wordsWidth);g2d.dispose();}/*** @return void* @Author fengfanli* @Description //TODO 写字换行算法* @Date 18:08 2021/4/1* @Param []**/private static void drawWordAndLineFeed(Graphics2D g2d, Font font, String words, int wordsX, int wordsY, int wordsWidth) {FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);// 获取字符的最高的高度int height = metrics.getHeight();int width = 0;int count = 0;int total = words.length();String subWords = words;int b = 0;for (int i = 0; i < total; i++) {// 统计字符串宽度 并与 预设好的宽度 作比较if (width <= wordsWidth) {width += metrics.charWidth(words.charAt(i)); // 获取每个字符的宽度count++;} else {// 画 除了最后一行的前几行String substring = subWords.substring(0, count);g2d.drawString(substring, wordsX, wordsY + (b * height));subWords = subWords.substring(count);b++;width = 0;count = 0;}// 画 最后一行字符串if (i == total - 1) {g2d.drawString(subWords, wordsX, wordsY + (b * height));}}}/*** @return java.awt.image.BufferedImage* @Author fengfanli* @Description //TODO 将正方形的头像 改为 圆形头像* @Date 14:37 2021/3/31* @Param [imgUrl, width]**/public static BufferedImage drawImgToCircle(String imgUrl, int width) throws IOException {BufferedImage avatarImage = ImageIO.read(new URL(imgUrl));//int width = 120;// 透明底的图片BufferedImage formatAvatarImage = new BufferedImage(width, width, BufferedImage.TYPE_4BYTE_ABGR);Graphics2D graphics = formatAvatarImage.createGraphics();//把图片切成一个圓{// 抗锯齿graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//留一个像素的空白区域,这个很重要,画圆的时候把这个覆盖int border = 1;//图片是一个圆型Ellipse2D.Double shape = new Ellipse2D.Double(border, border, width - border * 2, width - border * 2);//需要保留的区域graphics.setClip(shape);graphics.drawImage(avatarImage, border, border, width - border * 2, width - border * 2, null);graphics.dispose();}return formatAvatarImage;}/*** @return java.lang.String* @Author fengfanli* @Description //TODO 存放到本地* @Date 9:58 2021/3/30* @Param [canvas, type, urlPath]**/public static void save(BufferedImage canvas, String type, String urlPath) throws Exception {ImageIO.write(canvas, type, new File(urlPath));}
}
二、测试生成海报
1. 描述
注释很详细,直接看注释即可
2. 直接上代码
package com.feng.controller;import com.alibaba.fastjson.JSONObject;
import com.feng.bean.BakeEventList;
import com.feng.bean.PhotoSeaMainModel;
import com.feng.bean.XfxUserbaseModel;
import com.feng.echartsUtils.EchartsUtil;
import com.feng.echartsUtils.HttpUtil;
import com.feng.fileUtils.PropertiesFileUtil;
import com.feng.ossUtils.OssUtil;
import com.feng.posterUtils.PosterUtil;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.*;/*** @ClassName Main* @Description TODO* @Author admin* @Date 2021/3/30 15:21* @Version 1.0*/
public class Main_CreatePosterAndEchart {public static void main(String[] args) {// 生成海报Map<String, Object> result = createPoster();System.out.println(result);// 生成 带echarts图的海报Map<String, Object> posterDrawEchartTable = createPosterDrawEchartTable();System.out.println(posterDrawEchartTable);}/*** @Author fengfanli* @Description //TODO 创建海报,画字、画图* @Date 17:41 2021/4/8* @Param []* @return java.util.Map<java.lang.String,java.lang.Object>**/public static Map<String, Object> createPoster() {String nickName = "爱吃鱼的猫";// headUrlString headUrl = "https://img-blog.csdn.net/20180529211243786?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3plbmdyZW55dWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/7";// 单品生豆背景模板图String background = "https://xkximg.xiaokaxia.com/wx/1/9dfb96f770e64642835289912cc13c46.png";// 统一字体 格式String wordsFont = "平方-简";Map<String, Object> map = new HashMap<>();try {// 初始化模板图BufferedImage bufferedImage = PosterUtil.drawInit(background, null);// 将头像图片处理成圆形BufferedImage head = PosterUtil.drawImgToCircle(headUrl, 92);// 画 微信头像PosterUtil.drawImage(bufferedImage, head, 49, 49);// 下面三个数据都可以从数据库中动态获取String title = "布隆迪BURUNDI恩戈齐NGOZI2020-2021瑰夏GEISHA日晒处理";String provider = "生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息"; // 42if (provider.length() > 42) {provider = provider.substring(0, 42) + "...";}String remark = "备注信息备注信息备注信息备注信息备注信息备注信息备注信息备注信息备注信息备注信息";if (remark.length() > 28) {remark = remark.substring(0, 28) + "...";}String rawInfoMood = "为您诚挚推荐生豆信息";// 画 二维码 并改变大小// 1. 先 获取二维码(二维码携带一个参数)InputStream erWeiMa = getErWeiMa(1);// 2. 初始化并的改变大小BufferedImage logoImg = PosterUtil.drawInitAndChangeSize(null, erWeiMa, 130, 130);// 将二维码保存到本地PosterUtil.save(logoImg, "png", "d:\\test.png");// 3. 画二维码PosterUtil.drawImage(bufferedImage, logoImg, 532, 1108);// 自定义咖啡背景图片String customCoffeeImageUrl = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1789442356,2769602647&fm=26&gp=0.jpg";BufferedImage coffeeImage = PosterUtil.drawInitAndChangeSize(customCoffeeImageUrl, null, 575, 431);PosterUtil.drawImage(bufferedImage, coffeeImage, 87, 379);// 画字:nickNamePosterUtil.drawWords(bufferedImage, nickName, false, wordsFont, 28, 158, 90, 1000, 26);// 画字:rawInfoMood:为您诚挚推荐生豆信息PosterUtil.drawWords(bufferedImage, rawInfoMood, false, wordsFont, 20, 158, 125, 1000, 19);// 画字:titlePosterUtil.drawWords(bufferedImage, title, true, wordsFont, 36, 88, 265, 552, 119);// 画字:providerPosterUtil.drawWords(bufferedImage, provider, false, wordsFont, 30, 89, 870, 552, 100);// 画字:remarkPosterUtil.drawWords(bufferedImage, remark, false, wordsFont, 24, 88, 1000, 552, 70);// 海报 保存到本地PosterUtil.save(bufferedImage, "png", "d:\\singleRawBeanBackground.png");// 上传到 OSSByteArrayOutputStream os = new ByteArrayOutputStream();ImageIO.write(bufferedImage, "png", os);InputStream inputStream = new ByteArrayInputStream(os.toByteArray());// map = uploadShareSeaImg(inputStream, "bakeShare", request);map = uploadShareSeaImg(inputStream, "bakeShare");return map;} catch (Exception e) {System.out.println("PictorialController createPoster error:" + e.getLocalizedMessage());return null;}}/*** @Author fengfanli* @Description //TODO 创建海报,画字,画图,画echarts图* @Date 17:41 2021/4/8* @Param []* @return java.util.Map<java.lang.String,java.lang.Object>**/public static Map<String, Object> createPosterDrawEchartTable() {String nickName = "爱吃鱼的猫";// headUrlString headUrl = "https://img-blog.csdn.net/20180529211243786?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3plbmdyZW55dWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/7";// 单品烘焙背景模板图String background = "https://xkximg.xiaokaxia.com/wx/1/fb16ea06f66644009f54b8efbb670bd2.png";// 统一字体 格式String wordsFont = "平方-简";Map<String, Object> map = new HashMap<>();try {// 初始化模板图BufferedImage bufferedImage = PosterUtil.drawInit(background, null);// 将头像图片处理成圆形BufferedImage head = PosterUtil.drawImgToCircle(headUrl, 92);// 画 微信头像PosterUtil.drawImage(bufferedImage, head, 49, 49);// 下面三个数据都可以从数据库中动态获取String title = "布隆迪BURUNDI恩戈齐NGOZI2020-2021瑰夏GEISHA日晒处理";String rawInfoMood = "为您诚挚推荐烘焙信息";// 画 二维码 并改变大小// 1. 先 获取二维码(二维码携带一个参数)InputStream erWeiMa = getErWeiMa(1);// 2. 初始化并的改变大小BufferedImage logoImg = PosterUtil.drawInitAndChangeSize(null, erWeiMa, 130, 130);// 将二维码保存到本地PosterUtil.save(logoImg, "png", "d:\\test.png");// 3. 画二维码PosterUtil.drawImage(bufferedImage, logoImg, 532, 1108);// 自定义咖啡背景图片String customCoffeeImageUrl = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1789442356,2769602647&fm=26&gp=0.jpg";BufferedImage coffeeImage = PosterUtil.drawInitAndChangeSize(customCoffeeImageUrl, null, 575, 287);PosterUtil.drawImage(bufferedImage, coffeeImage, 87, 379);// 画字:nickNamePosterUtil.drawWords(bufferedImage, nickName, false, wordsFont, 28, 158, 90, 1000, 26);// 画字:rawInfoMood:为您诚挚推荐生豆信息PosterUtil.drawWords(bufferedImage, rawInfoMood, false, wordsFont, 20, 158, 125, 1000, 19);// 画字:titlePosterUtil.drawWords(bufferedImage, title, true, wordsFont, 36, 88, 265, 552, 119);// 画表格List<BakeEventList> bakeEventLists = new ArrayList<>();bakeEventLists.add(new BakeEventList("12:01", 10.10));bakeEventLists.add(new BakeEventList("13:01", 15.10));bakeEventLists.add(new BakeEventList("14:01", 18.10));bakeEventLists.add(new BakeEventList("15:01", 5.10));bakeEventLists.add(new BakeEventList("16:01", 4.10));try {EchartsUtil.createEcharts(bufferedImage, bakeEventLists);} catch (Exception e) {System.out.println("PosterController createPoster bake draw table error:" + e);}// 海报 保存到本地PosterUtil.save(bufferedImage, "png", "d:\\singleRawBeanBackground.png");// 上传值 OSSByteArrayOutputStream os = new ByteArrayOutputStream();ImageIO.write(bufferedImage, "png", os);InputStream inputStream = new ByteArrayInputStream(os.toByteArray());
// map = uploadShareSeaImg(inputStream, "bakeShare", request);map = uploadShareSeaImg(inputStream, "bakeShare");return map;} catch (Exception e) {System.out.println("PictorialController createPictorial error:" + e.getLocalizedMessage());return null;}}/*** @return java.io.InputStream* @Author fengfanli* @Description //TODO 从微信平台 获取小程序二维码* @Date 16:53 2021/4/1* @Param []**/public static InputStream getErWeiMa(Integer id) {// 获取二维码:1、先获取access_token 2、在获取 二维码String appId = PropertiesFileUtil.getInstance("app").get("wx.app.ip");String appSecret = PropertiesFileUtil.getInstance("app").get("wx.app.secret");System.out.println("appId==" + appId + ";appSecret==" + appSecret);// 获取 access_tokenString getUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;System.out.println("getUrl==" + getUrl);String str = HttpUtil.sendGet(getUrl);JSONObject json = (JSONObject) JSONObject.parse(str);String access_token = (String) json.get("access_token");System.out.println("access_token:" + access_token);// 获取 二维码图片流String postURL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + access_token;System.out.println("postURL==" + postURL);JSONObject jsonObject = new JSONObject();// 这里往二维码里放入前端传过来的 id,前端获取之后,根据id 去获取详情jsonObject.put("scene", id);String scene = JSONObject.toJSONString(jsonObject);InputStream inputStream = null;inputStream = HttpUtil.sendPostForErWeiMa(postURL, scene);return inputStream;}/*** @return java.util.Map<java.lang.String , java.lang.Object>* @Author fengfanli* @Description //TODO 上传生成的海报 上传到云服务器 并返回给前端 url* @Date 16:54 2021/4/1* @Param [inputStream, shareCategory, request]**/public static Map<String, Object> uploadShareSeaImg(InputStream inputStream, String shareCategory) {// 获取用户的目的是为了 1、文件新名称,2、将海报添加到数据库做记录// XfxUserbaseModel user = upmsSessionDao.getUser(request); // 通过 request 获取当前用户信息。XfxUserbaseModel user = new XfxUserbaseModel(); // 就是一个用户实体类user.setId(1);// 新名称String newFileName = UUID.randomUUID().toString().replace("-", "") + ".png";String key = "wx/" + user.getId() + "/" + shareCategory + "/" + newFileName;String ok = OssUtil.uploadImg(key, inputStream);if (!"OK".equals(ok)) {System.out.println("PosterController oss uploadShareSeaImg fail:" + user.getId());}Map<String, Object> map = new HashMap<>(2);map.put("ossKey", key);map.put("fileUrl", OssUtil.getImgUrl(key));// 将做好的海报URL oss key 放到 数据库PhotoSeaMainModel model = new PhotoSeaMainModel();model.setUserId(user.getId());model.setTitle(shareCategory);model.setFileOss(key);// photoSeaService.addPhotoSeaModel(model);return map;}}
四、其他测试
1. Test1_CreateImage 测试创建图片
a、代码
package com.feng.controller;import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;public class Test1_CreateImage {/*** @Author fengfanli* @Description //TODO 生成一个白色的图片* @Date 15:51 2021/4/8* @Param [args]* @return void**/public static void main(String[] args) throws Exception {BufferedImage bufIma = new BufferedImage( 50, 50, BufferedImage.TYPE_INT_RGB);Graphics2D g2d = bufIma.createGraphics();g2d.setBackground(new Color(255, 255, 255));g2d.clearRect(0, 0, 50, 50);ImageIO.write(bufIma, "png", new File("d:\\6.png"));}
}
b、效果
2. Test2_CreateEcharts 创建echarts图
a、代码
package com.feng.controller;import com.alibaba.fastjson.JSON;
import com.feng.echartsUtils.EchartsUtil;
import com.feng.echartsUtils.FreemarkerUtil;
import freemarker.template.TemplateException;
import org.apache.http.client.ClientProtocolException;import java.io.IOException;
import java.util.HashMap;/*** @ClassName CreateEcharts* @Description TODO* @Author admin* @Date 2021/4/8 15:40* @Version 1.0*/
public class Test2_CreateEcharts {/*** @Author fengfanli* @Description //TODO 创建一个echarts图* @Date 18:06 2021/4/8* @Param [args]* @return void**/public static void main(String[] args) throws ClientProtocolException, IOException, TemplateException {// 变量String title = "水果";String[] categories = new String[]{"苹果", "香蕉", "西瓜"};int[] values = new int[]{3, 2, 1};// 模板参数HashMap<String, Object> datas = new HashMap<>();datas.put("categories", JSON.toJSONString(categories));datas.put("values", JSON.toJSONString(values));datas.put("title", title);// 生成option字符串String option = FreemarkerUtil.generateString("option.ftl", "echarts", datas);// 根据option参数String base64 = EchartsUtil.generateEchartsBase64(option);System.out.println("BASE64:" + base64);EchartsUtil.generateImage(base64, "C:\\Users\\admin\\Desktop\\test.png");}
}
b、效果
3. Test3_HeadImageToCircle 创建圆形头像
a、代码
package com.feng.controller;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;/*** Created by zengrenyuan on 18/5/29.*/
/*** @Author fengfanli* @Description //TODO 将头像画成圆形* @Date 18:29 2021/4/7* @Param * @return **/
public class Test3_HeadImageToCircle {/*** @Author fengfanli* @Description //TODO 将一个头像 变成圆形* @Date 18:11 2021/4/8* @Param [args]* @return void**/public static void main(String[] args) throws IOException {String url = "https://img-blog.csdn.net/20180529211243786?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3plbmdyZW55dWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/7";BufferedImage avatarImage = ImageIO.read(new URL(url));int width = 120;// 透明底的图片BufferedImage formatAvatarImage = new BufferedImage(width, width, BufferedImage.TYPE_4BYTE_ABGR);Graphics2D graphics = formatAvatarImage.createGraphics();//把图片切成一个圓{graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//留一个像素的空白区域,这个很重要,画圆的时候把这个覆盖int border = 1;//图片是一个圆型Ellipse2D.Double shape = new Ellipse2D.Double(border, border, width - border * 2, width - border * 2);//需要保留的区域graphics.setClip(shape);graphics.drawImage(avatarImage, border, border, width - border * 2, width - border * 2, null);graphics.dispose();}try (OutputStream os = new FileOutputStream("C:\\Users\\admin\\Desktop\\test2.png")) {ImageIO.write(formatAvatarImage, "PNG", os);}//在圆图外面再画一个圆{//新创建一个graphics,这样画的圆不会有锯齿graphics = formatAvatarImage.createGraphics();graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);int border = 3;//画笔是4.5个像素,BasicStroke的使用可以查看下面的参考文档//使画笔时基本会像外延伸一定像素,具体可以自己使用的时候测试Stroke s = new BasicStroke(4.5F, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);graphics.setStroke(s);graphics.setColor(Color.WHITE);graphics.drawOval(border, border, width - border * 2, width - border * 2);graphics.dispose();}try (OutputStream os = new FileOutputStream("C:\\Users\\admin\\Desktop\\test3.png")) {ImageIO.write(formatAvatarImage, "PNG", os);}{url = "https://img-blog.csdn.net/20180529213113521";BufferedImage srcImg = ImageIO.read(new URL(url));//scrImg加载完之后没有任何颜色BufferedImage blankImage = new BufferedImage(srcImg.getWidth(), srcImg.getHeight(), BufferedImage.TYPE_INT_RGB);graphics = blankImage.createGraphics();graphics.drawImage(srcImg, 0, 0, null);int x = (blankImage.getWidth() - width) / 2;int y = (blankImage.getHeight() - width) / 2;graphics.drawImage(formatAvatarImage, x, y, width, width, null);try (OutputStream os = new FileOutputStream("C:\\Users\\admin\\Desktop\\test4.png")) {ImageIO.write(blankImage, "PNG", os);}}}
}
b、效果
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题相关推荐
- Java中 LocalDate、LocalTime、LocalDateTime三个时间工具类的使用介绍
Java中 LocalDate.LocalTime.LocalDateTime三个时间工具类的使用介绍 一.背景: 之前在做项目的过程中,对日期时间类没有一个系统的了解,总是在用的时候去搜索一下,解决 ...
- Java时间工具类(把日期时间转换成xx秒前、xx分钟前、xx小时前...)
Java时间工具类(把日期时间转换成xx秒前.xx分钟前.xx小时前...) package com.liuzy.javaopen.entity; import java.text.ParseExce ...
- 采用itextpdf 实现java的PDF生成与导出功能,含封装工具类代码
引入jar包 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</a ...
- java实现二维码的生成和解析包含工具类
1.下载jar包( jdk1.7) 链接:https://pan.baidu.com/s/1LVq_zGsp_Po8V456h1TVmA 提取码:vqyd 2.工具类Utils.java packag ...
- java跳过_java跳过https证书直接请求工具类
/** * 过滤https协议 * @author edwin */ public class FiltratHttpsUtils { static HostnameVerifier hv = new ...
- java druid jdbc例子_JDBC【使用Druid连接数据库,DBUtils工具类的使用】
Druid连接数据库,DBUtils工具类的使用 1.在maven中添加Druid依赖 com.alibaba druid 1.2.0 2.封装Druid连接方法 import com.alibaba ...
- java中的locksupport_java中线程的停止以及LockSupport工具类
看jstack输出的时候,可以发现很多状态都是TIMED_WAITING(parking),如下所示: "http-bio-8080-exec-16" #70 daemon pri ...
- java读写excel文件poi_Java利用POI读写Excel文件工具类
本文实例为大家分享了Java读写Excel文件工具类的具体代码,供大家参考,具体内容如下 package com.test.app.utils; import java.io.File; import ...
- java des加密解密_Java实现的DES加密解密工具类实例
本文实例讲述了Java实现的DES加密解密工具类.分享给大家供大家参考,具体如下: 一个工具类,很常用,不做深入研究了,那来可直接用 DesUtil.java package lsy; import ...
最新文章
- linux sudo命令错误 is not in the sudoers file
- 跟我一起写 Makefile(十二)
- 虚拟机种mysql的安装_RedHat7.0虚拟机下mysql安装
- MySQL分库分表分库准备(6th)
- Rust 社区求变,PHP 大旗不倒?
- Python 中,matplotlib绘图无法显示中文的问题
- 【转载】贝叶斯决策论
- Adobe Illustrator CS6 绿色简体中文版下载地址
- Python的继承与多继承
- 字节、十六进制字符串相互转换(asc2hex、hex2asc)
- 一个小巧好用的Url编解码工具
- 关于ResourceBundle国际化的一些思考
- Go语言发展状况和前景
- 计算机网络中的基本器件(网卡,集线器,交换机,路由器)
- 谷俊丽分享之基于深度学习的大数据挖掘
- day9:JAVA中while的用法
- 【物联网】22.物联网开发之先进传感 - 立体相机
- 统计在线人数和登录人数
- 解决:ERROR kuhl m_privilege simple: Rtiadjustprivilege (20) c0000061
- vb.net 打印条形码code39、code128A、code128C、code128Auto(picturebox和打印机)封装类
热门文章
- 【U8】填制凭证输入完摘要,回车后报错运行时错误70,拒绝的权限。
- GEE开发2——GPP/ET数据的下载
- Quest 3d中Lua script中常用方法1
- java machine 报错_Rhapsody启动过程显示[Cannot Find Java Virtual Machine file]错误信息
- 财务分析与决策——绪论
- DFX 安全测试-- 告诉你什么是XSS、sql注入?POST和GET的区别....
- 笔记:刘未鹏思考的技术与艺术(原“学会思考”)
- 构建智慧B2B集采商城系统,实现房地产行业采购业务的集中管控
- 【技术教程】ArcGIS入门教程来袭,零基础的同学快看过来!
- java 城市公交查询系统源码_基于Java的城市公交查询系统的毕业设计参考源码