Due to some mobile compatibility reasons, one of our projects requires the front-end to convert PDF into an interface that can be viewed directly on the mobile page. In order to facilitate the solution, we use the pdf.js plug-in, which can convert pdf into canvas and draw it on the page. However, during the testing process, it was discovered that on the mobile browser, the drawn content was very blurry (as shown below). After analysis, it was found that this was caused by the high-definition screen of the mobile terminal. After solving the problem, write down the reasons and findings in writing
Before explaining the problem, you first need to understand some basic knowledge about mobile display and cavans to facilitate further exploration. If you want to see the results directly, you can scroll to the end.
Some basic knowledge about screens Physical pixels (DP)Physical pixels are also called device pixels. We often hear that the resolution of mobile phones is physical pixels. For example, the physical resolution of iPhone 7 is 750 * 1334. The screen is composed of pixels, which means that the screen has 750 pixels in the horizontal direction and 1334 pixels in the vertical direction.
Device Independent Pixel (DIP)Also called logical pixels, for example, the sizes of Iphone4 and Iphone3GS are both 3.5 inches. The physical resolution of iphone4 is 640 * 980, while 3gs is only 320 * 480. If we draw an image with a width of 320px according to the real layout, in the iphone4 Only half of the screen has content, and the remaining half is blank. In order to avoid this problem, we introduced logical pixels and set the logical pixels of both mobile phones to 320px to facilitate drawing.
Device Pixel Ratio (DPR)The above device independent pixels are ultimately for the convenience of calculation. We have unified the logical pixels of the device, but the physical pixels represented by each logical pixel are not certain. In order to determine the relationship between physical pixels and logical pixels without scaling, , we introduced the concept of Device Pixel Ratio (DPR)
Device pixel ratio = device pixels / logical pixels DPR = DP / DIP
There are a lot of theories mentioned above. Here is a picture to explain.
As can be seen from the above figure, with the same size of logical pixels, a high-definition screen has more physical pixels. Under a normal screen, 1 logical pixel corresponds to 1 physical pixel, while under a high-definition screen with dpr = 2, 1 logical pixel is composed of 4 physical pixels. This is also the reason why high-definition screens are more delicate.
Some basic knowledge about canvas Canvas draws bitmapsThis is a knowledge point that everyone who knows canvas should know, and it is also the core of the problem we will analyze next.
We will leave the explanation of bitmaps later. Now we only need to know that the image drawn by canvas is a bitmap.
The width and height properties of canvasThe width and height attributes of canvas are very easy for beginners to make mistakes. These two properties are often confused with the width and height properties in CSS.
For example, we have the following code (1):
<canvas width=600 height=300 style=width: 300px; height: 150px></canvas>
If you still can’t understand it, you can imagine it as the following code (2):
<!-- The pixels of logo.png are 600 * 300 --><img style=width: 300px; height: 150px src=logo.png />
The default width and height of the canvas are 300 * 150. After setting the css, the canvas will be scaled (note not cropped) according to the set css width and height , which is the same as the img tag.
The above code (1) can actually be explained in a more popular way, that is, one logical pixel is actually filled by two canvas pixels.
A preliminary discussion on the causes of ambiguityThe above is an introduction to some basic knowledge required, and the formal exploration will begin below.
First of all, we mentioned that using canvas to draw images is bitmap, and the jpg and png we usually use are also bitmaps. So what is a bitmap?
Bitmap, also called pixel map or raster map, stores and displays images by recording the color, depth, transparency and other information of each point in the image. To put it more concretely, you can think of a bitmap as a huge puzzle. This puzzle has countless pieces, and each piece represents a solid-color pixel. Theoretically, one bitmap pixel corresponds to one physical pixel . But what if you use a high-definition screen, such as Apple's retina screen, to view a picture?
Suppose we have the following code, which will be displayed on the retina screen of iPhone 4:
<canvas width=320 height=150 style=width: 320px; height: 150px></canvas>
The physical pixels of iPhone 4 itself are 640 * 980, while the device independent pixels are 320 * 480, which means that 1 CSS pixel is actually composed of 4 physical pixels. The pixels of canvas are 320 * 150, and its CSS pixels are 320 * 150. It means that one css pixel will be composed of one canvas element, so the conversion is done like this: On a retina screen, one canvas pixel (or one bitmap pixel) will fill 4 physical pixels. Since a single bitmap pixel cannot be further divided, it can only take the nearest color, causing the picture to be blurred.
If you are still confused, the following picture can illustrate how the bitmap is filled on the retina screen:
The left side of the picture above shows the display rules on a normal screen. It can be seen that there are 4 bitmap pixels, while the high-definition screen on the right has 16 pixels. Because the pixels cannot be cut, the color changes.
But one thing that has not been explained clearly is why the picture takes the nearest color instead of taking the original value directly. This is also the culprit behind the blur.
The man behind the scenes---smoothing technologyThe following is what one of my senior classmates helped me explain. Just now we said that each bitmap element is actually a solid-color pixel. Now suppose we need to draw a number 0 on a normal screen with a css size of 4px * 4px and a dpr of 1. Then what we draw should look like the following picture, where 1 represents black pixels and 0 represents white pixels.
It can be seen that when the dpr is relatively small, our 0 pattern is still relatively obvious. Now if our css size remains unchanged, but the image is drawn on the retina screen, what will the effect be like?
We know that under the retina screen, one CSS pixel represents 4 physical pixels. If we do not do any processing, directly arrange according to the matrix above, and expand the matrix, we will find that under the retina screen, our pattern has a very obvious jagged feeling. The image clearly lacks a hint of Hue.
If we slightly change the image, change it to the following picture
The image feels instantly softer, but the place that should have been filled with 4 0s has become 3 1s plus 1 0. This is actually the so-called image smoothing process. In order to solve the jaggy feeling, the original color is changed. On pictures filled with more colors, in order to be more natural, the joints of the pictures become approximate colors. This also explains why When filling the color above, not the original color but the approximate color is used.
Summary of reasonsAfter passing the above explanation, let us now summarize the following conclusions. Now that mobile terminals are popular and high-definition screens have basically become popular, a 1px CSS pixel actually represents 4 or more physical pixels. However, due to our code problem, our 1px CSS pixel and 1 canvas pixel are equal, which results in 1 canvas pixel actually needing to be filled with 4 or more physical pixels. In order to ensure smooth image processing, the filling The remaining physical pixels use an approximation of the original color, resulting in a blurry image.
Solution ideasOnce you understand the cause of the problem, it is easy to solve the problem. The most important thing to solve the problem is to equalize one canvas pixel and one physical pixel.
There is a devicePixelRatio attribute hanging under the window object of higher version browsers, which is the dpr mentioned above.
When the canvas element css width and height are determined, we can do this
let canvas = document.getElementById('canvas');let ctx = canvas.getContext('2d');let dpr = window.devicePixelRatio; // Assume dpr is 2// Get the width and height of css let { width: cssWidth, height: cssHeight } = canvas.getBoundingClientRect();// According to dpr, expand the pixels of the canvas canvas so that one canvas pixel is equal to one physical pixel canvas.width = dpr * cssWidth; canvas.height = dpr * cssHeight; // As the canvas expands, the coordinate system of the canvas also expands. If the drawing content is based on the original coordinate system, the content will be reduced // so the drawing scale needs to be enlarged ctx.scale(dpr,dpr);Experience summary
Many times, when we find a problem, we cannot focus on solving the problem. Instead, we should deeply understand the cause of the problem so that we can move forward better.
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.