การวางแนว Exif ของไคลเอ็นต์ JS: การหมุนและมิเรอร์ไฟล์ JPEG


154

ภาพถ่ายจากกล้องดิจิทัลมักถูกบันทึกเป็น JPEG พร้อมแท็ก "การวางแนว" EXIF หากต้องการแสดงอย่างถูกต้องรูปภาพจะต้องหมุน / ทำมิรเรอร์ตามทิศทางที่ตั้งไว้ แต่เบราว์เซอร์จะไม่สนใจข้อมูลที่แสดงภาพ แม้จะอยู่ในเว็บแอปเชิงพาณิชย์ขนาดใหญ่, การสนับสนุนสำหรับการวางแนว EXIF สามารถเป็นจุด ๆ1 แหล่งข้อมูลเดียวกันยังให้บทสรุปที่ดีเกี่ยวกับทิศทางที่แตกต่างกัน 8 แบบที่ JPEG สามารถมี:

สรุปการปฐมนิเทศ EXIF

ภาพตัวอย่างมีให้บริการที่4

คำถามคือวิธีหมุน / ทำมิเรอร์รูปภาพทางฝั่งไคลเอ็นต์เพื่อให้แสดงอย่างถูกต้องและสามารถประมวลผลเพิ่มเติมถ้าจำเป็น

มี JS ไลบรารีที่มีการแยกข้อมูล EXIF รวมทั้งแอตทริบิวต์การวางแนวทางที่มี2 Flickr ตั้งข้อสังเกตปัญหาประสิทธิภาพการทำงานเป็นไปได้เมื่อแยกภาพขนาดใหญ่ต้องใช้ webworkers 3

เครื่องมือคอนโซลได้อย่างถูกต้องสามารถ re-ปรับทิศทางภาพที่5 สคริปต์ PHP ในการแก้ปัญหามีให้ที่6

คำตอบ:


145

JavaScript-Load-Imageโครงการ github เป็นโซลูชั่นที่สมบูรณ์สำหรับปัญหาการวางแนว EXIF, หมุน / สะท้อนภาพอย่างถูกต้องสำหรับการวางแนว exif ทั้ง 8 ดูตัวอย่างออนไลน์ของการวางแนว javascript exif

รูปภาพถูกวาดลงบนผืนผ้าใบ HTML5 การเรนเดอร์ที่ถูกต้องถูกนำไปใช้ในjs / load-image-Orient.jsผ่านการดำเนินการ Canvas

หวังว่านี่จะช่วยให้คนอื่นประหยัดเวลาและสอนเครื่องมือค้นหาเกี่ยวกับอัญมณีโอเพนซอร์สนี้ :)


1
ฉันใช้ห้องสมุดนี้ แต่เมื่อเร็ว ๆ นี้มันพังบน iOS 8.3 ซึ่งเป็นที่ที่ฉันต้องการใช้งานได้มากที่สุด :(
Gordon Sun

2
ฉันกำลังดิ้นรนจริงๆเพื่อดูว่าสิ่งนี้มีประโยชน์อย่างไร ฉันกำลังเล่นกับมันเพื่อพยายามเรียนรู้ดังนั้นฉันจึงสามารถแยกวิเคราะห์หน้าและหมุนภาพเมื่อพวกเขาต้องหมุนหรือตรวจจับทิศทางและหมุนไฟล์ (อย่างใด) ก่อนที่จะอัปโหลดจริง การสาธิตไม่ได้ มันใช้ไฟล์จากอินพุตไฟล์และแสดงอย่างถูกต้องเมื่อมันมีประโยชน์ในโลกแห่งความจริง? เมื่อฉันแยกวิเคราะห์หน้าและป้อน URL จากแท็กรูปภาพลงในไลบรารี loadImage ไม่มีข้อมูล exif ดังนั้นจึงไม่สามารถทำได้ สำหรับการอัพโหลดมันจะคืนค่าวัตถุผ้าใบดังนั้นฉันจึงไม่สามารถส่งสิ่งนั้นไปยังเซิร์ฟเวอร์หรืออะไรก็ได้
Igneosaur

3
@igneosaur: คุณสามารถส่งข้อมูลที่เข้ารหัส base64 ไปยังเซิร์ฟเวอร์ด้วยcanvas.toDataURL()และถอดรหัสแล้วบันทึกลงในฝั่งเซิร์ฟเวอร์
br4nnigan

1
มากกว่าการใช้โครงการโหลดภาพที่คุณสามารถใช้บางส่วนของรหัสฐานในการอบของคุณเอง - ดูเพียงแค่ในgithub.com/blueimp/JavaScript-Load-Image/blob/master/js/...
Andy Lorenz

1
มีวิธีใดที่จะทำให้ผืนผ้าใบที่ไลบรารีนี้สร้างการตอบสนองเหมือน<img>แท็กปกติหรือไม่
Erik Berkun-Drevnig

103

การแปลงบริบทของ Mederrทำงานได้อย่างสมบูรณ์แบบ หากคุณต้องการแยกการวางแนวใช้ฟังก์ชั่นนี้เท่านั้น- คุณไม่ต้องการ libs การอ่าน EXIF ด้านล่างเป็นฟังก์ชั่นสำหรับปรับการวางแนวใหม่ใน base64 ภาพ นี่คือไวโอลินสำหรับมัน ผมเตรียมมานอกจากนี้ยังมีซอกับการสาธิตการสกัดการปฐมนิเทศ

function resetOrientation(srcBase64, srcOrientation, callback) {
  var img = new Image();    

  img.onload = function() {
    var width = img.width,
        height = img.height,
        canvas = document.createElement('canvas'),
        ctx = canvas.getContext("2d");

    // set proper canvas dimensions before transform & export
    if (4 < srcOrientation && srcOrientation < 9) {
      canvas.width = height;
      canvas.height = width;
    } else {
      canvas.width = width;
      canvas.height = height;
    }

    // transform context before drawing image
    switch (srcOrientation) {
      case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
      case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
      case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
      case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
      case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
      case 7: ctx.transform(0, -1, -1, 0, height, width); break;
      case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
      default: break;
    }

    // draw image
    ctx.drawImage(img, 0, 0);

    // export base64
    callback(canvas.toDataURL());
  };

  img.src = srcBase64;
};

7
กรณีเริ่มต้นในการวางแนวswitchไม่จำเป็นเนื่องจากการแปลงนั้นไม่ได้ทำอะไรเลย ลองพิจารณาใช้srcOrientation > 4 && srcOrientation < 9แทน[5,6,7,8].indexOf(srcOrientation) > -1เพราะเร็วกว่าและใช้ทรัพยากรน้อยลง (ทั้ง RAM และ CPU) ไม่จำเป็นต้องมีอาร์เรย์ที่นั่น สิ่งนี้สำคัญเมื่อทำการรวมภาพจำนวนมากซึ่งทุก ๆ บิตนับ มิฉะนั้นคำตอบที่ดีงาม upvoted!
Ryan Casas

4
@RyanCasas ฉันไม่ทราบว่าจะสามารถindexOfเปรียบเทียบความหนากับสิ่งที่คุณเสนอ ฉันวิ่งวนรอบง่าย ๆ ด้วยการวนซ้ำ 10M และเร็วขึ้น 1400% นิสัยดี: D ขอบคุณพวง!
WunderBart

1
ฉันใช้คำตอบนี้ใน Android WebView และปรากฎว่ามีอุปกรณ์ Android บางอย่างที่ไม่สนับสนุน WebGL ภายใน WebView (ดูbugs.chromium.org/p/chromium/issues/detail?id=555116 ) การหมุนอาจใช้เวลานานมากในอุปกรณ์เหล่านั้นขึ้นอยู่กับขนาดของภาพ
ndreisg

1
เมื่อใช้กับการอ้างอิงgetOrientationฉันอยากรู้ว่าสิ่งนี้มีประสิทธิภาพในแง่ของประสิทธิภาพหรือไม่ getOrientationcall fileReader.readAsArrayBufferจากนั้นเราจะเรียกURL.createObjectURLและส่งผลลัพธ์ไปresetOrientationให้ซึ่งจะโหลด URL นี้เป็นรูปภาพ สิ่งนี้หมายความว่าไฟล์รูปภาพจะถูก "โหลด" / อ่านโดยเบราว์เซอร์ไม่ใช่หนึ่งครั้ง แต่สองครั้งหรือฉันเข้าใจผิด?
โอลิเวอร์โจเซฟแอช

1
นอกจากนี้สิ่งที่ต้องทำเกี่ยวกับเบราว์เซอร์ที่การวางแนวจะได้รับการเคารพแล้ว? ฉันเชื่อว่านี่เป็นกรณีสำหรับ iOS Safari และในเบราว์เซอร์ที่สนับสนุน CSS image-orientation: from-imageเมื่อมีการใช้งาน
โอลิเวอร์โจเซฟแอช

40

ถ้า

width = img.width;
height = img.height;
var ctx = canvas.getContext('2d');

จากนั้นคุณสามารถใช้การแปลงภาพเหล่านี้เพื่อเปลี่ยนรูปภาพเป็นทิศทาง 1

จากการวางแนว:

  1. ctx.transform(1, 0, 0, 1, 0, 0);
  2. ctx.transform(-1, 0, 0, 1, width, 0);
  3. ctx.transform(-1, 0, 0, -1, width, height);
  4. ctx.transform(1, 0, 0, -1, 0, height);
  5. ctx.transform(0, 1, 1, 0, 0, 0);
  6. ctx.transform(0, 1, -1, 0, height, 0);
  7. ctx.transform(0, -1, -1, 0, height, width);
  8. ctx.transform(0, -1, 1, 0, 0, width);

ก่อนที่จะวาดภาพบน ctx


58
เกิดอะไรขึ้นที่นี่
มูฮัมหมัดอูเมอ

1
ด้วยสิ่งนี้คุณเพียงแค่ต้องรู้การวางแนว (เช่นผ่าน EXIF) แล้วหมุนตามต้องการ ครึ่งหนึ่งของสิ่งที่ฉันกำลังมองหา
Brenden

2
การแปลงเหล่านี้ใช้ไม่ได้สำหรับฉัน - ฉันใช้รหัสจากโครงการโหลดภาพที่github.com/blueimp/JavaScript-Load-Image/blob/master/js/เพื่อให้ได้สิ่งที่ฉันเชื่อว่าเป็นรหัสที่ได้รับการพิสูจน์แล้ว ซึ่งใช้ทั้งการแปลหมุนการดำเนินการในบริบทแคนวาสพร้อมกับการสลับความกว้าง / ความสูง ให้ผลลัพธ์ 100% กับฉันหลังจากการทดลองเป็นเวลาหลายชั่วโมงพร้อมความพยายามในการเปลี่ยนรูปแบบอื่น ๆ
Andy Lorenz

1
ทำไมมันสำคัญเมื่อคุณวาดภาพบน ctx คุณไม่สามารถหมุนผืนผ้าใบหลังจากวาดภาพลงไปได้หรือไม่?
AlxVallejo

การหมุนสำหรับการวางแนว 8 ทำงานด้วยวิธีนี้สำหรับฉัน: ctx.transform (0, -1, 1, 0, 0, ความสูง);
Giorgio Barchiesi

24

ตกลงนอกเหนือจาก @ user3096626 คำตอบฉันคิดว่ามันจะมีประโยชน์มากขึ้นถ้ามีคนให้ตัวอย่างรหัสตัวอย่างต่อไปนี้จะแสดงวิธีแก้ไขการวางแนวภาพมาจาก url (ภาพระยะไกล):


โซลูชันที่ 1: ใช้ javascript (แนะนำ)

  1. เนื่องจากไลบรารีโหลดรูปภาพไม่ได้ดึงแท็ก exif จากรูปภาพ url เท่านั้น (ไฟล์ / blob) เราจะใช้ทั้งไลบรารีexif-jsและไลบรารี JavaScript ภาพโหลดรูปภาพดังนั้นก่อนเพิ่มไลบรารีเหล่านี้ในหน้าของคุณดังนี้:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.1.0/exif.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image-scale.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-load-image/2.12.2/load-image-orientation.min.js"></script>

    โปรดทราบว่า exif-js รุ่น 2.2 ดูเหมือนว่ามีปัญหาดังนั้นเราจึงใช้ 2.1

  2. ถ้าอย่างนั้นสิ่งที่เราจะทำก็คือ

    - โหลดภาพโดยใช้ window.loadImage()

    b - อ่านแท็ก exif โดยใช้ window.EXIF.getData()

    c - แปลงภาพเป็นผืนผ้าใบและแก้ไขการวางแนวภาพโดยใช้ window.loadImage.scale()

    d - วางผืนผ้าใบลงในเอกสาร

ไปเลย :)

window.loadImage("/your-image.jpg", function (img) {
  if (img.type === "error") {
    console.log("couldn't load image:", img);
  } else {
    window.EXIF.getData(img, function () {
        var orientation = EXIF.getTag(this, "Orientation");
        var canvas = window.loadImage.scale(img, {orientation: orientation || 0, canvas: true});
        document.getElementById("container").appendChild(canvas); 
        // or using jquery $("#container").append(canvas);

    });
  }
});

แน่นอนคุณยังสามารถรับภาพเป็น base64 จากวัตถุ Canvas และวางไว้ในแอตทริบิวต์ img src ดังนั้นการใช้ jQuery คุณสามารถทำได้;)

$("#my-image").attr("src",canvas.toDataURL());

นี่คือรหัสเต็มเมื่อ: github: https://github.com/digital-flowers/loadimage-exif-example


โซลูชันที่ 2: ใช้ html (เบราว์เซอร์แฮ็ค)

มีการแฮ็กที่ง่ายและรวดเร็วเบราว์เซอร์ส่วนใหญ่จะแสดงภาพในทิศทางที่ถูกต้องหากรูปภาพนั้นเปิดในแท็บใหม่โดยตรงโดยไม่ต้องมี HTML (ฮ่า ๆ ฉันไม่รู้ว่าทำไม) ดังนั้นโดยทั่วไปคุณสามารถแสดงภาพของคุณโดยใช้ iframe โดยใส่แอตทริบิวต์ iframe src เป็น URL ของภาพโดยตรง:

<iframe src="/my-image.jpg"></iframe>

โซลูชันที่ 3: ใช้ css (เฉพาะ firefox & safari บน ios)

มีแอตทริบิวต์ css3 เพื่อแก้ไขการวางแนวภาพ แต่ปัญหามันทำงานเฉพาะกับ firefox และ safari / ios เท่านั้นยังคงมีการกล่าวถึงเพราะเร็ว ๆ นี้เบราว์เซอร์ทั้งหมดจะสามารถใช้งานได้ (ข้อมูลการสนับสนุนเบราว์เซอร์จากcaniuse )

img {
   image-orientation: from-image;
}

โซลูชันที่ 1 ไม่ทำงานสำหรับฉัน มันกลับมา window.loadImage ไม่ได้ถูกกำหนด
Perry

สิ่งนี้เกิดขึ้นหากคุณไม่ได้รวมห้องสมุดที่ฉันพูดถึงในขั้นตอนที่ 1
Fareed Alnamrouti

ฉันรวมห้องสมุด ฉันชอบความเรียบง่ายของตัวอย่างของคุณ แต่ฉันได้รับข้อความแสดงข้อผิดพลาดต่อไป
เพอร์รี

1
ดูเหมือนว่า exif-js เสียหายโปรดตรวจสอบการแก้ไขของฉันฉันได้เพิ่มรหัสเต็มใน github: github.com/digital-flowers/loadimage-exif-example
Fareed Alnamrouti

1
ตกลงชำระเงินโครงการ github มีไฟล์ใหม่ "upload.html" ยินดีต้อนรับ :)
Fareed Alnamrouti

10

สำหรับผู้ที่มีไฟล์จากการควบคุมการป้อนข้อมูลไม่ทราบว่ามันคือการวางแนวเป็นบิตขี้เกียจและไม่ต้องการที่จะรวมห้องสมุดขนาดใหญ่ด้านล่างเป็นรหัสที่ @WunderBart ให้มาด้วยคำตอบที่เขาเชื่อมโยงไปยัง ( https://stackoverflow.com/a/32490603 ) ที่ค้นหาการวางแนว

function getDataUrl(file, callback2) {
        var callback = function (srcOrientation) {
            var reader2 = new FileReader();
            reader2.onload = function (e) {
                var srcBase64 = e.target.result;
                var img = new Image();

                img.onload = function () {
                    var width = img.width,
                        height = img.height,
                        canvas = document.createElement('canvas'),
                        ctx = canvas.getContext("2d");

                    // set proper canvas dimensions before transform & export
                    if (4 < srcOrientation && srcOrientation < 9) {
                        canvas.width = height;
                        canvas.height = width;
                    } else {
                        canvas.width = width;
                        canvas.height = height;
                    }

                    // transform context before drawing image
                    switch (srcOrientation) {
                        case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
                        case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
                        case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
                        case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
                        case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
                        case 7: ctx.transform(0, -1, -1, 0, height, width); break;
                        case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
                        default: break;
                    }

                    // draw image
                    ctx.drawImage(img, 0, 0);

                    // export base64
                    callback2(canvas.toDataURL());
                };

                img.src = srcBase64;
            }

            reader2.readAsDataURL(file);
        }

        var reader = new FileReader();
        reader.onload = function (e) {

            var view = new DataView(e.target.result);
            if (view.getUint16(0, false) != 0xFFD8) return callback(-2);
            var length = view.byteLength, offset = 2;
            while (offset < length) {
                var marker = view.getUint16(offset, false);
                offset += 2;
                if (marker == 0xFFE1) {
                    if (view.getUint32(offset += 2, false) != 0x45786966) return callback(-1);
                    var little = view.getUint16(offset += 6, false) == 0x4949;
                    offset += view.getUint32(offset + 4, little);
                    var tags = view.getUint16(offset, little);
                    offset += 2;
                    for (var i = 0; i < tags; i++)
                        if (view.getUint16(offset + (i * 12), little) == 0x0112)
                            return callback(view.getUint16(offset + (i * 12) + 8, little));
                }
                else if ((marker & 0xFF00) != 0xFF00) break;
                else offset += view.getUint16(offset, false);
            }
            return callback(-1);
        };
        reader.readAsArrayBuffer(file);
    }

ซึ่งสามารถเรียกได้ง่ายเช่นนี้

getDataUrl(input.files[0], function (imgBase64) {
      vm.user.BioPhoto = imgBase64;
});

2
ขอบคุณหลังจากการค้นหามากกว่า 2 ชั่วโมงโดย google ฉันพบทางออกที่ถูกต้อง
Mr.Trieu

2
เหตุใดบางคนจึงขี้เกียจเลือกโซลูชันที่เบากว่า
น้ำค้าง

4
พอร์ตไปยัง typescript และปรับให้เหมาะสมจากประมาณ 4 วินาทีถึง ~ 20 มิลลิวินาที การเข้ารหัส Base64 เป็นคอขวด - ใช้image/jpegแทนค่าเริ่มต้นimage/pngและการปรับขนาดภาพออกเป็นความกว้างสูงสุด (400px ในกรณีของฉัน) สร้างความแตกต่างอย่างมาก (วิธีนี้ใช้งานได้ดีสำหรับรูปขนาดย่อ แต่ถ้าคุณต้องแสดงภาพเต็มฉันแนะนำให้หลีกเลี่ยง base64 และเพียงแค่ใส่องค์ประกอบของผืนผ้าใบลงในหน้า ... )
mindplay.dk

8

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

รวบรวมข้อมูลทั้งหมดจาก wunderbart ด้วยกันบางอย่างเช่นนี้

var handleTakePhoto = function () {
    let fileInput: HTMLInputElement = <HTMLInputElement>document.getElementById('photoInput');
    fileInput.addEventListener('change', (e: any) => handleInputUpdated(fileInput, e.target.files));
    fileInput.click();
}

var handleInputUpdated = function (fileInput: HTMLInputElement, fileList) {
    let file = null;

    if (fileList.length > 0 && fileList[0].type.match(/^image\//)) {
        isLoading(true);
        file = fileList[0];
        getOrientation(file, function (orientation) {
            if (orientation == 1) {
                imageBinary(URL.createObjectURL(file));
                isLoading(false);
            }
            else 
            {
                resetOrientation(URL.createObjectURL(file), orientation, function (resetBase64Image) {
                    imageBinary(resetBase64Image);
                    isLoading(false);
                });
            }
        });
    }

    fileInput.removeEventListener('change');
}


// from http://stackoverflow.com/a/32490603
export function getOrientation(file, callback) {
    var reader = new FileReader();

    reader.onload = function (event: any) {
        var view = new DataView(event.target.result);

        if (view.getUint16(0, false) != 0xFFD8) return callback(-2);

        var length = view.byteLength,
            offset = 2;

        while (offset < length) {
            var marker = view.getUint16(offset, false);
            offset += 2;

            if (marker == 0xFFE1) {
                if (view.getUint32(offset += 2, false) != 0x45786966) {
                    return callback(-1);
                }
                var little = view.getUint16(offset += 6, false) == 0x4949;
                offset += view.getUint32(offset + 4, little);
                var tags = view.getUint16(offset, little);
                offset += 2;

                for (var i = 0; i < tags; i++)
                    if (view.getUint16(offset + (i * 12), little) == 0x0112)
                        return callback(view.getUint16(offset + (i * 12) + 8, little));
            }
            else if ((marker & 0xFF00) != 0xFF00) break;
            else offset += view.getUint16(offset, false);
        }
        return callback(-1);
    };

    reader.readAsArrayBuffer(file.slice(0, 64 * 1024));
};

export function resetOrientation(srcBase64, srcOrientation, callback) {
    var img = new Image();

    img.onload = function () {
        var width = img.width,
            height = img.height,
            canvas = document.createElement('canvas'),
            ctx = canvas.getContext("2d");

        // set proper canvas dimensions before transform & export
        if (4 < srcOrientation && srcOrientation < 9) {
            canvas.width = height;
            canvas.height = width;
        } else {
            canvas.width = width;
            canvas.height = height;
        }

        // transform context before drawing image
        switch (srcOrientation) {
            case 2: ctx.transform(-1, 0, 0, 1, width, 0); break;
            case 3: ctx.transform(-1, 0, 0, -1, width, height); break;
            case 4: ctx.transform(1, 0, 0, -1, 0, height); break;
            case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
            case 6: ctx.transform(0, 1, -1, 0, height, 0); break;
            case 7: ctx.transform(0, -1, -1, 0, height, width); break;
            case 8: ctx.transform(0, -1, 1, 0, 0, width); break;
            default: break;
        }

        // draw image
        ctx.drawImage(img, 0, 0);

        // export base64
        callback(canvas.toDataURL());
    };

    img.src = srcBase64;
}

1
วิธีการที่ยอดเยี่ยม คุณควรพิจารณาจัดการ-2และ-1ส่งคืนจากgetOrientationดังนั้นคุณจะไม่พยายามหมุน non-jpgs หรือรูปภาพโดยไม่มีข้อมูลการหมุน
Steven Lambert

ฉันทำการเพิ่มประสิทธิภาพมากขึ้นดูความคิดเห็นของฉันด้านบน - ฉันเพิ่งเพิ่มการเพิ่มfile.slice()ประสิทธิภาพของคุณเช่นกัน แต่การเพิ่มประสิทธิภาพที่แท้จริงมาจากการใช้รูปภาพขนาดเล็กและimage/jpegรูปแบบผลลัพธ์เพื่อสร้าง URL ข้อมูลที่เล็กลง (ไม่มีการหน่วงเวลาที่เห็นได้ชัดเจนแม้กระทั่งภาพขนาด 10 ล้านพิกเซล)
mindplay.dk

ระมัดระวังfile.slice()เพราะคุณจะป้องกันการสนับสนุนแหล่งที่มาของภาพ base64
ทำเครื่องหมาย

ขอบคุณทำเครื่องหมาย - สนใจที่จะให้การแก้ไขสำหรับทางเลือก?
Statler

7

ใครซับหนึ่ง?

ผมยังไม่เห็นใครพูดถึงห้องสมุดbrowser-image-compression มันมีฟังก์ชั่นผู้ช่วยที่สมบูรณ์แบบสำหรับสิ่งนี้

การใช้งาน: const orientation = await imageCompression.getExifOrientation(file)

เป็นเครื่องมือที่มีประโยชน์ในหลาย ๆ ด้านเช่นกัน


นี่เป็นการวางแนว แต่ฉันจะสร้างออบเจ็กต์ไฟล์. jpg ใหม่ในฝั่งไคลเอ็นต์โดยใช้ข้อมูลนี้ได้อย่างไร
masterxilo

คุณไม่สามารถสร้างFileวัตถุได้เท่าที่ฉันรู้ สิ่งที่ดีที่สุดถัดไปคือการส่งภาพและทิศทางไปยังเซิร์ฟเวอร์และทำการจัดการไฟล์ที่นั่น หรือคุณสามารถสร้างสตริงเบส 64 โดยใช้canvasและtoDataURLวิธีการ
gilbert-v

1
ไม่คุณสามารถสร้างวัตถุไฟล์จาก Blob ได้ ไฟล์ไฟล์ (ส่วนอาร์เรย์, ชื่อไฟล์สตริง, คุณสมบัติ BlobPropertyBag); developer.mozilla.org/de/docs/Web/API/File
masterxilo

2
สติกเกอร์สีทอง! @masterxilo
gilbert-v

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

2

ฉันสร้างคลาสที่รวมอยู่ในโมดูล ES6 ซึ่งแก้ปัญหาตรงนี้ได้

มี 103 บรรทัดไม่มีการขึ้นต่อกันและมีโครงสร้างและการจัดทำเอกสารค่อนข้างดีซึ่งหมายความว่าง่ายต่อการแก้ไข / นำมาใช้ซ้ำ

รองรับการหมุนที่เป็นไปได้ทั้ง 8 แบบและเป็นไปตามสัญญา

ไปเลยหวังว่านี่จะช่วยให้ใครบางคน: https://gist.github.com/vdavid/3f9b66b60f52204317a4cc0e77097913


1

ฉันกำลังใช้โซลูชันผสม (php + css)

ภาชนะบรรจุที่จำเป็นสำหรับ:

  • div.imgCont2 ภาชนะที่จำเป็นในการหมุน;
  • div.imgCont1ภาชนะที่จำเป็นในการซูมออก - width:150%;
  • div.imgCont ภาชนะที่จำเป็นสำหรับแถบเลื่อนเมื่อภาพเป็น zoomOut

.

<?php
    $image_url = 'your image url.jpg';
    $exif = @exif_read_data($image_url,0,true);
    $orientation = @$exif['IFD0']['Orientation'];
?>

<style>
.imgCont{
    width:100%;
    overflow:auto;
}
.imgCont2[data-orientation="8"]{
    transform:rotate(270deg);
    margin:15% 0;
}
.imgCont2[data-orientation="6"]{
    transform:rotate(90deg);
    margin:15% 0;
}
.imgCont2[data-orientation="3"]{
    transform:rotate(180deg);
}
img{
    width:100%;
}
</style>

<div class="imgCont">
  <div class="imgCont1">
    <div class="imgCont2" data-orientation="<?php echo($orientation) ?>">
      <img src="<?php echo($image_url) ?>">
    </div>
  </div>
</div>

ขอบคุณดูเหมือนว่าทางออกที่ดีที่สุดสำหรับความต้องการของฉันต่อไป ไม่จำเป็นสำหรับไลบรารี่ภายนอกและไม่มีโค้ดที่ไม่จำเป็นจำนวนมาก เพียงแค่กำหนดทิศทางจาก exif ด้วย php ส่งไปที่มุมมองและใช้เพื่อเรียกคลาส CSS ที่หมุนตามจำนวนองศาที่เหมาะสม ดีและสะอาด! แก้ไข: นี่จะเป็นการหมุนรูปภาพในเบราว์เซอร์ที่อ่านข้อมูล exif และหมุนตามนั้น AKA จะแก้ไขปัญหาบนเดสก์ท็อป แต่สร้างใหม่บน ios safari
cwal

0

นอกจากคำตอบ @fareed namrouti แล้ว

ควรใช้สิ่งนี้หากรูปภาพจำเป็นต้องเรียกดูจากองค์ประกอบอินพุตไฟล์

<input type="file" name="file" id="file-input"><br/>
image after transform: <br/>
<div id="container"></div>

<script>
    document.getElementById('file-input').onchange = function (e) {
        var image = e.target.files[0];
        window.loadImage(image, function (img) {
            if (img.type === "error") {
                console.log("couldn't load image:", img);
            } else {
                window.EXIF.getData(image, function () {
                    console.log("load image done!");
                    var orientation = window.EXIF.getTag(this, "Orientation");
                    var canvas = window.loadImage.scale(img,
                        {orientation: orientation || 0, canvas: true, maxWidth: 200});
                    document.getElementById("container").appendChild(canvas);
                    // or using jquery $("#container").append(canvas);
                });
            }
        });
    };
</script>

0

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

<?php

header("Content-type: image/jpeg");
$img = 'IMG URL';

$exif = @exif_read_data($img,0,true);
$orientation = @$exif['IFD0']['Orientation'];
if($orientation == 7 || $orientation == 8) {
    $degrees = 90;
} elseif($orientation == 5 || $orientation == 6) {
    $degrees = 270;
} elseif($orientation == 3 || $orientation == 4) {
    $degrees = 180;
} else {
    $degrees = 0;
}
$rotate = imagerotate(imagecreatefromjpeg($img), $degrees, 0);
imagejpeg($rotate);
imagedestroy($rotate);

?>

ไชโย

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