ज़्यादातर ब्राउज़र में उपयोगकर्ता के कैमरे का ऐक्सेस मिल सकता है.
कई ब्राउज़र में अब लोग, वीडियो और ऑडियो इनपुट को ऐक्सेस कर सकते हैं. हालांकि, ब्राउज़र के हिसाब से यह पूरी तरह से डाइनैमिक और इनलाइन अनुभव हो सकता है. इसके अलावा, इसे उपयोगकर्ता के डिवाइस पर मौजूद किसी दूसरे ऐप्लिकेशन को भी सौंपा जा सकता है. इसके अलावा, हर डिवाइस में कैमरा भी नहीं होता. तो, ऐसा अनुभव कैसे बनाया जा सकता है जिसमें उपयोगकर्ता की जनरेट की गई इमेज का इस्तेमाल किया जा सके और वह हर जगह ठीक से काम करे?
आसानी से और धीरे-धीरे शुरू करें
अगर आपको अपने अनुभव को लगातार बेहतर बनाना है, तो आपको किसी ऐसे टूल से शुरुआत करनी होगी जो हर जगह काम करता हो. सबसे आसान तरीका यह है कि उपयोगकर्ता से पहले से रिकॉर्ड की गई फ़ाइल मांगें.
यूआरएल मांगें
यह सबसे अच्छा विकल्प है, लेकिन यह पूरी तरह से संतोषजनक नहीं है. उपयोगकर्ता से कोई यूआरएल पाएं और फिर उसका इस्तेमाल करें. सिर्फ़ इमेज दिखाने के लिए, यह हर जगह काम करता है. img
एलिमेंट बनाएं, src
सेट करें, और आपका काम हो गया.
हालांकि, अगर आपको इमेज में किसी भी तरह का बदलाव करना है, तो चीज़ें थोड़ी मुश्किल हो जाती हैं. CORS आपको तब तक असल पिक्सल ऐक्सेस करने से रोकती है, जब तक सर्वर सही हेडर सेट नहीं कर देता और आप इमेज को क्रॉसऑरिजिन के तौर पर मार्क नहीं करते. इसके लिए, प्रॉक्सी सर्वर चलाना ही एक तरीका है.
फ़ाइल इनपुट
आपके पास एक सामान्य फ़ाइल इनपुट एलिमेंट का इस्तेमाल करने का भी विकल्प है. इसमें accept
फ़िल्टर भी शामिल है, जो बताता है कि आपको सिर्फ़
इमेज फ़ाइलें चाहिए.
<input type="file" accept="image/*" />
यह तरीका सभी प्लैटफ़ॉर्म पर काम करता है. डेस्कटॉप पर, यह उपयोगकर्ता को फ़ाइल सिस्टम से इमेज फ़ाइल अपलोड करने के लिए कहेगा. iOS और Android पर Chrome और Safari में, इस तरीके से उपयोगकर्ता को यह चुनने का विकल्प मिलेगा कि इमेज कैप्चर करने के लिए किस ऐप्लिकेशन का इस्तेमाल करना है. इसमें, सीधे कैमरे से फ़ोटो लेने या किसी मौजूदा इमेज फ़ाइल को चुनने का विकल्प भी शामिल है.
इसके बाद, डेटा को <form>
से अटैच किया जा सकता है या JavaScript की मदद से डेटा में बदलाव किया जा सकता है. इसके लिए, इनपुट एलिमेंट पर onchange
इवेंट को सुनें और फिर इवेंट target
की files
प्रॉपर्टी पढ़ें.
<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
क्या है.
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 playsinline 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 के उलट, वेब पर वीडियो के लिए कोई अलग से स्ट्रीम प्रोसेसिंग एपीआई नहीं है, इसलिए उपयोगकर्ता के कैमरे से स्नैपशॉट लेने के लिए आपको थोड़ी हैकर का इस्तेमाल करना होगा.
इसकी प्रोसेस इस तरह से होती है:
- कैनवस ऑब्जेक्ट बनाएं, जो कैमरे से फ़्रेम को होल्ड करेगा
- कैमरे की स्ट्रीम का ऐक्सेस पाना
- इसे किसी वीडियो एलिमेंट से अटैच करें
- जब आपको कोई सटीक फ़्रेम कैप्चर करना हो, तो
drawImage()
का इस्तेमाल करके वीडियो एलिमेंट का डेटा, कैनवस ऑब्जेक्ट में जोड़ें.
<video id="player" controls playsinline 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 playsinline 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 शिम का इस्तेमाल करें.