پیش نمایش دوربین

توجه: این صفحه به پکیج Camera2 اشاره دارد. توصیه می‌کنیم از CameraX استفاده کنید، مگر اینکه برنامه شما به ویژگی‌های خاص و سطح پایین Camera2 نیاز داشته باشد. هر دو CameraX و Camera2 از اندروید 5.0 (سطح API 21) و بالاتر پشتیبانی می کنند.

دوربین‌ها و پیش‌نمایش‌های دوربین همیشه در دستگاه‌های Android در یک جهت نیستند.

دوربین بدون توجه به اینکه دستگاه تلفن، تبلت یا رایانه باشد، در موقعیت ثابتی روی دستگاه قرار دارد. هنگامی که جهت دستگاه تغییر می کند، جهت دوربین تغییر می کند.

در نتیجه، برنامه‌های دوربین معمولاً یک رابطه ثابت بین جهت دستگاه و نسبت تصویر پیش‌نمایش دوربین را فرض می‌کنند. هنگامی که یک تلفن در جهت عمودی است، پیش‌نمایش دوربین بلندتر از عریض فرض می‌شود. هنگامی که تلفن (و دوربین) به حالت افقی چرخانده می شوند، انتظار می رود پیش نمایش دوربین عریض تر از ارتفاع آن باشد.

اما این مفروضات توسط عوامل شکل جدید، مانند دستگاه های تاشو ، و حالت های نمایش مانند چند پنجره ای و چند صفحه ای به چالش کشیده می شوند. دستگاه های تاشو بدون تغییر جهت، اندازه و نسبت تصویر را تغییر می دهند. حالت چند پنجره‌ای، برنامه‌های دوربین را به بخشی از صفحه محدود می‌کند و پیش‌نمایش دوربین را بدون توجه به جهت‌گیری دستگاه، مقیاس‌بندی می‌کند. حالت چند نمایشگر استفاده از نمایشگرهای ثانویه را که ممکن است در جهتی یکسان با نمایشگر اصلی نباشند را امکان پذیر می کند.

جهت گیری دوربین

تعریف سازگاری اندروید مشخص می کند که حسگر تصویر دوربین "باید به گونه ای جهت گیری شود که بعد طولانی دوربین با بعد طولانی صفحه نمایش همراستا شود. یعنی وقتی دستگاه در جهت افقی نگه داشته شود، دوربین ها باید تصاویر را در جهت افقی بگیرند. این بدون در نظر گرفتن جهت گیری طبیعی دستگاه اعمال می شود، یعنی برای دستگاه های اصلی افقی و همچنین دستگاه های عمودی اعمال می شود.

چینش دوربین به صفحه نمایش، ناحیه نمایش منظره یاب دوربین را در برنامه دوربین به حداکثر می رساند. همچنین، سنسورهای تصویر معمولاً داده‌های خود را در نسبت‌های منظره خروجی می‌دهند که رایج‌ترین آنها 4:3 است.

حسگر تلفن و دوربین هر دو در جهت عمودی.
شکل 1. رابطه معمولی جهت گیری حسگر گوشی و دوربین.

جهت طبیعی سنسور دوربین افقی است. در شکل 1، سنسور دوربین جلو (دوربین که در جهت نمایشگر قرار دارد) 270 درجه نسبت به گوشی چرخانده شده است تا با تعریف سازگاری اندروید مطابقت داشته باشد.

برای نمایش چرخش حسگر در برنامه‌ها، API 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).

API های مختلف چرخش دستگاه را متفاوت گزارش می کنند:

  • Display#getRotation() چرخش دستگاه را در خلاف جهت عقربه های ساعت (از دید کاربر) فراهم می کند. این مقدار همانطور که هست به فرمول بالا متصل می شود.
  • OrientationEventListener#onOrientationChanged() چرخش در جهت عقربه های ساعت دستگاه (از دید کاربر) را برمی گرداند. مقدار مورد استفاده در فرمول بالا را نفی کنید.

دوربین های جلو

پیش نمایش دوربین و سنسور هر دو در جهت افقی، سنسور سمت راست به بالا است.
شکل 2. پیش نمایش دوربین و سنسور با چرخش 90 درجه ای تلفن به جهت افقی.

بافر تصویر تولید شده توسط سنسور دوربین در شکل 2 در اینجا آمده است:

سنسور دوربین در جهت افقی با تصویر عمودی.

برای تنظیم جهت سنسور، بافر باید 270 درجه در خلاف جهت عقربه های ساعت چرخانده شود (به جهت دوربین در بالا مراجعه کنید):

سنسور دوربین به جهت عمودی با تصویر به پهلو، بالا سمت راست چرخید.

سپس بافر 90 درجه اضافی در خلاف جهت عقربه‌های ساعت چرخانده می‌شود تا چرخش دستگاه را در نظر بگیرد، که منجر به جهت‌گیری صحیح پیش‌نمایش دوربین در شکل 2 می‌شود:

سنسور دوربین در جهت افقی با تصویر به صورت عمودی چرخیده است.

در اینجا دوربین به سمت راست به جهت افقی چرخیده است:

پیش نمایش دوربین و سنسور هر دو در جهت افقی هستند، اما سنسور وارونه است.
شکل 3. پیش نمایش دوربین و حسگر با تلفن 270 درجه (یا 90- درجه) جهت جهت افقی.

بافر تصویر اینجاست:

سنسور دوربین با جهت گیری افقی با تصویر وارونه چرخش کرد.

برای تنظیم جهت سنسور، بافر باید 270 درجه در خلاف جهت عقربه های ساعت چرخانده شود:

سنسور دوربین به جهت عمودی با تصویر به طرف، بالا سمت چپ رتبه بندی شده است.

سپس بافر 270 درجه دیگر در خلاف جهت عقربه های ساعت چرخانده می شود تا چرخش دستگاه محاسبه شود:

سنسور دوربین در جهت افقی با تصویر به صورت عمودی چرخیده است.

دوربین های پشتی

دوربین های پشتی معمولاً جهت سنسور 90 درجه دارند (همانطور که از پشت دستگاه مشاهده می شود). هنگام جهت‌دهی پیش‌نمایش دوربین، بافر تصویر حسگر بر اساس میزان چرخش سنسور در جهت عقربه‌های ساعت می‌چرخد (به جای خلاف جهت عقربه‌های ساعت مانند دوربین‌های جلو)، و سپس بافر تصویر بر اساس میزان چرخش دستگاه در خلاف جهت عقربه‌های ساعت می‌چرخد.

پیش نمایش دوربین و سنسور هر دو در جهت افقی هستند، اما سنسور وارونه است.
شکل 4. تلفن با دوربین پشت در جهت افقی (270 یا 90- درجه چرخیده).

بافر تصویر از سنسور دوربین در شکل 4 آمده است:

سنسور دوربین با جهت گیری افقی با تصویر وارونه چرخش کرد.

برای تنظیم جهت سنسور، بافر باید 90 درجه در جهت عقربه های ساعت چرخانده شود:

سنسور دوربین به جهت عمودی با تصویر به طرف، بالا سمت چپ رتبه بندی شده است.

سپس بافر 270 درجه در خلاف جهت عقربه های ساعت چرخانده می شود تا چرخش دستگاه را محاسبه کند:

سنسور دوربین در جهت افقی با تصویر به صورت عمودی چرخیده است.

نسبت ابعاد

نسبت صفحه نمایش زمانی که جهت دستگاه تغییر می کند، اما همچنین زمانی که تاشوها تا می شوند و باز می شوند، زمانی که پنجره ها در محیط های چند پنجره ای تغییر اندازه می دهند، و زمانی که برنامه ها در نمایشگرهای ثانویه باز می شوند، تغییر می کند.

بافر تصویر حسگر دوربین باید جهت یابی و مقیاس بندی شود تا با جهت و نسبت ابعاد عنصر UI منظره یاب مطابقت داشته باشد، زیرا رابط کاربری به صورت پویا جهت را تغییر می دهد - با یا بدون تغییر جهت دستگاه.

در فاکتورهای فرم جدید یا در محیط‌های چند پنجره‌ای یا چند صفحه‌ای، اگر برنامه شما فرض می‌کند که پیش‌نمایش دوربین جهت‌گیری یکسانی با دستگاه دارد (عمودی یا افقی)، ممکن است پیش‌نمایش شما نادرست، مقیاس نادرست یا هر دو باشد.

دستگاه تاشو باز شده با پیش‌نمایش دوربین پرتره که به طرفین چرخانده شده است.
شکل 5. دستگاه تاشو از نسبت تصویر عمودی به منظره تغییر می کند، اما حسگر دوربین در جهت عمودی باقی می ماند.

در شکل 5، برنامه به اشتباه دستگاه را 90 درجه در خلاف جهت عقربه های ساعت چرخانده است. و بنابراین، برنامه پیش نمایش را به همان میزان چرخاند.

دستگاه تاشو باز شده با پیش‌نمایش دوربین در حالت عمودی، اما به دلیل مقیاس نادرست له شده است.
شکل 6. دستگاه تاشو از نسبت تصویر عمودی به منظره تغییر می کند اما حسگر دوربین در جهت عمودی باقی می ماند.

در شکل 6، برنامه نسبت ابعاد بافر تصویر را تنظیم نکرده است تا بتواند به درستی مقیاس شود تا با ابعاد جدید عنصر رابط کاربری پیش‌نمایش دوربین سازگار باشد.

برنامه‌های دوربین با جهت ثابت معمولاً در دستگاه‌های تاشو و سایر دستگاه‌های صفحه بزرگ مانند لپ‌تاپ با مشکلاتی مواجه می‌شوند:

پیش‌نمایش دوربین در لپ‌تاپ به صورت عمودی است، اما رابط کاربری برنامه در کناره است.
شکل 7. برنامه پرتره با جهت ثابت در رایانه لپ تاپ.

در شکل 7، رابط کاربری برنامه دوربین به صورت جانبی است، زیرا جهت گیری برنامه فقط به حالت عمودی محدود شده است. جهت گیری تصویر منظره یاب نسبت به سنسور دوربین درست است.

درج حالت پرتره

برنامه‌های دوربینی که از حالت چندپنجره‌ای ( resizeableActivity="false" ) پشتیبانی نمی‌کنند و جهت آن‌ها را محدود می‌کنند ( screenOrientation="portrait" یا screenOrientation="landscape" ) می‌توانند در حالت عمودی داخلی در دستگاه‌های صفحه بزرگ قرار بگیرند تا دوربین را به درستی جهت دهی کنند. پیش نمایش.

با وجود اینکه نسبت ابعاد نمایشگر افقی است، صندوق‌های نامه حالت عمودی (inset) برنامه‌های فقط عمودی را در جهت عمودی قرار دهید. برنامه‌های فقط منظره در جهت افقی جعبه نامه هستند، حتی اگر نسبت صفحه نمایش به صورت عمودی باشد. تصویر دوربین چرخانده می‌شود تا با رابط کاربری برنامه هماهنگ شود، برش داده می‌شود تا با نسبت تصویر پیش‌نمایش دوربین مطابقت داشته باشد، و سپس برای پر کردن پیش‌نمایش مقیاس‌گذاری می‌شود.

حالت عمودی ورودی زمانی فعال می شود که نسبت ابعاد سنسور تصویر دوربین و نسبت تصویر فعالیت اصلی برنامه مطابقت نداشته باشند.

پیش نمایش دوربین و رابط کاربری برنامه در جهت گیری پرتره مناسب در لپ تاپ.             تصویر پیش‌نمایش عریض برای تناسب با جهت پرتره، کوچک و برش داده می‌شود.
شکل 8. برنامه پرتره با جهت ثابت در حالت عمودی داخل لپ تاپ.

در شکل 8، برنامه دوربین فقط پرتره چرخانده شده است تا رابط کاربری را به صورت عمودی بر روی صفحه نمایش لپ تاپ نمایش دهد. این برنامه به دلیل تفاوت در نسبت تصویر بین برنامه پرتره و صفحه نمایش افقی دارای جعبه نامه است. تصویر پیش‌نمایش دوربین برای جبران چرخش رابط کاربری برنامه (به دلیل حالت عمودی درج شده) چرخانده شده است، و تصویر برش داده شده و برای تناسب با جهت پرتره کوچک شده است و میدان دید را کاهش می‌دهد.

چرخش، برش، مقیاس

حالت عمودی داخلی برای یک برنامه دوربین فقط پرتره روی نمایشگری که دارای نسبت منظره است فراخوانی می شود:

پیش‌نمایش دوربین در لپ‌تاپ به صورت عمودی است، اما رابط کاربری برنامه در کناره است.
شکل 9. برنامه پرتره با جهت ثابت در لپ تاپ.

برنامه در جهت عمودی جعبه نامه است:

برنامه به جهت عمودی و جعبه نامه چرخانده شد. تصویر به پهلو، بالا به راست است.

تصویر دوربین 90 درجه چرخانده می شود تا جهت گیری مجدد برنامه تنظیم شود:

تصویر حسگر 90 درجه چرخید تا به حالت عمودی درآید.

تصویر به نسبت تصویر پیش‌نمایش دوربین برش داده می‌شود، سپس برای پر کردن پیش‌نمایش مقیاس‌گذاری می‌شود (میدان دید کاهش می‌یابد):

تصویر دوربین برش خورده برای پر کردن پیش‌نمایش دوربین کوچک‌شده است.

در دستگاه‌های تاشو، جهت سنسور دوربین می‌تواند عمودی باشد در حالی که نسبت تصویر نمایشگر افقی است:

پیش‌نمایش دوربین و رابط کاربری برنامه از صفحه نمایش باز و عریض به طرفین چرخید.
شکل 10. دستگاه باز شده با برنامه دوربین فقط پرتره و نسبت های مختلف سنسور دوربین و نمایشگر.

از آنجایی که پیش‌نمایش دوربین برای تنظیم جهت سنسور چرخانده می‌شود، تصویر به‌درستی در منظره یاب جهت‌گیری می‌شود، اما برنامه فقط پرتره به پهلو است.

حالت پرتره درج شده فقط باید برنامه را در جهت عمودی جعبه نامه قرار دهد تا به درستی برنامه و پیش نمایش دوربین را جهت دهی کند:

برنامه جعبه نامه در جهت عمودی با پیش نمایش دوربین به صورت عمودی روی دستگاه تاشو.

API

از Android 12 (سطح API 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 مراجعه کنید.

CameraX

کتابخانه Jetpack CameraX ایجاد یک منظره یاب دوربین را که جهت گیری حسگر و چرخش دستگاه را در خود جای می دهد به یک کار ساده تبدیل می کند.

عنصر طرح‌بندی PreviewView یک پیش‌نمایش دوربین ایجاد می‌کند که به‌طور خودکار جهت سنسور، چرخش دستگاه و مقیاس‌بندی را تنظیم می‌کند. PreviewView نسبت ابعاد تصویر دوربین را با اعمال نوع مقیاس FILL_CENTER حفظ می کند، که تصویر را در مرکز قرار می دهد اما ممکن است آن را برش دهد تا با ابعاد PreviewView مطابقت داشته باشد. برای جعبه نامه تصویر دوربین، نوع مقیاس را روی FIT_CENTER تنظیم کنید.

برای یادگیری اصول اولیه ایجاد پیش نمایش دوربین با PreviewView ، به اجرای پیش نمایش مراجعه کنید.

برای اجرای نمونه کامل، به مخزن CameraXBasic در GitHub مراجعه کنید.

CameraViewfinder

کتابخانه CameraViewfinder مانند حالت استفاده از پیش نمایش ، مجموعه ای از ابزارها را برای ساده سازی ایجاد پیش نمایش دوربین فراهم می کند. این به CameraX Core بستگی ندارد، بنابراین می‌توانید به‌طور یکپارچه آن را در پایگاه کد Camera2 موجود خود ادغام کنید.

به جای استفاده مستقیم از Surface ، می توانید از ویجت CameraViewfinder برای نمایش فید دوربین برای Camera2 استفاده کنید.

CameraViewfinder به صورت داخلی از یک TextureView یا SurfaceView برای نمایش فید دوربین استفاده می کند و تغییرات لازم را روی آنها اعمال می کند تا منظره یاب را به درستی نمایش دهد. این شامل اصلاح نسبت ابعاد، مقیاس و چرخش آنها است.

برای درخواست سطح از شی CameraViewfinder ، باید یک ViewfinderSurfaceRequest ایجاد کنید.

این درخواست شامل الزامات مربوط به وضوح سطح و اطلاعات دستگاه دوربین از CameraCharacteristics است.

فراخوانی requestSurfaceAsync() درخواست را به ارائه‌دهنده سطح می‌فرستد که یک TextureView یا SurfaceView است و یک ListenableFuture از Surface دریافت می‌کند.

فراخوانی markSurfaceSafeToRelease() به ارائه‌دهنده سطح اطلاع می‌دهد که سطح مورد نیاز نیست و منابع مرتبط می‌توانند آزاد شوند.

کاتلین


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))
}

جاوا


    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() در چرخش نسبی در زیر است.)

کاتلین

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)
}

جاوا

@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

TextureView عملکرد کمتری نسبت به SurfaceView دارد - و کار بیشتری دارد - اما TextureView حداکثر کنترل پیش نمایش دوربین را به شما می دهد.

TextureView بافر تصویر حسگر را بر اساس جهت گیری حسگر می چرخاند اما چرخش دستگاه یا مقیاس پیش نمایش را کنترل نمی کند.

مقیاس بندی و چرخش را می توان در یک تبدیل ماتریسی کدگذاری کرد. برای یادگیری نحوه صحیح مقیاس‌بندی و چرخاندن یک TextureView ، به پشتیبانی از سطوح قابل تغییر اندازه در برنامه دوربین خود مراجعه کنید.

چرخش نسبی

چرخش نسبی سنسور دوربین میزان چرخش مورد نیاز برای تراز کردن خروجی سنسور دوربین با جهت دستگاه است.

چرخش نسبی توسط مؤلفه هایی مانند SurfaceView و TextureView برای تعیین فاکتورهای مقیاس بندی x و y برای تصویر پیش نمایش استفاده می شود. همچنین برای تعیین چرخش بافر تصویر حسگر استفاده می شود.

کلاس های CameraCharacteristics و Surface محاسبه چرخش نسبی سنسور دوربین را امکان پذیر می کند:

کاتلین

/**
 * 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
}

جاوا

/**
 * 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() (افزوده شده در سطح API 30) اندازه پنجره برنامه را به جای اندازه صفحه باز می گرداند. روش‌های کتابخانه Jetpack WindowManager WindowMetricsCalculator#computeCurrentWindowMetrics() و WindowInfoTracker#currentWindowMetrics() پشتیبانی مشابهی را با سازگاری با API سطح 14 ارائه می‌کنند.

چرخش 180 درجه

چرخش 180 درجه ای یک دستگاه (به عنوان مثال، از جهت طبیعی به جهت طبیعی وارونه) پاسخ تماس onConfigurationChanged() را راه اندازی نمی کند. در نتیجه، پیش نمایش دوربین ممکن است وارونه باشد.

برای تشخیص چرخش 180 درجه، یک DisplayListener پیاده سازی کنید و چرخش دستگاه را با فراخوانی Display#getRotation() در پاسخ تماس onDisplayChanged() بررسی کنید.

منابع انحصاری

قبل از Android 10، تنها بالاترین فعالیت قابل مشاهده در یک محیط چند پنجره ای در حالت RESUMED بود. این برای کاربران گیج کننده بود زیرا سیستم هیچ نشانه ای از شروع مجدد فعالیت ارائه نمی داد.

اندروید 10 (سطح API 29) چند رزومه را معرفی کرد که در آن تمام فعالیت های قابل مشاهده در حالت RESUMED هستند. فعالیت‌های قابل مشاهده همچنان می‌توانند وارد حالت PAUSED شوند اگر، برای مثال، یک فعالیت شفاف در بالای فعالیت باشد یا فعالیت قابل تمرکز نباشد، مانند حالت تصویر در تصویر (به پشتیبانی تصویر در تصویر مراجعه کنید).

برنامه‌ای که از دوربین، میکروفون، یا هر منبع انحصاری یا تکی در سطح API 29 یا بالاتر استفاده می‌کند، باید از چند رزومه پشتیبانی کند. به عنوان مثال، اگر سه فعالیت از سر گرفته شده بخواهند از دوربین استفاده کنند، تنها یکی می تواند به این منبع انحصاری دسترسی پیدا کند. هر اکتیویتی باید یک callback onDisconnected() را اجرا کند تا از دسترسی پیشگیرانه به دوربین توسط یک فعالیت با اولویت بالاتر آگاه بماند.

برای اطلاعات بیشتر به چند رزومه مراجعه کنید.

منابع اضافی