This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.


This article was originally sent out this morning, but after it was sent out, I found that the demo website was maliciously redirected to an advertising website, and then deleted the article. I’m sorry to those who read this article, for bringing a bad experience.

The investigation of the problem for a long time, and finally found that the dependency library file was injected malicious code, has been restored, thank you for your understanding!


Tomorrow is the National Day, recently saw a lot of friends for the National Day wind profile picture, feel this is very interesting, found a similar source research, and transformed (not original, just transformed, as long as you want to share the realization of ideas). Here is how to achieve a key to generate National Day limelight like a small tool.

The techniques used here:

  • HTML + CSS + JavaScript;
  • Download. Js library;
  • Fabric. Js library;

Go to g.cuggz.com/.

Note: You can click the link above to use it, but my domain name is blocked by TX and I am still appealing, so I cannot open it in QQ and wechat. I need to copy the link to the browser to view and use it.

Here’s a screenshot of the gadget:

1. Page layout

This part does not say more, directly on the code:

<div class="wrapper">
    <! -- Select box -->
    <div class="main-box">
      <a class="prev" onClick='changeHat()'></a>
      <div class="main-img">
        <div id="content">
          <canvas id='cvs'></canvas>
        </div>
      </div>
      <a class="next" onClick='changeHat()'></a>
    </div>
    <! -->
    <img id='export-img' alt='National Day portrait' src=' ' crossorigin="anonymous"/>
    <! -- Operation button -->
    <div class="operation-btns">
      <a class="upload-btn">
        <input id='upload' type='file' onchange='viewer()' style='opacity: 0; '/>
      </a>
      <a class="export-btn" onClick='exportFunc()'></a>
    </div>
  </div>
	<! -- -- -- > templates
  <div style='display: none'>
    <img id='img' src=' ' alt=' ' />
    <img class='hide' id='hat0' src='img/1.png' />
    <img class='hide' id='hat1' src='img/2.png' />
    <img class='hide' id='hat2' src='img/3.png' />
    <img class='hide' id='hat3' src='img/4.png' />
    <img class='hide' id='hat4' src='img/5.png' />
    <img class='hide' id='hat5' src='img/6.png' />
    <img class='hide' id='hat6' src='img/7.png' />
  </div>
Copy the code

This page is relatively simple, outside is a large background image, in the middle is an avatar display box and template switch button, below is an upload button and a download button. After the page layout is complete, it is time to write the style, CSS code is as follows:

body.html {
    min-height: 100%;
    width: 100%;
    user-select: none;
    font-size: 18px;
}

.wrapper {
    width: 100%;
    height: 100%;
    max-width: 620px;
    max-height: 800px ;
    margin: 0 auto;
    background-image: url('.. /img/bg.png');
    background-repeat: no-repeat;
    background-size: 100% 100%;
    padding-top: 13em;
}

#export-img {
    display:none;
    margin:0 auto;
    width:250px;
    height:250px;
}

.main-box {
    display: flex;
    align-items: center;
    justify-content: center;
}

.main-box .next..main-box .prev {
    background-image: url('.. /img/next.png');
    background-size: contain;
    border-radius: 50%;
    width: 2.275 rem;
    height: 2.275 rem
}

.main-box .prev {
    transform: rotate(180deg)}.main-box .main-img {
    margin: 0 .75rem;
    background: #fff;
    border:.25rem solid #fbe6b5;
    border-radius:.75rem;
    font-size: 0
}

#content {
    border-radius:.5rem;
    position: relative;
    width: 9.5 rem;
    height: 9.5 rem;
    margin-left: 50%;
    transform: translateX(-50%);
    overflow: hidden
}

.operation-btns {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    margin-top:.75rem
}

.operation-btns .upload-btn {
    width: 11.6 rem;
    height: 3.6 rem;
    background-size: 100% 100%;
    background-image: url('.. /img/upload.png')}.operation-btns .export-btn {
    display: none;
    width: 11.6 rem;
    height: 3.75 rem;
    background-size: 100% 100%;
    background-image: url('.. /img/export.png')}Copy the code

Here is a simple implementation for reference only. There are a lot of places can be optimized, here is not modified, interested in their own personalized customization.

2. Upload and display pictures

The next step is to implement the logic. First, there are a few global variables that need to be defined, which will be used later:

let canvasFabric; // canvas instance let hat = "hat0"; // The current template class let hatInstance; // Template layer instance const screenWidth = document.getElementById("content").scrollHeight; // The height of the content boxCopy the code

Then you need to process the uploaded image and display it on the page:

Function viewer() {const file = document.getElementById("upload").files[0]; // Get the tag const to display the imageimg = document.getElementById("img"); Const reader = new FileReader(); If (file) {// Convert the file to Base64 reader.readAsDataURL(file); // Reader is triggered when the file is successfully read.onload= () => {// Assign the URL of base64 to the label of the image to displayimg.src = reader.result; // Image loading is completeimg.onload = () => img2Cvs(img);
    }
  } else {
    img.src= ""}}Copy the code

The HTML5 FileReader object is used here, which provides a method to read the file and an event model containing the read results. You can use new to initialize the object. The FileReader object contains four methods, three to read the file and one to interrupt the reading. Note that whether the read succeeds or fails, the method does not return the read result, which is stored in the Result property. Here, the readAsDataURL method is used, which is introduced by MDN as follows:

The readAsDataURL method reads the specified Blob or File object. When the read operation is complete, readyState changes to DONE and the LoadEnd (en-US) event is triggered, and the result property contains a string in data:URL format (Base64 encoded) representing the contents of the read file.

That is, convert the uploaded image into a Base64 URL and assign a value to the tag that displays the image. This tag will display the image as follows:Now that the image is uploaded and displayed, it’s time to initialize a canvas.

Initialize the canvas

Img. load is executed at the end of the above code, where the onload event is executed immediately after the image is loaded. After the image display is complete, the img2Cvs method is executed, which initializes a canvas and shows and hides some elements of the page.

The fabric library is used in the img2Cvs method. Fabric.js is a library that simplifies writing Canvas programs. Fabric.js provides Canvas’s missing object model, SVG Parser, interaction, and a whole set of other indispensable tools. Canvas provides a good Canvas capability, but the Api is not friendly enough. Fabric.js was developed for this purpose, primarily to write code as objects. Fabric.js can do the following:

  • Create and fill graphics (including pictures, text, regular graphics and complex path composition graphics) on the Canvas.
  • Fill the shape with a gradient color.
  • Combined graphics (including combined graphics, graphic text, pictures, etc.).
  • Set up graphical animation set user interaction.
  • Generate JSON, SVG data, etc.
  • Generating Canvas objects comes with drag-and-drop functionality.

The fabric.js library can be installed using the NPM command:

npm install fabric --save
Copy the code

Can also be referenced by CDN:

<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.min.js"></script>

Copy the code

Here’s how the img2Cvs method works:

function img2Cvs(img) {
  	// Get and display the Canvas canvas and set the size of the canvas to the size of the image
    const cvs = document.getElementById("cvs");
    cvs.width = img.width;
    cvs.height = img.height;
    cvs.style.display = "block";
  	
  	// Create a canvas and set its position and background
    canvasFabric = new fabric.Canvas("cvs", {
      width: screenWidth,
      height: screenWidth,
      backgroundImage: new fabric.Image(img, {
        scaleX: screenWidth / img.width,
        scaleY: screenWidth / img.height
      })
    });
  	// Switch templates
    changeHat();
		// Hide the upload image button and show the download image button
    document.getElementsByClassName("upload-btn") [0].style.display = "none";
    document.getElementsByClassName("export-btn") [0].style.display = "block";
  }
Copy the code

The fabric.canvas () method takes two parameters. The first parameter is the ID of the Canvas and the second parameter is the configuration item when the Canvas is initialized. Here we set the size of the initial Canvas and the background image, using our uploaded avatar as the background image. The background Image here is the instantiated fabric.image object, which is initialized with the Image object as its first parameter and the Image style configuration object as its second parameter.

Once the canvas is created, you need to switch out the first template and hide the Upload image button and show the download picture button. That completes the first step. Let’s look at how to switch existing templates.

4. Switch templates

Here’s how switching templates are implemented:

function changeHat() {
  	// Hide the current template
    document.getElementById(hat).style.display = "none";
  	// Get all the templates
    const hats = document.getElementsByClassName("hide");
    hat = "hat" + (+hat.replace("hat"."") + 1) % hats.length;
  	// Get the current template and display it
    const hatImage = document.getElementById(hat);
    hatImage.style.display = "block";
  	// If there is an existing layer, remove it
    if (hatInstance) {
      canvasFabric.remove(hatInstance)
    }
  	// Add the current template as a layer object
    hatInstance = new fabric.Image(hatImage, {
      top: 0.left: 0.scaleX: screenWidth / hatImage.width,
      scaleY: screenWidth / hatImage.height,
      cornerColor: "#0b3a42".cornerStrokeColor: "#fff".cornerStyle: "circle".transparentCorners: false.rotatingPointOffset: 30
    });
  	// Set the layer object to unstretchable
    hatInstance.setControlVisible({
       mt: false.mb: false.ml: false.先生: false.bl: false.br: false.tl: false.tr: false.mtr: false,})// Add layers to the canvas
    canvasFabric.add(hatInstance);
  }
Copy the code

By default, the fabric.js element has eight points to scale any object. We do not want the user to stretch the Fabric object horizontally or vertically. We can set it to unstretch using the setControlsVisibility() method, which requires passing in a configuration object, This object contains eight zoom points, all set to false.

Finally, we add the layer created using the template to the canvas, using the add method. This is an event provided by Fabric. The following are common events provided by fabric.js:

  • Object: Added Adds a layer
  • Object: Modified Edits a layer
  • Object :removed Layer
  • Selection: creates the first selected layer
  • Selection: Updated layer selection changes
  • Selection: Cleared Layer selected

5. Output images

After the above steps, we have initialized a canvas with our uploaded image as the background and a layer of template of our own choice. The last step is to output the composite image. Here’s what happens when you click the Download image button:

function exportFunc() {
  // Hide the selection box, upload and download button, canvas canvas
  document.getElementsByClassName("main-box") [0].style.display = "none";
  document.getElementsByClassName("operation-btns") [0].style.display = "none";
  document.getElementById("cvs").style.display = "none";

  // Generate a URL for the canvas and assign it to the corresponding tag for display
  const exportImage = document.getElementById("export-img");
  exportImage.style.display = "block";
  exportImage.src = canvasFabric.toDataURL({
    width: screenWidth,
    height: screenWidth
  });
  // Download the generated image
  window.confirm("Do you want to download your avatar?")? download(exportImage.src,"National Day Spotlight".'image/png') : void 0
}
Copy the code

Here we use the toDataURL method to generate an image from the Canvas instance object, which is the fabric object’s method to export the canvas as an image, a Base64 URL. So the IMG tag gets the URL and displays the final image.

Finally, an optional function is added to download the generated avatar, using the download.js library. The first parameter of this method is the URL of the image, the second parameter is the name of the downloaded image, and the third parameter is the format of the image.

This is all the functions of this small application, only a simple implementation, there is a BUG, mainly to provide an implementation of the idea. I have never touched canvas and the concept of canvas before, but this time I have learned more. Later, I had more time to learn related use, interesting!

If you think this gadget is funny, just give it a thumbs up!

I wish you a happy National Day in advance!