يتضمّن إطار عمل Android إمكانية استخدام مختلف الكاميرات وميزات الكاميرا المتوفّرة على الأجهزة، ما يتيح لك التقاط الصور والفيديوهات في تطبيقاتك. يناقش هذا المستند طريقة سريعة وبسيطة لالتقاط الصور والفيديوهات، ويقدّم طريقة متقدّمة لإنشاء تجارب كاميرا مخصّصة للمستخدمين.
ملاحظة:
توضّح هذه الصفحة الفئة
Camera
،
التي تم إيقافها نهائيًا. ننصحك باستخدام مكتبة CameraX Jetpack أو الفئة camera2
في حالات استخدام معيّنة. تعمل كلّ من CameraX وCamera2 على الإصدار 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث من نظام التشغيل Android.
يُرجى الرجوع إلى المراجع ذات الصلة التالية:
الاعتبارات
قبل تفعيل تطبيقك لاستخدام الكاميرات على أجهزة Android، عليك التفكير في بعض الأسئلة حول كيفية استخدام تطبيقك لهذه الميزة.
- متطلبات الكاميرا: هل استخدام الكاميرا مهم جدًا لتطبيقك إلى الحد الذي لا تريد فيه أن يتم تثبيت تطبيقك على جهاز لا يتضمّن كاميرا؟ في هذه الحالة، عليك توضيح متطلبات الكاميرا في ملف البيان.
- صورة سريعة أو كاميرا مخصّصة: كيف سيستخدم تطبيقك الكاميرا؟ هل أنت مهتم فقط بالتقاط صورة أو مقطع فيديو سريع، أم أنّ تطبيقك سيوفر طريقة جديدة لاستخدام الكاميرات؟ لالتقاط صورة أو مقطع فيديو سريع، ننصحك باستخدام تطبيقات الكاميرا الحالية. لتطوير ميزة كاميرا مخصّصة، يمكنك الاطّلاع على قسم إنشاء تطبيق كاميرا.
- متطلبات الخدمات التي تعمل في المقدّمة - متى يتفاعل تطبيقك مع الكاميرا؟ في نظام التشغيل Android 9 (المستوى 28 لواجهة برمجة التطبيقات) والإصدارات الأحدث، لا يمكن للتطبيقات التي تعمل في الخلفية الوصول إلى الكاميرا. لذلك، يجب استخدام الكاميرا إما عندما يكون تطبيقك في المقدّمة أو كجزء من خدمة تعمل في المقدّمة.
- مساحة التخزين - هل من المفترض أن تكون الصور أو الفيديوهات التي ينشئها تطبيقك مرئية فقط لتطبيقك أو تتم مشاركتها حتى تتمكن تطبيقات أخرى، مثل "معرض الصور" أو تطبيقات الوسائط والتواصل الاجتماعي الأخرى، من استخدامها؟ هل تريد أن تظل الصور والفيديوهات متاحة حتى إذا تم إلغاء تثبيت تطبيقك؟ راجِع قسم حفظ ملفات الوسائط للتعرّف على كيفية تنفيذ هذه الخيارات.
الأساسيات
يتيح إطار عمل Android التقاط الصور والفيديوهات من خلال واجهة برمجة التطبيقات android.hardware.camera2
أو الكاميرا Intent
. في ما يلي الفئات ذات الصلة:
android.hardware.camera2
- هذه الحزمة هي واجهة برمجة التطبيقات الأساسية للتحكّم في كاميرات الأجهزة. ويمكن استخدامها لالتقاط صور أو فيديوهات عند إنشاء تطبيق كاميرا.
Camera
- هذه الفئة هي واجهة برمجة التطبيقات القديمة المتوقّفة نهائيًا للتحكّم في كاميرات الأجهزة.
SurfaceView
- يتم استخدام هذه الفئة لعرض معاينة مباشرة للكاميرا للمستخدم.
MediaRecorder
- يتم استخدام هذه الفئة لتسجيل فيديو من الكاميرا.
Intent
- يمكن استخدام نوع إجراء الهدف
MediaStore.ACTION_IMAGE_CAPTURE
أوMediaStore.ACTION_VIDEO_CAPTURE
لالتقاط الصور أو الفيديوهات بدون استخدام العنصرCamera
مباشرةً.
بيانات ملف البيان
قبل بدء تطوير تطبيقك باستخدام Camera API، عليك التأكّد من أنّ بيانك يتضمّن التصريحات المناسبة للسماح باستخدام أجهزة الكاميرا والميزات الأخرى ذات الصلة.
- إذن الوصول إلى الكاميرا: يجب أن يطلب تطبيقك الإذن باستخدام كاميرا الجهاز.
<uses-permission android:name="android.permission.CAMERA" />
ملاحظة: إذا كنت تستخدم الكاميرا من خلال استدعاء تطبيق كاميرا حالي، لن يحتاج تطبيقك إلى طلب هذا الإذن.
- ميزات الكاميرا: يجب أن يوضّح تطبيقك أيضًا استخدام ميزات الكاميرا،
على سبيل المثال:
<uses-feature android:name="android.hardware.camera" />
للاطّلاع على قائمة بميزات الكاميرا، يُرجى الرجوع إلى مرجع الميزات في ملف البيان.
تؤدي إضافة ميزات الكاميرا إلى ملف البيان إلى منع Google Play من تثبيت تطبيقك على الأجهزة التي لا تتضمّن كاميرا أو لا تتوافق مع ميزات الكاميرا التي تحدّدها. لمزيد من المعلومات حول استخدام الفلترة المستندة إلى الميزات مع Google Play، يُرجى الاطّلاع على مقالة Google Play والفلترة المستندة إلى الميزات.
إذا كان تطبيقك يمكنه استخدام كاميرا أو ميزة كاميرا ليعمل بشكل سليم، ولكنّه لا يتطلّب ذلك، عليك تحديد ذلك في ملف البيان من خلال تضمين السمة
android:required
وضبطها علىfalse
:<uses-feature android:name="android.hardware.camera" android:required="false" />
- إذن الوصول إلى مساحة التخزين: يمكن لتطبيقك حفظ الصور أو الفيديوهات في مساحة التخزين الخارجية للجهاز (بطاقة SD) إذا كان يستهدف الإصدار Android 10 (المستوى 29 من واجهة برمجة التطبيقات) أو إصدارًا أقدم ويحدّد ما يلي في البيان.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- إذن تسجيل الصوت: لتسجيل الصوت أثناء التقاط الفيديو، يجب أن يطلب تطبيقك إذن تسجيل الصوت.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
-
إذن تحديد الموقع الجغرافي: إذا كان تطبيقك يضع علامات على الصور تتضمّن معلومات الموقع الجغرافي لنظام تحديد المواقع العالمي (GPS)، عليك طلب الحصول على إذن
ACCESS_FINE_LOCATION
. يُرجى العِلم أنّه إذا كان تطبيقك يستهدف الإصدار 5.0 من نظام التشغيل Android (المستوى 21 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، عليك أيضًا الإفصاح عن أنّ تطبيقك يستخدم نظام تحديد المواقع العالمي (GPS) على الجهاز:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> <uses-feature android:name="android.hardware.location.gps" />
لمزيد من المعلومات حول الحصول على الموقع الجغرافي للمستخدم، يُرجى الاطّلاع على استراتيجيات تحديد الموقع الجغرافي.
استخدام تطبيقات الكاميرا الحالية
تتمثّل إحدى الطرق السريعة لتفعيل التقاط الصور أو الفيديوهات في تطبيقك بدون الحاجة إلى الكثير من الرموز البرمجية الإضافية في استخدام Intent
لاستدعاء تطبيق كاميرا Android حالي.
يمكنك الاطّلاع على التفاصيل في دروس التدريب
التقاط الصور بسهولة و
تسجيل الفيديوهات بسهولة.
إنشاء تطبيق كاميرا
قد يحتاج بعض المطوّرين إلى واجهة مستخدم للكاميرا مخصّصة لتناسب شكل تطبيقاتهم أو توفّر ميزات خاصة. يمكن أن يؤدي كتابة رمز التقاط الصور الخاص بك إلى توفير تجربة أكثر جاذبية للمستخدمين.
ملاحظة: الدليل التالي مخصّص لواجهة برمجة التطبيقات القديمة التي تم إيقافها Camera
. بالنسبة إلى تطبيقات الكاميرا الجديدة أو المتقدّمة، يُنصح باستخدام android.hardware.camera2
واجهة برمجة التطبيقات الأحدث.
في ما يلي الخطوات العامة لإنشاء واجهة كاميرا مخصّصة لتطبيقك:
- الرصد والوصول إلى الكاميرا: إنشاء رمز للتحقّق من توفّر كاميرات وطلب الوصول إليها
- إنشاء فئة معاينة: أنشئ فئة معاينة للكاميرا توسّع
SurfaceView
وتنفّذ واجهةSurfaceHolder
. تعرض هذه الفئة معاينة للصور المباشرة من الكاميرا. - إنشاء تخطيط معاينة: بعد الحصول على فئة معاينة الكاميرا، أنشئ تخطيط عرض يتضمّن المعاينة وعناصر التحكّم في واجهة المستخدم التي تريدها.
- إعداد أدوات معالجة الأحداث لعملية الالتقاط: يمكنك ربط أدوات معالجة الأحداث بعناصر التحكّم في واجهتك لبدء عملية التقاط الصور أو الفيديوهات استجابةً لإجراءات المستخدم، مثل الضغط على زر.
- التقاط الصور والفيديوهات وحفظها: يمكنك إعداد الرمز البرمجي لالتقاط الصور أو الفيديوهات وحفظ الناتج.
- إيقاف استخدام الكاميرا: بعد استخدام الكاميرا، يجب أن يوقف تطبيقك استخدامها بشكل صحيح لكي تتمكّن التطبيقات الأخرى من استخدامها.
أجهزة الكاميرا هي موارد مشترَكة يجب إدارتها بعناية حتى لا يتعارض تطبيقك مع التطبيقات الأخرى التي قد تريد استخدامها أيضًا. تتناول الأقسام التالية كيفية رصد أجهزة الكاميرا وكيفية طلب إذن الوصول إلى الكاميرا وكيفية التقاط الصور أو الفيديو وكيفية إيقاف الكاميرا عندما ينتهي تطبيقك من استخدامها.
تنبيه: تذكَّر تحرير الكائن Camera
من خلال استدعاء Camera.release()
عند انتهاء تطبيقك من استخدامه. إذا لم يحرّر تطبيقك الكاميرا بشكل صحيح، ستفشل جميع محاولات الوصول إلى الكاميرا اللاحقة، بما في ذلك تلك التي يجريها تطبيقك، وقد يؤدي ذلك إلى إغلاق تطبيقك أو تطبيقات أخرى.
اكتشاف أجهزة الكاميرا
إذا كان تطبيقك لا يتطلّب استخدام كاميرا بشكل محدّد من خلال بيان في ملف البيان، عليك التحقّق مما إذا كانت الكاميرا متاحة أثناء التشغيل. لإجراء عملية التحقّق هذه، استخدِم طريقة PackageManager.hasSystemFeature()
، كما هو موضّح في مثال الرمز البرمجي أدناه:
Kotlin
/** Check if this device has a camera */ private fun checkCameraHardware(context: Context): Boolean { if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { // this device has a camera return true } else { // no camera on this device return false } }
Java
/** Check if this device has a camera */ private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){ // this device has a camera return true; } else { // no camera on this device return false; } }
يمكن أن تتضمّن أجهزة Android كاميرات متعددة، مثل كاميرا خلفية للتصوير وكاميرا أمامية لمكالمات الفيديو. يتيح لك الإصدار 2.3 من نظام التشغيل Android (المستوى 9 من واجهة برمجة التطبيقات) والإصدارات الأحدث التحقّق من عدد الكاميرات المتوفّرة على الجهاز باستخدام الطريقة Camera.getNumberOfCameras()
.
الوصول إلى الكاميرات
إذا تبيّن لك أنّ الجهاز الذي يتم تشغيل تطبيقك عليه يتضمّن كاميرا، عليك طلب الوصول إليها من خلال الحصول على مثيل من Camera
(إلا إذا كنت تستخدم intent للوصول إلى الكاميرا).
للوصول إلى الكاميرا الأساسية، استخدِم طريقة Camera.open()
وتأكَّد من رصد أي استثناءات، كما هو موضّح في الرمز البرمجي أدناه:
Kotlin
/** A safe way to get an instance of the Camera object. */ fun getCameraInstance(): Camera? { return try { Camera.open() // attempt to get a Camera instance } catch (e: Exception) { // Camera is not available (in use or does not exist) null // returns null if camera is unavailable } }
Java
/** A safe way to get an instance of the Camera object. */ public static Camera getCameraInstance(){ Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e){ // Camera is not available (in use or does not exist) } return c; // returns null if camera is unavailable }
تنبيه: تحقَّق دائمًا من الاستثناءات عند استخدام Camera.open()
. سيؤدي عدم التحقّق من الاستثناءات في حال كانت الكاميرا قيد الاستخدام أو غير متوفّرة إلى إيقاف النظام لتطبيقك.
على الأجهزة التي تعمل بالإصدار 2.3 من نظام التشغيل Android (المستوى 9 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكنك الوصول إلى كاميرات معيّنة باستخدام
Camera.open(int)
. سيصل رمز المثال أعلاه إلى الكاميرا الأولى الخلفية على جهاز يحتوي على أكثر من كاميرا واحدة.
التحقّق من ميزات الكاميرا
بعد الحصول على إذن الوصول إلى الكاميرا، يمكنك الحصول على مزيد من المعلومات حول إمكاناتها باستخدام طريقة Camera.getParameters()
والتحقّق من عنصر Camera.Parameters
الذي تم عرضه لمعرفة الإمكانات المتوافقة. عند استخدام
المستوى 9 من واجهة برمجة التطبيقات أو مستوى أعلى، استخدِم Camera.getCameraInfo()
لتحديد ما إذا كانت الكاميرا في مقدّمة الجهاز
أو خلفه، وتحديد اتجاه الصورة.
إنشاء فئة معاينة
لكي يتمكّن المستخدمون من التقاط الصور أو تسجيل الفيديوهات بفعالية، يجب أن يتمكّنوا من رؤية ما تراه كاميرا الجهاز. فئة معاينة الكاميرا هي SurfaceView
يمكنها عرض بيانات الصورة المباشرة الواردة من الكاميرا، ما يتيح للمستخدمين تأطير صورة أو فيديو والتقاطهما.
يوضّح نموذج الرمز البرمجي التالي كيفية إنشاء فئة معاينة أساسية للكاميرا يمكن تضمينها في تصميم View
. تنفِّذ هذه الفئة SurfaceHolder.Callback
من أجل تسجيل أحداث معاودة الاتصال
لإنشاء العرض وتدميره، وهي الأحداث اللازمة لتعيين إدخال معاينة الكاميرا.
Kotlin
/** A basic Camera preview class */ class CameraPreview( context: Context, private val mCamera: Camera ) : SurfaceView(context), SurfaceHolder.Callback { private val mHolder: SurfaceHolder = holder.apply { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. addCallback(this@CameraPreview) // deprecated setting, but required on Android versions prior to 3.0 setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } override fun surfaceCreated(holder: SurfaceHolder) { // The Surface has been created, now tell the camera where to draw the preview. mCamera.apply { try { setPreviewDisplay(holder) startPreview() } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } } override fun surfaceDestroyed(holder: SurfaceHolder) { // empty. Take care of releasing the Camera preview in your activity. } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.surface == null) { // preview surface does not exist return } // stop preview before making changes try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings mCamera.apply { try { setPreviewDisplay(mHolder) startPreview() } catch (e: Exception) { Log.d(TAG, "Error starting camera preview: ${e.message}") } } } }
Java
/** A basic Camera preview class */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; public CameraPreview(Context context, Camera camera) { super(context); mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your activity. } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } }
إذا أردت ضبط حجم معيّن لمعاينة الكاميرا، يمكنك ضبط ذلك في طريقة surfaceChanged()
كما هو موضّح في التعليقات أعلاه. عند ضبط حجم المعاينة،
يجب استخدام قيم من getSupportedPreviewSizes()
.
لا تضبط قيمًا عشوائية في طريقة setPreviewSize()
.
ملاحظة:
مع طرح ميزة
النوافذ المتعددة في الإصدار 7.0 من نظام التشغيل Android (المستوى 24 من واجهة برمجة التطبيقات) والإصدارات الأحدث، لم يعُد بإمكانك
افتراض أنّ نسبة العرض إلى الارتفاع للمعاينة هي نفسها نسبة العرض إلى الارتفاع للنشاط
حتى بعد استدعاء setDisplayOrientation()
.
استنادًا إلى حجم النافذة ونسبة العرض إلى الارتفاع، قد تحتاج إلى ملاءمة معاينة الكاميرا العريضة مع تخطيط عمودي، أو العكس، باستخدام تخطيط letterbox.
وضع المعاينة في تخطيط
يجب وضع فئة معاينة الكاميرا، مثل المثال الموضّح في القسم السابق، في تصميم أحد الأنشطة مع عناصر تحكّم أخرى في واجهة المستخدم لالتقاط صورة أو فيديو. يوضّح لك هذا القسم كيفية إنشاء تخطيط ونشاط أساسيين للمعاينة.
يوفر رمز التنسيق التالي عرضًا أساسيًا جدًا يمكن استخدامه لعرض معاينة للكاميرا. في هذا المثال، من المفترض أن يكون العنصر FrameLayout
هو الحاوية لفئة معاينة الكاميرا. يتم استخدام نوع التنسيق هذا لكي يمكن عرض معلومات أو عناصر تحكّم إضافية في الصور المعروضة في معاينة الكاميرا المباشرة.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/camera_preview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <Button android:id="@+id/button_capture" android:text="Capture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
في معظم الأجهزة، يكون الاتجاه التلقائي لمعاينة الكاميرا أفقيًا. يحدّد تصميم المثال هذا تصميمًا أفقيًا، ويصلح الرمز أدناه اتجاه التطبيق إلى الوضع الأفقي. لتسهيل عرض معاينة الكاميرا، عليك تغيير اتجاه نشاط المعاينة في تطبيقك إلى الوضع الأفقي من خلال إضافة ما يلي إلى ملف البيان.
<activity android:name=".CameraActivity" android:label="@string/app_name" android:screenOrientation="landscape"> <!-- configure this activity to use landscape orientation --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
ملاحظة: ليس من الضروري أن تكون معاينة الكاميرا في الوضع الأفقي.
بدءًا من الإصدار 2.2 من نظام التشغيل Android (المستوى 8 من واجهة برمجة التطبيقات)، يمكنك استخدام طريقة setDisplayOrientation()
لضبط دوران صورة المعاينة. لتغيير اتجاه المعاينة عندما يعيد المستخدم توجيه الهاتف، عليك أولاً إيقاف المعاينة باستخدام surfaceChanged()
، ثم تغيير الاتجاه، ثم إعادة بدء المعاينة باستخدام Camera.startPreview()
، وذلك ضمن طريقة Camera.stopPreview()
لفئة المعاينة.
في نشاط عرض الكاميرا، أضِف فئة المعاينة إلى العنصر FrameLayout
الموضّح في المثال أعلاه. يجب أن يضمن نشاط الكاميرا أيضًا إيقافها عند إيقافها مؤقتًا أو إغلاقها. يوضّح المثال التالي كيفية تعديل نشاط الكاميرا لإرفاق فئة المعاينة الموضّحة في إنشاء فئة معاينة.
Kotlin
class CameraActivity : Activity() { private var mCamera: Camera? = null private var mPreview: CameraPreview? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create an instance of Camera mCamera = getCameraInstance() mPreview = mCamera?.let { // Create our Preview view CameraPreview(this, it) } // Set the Preview view as the content of our activity. mPreview?.also { val preview: FrameLayout = findViewById(R.id.camera_preview) preview.addView(it) } } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private CameraPreview mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create an instance of Camera mCamera = getCameraInstance(); // Create our Preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mPreview); } }
ملاحظة: يشير الأسلوب getCameraInstance()
في المثال أعلاه إلى أسلوب المثال المعروض في الوصول إلى الكاميرات.
التقاط الصور
بعد إنشاء فئة معاينة وتصميم عرض لعرضها، ستكون مستعدًا لبدء التقاط الصور باستخدام تطبيقك. في رمز تطبيقك، عليك إعداد أدوات معالجة الأحداث لعناصر التحكّم في واجهة المستخدم من أجل الاستجابة لإجراء يتخذه المستخدم من خلال التقاط صورة.
لاسترداد صورة، استخدِم طريقة Camera.takePicture()
. تتلقّى هذه الطريقة ثلاث مَعلمات تستقبل البيانات من الكاميرا.
لتلقّي البيانات بتنسيق JPEG، يجب تنفيذ واجهة Camera.PictureCallback
لتلقّي بيانات الصورة وكتابتها في ملف. يوضّح الرمز البرمجي التالي عملية تنفيذ أساسية للواجهة Camera.PictureCallback
لحفظ صورة تم تلقّيها من الكاميرا.
Kotlin
private val mPicture = Camera.PictureCallback { data, _ -> val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run { Log.d(TAG, ("Error creating media file, check storage permissions")) return@PictureCallback } try { val fos = FileOutputStream(pictureFile) fos.write(data) fos.close() } catch (e: FileNotFoundException) { Log.d(TAG, "File not found: ${e.message}") } catch (e: IOException) { Log.d(TAG, "Error accessing file: ${e.message}") } }
Java
private PictureCallback mPicture = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); if (pictureFile == null){ Log.d(TAG, "Error creating media file, check storage permissions"); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); } } };
ابدأ عملية التقاط صورة من خلال استدعاء الطريقة Camera.takePicture()
. يوضّح رمز المثال التالي كيفية استدعاء هذه الطريقة من زر View.OnClickListener
.
Kotlin
val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { // get an image from the camera mCamera?.takePicture(null, null, picture) }
Java
// Add a listener to the Capture button Button captureButton = (Button) findViewById(R.id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // get an image from the camera mCamera.takePicture(null, null, picture); } } );
ملاحظة: يشير العضو mPicture
في المثال التالي إلى الرمز النموذجي أعلاه.
تنبيه: تذكَّر تحرير الكائن Camera
من خلال استدعاء Camera.release()
عند انتهاء تطبيقك من استخدامه. للحصول على معلومات حول كيفية إيقاف الكاميرا، يمكنك الاطّلاع على إيقاف الكاميرا.
تسجيل الفيديوهات
يتطلّب تسجيل الفيديو باستخدام إطار عمل Android إدارة دقيقة للعنصر Camera
والتنسيق مع الفئة MediaRecorder
. عند تسجيل فيديو باستخدام Camera
، عليك إدارة مكالمات Camera.lock()
وCamera.unlock()
للسماح لتطبيق MediaRecorder
بالوصول إلى أجهزة الكاميرا، بالإضافة إلى مكالمات Camera.open()
وCamera.release()
.
ملاحظة: بدءًا من الإصدار 4.0 من نظام التشغيل Android (المستوى 14 من واجهة برمجة التطبيقات)، تتم إدارة طلبات Camera.lock()
وCamera.unlock()
تلقائيًا.
على عكس التقاط الصور باستخدام كاميرا الجهاز، يتطلّب تسجيل الفيديو ترتيبًا معيّنًا جدًا للاستدعاء. يجب اتّباع ترتيب تنفيذ محدّد للاستعداد لتسجيل الفيديو والتقاطه بنجاح باستخدام تطبيقك، كما هو موضّح أدناه.
- Open Camera: استخدِم
Camera.open()
للحصول على مثيل لكائن الكاميرا. - معاينة الاتصال: يمكنك إعداد معاينة مباشرة لصورة الكاميرا من خلال توصيل
SurfaceView
بالكاميرا باستخدامCamera.setPreviewDisplay()
. - بدء المعاينة: اتّصِل بـ
Camera.startPreview()
لبدء عرض صور الكاميرا المباشرة. - بدء تسجيل الفيديو: يجب إكمال الخطوات التالية بالترتيب لتسجيل الفيديو بنجاح:
- فتح قفل الكاميرا: يمكنك فتح قفل الكاميرا لاستخدامها من خلال
MediaRecorder
عن طريق الاتصال بالرقمCamera.unlock()
. - ضبط MediaRecorder: استدعِ طرق
MediaRecorder
التالية بهذا الترتيب. لمزيد من المعلومات، يُرجى الاطّلاع على مستنداتMediaRecorder
المرجعية.setCamera()
: لضبط الكاميرا التي سيتم استخدامها لتسجيل الفيديو، استخدِم النسخة الحالية من تطبيقكCamera
.setAudioSource()
- ضبط مصدر الصوت باستخدامMediaRecorder.AudioSource.CAMCORDER
setVideoSource()
- ضبط مصدر الفيديو، استخدِمMediaRecorder.VideoSource.CAMERA
.- اضبط تنسيق إخراج الفيديو وبرنامج الترميز. بالنسبة إلى الإصدار 2.2 من نظام التشغيل Android (المستوى 8 من واجهة برمجة التطبيقات) والإصدارات الأحدث، استخدِم طريقة
MediaRecorder.setProfile
، واحصل على مثيل ملف شخصي باستخدامCamcorderProfile.get()
. بالنسبة إلى إصدارات Android الأقدم من 2.2، يجب ضبط تنسيق إخراج الفيديو ومعلمات الترميز:setOutputFormat()
- لضبط تنسيق الإخراج، حدِّد الإعداد التلقائي أوMediaRecorder.OutputFormat.MPEG_4
.setAudioEncoder()
- ضبط نوع ترميز الصوت، وتحديد الإعداد التلقائي أوMediaRecorder.AudioEncoder.AMR_NB
setVideoEncoder()
: لضبط نوع ترميز الفيديو، حدِّد الإعداد التلقائي أوMediaRecorder.VideoEncoder.MPEG_4_SP
.
setOutputFile()
- اضبط ملف الإخراج، واستخدِمgetOutputMediaFile(MEDIA_TYPE_VIDEO).toString()
من مثال الطريقة في قسم حفظ ملفات الوسائط.setPreviewDisplay()
- حدِّد عنصر تخطيط المعاينةSurfaceView
لتطبيقك. استخدِم العنصر نفسه الذي حدّدته في معاينة الربط.
تنبيه: يجب استدعاء طرق إعداد
MediaRecorder
بهذا الترتيب، وإلا سيحدث خطأ في تطبيقك وستتعذّر عملية التسجيل. - إعداد MediaRecorder: يتم إعداد
MediaRecorder
باستخدام إعدادات الضبط المتوفّرة من خلال استدعاءMediaRecorder.prepare()
. - بدء MediaRecorder: ابدأ تسجيل الفيديو من خلال استدعاء
MediaRecorder.start()
.
- فتح قفل الكاميرا: يمكنك فتح قفل الكاميرا لاستخدامها من خلال
- إيقاف تسجيل الفيديو: استدعِ الطرق التالية بالترتيب لإكمال تسجيل الفيديو بنجاح:
- Stop MediaRecorder: لإيقاف تسجيل الفيديو من خلال استدعاء
MediaRecorder.stop()
- إعادة ضبط MediaRecorder: يمكنك اختياريًا إزالة إعدادات الضبط من المسجّل من خلال استدعاء
MediaRecorder.reset()
. - Release MediaRecorder: لإيقاف
MediaRecorder
، استخدِمMediaRecorder.release()
. - قفل الكاميرا: لقفل الكاميرا حتى تتمكّن جلسات
MediaRecorder
المستقبلية من استخدامها من خلال استدعاءCamera.lock()
. بدءًا من الإصدار 4.0 من نظام التشغيل Android (المستوى 14 لواجهة برمجة التطبيقات)، لا يكون هذا الطلب ضروريًا إلا إذا تعذّر تنفيذ الطلبMediaRecorder.prepare()
.
- Stop MediaRecorder: لإيقاف تسجيل الفيديو من خلال استدعاء
- إيقاف المعاينة: عند انتهاء نشاطك من استخدام الكاميرا، أوقِف المعاينة باستخدام
Camera.stopPreview()
. - Release Camera: لإتاحة استخدام الكاميرا للتطبيقات الأخرى من خلال استدعاء
Camera.release()
.
ملاحظة: يمكن استخدام MediaRecorder
بدون إنشاء معاينة للكاميرا أولاً وتخطّي الخطوات القليلة الأولى من هذه العملية. ومع ذلك،
بما أنّ المستخدمين يفضّلون عادةً مشاهدة معاينة قبل بدء التسجيل، لن نتناول هذه العملية هنا.
ملاحظة: إذا كان تطبيقك يُستخدم عادةً لتسجيل الفيديو، اضبط قيمة
setRecordingHint(boolean)
على true
قبل بدء المعاينة. يمكن أن يساعد هذا الإعداد في تقليل الوقت المستغرَق لبدء التسجيل.
ضبط MediaRecorder
عند استخدام الفئة MediaRecorder
لتسجيل فيديو، يجب تنفيذ خطوات الإعداد بترتيب معيّن، ثم استدعاء الطريقة MediaRecorder.prepare()
للتحقّق من الإعداد وتنفيذه. يوضّح نموذج الرمز البرمجي التالي كيفية إعداد وتجهيز الفئة
MediaRecorder
بشكلٍ سليم لتسجيل الفيديو.
Kotlin
private fun prepareVideoRecorder(): Boolean { mediaRecorder = MediaRecorder() mCamera?.let { camera -> // Step 1: Unlock and set camera to MediaRecorder camera?.unlock() mediaRecorder?.run { setCamera(camera) // Step 2: Set sources setAudioSource(MediaRecorder.AudioSource.CAMCORDER) setVideoSource(MediaRecorder.VideoSource.CAMERA) // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)) // Step 4: Set output file setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()) // Step 5: Set the preview output setPreviewDisplay(mPreview?.holder?.surface) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) // Step 6: Prepare configured MediaRecorder return try { prepare() true } catch (e: IllegalStateException) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } catch (e: IOException) { Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } } } return false }
Java
private boolean prepareVideoRecorder(){ mCamera = getCameraInstance(); mediaRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mediaRecorder.setCamera(mCamera); // Step 2: Set sources mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); // Step 4: Set output file mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); // Step 5: Set the preview output mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); // Step 6: Prepare configured MediaRecorder try { mediaRecorder.prepare(); } catch (IllegalStateException e) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } catch (IOException e) { Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } return true; }
قبل الإصدار 2.2 من Android (المستوى 8 من واجهة برمجة التطبيقات)، يجب ضبط مَعلمات تنسيقات الإخراج والترميز مباشرةً، بدلاً من استخدام CamcorderProfile
. يتم توضيح هذا النهج في الرمز التالي:
Kotlin
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder?.apply { setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) }
Java
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
يتم ضبط معلَمات تسجيل الفيديو التالية في MediaRecorder
على الإعدادات التلقائية، ولكن قد تحتاج إلى تعديل هذه الإعدادات لتطبيقك:
setVideoEncodingBitRate()
setVideoSize()
setVideoFrameRate()
setAudioEncodingBitRate()
setAudioChannels()
setAudioSamplingRate()
بدء MediaRecorder وإيقافه
عند بدء تسجيل الفيديو وإيقافه باستخدام الفئة MediaRecorder
،
يجب اتّباع ترتيب معيّن، كما هو موضّح أدناه.
- فتح قفل الكاميرا باستخدام "
Camera.unlock()
" - اضبط
MediaRecorder
كما هو موضّح في مثال الرمز البرمجي أعلاه - بدء التسجيل باستخدام
MediaRecorder.start()
- تسجيل الفيديو
- إيقاف التسجيل باستخدام
MediaRecorder.stop()
- إيقاف "مسجّلة الوسائط" باستخدام
MediaRecorder.release()
- قفل الكاميرا باستخدام
Camera.lock()
يوضّح مثال الرمز البرمجي التالي كيفية ربط زر لبدء تسجيل الفيديو وإيقافه بشكل صحيح باستخدام الكاميرا وفئة MediaRecorder
.
ملاحظة: عند الانتهاء من تسجيل فيديو، لا ترفعوا أيديكم عن الكاميرا وإلا سيتم إيقاف المعاينة.
Kotlin
var isRecording = false val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { if (isRecording) { // stop recording and release camera mediaRecorder?.stop() // stop the recording releaseMediaRecorder() // release the MediaRecorder object mCamera?.lock() // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture") isRecording = false } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder?.start() // inform the user that recording has started setCaptureButtonText("Stop") isRecording = true } else { // prepare didn't work, release the camera releaseMediaRecorder() // inform user } } }
Java
private boolean isRecording = false; // Add a listener to the Capture button Button captureButton = (Button) findViewById(id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { if (isRecording) { // stop recording and release camera mediaRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object mCamera.lock(); // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture"); isRecording = false; } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder.start(); // inform the user that recording has started setCaptureButtonText("Stop"); isRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); // inform user } } } } );
ملاحظة: في المثال أعلاه، يشير prepareVideoRecorder()
إلى رمز المثال المعروض في ضبط MediaRecorder. تتولّى هذه الطريقة مهمة قفل الكاميرا وضبط إعدادات مثيل MediaRecorder
وإعداده.
إلغاء إذن الوصول إلى الكاميرا
الكاميرات هي مورد تشترك فيه التطبيقات على الجهاز. يمكن لتطبيقك استخدام الكاميرا بعد الحصول على مثيل من Camera
، ويجب توخّي الحذر بشكل خاص لإصدار عنصر الكاميرا عندما يتوقف تطبيقك عن استخدامه، وذلك فور إيقاف تطبيقك مؤقتًا (Activity.onPause()
). وإذا لم يحرر تطبيقك الكاميرا بشكل صحيح، ستفشل جميع المحاولات اللاحقة للوصول إلى الكاميرا، بما في ذلك تلك التي يجريها تطبيقك، وقد يؤدي ذلك إلى إغلاق تطبيقك أو تطبيقات أخرى.
لإصدار مثيل من العنصر Camera
، استخدِم الطريقة Camera.release()
، كما هو موضّح في مثال الرمز البرمجي أدناه.
Kotlin
class CameraActivity : Activity() { private var mCamera: Camera? private var preview: SurfaceView? private var mediaRecorder: MediaRecorder? override fun onPause() { super.onPause() releaseMediaRecorder() // if you are using MediaRecorder, release it first releaseCamera() // release the camera immediately on pause event } private fun releaseMediaRecorder() { mediaRecorder?.reset() // clear recorder configuration mediaRecorder?.release() // release the recorder object mediaRecorder = null mCamera?.lock() // lock camera for later use } private fun releaseCamera() { mCamera?.release() // release the camera for other applications mCamera = null } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private SurfaceView preview; private MediaRecorder mediaRecorder; ... @Override protected void onPause() { super.onPause(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private void releaseMediaRecorder(){ if (mediaRecorder != null) { mediaRecorder.reset(); // clear recorder configuration mediaRecorder.release(); // release the recorder object mediaRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } }
تنبيه: إذا لم يحرّر تطبيقك الكاميرا بشكل صحيح، ستفشل جميع المحاولات اللاحقة للوصول إلى الكاميرا، بما في ذلك تلك التي يجريها تطبيقك، وقد يؤدي ذلك إلى إغلاق تطبيقك أو تطبيقات أخرى.
حفظ ملفات الوسائط
يجب حفظ ملفات الوسائط التي ينشئها المستخدمون، مثل الصور والفيديوهات، في دليل وحدة التخزين الخارجية (بطاقة SD) بالجهاز للحفاظ على مساحة النظام وللسماح للمستخدمين بالوصول إلى هذه الملفات بدون أجهزتهم. هناك العديد من المواقع المحتملة للأدلة لحفظ ملفات الوسائط على الجهاز، ولكن هناك موقعان عاديان فقط يجب أن تأخذهما في الاعتبار كمطوّر:
-
Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_PICTURES
): تعرض هذه الطريقة الموقع الجغرافي العادي والمشترَك والمقترَح لحفظ الصور والفيديوهات. هذا الدليل مشترك (علني)، لذا يمكن للتطبيقات الأخرى العثور على الملفات المحفوظة في هذا الموقع الجغرافي وقراءتها وتغييرها وحذفها بسهولة. إذا أزال المستخدم تثبيت تطبيقك، لن تتم إزالة ملفات الوسائط المحفوظة في هذا الموقع. ولتجنُّب التداخل مع الصور والفيديوهات الحالية للمستخدمين، عليك إنشاء دليل فرعي لملفات الوسائط الخاصة بتطبيقك ضمن هذا الدليل، كما هو موضّح في نموذج الرمز البرمجي أدناه. تتوفّر هذه الطريقة في الإصدار 2.2 من نظام التشغيل Android (المستوى 8 من واجهة برمجة التطبيقات). وللاطّلاع على المكالمات المكافئة في إصدارات واجهة برمجة التطبيقات السابقة، راجِع حفظ الملفات المشترَكة. Context.getExternalFilesDir
(Environment.DIRECTORY_PICTURES
) - تعرض هذه الطريقة موقعًا جغرافيًا عاديًا لحفظ الصور والفيديوهات المرتبطة بتطبيقك. في حال إلغاء تثبيت تطبيقك، ستتم إزالة أي ملفات تم حفظها في هذا الموقع. لا يتم فرض الأمان على الملفات في هذا الموقع الجغرافي، وقد تتمكّن التطبيقات الأخرى من قراءتها وتغييرها وحذفها.
يوضّح نموذج الرمز التالي كيفية إنشاء موقع File
أو Uri
لملف وسائط يمكن استخدامه عند استدعاء كاميرا الجهاز باستخدام Intent
أو كجزء من إنشاء تطبيق كاميرا.
Kotlin
val MEDIA_TYPE_IMAGE = 1 val MEDIA_TYPE_VIDEO = 2 /** Create a file Uri for saving an image or video */ private fun getOutputMediaFileUri(type: Int): Uri { return Uri.fromFile(getOutputMediaFile(type)) } /** Create a File for saving an image or video */ private fun getOutputMediaFile(type: Int): File? { // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. val mediaStorageDir = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp" ) // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist mediaStorageDir.apply { if (!exists()) { if (!mkdirs()) { Log.d("MyCameraApp", "failed to create directory") return null } } } // Create a media file name val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) return when (type) { MEDIA_TYPE_IMAGE -> { File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg") } MEDIA_TYPE_VIDEO -> { File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4") } else -> null } }
Java
public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; /** Create a file Uri for saving an image or video */ private static Uri getOutputMediaFileUri(int type){ return Uri.fromFile(getOutputMediaFile(type)); } /** Create a File for saving an image or video */ private static File getOutputMediaFile(int type){ // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "MyCameraApp"); // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist if (! mediaStorageDir.exists()){ if (! mediaStorageDir.mkdirs()){ Log.d("MyCameraApp", "failed to create directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE){ mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg"); } else if(type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_"+ timeStamp + ".mp4"); } else { return null; } return mediaFile; }
ملاحظة: تتوفّر السمة Environment.getExternalStoragePublicDirectory()
في الإصدار 2.2 من نظام التشغيل Android (المستوى 8 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث. إذا كنت تستهدف أجهزة تعمل بإصدارات أقدم من Android، استخدِم Environment.getExternalStorageDirectory()
بدلاً من ذلك. لمزيد من المعلومات، يُرجى الاطّلاع على حفظ الملفات المشترَكة.
لإتاحة استخدام معرّف الموارد المنتظم (URI) في ملفات العمل، عليك أولاً
تحويل معرّف الموارد المنتظم للملف إلى معرّف موارد منتظم للمحتوى. بعد ذلك، أضِف معرّف الموارد المنتظم (URI) الخاص بالمحتوى إلى
EXTRA_OUTPUT
في Intent
.
لمزيد من المعلومات حول حفظ الملفات على جهاز Android، يُرجى الاطّلاع على تخزين البيانات.
ميزات الكاميرا
يتيح Android مجموعة كبيرة من ميزات الكاميرا التي يمكنك التحكّم فيها باستخدام تطبيق الكاميرا، مثل تنسيق الصورة ووضع الفلاش وإعدادات التركيز وغيرها الكثير. يسرد هذا القسم ميزات الكاميرا الشائعة، ويناقش بإيجاز كيفية استخدامها. يمكن الوصول إلى معظم ميزات الكاميرا وضبطها باستخدام العنصر Camera.Parameters
. ومع ذلك، هناك العديد من الميزات المهمة التي تتطلّب أكثر من مجرد إعدادات بسيطة في Camera.Parameters
. يتم تناول هذه الميزات في الأقسام التالية:
للحصول على معلومات عامة حول كيفية استخدام الميزات التي يتم التحكّم فيها من خلال Camera.Parameters
، راجِع قسم استخدام ميزات الكاميرا. للحصول على معلومات أكثر تفصيلاً حول كيفية استخدام الميزات التي يتم التحكّم فيها من خلال عنصر مَعلمات الكاميرا، اتّبِع الروابط في قائمة الميزات أدناه للانتقال إلى مستندات مرجع واجهة برمجة التطبيقات.
الجدول 1. ميزات الكاميرا الشائعة مرتّبة حسب مستوى واجهة برمجة تطبيقات Android الذي تم طرحها فيه
الميزة | مستوى واجهة برمجة التطبيقات | الوصف |
---|---|---|
التعرّف على الوجوه | 14 | التعرّف على وجوه الأشخاص في الصورة واستخدامها للتركيز وقياس الإضاءة وتوازن اللون الأبيض |
مناطق القياس | 14 | تحديد منطقة واحدة أو أكثر ضمن صورة لاحتساب توازن اللون الأبيض |
مجالات التركيز | 14 | تحديد منطقة واحدة أو أكثر ضمن صورة لاستخدامها في التركيز البؤري |
White Balance Lock |
14 | إيقاف التعديلات التلقائية لموازنة اللون الأبيض أو تفعيلها |
Exposure Lock |
14 | إيقاف تعديلات التعرّض للضوء التلقائية أو تفعيلها |
Video Snapshot |
14 | التقاط صورة أثناء تصوير فيديو (التقاط لقطة) |
فيديو التسريع الزمني | 11 | تسجيل لقطات مع تأخيرات محدّدة لتسجيل فيديو بوضع "التسريع الزمني" |
Multiple Cameras |
9 | إتاحة استخدام أكثر من كاميرا واحدة على الجهاز، بما في ذلك الكاميرات الأمامية والخلفية |
Focus Distance |
9 | تعرض المسافات بين الكاميرا والأجسام التي يبدو أنّها في نطاق التركيز |
Zoom |
8 | ضبط تكبير الصورة |
Exposure
Compensation |
8 | زيادة مستوى التعرّض للضوء أو خفضه |
GPS Data |
5 | تضمين بيانات الموقع الجغرافي مع الصورة أو حذفها |
White Balance |
5 | ضبط وضع توازن اللون الأبيض الذي يؤثر في قيم الألوان في الصورة الملتقطة |
Focus Mode |
5 | تحديد طريقة تركيز الكاميرا على أحد العناصر، مثل التركيز التلقائي أو الثابت أو الفائق أو البعيد |
Scene Mode |
5 | تطبيق وضع مُسبَق الضبط لأنواع معيّنة من حالات التصوير، مثل المشاهد الليلية أو الشاطئ أو الثلج أو ضوء الشموع |
JPEG Quality |
5 | ضبط مستوى الضغط لصورة JPEG، ما يؤدي إلى زيادة أو تقليل جودة وحجم ملف إخراج الصورة |
Flash Mode |
5 | تفعيل الفلاش أو إيقافه أو استخدام الإعداد التلقائي |
Color Effects |
5 | تطبيق تأثير لون على الصورة الملتقطة، مثل الأبيض والأسود أو اللون البني الداكن أو اللون السلبي |
Anti-Banding |
5 | يقلّل من تأثير التدرّج اللوني في تدرّجات الألوان بسبب ضغط JPEG |
Picture Format |
1 | تحديد تنسيق الملف للصورة |
Picture Size |
1 | تحديد أبعاد البكسل للصورة المحفوظة |
ملاحظة: لا تتوفّر هذه الميزات على جميع الأجهزة بسبب الاختلافات في الأجهزة وتنفيذ البرامج. للحصول على معلومات حول التحقّق من توفّر الميزات على الجهاز الذي يتم تشغيل تطبيقك عليه، يُرجى الاطّلاع على التحقّق من توفّر الميزات.
التحقّق من توفّر الميزات
أول ما يجب معرفته عند استخدام ميزات الكاميرا على أجهزة Android هو أنّ بعض ميزات الكاميرا غير متاحة على بعض الأجهزة. بالإضافة إلى ذلك، قد تتيح الأجهزة التي تتوافق مع ميزة معيّنة استخدامها بمستويات مختلفة أو مع خيارات مختلفة. لذلك، فإنّ جزءًا من عملية اتخاذ القرار أثناء تطوير تطبيق كاميرا هو تحديد ميزات الكاميرا التي تريد توفيرها ومستوى توفيرها. بعد اتّخاذ هذا القرار، عليك التخطيط لتضمين رمز برمجي في تطبيق الكاميرا يتحقّق مما إذا كانت أجهزة الجهاز تتوافق مع هذه الميزات، ويتم إيقاف التطبيق بشكل سليم في حال عدم توفّر إحدى الميزات.
يمكنك التحقّق من توفّر ميزات الكاميرا من خلال الحصول على مثيل لكائن مَعلمات الكاميرا والتحقّق من الطرق ذات الصلة. يوضّح نموذج الرمز البرمجي التالي كيفية الحصول على كائن
Camera.Parameters
والتحقّق مما إذا كانت الكاميرا تتوافق مع ميزة التركيز التلقائي:
Kotlin
val params: Camera.Parameters? = camera?.parameters val focusModes: List<String>? = params?.supportedFocusModes if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) { // Autofocus mode is supported }
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // Autofocus mode is supported }
يمكنك استخدام الأسلوب الموضّح أعلاه لمعظم ميزات الكاميرا. يوفّر الكائن Camera.Parameters
الطريقة getSupported...()
أو is...Supported()
أو getMax...()
لتحديد ما إذا كانت إحدى الميزات متوافقة (ومدى توافقها).
إذا كان تطبيقك يتطلّب ميزات معيّنة في الكاميرا لكي يعمل بشكل صحيح، يمكنك فرض استخدامها من خلال إضافة هذه الميزات إلى ملف بيان التطبيق. عند الإفصاح عن استخدام ميزات معيّنة في الكاميرا، مثل الفلاش والتركيز التلقائي، يمنع Google Play تثبيت تطبيقك على الأجهزة التي لا تتوافق مع هذه الميزات. للاطّلاع على قائمة بميزات الكاميرا التي يمكن الإفصاح عنها في بيان تطبيقك، راجِع مرجع الميزات في البيان.
استخدام ميزات الكاميرا
يتم تفعيل معظم ميزات الكاميرا والتحكّم فيها باستخدام عنصر Camera.Parameters
. يمكنك الحصول على هذا العنصر من خلال الحصول أولاً على مثيل من العنصر Camera
، ثم استدعاء الطريقة getParameters()
، وتغيير عنصر المَعلمات الذي تم عرضه، ثم إعادة ضبطه في عنصر الكاميرا، كما هو موضّح في مثال الرمز التالي:
Kotlin
val params: Camera.Parameters? = camera?.parameters params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO camera?.parameters = params
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters camera.setParameters(params);
تعمل هذه الطريقة مع جميع ميزات الكاميرا تقريبًا، ويمكن تغيير معظم المَعلمات في أي وقت بعد الحصول على مثيل من العنصر Camera
. تظهر عادةً التغييرات التي يتم إجراؤها على المَعلمات للمستخدم على الفور في معاينة الكاميرا داخل التطبيق.
من ناحية البرامج، قد يستغرق تطبيق تغييرات المَعلمات عدة لقطات لأنّ أجهزة الكاميرا تعالج التعليمات الجديدة ثم ترسل بيانات الصور المعدَّلة.
ملاحظة مهمة: لا يمكن تغيير بعض ميزات الكاميرا حسب الرغبة. على وجه الخصوص، يتطلّب تغيير حجم معاينة الكاميرا أو اتجاهها إيقاف المعاينة أولاً، ثم تغيير حجمها، ثم إعادة تشغيلها. بدءًا من الإصدار 4.0 من نظام التشغيل Android (المستوى 14 من واجهة برمجة التطبيقات)، يمكن تغيير اتجاه المعاينة بدون إعادة تشغيلها.
تتطلّب ميزات الكاميرا الأخرى المزيد من الرموز البرمجية لتنفيذها، بما في ذلك:
- القياس ومناطق التركيز
- التعرّف على الوجوه
- فيديو التسريع الزمني
في ما يلي مخطط سريع حول كيفية تنفيذ هذه الميزات.
القياس ومناطق التركيز
في بعض سيناريوهات التصوير، قد لا يؤدي التركيز التلقائي وقياس الإضاءة إلى النتائج المرجوة. بدءًا من الإصدار 4.0 من نظام التشغيل Android (المستوى 14 من واجهة برمجة التطبيقات)، يمكن لتطبيق الكاميرا توفير عناصر تحكّم إضافية للسماح لتطبيقك أو للمستخدمين بتحديد مناطق في الصورة لاستخدامها في تحديد إعدادات التركيز أو مستوى الإضاءة وتمرير هذه القيم إلى أجهزة الكاميرا لاستخدامها في التقاط الصور أو الفيديو.
تعمل مناطق القياس والتركيز بشكل مشابه جدًا لميزات الكاميرا الأخرى، حيث يمكنك التحكّم فيها من خلال طرق في العنصر Camera.Parameters
. يوضّح الرمز التالي كيفية ضبط منطقتَين لقياس الإضاءة في مثيل من Camera
:
Kotlin
// Create an instance of Camera camera = getCameraInstance() // set Camera parameters val params: Camera.Parameters? = camera?.parameters params?.apply { if (maxNumMeteringAreas > 0) { // check that metering areas are supported meteringAreas = ArrayList<Camera.Area>().apply { val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image add(Camera.Area(areaRect1, 600)) // set weight to 60% val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image add(Camera.Area(areaRect2, 400)) // set weight to 40% } } camera?.parameters = this }
Java
// Create an instance of Camera camera = getCameraInstance(); // set Camera parameters Camera.Parameters params = camera.getParameters(); if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60% Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40% params.setMeteringAreas(meteringAreas); } camera.setParameters(params);
يحتوي العنصر Camera.Area
على مَعلمتَي بيانات: العنصر Rect
لتحديد مساحة ضمن مجال رؤية الكاميرا وقيمة الوزن، والتي تحدد للكاميرا مستوى الأهمية الذي يجب أن توليه لهذه المساحة في قياس الضوء أو حسابات التركيز.
يصف الحقل Rect
في العنصر Camera.Area
شكلاً مستطيلاً يتم ربطه بشبكة وحدات 2000 × 2000. تمثّل الإحداثيتان -1000 و-1000 الزاوية العلوية اليمنى لصورة الكاميرا، وتمثّل الإحداثيتان 1000 و1000 الزاوية السفلية اليسرى لصورة الكاميرا، كما هو موضّح في الرسم التوضيحي أدناه.
الشكل 1. توضّح الخطوط الحمراء نظام الإحداثيات لتحديد Camera.Area
ضمن معاينة الكاميرا. يعرض المربّع الأزرق الموقع الجغرافي وشكل منطقة الكاميرا مع القيم Rect
333,333,667,667.
تتوافق حدود نظام الإحداثيات هذا دائمًا مع الحافة الخارجية للصورة المرئية في معاينة الكاميرا، ولا تتقلّص أو تتوسّع مع مستوى التكبير/التصغير. وبالمثل، فإنّ تدوير معاينة الصورة باستخدام Camera.setDisplayOrientation()
لا يعيد تعيين نظام الإحداثيات.
التعرّف على الوجوه
بالنسبة إلى الصور التي تتضمّن أشخاصًا، تكون الوجوه عادةً الجزء الأكثر أهمية في الصورة، ويجب استخدامها لتحديد كل من التركيز وتوازن اللون الأبيض عند التقاط صورة. يوفّر إطار عمل Android 4.0 (المستوى 14 لواجهة برمجة التطبيقات) واجهات برمجة تطبيقات لتحديد الوجوه واحتساب إعدادات الصور باستخدام تكنولوجيا التعرّف على الوجوه.
ملاحظة: أثناء تشغيل ميزة "التعرّف على الوجوه"، لن يكون هناك أي تأثير على setWhiteBalance(String)
وsetFocusAreas(List<Camera.Area>)
وsetMeteringAreas(List<Camera.Area>)
.
يتطلّب استخدام ميزة "التعرّف على الوجوه" في تطبيق الكاميرا اتّباع بعض الخطوات العامة:
- التأكّد من توفّر ميزة "التعرّف على الوجه" على الجهاز
- إنشاء أداة معالجة لعمليات رصد الوجوه
- إضافة أداة معالجة التعرّف على الوجوه إلى عنصر الكاميرا
- بدء رصد الوجوه بعد المعاينة (وبعد إعادة تشغيل المعاينة في كل مرة)
لا تتوفّر ميزة "التعرّف على الوجوه" على جميع الأجهزة. يمكنك التأكّد من أنّ هذه الميزة متاحة من خلال الاتصال بالرقم getMaxNumDetectedFaces()
. يتم عرض مثال على عملية التحقّق هذه في طريقة startFaceDetection()
النموذجية أدناه.
لكي تتلقّى إشعارات بشأن رصد وجه وتتمكّن من الردّ على ذلك، يجب أن يضبط تطبيق الكاميرا أداة معالجة لأحداث رصد الوجوه. لإجراء ذلك، يجب إنشاء فئة مستمع تنفّذ واجهة Camera.FaceDetectionListener
كما هو موضّح في نموذج الرمز البرمجي أدناه.
Kotlin
internal class MyFaceDetectionListener : Camera.FaceDetectionListener { override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) { if (faces.isNotEmpty()) { Log.d("FaceDetection", ("face detected: ${faces.size}" + " Face 1 Location X: ${faces[0].rect.centerX()}" + "Y: ${faces[0].rect.centerY()}")) } } }
Java
class MyFaceDetectionListener implements Camera.FaceDetectionListener { @Override public void onFaceDetection(Face[] faces, Camera camera) { if (faces.length > 0){ Log.d("FaceDetection", "face detected: "+ faces.length + " Face 1 Location X: " + faces[0].rect.centerX() + "Y: " + faces[0].rect.centerY() ); } } }
بعد إنشاء هذه الفئة، عليك ضبطها في عنصر Camera
الخاص بتطبيقك، كما هو موضّح في نموذج الرمز البرمجي أدناه:
Kotlin
camera?.setFaceDetectionListener(MyFaceDetectionListener())
Java
camera.setFaceDetectionListener(new MyFaceDetectionListener());
يجب أن يبدأ تطبيقك وظيفة رصد الوجه في كل مرة تبدأ فيها (أو تعيد تشغيل) معاينة الكاميرا. أنشئ طريقة لبدء عملية رصد الوجوه حتى تتمكّن من استدعائها عند الحاجة، كما هو موضّح في نموذج الرمز البرمجي أدناه.
Kotlin
fun startFaceDetection() { // Try starting Face Detection val params = mCamera?.parameters // start face detection only *after* preview has started params?.apply { if (maxNumDetectedFaces > 0) { // camera supports face detection, so can start it: mCamera?.startFaceDetection() } } }
Java
public void startFaceDetection(){ // Try starting Face Detection Camera.Parameters params = mCamera.getParameters(); // start face detection only *after* preview has started if (params.getMaxNumDetectedFaces() > 0){ // camera supports face detection, so can start it: mCamera.startFaceDetection(); } }
يجب بدء عملية رصد الوجه في كل مرة تبدأ فيها (أو تعيد بدء) معاينة الكاميرا. إذا كنت تستخدم فئة المعاينة الموضّحة في إنشاء فئة معاينة، أضِف طريقة startFaceDetection()
إلى كل من الطريقتين surfaceCreated()
وsurfaceChanged()
في فئة المعاينة، كما هو موضّح في نموذج الرمز البرمجي أدناه.
Kotlin
override fun surfaceCreated(holder: SurfaceHolder) { try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // start face detection feature } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { if (holder.surface == null) { // preview surface does not exist Log.d(TAG, "holder.getSurface() == null") return } try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: ${e.message}") } try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // re-start face detection feature } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: ${e.message}") } }
Java
public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // start face detection feature } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (holder.getSurface() == null){ // preview surface does not exist Log.d(TAG, "holder.getSurface() == null"); return; } try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // re-start face detection feature } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } }
ملاحظة: تذكَّر استدعاء هذه الطريقة بعد استدعاء
startPreview()
. لا تحاول بدء عملية رصد الوجوه في طريقة onCreate()
لنشاط تطبيق الكاميرا الرئيسي، لأنّ المعاينة لا تكون متاحة في هذه المرحلة من تنفيذ تطبيقك.
فيديو التسريع الزمني
يتيح فيديو الفاصل الزمني للمستخدمين إنشاء مقاطع فيديو تجمع بين صور تم التقاطها بفارق بضع ثوانٍ أو دقائق. تستخدِم هذه الميزة MediaRecorder
لتسجيل الصور في تسلسل
الفاصل الزمني.
لتسجيل فيديو في وضع التسريع الزمني باستخدام MediaRecorder
، عليك ضبط عنصر المسجّل كما لو كنت تسجّل فيديو عاديًا، مع ضبط عدد اللقطات التي يتم التقاطها في الثانية على عدد منخفض واستخدام أحد إعدادات جودة التسريع الزمني، كما هو موضّح في مثال الرمز البرمجي أدناه.
Kotlin
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)) mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds
Java
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); ... // Step 5.5: Set the video capture rate to a low number mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
يجب إجراء هذه الإعدادات كجزء من إجراء إعداد أكبر لـ MediaRecorder
. للاطّلاع على مثال كامل لرمز الإعداد، يُرجى الرجوع إلى إعداد MediaRecorder. بعد اكتمال عملية الضبط، ابدأ بتسجيل الفيديو كما لو كنت تسجّل مقطع فيديو عاديًا. لمزيد من المعلومات حول إعداد MediaRecorder
وتشغيله، يُرجى الاطّلاع على تسجيل الفيديوهات.
يقدّم نموذجا Camera2Video وHdrViewfinder توضيحًا إضافيًا حول كيفية استخدام واجهات برمجة التطبيقات الموضّحة في هذه الصفحة.
حقول الكاميرا التي تتطلّب إذنًا
يجب أن تتضمّن التطبيقات التي تعمل بالإصدار 10 من نظام التشغيل Android (المستوى 29 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث الإذن
CAMERA
من أجل
الوصول إلى قيم الحقول التالية التي تعرضها الطريقة
getCameraCharacteristics()
:
LENS_POSE_ROTATION
LENS_POSE_TRANSLATION
LENS_INTRINSIC_CALIBRATION
LENS_RADIAL_DISTORTION
LENS_POSE_REFERENCE
LENS_DISTORTION
LENS_INFO_HYPERFOCAL_DISTANCE
LENS_INFO_MINIMUM_FOCUS_DISTANCE
SENSOR_REFERENCE_ILLUMINANT1
SENSOR_REFERENCE_ILLUMINANT2
SENSOR_CALIBRATION_TRANSFORM1
SENSOR_CALIBRATION_TRANSFORM2
SENSOR_COLOR_TRANSFORM1
SENSOR_COLOR_TRANSFORM2
SENSOR_FORWARD_MATRIX1
SENSOR_FORWARD_MATRIX2
رمز نموذجي إضافي
لتنزيل تطبيقات نموذجية، اطّلِع على نموذج Camera2Basic و تطبيق CameraX النموذجي الرسمي.