Teach you Java 5 minutes to make posters and completely solve the problem of terminal compatibility

Posted by caminator on Wed, 26 Jan 2022 21:25:07 +0100

Teach you Java 5 minutes to make posters and completely solve the problem of terminal compatibility

1, Demand background

We often encounter such needs in the development of multi terminal applications: users feel good when browsing products and hope to share them with friends. At this time, we hope to generate a beautiful product poster and share it with others through wechat or other channels. There may also be a need to make personal business cards, print them or share them with others. The effect is like this:

(the above pictures are all from the Internet. They are only for reference and learning to avoid advertising. Some processing has been done.)

When we first designed this requirement, we completed it at the front end, that is, the functions are independently realized by developers of Android, IOS, H5 and wechat. After the development of each end is completed and released to the whole network, it is soon found that there are compatibility problems on some user models (there are many versions of Android models on the C end). The Android version of the user's mobile phone has changed from 5 N to the latest version, from ip6 to the latest version, with a maximum span of more than 10 years. This compatibility problem is unpredictable for us. The DOM to image and html2canvas I tried to use are not ideal. They solve the problems of white screen and cross domain, and they encounter the problem that the lower version does not support labels. After a toss, we finally decided to generate the poster image on the server and display the image directly on the terminal.

2, Generate posters with JAVA

From the above three posters, I randomly selected the picture of "beauty" as today's demonstration effect. (I didn't use the drawing on the previous project when doing this demonstration, and I was developing according to the drawing for the first time).

Firstly, the posters are divided into three categories: background picture, other pictures, text and QR code.

For example: 1-the base picture is pure white, 2-The product introduction picture, 3-The avatar material, 4-The picture material with the word "strict selection", 5-The two-dimensional code with color, 6-the text such as title and price. In the actual development, it can be based on the pictures given by vision and art engineering.

Let me finish the final effect first:

Simply do it. It's about the same as the visual picture. Although it's a little rough, it's enough to express the effect.

2.1 Easy Poster generator

In the process of developing posters, I also found a lot of materials and spent a lot of time. Later, I found that the design of Easy Poster was still good. Therefore, after the development, I reorganized and improved the code: fixed some problems, added the function of QR code, and became a poster generation tool out of the box.

Next, I will introduce how to make posters quickly.

Creating a new poster takes only 3 steps

  • Modify POM XML add dependency and package filter font library.
  • Create poster objects and configure related properties.
  • Pass in parameters to generate posters

2.2 modify POM XML add dependency and package filter font library.

pom.xml

<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <lombok.version>1.16.18</lombok.version>
    <hutool-all.version>5.7.19</hutool-all.version>
    <zxing.version>3.4.1</zxing.version>
    <testng.version>6.8.8</testng.version>
    <slf4j.version>1.7.13</slf4j.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <!-- QR code generation -->
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>${zxing.version}</version>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>${hutool-all.version}</version>
    </dependency>
    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>${testng.version}</version>
    </dependency>
</dependencies>
<!-- SpringBoot Project maven Font library referenced by the project font after maven of filter,Will destroy font Binary file format of the file -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <configuration>
                <nonFilteredFileExtensions>
                    <nonFilteredFileExtension>ttf</nonFilteredFileExtension>
                    <nonFilteredFileExtension>woff</nonFilteredFileExtension>
                    <nonFilteredFileExtension>woff2</nonFilteredFileExtension>
                </nonFilteredFileExtensions>
            </configuration>
        </plugin>
    </plugins>
</build>

*Note: our poster uses fonts as resource files. After maven's filter, the binary file format of font files will be destroyed, resulting in packaging exceptions. Please pay attention here.

2.3 creating poster objects and configuring related attributes

CommodityPosterPojo.java

package com.naiqing.poster.demo;

import com.quaint.poster.annotation.PosterBackground;
import com.quaint.poster.annotation.PosterBarCodeCss;
import com.quaint.poster.annotation.PosterFontCss;
import com.quaint.poster.annotation.PosterImageCss;
import com.quaint.poster.core.abst.AbstractDefaultPoster;
import com.quaint.poster.core.dto.PosterBarcode;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Tolerate;

import java.awt.*;
import java.awt.image.BufferedImage;

/**
 * 〈Product sharing poster elements and related parameter definitions < br >
 *
 * @author naiqing
 * @Date 2022/1/21
 * @see [Related classes / methods]
 * @since [Product / module version]
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
public class CommodityPoster2Pojo extends AbstractDefaultPoster {

    /**
     * Background map
     */
    @PosterBackground(width = 540, height = 868)
    private BufferedImage backgroundImage;

    /**
     * Commodity map
     */
    @PosterImageCss(position = {0, 0}, width = 540, height = 614)
    private BufferedImage commodityImage;

    /**
     * Strict selection icon
     */
    @PosterImageCss(position = {16, 625}, width = 50, height = 28)
    private BufferedImage yanxuanImage;
    /**
     * Product title
     */
    @PosterFontCss(position = {16, 625}, size = 22, canNewLine = {1, 482, 2}, style = Font.BOLD)
    private String commodityTitle;

    /**
     * Privilege price
     */
    @PosterFontCss(position = {16, 706}, size = 20, color = {247,23,61})
    private String vipPrice;
    /**
     * original price
     */
    @PosterFontCss(position = {16, 742}, size = 15, color = {51, 51, 51}, delLine = true)
    private String oldPrice;

    /**
     * head portrait
     */
    @PosterImageCss(position = {10, 780}, width = 55, height = 55, circle = true)
    private BufferedImage headImage;

    /**
     * nickname
     */
    @PosterFontCss(position = {77, 788}, color = {85,85,85}, name = "TengXiang love style", style = Font.BOLD)
    private String nickName;
    /**
     * Description under nickname
     */
    @PosterFontCss(position = {75, 813}, size = 15, color = {104,104,104}, name = "TengXiang love style")
    private String nickDesc;


    /**
     * QR code
     */
    @PosterBarCodeCss(position = {376, 695}, width = 130, height = 130, foreColor = {17,125,124})
    private PosterBarcode qrCode;

    /**
     * Two dimensional codeword
     */
    @PosterFontCss(position = {386, 833}, size = 20, color = {104,104,104}, center = true)
    private String qrCodeText;

    @Tolerate
    public CommodityPoster2Pojo() {
    }
}


All elements of the poster are defined here through annotations: background picture PosterBackground, other pictures @ PosterImageCss and font

@PosterFontCss and QR code @ PosterBarCodeCss to configure parameters such as position and width (more parameters can be understood through the source code).

@PosterBarCodeCss QR code annotation is only applicable to class PosterBarcodeDto

@PosterBackground background picture annotation, @ PosterImageCss, only applicable to class BufferedImage

@PosterFontCss text annotation, only applicable to class String

  • How to quickly get x\y coordinates and width \ height dimensions

    Normally, when we develop the visual manuscript, we can quickly get the position and size of each element on the page, but here we can only do it by ourselves because we find the whole picture from the Internet.

    Here I open the picture through ps and open "window - Information" to view the coordinates of the mouse and the size of the circle. As shown in the figure below, I can quickly get the position of each element:

2.5 pass in parameters and generate posters

1) Load font library

Before calling to generate posters, we need to put the font libraries used into the project. For example, I use two font libraries here: resources \ fonts \ simkai Ttf and resources\fonts\TTAiQingXiJ_0.ttf.

Here I want to make a special note: if you don't load the font library, you can also use it directly under windows (Song typeface will be used by default), but all Chinese will be garbled when publishing the service to Linux under the server, because there is no corresponding font library under Linux.

2) Generate Poster

I use a unit test to realize poster generation, call demonstration and pass in relevant information of product name

package com.naiqing.poster.demo;

import com.quaint.poster.core.dto.PosterBarcode;
import com.quaint.poster.core.impl.PosterBarcodeImpl;
import lombok.SneakyThrows;
import org.testng.annotations.Test;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;

/**
 * 〈Test poster > < br >
 *
 * @author naiqing
 * @Date 2022/1/22
 * @see [Related classes / methods]
 * @since [Product / module version]
 */
public class CommodityPoster2Test {

    @SneakyThrows
    @Test
    public void testCreate() {
        //Background image. Here I test the local image I use. The actual development can be changed to obtain images on the network (an example is shown below)
        BufferedImage backgroundImage = ImageIO.read(new File("D:\\temp\\s_bg.jpg"));
        //Commodity master chart
        BufferedImage commodityImage = ImageIO.read(new File("D:\\temp\\s_commodity.jpg"));
        //Strict selection icon
        BufferedImage yanxuanImage = ImageIO.read(new File("D:\\temp\\s_yanxuan.jpg"));
        //head portrait
        BufferedImage headImage = ImageIO.read(new File("D:\\temp\\s_head.jpg"));
        //QR code logo
        BufferedImage qrLogo = headImage;
        //QR code content
        String qrContent = "http://www.baidu.com";

        //Global default font (if you do not import the font library resources, it will be OK under windows, but linux does not have the default "Tahoma" and will display garbled code)
        InputStream in1 = this.getClass().getResourceAsStream("/fonts/simkai.ttf");
        Font defaultFont = Font.createFont(Font.TRUETYPE_FONT, in1);
        //The font displayed by the nickname (this font library is downloaded from the Internet and not from windows). When using, just refer to the font name of FontName (Font Name: double click the font library to see the font name)
        InputStream in2 = this.getClass().getResourceAsStream("/fonts/TTAiQingXiJ_0.ttf");
        Font txin2 = Font.createFont(Font.TRUETYPE_FONT, in2);

        CommodityPoster2Pojo shareCommodityInfo = CommodityPoster2Pojo.builder()
                .backgroundImage(backgroundImage)
                .commodityImage(commodityImage)
                .yanxuanImage(yanxuanImage)
                .commodityTitle("         Girls in the fog 2022 winter new women's hooded zipper long sleeved cotton clothes WH88888")
                .vipPrice("Privilege price¥0.01")
                .oldPrice("price¥268")
                .headImage(headImage)
                .nickName("Call me Hu Ge")
                .nickDesc("Invite friends to enjoy internal discounts")
                .qrCode(PosterBarcode.builder().content(qrContent).logo(qrLogo).build())
                .qrCodeText("Wechat scan")
                .build();
        //Create poster builder
        PosterBarcodeImpl<CommodityPoster2Pojo> poster = new PosterBarcodeImpl<>();
        //Set the default font library / all font libraries used in the installation (multiple font libraries are supported)
        poster.defaultFont(defaultFont).installFonts(txin2,...);
        //Generate Poster
        BufferedImage image = poster.annotationDrawPoster(shareCommodityInfo).draw(null);
        ImageIO.write(image, "png", new File("D:\\temp\\out2.png"));
    }
}

You can see that it is still very simple to use, out of the box! With this tool, you can make a poster in 5 minutes! There is no need to consider the uncertain compatibility of the APP side, and there is no need to mobilize people to develop by multiple developers such as Android, apple and H5. Meizizi~

The example above is the local image used by me. You can also use image links.

   //Remote picture
   BufferedImage backgroundImage = ImageIO.read(new URL("https://img-blog.csdnimg.cn/8bf7094ae7b044f495035c8ea734dca8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6LGB6L6-6aOO562d,size_18,color_FFFFFF,t_70,g_se,x_16"));
  • How do I use a custom font library?

When we are making posters, the visual renderings may require the use of specified fonts in addition to the color and bold requirements. At this point, we need to get the font library file "*" ttf "and put it in the project resource directory. For example, mine is resources\fonts\*.ttf.

The second step is to get the font name of this font library. When creating posters, configure @ PosterFontCss to set the font. You need to specify the font name. Double click the font library file, and you can see the font name in the first line, as shown in the following figure:

  • How to convert the poster image into base64 and return it to the front end

    //Write back the generated poster picture to the terminal in the form of base64
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    ImageIO.write(image, "png", stream);
    String asBase64 = "data:image/png;base64,"+Base64.encode(stream.toByteArray());
    System.out.println(asBase64);
    

3, Used technology and related source code

3.1 Easy Poster generator

The above source code and sample code are on gitee and can be downloaded directly. Welcome to repair and improve this tool.
https://gitee.com/naiqing/easyposter

I would like to thank the author of the framework Easy Poster for my secondary development after fixing some problems based on this framework.

3.3 QR code generation zxing

For the generation of QR code, I use Google's zxing, and then use hutool all to simplify the call.

Topics: Java