일부 모바일 호환성 이유로 인해 우리 프로젝트 중 하나에서는 PDF를 모바일 페이지에서 직접 볼 수 있는 인터페이스로 변환하기 위해 프런트 엔드가 필요합니다. 솔루션을 용이하게 하기 위해 우리는 PDF를 캔버스로 변환하고 페이지에 그릴 수 있는 pdf.js 플러그인을 사용합니다. 그러나 테스트 과정에서 모바일 브라우저에서는 그려진 내용이 매우 흐릿한 것으로 확인되었습니다(아래 그림 참조). 분석 결과 이는 모바일 단말기의 고화질 화면에 의한 것으로 확인되었습니다. 문제를 해결한 후 그 이유와 결과를 글로 적는다.
문제를 설명하기 전에 먼저 모바일 디스플레이 및 캐번에 대한 기본 지식을 이해해야 추가 탐색이 가능합니다. 결과를 직접 보고 싶으시면 스크롤을 끝까지 내리시면 됩니다.
화면에 대한 기본 지식 물리적 픽셀(DP)물리적 픽셀은 기기 픽셀이라고도 합니다. 예를 들어 iPhone 7의 물리적 해상도는 750 * 1334입니다. 화면은 픽셀로 구성되어 있는데, 이는 화면이 가로 방향으로 750픽셀, 세로 방향으로 1334픽셀로 구성되어 있음을 의미합니다.
장치 독립적 픽셀(DIP)논리 픽셀이라고도 하는데, 예를 들어 Iphone4와 Iphone3GS의 크기는 모두 3.5인치입니다. iphone4의 물리적 해상도는 640*980인 반면, 3gs는 320*480에 불과합니다. 실제 레이아웃, iphone4에서는 화면의 절반만 콘텐츠가 있고 나머지 절반은 비어 있습니다. 이 문제를 피하기 위해 논리적 픽셀을 도입하고 두 휴대폰의 논리적 픽셀을 320px로 설정하여 그리기를 용이하게 했습니다.
장치 픽셀 비율(DPR)위의 장치 독립적 픽셀은 궁극적으로 계산의 편의를 위해 장치의 논리적 픽셀을 통합했지만, 각 논리적 픽셀이 표현하는 물리적 픽셀은 스케일링 없이 물리적 픽셀과 논리적 픽셀 간의 관계를 결정하기 위해 필요합니다. , 장치 픽셀 비율(DPR) 개념을 도입했습니다.
장치 픽셀 비율 = 장치 픽셀 / 논리 픽셀 DPR = DP / DIP
위에서 언급한 많은 이론이 있습니다. 여기에 설명할 그림이 있습니다.
위 그림에서 볼 수 있듯이, 동일한 크기의 논리 픽셀을 사용하는 경우 고화질 화면에는 더 많은 물리적 픽셀이 있습니다. 일반 화면에서는 1개의 논리 픽셀이 1개의 물리적 픽셀에 해당하는 반면, dpr = 2인 고화질 화면에서는 1개의 논리 픽셀이 4개의 물리적 픽셀로 구성됩니다. 고화질 화면이 더 섬세한 이유이기도 합니다.
캔버스에 대한 기본 지식 캔버스는 비트맵을 그립니다.이는 캔버스를 아는 사람이라면 누구나 알아야 할 지식 포인트이자, 다음에 분석할 문제의 핵심이기도 하다.
비트맵에 대한 설명은 나중에 남겨두겠습니다. 이제 캔버스로 그린 이미지가 비트맵이라는 것만 알아두면 됩니다.
캔버스의 너비와 높이 속성캔버스의 너비와 높이 속성은 초보자가 실수하기 매우 쉽습니다. 이 두 속성은 CSS의 너비 및 높이 속성과 혼동되는 경우가 많습니다.
예를 들어 다음 코드(1)가 있습니다.
<캔버스 너비=600 높이=300 스타일=너비: 300px 높이: 150px></canvas>
그래도 이해가 되지 않는다면 다음 코드(2)를 상상해 보세요.
<!-- logo.png의 픽셀은 600 * 300 --><img style=width: 300px; height: 150px src=logo.png />
캔버스의 기본 너비와 높이는 300 * 150입니다. CSS를 설정하면 설정된 CSS 너비와 높이에 따라 캔버스의 크기가 조정됩니다(잘리지 않음) . 이는 img 태그와 동일합니다.
위의 코드 (1)은 실제로 더 대중적인 방식으로 설명할 수 있습니다. 즉, 하나의 논리적 픽셀이 실제로 두 개의 캔버스 픽셀로 채워집니다.
모호함의 원인에 대한 예비 논의위 내용은 필요한 몇 가지 기본 지식에 대한 소개이며, 정식 탐구는 아래에서 시작됩니다.
먼저 캔버스를 사용하여 이미지를 그리는 것이 비트맵이고 우리가 일반적으로 사용하는 jpg, png도 비트맵이라고 언급했습니다. 그렇다면 비트맵이란 무엇일까요?
픽셀 맵 또는 래스터 맵이라고도 불리는 비트맵은 이미지의 각 지점에 대한 색상, 깊이, 투명도 및 기타 정보를 기록하여 이미지를 저장하고 표시합니다. 좀 더 구체적으로 말하면 비트맵은 거대한 퍼즐이라고 생각하면 됩니다. 이 퍼즐은 수많은 조각으로 구성되어 있으며 각 조각은 단색 픽셀을 나타냅니다. 이론적으로 하나의 비트맵 픽셀은 하나의 물리적 픽셀에 해당합니다 . 하지만 애플의 레티나 스크린과 같은 고화질 화면을 사용하여 사진을 보는 경우에는 어떻게 될까요?
iPhone 4의 Retina 화면에 표시될 다음 코드가 있다고 가정합니다.
<캔버스 너비=320 높이=150 스타일=너비: 320px 높이: 150px></canvas>
iPhone 4 자체의 물리적 픽셀은 640 * 980인 반면, 장치 독립 픽셀은 320 * 480입니다. 즉, 1개의 CSS 픽셀은 실제로 4개의 물리적 픽셀로 구성되며 캔버스의 픽셀은 320 * 150입니다. 320 * 150. 1 CSS 픽셀이 1 개의 캔버스 요소로 구성되므로 변환이 완료된다는 의미이며, 레티나 화면에서는 하나의 캔버스 픽셀(또는 하나의 비트맵 픽셀)이 4개의 물리적 픽셀을 채웁니다. 단일 비트맵 픽셀은 더 이상 나눌 수 없으므로 가장 가까운 색상만 취할 수 있으므로 그림이 흐려집니다.
여전히 혼란스럽다면 다음 그림을 통해 레티나 화면에 비트맵이 어떻게 채워지는지 확인할 수 있습니다.
위 그림의 왼쪽은 일반 화면의 표시 규칙을 보여줍니다. 비트맵 픽셀이 4개인 반면, 오른쪽의 고화질 화면은 16개의 픽셀이 있음을 알 수 있습니다. 픽셀을 잘라낼 수 없기 때문에 색상이 변경됩니다.
하지만 명확하게 설명되지 않은 것은 왜 사진이 원래의 값을 직접 취하지 않고 가장 가까운 색상을 취하는가 하는 것입니다.
무대 뒤의 남자---스무딩 기술다음은 내 선배 친구 중 한 명이 설명하는 데 도움을 준 내용입니다. 방금 우리는 각 비트맵 요소가 실제로 단색 픽셀이라고 말했습니다. 이제 CSS 크기가 4px * 4px이고 dpr이 1인 일반 화면에 숫자 0을 그려야 한다고 가정합니다. 그런 다음 우리가 그리는 것은 다음 그림과 같아야 합니다. 여기서 1은 검은색 픽셀을 나타내고 0은 흰색 픽셀을 나타냅니다.
dpr이 상대적으로 작을 때 0 패턴이 여전히 상대적으로 분명하다는 것을 알 수 있습니다. 이제 CSS 크기는 변경되지 않고 이미지가 레티나 화면에 그려지면 효과는 어떻게 될까요?
우리는 레티나 스크린 아래에서 하나의 CSS 픽셀이 4개의 물리적 픽셀을 나타낸다는 것을 알고 있습니다. 아무런 처리도 하지 않고 위의 행렬에 따라 직접 배열하고 행렬을 확장하면 레티나 스크린 아래에 패턴이 있다는 것을 알 수 있습니다. 매우 명백하게 들쭉날쭉한 느낌이 듭니다. 이미지에 색조의 힌트가 확실히 부족합니다.
이미지를 살짝 바꾸면 다음 그림으로 바꿔주세요
이미지가 순간적으로 부드러워진 느낌이 들지만 4 0으로 채워져야 할 자리가 3 1 더하기 1 0이 되었습니다. 이것은 실제로 소위 이미지 평활화 과정으로, 들쭉날쭉한 느낌을 해결하기 위해 원래 색상을 변경합니다. 더 많은 색상으로 채워진 사진에서는 사진의 연결 부분이 대략적인 색상이 됩니다. 위의 색상을 채울 때 원래 색상이 아닌 대략적인 색상을 사용하는 이유를 설명합니다.
이유 요약위의 설명을 마치고 이제 다음과 같은 결론을 요약해 보겠습니다. 이제 모바일 단말기가 대중화되고 고화질 화면이 기본적으로 대중화되었으므로 1px CSS 픽셀은 실제로 4개 이상의 물리적 픽셀을 나타냅니다. 그러나 코드 문제로 인해 1px CSS 픽셀과 1개의 캔버스 픽셀이 동일하므로 1개의 캔버스 픽셀은 실제로 4개 이상의 물리적 픽셀로 채워져야 하며, 원활한 이미지 처리를 보장하려면 나머지 물리적 픽셀을 채워야 합니다. 픽셀은 원래 색상의 근사치를 사용하므로 이미지가 흐릿해집니다.
솔루션 아이디어문제의 원인을 이해하면 문제 해결은 쉽습니다. 문제 해결에서 가장 중요한 것은 하나의 캔버스 픽셀과 하나의 물리적 픽셀을 동일하게 만드는 것입니다.
위에서 언급한 dpr인 상위 버전 브라우저의 창 개체 아래에는 devicePixelRatio 속성이 있습니다.
캔버스 요소 CSS 너비와 높이가 결정되면 다음을 수행할 수 있습니다.
let canvas = document.getElementById('canvas');let ctx = canvas.getContext('2d');let dpr = window.devicePixelRatio; // dpr이 2라고 가정// CSS의 너비와 높이를 가져옵니다. let { width: cssWidth, 높이: cssHeight } = canvas.getBoundingClientRect();// dpr에 따르면 하나의 캔버스 픽셀이 하나의 물리적 픽셀과 동일하도록 캔버스 캔버스의 픽셀을 확장합니다. canvas.width = dpr * cssWidth; canvas.height = dpr * cssHeight; 캔버스도 확장됩니다. 그리기 내용이 원래 좌표계를 기반으로 하는 경우 내용이 줄어들므로 // 그리기 배율을 확대해야 합니다. ctx.scale(dpr,dpr);경험 요약
문제를 발견하면 문제 해결에 집중하지 못하는 경우가 많습니다. 대신 문제의 원인을 깊이 이해해야 더 나은 방향으로 나아갈 수 있습니다.
위의 내용은 이 기사의 전체 내용입니다. 모든 분들의 학습에 도움이 되기를 바랍니다. 또한 모든 분들이 VeVb Wulin Network를 지지해 주시길 바랍니다.