Unity Android Cihaz Kamerasıyla Resim/Video Çekmek

Yayınlandı: 04 Haziran 2018 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde
Etiketler:, , , , , , , , ,

Merhabalar,

Bu Unity dersinde, Android ve iOS platformlarda cihazın kamerasını kullanarak resim çekmeyi veya video kaydetmeyi göreceğiz.

O halde hadi başlayalım!

Kurulum

İlk önce şu adresteki unitypackage‘ı Assets-Import Package yoluyla projenize import edin: https://github.com/yasirkula/UnityNativeCamera/raw/master/NativeCamera.unitypackage

Eğer iOS’a build alacaksanız, Plugins/NativeCamera/Editor/NCPostProcessBuild.cs scriptindeki CAMERA_USAGE_DESCRIPTION‘ın değerini dilerseniz değiştirin. Buraya girdiğiniz yazı, kameraya erişim izni isterken gözükecek.

Eğer Android’e build alacaksanız, öncelikle Edit-Project Settings-Player‘daki Write Permission‘ı External (SDCard) yapın.

Plugin’i Android’de çalıştırabilmek için, projenizin Assets/Plugins/Android klasöründe bir AndroidManifest.xml dosyası bulunması gerekiyor. Henüz bir AndroidManifest’iniz yoksa C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer konumundaki Unity’nin varsayılan AndroidManifest.xml dosyasını kopyalayıp (dosya Apk gibi bir alt klasörde de olabilir) projenizin Assets/Plugins/Android klasörüne yapıştırın (Plugins veya Android klasörleri yoksa elle oluşturun).

Ardından AndroidManifest’te <application>...</application> etiketleri arasına şunu yapıştırın:

<provider // >_>
  android:name="com.yasirkula.unity.NativeCameraContentProvider"
  android:authorities="EŞSİZ_BİR_STRİNG"
  android:exported="false"
  android:grantUriPermissions="true" />

Buradaki “EŞSİZ_BİR_STRİNG“i kendinize has eşsiz bir yazı ile değiştirin (mesela oyununuzun bundle identifier‘ı). Bu değerin eşsiz olması gerekmesinin sebebi, bir cihaza aynı authorities‘e sahip birden çok uygulamanın yüklenememesidir. Bu string’de boşluk veya Türkçe karakter kullanmayın (ne olur ne olmaz). Örneğin:

DİKKAT: Aynı anda hem bu plugin’i hem de bir önceki yazımda paylaştığım NativeShare plugin’ini kullanacaksanız, iki plugin’in de provider‘larını AndroidManifest’e eklemeyi unutmayın (çünkü ikisinin de android:name değerleri farklı).

Fonksiyonlar

A) Kameranın Durumunu Kontrol Etmek

  • NativeCamera.DeviceHasCamera()

Cihazın kamerası olup olmadığını döndürür. Bazı telefonlarda kamera olmadığı için, bu fonksiyon o cihazlarda false döndürür.

  • NativeCamera.IsCameraBusy()

Kameranın meşgul olup olmadığını döndürür. Eğer kamera meşgulse (true), o an kameraya erişmek mümkün değildir.

B) Resim Çekmek

  • NativeCamera.TakePicture( CameraCallback callback, int maxSize = -1 )

callback: Kullanıcı kamera ile bir resim çekince veya işlemi iptal edince bu fonksiyon çağrılır. Buraya vereceğiniz fonksiyon bir string parametre almak zorundadır. Eğer işlem iptal edildiyse bu parametrenin değeri null olurken aksi taktirde, çekilen resim dosyasının konumu bu string’de depolanır.

maxSize: Eğer resmin genişliği veya yüksekliği bu değerden büyük olursa, resmin bu boyuta küçültülmüş bir versiyonu döndürülür. Varsayılan olarak bir büyüklük limiti yoktur ancak resim ne kadar büyük olursa hafızada o kadar çok yer kaplayacağı için bu parametreye 512, 1024 vs. gibi işinizi görmeye yetecek bir değer vermeniz şiddetle önerilir.

C) Video Kaydetmek

  • NativeCamera.RecordVideo( CameraCallback callback, Quality quality = Quality.Default, int maxDuration = 0, long maxSizeBytes = 0L )

quality: Çekilen videonun kalitesini belirler. Değeri Default (varsayılan), Low, Medium veya High olabilir.

maxDuration: Çekilen videoya saniye cinsinden bir süre limiti koyar. Bu süre bitiminde video çekimi hâlâ devam ediyorsa, video otomatik olarak durdurulur. Varsayılan olarak bir süre limiti yoktur. Yalnız bu parametrenin doğru çalışabilmesi için, cihazın üreticisinin kamera yazılımına bu işlevselliği eklemiş olması gerekmektedir; yani bu parametre bazı cihazlarda bir işe yaramayabilir.

maxSizeBytes: Çekilen videoya byte cinsinden bir boyut limiti koyar. Video bu boyutu aşarsa, çekim otomatik olarak durdurulur. Varsayılan olarak bir boyut limiti yoktur. Bu parametrenin iOS’ta bir etkisi yoktur. Ayrıca bu parametrenin doğru çalışabilmesi için, cihazın üreticisinin kamera yazılımına bu işlevselliği eklemiş olması gerekmektedir; yani bu parametre bazı cihazlarda bir işe yaramayabilir.

D) Çalışma Zamanı İzinleri (Runtime Permissions) Hakkında

Android 6.0 sürümü itibariyle artık önemli bir Android fonksiyonuna erişmeden önce, çalışma zamanında bu fonksiyona erişim izni istemek zorundayız. NativeCamera fonksiyonları çalışmadan önce otomatik olarak izin isterler ancak dilerseniz kendi başınıza da izinlerin mevcut durumunu sorgulayabilir veya izin isteyebilirsiniz.

  • NativeCamera.CheckPermission()

İzinlerin durumunu sorgular ve bir NativeCamera.Permission enum‘u döndürür. Eğer kameraya erişim iznimiz varsa bu enum’un değeri Permission.Granted olurken eğer henüz iznimiz yoksa Permission.ShouldAsk olur. Eğer kullanıcı karşısına gelen izin ekranını “Bir daha sorma” seçili bir şekilde reddederse veya kullanıcının cihazında aktif olan bir ebeveyn kontrol sistemi bu iznin verilmesini engelliyorsa, Permission.Denied döndürülür. Bu durumda kullanıcı izni cihazın ayarlar menüsünden elle vermek zorundadır. Böyle bir durumla baş başa kalırsanız, kullanıcıya ayarlar menüsünden izin vermesini söyleyen bir uyarı penceresi göstermenizi öneririm.

  • NativeCamera.RequestPermission()

Kameraya erişim izni ister ve sonucu bir NativeCamera.Permission enum’unda döndürür. Resim/video çekmeye yarayan NativeCamera fonksiyonları bu fonksiyonu otomatik olarak çağırıp sonucu döndürürler.

E) Çekilen Resim Dosyasını Texture’a Çevirmek

  • NativeCamera.LoadImageAtPath( string imagePath, int maxSize = -1, bool markTextureNonReadable = true, bool generateMipmaps = true, bool linearColorSpace = false )

Bu fonksiyon vasıtasıyla bir resim dosyasını hızlıca bir Texture2D objesine çevirebilirsiniz.

imagePath: Texture2D olmasını istediğiniz resim dosyasının konumunu buraya girmelisiniz.

maxSize: Eğer resmin genişliği veya yüksekliği bu değerden büyük olursa, resmin bu boyuta küçültülmüş bir versiyonu döndürülür. Varsayılan olarak bir büyüklük limiti yoktur ancak resim ne kadar büyük olursa hafızada o kadar çok yer kaplayacağı için bu parametreye 512, 1024 vs. gibi işinizi görmeye yetecek bir değer vermeniz şiddetle önerilir.

markTextureNonReadable: Texture2D objesinin RAM’deki kopyasını silerek hafızayı rahatlatır. Bunun dezavantajı, artık resmin piksellerine elle erişemezsiniz; yani eğer GetPixel veya SetPixel fonksiyonlarını kullanıyorsanız bu parametreyi false yapın.

generateMipmaps: Texture’un mipmap’lerinin olup olmayacağını belirler.

linearColorSpace: Texture’un linear renk uzayını mı yoksa gamma renk uzayını mı (varsayılan) kullanacağını belirler.

Örnek Kod

Aşağıdaki örnek kodun iki işlevi bulunmaktadır:

  • ekranın sol yarısına tıklarsanız, kamera ile resim çekmeniz istenir ve çekilen resim geçici bir küp objesine texture olarak verilir
  • ekranın sağ yarısına tıklarsanız, kamera ile video kaydetmeniz istenir ve bu kaydedilen video daha sonra oynatılır
void Update()
{
	if( Input.GetMouseButtonDown( 0 ) )
	{
		// Eğer kamera meşgulse bir şey yapma
		if( NativeCamera.IsCameraBusy() )
			return;

		if( Input.mousePosition.x < Screen.width / 2 ) // >_>
		{
			// Kamera ile resim çek
			// Eğer resmin genişliği veya yüksekliği 512 pikselden büyükse, resmi ufalt
			ResimCek( 512 );
		}
		else
		{
			// Kamera ile video kaydet
			VideoKaydet();
		}
	}
}

private void ResimCek( int maksimumBuyukluk )
{
	NativeCamera.Permission izin = NativeCamera.TakePicture( ( konum ) =>
	{
		Debug.Log( "Çekilen resmin konumu: " + konum );
		if( konum != null )
		{
			// Çekilen resmi bir Texture2D'ye çevir
			Texture2D texture = NativeCamera.LoadImageAtPath( konum, maksimumBuyukluk );
			if( texture == null )
			{
				Debug.Log( konum + " konumundaki resimden bir texture oluşturulamadı." );
				return;
			}

			// Texture'u geçici bir küp objesine ver
			GameObject kup = GameObject.CreatePrimitive( PrimitiveType.Cube );
			kup.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 5f;
			kup.transform.forward = -Camera.main.transform.forward;
			kup.transform.localScale = new Vector3( 1f, texture.height / (float) texture.width, 1f );

			Material material = kup.GetComponent<Renderer>().material;
			if( !material.shader.isSupported ) // eğer Standard shader desteklenmiyorsa Diffuse shader'ı kullan
				material.shader = Shader.Find( "Legacy Shaders/Diffuse" );

			material.mainTexture = texture;

			// 5 saniye sonra küp objesini yok et
			Destroy( kup, 5f );

			// Küp objesi ile birlikte Texture2D objesini de yok et
			// Eğer prosedürel bir objeyi (Texture2D) işiniz bitince yok etmezseniz,
			// mevcut scene'i değiştirene kadar obje hafızada kalmaya devam eder
			Destroy( texture, 5f );
		}
	}, maksimumBuyukluk );

	Debug.Log( "İzin durumu: " + izin );
}

private void VideoKaydet()
{
	NativeCamera.Permission izin = NativeCamera.RecordVideo( ( konum ) =>
	{
		Debug.Log( "Kaydedilen videonun konumu: " + konum );
		if( konum != null )
		{
			// Videoyu oynat
			Handheld.PlayFullScreenMovie( "file://" + konum );
		}
	} );

	Debug.Log( "İzin durumu: " + izin );
}

Böylece bu dersi de noktalamış olduk. Bir sonraki derste görüşmek dileğiyle!

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.