Çoğu tarayıcı, kullanıcının kamerasına erişebilir.
Artık birçok tarayıcı, kullanıcının video ve ses girişine erişebilir. Ancak, tarayıcıya bağlı olarak bu tam dinamik ve satır içi bir deneyim olabilir veya kullanıcının cihazındaki başka bir uygulamaya devredilebilir. Üstelik her cihazın kamerası bile yoktur. Peki, kullanıcı tarafından oluşturulan ve her yerde işe yarayan resmin kullanıldığı bir deneyimi nasıl oluşturabilirsiniz?
Basit ve kademeli bir şekilde başlayın
Deneyiminizi kademeli olarak geliştirmek istiyorsanız, her yerde geçerli olan bir şeyle başlamanız gerekir. Yapılacak en kolay şey kullanıcıdan önceden kaydedilmiş bir dosya istemektir.
URL isteyin
Bu, en iyi desteklenen, ancak kullanıcıyı en az memnun eden seçenektir. Kullanıcıdan size bir URL vermesini sağlayın ve
sonra bunu kullanın. Yalnızca resmin görüntülenmesi için bu işlem her yerde çalışır. Bir img
öğesi oluşturup src
öğesini ayarlayın. Hepsi bu kadar.
Resmi herhangi bir şekilde değiştirmek istiyorsanız işler biraz daha karmaşıktır. CORS, sunucu uygun üst bilgileri ayarlamadığı ve siz resmi çapraz kaynak olarak işaretlemediğiniz sürece gerçek piksellere erişmenizi engeller. Bunun tek pratik yolu proxy sunucu çalıştırmaktır.
Dosya girişi
Yalnızca resim dosyaları istediğinizi belirten accept
filtresi dahil olmak üzere basit bir dosya giriş öğesi de kullanabilirsiniz.
<input type="file" accept="image/*" />
Bu yöntem tüm platformlarda çalışır. 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ğına dair bir seçenek sunar. Örneğin, doğrudan kamerayla fotoğraf çekme veya mevcut bir resim dosyasını seçme imkanı sunulur.
Daha sonra veriler, giriş öğesinde onchange
etkinliği dinlenip target
etkinliğinin files
özelliği 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
özelliği, daha sonra ayrıntılı olarak ele alacağım bir FileList
nesnesidir.
Ayrıca, isteğe bağlı olarak öğeye capture
özelliğini de ekleyebilirsiniz. Bu özellik, tarayıcıya kameradan resim almayı tercih ettiğinizi belirtir.
<input type="file" accept="image/*" capture />
<input type="file" accept="image/*" capture="user" />
<input type="file" accept="image/*" capture="environment" />
capture
özelliğinin değer olmadan eklenmesi, hangi kameranın kullanılacağına tarayıcının karar vermesine olanak tanırken "user"
ve "environment"
değerleri, tarayıcıya sırasıyla ön ve arka kameraları tercih etmesini bildirir.
capture
özelliği, Android ve iOS'ta çalışır ancak masaüstünde yoksayılır. Ancak
Android'de bu şekilde kullanıcının artık mevcut bir resmi seçme
seçeneğine sahip olmayacağı anlamına geldiğini
unutmayın. Bunun yerine, sistem kamerası uygulaması doğrudan başlatılır.
Sürükle ve bırak
Zaten dosya yükleme özelliği ekliyorsanız kullanıcı deneyimini biraz daha zengin hale getirmenin birkaç kolay yolu vardır.
İlki sayfanıza, kullanıcının masaüstünden veya başka bir uygulamadan bir 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
özelliğinden bir FileList
nesnesi alabilirsiniz;
dragover
etkinlik işleyici, dropEffect
özelliğini kullanarak kullanıcıya dosyayı bıraktığında ne olacağını bildirmenizi sağlar.
Sürükle ve bırak işlevi uzun zamandır kullanılmaktadır ve başlıca tarayıcılar tarafından iyi desteklenmektedir.
Panodan yapıştır
Mevcut bir resim dosyasını almanın son yolu panodan kullanmaktır. Bunun kodu çok basittir, ancak kullanıcı deneyimini doğru almak 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
yine bir başka FileList
nesnesidir.)
Pano API'sinin zorlu yanı, tarayıcılar arası tam destek için hedef öğenin hem seçilebilir hem de düzenlenebilir olması gerekir. Hem <textarea>
hem de <input type="text">
, contenteditable
özelliğine sahip öğeler gibi bu işleve uyum sağlar. Ancak bunlar açıkça metin düzenlemek
için tasarlanmıştır.
Kullanıcının metin girebilmesini istemiyorsanız bu işlemin sorunsuz şekilde yapılması zor olabilir. Başka bir öğeyi tıkladığınızda seçilen gizli bir girişe sahip olmak gibi püf noktaları, erişilebilirliğin korunmasını zorlaştırabilir.
FileList nesnesini işleme
Yukarıdaki yöntemlerin çoğu FileList
ürettiğinden, bunun ne olduğundan biraz bahsetmem gerekir.
FileList
, Array
ile benzerdir. Sayısal anahtarları ve length
özelliği vardır ancak aslında bir dizi değildir. forEach()
veya pop()
gibi dizi yöntemleri yoktur ve yinelenemez.
Elbette, Array.from(fileList)
kullanarak gerçek bir Dizi elde edebilirsiniz.
FileList
girişleri File
nesneleridir. 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 örnekte, resim MIME türüne sahip ilk dosya bulunmuştur. Ancak aynı anda birden fazla resmi seçmek/yapıştırmak/bırakmak da mümkün.
Dosyaya erişim elde ettikten sonra dosyayla istediğiniz her şeyi yapabilirsiniz. Örneğin, şunları yapabilirsiniz:
- Değiştirebilmek için bir
<canvas>
öğesinin içine çizin - Kullanıcının cihazına indirin
fetch()
ile bir sunucuya yükleyin
Kameraya etkileşimli olarak erişin
Temel bilgileri edindiğinize göre artık ilerledikçe kendinizi geliştirebilirsiniz.
Modern tarayıcılar kameralara doğrudan erişebilir, bu da web sayfasıyla tamamen entegre edilmiş deneyimler oluşturmanıza olanak tanır. Böylece kullanıcının tarayıcıdan hiçbir zaman ayrılması gerekmez.
Kameraya erişim izni alın
WebRTC spesifikasyonunda getUserMedia()
adlı bir API kullanarak kameraya ve mikrofona doğrudan erişebilirsiniz. Kullanıcıdan bağlı mikrofon ve kameralara erişmesi istenir.
getUserMedia()
desteği oldukça iyi olsa da henüz her yerde desteklenmiyor. Özellikle, bu yazı yazıldığında hâlâ en yeni kararlı sürüm olan Safari 10 veya önceki sürümlerde kullanılamıyor.
Ancak Apple, Safari 11'de kullanıma sunulacağını duyurdu.
Bununla birlikte, desteği algılamak çok kolaydır.
const supported = 'mediaDevices' in navigator;
getUserMedia()
yöntemini çağırırken ne tür bir medya istediğinizi açıklayan bir nesne iletmeniz gerekir. Bu seçeneklere kısıtlamalar denir. Tercih ettiğiniz ön veya arka kamera tercihiniz, ses isteyip istemediğiniz ve yayın için tercih ettiğiniz çözünürlük gibi birkaç olası kısıtlama vardır.
Ancak kameradan veri almak için tek bir kısıtlamanız vardır, bu da video: true
olur.
Başarılı olursa API, kameradan veri içeren bir MediaStream
döndürür. Ardından, bu öğeyi bir <video>
öğesine ekleyip gerçek zamanlı bir önizleme göstermek için oynatabilir veya anlık görüntü almak için <canvas>
öğesine ekleyebilirsiniz.
<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>
Bu tek başına pek faydalı değil. Tek yapmanız gereken video verilerini alıp oynatmaktır. Bir resim almak istiyorsanız ekstra bir işlem yapmanız gerekir.
Anlık görüntü al
Resim almak için desteklenen en iyi seçenek, videodan kanvasa bir kare çizmektir.
Web Audio API'nın aksine, web üzerinde video için özel bir akış işleme API'si yoktur. Bu nedenle, kullanıcının kamerasından anlık görüntü yakalamak için küçük bir bilgisayar korsanlığına başvurmanız gerekir.
Süreç aşağıdaki gibidir:
- Çerçeveyi kameradan tutacak bir tuval nesnesi oluşturun
- Kamera akışına erişin
- Bir video öğesine ekleyin
- Hassas bir kare yakalamak istediğinizde, video öğesindeki verileri
drawImage()
kullanarak bir kanvas nesnesine ekleyin.
<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>
Kameradan alınan veriler kanvasta depolandıktan sonra bunlarla birçok işlem yapabilirsiniz. Şunları yapabilirsiniz:
- Doğrudan sunucuya yükleyin
- Yerel olarak depolayın
- Resme ilginç efektler uygulayın
İpuçları
Gerekmediğinde kameradan yayın yapmayı durdurun
Artık ihtiyaç duymadığınızda kamerayı kullanmayı bırakmak iyi bir uygulamadır. Bu, pil ve işlem gücünden tasarruf etmekle kalmaz, 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()
komutunu çağırmanız yeterlidir.
<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>
Kamerayı sorumlu bir şekilde kullanmak için izin isteyin
Kullanıcı daha önce sitenizin kameraya erişmesine izin vermediyse getUserMedia()
çağrısı yaptığınız anda tarayıcı, kullanıcıdan sitenizin kameraya erişim izni vermesini ister.
Kullanıcılar, makinelerindeki güçlü cihazlara erişim istenmesinden nefret ederler ve bu isteği sık sık engellerler veya istemin oluşturulduğu bağlamı anlamadıkları takdirde bunu göz ardı ederler. Kameraya yalnızca ilk gerektiğinde erişim izni istemek en iyi uygulamadır. Kullanıcı erişim verdikten sonra bu istek bir daha sorulmaz. Ancak kullanıcı erişimi reddederse kamera izni ayarları manuel olarak değiştirilmediği sürece tekrar erişemezsiniz.
Uyumluluk
Mobil ve masaüstü tarayıcı uygulaması hakkında daha fazla bilgi:
Uygulamaları WebRTC spesifikasyon değişikliklerinden ve önek farklarından korumak için adapter.js dolgusunu da kullanmanızı öneririz.