Çoğu tarayıcı, kullanıcının kamerasına erişebilir.
Birçok tarayıcı artık kullanıcıdan gelen video ve ses girişine erişebiliyor. Ancak tarayıcıya bağlı olarak tam dinamik ve satır içi bir deneyim olabilir veya kullanıcının cihazındaki başka bir uygulamaya yetkilendirilebilir. Ayrıca, her cihazda kamera yoktur. Peki, her yerde iyi çalışan, kullanıcı tarafından oluşturulan bir resim kullanan bir deneyim nasıl oluşturabilirsiniz?
Basit ve aşamalı bir şekilde başlayın
Deneyimi aşamalı olarak iyileştirmek istiyorsanız her yerde işe yarayan bir şeyle başlamanız gerekir. En kolay yöntem, kullanıcıdan önceden kaydedilmiş bir dosya istemektir.
URL isteyin
Bu, en iyi desteklenen ancak en az tatmin edici seçenektir. Kullanıcıdan size bir URL vermesini isteyin, sonra bunu kullanın. Yalnızca resmi görüntülemek için bu yöntem her yerde işe yarar. Bir img
öğesi oluşturup src
değerini ayarlayın. Hepsi bu kadar.
Ancak resim üzerinde herhangi bir şekilde değişiklik yapmak isterseniz işler biraz daha karmaşık hale gelir. CORS, sunucu uygun başlıkları ayarlamadığı ve resmi çapraz kaynak olarak işaretlemediğiniz sürece gerçek piksellere erişmenizi engeller. Bunun için tek pratik yol proxy sunucusu çalıştırmaktır.
Dosya girişi
Yalnızca resim dosyaları istediğinizi belirten bir accept
filtresi içeren basit bir dosya giriş öğesi de kullanabilirsiniz.
<input type="file" accept="image/*" />
Bu yöntem tüm platformlarda kullanılabilir. Masaüstünde, kullanıcıdan dosya sisteminden bir resim dosyası yüklemesi istenir. iOS ve Android'deki Chrome ve Safari'de bu yöntem, kullanıcıya resmi çekmek için hangi uygulamayı kullanacağını seçme seçeneği sunar. Doğrudan kamerayla fotoğraf çekme veya mevcut bir resim dosyasını seçme seçenekleri de buna dahildir.
Ardından veriler, giriş öğesinde bir onchange
etkinliği dinlenerek ve ardından etkinliğin files
özelliği target
okunarak bir <form>
öğesine eklenebilir veya JavaScript ile değiştirilebilir.
<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
mülkü bir FileList
nesnesi olup daha sonra daha ayrıntılı olarak ele alınacaktır.
İsterseniz öğeye capture
özelliğini de ekleyebilirsiniz. Bu özellik, tarayıcıya kameradan resim çekmeyi tercih ettiğinizi gösterir.
<input type="file" accept="image/*" capture />
<input type="file" accept="image/*" capture="user" />
<input type="file" accept="image/*" capture="environment" />
capture
özelliğini değer olmadan eklemek, hangi kameranın kullanılacağına tarayıcıya karar vermesine olanak tanır. "user"
ve "environment"
değerleri ise tarayıcıya sırasıyla ön ve arka kameraları tercih etmesini söyler.
capture
özelliği Android ve iOS'te çalışır, ancak masaüstünde yoksayılır. Ancak Android'de bu, kullanıcının artık mevcut bir resmi seçme seçeneğinin olmayacağı anlamına gelir. Bunun yerine sistem kamera uygulaması doğrudan başlatılacak.
Sürükle ve bırak
Dosya yükleme özelliğini zaten ekliyorsanız kullanıcı deneyimini biraz daha zenginleştirmenin birkaç kolay yolu vardır.
Bunlardan ilki, sayfanıza kullanıcının masaüstünden veya başka bir uygulamadan dosya sürüklemesine olanak tanıyan bir bırakma hedefi eklemektir.
<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>
Dosya girişine benzer şekilde, drop
etkinliğinin dataTransfer.files
mülkünden bir FileList
nesnesi alabilirsiniz;
dragover
etkinlik işleyicisi, dropEffect
mülkünü kullanarak kullanıcıya dosyayı bıraktığında ne olacağını bildirmenize olanak tanır.
Sürükle ve bırak özelliği uzun süredir kullanılıyor ve önde gelen tarayıcılar tarafından iyi bir şekilde destekleniyor.
Panodan yapıştırma
Mevcut bir resim dosyasını almanızı sağlayan son yöntem, panodur. Bunun kodu çok basittir ancak kullanıcı deneyimini doğru şekilde oluşturmak biraz daha zordur.
<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
başka bir FileList
nesnesidir.)
Panoya API'sinin zor kısmı, tam tarayıcı desteği için hedef öğenin hem seçilebilir hem de düzenlenebilir olması gerektiğidir. Hem <textarea>
hem de <input type="text">
, contenteditable
özelliğine sahip öğeler gibi bu ölçütlere uyar. Ancak bunlar, metin düzenlemek için de tasarlanmıştır.
Kullanıcının metin girmesini istemiyorsanız bu işlemin sorunsuz şekilde çalışmasını sağlamak zor olabilir. Başka bir öğeyi tıkladığınızda seçilen gizli bir girişe sahip olmak gibi püf noktaları, erişilebilirliği korumayı zorlaştırabilir.
FileList nesnesini işleme
Yukarıdaki yöntemlerin çoğu FileList
oluşturduğundan, bunun ne olduğundan biraz bahsetmem gerekiyor.
FileList
, Array
'a benzer. Sayısal anahtarları ve length
mülkü vardır ancak aslında bir dizi değildir. forEach()
veya pop()
gibi dizi yöntemi yoktur ve yinelenemez.
Elbette Array.from(fileList)
kullanarak gerçek bir dizi de alabilirsiniz.
FileList
girişleri File
nesnedir. Bunlar, ek name
ve lastModified
salt okunur özelliklerine sahip olmaları dışında Blob
nesneleriyle tamamen aynıdır.
<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>
Bu örnek, resim MIME türüne sahip ilk dosyayı bulur ancak aynı anda birden fazla resmin seçilmesi/yapıştırılması/bırakılması işlemini de gerçekleştirebilir.
Dosyaya eriştikten sonra istediğiniz işlemi yapabilirsiniz. Örneğin, şunları yapabilirsiniz:
- Düzenleyebilmeniz için bir
<canvas>
öğesine çizin - Kullanıcının cihazına indirme
fetch()
ile bir sunucuya yükleyin
Kameraya etkileşimli olarak erişme
Temelleri ele aldığınıza göre artık onu daha da geliştirmenin zamanı geldi.
Modern tarayıcılar kameralara doğrudan erişebilir. Bu sayede, web sayfasıyla tamamen entegre deneyimler oluşturabilirsiniz. Böylece kullanıcının tarayıcıdan çıkması gerekmez.
Kameraya erişim elde etme
WebRTC spesifikasyonundaki getUserMedia()
adlı bir API'yi kullanarak kamera ve mikrofona doğrudan erişebilirsiniz. Bu işlem, kullanıcıdan bağlı mikrofon ve kameralara erişim izni ister.
getUserMedia()
için destek oldukça iyidir ancak henüz her yerde kullanılamaz. Özellikle, Safari 10 veya önceki sürümlerde kullanılamaz. Bu sürüm, makalenin yazıldığı sırada en son kararlı sürümdür.
Ancak Apple, Safari 11'de kullanılabileceğini duyurdu.
Bununla birlikte, desteğin tespit edilmesi çok basittir.
const supported = 'mediaDevices' in navigator;
getUserMedia()
işlevini çağırırken ne tür bir medya istediğinizi açıklayan bir nesne iletmeniz gerekir. Bu seçimlere kısıtlama adı verilir. Ön veya arka kamera tercihiniz, ses ekleme tercihiniz ve yayın için tercih ettiğiniz çözünürlük gibi çeşitli kısıtlamalar olabilir.
Ancak kameradan veri almak için yalnızca bir kısıtlamaya ihtiyacınız vardır: video: true
.
İşlem başarılı olursa API, kameradan alınan verileri içeren bir MediaStream
döndürür. Ardından bu öğeyi bir <video>
öğesine ekleyip oynatarak gerçek zamanlı önizleme yapabilir veya <canvas>
öğesine ekleyip anlık görüntü alabilirsiniz.
<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>
Tek başına bu pek faydalı değildir. Tek yapmanız gereken video verilerini alıp oynatmaktır. Resim almak istiyorsanız biraz daha çalışmanız gerekir.
Anlık görüntü alma
Resim almak için en iyi seçenek, videodan kanvas üzerine çerçeve çizmektir.
Web Audio API'nin aksine, web'de video için özel bir akış işleme API'si yoktur. Bu nedenle, kullanıcının kamerasından anlık görüntü almak için biraz da olsa bilgisayar korsanlığı yapmanız gerekir.
Süreç şu şekildedir:
- Kameradan gelen kareyi barındıracak bir kanvas nesnesi oluşturun
- Kamera akışına erişim
- Bir video öğesine ekleyin
- Hassas bir kare yakalamak istediğinizde video öğesindeki verileri
drawImage()
kullanarak bir tuval nesnesine ekleyin.
<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>
Kameradan gelen verileri tuvalde depoladıktan sonra bu verilerle birçok işlem yapabilirsiniz. Şunları yapabilirsiniz:
- Doğrudan sunucuya yükleyin
- Yerel olarak depolayın
- Resme eğlenceli efektler uygulama
İpuçları
Gerektiğinde kameradan akışı durdurun
Artık ihtiyacınız olmadığında kamerayı kullanmayı bırakmak iyi bir uygulamadır. Bu, yalnızca pil ve işlem gücü tasarrufu sağlamaz, aynı zamanda kullanıcıların uygulamanıza güvenmesini de sağlar.
Kameraya erişimi durdurmak için getUserMedia()
tarafından döndürülen akış için her video kanalında stop()
işlevini çağırmanız yeterlidir.
<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>
Kamerayı sorumlu bir şekilde kullanmak için izin isteyin
Kullanıcı daha önce sitenize kamera erişimi vermemişse getUserMedia()
çağrısını yaptığınız anda tarayıcı, kullanıcıdan sitenize kamera erişimi vermesini ister.
Kullanıcılar, makinelerindeki güçlü cihazlara erişim istenmesinden nefret eder ve isteği sık sık engeller veya istemin oluşturulduğu bağlamı anlamadıklarında isteği yoksayar. Kameraya erişimi yalnızca ilk kez ihtiyaç duyulduğunda istemek en iyi uygulamadır. Kullanıcı erişim izni verdikten sonra bu istek tekrar gösterilmez. Ancak kullanıcı erişim iznini reddederse kamera izni ayarlarını manuel olarak değiştirmediği sürece tekrar erişim izni alamazsınız.
Uyumluluk
Mobil ve masaüstü tarayıcı uygulaması hakkında daha fazla bilgi:
Ayrıca, uygulamaları WebRTC spesifikasyonu değişikliklerine ve ön ek farklılıklarına karşı korumak için adapter.js ara yazılımını kullanmanızı öneririz.