ক্লায়েন্টের পাশে জাভাস্ক্রিপ্টে জেপিইজি এক্সআইএফ রোটেশন ডেটা অ্যাক্সেস করা


125

আমি জেপিইজি EXIF ​​চিত্রের ডেটাতে ক্যামেরার দ্বারা সেট করা ফটোগুলি তাদের মূল ঘূর্ণনের উপর ভিত্তি করে ঘোরানো চাই। কৌশলটি হ'ল জাভাস্ক্রিপ্ট এবং ব্যবহার করে ব্রাউজারে এই সমস্ত হওয়া উচিত <canvas>

ঘূর্ণন সম্পর্কিত তথ্য পড়ার জন্য কীভাবে জাভাস্ক্রিপ্ট JPEG, স্থানীয় ফাইল এপিআই আইজেক্ট, স্থানীয় <img>বা দূরবর্তী <img>, এক্সআইএফ ডেটা অ্যাক্সেস করতে পারে ?

সার্ভার-পাশের উত্তরগুলি ঠিক নেই; আমি ক্লায়েন্ট-সাইড সলিউশন খুঁজছি ।

উত্তর:


261

আপনি যদি কেবল ওরিয়েন্টেশন ট্যাগ এবং অন্য কিছু চান না এবং অন্য একটি বিশাল জাভাস্ক্রিপ্ট লাইব্রেরি অন্তর্ভুক্ত করতে চান না তবে আমি একটি ছোট্ট কোড লিখেছি যা ওরিয়েন্টেশন ট্যাগটি যত তাড়াতাড়ি এক্সট্রাক্ট করে তোলে (এটি ডেটাভিউ ব্যবহার করে readAsArrayBufferযা আই 10 + এ উপলব্ধ, তবে আপনি লিখতে পারেন পুরানো ব্রাউজারগুলির জন্য আপনার নিজস্ব ডেটা রিডার):

function getOrientation(file, callback) {
    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) 
        {
            if (view.getUint16(offset+2, false) <= 8) return callback(-1);
            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);
}

// usage:
var input = document.getElementById('input');
input.onchange = function(e) {
    getOrientation(input.files[0], function(orientation) {
        alert('orientation: ' + orientation);
    });
}
<input id='input' type='file' />

মান:

-2: not jpeg
-1: not defined

এখানে চিত্র বর্ণনা লিখুন

যারা টাইপস্ক্রিপ্ট ব্যবহার করছেন তাদের জন্য আপনি নিম্নলিখিত কোডটি ব্যবহার করতে পারেন:

export const getOrientation = (file: File, callback: Function) => {
  var reader = new FileReader();

  reader.onload = (event: ProgressEvent) => {

    if (! event.target) {
      return;
    }

    const file = event.target as FileReader;
    const view = new DataView(file.result as ArrayBuffer);

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

    const length = view.byteLength
    let offset = 2;

    while (offset < length)
    {
        if (view.getUint16(offset+2, false) <= 8) return callback(-1);
        let marker = view.getUint16(offset, false);
        offset += 2;

        if (marker == 0xFFE1) {
          if (view.getUint32(offset += 2, false) != 0x45786966) {
            return callback(-1);
          }

          let little = view.getUint16(offset += 6, false) == 0x4949;
          offset += view.getUint32(offset + 4, little);
          let tags = view.getUint16(offset, little);
          offset += 2;
          for (let 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);
}

2,4,5,7 এর জন্য সঠিক চিত্র পেতে আপনার ঘোরানো এবং ফ্লিপ করতে হবে, তাই না?
মুহাম্মদ উমার

আমার চিত্রটির ওরিয়েন্টেশনটি ৩. আমি কীভাবে ওরিয়েন্টেশনটি 1 এ সেট করব?
লুসি

3
@Mick PNG বা GIF দোকান ইমেজ অভিযোজন কোনো প্রমিত বিন্যাস হবে না stackoverflow.com/questions/9542359/...
আলী

2
আমার পক্ষে কাজ করা, তবে আমার শেষ পংক্তিকে কেবল পাঠক.প্রেমআডআআআরআরফার (ফাইল) এ পরিবর্তন করা দরকার; আমার বেস 64 ইমেজের জন্য বাফারটি ব্যবহার করার ইচ্ছা হিসাবে আমি স্লাইস ছাড়াই অন্যথায়, আপনি কেবল চিত্রটির প্রথম স্লাইসটি দেখতে পাবেন। বিটিডাব্লু, আপনার যদি কেবল ওরিয়েন্টেশন সম্পর্কিত তথ্য প্রয়োজন হয় তবে এটির প্রয়োজন হয় না। ধন্যবাদ
ফিলিপ মারফি

2
@ দারাজাভা আমি স্লাইস অংশটি সরিয়ে দিয়েছি কারণ মাঝে মধ্যে সীমাবদ্ধতার পরে ট্যাগটি আসে তবে ট্যাগটি কখনও না পেলে এটি অপারেশনকে ধীর করে দেবে। যাইহোক, ওরিয়েন্টেশন ট্যাগের বিপরীতে, ফ্ল্যাশ ট্যাগ আইএফডি0 ডিরেক্টরিতে নেই এবং আমার কোডটি কেবল এই অংশটি অনুসন্ধান করে। ফ্ল্যাশ ট্যাগ পেতে আপনাকে অবশ্যই সাবআইএফডি ডিরেক্টরি অনুসন্ধান করতে হবে। আপনি এখানে এক্সআইএফ
আলী

22

আপনি এইচটিএমএল 5 ফাইল এপিআইয়ের সাথে এক্সেফ-জেএস লাইব্রেরিটি ব্যবহার করতে পারেন : http://jsfiddle.net/xQnMd/1/

$("input").change(function() {
    var file = this.files[0];  // file
        fr   = new FileReader; // to read file contents

    fr.onloadend = function() {
        // get EXIF data
        var exif = EXIF.readFromBinaryFile(new BinaryFile(this.result));

        // alert a value
        alert(exif.Make);
    };

    fr.readAsBinaryString(file); // read the file
});

ধন্যবাদ। প্রশ্নের জেএস লিবটি সামান্য পুরানো দেখায় তবে সম্ভবত এটি কার্যকর হবে।
মিক্কো ওহতামা

আমি সবেমাত্র লিখেছি এমন একটি ফাইল আপলোড উইজেটের আমার ডেমোটিও দেখুন। এটি চিত্রের ফাইলের মেটাডেটাতে এক্সআইএফ ওরিয়েন্টেশন পতাকাটি পড়তে উপরে উল্লিখিত EXIF.js গ্রন্থাগারটি ব্যবহার করে। তথ্যের উপর ভিত্তি করে, এটি একটি ক্যানভাস উপাদান ব্যবহার করে ঘূর্ণনটি প্রয়োগ করে ... স্যান্ডবক্স.জুরলিংক.আর
রব জুউরলিংক

এমনকি আমার প্রকল্পে বাইনারিজ্যাক্স.জেগুলি অন্তর্ভুক্ত করার চেষ্টা করা অ্যাক্সেস অস্বীকারের ত্রুটির কারণ হয়ে দাঁড়ায়।
ওবি ওয়ান

EXIF অবজেক্টটি কোথা থেকে আসে? বাইনারিফাইলে স্ক্রিপ্টটি এটি ধারণ করে বলে মনে হয় না এবং যতদূর আমি বলতে পারি এটি jquery বা আমি নিয়মিত ব্যবহার করি এমন কোনও স্ক্রিপ্টের অংশ নয় ...
জ্রিস্টা

6
লাইব্রেরির ওয়েবসাইটটি নীচে নেমে গেছে বলে মনে হয়েছে এবং আমি খুঁজে পেয়েছি কেবলমাত্র অন্যান্য এক্সিফ্রেডার লাইব্রেরি ব্রাউজার সমর্থনে সীমাবদ্ধ ছিল। কোন ভাল বিকল্প আছে?
প্র্যাক্সিস অ্যাসিলিন

19

ফায়ারফক্স 26 সমর্থন করে image-orientation: from-image: চিত্রগুলি পোর্ট্রেট বা ল্যান্ডস্কেপ প্রদর্শিত হয়, এক্সআইএফ ডেটার উপর নির্ভর করে। ( Sethfowler.org/blog/2013/09/13/new-in-firefox-26-css-image-orientation ।)

ক্রোমে এটি প্রয়োগ করার জন্য একটি বাগও রয়েছে

সাবধান থাকুন যে এই সম্পত্তিটি কেবল ফায়ারফক্স দ্বারা সমর্থিত এবং সম্ভবত হ্রাস পাওয়ার সম্ভাবনা রয়েছে


5
বাগ রিপোর্টের লিঙ্কটির জন্য ধন্যবাদ। আমি এটি তারকাচিহ্নিত করেছি যাতে ক্রোম টিম আরও বেশি লোকেরা এটি জানতে পারে knows
ডেমিইম্প

এই মন্তব্য অনুসারে bugs.chromium.org/p/chromium/issues/detail?id=158753#c104 একটি ক্রোমিয়াম প্রকল্পের সদস্য দ্বারা: "পরিবর্তনটি ক্রোম 81-এ রয়েছে That এটি 8 এ স্থিতিশীল সংস্করণ হিসাবে জনসাধারণের কাছে উপস্থিত হবে will -10 সপ্তাহের সময় "
জেফ ফরেস্ট

1
৮১ starting দিয়ে শুরু হওয়া ক্রোমে প্রয়োগ করা হয়েছে লোকেরা তাদের ব্রাউজার আপডেট করার আগে কিছুটা সময় নেবে
রবিন ম্যাট্রাল

11

https://github.com/blueimp/JavaScript-Load- চিত্র একটি আধুনিক জাভাস্ক্রিপ্ট লাইব্রেরি যা কেবল এক্সিফ ওরিয়েন্টেশন পতাকাটিই বের করতে পারে না - এটি ক্লায়েন্টের পাশে JPEG চিত্রগুলিকে সঠিকভাবে আয়না / ঘোরানোও করতে পারে।

আমি এই লাইব্রেরির সাথে একই সমস্যার সমাধান করেছি: জেএস ক্লায়েন্ট-সাইড এক্সিফ ওরিয়েন্টেশন: ঘোরান এবং মিরর জেপিইজি চিত্রগুলি


4

আপনি যদি ক্রস ব্রাউজারটি চান তবে আপনার সেরা বেটটি এটি সার্ভারে করা। আপনার কাছে এমন একটি API থাকতে পারে যা কোনও ফাইলের ইউআরএল নেয় এবং আপনাকে এক্সআইএফ ডেটা ফেরত দেয়; পিএইচপি এর জন্য একটি মডিউল রয়েছে

এটি অ্যাজাক্স ব্যবহার করে করা যেতে পারে তাই এটি ব্যবহারকারীর পক্ষে নির্বিঘ্ন হতে পারে। যদি আপনি ক্রস ব্রাউজারের সামঞ্জস্যতা সম্পর্কে চিন্তা না করেন এবং HTML5 ফাইলের কার্যকারিতার উপর নির্ভর করতে পারেন তবে JsJPEGmeta লাইব্রেরিটি দেখুন যা আপনাকে সেই জাভাস্ক্রিপ্টে সেই ডেটা পেতে দেয়।


21
@ মিক্কোওহট্টামা: আপনার বুঝতে হবে যে স্ট্যাক ওভারফ্লো সবার জন্য প্রশ্নের উত্তর দেয় , কেবল আসল ব্যক্তি এটি জিজ্ঞাসা করছেন। পরবর্তী ব্যক্তি যার আপনার একই উদ্দেশ্য পিএইচপি বিকাশকারী হতে পারে - আপনি কেন তাদের Xeon06 অন্তর্ভুক্ত তথ্য অস্বীকার করতে চান? আপনি পিএইচপি সমাধান চান না কেবল এই কারণে এটি সম্পাদনা করা অনুচিত ছিল ।
জন স্কিটি

5
প্রশ্নটি "জাভাস্ক্রিপ্টে" বলে তাই অংশটি অপ্রাসঙ্গিক ছিল। ইতিমধ্যে সাইটে পিএইচপি এর জন্য আরও অনেক অনুরূপ প্রশ্ন এবং উত্তর রয়েছে এবং এই প্রশ্নটি সম্পর্কে এটি অপ্রয়োজনীয় গোলমাল।
মিক্কো ওহতামা

2
লোকেরা জাভাস্ক্রিপ্ট সমাধানের জন্য জিজ্ঞাসা করলে তারা পিএইচপি সমাধানটি প্রথম পোস্ট হিসাবে দেখতে চায় না।
মিক্কো ওহতামা

1
@ মিকোওহট্টমাকে এটি আপনার সাথে মেটা.স্ট্যাকেক্সেঞ্জঞ্জ / প্রশ্নগুলি / 157338/… নিয়ে সবচেয়ে বেশি মতবিরোধ বলে মনে হচ্ছে আপনার প্রশ্নগুলির উত্তরের উপর আপনার মালিকানা সম্পর্কে কিছু ভুল ধারণা রয়েছে।
অ্যালেক্স টারপিন

1
আমি শুরুতে সঠিক উত্তর পেতে উত্তরটি সম্পাদনা করেছি। ফাজের জন্য দুঃখিত
মিক্কো ওহতামা

3

আমি লিখেছি এমন একটি মডিউল দেখুন (আপনি এটি ব্রাউজারে ব্যবহার করতে পারেন) যা এক্সিফ ওরিয়েন্টেশনকে সিএসএস রূপান্তর করতে রূপান্তর করে: https://github.com/Sobesednik/exif2css

সমস্ত ওরিয়েন্টেশন সহ জেপিইজি ফিক্সারগুলি তৈরি করার জন্য এই নোড প্রোগ্রামটিও রয়েছে: https://github.com/Sobesednik/generate-exif-fixtures


1
দুর্দান্ত মডিউল! তবে এটি কীভাবে প্রথম স্থানটিতে জেপিজি থেকে এক্সআইএফ তথ্য পাবে?
মিক্কো ওহতামা

@ মিক্কোওহট্টমাকে ধন্যবাদ এবং এটি না, আপনাকে এক্সিফ-জেএস বা এক্সিফ্টোল সার্ভার-সাইড দিয়ে করতে হবে
জাভর

এটি দরকারী। তবে এটি আমার কাছে দেখে মনে হচ্ছে এটি কেবল প্রতিকৃতি ফটোগুলির জন্য সঠিকভাবে কাজ করে, ল্যান্ডস্কেপগুলি নয়।
শ্রীধর সারনোবাত

3

আমি ডান রোটিওন সহ কিছু ইমগ ট্যাগে HTML হিসাবে স্বাভাবিক হিসাবে অ্যান্ড্রয়েড ক্যামেরায় ফটো দেখানোর জন্য প্রসারণ কোড আপলোড করি , বিশেষত ইমগ ট্যাগের জন্য যার প্রস্থ উচ্চতার চেয়ে প্রশস্ত। আমি জানি এই কোডটি কুৎসিত তবে আপনার অন্য কোনও প্যাকেজ ইনস্টল করার দরকার নেই। (আমি এক্সিফ রোটেশন মান পেতে উপরের কোডটি ব্যবহার করেছি, আপনাকে ধন্যবাদ))

function getOrientation(file, callback) {
  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);
}

var isChanged = false;
function rotate(elem, orientation) {
    if (isIPhone()) return;

    var degree = 0;
    switch (orientation) {
        case 1:
            degree = 0;
            break;
        case 2:
            degree = 0;
            break;
        case 3:
            degree = 180;
            break;
        case 4:
            degree = 180;
            break;
        case 5:
            degree = 90;
            break;
        case 6:
            degree = 90;
            break;
        case 7:
            degree = 270;
            break;
        case 8:
            degree = 270;
            break;
    }
    $(elem).css('transform', 'rotate('+ degree +'deg)')
    if(degree == 90 || degree == 270) {
        if (!isChanged) {
            changeWidthAndHeight(elem)
            isChanged = true
        }
    } else if ($(elem).css('height') > $(elem).css('width')) {
        if (!isChanged) {
            changeWidthAndHeightWithOutMargin(elem)
            isChanged = true
        } else if(degree == 180 || degree == 0) {
            changeWidthAndHeightWithOutMargin(elem)
            if (!isChanged)
                isChanged = true
            else
                isChanged = false
        }
    }
}


function changeWidthAndHeight(elem){
    var e = $(elem)
    var width = e.css('width')
    var height = e.css('height')
    e.css('width', height)
    e.css('height', width)
    e.css('margin-top', ((getPxInt(height) - getPxInt(width))/2).toString() + 'px')
    e.css('margin-left', ((getPxInt(width) - getPxInt(height))/2).toString() + 'px')
}

function changeWidthAndHeightWithOutMargin(elem){
    var e = $(elem)
    var width = e.css('width')
    var height = e.css('height')
    e.css('width', height)
    e.css('height', width)
    e.css('margin-top', '0')
    e.css('margin-left', '0')
}

function getPxInt(pxValue) {
    return parseInt(pxValue.trim("px"))
}

function isIPhone(){
    return (
        (navigator.platform.indexOf("iPhone") != -1) ||
        (navigator.platform.indexOf("iPod") != -1)
    );
}

এবং তারপরে যেমন ব্যবহার করুন

$("#banner-img").change(function () {
    var reader = new FileReader();
    getOrientation(this.files[0], function(orientation) {
        rotate($('#banner-img-preview'), orientation, 1)
    });

    reader.onload = function (e) {
        $('#banner-img-preview').attr('src', e.target.result)
        $('#banner-img-preview').css('display', 'inherit')

    };

    // read the image file as a data URL.
    reader.readAsDataURL(this.files[0]);

});

2

প্রথম থেকেই আলীর উত্তরে আরও কার্যকারিতা সংশোধন / যুক্ত করার পরে, আমি টাইপস্ক্রিপ্টে একটি ব্যবহার পদ্ধতি তৈরি করেছি যা এই সমস্যাটির জন্য আমার প্রয়োজন অনুসারে উপযুক্ত। এই সংস্করণটি এমন ডিগ্রিতে ঘূর্ণন দেয় যা আপনার প্রকল্পের জন্যও দরকার হতে পারে।

ImageUtils.ts

/**
 * Based on StackOverflow answer: https://stackoverflow.com/a/32490603
 *
 * @param imageFile The image file to inspect
 * @param onRotationFound callback when the rotation is discovered. Will return 0 if if it fails, otherwise 0, 90, 180, or 270
 */
export function getOrientation(imageFile: File, onRotationFound: (rotationInDegrees: number) => void) {
  const reader = new FileReader();
  reader.onload = (event: ProgressEvent) => {
    if (!event.target) {
      return;
    }

    const innerFile = event.target as FileReader;
    const view = new DataView(innerFile.result as ArrayBuffer);

    if (view.getUint16(0, false) !== 0xffd8) {
      return onRotationFound(convertRotationToDegrees(-2));
    }

    const length = view.byteLength;
    let offset = 2;

    while (offset < length) {
      if (view.getUint16(offset + 2, false) <= 8) {
        return onRotationFound(convertRotationToDegrees(-1));
      }
      const marker = view.getUint16(offset, false);
      offset += 2;

      if (marker === 0xffe1) {
        if (view.getUint32((offset += 2), false) !== 0x45786966) {
          return onRotationFound(convertRotationToDegrees(-1));
        }

        const little = view.getUint16((offset += 6), false) === 0x4949;
        offset += view.getUint32(offset + 4, little);
        const tags = view.getUint16(offset, little);
        offset += 2;
        for (let i = 0; i < tags; i++) {
          if (view.getUint16(offset + i * 12, little) === 0x0112) {
            return onRotationFound(convertRotationToDegrees(view.getUint16(offset + i * 12 + 8, little)));
          }
        }
        // tslint:disable-next-line:no-bitwise
      } else if ((marker & 0xff00) !== 0xff00) {
        break;
      } else {
        offset += view.getUint16(offset, false);
      }
    }
    return onRotationFound(convertRotationToDegrees(-1));
  };
  reader.readAsArrayBuffer(imageFile);
}

/**
 * Based off snippet here: https://github.com/mosch/react-avatar-editor/issues/123#issuecomment-354896008
 * @param rotation converts the int into a degrees rotation.
 */
function convertRotationToDegrees(rotation: number): number {
  let rotationInDegrees = 0;
  switch (rotation) {
    case 8:
      rotationInDegrees = 270;
      break;
    case 6:
      rotationInDegrees = 90;
      break;
    case 3:
      rotationInDegrees = 180;
      break;
    default:
      rotationInDegrees = 0;
  }
  return rotationInDegrees;
}

ব্যবহার:

import { getOrientation } from './ImageUtils';
...
onDrop = (pics: any) => {
  getOrientation(pics[0], rotationInDegrees => {
    this.setState({ image: pics[0], rotate: rotationInDegrees });
  });
};
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.