Canvas draws QR code with logo/text

Originally, I was in charge of the WeChat applet. Later, when I saw that the QR code generated on the web side of the project was relatively monotonous, I decided to add a logo in the middle of the QR code, so I searched for the ready-made source code everywhere on the Internet, and finally found it on github. Created a qrcode library that can put a logo in the middle of the QR code. As a result, the boss raised a demand and wanted to display text in the middle instead of pictures. This is embarrassing. This demand is a bit strange. I am afraid that the source code cannot be found, so I decided to go deep into the interior of the QR code generation library. , to find out how this stuff was drawn. The first is to study how the logo is drawn. Since I don't have much experience in web development myself, especially I haven't studied jquery, I am still very confused about the architecture of this library, but I still use js in the development of WeChat applet, so even if the framework structure is not very clear, But the role of each function can still be understood. Locate such a function according to the keyword imgWidth:

var QRMode, QRErrorCorrectLevel, QRMaskPattern, QRUtil, QRMath, i;
for (function (a) {
        a.fn.qrcode = function (b) {
            var c, d;
            return "string" == typeof b && (b = {
                text: b
            }), b = a.extend({}, {
                width: 256,
                height: 256,
                cheight: b.height + 50,
                cwidth: b.width,
                cstyle:"width:"+b.cwidth/4+"px;height:"+b.cheight/4+"px;",
                content:"",
                imgWidth: b.width / 2.5,
                imgHeight: b.height / 2.5,
                typeNumber: -1,
                correctLevel: QRErrorCorrectLevel.H,
                background: "#ffffff",
                foreground: "#000000"

To be honest, I am really clueless about such a structure, it looks like an anonymous function, but what the hell is a direct for? This code is directly restored by me based on the compressed code, which can only be interpreted as a complete for statement, but too many things are placed in the for, which causes the logic behind it to be far away. But regardless of these, my purpose is to find the logic of picture drawing, and continue to look down:

c = function () {
                var c, d, e, f, g, h, i, j, k, a = new QRCode(b.typeNumber, b.correctLevel);
                for (a.addData(b.text), a.make(), c = document.createElement("canvas"), c.width = b.cwidth, c.height = b.cheight,c.style=b.cstyle, d = c.getContext("2d"), b.src && (e = new Image(), e.src = b.src, e.onload = function () {
                        d.drawImage(e, (b.width - b.imgWidth) / 2, (b.height - b.imgHeight) / 2, b.imgWidth, b.imgHeight)
                    }), f = b.width / a.getModuleCount(), g = b.height / a.getModuleCount(), h = 0; h < a.getModuleCount(); h++) {
                    for (i = 0; i < a.getModuleCount(); i++) {
                        d.fillStyle = a.isDark(h, i) ? b.foreground : b.background,
                            j = Math.ceil((i + 1) * f) - Math.floor(i * f),
                            k = Math.ceil((h + 1) * f) - Math.floor(h * f),
                            d.fillRect(Math.round(i * f), Math.round(h * g), j, k)
                    }
                }
                return c
            }

I found such a function named c below. I have to say that the compressed code naming method is really simple and violent, all of which are single letters. But fortunately I can read this function. The first is to generate a QRCode object, and save the return value in several variables c, d, e, f, g, h, i, j, k, a by destructuring assignment. I will do it first. No matter, concentrate on the part of the picture below. The next line is a for loop statement, but a lot of assignment operations and initialization operations are performed in the first part of the for, and even an Image object is generated and stored in the e variable, and the image resource of e is assigned. And the operation of drawing pictures is also completed:

e = new Image(), e.src = b.src, e.onload = function () {
        d.drawImage(e, (b.width - b.imgWidth) / 2, (b.height - b.imgHeight) / 2,             
        b.imgWidth, b.imgHeight)
}

Seeing this part, I am not amazed at the compactness of the compressed code. A short for statement can do so many things. Among them, there is a d variable, this d is the context of the acquired canvas, and this part of the code is also in the first part of this for statement:

d = c.getContext("2d")

So it was so magical to complete the drawing of the logo. But now that I see this, I might as well see how the QR code itself is drawn, so I continue to read:

for (i = 0; i < a.getModuleCount(); i++) {
        d.fillStyle = a.isDark(h, i) ? b.foreground : b.background,
         j = Math.ceil((i + 1) * f) - Math.floor(i * f),
         k = Math.ceil((h + 1) * f) - Math.floor(h * f),
         d.fillRect(Math.round(i * f), Math.round(h * g), j, k);
}

This is the logic inside the for loop that drew the picture before, and it is another loop, but this loop is much more normal, there is no such fancy combination, you can see that the three variables f and g initialized in the previous loop are used here. , here are the calculated width and height of each small block of the QR code that needs to be drawn. The overall two for loops are combined. Similar to our typewriter, scanning line by line saves the QR code information. The array a is drawn on the canvas piece by piece. As for how this a is calculated, this belongs to the logic of QR code calculation. Even if I understand it, I can’t change anything, so I won’t read it. Here is a display of the logo drawn:

QR code with logo

sample code

Now I understand the logic of the logo drawing, so I started to change the image drawing to text drawing. First delete the picture drawing part in the outer for loop:

for (a.addData(b.text), 
      a.make(), 
      c = document.createElement("canvas"),
      c.width = b.cwidth, 
      c.height = b.cheight, 
      c.style = b.cstyle, 
      d = c.getContext("2d"),
      d.fillStyle = b.background, 
      d.fillRect(0, 0, b.cwidth, b.cheight),
      f = b.width / a.getModuleCount(), 
      g = b.height / a.getModuleCount(), 
      h = 0; h < a.getModuleCount(); h++) {
      for (i = 0; i < a.getModuleCount(); i++) {
               d.fillStyle = a.isDark(h, i) ? b.foreground : b.background,
                j = Math.ceil((i + 1) * f) - Math.floor(i * f),
                k = Math.ceil((h + 1) * f) - Math.floor(h * f),
                d.fillRect(Math.round(i * f + b.border), Math.round(h * g + b.border), j, k)
      }
}

Then draw a white opaque circle in the canvas as the background of the text, of course, if you like green, you can also.

                d.beginPath();
                d.strokeStyle = "white";
                d.arc(b.width / 2 + b.border, b.height / 2 + b.border, 35, 0, Math.PI * 2, false);
                d.closePath();
                d.fillStyle = 'white';
                d.fill();

The variable type for receiving the text to be passed in is added to the external parameter section, so that when qrcode is called, the text information displayed by the QR code can be controlled by modifying the incoming type field. The code for drawing the intermediate text is as follows:

                d.font = "normal 35px arial";
                //设置字体颜色
                d.fillStyle = "red";
                d.moveTo(d.width / 2 + b.border, 20);
                d.lineTo(d.width / 2 + b.border, 50);
                d.stroke();
                d.textAlign = "center"
                d.fillText(b.type, Math.floor(b.width / 2 + b.border), Math.floor(b.height / 2 +b.border +12));

The text display I use is red, there is no special reason, it is angry. In addition, I also left a border around the QR code, so that when the QR code is displayed, it will not appear too crowded with the surrounding space, especially by drawing the border inside the canvas, the downloaded The QR code is more beautiful, and the final result is shown as follows:

QR code showing text

sample code

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324153077&siteId=291194637