معاينة الكاميرا

ملاحظة: تشير هذه الصفحة إلى حزمة camera2. ننصحك باستخدام cameraX ما لم يكن تطبيقك يتطلب ميزات محدّدة ومنخفضة المستوى من Camera2. يتوافق كل من CameraX و Camera2 مع الإصدار Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث.

لا تكون معاينات الكاميرات والكاميرا دائمًا في الاتجاه نفسه على أجهزة Android.

تكون الكاميرا في موضع ثابت على الجهاز، بصرف النظر عمّا إذا كان الجهاز هو الهاتف أو الجهاز اللوحي أو الكمبيوتر. عندما يتغير اتجاه الجهاز، يتغير اتجاه الكاميرا.

ونتيجةً لذلك، تفترض تطبيقات الكاميرا بشكل عام وجود علاقة ثابتة بين اتجاه الجهاز ونسبة العرض إلى الارتفاع لمعاينة الكاميرا. عندما يكون الهاتف في الاتجاه الرأسي، يُفترض أن تكون معاينة الكاميرا أطول من عرضها. عند تدوير الهاتف (والكاميرا) إلى الوضع الأفقي، من المتوقّع أن تكون معاينة الكاميرا أعرض من طولها.

ومع ذلك، تواجه هذه الافتراضات أشكالاً جديدة من أشكال الأجهزة، مثل الأجهزة القابلة للطي وأوضاع العرض، مثل النوافذ المتعددة وشاشات العرض المتعددة. تغيّر الأجهزة القابلة للطي حجم الشاشة ونسبة العرض إلى الارتفاع بدون تغيير الاتجاه. يؤدي وضع النوافذ المتعددة إلى تقييد تطبيقات الكاميرا بجزء من الشاشة، وتغيير حجم معاينة الكاميرا بغض النظر عن اتجاه الجهاز. يتيح وضع الشاشات المتعددة استخدام شاشات العرض الثانوية التي قد لا تكون في الاتجاه نفسه للشاشة الأساسية.

اتجاه الكاميرا

بينما يحدد تعريف التوافق مع Android أنه يجب توجيه مستشعر صور الكاميرا "حتى يتوافق البُعد الطويل للكاميرا مع البُعد الطويل للشاشة. أي، عندما يتم تثبيت الجهاز في الاتجاه الأفقي، يجب أن تلتقط الكاميرات الصور في الاتجاه الأفقي. وينطبق ذلك بغض النظر عن الاتجاه الطبيعي للجهاز، أي أنّه ينطبق على الأجهزة الأساسية في الوضع الأفقي وعلى الأجهزة الأساسية في الوضع العمودي".

تؤدي إعدادات الكاميرا إلى الشاشة إلى زيادة مساحة عرض عدسة الكاميرا في تطبيق الكاميرا. بالإضافة إلى ذلك، تُخرج أجهزة استشعار الصور بياناتها عادةً بنِسب عرض إلى ارتفاع أفقية، وتكون نسبة العرض إلى الارتفاع 4:3 هي الأكثر شيوعًا.

أداة استشعار الهاتف والكاميرا في الاتجاه العمودي
الشكل 1. العلاقة النموذجية بين الهاتف وجهاز الاستشعار في الكاميرا

يكون الاتجاه الطبيعي لجهاز استشعار الكاميرا في الوضع الأفقي. في الشكل 1، تم تدوير أداة استشعار الكاميرا الأمامية (الكاميرا الموجهة في نفس اتجاه الشاشة) بمقدار 270 درجة بالنسبة إلى الهاتف للتوافق مع تعريف التوافق مع Android.

لعرض دوران أداة الاستشعار على التطبيقات، تتضمّن واجهة برمجة التطبيقات camera2 قيمة ثابتة SENSOR_ORIENTATION ثابتة. بالنسبة إلى معظم الهواتف والأجهزة اللوحية، يبلغ الجهاز عن اتجاه أداة الاستشعار بمقدار 270 درجة للكاميرات الأمامية و90 درجة (نقطة رؤية من الجزء الخلفي من الجهاز) للكاميرات الخلفية، ما يؤدي إلى محاذاة الحافة الطويلة لأداة الاستشعار مع الحافة الطويلة للجهاز. تبلغ كاميرات الكمبيوتر المحمول بشكل عام اتجاه أداة الاستشعار 0 أو 180 درجة.

بما أنّ أدوات استشعار صور الكاميرا تُخرج بياناتها (مخزن صور مؤقت) في الاتجاه الطبيعي للمستشعر (أفقي)، يجب تدوير المخزن المؤقت للصور عدد الدرجات المحددة في SENSOR_ORIENTATION لكي تظهر معاينة الكاميرا في وضع عمودي في الاتجاه الطبيعي للجهاز. بالنسبة للكاميرات الأمامية، يكون الدوران عكس اتجاه عقارب الساعة، وبالنسبة للكاميرات الأمامية، يتم الدوران في اتجاه عقارب الساعة.

على سبيل المثال، بالنسبة للكاميرا الأمامية في الشكل 1، يبدو المخزن المؤقت للصور الذي أنتجه أداة استشعار الكاميرا على النحو التالي:

تم تدوير أداة استشعار الكاميرا إلى اتجاه أفقي مع صورة
            جانبية، أعلى اليسار.

يجب تدوير الصورة بزاوية 270 درجة عكس اتجاه عقارب الساعة بحيث يتطابق اتجاه المعاينة مع اتجاه الجهاز:

أداة استشعار الكاميرا في الاتجاه العمودي مع صورة عمودية.

تُنتج الكاميرا الخلفية مخزنًا مؤقتًا للصور بنفس اتجاه المخزن المؤقت أعلاه، ولكن تبلغ درجة SENSOR_ORIENTATION 90 درجة. ونتيجة لذلك، يتم تدوير المخزن المؤقت 90 درجة في اتجاه عقارب الساعة.

تدوير الجهاز

تدوير الجهاز هو عدد درجات تدوير الجهاز عن اتجاهه الطبيعي. على سبيل المثال، الهاتف في الاتجاه الأفقي له دوران الجهاز 90 أو 270 درجة، بناءً على اتجاه الدوران.

يجب تدوير المخزن المؤقت للصور الخاص بأداة استشعار الكاميرا بنفس عدد الدرجات التي يتم تدويرها في دوران الجهاز (بالإضافة إلى درجات اتجاه أداة الاستشعار) حتى تظهر معاينة الكاميرا في وضع عمودي.

حساب الاتجاه

ويراعي الاتجاه الصحيح لمعاينة الكاميرا اتجاه أداة الاستشعار ودوران الجهاز.

يمكن حساب الدوران الكلي للمخزن المؤقت لصور أداة الاستشعار باستخدام الصيغة التالية:

rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360

حيث sign هو 1 للكاميرات الأمامية و-1 للكاميرات الخلفية.

بالنسبة إلى الكاميرات الأمامية، يتم تدوير المخزن المؤقت للصور عكس اتجاه عقارب الساعة (من الاتجاه الطبيعي لأداة الاستشعار). في الكاميرات الخلفية، يتم تدوير المخزن المؤقت لصور أداة الاستشعار في اتجاه عقارب الساعة.

ويحوِّل التعبير deviceOrientationDegrees * sign + 360 دوران الجهاز من عكس اتجاه عقارب الساعة إلى اتجاه عقارب الساعة في الكاميرات الخلفية (على سبيل المثال، تحويل 270 درجة عكس اتجاه عقارب الساعة إلى 90 درجة في اتجاه عقارب الساعة). تعمل عملية باقي القسمة على تغيير حجم النتيجة إلى أقل من 360 درجة (على سبيل المثال، ضبط 540 درجة من التدوير إلى 180 درجة).

تبلغ واجهات برمجة التطبيقات المختلفة عن تدوير الجهاز بشكل مختلف:

  • توفِّر Display#getRotation() تدوير الجهاز عكس اتجاه عقارب الساعة (من منظور المستخدم). ويتم إدراج هذه القيمة في الصيغة أعلاه كما هي.
  • OrientationEventListener#onOrientationChanged() لعرض تدوير الجهاز في اتجاه عقارب الساعة (من وجهة نظر المستخدم). قم بإبطال القيمة للاستخدام في الصيغة أعلاه.

الكاميرات الأمامية

معاينة الكاميرا والمستشعر في الاتجاه الأفقي، تكون أداة الاستشعار بالاتجاه الأيمن.
الشكل 2. تم تحويل معاينة الكاميرا والأداة الاستشعار في الهاتف بمقدار 90 درجة إلى الاتجاه الأفقي.

في ما يلي المخزن المؤقت للصور الذي أنشأه مستشعر الكاميرا في الشكل 2:

أداة استشعار الكاميرا في الاتجاه الأفقي مع صورة عمودية

يجب تدوير المخزن المؤقت بمقدار 270 درجة عكس اتجاه عقارب الساعة لضبط اتجاه أداة الاستشعار (راجع اتجاه الكاميرا أعلاه):

تم تدوير أداة استشعار الكاميرا في اتجاه أفقي مع صورة جانبية،
            أعلى اليمين.

ثم يتم تدوير المخزن المؤقت بمقدار 90 درجة عكس اتجاه عقارب الساعة لحساب دوران الجهاز، مما يؤدي إلى الاتجاه الصحيح لمعاينة الكاميرا في الشكل 2:

تم تدوير أداة استشعار الكاميرا إلى اتجاه أفقي مع وضع الصورة في وضع عمودي.

في ما يلي الكاميرا تم تحويلها من اليمين إلى الاتجاه الأفقي:

معاينة الكاميرا وجهاز الاستشعار في الاتجاه الأفقي، ولكن
            أداة الاستشعار مقلوبة.
الشكل 3. تم تحويل معاينة الكاميرا وجهاز الاستشعار في الهاتف إلى 270 درجة (أو -90 درجة) إلى الاتجاه الأفقي.

إليك المخزن المؤقت للصور:

تم تدوير أداة استشعار الكاميرا إلى اتجاه أفقي مع إبقاء الصورة مقلوبة
            إلى الأسفل.

يجب تدوير المخزن المؤقت بمقدار 270 درجة عكس اتجاه عقارب الساعة لضبط اتجاه أداة الاستشعار:

تم تقييم أداة استشعار الكاميرا على الاتجاه العمودي مع صورة جانبية،
            أعلى اليسار.

ثم يتم تدوير المخزن المؤقت بمقدار 270 درجة عكس اتجاه عقارب الساعة لحساب دوران الجهاز:

تم تدوير أداة استشعار الكاميرا إلى اتجاه أفقي مع وضع الصورة في وضع عمودي.

الكاميرات الخلفية

يكون اتجاه الكاميرات الخلفية عادةً في اتجاه أداة الاستشعار يتجه بمقدار 90 درجة (كما هو موضّح من الجزء الخلفي من الجهاز). عند توجيه معاينة الكاميرا، يتم تدوير المخزن المؤقت للصور الخاص بأداة الاستشعار في اتجاه عقارب الساعة وفقًا لحجم دوران أداة الاستشعار (بدلاً من عكس اتجاه عقارب الساعة مثل الكاميرات الأمامية)، ثم يتم تدوير المخزن المؤقت للصور عكس اتجاه عقارب الساعة حسب مقدار دوران الجهاز.

معاينة الكاميرا وجهاز الاستشعار في الاتجاه الأفقي، ولكن
            أداة الاستشعار مقلوبة.
الشكل 4. هاتف مزوّد بكاميرا خلفية في الاتجاه الأفقي (باتجاه 270 أو -90 درجة).

في ما يلي المورد الاحتياطي للصور من مستشعر الكاميرا في الشكل 4:

تم تدوير أداة استشعار الكاميرا إلى اتجاه أفقي مع إبقاء الصورة مقلوبة
            إلى الأسفل.

يجب تدوير المخزن المؤقت بمقدار 90 درجة في اتجاه عقارب الساعة لضبط اتجاه أداة الاستشعار:

تم تقييم أداة استشعار الكاميرا على الاتجاه العمودي مع صورة جانبية،
            أعلى اليسار.

ثم يتم تدوير المخزن المؤقت بمقدار 270 درجة عكس اتجاه عقارب الساعة لحساب دوران الجهاز:

تم تدوير أداة استشعار الكاميرا إلى اتجاه أفقي مع وضع الصورة في وضع عمودي.

نسبة العرض إلى الارتفاع

تتغيّر نسبة العرض إلى الارتفاع عند تغيير اتجاه الجهاز، وأيضًا عند طي الجهاز القابل للطي وفتحه، وعند تغيير حجم النوافذ في بيئات متعددة النوافذ، وعند فتح التطبيقات على شاشات ثانوية.

يجب توجيه المخزن المؤقت للصور وقياسه ليلائم الاتجاه ونسبة العرض إلى الارتفاع لعنصر واجهة المستخدم في عدسة الكاميرا عندما تغيّر واجهة المستخدم الاتجاه ديناميكيًا، مع تغيير اتجاه الجهاز أو بدونه.

في أشكال الأجهزة الجديدة أو في البيئات التي تضمّ شاشات متعددة أو شاشات متعددة، إذا كان تطبيقك يفترض أنّ معاينة الكاميرا لها الاتجاه نفسه للجهاز (عمودي أو أفقي)، قد يتم توجيه المعاينة بشكل غير صحيح أو تغيير حجمها بشكل غير صحيح أو كليهما.

جهاز قابل للطي غير مطوي يعرض معاينة الكاميرا العمودية
            إلى جانب الشاشة
الشكل 5. يمكن تغيير نسبة العرض إلى الارتفاع في الجهاز القابل للطي من الوضع العمودي إلى الوضع الأفقي، ولكن تظل أداة استشعار الكاميرا في الاتجاه العمودي.

في الرسم 5، افترض التطبيق عن طريق الخطأ أنه تم تدوير الجهاز بمقدار 90 درجة عكس اتجاه عقارب الساعة، وبالتالي، قام التطبيق بتدوير المعاينة بنفس المقدار.

جهاز قابل للطي غير مطوي ومعاينة الكاميرا في وضع عمودي ولكن تم ضغطه
            بسبب ضبط الحجم بشكل غير صحيح.
الشكل 6. يمكن تغيير نسبة العرض إلى الارتفاع في الجهاز القابل للطي من الوضع العمودي إلى الوضع الأفقي، ولكن تظل أداة استشعار الكاميرا في الاتجاه العمودي.

في الشكل 6، لم يضبط التطبيق نسبة العرض إلى الارتفاع للمخزن المؤقت للصور لتمكينه من تغيير حجمه بشكل صحيح ليلائم الأبعاد الجديدة لعنصر واجهة المستخدم لمعاينة الكاميرا.

عادةً ما تواجه تطبيقات الكاميرا ذات الاتجاه الثابت مشاكل على الأجهزة القابلة للطي وغيرها من الأجهزة ذات الشاشات الكبيرة، مثل أجهزة الكمبيوتر المحمول:

تظهر معاينة الكاميرا على الكمبيوتر المحمول في وضع عمودي، فيما تظهر واجهة مستخدم التطبيق بشكل جانبي.
الشكل 7. تطبيق عمودي ثابت الاتجاه على جهاز كمبيوتر محمول.

في الشكل 7، تظهر واجهة المستخدم لتطبيق الكاميرا بشكل جانبي لأن اتجاه التطبيق يقتصر على الوضع العمودي فقط. يتم توجيه صورة عدسة الكاميرا بشكل صحيح بالنسبة إلى مستشعر الكاميرا،

إدراج وضع "بورتريه"

تطبيقات الكاميرا التي لا تتيح وضع النوافذ المتعددة (resizeableActivity="false") والتي تُقيِّد اتجاهها (screenOrientation="portrait" أو screenOrientation="landscape") يمكن وضعها في وضع "بورتريه" الداخلي على الأجهزة ذات الشاشات الكبيرة لتوجيه معاينة الكاميرا بشكل صحيح.

إدراج تطبيقات أفقية فقط في الوضع العمودي في الاتجاه العمودي حتى لو كانت نسبة العرض إلى الارتفاع للعرض أفقي يتم عرض التطبيقات ذات الوضع الأفقي فقط على أشرطة أفقية في الاتجاه الأفقي على الرغم من أن نسبة العرض إلى الارتفاع للعرض عمودي. يتم تدوير صورة الكاميرا لتتوافق مع واجهة مستخدم التطبيق، ويتم اقتصاصها لتتناسب مع نسبة العرض إلى الارتفاع لمعاينة الكاميرا، ثم تحجيمها لملء المعاينة.

يتم تفعيل وضع "بورتريه" المُدرج عندما لا تتطابق نسبة العرض إلى الارتفاع في أداة استشعار الصور في الكاميرا مع نسبة العرض إلى الارتفاع للنشاط الأساسي للتطبيق.

معاينة الكاميرا وواجهة مستخدم التطبيق في الاتجاه العمودي الصحيح على الكمبيوتر المحمول.
            يتم تغيير حجم صورة المعاينة العريضة واقتصاصها لتلائم الاتجاه العمودي.
الشكل 8. تطبيق عمودي ثابت الاتجاه في وضع "بورتريه" داخلي على الكمبيوتر المحمول.

في الشكل 8، تم تدوير تطبيق الكاميرا العمودية فقط لعرض واجهة المستخدم في وضع عمودي على شاشة الكمبيوتر المحمول. تم عرض التطبيق على شاشة عريضة أفقيًا بسبب الفرق في نسبة العرض إلى الارتفاع بين تطبيق العرض العمودي والعرض الأفقي. تم تدوير صورة معاينة الكاميرا لتعويض تدوير واجهة مستخدم التطبيق (بسبب الوضع العمودي المُدرج)، وتم اقتصاص الصورة وتغيير حجمها لتلائم الاتجاه الرأسي، مما يقلل من مجال الرؤية.

التدوير، الاقتصاص، تغيير الحجم

يتم استدعاء وضع "بورتريه" المدرَج في تطبيق كاميرا عمودي فقط على شاشة تتضمّن نسبة عرض إلى ارتفاع أفقية:

تظهر معاينة الكاميرا على الكمبيوتر المحمول في وضع عمودي، فيما تظهر واجهة مستخدم التطبيق بشكل جانبي.
الشكل 9. تطبيق عمودي ثابت الاتجاه على الكمبيوتر المحمول.

يظهر التطبيق على شاشة عريضة أفقيًا بتنسيق عمودي:

تم تدوير التطبيق إلى الاتجاه العمودي ووضع العرض الأفقي على شاشة عريضة أفقيًا. الصورة جانبية، أعلى اليسار.

تم تدوير صورة الكاميرا بمقدار 90 درجة لتعديل اتجاه التطبيق:

تم تدوير صورة جهاز الاستشعار بزاوية 90 درجة لجعلها في وضع مستقيم.

يتم اقتصاص الصورة إلى نسبة العرض إلى الارتفاع لمعاينة الكاميرا، ثم يتم تغيير حجمها لملء المعاينة (يتم تقليل مجال الرؤية):

تم اقتصاص صورة الكاميرا تم تغيير حجمها لملء معاينة الكاميرا.

على الأجهزة القابلة للطي، يمكن أن يكون اتجاه أداة استشعار الكاميرا عموديًا بينما تكون نسبة العرض إلى الارتفاع للشاشة في الوضع الأفقي:

معاينة الكاميرا وواجهة مستخدم التطبيق تحولت إلى جانبي الشاشة العريضة غير المطوية.
الشكل 10. جهاز غير مطوي يتضمن تطبيق كاميرا عمودي فقط ونِسب عرض إلى ارتفاع مختلفة لجهاز الاستشعار في الكاميرا وشاشة العرض

نظرًا لتدوير معاينة الكاميرا لضبط اتجاه أداة الاستشعار، يتم توجيه الصورة بشكل صحيح في نطاق عدسة الكاميرا، ولكن يتم توجيه التطبيق في الوضع الرأسي فقط إلى الجانبين.

في وضع "بورتريه"، يجب إدراج التطبيق في شاشة عريضة أفقيًا من أجل توجيه التطبيق ومعاينة الكاميرا بشكل صحيح:

تطبيق مُعدّ للعرض على شاشة عريضة أفقيًا بتنسيق أفقي مع إمكانية معاينة الكاميرا
            بشكل عمودي على الجهاز القابل للطي

واجهة برمجة التطبيقات

بدءًا من نظام التشغيل Android 12 (المستوى 31 من واجهة برمجة التطبيقات)، يمكن أيضًا للتطبيقات التحكم صراحةً في الوضع العمودي المُدرج باستخدام سمة SCALER_ROTATE_AND_CROP من الفئة CaptureRequest.

والقيمة التلقائية هي SCALER_ROTATE_AND_CROP_AUTO، والتي تتيح للنظام استدعاء وضع "بورتريه" الداخلي. SCALER_ROTATE_AND_CROP_90 هو سلوك وضع "بورتريه" الداخلي كما هو موضَّح أعلاه.

لا تتوافق بعض الأجهزة مع جميع قيم SCALER_ROTATE_AND_CROP. للحصول على قائمة بالقيم المسموح بها، ارجِع إلى CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.

كاميراX

تجعل مكتبة Jetpack CameraX إنشاء منظار كاميرا يتناسب مع اتجاه أداة الاستشعار وتدوير الجهاز مهمة بسيطة.

ينشئ عنصر التنسيق PreviewView معاينة للكاميرا، ويتم تعديله تلقائيًا حسب اتجاه أداة الاستشعار، وتدوير الجهاز، وتغيير الحجم. يحافظ PreviewView على نسبة العرض إلى الارتفاع لصورة الكاميرا من خلال تطبيق نوع المقياس FILL_CENTER الذي يعمل على توسيط الصورة ولكن قد يتم اقتصاصها لتتناسب مع أبعاد PreviewView. لعرض صورة الكاميرا على شاشة عريضة أفقيًا، اضبط نوع المقياس على FIT_CENTER.

للتعرّف على أساسيات إنشاء معاينة للكاميرا باستخدام "PreviewView"، يُرجى الاطّلاع على تنفيذ معاينة.

للحصول على نموذج تنفيذ كامل، يُرجى الاطّلاع على مستودع CameraXBasic على GitHub.

عدسة الكاميرا

وعلى غرار حالة استخدام Preview (معاينة)، توفر مكتبة cameraViewfinder مجموعة من الأدوات لتبسيط عملية إنشاء معاينة للكاميرا. ولا يعتمد ذلك على CameraX Core، لذا يمكنك دمجه بسلاسة مع قاعدة رموز Camera2 الحالية.

بدلاً من استخدام Surface بشكل مباشر، يمكنك استخدام التطبيق المصغّر CameraViewfinder لعرض خلاصة الكاميرا للكاميرا2.

تستخدم CameraViewfinder داخليًا إما TextureView أو SurfaceView لعرض خلاصة الكاميرا، وتطبق التحويلات المطلوبة عليها لعرض عدسة الكاميرا بشكل صحيح. ويشمل ذلك تصحيح نسبة العرض إلى الارتفاع والمقياس والتدوير.

لطلب السطح من العنصر CameraViewfinder، عليك إنشاء ViewfinderSurfaceRequest.

يحتوي هذا الطلب على متطلبات متعلقة بدرجة دقة السطح ومعلومات جهاز الكاميرا من CameraCharacteristics.

يؤدي الاتصال بالرقم requestSurfaceAsync() إلى إرسال الطلب إلى مقدّم مساحة العرض، والذي يكون إما TextureView أو SurfaceView، ويحصل على ListenableFuture بقيمة Surface.

يؤدي الاتصال بالرقم markSurfaceSafeToRelease() إلى إعلام مقدّم مساحة العرض بأنّ سطح المكتب غير مطلوب وأنّه يمكن إصدار الموارد ذات الصلة.

Kotlin


fun startCamera(){
    val previewResolution = Size(width, height)
    val viewfinderSurfaceRequest =
        ViewfinderSurfaceRequest(previewResolution, characteristics)
    val surfaceListenableFuture =
        cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)

    Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
        override fun onSuccess(surface: Surface) {
            /* create a CaptureSession using this surface as usual */
        }
        override fun onFailure(t: Throwable) { /* something went wrong */}
    }, ContextCompat.getMainExecutor(context))
}

Java


    void startCamera(){
        Size previewResolution = new Size(width, height);
        ViewfinderSurfaceRequest viewfinderSurfaceRequest =
                new ViewfinderSurfaceRequest(previewResolution, characteristics);
        ListenableFuture<Surface> surfaceListenableFuture =
                cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest);

        Futures.addCallback(surfaceListenableFuture, new FutureCallback<Surface>() {
            @Override
            public void onSuccess(Surface result) {
                /* create a CaptureSession using this surface as usual */
            }
            @Override public void onFailure(Throwable t) { /* something went wrong */}
        },  ContextCompat.getMainExecutor(context));
    }

SurfaceView

تمثِّل السمة SurfaceView طريقة واضحة لإنشاء معاينة للكاميرا إذا لم تكن المعاينة تتطلّب معالجة وليست متحركة.

يعمل SurfaceView تلقائيًا على تدوير المخزن المؤقت للصور لجهاز استشعار الكاميرا ليلائم اتجاه العرض، مع مراعاة اتجاه أداة الاستشعار وتدوير الجهاز معًا. ومع ذلك، يتم تغيير حجم المخزن المؤقت للصور ليلائم أبعاد SurfaceView بدون أي أخذ في الاعتبار نسبة العرض إلى الارتفاع.

يجب التأكّد من أنّ نسبة العرض إلى الارتفاع للمخزن المؤقت للصور تطابق نسبة العرض إلى الارتفاع في SurfaceView، وهو ما يمكنك تحقيقه من خلال تغيير حجم محتوى SurfaceView في طريقة onMeasure() المكوِّن:

(رمز المصدر computeRelativeRotation() في قسم التناوب النسبي أدناه).

Kotlin

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val width = MeasureSpec.getSize(widthMeasureSpec)
    val height = MeasureSpec.getSize(heightMeasureSpec)

    val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees)

    if (previewWidth > 0f && previewHeight > 0f) {
        /* Scale factor required to scale the preview to its original size on the x-axis. */
        val scaleX =
            if (relativeRotation % 180 == 0) {
                width.toFloat() / previewWidth
            } else {
                width.toFloat() / previewHeight
            }
        /* Scale factor required to scale the preview to its original size on the y-axis. */
        val scaleY =
            if (relativeRotation % 180 == 0) {
                height.toFloat() / previewHeight
            } else {
                height.toFloat() / previewWidth
            }

        /* Scale factor required to fit the preview to the SurfaceView size. */
        val finalScale = min(scaleX, scaleY)

        setScaleX(1 / scaleX * finalScale)
        setScaleY(1 / scaleY * finalScale)
    }
    setMeasuredDimension(width, height)
}

Java

@Override
void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees);

    if (previewWidth > 0f && previewHeight > 0f) {

        /* Scale factor required to scale the preview to its original size on the x-axis. */
        float scaleX = (relativeRotation % 180 == 0)
                       ? (float) width / previewWidth
                       : (float) width / previewHeight;

        /* Scale factor required to scale the preview to its original size on the y-axis. */
        float scaleY = (relativeRotation % 180 == 0)
                       ? (float) height / previewHeight
                       : (float) height / previewWidth;

        /* Scale factor required to fit the preview to the SurfaceView size. */
        float finalScale = Math.min(scaleX, scaleY);

        setScaleX(1 / scaleX * finalScale);
        setScaleY(1 / scaleY * finalScale);
    }
    setMeasuredDimension(width, height);
}

للمزيد من التفاصيل حول تطبيق SurfaceView كمعاينة للكاميرا، يُرجى الاطّلاع على اتجاهات الكاميرا.

عرض الزخرفة

إنّ أداء TextureView أقل من SurfaceView ومزيد من العمل، إلا أنّ TextureView يمنحك أقصى قدرة على التحكّم في معاينة الكاميرا.

يعمل TextureView على تدوير المخزن المؤقت لصور أداة الاستشعار بناءً على اتجاه أداة الاستشعار، ولكنّه لا يعالج تدوير الجهاز أو ضبط حجم المعاينة.

يمكن ترميز تغيير الحجم والتدوير في تحويل مصفوفة. للتعرّف على طريقة ضبط حجم جهاز TextureView وتدويره بشكل صحيح، يمكنك الاطّلاع على إتاحة المساحات التي يمكن تغيير حجمها في تطبيق الكاميرا.

الدوران النسبي

الدوران النسبي لجهاز استشعار الكاميرا هو مقدار الدوران المطلوب لمحاذاة ناتج أداة استشعار الكاميرا مع اتجاه الجهاز.

يتم استخدام التدوير النسبي بواسطة مكونات مثل SurfaceView وTextureView لتحديد عوامل ضبط الحجم x وy لصورة المعاينة. ويُستخدم أيضًا لتحديد دوران المخزن المؤقت لصور أداة الاستشعار.

تتيح فئتا CameraCharacteristics وSurface حساب الدوران النسبي لمستشعر الكاميرا:

Kotlin

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public fun computeRelativeRotation(
    characteristics: CameraCharacteristics,
    surfaceRotationDegrees: Int
): Int {
    val sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)!!

    // Reverse device orientation for back-facing cameras.
    val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT
    ) 1 else -1

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360
}

Java

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public int computeRelativeRotation(
    CameraCharacteristics characteristics,
    int surfaceRotationDegrees
){
    Integer sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

    // Reverse device orientation for back-facing cameras.
    int sign = characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT ? 1 : -1;

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360;
}

مقاييس الفترة الزمنية

يجب عدم استخدام حجم الشاشة لتحديد أبعاد عدسة الكاميرا، لأنّ تطبيق الكاميرا قد يكون يعمل في جزء من الشاشة، سواء في وضع النوافذ المتعددة على الأجهزة الجوّالة أو الوضع "بدون استخدام" على ChromeOS.

WindowManager#getCurrentWindowMetrics() (مُضاف في المستوى 30 من واجهة برمجة التطبيقات) يعرض حجم نافذة التطبيق بدلاً من حجم الشاشة. توفّر طريقتا مكتبة Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() وWindowInfoTracker#currentWindowMetrics() دعمًا مماثلاً بالتوافق مع الأنظمة القديمة لمستوى واجهة برمجة التطبيقات 14.

التدوير بمقدار 180 درجة

لا يؤدي تدوير الجهاز بزاوية 180 درجة (على سبيل المثال، من الاتجاه الطبيعي إلى الاتجاه الطبيعي المقلوب) إلى تشغيل معاودة الاتصال onConfigurationChanged(). ونتيجةً لذلك، قد تكون معاينة الكاميرا مقلوبة.

لاكتشاف تدوير 180 درجة، نفِّذ DisplayListener وتحقَّق من تدوير الجهاز من خلال إدخال طلب إلى Display#getRotation() في onDisplayChanged() معاودة الاتصال.

مراجع حصرية

قبل نظام Android 10، كان أعلى نشاط مرئي في البيئة المتعددة النوافذ هو في حالة RESUMED. كان هذا مربكًا للمستخدمين لأن النظام لم يقدم أي إشارة إلى النشاط الذي تم استئنافه.

قدّم Android 10 (المستوى 29 من واجهة برمجة التطبيقات) ميزة الاستئناف المتعدد حيث تظهر جميع الأنشطة المرئية في حالة RESUMED. قد تظل الأنشطة المرئية تدخل حالة PAUSED إذا كان، على سبيل المثال، نشاط شفاف في أعلى النشاط أو عدم إمكانية التركيز على النشاط، كما هو الحال في وضع "نافذة ضمن النافذة" (راجِع دعم ميزة "نافذة ضمن النافذة").

التطبيق الذي يستخدم الكاميرا أو الميكروفون أو أي مورد حصري أو مورد سينغلتون على المستوى 29 لواجهة برمجة التطبيقات أو مستوى أعلى يجب أن يدعم الاستئناف المتعدد. على سبيل المثال، إذا أرادت ثلاثة أنشطة تم استئنافها استخدام الكاميرا، فلن يتمكن سوى نشاط واحد من الوصول إلى هذا المورد الحصري. يجب تنفيذ استدعاء onDisconnected() في كل نشاط ليكون على عِلم بالوصول الاستباقي إلى الكاميرا من خلال نشاط ذي أولوية أعلى.

لمزيد من المعلومات، يُرجى الاطّلاع على صفحة السيرة الذاتية المتعددة.

مراجع إضافية

  • للحصول على نموذج من Camera2، يُرجى الاطّلاع على تطبيق Camera2Basic على GitHub.
  • للحصول على معلومات حول حالة استخدام معاينة تطبيق CameraX، يمكنك الاطّلاع على تطبيق CameraX تنفيذ معاينة.
  • للاطّلاع على نموذج لتنفيذ معاينة كاميرا CameraX، يُرجى مراجعة مستودع CameraXBasic على GitHub.
  • للحصول على معلومات حول معاينة الكاميرا في نظام التشغيل ChromeOS، يُرجى الاطّلاع على اتجاهات الكاميرا.
  • للحصول على معلومات حول التطوير للأجهزة القابلة للطي، يُرجى الاطّلاع على التعرّف على الأجهزة القابلة للطي.