Note: [n] is identified as a legacy problem, which is explained in detail at the end of the article.

Before, I made a tool to add text boxes to pictures online. The general idea is to first load pictures into a DOM structure, then export them to a canvas through HTML2Canvas, and finally export them into pictures through the toDataURL method of canvas.

This idea is not complicated, but there are a few minor problems:

  1. Exporting cross-domain images: You can draw images to the Canvas, but you can’t do anything to export data (such as toDataURL) because the Canvas considers itself contaminated (tainted). (Of course, there is no such problem with locally uploaded pictures)

    This protects users from having private data exposed by using images to pull information from remote web sites without permission.

    – from the canvas – todataurl – securityerror

    This protects users’ private data from being exposed.

  2. Canvas content becomes blurred on the Retina screen.

  3. If the image is blurry, why should fillText be blurry? And the export is a little bit clearer (but still fuzzy)

Solution process:

  1. The first problem is solving the familiar cross-domain problem. The main use scenario of this tool is i8N project overseas, and the pictures are generally stored on the overseas picture server. I added crossorigin:anonymous to the picture didn’t work, so I decided to change the path.

    Since traditional cross-domain usage fails, we know that the SRC attribute of can represent the content of an image with Base64 encoded data without cross-domain problems. So I want to convert the image format with FileReader. But it turns out that FileReader doesn’t allow you to handle cross-domain resources either… The plan went up in smoke.

    CORS Anywhere adds CORS Headers to your requests. This should solve the cross-domain problem. (No specific attempt)

  2. That’s what I want to talk about today.

    Let’s start by Posting online solutions:

    devicePixelRatio = window.devicePixelRatio || 1,
    backingStoreRatio = context.webkitBackingStorePixelRatio || 1,
    ratio = devicePixelRatio / backingStoreRatio;
    
    var w = $("#code").width();
    var h = $("#code").height();
    
    // Set the canvas width to twice that of the container
    var canvas = document.createElement("canvas");
    canvas.width = w * ratio;
    canvas.height = h * ratio;
    canvas.style.width = w + "px";
    canvas.style.height = h + "px";
    var context = canvas.getContext("2d");
    // Then scale the canvas and double the size of the image onto the canvas
    context.scale(ratio,ratio);
    Copy the code

    Let’s look at the above code in two parts. First, ignore the part that defines ratio and move on. To clarify, the canvas property width/height is different from the width/height specified in the stylesheet. The former determines the content size of the canvas, while the latter is just the display size. So the above code is not difficult to understand, in fact, the content of the canvas is enlarged twice as high and wide, but the style is unchanged, the visual will become much more fine, and the principle of the double image is basically similar.

    I get it, but what about all that stuff at the beginning of the code?

    Following the logic above, all we need is a devicePixelRatio to determine if the device is (loosely speaking) retina. Why do we have to calculate his ratio to backingStoreRatio? What is this thing?

    Whenever we draw anything to the canvas, the browser is actually writing it to a backup storage space. This is where the data comes from when the browser redraws to the screen. WebkitBackingStorePixelRatio told us this value is the size of the backup space capacity of the canvas itself.

    Now that we know what this value does, how does it control presentation?

    The image above shows DPR :bk === 1, just as there is no retina display, export and import are irrelevant. The point is that this is also true when both are equal to 2. So even on retina screens, it’s possible to manipulate images very clearly without doing extra code. And that’s why we say that when we calculate the ratio we want to calculate the ratio of the two rather than just using DPR. And there’s really no relationship between these two more times, it’s not that just because DPR is 2 bk is always higher.

    dpr:bk === 2There’s a problem. We put the picture in as is, the canvas has no other processing for the picture because the bk value is 1, and it will be blurred when it is displayed on the page. This is actually the same reason why images are blurry on retina screens.

    Let’s say we have an image that is 30px by 30px, which is 30 CSSPX wide on the Retina screen, but it actually fills its width with 60 physical pixels. Our image provides only 30 known pixel values, leaving the remaining 30 to be computed by the browser based on the surrounding pixels. So it gets fuzzy.

  3. Here’s why the text is vague. At the beginning, when I saw the blurred text, I thought it was not difficult to understand. It was obviously the same routine as the picture. However, when I think about it, I find it wrong. The reason for the picture is that in the case of DPR of 2, the width of the picture content and the width of the picture style are the same, so it is blurred. However, the actual pixel number of the text is enough when I type it on the page and draw it on the canvas. Why is it blurred?

    After checking some materials, I found that font display on the page is different from text drawing with fillText in the Canvas. The latter is actually “drawing” characters in the Canvas, and the display unit of the drawing result is the same as the picture above. So far we can think of the process as the same as the picture presentation.

    As for why downloading is clearer but not “so clear”, we will answer two questions. Why is it clearer? Because blurring is actually a browser rendering behavior, there is no pixel estimation for viewing images after downloading. Why is it not so clear? Detailed I do not want to say, specific can see this answer

Legacy issues: [1]: Are file protocol requests sent to the server judged to be cross-domain by the same standard as HTTP? Personally, I think it should be, because the same origin policy itself is for security, and it has nothing to do with your client’s protocol.

Reference article:

High DPI Canvas

Device pixels, device independent pixels, CSS pixels

Canvas text rendering (blurry)