این موضوع نشان میدهد که چگونه موارد استفاده CameraX را در برنامه خود راهاندازی کنید تا
تصاویر با اطلاعات چرخش صحیح دریافت کنید، چه از
ImageAnalysis باشد یا از مورد استفاده ImageCapture. بنابراین:
Analyzerمورد استفادهImageAnalysisباید فریمها را با چرخش صحیح دریافت کند.- مورد استفاده
ImageCaptureباید عکسها را با چرخش صحیح بگیرد.
اصطلاحات
این موضوع از اصطلاحات زیر استفاده میکند، بنابراین درک معنای هر اصطلاح مهم است:
- جهت نمایش
- این به این اشاره دارد که کدام طرف دستگاه در موقعیت رو به بالا قرار دارد و میتواند یکی از چهار مقدار باشد: عمودی، افقی، عمودی معکوس، یا افقی معکوس.
- چرخش نمایش
- این مقداری است که توسط
Display.getRotation()برگردانده میشود و نشاندهنده درجهای است که دستگاه در خلاف جهت عقربههای ساعت از جهت طبیعی خود چرخیده است. - چرخش هدف
- این نشاندهنده تعداد درجهای است که دستگاه باید در جهت عقربههای ساعت بچرخد تا به جهت طبیعی خود برسد.
نحوه تعیین چرخش هدف
نمونههای زیر نشان میدهند که چگونه میتوان چرخش هدف را برای دستگاه براساس جهت طبیعی آن تعیین کرد.
مثال ۱: جهت طبیعی عمودی
| نمونه دستگاه: Pixel 3 XL | |
|---|---|
|
جهت طبیعی = عمودی چرخش نمایش = 0 |
|
|
جهت طبیعی = عمودی چرخش نمایش = ۹۰ |
|
مثال ۲: جهت طبیعی افقی
| نمونه دستگاه: Pixel C | |
|---|---|
|
جهت طبیعی = افقی چرخش نمایش = 0 |
|
|
جهت طبیعی = افقی چرخش نمایش = ۲۷۰ |
|
چرخش تصویر
کدام طرف بالا است؟ جهت حسگر در Android بهعنوان مقدار ثابتی تعریف میشود که نشاندهنده درجه (۰، ۹۰، ۱۸۰، ۲۷۰) چرخش حسگر از بالای دستگاه است، وقتی دستگاه در موقعیت طبیعی قرار دارد. برای همه موارد در نمودارها، چرخش تصویر نحوه چرخش دادهها در جهت عقربههای ساعت را برای نمایش عمودی توصیف میکند.
مثالهای زیر نشان میدهند که چرخش تصویر بسته به جهت حسگر دوربین باید چگونه باشد. همچنین فرض میکنند که چرخش هدف روی چرخش نمایشگر تنظیم شده است.
مثال ۱: حسگر ۹۰ درجه چرخیده است
| نمونه دستگاه: Pixel 3 XL | |
|---|---|
|
چرخش نمایشگر = ۰ |
|
|
چرخش نمایشگر = ۹۰ |
|
مثال ۲: حسگر ۲۷۰ درجه چرخیده است
| نمونه دستگاه: Nexus 5X | |
|---|---|
|
چرخش نمایش = ۰ |
|
|
چرخش نمایشگر = ۹۰ |
|
مثال ۳: حسگر ۰ درجه چرخیده است
| نمونه دستگاه: Pixel C (رایانه لوحی) | |
|---|---|
|
چرخش نمایش = ۰ |
|
|
چرخش نمایش = ۲۷۰ |
|
محاسبه چرخش تصویر
ImageAnalysis
Analyzer ImageAnalysis تصاویر را از دوربین بهصورت
ImageProxy دریافت میکند. هر تصویر حاوی اطلاعات چرخش است که ازطریق زیر قابلدسترسی است:
val rotation = imageProxy.imageInfo.rotationDegrees
این مقدار نشاندهنده درجهای است که تصویر باید در جهت ساعتگرد بچرخد تا با چرخش هدف ImageAnalysis مطابقت داشته باشد. در بافت برنامه Android، چرخش هدف ImageAnalysis معمولاً با جهت صفحه مطابقت دارد.
ImageCapture
یک فراخوانی برگشتی به نمونه ImageCapture پیوست شده است تا وقتی نتیجه ضبط آماده شد، سیگنال دهد. نتیجه میتواند تصویر ثبتشده یا خطا باشد.
هنگام گرفتن عکس، callback ارائهشده میتواند یکی از انواع زیر باشد:
-
OnImageCapturedCallback: تصویری را با دسترسی درونحافظهای بهشکلImageProxyدریافت میکند. OnImageSavedCallback: زمانی فراخوانده میشود که تصویر ثبتشده با موفقیت در مکان مشخصشده توسطImageCapture.OutputFileOptionsذخیره شده باشد. این گزینهها میتوانندFile،OutputStream، یا مکانی درMediaStoreرا مشخص کنند.
چرخش تصویر ثبتشده، صرفنظر از قالب آن (ImageProxy،
File، OutputStream، MediaStore Uri) نشاندهنده درجه چرخشی است که
تصویر ثبتشده باید در جهت عقربههای ساعت بچرخد تا با چرخش هدف ImageCapture
مطابقت داشته باشد، که این چرخش هدف نیز در بافت برنامه Android معمولاً
با جهت صفحهنمایش مطابقت دارد.
بازیابی چرخش تصویر ثبتشده را میتوان به یکی از روشهای زیر انجام داد:
ImageProxy
val rotation = imageProxy.imageInfo.rotationDegrees
File
val exif = Exif.createFromFile(file) val rotation = exif.rotation
OutputStream
val byteArray = outputStream.toByteArray() val exif = Exif.createFromInputStream(ByteArrayInputStream(byteArray)) val rotation = exif.rotation
MediaStore uri
val inputStream = contentResolver.openInputStream(outputFileResults.savedUri) val exif = Exif.createFromInputStream(inputStream) val rotation = exif.rotation
درستیسنجی چرخش تصویر
موارد استفاده ImageAnalysis و ImageCapture پساز درخواست ضبط موفق، ImageProxy را از دوربین دریافت میکنند. ImageProxy تصویر و اطلاعات مربوط به آن، ازجمله چرخش آن را دربرمیگیرد. این اطلاعات چرخش نشاندهنده درجهای است که تصویر باید بچرخد تا با چرخش هدف مورد استفاده مطابقت داشته باشد.
دستورالعملهای چرخش هدف ImageCapture/ImageAnalysis
ازآنجاییکه بسیاری از دستگاهها بهطور پیشفرض به حالت عمودی معکوس یا افقی معکوس نمیچرخند، برخیاز برنامههای Android از این جهتها پشتیبانی نمیکنند. اینکه برنامهای از آن پشتیبانی میکند یا نه، نحوه بهروزرسانی چرخش هدف موارد استفاده را تغییر میدهد.
در زیر دو جدول وجود دارد که نحوه همگامسازی چرخش هدف موارد استفاده با چرخش نمایشگر را تعریف میکند. اولی نشان میدهد که چگونه این کار را انجام دهید درحالیکه از هر چهار جهت پشتیبانی میکند؛ دومی فقط جهتهایی را مدیریت میکند که دستگاه بهطور پیشفرض به آنها میچرخد.
برای انتخاب اینکه کدام دستورالعملها را در برنامهتان دنبال کنید:
بررسی کنید که آیا دوربین برنامه شما
Activityجهت قفلشده دارد، جهت قفلنشده دارد، یا اینکه تغییرات پیکربندی جهت را لغو میکند.تصمیم بگیرید که آیا دوربین برنامه شما
Activityباید هر چهار جهت دستگاه (عمودی، عمودی معکوس، افقی، و افقی معکوس) را مدیریت کند یا فقط باید جهتهایی را مدیریت کند که دستگاهی که برنامه روی آن اجرا میشود بهطور پیشفرض پشتیبانی میکند.
پشتیبانی از هر چهار جهت
این جدول به دستورالعملهای خاصی اشاره میکند که باید در مواردی که دستگاه به حالت عمودی معکوس نمیچرخد، دنبال شوند. همین موضوع میتواند برای دستگاههایی که بهحالت افقی معکوس نمیچرخند اعمال شود.
| سناریو | رهنمودها | حالت تکپنجرهای | حالت صفحه دونیمه چندپنجرهای |
|---|---|---|---|
| جهت بازشده |
موارد استفاده را هربار که Activity ایجاد میشود، مثلاً در فراخوانی برگشتی onCreate() مربوط به Activity، راهاندازی کنید.
|
||
از OrientationEventListener
onOrientationChanged() استفاده کنید.
درون فراخوانی برگشتی، چرخش هدف موارد استفاده را بهروز کنید. این کار مواردی را مدیریت میکند که سیستم
Activity را حتی پساز تغییر جهت بازسازی نمیکند، مانند
زمانی که دستگاه ۱۸۰ درجه چرخانده میشود.
|
همچنین زمانی را که نمایشگر در جهت عمودی معکوس است و دستگاه بهطور پیشفرض به جهت عمودی معکوس نمیچرخد مدیریت میکند. |
همچنین مواردی را که Activity هنگام چرخش دستگاه (مثلاً ۹۰ درجه) بازسازی نمیشود، مدیریت میکند. این اتفاق در دستگاههای با ابعاد کوچک زمانی رخ میدهد که برنامه نیمی از صفحه را اشغال کند، و در دستگاههای بزرگتر زمانی رخ میدهد که برنامه دو سوم صفحه را اشغال کند.
|
|
اختیاری: ویژگی screenOrientation مربوط به Activity را در فایل AndroidManifest روی fullSensor تنظیم کنید.
|
این کار باعث میشود وقتی دستگاه در حالت عمودی معکوس است، میانای کاربر بهصورت عمودی باشد و به Activity اجازه میدهد هروقت دستگاه ۹۰ درجه چرخانده شد، توسط سیستم بازسازی شود.
|
بر دستگاههایی که بهطور پیشفرض به حالت عمودی معکوس نمیچرخند تأثیری ندارد. وقتی نمایشگر در جهت عمودی معکوس باشد، حالت چندپنجرهای پشتیبانی نمیشود. | |
| جهت قفلشده |
موارد استفاده را فقط یکبار، زمانی که
Activity برای اولینبار ایجاد میشود، مثلاً در
onCreate() callback مربوط به Activity، تنظیم کنید.
|
||
از OrientationEventListener
onOrientationChanged() استفاده کنید.
درون فراخوانی برگشتی، چرخش هدف موارد استفاده را بهجز «پیشنمایش» بهروز کنید.
|
همچنین مواردی را که Activity هنگام چرخش دستگاه (مثلاً ۹۰ درجه) بازسازی نمیشود، مدیریت میکند. این اتفاق در دستگاههای با ابعاد کوچک زمانی رخ میدهد که برنامه نیمی از صفحه را اشغال کند، و در دستگاههای بزرگتر زمانی رخ میدهد که برنامه دو سوم صفحه را اشغال کند.
|
||
| configChanges جهت لغو شد |
موارد استفاده را فقط یکبار، زمانی که
Activity برای اولینبار ایجاد میشود، مثلاً در
onCreate() callback مربوط به Activity، تنظیم کنید.
|
||
از OrientationEventListener
onOrientationChanged() استفاده کنید.
درون فراخوانی برگشتی، چرخش هدف موارد استفاده را بهروز کنید.
|
همچنین مواردی را که Activity هنگام چرخش دستگاه (مثلاً ۹۰ درجه) بازسازی نمیشود، مدیریت میکند. این اتفاق در دستگاههای با ابعاد کوچک زمانی رخ میدهد که برنامه نیمی از صفحه را اشغال کند، و در دستگاههای بزرگتر زمانی رخ میدهد که برنامه دو سوم صفحه را اشغال کند.
|
||
| اختیاری: ویژگی screenOrientation مربوط به Activity را در فایل AndroidManifest روی fullSensor تنظیم کنید. | به میانای کاربر اجازه میدهد وقتی دستگاه در حالت عمودی معکوس است، بهصورت عمودی قرار بگیرد. | بر دستگاههایی که بهطور پیشفرض به حالت عمودی معکوس نمیچرخند تأثیری ندارد. وقتی نمایشگر در جهت عمودی معکوس باشد، حالت چندپنجرهای پشتیبانی نمیشود. |
فقط از جهتهای پشتیبانیشده توسط دستگاه پشتیبانی کنید
فقط از جهتهایی پشتیبانی کنید که دستگاه بهطور پیشفرض پشتیبانی میکند (که ممکن است شامل عمودی معکوس/ افقی معکوس باشد یا نباشد).
| سناریو | رهنمودها | حالت صفحه دونیمه چندپنجرهای |
|---|---|---|
| جهت بازشده |
موارد استفاده را هربار که Activity ایجاد میشود، مثلاً در فراخوانی برگشتی onCreate() مربوط به Activity، راهاندازی کنید.
|
|
از onDisplayChanged()
DisplayListener استفاده کنید. درون
فراخوانی برگشتی، چرخش هدف موارد استفاده را بهروز کنید، مثلاً وقتی
دستگاه ۱۸۰ درجه میچرخد.
|
همچنین مواردی را که Activity هنگام چرخش دستگاه (مثلاً ۹۰ درجه) بازسازی نمیشود، مدیریت میکند. این اتفاق در دستگاههای با ابعاد کوچک زمانی رخ میدهد که برنامه نیمی از صفحه را اشغال کند، و در دستگاههای بزرگتر زمانی رخ میدهد که برنامه دو سوم صفحه را اشغال کند.
|
|
| جهت قفلشده |
موارد استفاده را فقط یکبار، زمانی که
Activity برای اولینبار ایجاد میشود، مثلاً در
onCreate() callback مربوط به Activity، تنظیم کنید.
|
|
از OrientationEventListener
onOrientationChanged() استفاده کنید.
درون فراخوانی برگشتی، چرخش هدف موارد استفاده را بهروز کنید.
|
همچنین مواردی را که Activity هنگام چرخش دستگاه (مثلاً ۹۰ درجه) بازسازی نمیشود، مدیریت میکند. این اتفاق در دستگاههای با ابعاد کوچک زمانی رخ میدهد که برنامه نیمی از صفحه را اشغال کند، و در دستگاههای بزرگتر زمانی رخ میدهد که برنامه دو سوم صفحه را اشغال کند.
|
|
| configChanges جهت لغو شد |
موارد استفاده را فقط یکبار، زمانی که
Activity برای اولینبار ایجاد میشود، مثلاً در
onCreate() callback مربوط به Activity، تنظیم کنید.
|
|
از onDisplayChanged()
DisplayListener استفاده کنید. درون
فراخوانی برگشتی، چرخش هدف موارد استفاده را بهروز کنید، مثلاً وقتی
دستگاه ۱۸۰ درجه میچرخد.
|
همچنین مواردی را که Activity هنگام چرخش دستگاه (مثلاً ۹۰ درجه) بازسازی نمیشود، مدیریت میکند. این اتفاق در دستگاههای با ابعاد کوچک زمانی رخ میدهد که برنامه نیمی از صفحه را اشغال کند، و در دستگاههای بزرگتر زمانی رخ میدهد که برنامه دو سوم صفحه را اشغال کند.
|
جهت قفلنشده
Activity زمانی جهت بازشده دارد که جهت نمایش آن (مانند عمودی یا افقی) با جهت فیزیکی دستگاه مطابقت داشته باشد، بهاستثنای عمودی/افقی معکوس که برخی دستگاهها بهطور پیشفرض از آن پشتیبانی نمیکنند. برای اینکه دستگاه را مجبور کنید به هر چهار جهت بچرخد،
خصوصیت screenOrientation مربوط به Activity را روی fullSensor تنظیم کنید.
در حالت چندپنجرهای، دستگاهی که از حالت عمودی/افقی معکوس پشتیبانی نمیکند
بهطور پیشفرض به حالت عمودی/افقی معکوس نمیچرخد، حتی وقتی که
ویژگی screenOrientation آن روی fullSensor تنظیم شده باشد.
<!-- The Activity has an unlocked orientation, but might not rotate to reverse portrait/landscape in single-window mode if the device doesn't support it by default. --> <activity android:name=".UnlockedOrientationActivity" /> <!-- The Activity has an unlocked orientation, and will rotate to all four orientations in single-window mode. --> <activity android:name=".UnlockedOrientationActivity" android:screenOrientation="fullSensor" />
جهت قفلشده
نمایشگر زمانی جهت قفلشده دارد که صرفنظر از جهت فیزیکی دستگاه، در همان جهت نمایش (مانند عمودی یا افقی) باقی بماند. این کار را میتوان با مشخص کردن ویژگی screenOrientation مربوط به Activity در داخل اظهارنامه آن در فایل AndroidManifest.xml انجام داد.
وقتی جهت نمایشگر قفل باشد، سیستم با چرخاندن دستگاه Activity را ازبین نمیبرد و دوباره ایجاد نمیکند.
<!-- The Activity keeps a portrait orientation even as the device rotates. --> <activity android:name=".LockedOrientationActivity" android:screenOrientation="portrait" />
تغییرات پیکربندی جهت لغو شد
وقتی Activity تغییرات پیکربندی جهت را لغو میکند، سیستم
آن را هنگام تغییر جهت فیزیکی دستگاه ازبین نمیبرد و دوباره ایجاد نمیکند.
بااینحال، سیستم میانای کاربر را بهروز میکند تا با جهت فیزیکی دستگاه مطابقت داشته باشد.
<!-- The Activity's UI might not rotate in reverse portrait/landscape if the device doesn't support it by default. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" /> <!-- The Activity's UI will rotate to all 4 orientations in single-window mode. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" android:screenOrientation="fullSensor" />
راهاندازی موارد استفاده دوربین
در سناریوهای شرحدادهشده در بالا، موارد استفاده از دوربین را میتوان هنگام ایجاد اولیه
Activity راهاندازی کرد.
در مورد Activity با جهت قفلنشده، این راهاندازی هربار که دستگاه چرخانده میشود انجام میشود، زیرا سیستم هنگام تغییر جهت، Activity را ازبین میبرد و دوباره ایجاد میکند. این امر باعث میشود که موارد استفاده، چرخش هدف خود را بهطور پیشفرض هربار با جهت نمایشگر مطابقت دهند.
درمورد Activity با جهت قفلشده یا موردی که تغییرات پیکربندی جهت را لغو میکند، این راهاندازی یکبار انجام میشود، یعنی زمانی که Activity برای اولینبار ایجاد میشود.
class CameraActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val cameraProcessFuture = ProcessCameraProvider.getInstance(this) cameraProcessFuture.addListener( Runnable { val cameraProvider = cameraProcessFuture.get() // By default, the use cases set their target rotation to match the // display’s rotation. val preview = buildPreview() val imageAnalysis = buildImageAnalysis() val imageCapture = buildImageCapture() cameraProvider.bindToLifecycle( this, cameraSelector, preview, imageAnalysis, imageCapture ) }, mainExecutor ) } }
راهاندازی OrientationEventListener
استفاده از OrientationEventListener به شما امکان میدهد تا با تغییر جهت دستگاه، چرخش هدف موارد استفاده دوربین را بهطور مداوم بهروز کنید.
class CameraActivity : AppCompatActivity() { private val orientationEventListener by lazy { object : OrientationEventListener(this) { override fun onOrientationChanged(orientation: Int) { if (orientation == ORIENTATION_UNKNOWN) { return } val rotation = when (orientation) { in 45 until 135 -> Surface.ROTATION_270 in 135 until 225 -> Surface.ROTATION_180 in 225 until 315 -> Surface.ROTATION_90 else -> Surface.ROTATION_0 } imageAnalysis.targetRotation = rotation imageCapture.targetRotation = rotation } } } override fun onStart() { super.onStart() orientationEventListener.enable() } override fun onStop() { super.onStop() orientationEventListener.disable() } }
راهاندازی DisplayListener
استفاده از DisplayListener به شما امکان میدهد چرخش هدف موارد استفاده از دوربین را در شرایط خاصی بهروز کنید، برای مثال وقتی سیستم Activity را پساز چرخش ۱۸۰ درجهای دستگاه ازبین نمیبرد و دوباره ایجاد نمیکند.
class CameraActivity : AppCompatActivity() { private val displayListener = object : DisplayManager.DisplayListener { override fun onDisplayChanged(displayId: Int) { if (rootView.display.displayId == displayId) { val rotation = rootView.display.rotation imageAnalysis.targetRotation = rotation imageCapture.targetRotation = rotation } } override fun onDisplayAdded(displayId: Int) { } override fun onDisplayRemoved(displayId: Int) { } } override fun onStart() { super.onStart() val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager displayManager.registerDisplayListener(displayListener, null) } override fun onStop() { super.onStop() val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager displayManager.unregisterDisplayListener(displayListener) } }