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

ملاحظة: تشير هذه الصفحة إلى حزمة Camera2. ننصحك باستخدام الكاميراX ما لم يكن تطبيقك يتطلب ميزات محدَّدة منخفضة المستوى من تطبيق 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 على جيت هب.

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

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

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

يستخدم 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() لمعاودة الاتصال بك بشأن الوصول الاستباقي إلى الكاميرا بأولوية أعلى الأخرى.

لمزيد من المعلومات، يُرجى مراجعة السير الذاتية المتعددة:

مصادر إضافية