उपयोगकर्ता से इमेज लेना

ज़्यादातर ब्राउज़र को उपयोगकर्ता के कैमरे का ऐक्सेस मिल सकता है.

मैट स्केल
पॉल किनलन
पॉल किनलन

कई ब्राउज़र में अब उपयोगकर्ता के वीडियो और ऑडियो इनपुट को ऐक्सेस कर सकते हैं. हालांकि, ब्राउज़र के आधार पर यह एक पूरा डाइनैमिक और इनलाइन अनुभव हो सकता है या इसे उपयोगकर्ता के डिवाइस पर किसी दूसरे ऐप्लिकेशन को दिया जा सकता है. सबसे अच्छी बात यह है कि हर डिवाइस में कैमरा नहीं होता. तो ऐसा अनुभव कैसे बनाया जा सकता है जिसमें उपयोगकर्ता की बनाई गई ऐसी इमेज का इस्तेमाल किया गया हो जो हर जगह अच्छी तरह से काम करती हो?

आसान और धीरे-धीरे शुरू करें

अगर आपको अपने अनुभव को धीरे-धीरे बढ़ाना है, तो कुछ ऐसा करें जो हर जगह काम करता हो. सबसे आसान तरीका है, उपयोगकर्ता से पहले से रिकॉर्ड की गई फ़ाइल मांगना.

यूआरएल के लिए अनुरोध करें

यह सबसे अच्छा काम करने वाला विकल्प है, लेकिन सबसे कम संतुष्टि देने वाला विकल्प है. उपयोगकर्ता से यूआरएल मांगें. इसके बाद, उसका इस्तेमाल करें. सिर्फ़ इमेज दिखाने के लिए यह हर जगह काम करता है. कोई img एलिमेंट बनाएं, src सेट करें और आपका काम हो गया.

हालांकि, अगर आपको इमेज में किसी भी तरह से बदलाव करना हो, तो चीज़ें थोड़ी ज़्यादा जटिल होती हैं. सीओआरएस आपको असल पिक्सल ऐक्सेस करने से तब तक रोकता है, जब तक सर्वर सही हेडर सेट नहीं करता और आप इमेज को क्रॉसऑरिजिन के तौर पर मार्क करते हैं. इसके लिए, सिर्फ़ प्रॉक्सी सर्वर को चलाया जा सकता है.

फ़ाइल इनपुट

किसी सामान्य फ़ाइल इनपुट एलिमेंट का भी इस्तेमाल किया जा सकता है. इसमें accept फ़िल्टर भी शामिल है, जो बताता है कि आपको सिर्फ़ इमेज फ़ाइलें चाहिए.

<input type="file" accept="image/*" />

यह तरीका सभी प्लैटफ़ॉर्म पर काम करता है. डेस्कटॉप पर, यह उपयोगकर्ता से फ़ाइल सिस्टम से एक इमेज फ़ाइल अपलोड करने के लिए कहेगा. iOS और Android पर Chrome और Safari में इस तरीके से उपयोगकर्ता को यह चुनने की सुविधा मिलती है कि वह इमेज कैप्चर करने के लिए किस ऐप्लिकेशन का इस्तेमाल करे. इसमें, सीधे कैमरे से फ़ोटो लेने या मौजूदा इमेज फ़ाइल चुनने का विकल्प भी शामिल है.

एक Android मेन्यू, जिसमें दो विकल्प हैं: इमेज और फ़ाइलें कैप्चर करें iOS मेन्यू, जिसमें तीन विकल्प हैं: फ़ोटो लें, फ़ोटो लाइब्रेरी, iCloud

इसके बाद, डेटा को <form> से जोड़ा जा सकता है या इनपुट एलिमेंट पर onchange इवेंट को सुनकर और फिर इवेंट target की files प्रॉपर्टी को पढ़कर JavaScript की मदद से उसमें बदलाव किया जा सकता है.

<input type="file" accept="image/*" id="file-input" />
<script>
  const fileInput = document.getElementById('file-input');

  fileInput.addEventListener('change', (e) =>
    doSomethingWithFiles(e.target.files),
  );
</script>

files प्रॉपर्टी एक FileList ऑब्जेक्ट है, जिसके बारे में मैं बाद में और बात करूंगी.

विकल्प के तौर पर, capture एट्रिब्यूट को एलिमेंट में भी जोड़ा जा सकता है. इससे, ब्राउज़र को पता चलता है कि कैमरे से इमेज लेना पसंद किया जा रहा है.

<input type="file" accept="image/*" capture />
<input type="file" accept="image/*" capture="user" />
<input type="file" accept="image/*" capture="environment" />

capture एट्रिब्यूट को बिना वैल्यू के जोड़ने से ब्राउज़र तय करता है कि कौनसा कैमरा इस्तेमाल करना है, जबकि "user" और "environment" वैल्यू से ब्राउज़र को यह पता चलता है कि सामने और पीछे के कैमरे को प्राथमिकता देनी है या नहीं.

capture एट्रिब्यूट, Android और iOS पर काम करता है, लेकिन डेस्कटॉप पर इसे अनदेखा कर दिया जाता है. हालाँकि, ध्यान रखें कि Android पर इसका मतलब है कि उपयोगकर्ता के पास मौजूदा तस्वीर चुनने का विकल्प नहीं होगा. इसके बजाय, सिस्टम कैमरा ऐप्लिकेशन सीधे चालू हो जाएगा.

खींचें और छोड़ें

अगर फ़ाइल को अपलोड करने की सुविधा पहले से ही जोड़ी जा रही है, तो यहां कुछ ऐसे आसान तरीके दिए गए हैं जिन्हें अपनाकर, उपयोगकर्ता अनुभव को बेहतर बनाया जा सकता है.

पहला तरीका है, अपने पेज पर ड्रॉप टारगेट जोड़ना. इससे उपयोगकर्ता, फ़ाइल को डेस्कटॉप या किसी दूसरे ऐप्लिकेशन से खींचकर ले जा सकता है.

<div id="target">You can drag an image file here</div>
<script>
  const target = document.getElementById('target');

  target.addEventListener('drop', (e) => {
    e.stopPropagation();
    e.preventDefault();

    doSomethingWithFiles(e.dataTransfer.files);
  });

  target.addEventListener('dragover', (e) => {
    e.stopPropagation();
    e.preventDefault();

    e.dataTransfer.dropEffect = 'copy';
  });
</script>

फ़ाइल इनपुट की तरह ही, आपको drop इवेंट की dataTransfer.files प्रॉपर्टी से, FileList ऑब्जेक्ट मिल सकता है;

dragover इवेंट हैंडलर की मदद से, उपयोगकर्ता को यह सिग्नल दिया जा सकता है कि dropEffect प्रॉपर्टी का इस्तेमाल करके, फ़ाइल छोड़ने पर क्या होगा.

'खींचें और छोड़ें' सुविधा लंबे समय से उपलब्ध है और मुख्य ब्राउज़र में यह सुविधा काम करती है.

क्लिपबोर्ड से पेस्ट करें

किसी मौजूदा इमेज फ़ाइल को पाने का आखिरी तरीका, क्लिपबोर्ड से है. इसका कोड बहुत आसान है, लेकिन उपयोगकर्ता अनुभव को सही से समझना थोड़ा मुश्किल है.

<textarea id="target">Paste an image here</textarea>
<script>
  const target = document.getElementById('target');

  target.addEventListener('paste', (e) => {
    e.preventDefault();
    doSomethingWithFiles(e.clipboardData.files);
  });
</script>

(e.clipboardData.files अभी तक एक और FileList ऑब्जेक्ट है.)

क्लिपबोर्ड एपीआई की मुश्किल बात यह है कि पूरे क्रॉस-ब्राउज़र सपोर्ट के लिए, टारगेट एलिमेंट को चुनने लायक और उसमें बदलाव करने लायक होना चाहिए. <textarea> और <input type="text">, दोनों यहां बिल में फ़िट होते हैं, जैसा कि contenteditable एट्रिब्यूट वाले एलिमेंट में किया जाता है. हालांकि, इन्हें टेक्स्ट में बदलाव करने के लिए भी डिज़ाइन किया गया है.

अगर आप नहीं चाहते कि लोग टेक्स्ट इनपुट कर पाएं, तो यह काम आसानी से किया जा सकता है. छिपा हुआ इनपुट होने जैसी तरकीबें, किसी दूसरे एलिमेंट पर क्लिक करने पर चुन ली जाती हैं. इससे सुलभता को बनाए रखना मुश्किल हो सकता है.

FileList ऑब्जेक्ट को मैनेज करना

ऊपर दिए गए ज़्यादातर तरीकों से FileList मिलता है. इसलिए, मुझे इसके बारे में बात करनी चाहिए.

FileList, Array से मिलता-जुलता है. इसमें अंकों वाली कुंजियां और एक length प्रॉपर्टी है, लेकिन असल में यह कोई कलेक्शन नहीं है. forEach() या pop() जैसा कोई कलेक्शन मेथड नहीं है. साथ ही, इसे दोहराया नहीं जा सकता. बिलकुल, Array.from(fileList) का इस्तेमाल करके आप असली अरे पा सकते हैं.

FileList की एंट्री, File ऑब्जेक्ट हैं. ये Blob ऑब्जेक्ट की तरह ही होते हैं. हालांकि, इसमें name और lastModified रीड ओनली प्रॉपर्टी हैं.

<img id="output" />
<script>
  const output = document.getElementById('output');

  function doSomethingWithFiles(fileList) {
    let file = null;

    for (let i = 0; i < fileList.length; i++) {
      if (fileList[i].type.match(/^image\//)) {
        file = fileList[i];
        break;
      }
    }

    if (file !== null) {
      output.src = URL.createObjectURL(file);
    }
  }
</script>

इस उदाहरण में ऐसी पहली फ़ाइल खोजी गई है जिसमें इमेज का MIME टाइप है. हालांकि, यह एक साथ कई इमेज को चुनने/चिपकाने/छोड़ने की प्रोसेस को भी हैंडल कर सकता है.

फ़ाइल का ऐक्सेस मिलने के बाद, उसके साथ कुछ भी किया जा सकता है. उदाहरण के लिए, आपके पास ये काम करने की सुविधा होती है:

  • इसे किसी <canvas> एलिमेंट में ड्रॉ करें, ताकि आप इसमें बदलाव कर सकें
  • इसे उपयोगकर्ता के डिवाइस पर डाउनलोड करें
  • इसे fetch() वाले सर्वर पर अपलोड करें

कैमरे को इंटरैक्टिव तरीके से ऐक्सेस करें

आपने अपने बेस को कवर कर लिया है. अब समय है कि आप और बेहतर करें!

मॉडर्न ब्राउज़र में कैमरा ऐक्सेस करने की सुविधा सीधे तौर पर मिल सकती है. इससे, ऐसे अनुभव बनाए जा सकते हैं जो वेब पेज के साथ पूरी तरह इंटिग्रेट किए गए हों. साथ ही, इनके लिए उपयोगकर्ता को ब्राउज़र से बाहर निकलने की ज़रूरत नहीं होती.

कैमरे का ऐक्सेस पाएं

आपके पास WebRTC की जानकारी में मौजूद getUserMedia() एपीआई का इस्तेमाल करके, कैमरा और माइक्रोफ़ोन को सीधे ऐक्सेस करने का विकल्प होता है. इससे उपयोगकर्ता को, कनेक्ट किए गए माइक्रोफ़ोन और कैमरे का ऐक्सेस पाने का निर्देश मिलेगा.

getUserMedia() के लिए सहायता बहुत अच्छी है, लेकिन अभी यह सुविधा हर जगह उपलब्ध नहीं है. खास तौर पर, यह Safari 10 या इससे पहले के वर्शन में उपलब्ध नहीं है, जो कि लिखते समय अभी भी सबसे नया और स्थिर वर्शन है. हालांकि, Apple ने एलान किया है कि यह Safari 11 में उपलब्ध होगा.

हालांकि, उपलब्ध सहायता का पता लगाना बहुत आसान है.

const supported = 'mediaDevices' in navigator;

getUserMedia() को कॉल करते समय, आपको एक ऑब्जेक्ट पास करना होगा, जो यह बताए कि आपको किस तरह का मीडिया चाहिए. इन विकल्पों को कंस्ट्रेंट कहा जाता है. इसमें कई तरह की रुकावटें हो सकती हैं. जैसे, आपको सामने का कैमरा पसंद है या पीछे का कैमरा, आपको ऑडियो की ज़रूरत है या नहीं, और स्ट्रीम के लिए आपका पसंदीदा रिज़ॉल्यूशन क्या है.

कैमरे से डेटा पाने के लिए, आपको सिर्फ़ एक कंस्ट्रेंट की ज़रूरत होगी और वह है video: true.

अगर एपीआई सही से काम करता है, तो MediaStream, जिसमें कैमरे का डेटा होगा. इसके बाद, इसे <video> एलिमेंट से अटैच करके, रीयल-टाइम झलक दिखाने के लिए इसे चलाया जा सकता है या स्नैपशॉट पाने के लिए, इसे <canvas> से अटैच किया जा सकता है.

<video id="player" controls autoplay></video>
<script>
  const player = document.getElementById('player');

  const constraints = {
    video: true,
  };

  navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
    player.srcObject = stream;
  });
</script>

अपने-आप में, यह उतना काम का नहीं है. बस वीडियो का डेटा लेकर, उसे फिर से चलाएं. अगर आपको इमेज चाहिए, तो आपको कुछ और काम करना होगा.

स्नैपशॉट लें

इमेज पाने का सबसे अच्छा तरीका यह है कि वीडियो से कैनवस पर एक फ़्रेम बनाएं.

Web Audio API के उलट, वेब पर वीडियो देखने के लिए कोई खास स्ट्रीम प्रोसेसिंग एपीआई नहीं होता. इसलिए, उपयोगकर्ता के कैमरे से स्नैपशॉट लेने के लिए आपको थोड़ी हैकरी का सहारा लेना पड़ता है.

इसकी प्रोसेस यहां दी गई है:

  1. ऐसा कैनवस ऑब्जेक्ट बनाएं जो कैमरे से फ़्रेम को होल्ड कर सके
  2. कैमरे की स्ट्रीम का ऐक्सेस पाना
  3. इसे किसी वीडियो एलिमेंट से अटैच करें
  4. अगर आपको सटीक फ़्रेम कैप्चर करना है, तो drawImage() का इस्तेमाल करके, वीडियो एलिमेंट से कैनवस ऑब्जेक्ट में डेटा जोड़ें.
<video id="player" controls autoplay></video>
<button id="capture">Capture</button>
<canvas id="canvas" width="320" height="240"></canvas>
<script>
  const player = document.getElementById('player');
  const canvas = document.getElementById('canvas');
  const context = canvas.getContext('2d');
  const captureButton = document.getElementById('capture');

  const constraints = {
    video: true,
  };

  captureButton.addEventListener('click', () => {
    // Draw the video frame to the canvas.
    context.drawImage(player, 0, 0, canvas.width, canvas.height);
  });

  // Attach the video stream to the video element and autoplay.
  navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
    player.srcObject = stream;
  });
</script>

जब आपके पास कैनवस में डेटा संग्रहित हो जाता है, तब आप उससे कई काम कर सकते हैं. इसके लिए, ये काम किए जा सकते हैं:

  • इसे सीधे सर्वर पर अपलोड करें
  • इसे स्थानीय रूप से सेव करें
  • इमेज में फ़ंकी इफ़ेक्ट लगाएं

सलाह

ज़रूरत न होने पर कैमरे से स्ट्रीमिंग बंद करना

जब आपको कैमरे की ज़रूरत न हो, तब इसका इस्तेमाल बंद कर दें. इससे न सिर्फ़ बैटरी और प्रोसेसिंग पावर बचेगा, बल्कि उपयोगकर्ता आपके ऐप्लिकेशन पर भरोसा भी कर सकेंगे.

कैमरे का ऐक्सेस बंद करने के लिए, getUserMedia() से मिलने वाली स्ट्रीम के लिए, हर वीडियो ट्रैक पर stop() को कॉल करें.

<video id="player" controls autoplay></video>
<button id="capture">Capture</button>
<canvas id="canvas" width="320" height="240"></canvas>
<script>
  const player = document.getElementById('player');
  const canvas = document.getElementById('canvas');
  const context = canvas.getContext('2d');
  const captureButton = document.getElementById('capture');

  const constraints = {
    video: true,
  };

  captureButton.addEventListener('click', () => {
    context.drawImage(player, 0, 0, canvas.width, canvas.height);

    // Stop all video streams.
    player.srcObject.getVideoTracks().forEach(track => track.stop());
  });

  navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
    // Attach the video stream to the video element and autoplay.
    player.srcObject = stream;
  });
</script>

कैमरे का ज़िम्मेदारी से इस्तेमाल करने के लिए, अनुमति मांगें

अगर उपयोगकर्ता ने पहले आपकी साइट को कैमरे का ऐक्सेस नहीं दिया है, तो जैसे ही आप getUserMedia() पर कॉल करेंगे, ब्राउज़र, उपयोगकर्ता से आपकी साइट को कैमरे के लिए अनुमति देने का अनुरोध करेगा.

उपयोगकर्ताओं को अपनी मशीन पर असरदार डिवाइसों का ऐक्सेस पाने के लिए, अनुरोध नहीं मिलता है. वे अक्सर उस अनुरोध को ब्लॉक कर देते हैं. इसके अलावा, अगर उन्हें यह पता नहीं चलता है कि प्रॉम्प्ट किस संदर्भ के लिए बनाया गया है, तो वे उस अनुरोध को अनदेखा कर देंगे. सबसे सही तरीका यह है कि ज़रूरत पड़ने पर ही कैमरा ऐक्सेस करने के लिए कहा जाए. उपयोगकर्ता से ऐक्सेस देने के बाद, उससे दोबारा ऐक्सेस नहीं मांगा जाएगा. हालांकि, अगर उपयोगकर्ता ऐक्सेस अस्वीकार कर देता है, तो आपको फिर से ऐक्सेस नहीं मिलेगा. बशर्ते, वह व्यक्ति कैमरे की अनुमति की सेटिंग को मैन्युअल तरीके से न बदले.

इनके साथ काम करता है

मोबाइल और डेस्कटॉप ब्राउज़र लागू करने के बारे में ज़्यादा जानकारी:

हम WebRTC की खास जानकारी में होने वाले बदलावों और प्रीफ़िक्स के अंतर से ऐप्लिकेशन को सुरक्षित रखने के लिए, adapter.js शिम का इस्तेमाल करने का भी सुझाव देते हैं.

सुझाव/राय दें या शिकायत करें