1. The demand

In the recent project I was working on, I needed to generate page pictures in the front end and save them in the mobile phone, so I wrote a demo in the process of technical call, without vue-CLI scaffolding, but with little difference. This demo also used vue2.js to develop the page and qrcode.js to generate two-dimensional code, the principle is relatively simple. The demo project: Github address, feel helpful to a star, thank you very much. This item cannot be accessed directly by opening index.html and an error will occur. Enable the local service using http-server. If you do not know how to configure the local service, see http-server

The online preview

Specific requirements are as follows:
  1. Obtain background information, ranking and user image
  2. Click the save button to change the page to generate a picture
  3. Hold down to save the picture or scan the QR code

2. The train of thought

  1. Html2canvas. Js: Convert HTMLDOM to canvas element.
  2. CanvasAPI: toDataUrl() converts canvas to Base64 format
  3. In wechat browser, long press img, actionsheet will pop up, you can save, send, identify two-dimensional code and other operations

3. Code analysis

Resolve Image Blur

There is no problem generating images during PC development, but there will be a fuzzy situation on mobile, mainly due to the pixel ratio problem.

Device pixel ratio (DPR for short) defines the relationship between physical pixels and device-independent pixels. Its value can be obtained as follows: Device pixel ratio = physical pixels/device-independent pixels // in a certain direction, x or Y direction

Solution code:

/** * Return {number} */ changeDpr:function() {
            if (window.devicePixelRatio && window.devicePixelRatio > 1) {
                return window.devicePixelRatio;
            }
            return 1;
        },
Copy the code

#### Resolve the problem of not displaying images. If you reference the image address without cross-domain configuration, an error will appear

 Uncaught (in promise) DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
Copy the code

Although it is possible to use images in a canvas without CORS, this pollutes the canvas. Once the canvas is contaminated, you can’t read its data. For example, you can no longer use the canvas’s toBlob(), toDataURL(), or getImageData() methods; calling them throws a security error. HTML code in the picture has a [crossorigin] (https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img#attr-crossorigin) attributes, Combined with the appropriate CORS response headers, it is possible to use images with cross-domain elements in the canvas.

The solution code is as follows:

ImgTobase64: // imgTobase64:function(url, crossOrigin) {
            return new Promise(resolve => {
                const img = new Image();

                img.onload = () => {
                    const c = document.createElement('canvas');

                    c.width = img.naturalWidth;
                    c.height = img.naturalHeight;

                    const cxt = c.getContext('2d'); cxt.drawImage(img, 0, 0); Resolve (c.todataurl ('image/png')); }; // Implement crossOrigin && img.setAttribute(crossOrigin && img.setAttribute('crossOrigin', crossOrigin);
                img.src = url;
            });
        }
Copy the code

#### Generate pictures Image generation is to use canvas to obtain and generate pictures, some requirements need to export long pictures, you can change the code

Var w = dom.style.width; // Set the size of the image to be generated. var h = dom.style.height;Copy the code

Because some requirements do not need to display individual elements, data-html2Canvas-ignore can be used to ignore. If the rendering is not displayed at the beginning, you can change its opacity to 1 before converting. The downloaded image will cover the entire page, which means you can call the ActionSheet with a long press. The code is as follows:

/** * createImage */ createImage:function() { var _this = this; // var dom = document.getelementById ('app');
            var dom = _this.$refs.app; var box = window.getComputedStyle(dom); // Show that the export requires style _this.$refs.scanText.style.opacity = '1'Var width = parseInt(box-width, 10); var width = parseInt(box-width, 10); var height = parseInt(box.height, 10); Var scaleBy = _this.changedpr (); // create a custom canvas element var canvas = document.createElement('canvas'); // Set canvas element property width to DOM node width * pixel ratio canvas. Width = width * scaleBy; canvas.height = height * scaleBy; // Set canvas CSS width to DOM node width canvas.style.width = width +'px';
            canvas.style.height = height + 'px'; Var context = canvas.getContext('2d'); Context. scale(scaleBy, scaleBy); Var w = dom.style.width; // Set the size of the image to be generated. var h = dom.style.height; html2canvas(dom, { allowTaint:true,
                width: w,
                height: h,
                useCORS: true
            }).then(functionVar url = canvas.todataurl (canvas) {// Convert canvas into a picture and render it on the page.'image/png'); // base64 data var image = new image (); image.src = url; document.getElementById('shareImg').appendChild(image); // Hide button _this.canvasImageHide =false; Var shareImgElem = document.getelementById ('shareImg');
                shareImgElem.style.height = '100%'
            });
        }
Copy the code