java后端生成微信分享图片:使用freemarker、cssbox

使用freemarker、cssbox生成微信分享图片

1. 生成微信图片我所想的有两种方式

  • 利用图片水印来制作,可以先制作好想要的模板在利用水印将相应的内容添加打相应的位置完成
  • 利用freemarker生成模板html、在使用cssbox将html转换为png图片

2. 想到的两种方法各有好处

  • 1方法如果在操作很多可变变量的时候就回变得非常麻烦,但是这个处理是oss处理的不会占用你服务器的资源,而且是比较快的
  • 2方法就比一方法相对来说就要慢一些了,但是比一要灵活很多,该方法主要基于cssbox对html与css的解析所以是需要填他框架的一些坑比如说一些css无法识别

3. 准备工作

  • 准备引入freeMarker,cssbox包
<properties>
    <version.cssbox>4.14</version.cssbox>
    <version.freemarker>2.3.28</versio.freemarker>
</properties>

<dependencies>
 <dependency>
    <groupId>net.sf.cssbox</groupId>
    <artifactId>cssbox</artifactId>
    <version>${version.cssbox}</version>
 </dependency>
 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker<artifactId>
    <version>${version.freemarker}</version>
 </dependency>
</dependencies>


  • 准备使用freeMarker 使用spring boot 在yml配置文件添加配置
freemarker:
    cache: false
    charset: UTF-8 
    check-template-location: true
    content-type: text/html #生成模板类型选择html
    enabled: true
    suffix: .ftl            #设置默认读取模板文件的后缀
    template-loader-path: classpath:/templates #模板文件所在的地址
  • freemarker的service
public interface ITemplateService {
     //我返回的输入流在后面好输入到cssbox
     InputStream getHtmlInputStream(Map<String, Object> root, String template) throws Exception;
}
@Service
public class TemplateServiceImpl implements ITemplateService {
    @Resource
    Configuration cfg;

    /**
     *  获取生成模板inputStream
     * @param root
     * @param template
     * @return
     * @throws Exception
     */
    public InputStream getHtmlInputStream(Map<String,Object> root,String template) throws Exception {

        Template temp = cfg.getTemplate(template+".ftl");
        StringWriter out = new StringWriter();
        temp.process(root, out);

        StringBuffer buffer = out.getBuffer();

        return  new ByteArrayInputStream(new String(buffer).getBytes());
    }

}

创建模板文件我的模板文件比较多就不粘出来了

  • 使用freemarker
        //map 里存的模板里面可以用的变量
        HashMap<String, Object> map = new HashMap<>();
        //背景图
        map.put("background", shareService.getRandomPic().getPicUrl());

        InputStream htmlStream = templateService.getHtmlInputStream(map, "activity_details_singer");

得到的输入流到时候可以用于cssbox

  • 准备cssbox

复写 DocumentSource 文档源添加输入源方式输入流输入

public class StreamAndUrlDocumentSource extends DocumentSource {
    private InputStream inputStream;
    private static String USER_AGENT = "Mozilla/5.0 (compatible; BoxBrowserTest/4.x; Linux) CSSBox/4.x (like Gecko)";
    private URLConnection con;

    public StreamAndUrlDocumentSource(URL base, String urlstring) throws IOException {
        super(base, urlstring);
        URL url = DataURLHandler.createURL(base, urlstring);
        this.con = this.createConnection(url);
        this.inputStream = null;
    }
    public StreamAndUrlDocumentSource(URL url) throws IOException {
        super(url);
        this.con = this.createConnection(url);
        this.inputStream = null;
    }
    public StreamAndUrlDocumentSource(String urlstring) throws IOException {
        super((URL)null, urlstring);
        URL url = DataURLHandler.createURL((URL)null, urlstring);
        this.con = this.createConnection(url);
        this.inputStream = null;
    }
    public StreamAndUrlDocumentSource(InputStream inputStream) throws IOException {
        super(null);
        this.inputStream =inputStream;
    }

    @Override
    public URL getURL() {

        URL url =null;
        if(this.con != null)
            url = this.con.getURL();
        return url;
    }

    @Override
    public String getContentType() {
        String s =null;
        if(this.con != null)
            s = this.con.getHeaderField("Content-Type");
        return s;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        if (this.inputStream == null) {
            this.inputStream = this.con.getInputStream();
        }
        return this.inputStream;
    }

    @Override
    public void close() throws IOException {
        if (this.inputStream != null) {
            this.inputStream.close();
        }
    }

    protected URLConnection createConnection(URL url) throws IOException {
        URLConnection con = url.openConnection();
        con.setRequestProperty("User-Agent", USER_AGENT);
        return con;
    }
}

cssbox 的service

public interface IShareService {
    void htmlToPicture(DocumentSource docSource, OutputStream out, Dimension windowSize) throws IOException, SAXException;

}
public class ShareServiceImpl extends BaseService<IShareService> implements IShareService {
    private String mediaType = "screen";
    //方法的out是生成图片后的输出流
    @Override
    public void htmlToPicture(DocumentSource docSource, OutputStream out, Dimension windowSize) throws IOException, SAXException {

        DOMSource parser = new DefaultDOMSource(docSource);
        Document doc = parser.parse();

        MediaSpec media = new MediaSpec(mediaType);
        media.setDimensions((float)windowSize.width, (float)windowSize.height);
        media.setDeviceDimensions((float)windowSize.width, (float)windowSize.height);
        DOMAnalyzer da = new DOMAnalyzer(doc);
        da.setMediaSpec(media);
        da.attributesToStyles();

        da.addStyleSheet((URL)null, CSSNorm.stdStyleSheet(), DOMAnalyzer.Origin.AGENT);
        da.addStyleSheet((URL)null, CSSNorm.userStyleSheet(), DOMAnalyzer.Origin.AGENT);
        da.addStyleSheet((URL)null, CSSNorm.formsStyleSheet(), DOMAnalyzer.Origin.AGENT);
        da.getStyleSheets();
        BrowserCanvas contentCanvas = new BrowserCanvas(da.getRoot(), da, docSource.getURL());
        contentCanvas.setAutoMediaUpdate(false);
        contentCanvas.getConfig().setClipViewport(false);
        contentCanvas.getConfig().setLoadImages(true);
        contentCanvas.getConfig().setLoadBackgroundImages(true);

        contentCanvas.createLayout(windowSize);
        //生成图片的类型可以是svg
        ImageIO.write(contentCanvas.getImage(), "png", out);
        docSource.close();
    }
  • 使用cssbox
//接收的输出流
ByteArrayOutputStream out = new ByteArrayOutputStream();
//htmlStream 生成的html输入流
//streamAndUrlDocumentSource为 生成png的文件源
StreamAndUrlDocumentSource streamAndUrlDocumentSource = new StreamAndUrlDocumentSource(htmlStream);

shareService.htmlToPicture(streamAndUrlDocumentSource, out, new Dimension(width, height));
//关闭输入流
htmlStream.close();

ps:如果你想接口直接返回一直图片的可以将out设置为:

//response 为 HttpServletResponse
 ServletOutputStream out = response.getOutputStream()

这样你请求接口就直接返回的是一张图片

  • 关于这个out可以随便处理放入文件,上传oss,转base64都可以

  • 最后的生成效果

  • image

  • 二维码与上面的文字与背景图都是变化的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尘锿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值