Small program canvas 2D to draw high-definition pictures of the solution, the maximum can generate 10m posters, solve the problem of too large width and height Android image generation failure.

Time:2020-10-27

wx.canvasToTempFilePath

As we all know, wechat canvas needs to call this interface to generate images. If this interface wants to generate high-definition images, it needs to solve the problem of font blurdestWidth * dpr

The width and height of the original canvas is too largedestWidth * dprThe width and height of destwidth will be too large, which may lead to Android failure in generating images.

Since this interface doesn’t work, don’t use it.

Another way of thinking, the small program canvas type = 2D interface supports more comprehensive basic libraries. According to the official introduction, canvas type = 2D basically refers to the H5 interface. Then, the methods available in H5 should be used here.

canvas 2d

According to the example provided by wechat:

Page({
  onReady() {
    const query = wx.createSelectorQuery()
    query.select('#myCanvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d')
        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        ctx.scale(dpr, dpr)
        ctx.fillRect(0, 0, 100, 100)
      })
   }
})

In order to draw high definition and not blur the text, you need to set the canvas.width and canvas.height Explicitly set the DPR (wxss should also set the normal width and height), and at the same time, the drawing context CTX needs to be scaled to DPR.

The purpose of CTX scaling DPR is to keep the drawing density consistent with the pixel density. If something doesn’t want to scale the drawing, you can set ctx.setTransform (1, 0, 0, 1, 0, 0) restores the scaling of the drawing context.

Now let’s paint boldly. Because the density of drawing is equal to the pixel density, the actual display is very clear. The width and height of canvas 2D can be set larger, but it can’t be set too large. If the width is too large, there will be crash problems under Android.

Real machine test 1500There is no problem with the width and height of 800. Because of the pixel density, if DPR = 3, it is actually 45002400

So this big width and height is in use wx.canvasToTempFilePath It is very likely that the image generation of the Android machine will fail. At this time, a artifact should be offered:

_canvas_.toDataURL(_type_, _encoderOptions_);

HTMLCanvasElement.toDataURL()Method returns adata URI。 have access totypeParameter. The default value isPNGFormat. The resolution of the image is 96 DPI.

  • typeOptional, picture format, default isimage/png
  • encoderOptionsOptional, when the specified image format isImage / JPEG or In the case of image / webp, the image quality can be selected from 0 to 1。 If the value is out of range, the default value will be used0.92。 Other parameters are ignored.

It can be done throughcanvas.toDataURL()Get a data URI with image display, and delete the headerdata:image/jpeg;base64,Get a pure Base64 image data.

Now that you get the image data, you can write the data into the image.

  • Open the file manager provided by wechat
  • Convert Base64 data to buffer
  • adopt fsm.writeFile Write files to user storagewx.env.USER_DATA_PATHLocation.
  • Filepath is a picture
  • As the storage space of wechat is only 10m, so it can support 10m image generation at most, which can meet most needs.
const filePath = `${wx.env.USER_DATA_PATH}/cover.jpg`;
let fsm = wx.getFileSystemManager();
let buffer = wx.base64ToArrayBuffer(bodyData);
fsm.writeFile({
     filePath: filePath,
     data: buffer,
     encoding: 'binary',
     success() {
         console.log('---success---', filePath);
     },
     fail(error) {
        console.error(error);
     }
 });

Don’t forget to clean up the storage space after use, otherwise you can’t save it next time

removeLocalFile() {
    //Note that the file storage space is 10m
    //In order to keep enough space, the files in the root directory are deleted
    const fsm = wx.getFileSystemManager();
    try {
      const ls = fsm.readdirSync(wx.env.USER_DATA_PATH);
      ls.forEach(d => {
        let path = `${wx.env.USER_DATA_PATH}/${d}`;
        let stats = fsm.statSync(path);
        if (stats.isFile()) {
          fsm.unlinkSync(path);
        }
      });
    } catch (e) {
      console.log(e);
    }
  }

You can empty different files according to your needs. There is no need to empty all the contents of the root directory

At this point, you can happily use canvas 2D to draw high-definition images.