Ç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 kademeli bir başlangıç yapın
Deneyiminizi aşamalı olarak iyileştirmek istiyorsanız her yerde kullanılabilen bir şeyle başlamanız gerekir. En kolay yöntem, kullanıcıdan önceden kaydedilmiş bir dosya istemektir.
URL isteme
Bu, en iyi desteklenen ancak en az tatmin edici seçenektir. Kullanıcıdan size bir URL vermesini isteyin ve bu URL'yi kullanın. Bu yöntem, resmin yalnızca gösterilmesi için her yerde kullanılabilir. Bir img
öğesi oluşturun, src
değerini ayarlayın ve işlemi tamamlayın.
Ancak resim üzerinde herhangi bir şekilde işlem yapmak istiyorsanız işler biraz daha karmaşıktır. CORS, sunucu uygun başlıkları ayarlamazsa ve resmi crossorigin olarak işaretlemezseniz gerçek piksellere erişmenizi engeller. Bunun tek pratik yolu bir 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 kamerası uygulaması doğrudan başlatılır.
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 zamandır kullanılıyor ve büyük 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 ise 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öntemleri yoktur ve dizi yinelenebilir değildir.
Elbette Array.from(fileList)
kullanarak gerçek bir dizi de alabilirsiniz.
FileList
girişleri File
nesnesi şeklindedir. 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şlemleri yapabilirsiniz. Örneğin, şunları yapabilirsiniz:
- Düzenleyebilmeniz için bir
<canvas>
öğesine çizin - Kullanıcının cihazına indirin
fetch()
ile bir sunucuya yükleyin
Kameraya etkileşimli olarak erişme
Temel bilgileri öğrendiğinize göre şimdi sıra aşamalı olarak geliştirmede.
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 kameraya ve mikrofona doğrudan erişebilirsiniz. Bu işlem, kullanıcıdan bağlı mikrofonlara 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.
Ancak desteği tespit etmek çok kolaydır.
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 denir. Ö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>
Bu bilgi tek başına çok faydalı değildir. Tek yapmanız gereken video verilerini alıp oynatmak. 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 kodlama 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.
- Tam bir kare yakalamak istediğinizde
drawImage()
kullanarak video öğesindeki verileri bir kanvas 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 alınan verileri kanvasta depoladıktan sonra bu verilerle birçok işlem yapabilirsiniz. Şunları yapabilirsiniz:
- Doğrudan sunucuya yükleyin
- Yerel olarak depolama
- Resme eğlenceli efektler uygulama
İpuçları
Gerekmediği durumlarda kameradan yayını durdurma
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 isteme
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 isteğinde bulunulmasından nefret eder ve isteği sık sık engeller ya da istemin oluşturulma bağlamını anlamazlarsa yoksayar. Kameraya erişmek için yalnızca ilk kez ihtiyaç duyulduğunda izin 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.