หมายเหตุ: หน้านี้อ้างอิงถึงแพ็กเกจ Camera2 เราขอแนะนำให้ใช้ CameraX เว้นแต่ว่าแอปของคุณต้องใช้ฟีเจอร์ระดับต่ำที่เฉพาะเจาะจงจาก Camera2 ทั้ง CameraX และ Camera2 รองรับ Android 5.0 (API ระดับ 21) ขึ้นไป
กล้องและตัวอย่างภาพจากกล้องไม่ได้อยู่ในการวางแนวเดียวกันเสมอไปในอุปกรณ์ Android
กล้องจะอยู่ในตำแหน่งคงที่บนอุปกรณ์ ไม่ว่าอุปกรณ์นั้นจะเป็นโทรศัพท์ แท็บเล็ต หรือคอมพิวเตอร์ก็ตาม เมื่อการวางแนวอุปกรณ์เปลี่ยนไป การวางแนวกล้องก็จะเปลี่ยนไปด้วย
ด้วยเหตุนี้ โดยทั่วไปแอปกล้องจะสันนิษฐานว่าการวางแนวของอุปกรณ์กับสัดส่วนภาพพรีวิวของกล้องมีความสัมพันธ์กันแบบตายตัว เมื่อโทรศัพท์อยู่ในแนวตั้ง ระบบจะถือว่าตัวอย่างภาพจากกล้องมีความสูงมากกว่าความกว้าง เมื่อหมุนโทรศัพท์ (และกล้อง) เป็นแนวนอน ตัวอย่างภาพจากกล้องควรจะกว้างกว่าความสูง
แต่สมมติฐานเหล่านี้อาจใช้ไม่ได้กับรูปแบบของอุปกรณ์ใหม่ๆ เช่น อุปกรณ์พับได้ และโหมดการแสดงผล เช่น แบบหลายหน้าต่างและหลายจอแสดงผล อุปกรณ์แบบพับได้จะเปลี่ยนขนาดการแสดงผลและสัดส่วนภาพโดยไม่เปลี่ยนการวางแนว โหมดหลายหน้าต่างจะจำกัดแอปกล้องให้อยู่ในส่วนหนึ่งของหน้าจอ โดยปรับขนาดตัวอย่างภาพจากกล้องไม่ว่าอุปกรณ์จะวางแนวอย่างไร โหมดหลายจอแสดงผลช่วยให้ใช้จอแสดงผลสำรองซึ่งอาจไม่ได้อยู่ในแนวเดียวกับจอแสดงผลหลักได้
การวางแนวของกล้อง
คำจำกัดความความเข้ากันได้ของ Android ระบุว่าเซ็นเซอร์รูปภาพของกล้อง "ต้องได้รับการปรับทิศทางให้ด้านยาวของกล้องอยู่ในแนวเดียวกับด้านยาวของหน้าจอ กล่าวคือ เมื่อถืออุปกรณ์ในแนวนอน กล้องต้องจับภาพในแนวนอน ซึ่งจะมีผลไม่ว่าอุปกรณ์จะมีการวางแนวตามปกติอย่างไร กล่าวคือจะมีผลกับอุปกรณ์ที่ใช้แนวนอนเป็นหลักและอุปกรณ์ที่ใช้แนวตั้งเป็นหลักด้วย"
การจัดเรียงกล้องกับหน้าจอจะเพิ่มพื้นที่แสดงผลของช่องมองภาพกล้องในแอปกล้องให้มากที่สุด นอกจากนี้ เซ็นเซอร์รูปภาพมักจะแสดงผลข้อมูลในสัดส่วนภาพแนวนอน โดย 4:3 เป็นสัดส่วนที่พบบ่อยที่สุด
การวางแนวตามธรรมชาติของเซ็นเซอร์กล้องคือแนวนอน ในรูปที่ 1 เซ็นเซอร์ของกล้องหน้า (กล้องที่หันไปในทิศทางเดียวกับจอแสดงผล) จะหมุน 270 องศาเมื่อเทียบกับโทรศัพท์เพื่อให้เป็นไปตามคำจำกัดความความเข้ากันได้ของ Android
หากต้องการแสดงการหมุนเซ็นเซอร์ต่อแอป 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
ต้องหมุนบัฟเฟอร์ทวนเข็มนาฬิกา 270 องศาเพื่อปรับการวางแนวเซ็นเซอร์ (ดูการวางแนวกล้องด้านบน)
จากนั้นบัฟเฟอร์จะหมุนทวนเข็มนาฬิกาอีก 90 องศาเพื่อพิจารณาการหมุนของอุปกรณ์ ส่งผลให้ตัวอย่างภาพจากกล้องมีการวางแนวที่ถูกต้องในรูปที่ 2
ภาพนี้แสดงกล้องที่หมุนไปทางขวาเป็นแนวนอน
นี่คือบัฟเฟอร์รูปภาพ
ต้องหมุนบัฟเฟอร์ 270 องศาทวนเข็มนาฬิกาเพื่อปรับการวางแนวเซ็นเซอร์ ดังนี้
จากนั้นบัฟเฟอร์จะหมุนอีก 270 องศาทวนเข็มนาฬิกาเพื่อพิจารณาการหมุนของอุปกรณ์ ดังนี้
กล้องหลัง
โดยทั่วไปกล้องหลังจะมีการวางแนวเซ็นเซอร์ 90 องศา (เมื่อมองจากด้านหลังของอุปกรณ์) เมื่อปรับการวางแนวตัวอย่างภาพจากกล้อง บัฟเฟอร์รูปภาพของเซ็นเซอร์จะหมุนตามเข็มนาฬิกาตามจำนวนการหมุนของเซ็นเซอร์ (แทนที่จะหมุนทวนเข็มนาฬิกาเหมือนกล้องหน้า) จากนั้นบัฟเฟอร์รูปภาพจะหมุนทวนเข็มนาฬิกาตามจำนวนการหมุนของอุปกรณ์
นี่คือบัฟเฟอร์รูปภาพจากเซ็นเซอร์กล้องในรูปที่ 4
ต้องหมุนบัฟเฟอร์ 90 องศาตามเข็มนาฬิกาเพื่อปรับการวางแนวเซ็นเซอร์ ดังนี้
จากนั้นบัฟเฟอร์จะหมุน 270 องศาทวนเข็มนาฬิกาเพื่อพิจารณาการหมุนของอุปกรณ์
สัดส่วนภาพ
สัดส่วนการแสดงผลจะเปลี่ยนไปเมื่อการวางแนวอุปกรณ์เปลี่ยนไป รวมถึงเมื่ออุปกรณ์แบบพับได้พับและกางออก เมื่อหน้าต่างมีการปรับขนาดในสภาพแวดล้อมแบบหลายหน้าต่าง และเมื่อแอปเปิดในจอแสดงผลรอง
บัฟเฟอร์รูปภาพของเซ็นเซอร์กล้องต้องได้รับการปรับการวางแนวและปรับขนาดให้ตรงกับการวางแนวและสัดส่วนภาพขององค์ประกอบ UI ช่องมองภาพเมื่อ UI เปลี่ยนการวางแนวแบบไดนามิก ไม่ว่าอุปกรณ์จะเปลี่ยนการวางแนวหรือไม่ก็ตาม
ในรูปแบบของอุปกรณ์ใหม่ๆ หรือในสภาพแวดล้อมแบบหลายหน้าต่างหรือหลายจอแสดงผล หากแอปของคุณถือว่าตัวอย่างภาพจากกล้องมีการวางแนวเดียวกับอุปกรณ์ (แนวตั้งหรือแนวนอน) ตัวอย่างภาพอาจมีการวางแนวไม่ถูกต้อง ปรับขนาดไม่ถูกต้อง หรือทั้ง 2 อย่าง
ในรูปที่ 5 แอปพลิเคชันเข้าใจผิดว่าอุปกรณ์หมุนทวนเข็มนาฬิกา 90 องศา แอปจึงหมุนตัวอย่างในปริมาณเท่ากัน
ในรูปที่ 6 แอปไม่ได้ปรับสัดส่วนภาพของบัฟเฟอร์รูปภาพเพื่อให้ปรับขนาดให้พอดีกับขนาดใหม่ขององค์ประกอบ UI ตัวอย่างภาพจากกล้องได้อย่างเหมาะสม
แอปกล้องที่มีการวางแนวคงที่มักประสบปัญหาในอุปกรณ์แบบพับได้และอุปกรณ์หน้าจอขนาดใหญ่อื่นๆ เช่น แล็ปท็อป ดังนี้
ในรูปที่ 7 UI ของแอปกล้องจะอยู่ด้านข้างเนื่องจากมีการจำกัดการวางแนวของแอปให้เป็นแนวตั้งเท่านั้น รูปภาพในช่องมองภาพจะวางแนวอย่างถูกต้องเมื่อเทียบกับเซ็นเซอร์กล้อง
โหมดภาพบุคคลแบบแทรก
แอปกล้องที่ไม่รองรับโหมดหลายหน้าต่าง (resizeableActivity="false") และจำกัดการวางแนว (screenOrientation="portrait" หรือ screenOrientation="landscape") สามารถวางในโหมดภาพบุคคลแบบแทรกในอุปกรณ์หน้าจอขนาดใหญ่เพื่อให้พรีวิวของกล้องมีการวางแนวที่เหมาะสม
แทรก Letterbox ในโหมดภาพบุคคล (ส่วนที่เว้นไว้) แอปแนวตั้งเท่านั้นในแนวตั้ง แม้ว่าสัดส่วนการแสดงผลจะเป็นแนวนอนก็ตาม แอปที่แสดงเฉพาะแนวนอนจะแสดงแบบ Letterbox ในแนวนอนแม้ว่าสัดส่วนการแสดงผลจะเป็นแนวตั้งก็ตาม ระบบจะหมุนรูปภาพจากกล้องให้สอดคล้องกับ UI ของแอป ครอบตัดให้ตรงกับสัดส่วนภาพของตัวอย่างกล้อง แล้วปรับขนาดให้เต็มตัวอย่าง
ระบบจะทริกเกอร์โหมดภาพบุคคลแบบแทรกเมื่อสัดส่วนภาพของเซ็นเซอร์รูปภาพของกล้องและสัดส่วนภาพของกิจกรรมหลักของแอปพลิเคชันไม่ตรงกัน
ในรูปที่ 8 แอปกล้องที่ใช้ได้เฉพาะแนวตั้งได้รับการหมุนเพื่อแสดง UI ในแนวตั้งบนจอแสดงผลของแล็ปท็อป แอปจะแสดงแบบ Letterbox เนื่องจากสัดส่วนภาพของแอปแนวตั้งและจอแสดงผลแนวนอนแตกต่างกัน ภาพตัวอย่างจากกล้องได้รับการหมุนเพื่อชดเชยการหมุน UI ของแอป (เนื่องจากโหมดภาพบุคคลแบบแทรก) และรูปภาพได้รับการครอบตัดและปรับขนาดให้พอดีกับการวางแนวตั้ง ซึ่งจะลดขอบเขตการมองเห็น
หมุน ครอบตัด ปรับขนาด
ระบบจะเรียกใช้โหมดภาพบุคคลแบบแทรกสำหรับแอปกล้องที่ใช้ได้เฉพาะโหมดภาพบุคคลบนจอแสดงผลที่มีสัดส่วนภาพแนวนอน ดังนี้
แอปจะแสดงแบบ Letterbox ในแนวตั้ง
ภาพจากกล้องจะหมุน 90 องศาเพื่อปรับตามการปรับแนวของแอป
ระบบจะครอบตัดรูปภาพตามสัดส่วนภาพของตัวอย่างภาพจากกล้อง จากนั้นปรับขนาดให้เต็มตัวอย่าง (ขอบเขตการมองเห็นลดลง) ดังนี้
ในอุปกรณ์แบบพับได้ การวางแนวของเซ็นเซอร์กล้องอาจเป็นแนวตั้งขณะที่สัดส่วนภาพของจอแสดงผลเป็นแนวนอน
เนื่องจากตัวอย่างภาพจากกล้องหมุนเพื่อปรับตามการวางแนวเซ็นเซอร์ รูปภาพจึงวางแนวอย่างถูกต้องในช่องมองภาพ แต่แอปที่แสดงเฉพาะแนวตั้งจะแสดงเป็นแนวนอน
โหมดภาพบุคคลแบบแทรกต้องใช้ Letterbox กับแอปในแนวตั้งเท่านั้นเพื่อปรับแนวแอปและตัวอย่างภาพจากกล้องให้เหมาะสม
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 หากต้องการแสดงภาพจากกล้องแบบ Letterbox ให้ตั้งค่าประเภทการปรับขนาดเป็น FIT_CENTER
หากต้องการดูข้อมูลเบื้องต้นเกี่ยวกับการสร้างตัวอย่างกล้องด้วย PreviewView โปรดดูหัวข้อใช้ตัวอย่าง
ดูตัวอย่างการติดตั้งใช้งานที่สมบูรณ์ได้ในที่เก็บ CameraXBasic ใน GitHub
CameraViewfinder
ไลบรารี CameraViewfinder มีชุดเครื่องมือที่ช่วยให้สร้างตัวอย่างภาพจากกล้องได้ง่ายขึ้น ซึ่งคล้ายกับกรณีการใช้งาน Preview โดยไม่ขึ้นอยู่กับ CameraX Core คุณจึงผสานรวมเข้ากับฐานของโค้ด Camera2 ที่มีอยู่ได้อย่างราบรื่น
คุณสามารถใช้วิดเจ็ต CameraViewfinder เพื่อแสดงฟีดกล้องสำหรับ Camera2 แทนการใช้ Surface โดยตรงได้
CameraViewfinder ใช้ TextureView หรือ SurfaceView ภายในเพื่อแสดงฟีดกล้อง และใช้การเปลี่ยนรูปแบบที่จำเป็นเพื่อแสดงช่องมองภาพอย่างถูกต้อง
ซึ่งรวมถึงการแก้ไขสัดส่วนภาพ ขนาด และการหมุน
หากต้องการขอพื้นผิวจากออบเจ็กต์ CameraViewfinder คุณต้องสร้าง ViewfinderSurfaceRequest
คำขอนี้มีข้อกำหนดสำหรับความละเอียดของพื้นผิวและข้อมูลอุปกรณ์กล้องจาก CameraCharacteristics
การเรียก requestSurfaceAsync() จะส่งคำขอไปยังผู้ให้บริการแพลตฟอร์ม ซึ่งอาจเป็น TextureView หรือ SurfaceView และได้รับ ListenableFuture ของ Surface
การเรียกใช้ markSurfaceSafeToRelease() จะแจ้งให้ผู้ให้บริการ Surface ทราบว่าไม่จำเป็นต้องใช้ Surface และสามารถปล่อยทรัพยากรที่เกี่ยวข้องได้
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)) }
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) }
ดูรายละเอียดเพิ่มเติมเกี่ยวกับการใช้ SurfaceView เป็นตัวอย่างภาพจากกล้องได้ที่การวางแนวกล้อง
TextureView
TextureView มีประสิทธิภาพน้อยกว่า SurfaceView และต้องทำงานมากกว่า แต่ TextureView ช่วยให้คุณควบคุมตัวอย่างภาพจากกล้องได้สูงสุด
TextureView จะหมุนบัฟเฟอร์รูปภาพของเซ็นเซอร์ตามการวางแนวของเซ็นเซอร์ แต่จะไม่จัดการการหมุนอุปกรณ์หรือการปรับขนาดตัวอย่าง
การปรับขนาดและการหมุนสามารถเข้ารหัสได้ในการเปลี่ยนรูปแบบ Matrix ดูวิธีปรับขนาดและหมุน 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) ?: 0 // 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 }
เมตริกหน้าต่าง
ไม่ควรใช้ขนาดหน้าจอเพื่อกำหนดขนาดของช่องมองภาพของกล้อง เนื่องจากแอปกล้องอาจทำงานในส่วนหนึ่งของหน้าจอ ไม่ว่าจะเป็นโหมดหลายหน้าต่างในอุปกรณ์เคลื่อนที่หรือโหมดรูปแบบอิสระใน ChromeOS
WindowManager#getCurrentWindowMetrics() (เพิ่มในระดับ API 30) จะแสดงขนาดของหน้าต่างแอปพลิเคชันแทนขนาดของหน้าจอ เมธอดไลบรารี Jetpack WindowManager
WindowMetricsCalculator#computeCurrentWindowMetrics()
และ
WindowInfoTracker#currentWindowMetrics()
ให้การรองรับที่คล้ายกันซึ่งมีความเข้ากันได้แบบย้อนหลังกับ API ระดับ 14
การหมุน 180 องศา
การหมุนอุปกรณ์ 180 องศา (เช่น จากการวางแนวปกติไปเป็นการวางแนวปกติแบบกลับหัว) จะไม่ทริกเกอร์ Callback onConfigurationChanged() ด้วยเหตุนี้ ตัวอย่างภาพจากกล้องจึงอาจกลับหัว
หากต้องการตรวจจับการหมุน 180 องศา ให้ใช้
DisplayListener
และตรวจสอบการหมุนของอุปกรณ์ด้วยการเรียกใช้
Display#getRotation()
ใน Callback ของ
onDisplayChanged()
แหล่งข้อมูลสุดพิเศษ
ก่อน Android 10 จะมีเพียงกิจกรรมที่มองเห็นได้ด้านบนสุดในสภาพแวดล้อมแบบหลายหน้าต่างเท่านั้นที่อยู่ในสถานะ RESUMED ซึ่งทำให้ผู้ใช้สับสนเนื่องจากระบบไม่ได้ระบุว่ากิจกรรมใดที่กลับมาทำงานต่อ
Android 10 (ระดับ API 29) เปิดตัวโหมดหลายหน้าต่างซึ่งกิจกรรมที่มองเห็นได้ทั้งหมดจะอยู่ในสถานะ RESUMED กิจกรรมที่มองเห็นได้ยังคงเข้าสู่สถานะ PAUSED ได้ เช่น หากกิจกรรมแบบโปร่งใสอยู่ด้านบนของกิจกรรมหรือกิจกรรมไม่สามารถโฟกัสได้ เช่น ในโหมดการแสดงภาพซ้อนภาพ (ดูการรองรับการแสดงภาพซ้อนภาพ)
แอปพลิเคชันที่ใช้กล้อง ไมโครโฟน หรือทรัพยากรเอกสิทธิ์หรือทรัพยากรซิงเกิลตันในระดับ API 29 ขึ้นไปต้องรองรับโหมดหลายหน้าต่าง ตัวอย่างเช่น หากกิจกรรมที่กลับมาทำงานอีกครั้ง 3 กิจกรรมต้องการใช้กล้อง จะมีเพียงกิจกรรมเดียวเท่านั้นที่เข้าถึงทรัพยากรพิเศษนี้ได้ กิจกรรมแต่ละรายการต้องใช้ Callback onDisconnected() เพื่อรับทราบการเข้าถึงกล้องล่วงหน้าโดยกิจกรรมที่มีลำดับความสำคัญสูงกว่า
ดูข้อมูลเพิ่มเติมได้ที่โหมดหลายหน้าต่าง
แหล่งข้อมูลเพิ่มเติม
- ดูตัวอย่าง Camera2 ได้ที่แอป Camera2Basic ใน GitHub
- ดูข้อมูลเกี่ยวกับกรณีการใช้งานตัวอย่างของ CameraX ได้ที่ใช้ตัวอย่างของ CameraX
- ดูตัวอย่างการติดตั้งใช้งานตัวอย่างภาพจากกล้อง CameraX ได้ที่ที่เก็บ CameraXBasic ใน GitHub
- ดูข้อมูลเกี่ยวกับตัวอย่างภาพจากกล้องใน ChromeOS ได้ที่การวางแนวกล้อง
- ดูข้อมูลเกี่ยวกับการพัฒนาสำหรับอุปกรณ์แบบพับได้ที่หัวข้อดูข้อมูลเกี่ยวกับอุปกรณ์แบบพับได้