چرخش کیس استفاده CameraX

این مبحث نحوه تنظیم موارد استفاده CameraX را در برنامه خود برای دریافت تصاویر با اطلاعات چرخش صحیح، چه از ImageAnalysis یا ImageCapture نشان می دهد. بنابراین:

  • Analyzer مورد استفاده ImageAnalysis باید فریم هایی را با چرخش صحیح دریافت کند.
  • کیس استفاده ImageCapture باید با چرخش صحیح عکس بگیرد.

اصطلاحات

این مبحث از اصطلاحات زیر استفاده می کند، بنابراین درک معنای هر اصطلاح مهم است:

جهت نمایش
این به این اشاره دارد که کدام سمت دستگاه در موقعیت رو به بالا قرار دارد و می تواند یکی از چهار مقدار باشد: عمودی، منظره، پرتره معکوس، یا منظره معکوس.
چرخش نمایشگر
این مقداری است که توسط Display.getRotation() برگردانده شده است و نشان دهنده درجاتی است که دستگاه در خلاف جهت عقربه های ساعت از جهت طبیعی خود می چرخد.
چرخش هدف
این نشان دهنده تعداد درجاتی است که از طریق آنها می توان دستگاه را در جهت عقربه های ساعت چرخاند تا به جهت طبیعی خود برسد.

نحوه تعیین چرخش هدف

مثال های زیر نحوه تعیین چرخش هدف برای یک دستگاه را بر اساس جهت گیری طبیعی آن نشان می دهد.

مثال 1: جهت گیری طبیعی پرتره

مثال دستگاه: Pixel 3 XL

جهت گیری طبیعی = پرتره
جهت گیری فعلی = پرتره

چرخش نمایشگر = 0
چرخش هدف = 0

جهت گیری طبیعی = پرتره
جهت فعلی = چشم انداز

چرخش نمایشگر = 90
چرخش هدف = 90

مثال 2: جهت گیری طبیعی منظر

مثال دستگاه: Pixel C

جهت گیری طبیعی = منظر
جهت فعلی = چشم انداز

چرخش نمایشگر = 0
چرخش هدف = 0

جهت گیری طبیعی = منظر
جهت گیری فعلی = پرتره

چرخش نمایشگر = 270
چرخش هدف = 270

چرخش تصویر

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

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

مثال 1: سنسور 90 درجه چرخیده است

مثال دستگاه: Pixel 3 XL

چرخش نمایشگر = 0
جهت نمایش = پرتره
چرخش تصویر = 90

چرخش نمایشگر = 90
جهت نمایش = منظره
چرخش تصویر = 0

مثال 2: سنسور 270 درجه چرخیده است

مثال دستگاه: Nexus 5X

چرخش نمایشگر = 0
جهت نمایش = پرتره
چرخش تصویر = 270

چرخش نمایشگر = 90
جهت نمایش = منظره
چرخش تصویر = 180

مثال 3: سنسور 0 درجه چرخیده است

مثال دستگاه: Pixel C (تبلت)

چرخش نمایشگر = 0
جهت نمایش = منظره
چرخش تصویر = 0

چرخش نمایشگر = 270
جهت نمایش = پرتره
چرخش تصویر = 90

محاسبه چرخش تصویر

تجزیه و تحلیل تصویر

ImageAnalysis 's Analyzer تصاویر را از دوربین به شکل ImageProxy s دریافت می کند. هر تصویر حاوی اطلاعات چرخش است که از طریق:

val rotation = imageProxy.imageInfo.rotationDegrees

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

ImageCapture

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

هنگام گرفتن عکس، پاسخ تماس ارائه شده می تواند یکی از انواع زیر باشد:

  • OnImageCapturedCallback : تصویری را با دسترسی درون حافظه به شکل ImageProxy دریافت می کند.
  • OnImageSavedCallback : زمانی فراخوانی می شود که تصویر گرفته شده با موفقیت در مکان مشخص شده توسط ImageCapture.OutputFileOptions ذخیره شود. گزینه ها می توانند یک File ، یک OutputStream یا یک مکان در MediaStore را مشخص کنند.

چرخش تصویر گرفته شده، صرف نظر از فرمت آن ( ImageProxy ، File ، OutputStream ، MediaStore Uri ) نشان دهنده درجه های چرخشی است که تصویر گرفته شده باید در جهت عقربه های ساعت بچرخد تا با چرخش هدف ImageCapture مطابقت داشته باشد، که دوباره در زمینه یک برنامه اندروید، معمولاً با جهت صفحه نمایش مطابقت دارد.

بازیابی چرخش تصویر گرفته شده را می توان به یکی از روش های زیر انجام داد:

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 از این جهت‌گیری‌ها پشتیبانی نمی‌کنند. اینکه آیا یک برنامه از آن پشتیبانی می کند یا نه، نحوه به روز رسانی چرخش هدف موارد استفاده را تغییر می دهد.

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

برای انتخاب دستورالعمل هایی که در برنامه خود دنبال کنید:

  1. بررسی کنید که آیا « Activity دوربین» برنامه شما جهت قفل شده، جهت قفل آن قفل نیست یا تغییرات پیکربندی جهت را لغو می کند.

  2. تصمیم بگیرید که آیا Activity دوربین» برنامه شما باید هر چهار جهت دستگاه (عمودی، عمودی معکوس، افقی و منظره معکوس) را انجام دهد یا اینکه فقط باید جهت گیری هایی را که دستگاهی که روی آن اجرا می شود به طور پیش فرض پشتیبانی می کند، انجام دهد.

از هر چهار جهت پشتیبانی کنید

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

سناریو رهنمودها حالت تک پنجره ای حالت چند پنجره ای تقسیم صفحه
جهت آنلاک هر بار که Activity ایجاد می‌شود، موارد استفاده را تنظیم کنید، مانند پاسخ به تماس onCreate() Activity .
از OrientationEventListener 's onOrientationChanged() استفاده کنید. در داخل callback، چرخش هدف موارد استفاده را به روز کنید. این کار مواردی را کنترل می کند که سیستم حتی پس از تغییر جهت، Activity را دوباره ایجاد نمی کند، مانند زمانی که دستگاه 180 درجه می چرخد. همچنین زمانی که نمایشگر در جهت عمودی معکوس است و دستگاه به طور پیش‌فرض به حالت عمودی معکوس نمی‌چرخد، کنترل می‌کند. همچنین مواردی را که هنگام چرخش دستگاه (مثلاً 90 درجه) « Activity ایجاد نمی‌شود، کنترل می‌کند. زمانی که برنامه نیمی از صفحه را اشغال می‌کند، این اتفاق در دستگاه‌های فاکتور کوچک و زمانی که برنامه دو سوم صفحه را اشغال می‌کند، روی دستگاه‌های بزرگتر اتفاق می‌افتد.
اختیاری: ویژگی screenOrientation Activity را در فایل AndroidManifest روی fullSensor تنظیم کنید. این اجازه می‌دهد تا زمانی که دستگاه در حالت عمودی قرار دارد، رابط کاربری در حالت عمودی قرار گیرد و هر زمان که دستگاه به اندازه ۹۰ درجه چرخانده می‌شود، امکان بازآفرینی Activity توسط سیستم وجود دارد. هیچ تاثیری روی دستگاه‌هایی که به‌طور پیش‌فرض برای پرتره معکوس نمی‌چرخند ندارد. در حالی که صفحه نمایش در جهت عمودی معکوس است، حالت چند پنجره ای پشتیبانی نمی شود.
جهت قفل شده موارد استفاده را فقط یک بار تنظیم کنید، زمانی که Activity برای اولین بار ایجاد می شود، مانند پاسخ به تماس onCreate() Activity .
از OrientationEventListener 's onOrientationChanged() استفاده کنید. در داخل فراخوان، چرخش هدف موارد استفاده به جز پیش نمایش را به روز کنید. همچنین مواردی را که هنگام چرخش دستگاه (مثلاً 90 درجه) « Activity ایجاد نمی‌شود، کنترل می‌کند. زمانی که برنامه نیمی از صفحه را اشغال می‌کند، این اتفاق در دستگاه‌های فاکتور کوچک و زمانی که برنامه دو سوم صفحه را اشغال می‌کند، روی دستگاه‌های بزرگتر اتفاق می‌افتد.
تنظیمات جهت یابی تغییرات لغو می شود موارد استفاده را فقط یک بار تنظیم کنید، زمانی که Activity برای اولین بار ایجاد می شود، مانند پاسخ به تماس onCreate() Activity .
از OrientationEventListener 's onOrientationChanged() استفاده کنید. در داخل callback، چرخش هدف موارد استفاده را به روز کنید. همچنین مواردی را که هنگام چرخش دستگاه (مثلاً 90 درجه) « Activity ایجاد نمی‌شود، کنترل می‌کند. زمانی که برنامه نیمی از صفحه را اشغال می‌کند، این اتفاق در دستگاه‌های فاکتور کوچک و زمانی که برنامه دو سوم صفحه را اشغال می‌کند، روی دستگاه‌های بزرگتر اتفاق می‌افتد.
اختیاری: ویژگی screenOrientation Activity را روی fullSensor در فایل AndroidManifest تنظیم کنید. هنگامی که دستگاه در حالت عمودی قرار دارد، به رابط کاربری اجازه می‌دهد تا عمودی باشد. هیچ تاثیری روی دستگاه‌هایی که به‌طور پیش‌فرض برای پرتره معکوس نمی‌چرخند ندارد. در حالی که صفحه نمایش در جهت عمودی معکوس است، حالت چند پنجره ای پشتیبانی نمی شود.

فقط جهت گیری های پشتیبانی شده توسط دستگاه را پشتیبانی کنید

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

سناریو رهنمودها حالت چند پنجره ای تقسیم صفحه
جهت آنلاک شده هر بار که Activity ایجاد می‌شود، موارد استفاده را تنظیم کنید، مانند پاسخ به تماس onCreate() Activity .
از DisplayListener 's onDisplayChanged() استفاده کنید. در داخل کال بک، چرخش هدف موارد استفاده را به روز کنید، مانند زمانی که دستگاه 180 درجه می چرخد. همچنین مواردی را که هنگام چرخش دستگاه (مثلاً 90 درجه) « Activity ایجاد نمی‌شود، کنترل می‌کند. زمانی که برنامه نیمی از صفحه را اشغال می‌کند، این اتفاق در دستگاه‌های فاکتور کوچک و زمانی که برنامه دو سوم صفحه را اشغال می‌کند، روی دستگاه‌های بزرگتر اتفاق می‌افتد.
جهت قفل شده موارد استفاده را فقط یک بار تنظیم کنید، زمانی که Activity برای اولین بار ایجاد می شود، مانند پاسخ به تماس onCreate() Activity .
از OrientationEventListener 's onOrientationChanged() استفاده کنید. در داخل callback، چرخش هدف موارد استفاده را به روز کنید. همچنین مواردی را که هنگام چرخش دستگاه (مثلاً 90 درجه) « Activity ایجاد نمی‌شود، کنترل می‌کند. زمانی که برنامه نیمی از صفحه را اشغال می‌کند، این اتفاق در دستگاه‌های فاکتور کوچک و زمانی که برنامه دو سوم صفحه را اشغال می‌کند، روی دستگاه‌های بزرگتر اتفاق می‌افتد.
تنظیمات جهت یابی تغییرات لغو می شود موارد استفاده را فقط یک بار تنظیم کنید، زمانی که Activity برای اولین بار ایجاد می شود، مانند پاسخ به تماس onCreate() Activity .
از DisplayListener 's onDisplayChanged() استفاده کنید. در داخل کال بک، چرخش هدف موارد استفاده را به روز کنید، مانند زمانی که دستگاه 180 درجه می چرخد. همچنین مواردی را که هنگام چرخش دستگاه (مثلاً 90 درجه) « 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 on جهت تغییرات می شود. این باعث می‌شود که موارد استفاده چرخش هدف خود را به‌طور پیش‌فرض هر بار با جهت نمایشگر مطابقت دهند.

در مورد یک Activity با جهت قفل شده یا فعالیتی که تغییرات پیکربندی جهت را لغو می کند، این تنظیم یک بار انجام می شود، زمانی که Activity برای اولین بار ایجاد می شود.

class CameraActivity : AppCompatActivity() {
   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 به شما این امکان را می‌دهد تا در موقعیت‌های خاص، چرخش مورد نظر دوربین را به‌روزرسانی کنید، به عنوان مثال زمانی که سیستم پس از چرخش 180 درجه‌ای دستگاه، 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)
    }
}