Ha ha, taking advantage of Christmas Eve to join in the fun, in fact, a long time ago to do a similar function of graduation season to generate invitations small application. In fact, the application of image synthesis only needs to be familiar with THE RELEVANT API of CANVAS in H5 and a little geometric knowledge, it is easy to achieve, here we explore the process of implementation. Plus, there are a lot of holidays coming up, so I’m sure this gadget is worth it. If you think it’s great, just give it a thumbs up. Also can follow my public account BRandF (has the small tool graphic information) recommended to friends with Ha, two-dimensional code at the end of the article.

The effect

  1. The user canTo upload pictures
  2. Can take pictures of usersAutomatically adjustInto the rightsize
  3. Can switchAct the role ofing is tasted
  4. You can switch your avatarGraphics frame
  5. canSave/DownloadGenerated image

Customize avatar online

Make your avatar online

Train of thought

  1. Initialize theIn this stage, the preset ornaments and graphics will be drawn on the canvas.

  1. State changesIn this stage, users can change ornaments, graphic borders and upload pictures. We need to draw the latest user picture, ornaments picture and graphic borders to canvas.

  1. Results outputAnd finally output the content of canvas into a picture that can be saved and downloaded.

Well, yes, the idea is very intuitive. The core functions are explained in detail below.

implementation

First of all, it should be clear that since we are going to make avatars, we can basically assume that the end user needs an image of equal length and width. But in fact, the user uploaded the picture is likely not neat, there are three cases, wide than high, width is less than high, width is equal to high, and at the same time, equal to the zoom or zoom, then how to do?

A clever way is to scale the height ratio of the original image to the height of the canvas, and the width of the original image to the same scale. As shown in the picture below, the proportion of the original picture can be kept in this way, and the canvas does not need to be blank. Although a small part of the original picture will be lost, it is still acceptable from the practical effect. Well, this step is to replace the tOU with the LAN and remove the custom clipping feature.

Resize the user image

// No hurry, I'll talk about these two functions in a minute
const base64Url = await this.file2Base64(sourceImage);
const imgObj = await this.createImage(base64Url);

const CANVANS_SIZE = 256;
const type = imgObj.width - imgObj.height;

// Three cases
if (type > 0) {
    // Whether the width is larger than or smaller than the height, the scale is proportional
    const w = imgObj.width * CANVANS_SIZE / imgObj.height;
    context.drawImage(imgObj, 0.0, w, CANVANS_SIZE);
} else if (type < 0) {
    const h = imgObj.height * CANVANS_SIZE / imgObj.width;
    context.drawImage(imgObj, 0.0, CANVANS_SIZE, h);
} else {
    context.drawImage(imgObj, 0.0, CANVANS_SIZE, CANVANS_SIZE);
}
Copy the code

The image is converted to Base64 format

The file uploaded by the user is read using the FileReader object and converted to base64 format. Since the image reading process is asynchronous, we encapsulate it with Promise.

file2Base64(domFile) {
    return new Promise((resolve, rejest) = > {
        const reader = new FileReader();
        reader.readAsDataURL(domFile);
        reader.onload = (e) = > {
            resolve(reader.result);
        };
    });
}
Copy the code

Create a picture

Since canvas only accepts picture objects when drawing pictures, base64 images need to be repackaged into picture objects before they can be drawn to canvas. Since loading into a picture object is also asynchronous, it’s wrapped in Promise

createImage(imgUrl) {
    return new Promise((resolve, rejest) = > {
        const imgObj = new Image();
        imgObj.src = imgUrl;
        imgObj.onload = (e) = > {
            resolve(imgObj);
        };
    });
}
Copy the code

Border processing

It is how to draw geometric graphics on canvas. I think this is a very good way to deal with it. Here I draw rounded corners and circles for reference. Drawing a Rounded Rectangle on a Canvas

Output to canvas

This is where the benefits of encapsulating asynchronous actions as promises come in, making it very straightforward to express asynchronous actions in synchronous writing. It should be noted that the user’s picture needs to be drawn to the canvas first, otherwise the jewelry and graphic border will be covered by the picture.

/** * @param {string} imgUrl (processed user imageUrl) * @param {object} decorationCurrent * @returns imageUrl * @memberof App */
async handleMakeImage(imgUrl, decorationCurrent) {
    if(! (imgUrl || decorationCurrent)) {return ' '; }
    const { border } = this.state;
    const { value } = border;
    const { source, style } = decorationCurrent;
    const { width, height, top, left } = style;
    const { canvas } = this.refs;
    this.clearCanvas(canvas);
    const context = canvas.getContext('2d');

    if (imgUrl) {
        const bgImg = await this.createImage(imgUrl);
        context.drawImage(bgImg, 0.0, bgImg.width, bgImg.height);
    }
    this.drawBorder(value, context);
    if (decorationCurrent && source) {
        const imgObj = await this.createImage(source);
        context.drawImage(imgObj, left, top, width, height);
    }

    const targetUrl = canvas.toDataURL('image/png');
    return targetUrl;
}
Copy the code

Save or download

Finally, simulate the click event of a label to complete the image download. If you are a mobile user, hold down the image to save the image.

downloadImage(url) {
    if (url) {
        const aLink = document.createElement('a');
        const evt = document.createEvent('HTMLEvents');
        evt.initEvent('click'.true.true);
        // Specify the image file name
        aLink.download = 'protrait.png'; aLink.href = url; aLink.click(); }}Copy the code

Reduce blurry images for small details

Found that if the normal image scale to load the image, the final generated image will appear blurred. A simple method is to enlarge the length and width of the canvas to twice the original size, but the picture is still displayed at the original scale. Simply speaking, the large picture is displayed in a smaller size. This will effectively alleviate the problem of blurred images.

.<canvas width="512" height="512" className="shadow d-n" ref="canvas" />.<img className="w256 h256" src={targetUrl} alt="" />
Copy the code

Ok, that’s it. That’s the core function code, less than 200 lines.

If you are interested, you can read the source code for more details

Source code && online application

The end of the

As the upcoming various festivals are approaching, the material of this small tool will be updated constantly, also welcome everyone to contribute some interesting material haha.

Welcome to pay attention to the public number to obtain the graphic information of this small tool

Or something that interests you

Re from scratch series

  • Re From Scratch Component Library Building and Publishing Process
  • Re from scratch UI library authoring life specification
  • Re from scratch UI library writing buttons for Life
  • Re writing forms for Life from scratch UI Library
  • Re writing life’s Table Components from scratch UI library
  • Re writing life from scratch UI Library – Step Management Component Steps
  • Re from scratch UI library writing life-tree components
  • Re from scratch UI library writing life – Progress Bar components
  • Re From Scratch backend learning configuration Ubuntu+Ngnix+Nodejs+Mysql environment
  • Configuring LAMP environments for Re From Scratch Back-end Learning

Web Security Series

  • “Web Attack and Defense Warrior Directory -XSS&CSRF”