업로드하기 전에 HTML5 사전 크기 조정 이미지
국수 긁는 도구입니다.
HTML5 로컬 저장소와 xhr v2가 있습니다. 누군가가 실제 사례를 찾거 나이 질문에 대해 예 또는 아니오를 줄 수 있는지 궁금합니다.
새로운 로컬 저장소 (또는 기타)를 사용하여 이미지 크기를 미리 조정할 수 있습니까? 이미지 크기 조정에 대한 단서가없는 사용자가 10MB 이미지를 내 웹 사이트로 드래그 할 수 있으며 새로운 로컬 저장소를 사용하여 크기를 조정할 수 있습니다. 그런 다음 작은 크기로 업로드하십시오.
나는 당신이 플래시, 자바 애플릿, 액티브 X로 그것을 할 수 있다는 것을 잘 알고 있습니다 ... 문제는 자바 스크립트 + Html5로 할 수 있는지입니다.
이에 대한 답변을 기대합니다.
지금 당장.
예, File API를 사용 하면 canvas 요소를 사용 하여 이미지를 처리 할 수 있습니다 .
이 Mozilla Hacks 블로그 게시물 은 대부분의 프로세스를 안내합니다. 블로그 게시물의 소스 코드는 다음과 같습니다.
// from an input element
var filesToUpload = input.files;
var file = filesToUpload[0];
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e) {img.src = e.target.result}
reader.readAsDataURL(file);
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 800;
var MAX_HEIGHT = 600;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/png");
//Post dataurl to the server with AJAX
몇 년 전에이 문제를 해결하고 https://github.com/rossturner/HTML5-ImageUploader 로 솔루션을 github에 업로드했습니다.
robertc의 답변은 Mozilla Hacks 블로그 게시물 에서 제안 된 솔루션을 사용 하지만 2 : 1 (또는 그 배수)이 아닌 스케일로 크기를 조정할 때 이미지 품질이 실제로 좋지 않다는 것을 알았습니다. 다른 이미지 크기 조정 알고리즘을 실험하기 시작했지만 대부분 속도가 느리거나 품질이 좋지 않았습니다.
마지막으로 x를 목표로 2 : 1 비율로 이미지 품질을 잃지 않고 1 캔버스에서 다른 캔버스로 복사하는 Mozilla 솔루션이 신속하게 작동하기 때문에 신속하게 실행되고 성능이 매우 좋은 솔루션을 생각해 냈습니다. 너비와 너비가 y 픽셀 인 경우 이미지가 x 와 2 x 사이 , y 와 2 y 사이가 될 때까지이 캔버스 크기 조정 방법을 사용합니다 . 이 시점에서 목표 크기로 크기를 조정하는 최종 "단계"에 대한 알고리즘 이미지 크기 조정으로 돌아갑니다. 몇 가지 다른 알고리즘을 시도한 후에 더 이상 온라인이 아니지만 인터넷 아카이브를 통해 액세스 할 수 있는 블로그에서 가져온 쌍 선형 보간에 정착했습니다.좋은 결과를 제공합니다. 적용 가능한 코드는 다음과 같습니다.
ImageUploader.prototype.scaleImage = function(img, completionCallback) {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
while (canvas.width >= (2 * this.config.maxWidth)) {
canvas = this.getHalfScaleCanvas(canvas);
}
if (canvas.width > this.config.maxWidth) {
canvas = this.scaleCanvasWithAlgorithm(canvas);
}
var imageData = canvas.toDataURL('image/jpeg', this.config.quality);
this.performUpload(imageData, completionCallback);
};
ImageUploader.prototype.scaleCanvasWithAlgorithm = function(canvas) {
var scaledCanvas = document.createElement('canvas');
var scale = this.config.maxWidth / canvas.width;
scaledCanvas.width = canvas.width * scale;
scaledCanvas.height = canvas.height * scale;
var srcImgData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
var destImgData = scaledCanvas.getContext('2d').createImageData(scaledCanvas.width, scaledCanvas.height);
this.applyBilinearInterpolation(srcImgData, destImgData, scale);
scaledCanvas.getContext('2d').putImageData(destImgData, 0, 0);
return scaledCanvas;
};
ImageUploader.prototype.getHalfScaleCanvas = function(canvas) {
var halfCanvas = document.createElement('canvas');
halfCanvas.width = canvas.width / 2;
halfCanvas.height = canvas.height / 2;
halfCanvas.getContext('2d').drawImage(canvas, 0, 0, halfCanvas.width, halfCanvas.height);
return halfCanvas;
};
ImageUploader.prototype.applyBilinearInterpolation = function(srcCanvasData, destCanvasData, scale) {
function inner(f00, f10, f01, f11, x, y) {
var un_x = 1.0 - x;
var un_y = 1.0 - y;
return (f00 * un_x * un_y + f10 * x * un_y + f01 * un_x * y + f11 * x * y);
}
var i, j;
var iyv, iy0, iy1, ixv, ix0, ix1;
var idxD, idxS00, idxS10, idxS01, idxS11;
var dx, dy;
var r, g, b, a;
for (i = 0; i < destCanvasData.height; ++i) {
iyv = i / scale;
iy0 = Math.floor(iyv);
// Math.ceil can go over bounds
iy1 = (Math.ceil(iyv) > (srcCanvasData.height - 1) ? (srcCanvasData.height - 1) : Math.ceil(iyv));
for (j = 0; j < destCanvasData.width; ++j) {
ixv = j / scale;
ix0 = Math.floor(ixv);
// Math.ceil can go over bounds
ix1 = (Math.ceil(ixv) > (srcCanvasData.width - 1) ? (srcCanvasData.width - 1) : Math.ceil(ixv));
idxD = (j + destCanvasData.width * i) * 4;
// matrix to vector indices
idxS00 = (ix0 + srcCanvasData.width * iy0) * 4;
idxS10 = (ix1 + srcCanvasData.width * iy0) * 4;
idxS01 = (ix0 + srcCanvasData.width * iy1) * 4;
idxS11 = (ix1 + srcCanvasData.width * iy1) * 4;
// overall coordinates to unit square
dx = ixv - ix0;
dy = iyv - iy0;
// I let the r, g, b, a on purpose for debugging
r = inner(srcCanvasData.data[idxS00], srcCanvasData.data[idxS10], srcCanvasData.data[idxS01], srcCanvasData.data[idxS11], dx, dy);
destCanvasData.data[idxD] = r;
g = inner(srcCanvasData.data[idxS00 + 1], srcCanvasData.data[idxS10 + 1], srcCanvasData.data[idxS01 + 1], srcCanvasData.data[idxS11 + 1], dx, dy);
destCanvasData.data[idxD + 1] = g;
b = inner(srcCanvasData.data[idxS00 + 2], srcCanvasData.data[idxS10 + 2], srcCanvasData.data[idxS01 + 2], srcCanvasData.data[idxS11 + 2], dx, dy);
destCanvasData.data[idxD + 2] = b;
a = inner(srcCanvasData.data[idxS00 + 3], srcCanvasData.data[idxS10 + 3], srcCanvasData.data[idxS01 + 3], srcCanvasData.data[idxS11 + 3], dx, dy);
destCanvasData.data[idxD + 3] = a;
}
}
};
config.maxWidth
원래의 종횡비를 유지하면서 이미지를 너비로 축소합니다 . 개발 당시 이것은 주요 데스크탑 브라우저 (IE9 +, Firefox, Chrome) 외에도 iPad / iPhone Safari에서 작동 했으므로 오늘날 HTML5가 더 광범위하게 채택되면 여전히 호환 될 것으로 기대합니다. canvas.toDataURL () 호출은 MIME 유형과 이미지 품질을 사용하여 품질 및 출력 파일 형식을 제어 할 수 있습니다 (원하는 경우 입력과 다를 수 있음).
여기서 다루지 않는 유일한 점은이 메타 데이터에 대한 지식이 없어도 방향 정보를 유지하는 것입니다. 이미지는 그대로 크기가 조정되어 저장된 상태에서 방향에 대한 이미지 내 메타 데이터가 손실되므로 태블릿 장치에서 "거꾸로"찍은 이미지는 장치의 카메라 뷰 파인더에서 뒤집어 졌더라도 렌더링됩니다. 이것이 우려되는 경우이 블로그 게시물 에는이를 수행하는 방법에 대한 좋은 가이드와 코드 예제가 있으며 위 코드에 통합 될 수 있습니다.
위의 수정 :
<img src="" id="image">
<input id="input" type="file" onchange="handleFiles()">
<script>
function handleFiles()
{
var filesToUpload = document.getElementById('input').files;
var file = filesToUpload[0];
// Create an image
var img = document.createElement("img");
// Create a file reader
var reader = new FileReader();
// Set the image once loaded into file reader
reader.onload = function(e)
{
img.src = e.target.result;
var canvas = document.createElement("canvas");
//var canvas = $("<canvas>", {"id":"testing"})[0];
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 400;
var MAX_HEIGHT = 300;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/png");
document.getElementById('image').src = dataurl;
}
// Load files into file reader
reader.readAsDataURL(file);
// Post the data
/*
var fd = new FormData();
fd.append("name", "some_filename.jpg");
fd.append("image", dataurl);
fd.append("info", "lah_de_dah");
*/
}</script>
- img.onload 추가
- 실제 예제로 POST 요청을 확장하십시오.
function handleFiles()
{
var dataurl = null;
var filesToUpload = document.getElementById('photo').files;
var file = filesToUpload[0];
// Create an image
var img = document.createElement("img");
// Create a file reader
var reader = new FileReader();
// Set the image once loaded into file reader
reader.onload = function(e)
{
img.src = e.target.result;
img.onload = function () {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 800;
var MAX_HEIGHT = 600;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
dataurl = canvas.toDataURL("image/jpeg");
// Post the data
var fd = new FormData();
fd.append("name", "some_filename.jpg");
fd.append("image", dataurl);
fd.append("info", "lah_de_dah");
$.ajax({
url: '/ajax_photo',
data: fd,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data){
$('#form_photo')[0].reset();
location.reload();
}
});
} // img.onload
}
// Load files into file reader
reader.readAsDataURL(file);
}
휠을 재발 명하지 않으려면 plupload.com을 사용해보십시오 .
fd.append("image", dataurl);
This will not work. On PHP side you can not save file with this.
Use this code instead:
var blobBin = atob(dataurl.split(',')[1]);
var array = [];
for(var i = 0; i < blobBin.length; i++) {
array.push(blobBin.charCodeAt(i));
}
var file = new Blob([new Uint8Array(array)], {type: 'image/png', name: "avatar.png"});
fd.append("image", file); // blob file
The accepted answer works great, but the resize logic ignores the case in which the image is larger than the maximum in only one of the axes (for example, height > maxHeight but width <= maxWidth).
I think the following code takes care of all cases in a more straight-forward and functional way (ignore the typescript type annotations if using plain javascript):
private scaleDownSize(width: number, height: number, maxWidth: number, maxHeight: number): {width: number, height: number} {
if (width <= maxWidth && height <= maxHeight)
return { width, height };
else if (width / maxWidth > height / maxHeight)
return { width: maxWidth, height: height * maxWidth / width};
else
return { width: width * maxHeight / height, height: maxHeight };
}
Resizing images in a canvas element is generally bad idea since it uses the cheapest box interpolation. The resulting image noticeable degrades in quality. I'd recommend using http://nodeca.github.io/pica/demo/ which can perform Lanczos transformation instead. The demo page above shows difference between canvas and Lanczos approaches.
It also uses web workers for resizing images in parallel. There is also WEBGL implementation.
There are some online image resizers that use pica for doing the job, like https://myimageresizer.com
Typescript
async resizeImg(file: Blob): Promise<Blob> {
let img = document.createElement("img");
img.src = await new Promise<any>(resolve => {
let reader = new FileReader();
reader.onload = (e: any) => resolve(e.target.result);
reader.readAsDataURL(file);
});
await new Promise(resolve => img.onload = resolve)
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
let MAX_WIDTH = 1000;
let MAX_HEIGHT = 1000;
let width = img.naturalWidth;
let height = img.naturalHeight;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
let result = await new Promise<Blob>(resolve => { canvas.toBlob(resolve, 'image/jpeg', 0.95); });
return result;
}
You can use dropzone.js if you want to use simple and easy upload manager with resizing before upload functions.
It has builtin resize functions, but you can provide your own if you want.
참고URL : https://stackoverflow.com/questions/10333971/html5-pre-resize-images-before-uploading
'IT story' 카테고리의 다른 글
파이썬에서 목록을 사전으로 변환 (0) | 2020.05.24 |
---|---|
C #의 "정적 방법"은 무엇입니까? (0) | 2020.05.24 |
브라우저를 다시로드 할 때 Angular 2.0 라우터가 작동하지 않습니다 (0) | 2020.05.24 |
Chrome에서 HTTP POST를 어떻게 디버깅 할 수 있습니까? (0) | 2020.05.24 |
Docker Postgres 스크립트에서 사용자 / 데이터베이스를 만드는 방법 (0) | 2020.05.24 |