java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: 这篇文章介绍了如何使用Java后端技术,结合Graphics2D和Echarts等工具,生成包含个性化信息和图表的海报,并提供了详细的代码实现和GitHub项目链接。

先看成品

  • 做成海报样品如下:(第二个是java后端使用echarts生成)

  • 海报原模板如下:

前言

  1. 文字换行算法详解,传送门:java制作海报一:java使用Graphics2D 在图片上写字,文字换行算法详解
  2. 头像切割成圆形方法详解,传送门:java制作海报二:java使用Graphics2D 在图片上合成另一个照片,并将照片切割成头像,头像切割成圆形方法详解
  3. 获取微信二维码详情,传送门:java制作海报三:获取微信二维码详情,并改变大小,合成到海报(另一张图片)上
  4. java BufferedImage 转 InputStreampng 图片合成到模板(另一个图片)上时,透明部分变成了黑色,传送门:java制作海报四:java BufferedImage 转 InputStream 上传至OSS。png 图片合成到模板(另一个图片)上时,透明部分变成了黑色
  5. java 整合echarts 画出 折线图,传送门:
  6. Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题,传送门:java制作海报六:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题
  7. 项目部署到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_RGB
        Graphics2D 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_HRGB
        g2d.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 = "爱吃鱼的猫";
        // headUrl
        String 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 = "生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息生豆商信息"; // 42
            if (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);

            // 画字:nickName
            PosterUtil.drawWords(bufferedImage, nickName, false, wordsFont, 28, 158, 90, 1000, 26);
            // 画字:rawInfoMood:为您诚挚推荐生豆信息
            PosterUtil.drawWords(bufferedImage, rawInfoMood, false, wordsFont, 20, 158, 125, 1000, 19);
            // 画字:title

            PosterUtil.drawWords(bufferedImage, title, true, wordsFont, 36, 88, 265, 552, 119);
            // 画字:provider
            PosterUtil.drawWords(bufferedImage, provider, false, wordsFont, 30, 89, 870, 552, 100);
            // 画字:remark
            PosterUtil.drawWords(bufferedImage, remark, false, wordsFont, 24, 88, 1000, 552, 70);

            // 海报 保存到本地
            PosterUtil.save(bufferedImage, "png", "d:\\singleRawBeanBackground.png");

            // 上传到 OSS
            ByteArrayOutputStream 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 = "爱吃鱼的猫";
        // headUrl
        String 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);

            // 画字:nickName
            PosterUtil.drawWords(bufferedImage, nickName, false, wordsFont, 28, 158, 90, 1000, 26);
            // 画字:rawInfoMood:为您诚挚推荐生豆信息
            PosterUtil.drawWords(bufferedImage, rawInfoMood, false, wordsFont, 20, 158, 125, 1000, 19);
            // 画字:title
            PosterUtil.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");

            // 上传值 OSS
            ByteArrayOutputStream 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_token
        String 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、效果

在这里插入图片描述

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
3月前
|
前端开发
后端返回图片二进制流,前端转base64
本文介绍了如何将后端返回的图片二进制流转换为Base64格式,以便在前端使用。通过在axios请求中设置`responseType`为`arraybuffer`,然后使用`btoa`和`Uint8Array`进行转换。
336 5
|
4天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
22 3
|
3月前
Echarts中横坐标文字显示不全
本文讨论了在ECharts中横坐标文字显示不全的问题,并通过设置`xAxis`的`axisLabel.interval`属性为`0`来解决。这样设置后,横坐标上的所有标签都会显示,而不会根据自动计算的间隔来显示部分标签。文章提供了问题的具体示例图片和解决方法,并附有官方文档链接。
103 4
Echarts中横坐标文字显示不全
|
2月前
|
JavaScript 前端开发 API
vue获取图片的blob传给django后端
vue获取图片的blob传给django后端
53 4
|
2月前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
26 1
|
2月前
|
算法 Java Linux
java制作海报一:java使用Graphics2D 在图片上写字,文字换行算法详解
这篇文章介绍了如何在Java中使用Graphics2D在图片上绘制文字,并实现自动换行的功能。
147 0
|
4月前
|
消息中间件 Java Kafka
【Azure 事件中心】在微软云中国区 (Mooncake) 上实验以Apache Kafka协议方式发送/接受Event Hubs消息 (Java版)
【Azure 事件中心】在微软云中国区 (Mooncake) 上实验以Apache Kafka协议方式发送/接受Event Hubs消息 (Java版)
114 1
|
4月前
|
数据采集 人工智能 监控
【Azure 应用程序见解】Application Insights Java Agent 3.1.0的使用实验,通过修改单个URL的采样率来减少请求及依赖项的数据采集
【Azure 应用程序见解】Application Insights Java Agent 3.1.0的使用实验,通过修改单个URL的采样率来减少请求及依赖项的数据采集
|
16天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
2天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。
下一篇
DataWorks