최근 커뮤니티 시스템은 사용자 아바타 업로드와 관련된 모바일 단말기를 지원해야 합니다. 아바타는 대, 중, 소의 세 가지 크기로 제공됩니다. PC 측에서는 커뮤니티가 Flash를 사용합니다. 아바타 편집 및 생성은 처리하지만 Flash 제어는 인터페이스가 불편하고 모바일 단말기는 이러한 문제를 고려하여 최종적으로 Canvas를 선택하여 이미지 크기 조정 및 이미지 데이터 수집을 완료했습니다.
아바타는 일반적으로 정사각형입니다. 먼저 이미지의 너비와 높이의 최소값을 구하고, 최소값을 측면 길이로 사용하여 중앙 자르기를 수행해야 합니다. :
var ImageEditor = function() { // 用离线canvas处理图片数据 this.canvas = document.createElement('canvas'); this.context = this.canvas.getContext('2d'); }; var fn = ImageEditor.prototype; fn.resizeCanvas = function(width, height) { this.canvas.width = width; this.canvas.height = height; }; fn.clipSquareImage = function(url, callback) { var that = this, img = new Image(); img.src = url; img.onload = function() { // 取宽高最小值作为正方形边长 var eLength = Math.min(img.width, img.height), picture = img; // canvas不支持局部截屏,截屏前必须先调节canvas的宽高 that.resizeCanvas(eLength, eLength); // 将图片以居中裁剪的方式画到canvas中。 // drawImage支持9个参数:图片对象,图片上的剪切坐标XY, // 剪切宽高,图片在canvas上的坐标XY及图片宽高 that.context.drawImage(picture, (picture.width - eLength) / 2, (picture.height - eLength) / 2, eLength, eLength, 0, 0, eLength, eLength); // 截屏,即获取base64数据 callback.call(that, that.canvas.toDataURL('image/png')); }; };
위 clipSquareImage
함수에서는 canvas.toDataURL
인터페이스가 너비 및 높이 매개변수를 제공하지 않기 때문에 한 번에 전체 캔버스 화면 데이터만 캡처할 수 있으므로 캔버스의 스크린샷을 찍기 전에 먼저 캔버스 요소의 크기를 설정해야 합니다. 하지만 모바일 사진의 해상도는 매우 높으며 너비와 높이가 대부분 3000을 넘습니다. 사진의 최소 너비와 높이를 기준으로 Canvas의 크기를 설정할 때 Canvas 요소의 최소 너비도 다음과 같습니다. 3000 이상으로 높습니다.
문제는 각 플랫폼마다 캔버스 크기에 제한이 있다는 것입니다. 캔버스의 너비나 높이가 플랫폼 제한을 초과하면 캔버스는 렌더링할 수 없으며 canvas.toDataURL
는 렌더링만 할 수 있습니다. 투명한 이미지 데이터를 얻습니다.
캔버스 요소의 최대 크기는 일부 플랫폼에서의 캔버스 크기 제한을 언급합니다.
chrome = 32767x32767 iPod Touch 16GB = 1448x1448 iPad Mini = 2290x2289 iPhone 3 = 1448x1448 iPhone 5 = 2290x2289
위 데이터를 참조하여 먼저 캔버스의 최대 너비를 설정합니다.
var MAX_WIDTH = 1000;
clipSquareImage
기능에 최대 너비 감지를 추가합니다. 제한을 초과하는 경우 이미지 크기 조정을 위한 임시 캔버스를 만들고 마지막으로 임시 캔버스를 중앙에서 자릅니다.
fn.clipSquareImage = function(url, callback) { var that = this, img = new Image(); img.src = url; img.onload = function() { // 取图片宽高和Canvas的最大宽度的最小值作为等边长 var eLength = Math.min(img.width, img.height, MAX_WIDTH), // 剪切对象 picture = img, tempEditor, ratio; // 如果图片尺寸超出限制 if (eLength === MAX_WIDTH) { // 创建一个临时editor tempEditor = new ImageEditor(); ratio = img.width / img.height; // 按图片比例缩放canvas img.width < img.height ? tempEditor.resizeCanvas(MAX_WIDTH * ratio, MAX_WIDTH) : tempEditor.resizeCanvas(MAX_WIDTH, MAX_WIDTH / ratio); tempEditor.context.drawImage(img, 0, 0, tempEditor.canvas.width, tempEditor.canvas.height); // 将临时Canvas作为剪切对象 picture = tempEditor.canvas; eLength = Math.min(tempEditor.canvas.width, tempEditor.canvas.height); } // 居中剪切 // ... ... // 截屏操作 // ... ... }; };
위에서는 Canvas를 통해 정사각형 이미지를 잘라낼 수 있었습니다. 다음으로 아바타 이미지를 대, 중, 소의 세 가지 크기로 처리해야 합니다. Canvas에서는 drawImage
인터페이스가 매우 편리한 스케일링 기능을 제공합니다:
var editor = new ImageEditor; // 将图片缩放到300x300 // drawImage支持5个参数:图片对象,及图片在canvas上的坐标和宽高 editor.context.drawImage(squareImage, 0, 0, 300, 300);
그러나 큰 이미지를 줄이기 위해 drawImage
를 직접 사용하면 이미지가 들쭉날쭉하게 보일 수 있습니다. 스택 오버플로에서 HTML5 캔버스 drawImage: 안티앨리어싱 적용 방법 제안: 이미지를 같은 비율로 여러 번 줄이고 최종적으로 대상 크기로 확대:
참조 이 솔루션에서는 antialiasScale
앤티앨리어싱 스케일링 기능을 구현할 수 있습니다:
fn.antialisScale = function(img, width, height) { var offlineCanvas = document.createElement('canvas'), offlineCtx = offlineCanvas.getContext('2d'), sourceWidth = img.width, sourceHeight = img.height, // 缩小操作的次数 steps = Math.ceil(Math.log(sourceWidth / width) / Math.log(2)) - 1, i; // 渲染图片 offlineCanvas.width = sourceWidth; offlineCanvas.height = sourceHeight; offlineCtx.drawImage(img, 0, 0, offlineCanvas.width, offlineCanvas.height); // 缩小操作 // 进行steps次的减半缩小 for(i = 0; i < steps; i++) { offlineCtx.drawImage(offlineCanvas, 0, 0, offlineCanvas.width * 0.5, offlineCanvas.height * 0.5); } // 放大操作 // 进行steps次的两倍放大 this.context.drawImage(offlineCanvas, 0, 0, offlineCanvas.width * Math.pow(0.5, steps), offlineCanvas.height * Math.pow(0.5, steps), 0, 0, width, height); };
drawImage 대신 이 함수를 사용하여 스케일링 작업을 완료하고 세 가지 크기의 아바타 이미지를 생성할 수 있습니다:
fn.scaleSquareImage = function(url, sizes, callback) { var that = this; // 先裁剪一个正方形 that.clipSquareImage(url, sizes, function(data) { var squareImage = new Image(), result = [], i; squareImage.src = data; // 抗锯齿缩放 for (i = 0; i < sizes.length; i++) { that.antialisScale(squareImage, sizes[i], size[i]); result.push(that.canvas.toDataURL('image/png')); } callback.call(that, result); }); };
Canvas.toDataURL()
에서 얻은 기본 이미지 데이터 형식은 data:image/png;base64,
+ base64 데이터:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAADElEQVQImWNgoBMAAABpAAFEI8ARAAAAAElFTkSuQmCC
Canvas 스크린샷 데이터가 백그라운드로 전달되면, 배경은 시작 필드를 잘라야 합니다data:image/png;base64,
. 실제 base64 데이터를 뒤에 가져옵니다.
<?php $imgData = $_POST['imgData']; // 截取有用的部分 list($type, $imgData) = explode(';', $imgData); list(, $imgData) = explode(',', $imgData); // base64 编码中使用了加号, // 如果通过url传递base64数据,+号会转换成空格 $imgData = str_replace(' ', '+', $imgData); // 存储文件 $success = file_put_contents('PATH/XXX.png', base64_decode($imgData));
다음을 사용하여 Base64로 인코딩된 캔버스 이미지를 png 파일에 저장합니다. PHP
Html5 canvas drawImage: 앤티앨리어싱 적용 방법
캔버스 요소의 최대 크기
base64 데이터 문자열에서 서버측 PNG 이미지를 저장하는 방법
jQuery에서 Ajax 요청을 사용하여 FormData 객체를 보내는 방법
위 내용은 HTML5 Canvas 처리 아바타입니다. 업로드된 그래픽 코드를 자세히 소개하고 있으니 관련 내용은 PHP 중국어 홈페이지(m.sbmmt.com)를 참고해주세요!