Demand scenarios

The operation background uploads a picture, and at the same time, the page generates a small program QR code, and the picture uploaded by the operation is combined into a large picture, which is used for the page to share and spread in the moments of friends.

Implementation approach

1. Upload the background image

Background image upload, call the interface implementation file to upload to the OSS platform, generate background image link.

2. Generate the small program TWO-DIMENSIONAL code of the page

Call the small program two-dimensional code generation interface to generate the two-dimensional code of the page. Details refer to the small program official documentation: developers.weixin.qq.com/miniprogram… . Call attention to the parameter length is limited, if the parameter is too long will lead to two-dimensional code generation failure. Our approach is to agree with the applets a set of URL mapping rules, through specific parameters to match the corresponding H5 page.

3. Write HTML code for screenshots

Complete the HTML code that needs to generate screenshots, including the background picture (the background picture uploaded by operation), the two-dimensional code of the page mini-program and other elements.

4. Call HTML2Canvas to achieve screenshots

After searching online, html2Canvas plug-in can be used to achieve screenshot function, the code is as follows:

// index.js
import html2canvas from 'html2canvas';

html2canvas(this.$refs.shareImgElem, {
  useCORS: true,
  backgroundColor: null
})
.then(canvas => {
  const dataUrl = canvas.toDataURL('images/jpg'); // Convert dataUrl to Blob const Blob = this.base64ToBlob(dataUrl); // Upload this. UploadShareImg (blob); })Copy the code
// index.vue // HTML code that needs to be captured <div ref="shareImgElem">... </div> // Link to screenshot image <img: SRC ="imgUrl" />
Copy the code

At this point, I thought that saving dataUrl could perfectly solve this requirement. However, the fact is that the base64-bit image generated by the screenshot is white. I also checked the usage of HTML2Canvas on the Internet, and confirmed that the calling method was not written wrong, but the graph cut out was blank. Later check the reason, from the simplest demo began to write, and finally found the reason for the blank screen, now summarized as follows.

5. Summary of the blank screen

5.1 Image cross-domain problem

If the screenshot code contains images, the images need to be set to allow cross-domain access, otherwise JS will not be able to read the image information. If the image is stored on the CDN, the CDN needs to set the CORS related Settings, that is, access-Control-allow-Origin: * in the response header of the image request

The pictures of our company are uploaded to ali OSS platform, and the cross-domain information set by bucket in OSS controls the domain name source when the pictures are uploaded. However, we need to set the cross-domain information when the picture is read. The picture is stored on CDN, so we can contact operation and maintenance to add cross-domain information in the CDN configuration.

5.2 Screenshot Elements are visible on the screen

After adding the cross-domain information in the response header of the image request, the screenshot still looked blank. Then we continued to find the reason, and finally found that the correct screenshot could be generated when the screenshot element was visible on the first screen. In the process of creating a screenshot, if the mouse is scrolling, the generated screenshot will be offset on the Canvas. There are two operations to solve this problem:

5.2.1 Put the screenshot elements in advance, at the top of the page, within the screen scope.

5.2.2 Scrolling is disabled during Screenshot generation. The code is as follows:

dom.setScrollTop(0); / / to scroll to the top of the document. The documentElement. Style. The position ='fixed';
Copy the code

5.2.3 After the screenshot is generated, the page resumes scrolling with the following code:

document.documentElement.style.position = ' ';
Copy the code

At this point, the screenshots finally show up. However, at this time, the screenshots are base64 encoded, so it is not suitable to save such a large string of characters in the background. At this time, it is considered to convert base64 characters into BLOB binary data stream and upload it to OSS.

6. Upload screenshots

6.1 Convert Base64 encoded characters into BLOB binary data objects.

The conversion code is as follows:

Base64ToBlob (dataUrl,type) {
    var arr = dataUrl.split(', '); var mime = arr[0].match(/:(.*?) ; / [1]) | |type; Byte var bytes = window.atob(arr[1]); // Remove the url header and convert to byte var bytes = window.atob(arr[1]); Var ab = new ArrayBuffer(bytes.length); Var ia = new Uint8Array(ab);for (var i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
    }
    return new Blob([ab], {
        type: mime
    });
}
Copy the code

6.2 Uploading BLOB binary Data streams to the OSS platform

The code is as follows:

// Upload binary data to uploadBlob(fileName, Blob) {return new Promise((resolve, reject) => {
        async function putBlob() {
            try {
                let result = await ossClient.put(fileName, blob);
                result.imgUrl = `${CDN_IMAGE_DOMAIN}/${result.name}`;
                resolve(result);
            } catch (e) {
                reject(e);
            }
        }
        putBlob();
    });
}
Copy the code
UploadShareImg (blob) {const fileName = 'web/activityms/share_big_img_${Date.parse(new Date())}.jpg`;
    this
        .uploadBlob(fileName, blob)
        .then(res => {
            this.imgUrl = res.imgUrl;
            this.$message.success('Wechat share big picture uploaded successfully! ');
        });
}
Copy the code

The screenshot is successfully generated and uploaded to the OSS platform, and the image path is returned.