การปรับขนาดภาพฝั่งไคลเอ็นต์ด้วย JavaScript ก่อนที่จะอัปโหลดไปยังเซิร์ฟเวอร์


147

ฉันกำลังมองหาวิธีปรับขนาดไคลเอนต์รูปภาพด้วย JavaScript (ปรับขนาดได้จริงๆไม่ใช่แค่เปลี่ยนความกว้างและความสูง)
ฉันรู้ว่าเป็นไปได้ที่จะทำใน Flash แต่ฉันต้องการหลีกเลี่ยงถ้าเป็นไปได้

มีอัลกอริธึมโอเพนซอร์ซที่ใดที่หนึ่งบนเว็บหรือไม่?


สำหรับผู้ที่ยังต้องการทราบคำตอบนี้คุณสามารถทำได้ แต่คุณจะต้องทำการโทร ajax เพื่อการประมวลผลภาพ
รูปทรงหลายเหลี่ยม

1
'ต้องทำ' คุณสามารถแก้ไขได้บนเซิร์ฟเวอร์หลังจากทั้งหมดและรับข้อมูลที่โปร่งใสผ่านการโทร AJAX แต่ความพยายามทั้งหมดก็คือการทำสิ่งนั้นให้กับลูกค้าและในฐานะที่เจเรมีชี้ให้เห็นว่าสามารถทำได้ ฉันคิดว่านี่เป็นตัวอย่างที่ดี: github.com/rossturner/HTML5-ImageUploader
Bart

2
ด้วยเวอร์ชันล่าสุด Dropzone.js รองรับการปรับขนาดภาพฝั่งไคลเอ็นต์ก่อนที่จะอัพโหลด
user1666456

คำตอบ:


111

นี่คือส่วนสำคัญที่ทำสิ่งนี้: https://gist.github.com/dcollien/312bce1270a5f511bf4a

(เวอร์ชัน es6 และรุ่น. js ซึ่งสามารถรวมอยู่ในแท็กสคริปต์)

คุณสามารถใช้มันได้ดังต่อไปนี้:

<input type="file" id="select">
<img id="preview">
<script>
document.getElementById('select').onchange = function(evt) {
    ImageTools.resize(this.files[0], {
        width: 320, // maximum width
        height: 240 // maximum height
    }, function(blob, didItResize) {
        // didItResize will be true if it managed to resize it, otherwise false (and will return the original file as 'blob')
        document.getElementById('preview').src = window.URL.createObjectURL(blob);
        // you can also now upload this blob using an XHR.
    });
};
</script>

มันมีเครือข่ายการตรวจจับการสนับสนุนและโพลีฟิลล์มากมายเพื่อให้แน่ใจว่าสามารถทำงานบนเบราว์เซอร์ได้มากเท่าที่ฉันสามารถจัดการได้

(นอกจากนี้ยังละเว้นรูปภาพ gif - ในกรณีที่เคลื่อนไหว)


2
ฉันรู้สึกว่าคุณยังไม่ได้รับคำชมมากพอสำหรับเรื่องนี้ - ฉันคิดว่ามันใช้งานได้ดีและง่ายมาก ขอบคุณสำหรับการแบ่งปัน!
Matt

4
อืม .. ฉันประสบความสำเร็จอย่างดีในเรื่องนี้ แต่ฉันพบว่าภาพของฉัน (นอกเหนือจากการปรับขนาด) ยังประสบกับการสูญเสียคุณภาพอย่างมาก
Ruben Martinez Jr.

1
สวัสดีฉันต้องการตัวอย่างที่จะใช้เช่นนี้และฉันคิดว่ามันเป็นสิ่งที่ดีมาก แต่ .. ฟังก์ชั่น (หยด, didItResize) {// didItResize จะเป็นจริงถ้ามันมีการจัดการเพื่อปรับขนาดมันเป็นอย่างอื่นเท็จ (และจะกลับมาเดิม ไฟล์เป็น 'blob') document.getElementById ('ตัวอย่าง') src = window.URL.createObjectURL (blob); // ขณะนี้คุณสามารถอัปโหลดหยดนี้โดยใช้ XHR ที่นี่ฉันมีปัญหา .. ฉันจะส่งภาพนี้ในแบบฟอร์มด้วยการส่งแบบฟอร์มได้อย่างไร ฉันหมายถึงเหมือนคำขอโพสต์ที่ถูกกระตุ้นโดยปุ่มส่ง คุณรู้วิธีปกติ ขอบคุณสำหรับส่วนสำคัญ!
iedmrc

3
สำหรับทุกคนที่มีการสูญเสียคุณภาพ (resampling) ปรับปรุงบริบทผ้าใบชุดimageSmoothingEnabledเป็น true` และการimageSmoothingQuality highใน typescript ว่าบล็อกมีลักษณะดังนี้: const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; (ctx as any).imageSmoothingQuality = 'high'; ctx.drawImage(image, 0, 0, width, height);
ฌอนเพอร์กิน

1
มีโอกาสที่จะทำแพ็กเกจนี้เป็น npm หรือไม่? จะดีมาก!
erksch

62

คำตอบคือใช่ - ใน HTML 5 คุณสามารถปรับขนาดรูปภาพฝั่งไคลเอ็นต์โดยใช้องค์ประกอบ Canvas คุณยังสามารถนำข้อมูลใหม่และส่งไปยังเซิร์ฟเวอร์ ดูบทช่วยสอนนี้:

http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/


28
นี่เป็นคำตอบสำหรับลิงค์เท่านั้นและควรแสดงความคิดเห็น
Jimbo

2
canvas.mozGetAsFile ( "foo.png"); เป็นฟังก์ชั่นที่เลิกใช้แล้ว
mili

12

หากคุณกำลังปรับขนาดก่อนอัปโหลดฉันเพิ่งค้นพบhttp://www.plupload.com/นี้

มันมหัศจรรย์สำหรับคุณในทุกวิถีทางเท่าที่จะเป็นไปได้

น่าเสียดายที่ HTML5 ปรับขนาดเท่านั้นรองรับเบราว์เซอร์ Mozilla แต่คุณสามารถเปลี่ยนเบราว์เซอร์อื่นเป็น Flash และ Silverlight

ฉันลองแล้วมันใช้งานได้กับ Android ของฉัน!

ฉันใช้http://swfupload.org/ในแฟลชมันทำงานได้ดี แต่ขนาดที่ปรับขนาดเล็กมาก (จำข้อ จำกัด ไม่ได้) และไม่กลับไปที่ html4 เมื่อไม่สามารถใช้งานแฟลชได้


44
เป็นการดีที่จะปรับขนาดฝั่งไคลเอ็นต์สำหรับเมื่อผู้ใช้พยายามอัปโหลดรูปถ่าย 10mb ที่จะถูกจัดเก็บเป็นรูปถ่ายขนาดเล็กกว่ามาก มันจะอัพโหลดเร็วขึ้นมากด้วยวิธีนี้
Kyle

สถานการณ์เดียวกันที่นี่ทันทีที่คุณมีไฟล์อินพุตและผู้ใช้อยู่บนสมาร์ทโฟนและถ่ายภาพโดยใช้กล้องมันจะมีขนาดประมาณ 10 mb บนสมาร์ทโฟนรุ่นใหม่ หากคุณอยู่บนฝั่งเซิร์ฟเวอร์จะทำการปรับขนาดและเก็บเฉพาะรุ่นที่เล็กกว่าเท่านั้นคุณจะประหยัดข้อมูลโทรศัพท์มือถือจำนวนมากและเวลาโหลดในการปรับขนาดล่วงหน้าในไคลเอนต์
อเล็กซ์

1
ระวังเนื่องจาก plupload คือ AGPL
อเล็กซ์

11

http://nodeca.github.io/pica/demo/

ในเบราว์เซอร์สมัยใหม่คุณสามารถใช้ Canvas เพื่อโหลด / บันทึกข้อมูลรูปภาพ แต่คุณควรจำไว้หลายสิ่งหากคุณปรับขนาดภาพบนไคลเอนต์:

  1. คุณจะมีเพียง 8 บิตต่อช่อง (jpeg สามารถมีช่วงไดนามิกที่ดีขึ้นประมาณ 12 บิต) หากคุณไม่ได้อัปโหลดรูปภาพมืออาชีพนั่นน่าจะเป็นปัญหา
  2. ระวังการปรับขนาดอัลกอริทึม ตัวแก้ไขข้อมูลด้านไคลเอนต์ส่วนใหญ่ใช้คณิตศาสตร์เล็กน้อยและผลลัพธ์นั้นแย่กว่าที่ควรจะเป็น
  3. คุณอาจต้องปรับภาพที่ลดขนาดให้แหลม
  4. หากคุณต้องการนำ metadata (exif และอื่น ๆ ) มาใช้ซ้ำจากต้นฉบับ - อย่าลืมตัดข้อมูลโปรไฟล์สี เพราะมันถูกนำไปใช้เมื่อคุณโหลดภาพไปยังแคนวาส

6

อาจมีแท็ก Canvas (แม้ว่าจะไม่สามารถพกพาได้) มีบล็อกเกี่ยวกับวิธีหมุนรูปภาพด้วยผืนผ้าใบที่นี่ฉันคิดว่าคุณสามารถหมุนได้คุณสามารถปรับขนาดได้ บางทีมันอาจเป็นจุดเริ่มต้น

ดูห้องสมุดนี้ด้วย


2
ตัวอย่างที่มีประโยชน์มาก คุณอาจต้องการเพิ่มตัวอย่างหรือสองคำตอบในกรณีที่ลิงก์เหล่านี้ไม่ทำงาน
เทรเวอร์

4

คุณสามารถใช้เฟรมเวิร์กการประมวลผลภาพจาวาสคริปต์สำหรับการประมวลผลอิมเมจฝั่งไคลเอ็นต์ก่อนอัพโหลดอิมเมจไปยังเซิร์ฟเวอร์

ด้านล่างฉันใช้MarvinJเพื่อสร้างรหัสที่รันได้ตามตัวอย่างในหน้าต่อไปนี้: "การประมวลผลภาพในฝั่งไคลเอ็นต์ก่อนที่จะอัปโหลดไปยังเซิร์ฟเวอร์"

โดยทั่วไปฉันใช้วิธีMarvin.scale (... )เพื่อปรับขนาดภาพ จากนั้นฉันอัปโหลดภาพเป็นหยด (โดยใช้วิธีการimage.toBlob () ) เซิร์ฟเวอร์ตอบกลับโดยระบุ URL ของภาพที่ได้รับ

/***********************************************
 * GLOBAL VARS
 **********************************************/
var image = new MarvinImage();

/***********************************************
 * FILE CHOOSER AND UPLOAD
 **********************************************/
 $('#fileUpload').change(function (event) {
	form = new FormData();
	form.append('name', event.target.files[0].name);
	
	reader = new FileReader();
	reader.readAsDataURL(event.target.files[0]);
	
	reader.onload = function(){
		image.load(reader.result, imageLoaded);
	};
	
});

function resizeAndSendToServer(){
  $("#divServerResponse").html("uploading...");
	$.ajax({
		method: 'POST',
		url: 'https://www.marvinj.org/backoffice/imageUpload.php',
		data: form,
		enctype: 'multipart/form-data',
		contentType: false,
		processData: false,
		
	   
		success: function (resp) {
       $("#divServerResponse").html("SERVER RESPONSE (NEW IMAGE):<br/><img src='"+resp+"' style='max-width:400px'></img>");
		},
		error: function (data) {
			console.log("error:"+error);
			console.log(data);
		},
		
	});
};

/***********************************************
 * IMAGE MANIPULATION
 **********************************************/
function imageLoaded(){
  Marvin.scale(image.clone(), image, 120);
  form.append("blob", image.toBlob());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.marvinj.org/releases/marvinj-0.8.js"></script>
<form id="form" action='/backoffice/imageUpload.php' style='margin:auto;' method='post' enctype='multipart/form-data'>
				<input type='file' id='fileUpload' class='upload' name='userfile'/>
</form><br/>
<button type="button" onclick="resizeAndSendToServer()">Resize and Send to Server</button><br/><br/>
<div id="divServerResponse">
</div>


นี่มันช่างยอดเยี่ยมมาก!
pimbrouwers

2

ใช่ด้วยเบราว์เซอร์รุ่นใหม่สิ่งนี้สามารถทำได้โดยสิ้นเชิง ถึงแม้จะสามารถอัปโหลดไฟล์เป็นไฟล์ไบนารี่ได้ก็ตาม

http://jsfiddle.net/bo40drmv/

(คำตอบนี้เป็นการปรับปรุงคำตอบที่ยอมรับได้ที่นี่ )

จำไว้ว่าให้ประมวลผลการส่งผลลัพธ์ใน PHP ด้วยสิ่งที่คล้ายกับ:

//File destination
$destination = "/folder/cropped_image.png";
//Get uploaded image file it's temporary name
$image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0];
//Move temporary file to final destination
move_uploaded_file($image_tmp_name, $destination);

หากใครกังวลเกี่ยวกับประเด็นของ Vitaly คุณสามารถลองการปลูกพืชและปรับขนาด jfiddle ที่ใช้งานได้


0

จากประสบการณ์ของฉันตัวอย่างนี้เป็นทางออกที่ดีที่สุดสำหรับการอัปโหลดภาพที่ปรับขนาดแล้ว: https://zocada.com/compress-resize-images-javascript-browser/

มันใช้คุณสมบัติผ้าใบ HTML5

รหัสเป็น 'ง่าย' เช่นนี้

compress(e) {
    const fileName = e.target.files[0].name;
    const reader = new FileReader();
    reader.readAsDataURL(e.target.files[0]);
    reader.onload = event => {
        const img = new Image();
        img.src = event.target.result;
        img.onload = () => {
                const elem = document.createElement('canvas');
                const width = Math.min(800, img.width);
                const scaleFactor = width / img.width;
                elem.width = width;
                elem.height = img.height * scaleFactor;

                const ctx = elem.getContext('2d');
                // img.width and img.height will contain the original dimensions
                ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);
                ctx.canvas.toBlob((blob) => {
                    const file = new File([blob], fileName, {
                        type: 'image/jpeg',
                        lastModified: Date.now()
                    });
                }, 'image/jpeg', 1);
            },
            reader.onerror = error => console.log(error);
    };
}

ตัวเลือกนี้มีข้อเสียเพียงข้อเดียวและเกี่ยวข้องกับการหมุนภาพเนื่องจากไม่สนใจข้อมูล EXIF ซึ่งฉันกำลังทำงานอยู่ในขณะนี้ จะอัปเดตหลังจากฉันทำเสร็จแล้ว

ข้อเสียอีกประการหนึ่งคือการขาดการสนับสนุน IE / Edge ของศัตรูซึ่งฉันกำลังทำงานอยู่เช่นกัน แม้ว่าจะมีข้อมูลในลิงค์ด้านบน สำหรับปัญหาทั้งสอง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.