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
- The user can
To upload pictures
- Can take pictures of users
Automatically adjust
Into the rightsize
- Can switch
Act the role ofing is tasted
- You can switch your avatar
Graphics frame
- can
Save/Download
Generated image
Customize avatar online
Make your avatar online
Train of thought
Initialize the
In this stage, the preset ornaments and graphics will be drawn on the canvas.
State changes
In 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.
Results output
And 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”