หากแอป Android ใช้กล้อง จะมีข้อควรพิจารณาพิเศษบางอย่างเมื่อจัดการการวางแนว เอกสารนี้ถือว่าคุณเข้าใจแนวคิดพื้นฐานของ Android camera2 API คุณสามารถอ่านบล็อกโพสต์หรือข้อมูลสรุปของเราเพื่อดูภาพรวมของ Camera2 นอกจากนี้ เราขอแนะนำให้คุณลองเขียนแอปกล้องก่อนที่จะอ่านเอกสารนี้
ฉากหลัง
การจัดการการวางแนวในแอปกล้อง Android เป็นเรื่องที่ซับซ้อนและต้องคำนึงถึงปัจจัยต่อไปนี้
- การวางแนวตามธรรมชาติ: การวางแนวการแสดงผลเมื่ออุปกรณ์อยู่ในตำแหน่ง "ปกติ" สำหรับการออกแบบอุปกรณ์ ซึ่งมักจะเป็นการวางแนวตั้งสำหรับโทรศัพท์มือถือและการวางแนวนอนสำหรับแล็ปท็อป
- การวางแนวเซ็นเซอร์: การวางแนวของเซ็นเซอร์ที่ติดตั้งในอุปกรณ์
- การหมุนจอแสดงผล: อุปกรณ์หมุนจากแนวตั้งปกติมากเพียงใด
- ขนาดช่องมองภาพ: ขนาดของช่องมองภาพที่ใช้แสดงตัวอย่างกล้อง
- ขนาดรูปภาพที่กล้องส่งออก
เมื่อรวมปัจจัยเหล่านี้เข้าด้วยกันแล้ว จะทำให้แอปกล้องมี UI และการกำหนดค่าตัวอย่างที่เป็นไปได้จำนวนมาก เอกสารนี้มีจุดประสงค์เพื่อแสดงให้เห็นว่านักพัฒนาแอปจะไปยังส่วนต่างๆ เหล่านี้และจัดการการวางแนวกล้องในแอป Android ได้อย่างไร
เพื่อความสะดวกยิ่งขึ้น ให้ถือว่าตัวอย่างทั้งหมดเกี่ยวข้องกับกล้องด้านหลัง เว้นแต่จะระบุไว้เป็นอย่างอื่น นอกจากนี้ รูปภาพต่อไปนี้ทั้งหมดเป็นการจำลองเพื่อให้ภาพประกอบชัดเจนยิ่งขึ้น
ข้อมูลทั้งหมดเกี่ยวกับการปฐมนิเทศ
การวางแนวตามธรรมชาติ
การวางแนวตามธรรมชาติหมายถึงการวางแนวของจอแสดงผลเมื่ออุปกรณ์อยู่ในตำแหน่งที่คาดไว้ตามปกติ สำหรับโทรศัพท์ การวางแนวตามธรรมชาติมักจะเป็นแนวตั้ง กล่าวคือ โทรศัพท์มีความกว้างสั้นลงและความสูงยาวขึ้น สำหรับแล็ปท็อป การวางแนวตามธรรมชาติคือแนวนอน ซึ่งหมายความว่ามีความกว้างยาวกว่าความสูง แท็บเล็ตมีความซับซ้อนกว่านี้เล็กน้อย โดยอาจเป็นแนวตั้งหรือแนวนอนก็ได้
การวางแนวเซ็นเซอร์
ในทางเทคนิคแล้ว การวางแนวเซ็นเซอร์จะวัดจากองศาที่ต้องหมุนรูปภาพเอาต์พุตจากเซ็นเซอร์ตามเข็มนาฬิกาเพื่อให้ตรงกับการวางแนวตามธรรมชาติของอุปกรณ์ กล่าวอีกนัยหนึ่งคือ การวางแนวเซ็นเซอร์คือจำนวนองศาที่เซ็นเซอร์หมุนทวนเข็มนาฬิกาก่อนที่จะติดตั้งบนอุปกรณ์ เมื่อมองที่หน้าจอ การหมุนจะดูเหมือนเป็นการหมุนตามเข็มนาฬิกา เนื่องจากเซ็นเซอร์กล้องหลังติดตั้งอยู่ที่ด้าน "หลัง" ของอุปกรณ์
ตามคำจำกัดความความเข้ากันได้ของ Android 10 ข้อ 7.5.5 การวางแนวกล้อง กล้องหน้าและกล้องหลัง "ต้องวางแนวให้มิติยาวของกล้องสอดคล้องกับมิติยาวของหน้าจอ"
บัฟเฟอร์เอาต์พุตจากกล้องมีขนาดแนวนอน เนื่องจากโดยปกติแล้วโทรศัพท์จะอยู่ในแนวนอน เซ็นเซอร์จึงมักจะหมุน 90 หรือ 270 องศาจากแนวนอนเพื่อให้ด้านยาวของบัฟเฟอร์เอาต์พุตตรงกับด้านยาวของหน้าจอ การวางแนวเซ็นเซอร์จะแตกต่างกันสำหรับอุปกรณ์ที่มีการวางแนวตามธรรมชาติเป็นแนวนอน เช่น Chromebook ในอุปกรณ์เหล่านี้ เซ็นเซอร์รูปภาพจะวางอีกครั้งเพื่อให้ด้านยาวของบัฟเฟอร์เอาต์พุตตรงกับด้านยาวของหน้าจอ เนื่องจากทั้ง 2 รูปมีขนาดแนวนอน การวางแนวจึงตรงกัน และการวางแนวเซ็นเซอร์จึงเป็น 0 หรือ 180 องศา
ภาพต่อไปนี้แสดงลักษณะที่ปรากฏจากมุมมองของผู้สังเกตการณ์ที่มองหน้าจออุปกรณ์
ลองพิจารณาฉากต่อไปนี้
| โทรศัพท์ | แล็ปท็อป |
|---|---|
![]() |
![]() |
เนื่องจากโดยปกติแล้วการวางแนวเซ็นเซอร์ในโทรศัพท์จะอยู่ที่ 90 หรือ 270 องศา หากไม่ได้คำนึงถึงการวางแนวเซ็นเซอร์ รูปภาพที่คุณจะได้รับจะมีลักษณะดังนี้
| โทรศัพท์ | แล็ปท็อป |
|---|---|
![]() |
![]() |
สมมติว่าการวางแนวเซ็นเซอร์ทวนเข็มนาฬิกาจัดเก็บไว้ในตัวแปร sensorOrientation หากต้องการชดเชยการวางแนวเซ็นเซอร์ คุณต้องหมุนบัฟเฟอร์เอาต์พุต ตามเข็มนาฬิกา `sensorOrientation` เพื่อให้การวางแนวกลับมาสอดคล้องกับการวางแนวตามธรรมชาติของอุปกรณ์
ใน Android แอปสามารถใช้ TextureView หรือ SurfaceView เพื่อแสดงตัวอย่างกล้องได้ ทั้ง 2 อย่างนี้สามารถจัดการการวางแนวเซ็นเซอร์ได้หากแอปใช้งานอย่างถูกต้อง เราจะอธิบายรายละเอียดเกี่ยวกับวิธีพิจารณาการวางแนวเซ็นเซอร์ในส่วนต่อไปนี้
การหมุนจอแสดงผล
การหมุนจอแสดงผลจะกำหนดอย่างเป็นทางการโดยการหมุนกราฟิกที่วาดบนหน้าจอ ซึ่งเป็นการหมุนในทิศทางตรงกันข้ามกับการหมุนทางกายภาพของอุปกรณ์จากการวางแนวปกติ ส่วนต่อไปนี้ถือว่าการหมุนจอแสดงผลทั้งหมดเป็นทวีคูณของ 90 หากดึงการหมุนจอแสดงผลตามองศาที่แน่นอน ให้ปัดขึ้นเป็นค่าที่ใกล้ที่สุดใน {0, 90, 180, 270}
"การวางแนวการแสดงผล" ในส่วนต่อไปนี้หมายถึงการถืออุปกรณ์ในแนวนอนหรือแนวตั้ง และแตกต่างจาก "การหมุนการแสดงผล"
สมมติว่าคุณหมุนอุปกรณ์ 90 องศาทวนเข็มนาฬิกาจากตำแหน่งก่อนหน้า ดังที่แสดงในรูปต่อไปนี้
สมมติว่ามีการหมุนบัฟเฟอร์เอาต์พุตตามการวางแนวของเซ็นเซอร์แล้ว คุณจะมีบัฟเฟอร์เอาต์พุตดังนี้
| โทรศัพท์ | แล็ปท็อป |
|---|---|
![]() |
![]() |
หากการหมุนจอแสดงผลจัดเก็บไว้ในตัวแปร displayRotation คุณควรหมุนบัฟเฟอร์เอาต์พุตตามตัวนับ displayRotation ทวนเข็มนาฬิกาเพื่อให้ได้รูปภาพที่ถูกต้อง
สำหรับกล้องหน้า การหมุนจอแสดงผลจะทำงานกับบัฟเฟอร์รูปภาพในทิศทางตรงกันข้ามกับหน้าจอ หากใช้กล้องหน้า คุณควรหมุนบัฟเฟอร์ตาม displayRotatation ตามเข็มนาฬิกา
ข้อควรระวัง
การหมุนจอแสดงผลจะวัดการหมุนทวนเข็มนาฬิกาของอุปกรณ์ แต่ไม่ได้เป็นเช่นนี้เสมอไปสำหรับ API การวางแนว/การหมุน
ตัวอย่างเช่น
-
หากใช้
Display#getRotation()คุณจะได้รับการหมุนทวนเข็มนาฬิกาตามที่ระบุไว้ในเอกสารนี้ - หากใช้ OrientationEventListener#onOrientationChanged(int) คุณจะได้รับการหมุนตามเข็มนาฬิกาแทน
สิ่งสำคัญที่ควรทราบคือการหมุนจอแสดงผลจะสัมพันธ์กับการวางแนวตามธรรมชาติ เช่น หากหมุนโทรศัพท์ 90 หรือ 270 องศา คุณจะเห็นหน้าจอเป็นแนวนอน ในทางตรงกันข้าม หากหมุนแล็ปท็อปในปริมาณเท่ากัน คุณจะได้หน้าจอรูปแนวตั้ง แอปควรคำนึงถึงเรื่องนี้เสมอและไม่ควรคาดเดาการวางแนวตามธรรมชาติของอุปกรณ์
ตัวอย่าง
มาใช้ตัวเลขก่อนหน้าเพื่ออธิบายว่าการวางแนวและการหมุนคืออะไร
| โทรศัพท์ | แล็ปท็อป |
|---|---|
| การวางแนวตามธรรมชาติ = แนวตั้ง | การวางแนวตามธรรมชาติ = แนวนอน |
| การวางแนวเซ็นเซอร์ = 90 | การวางแนวเซ็นเซอร์ = 0 |
| Display Rotation = 0 | Display Rotation = 0 |
| การวางแนวจอแสดงผล = แนวตั้ง | การวางแนวจอแสดงผล = แนวนอน |
| โทรศัพท์ | แล็ปท็อป |
|---|---|
| การวางแนวตามธรรมชาติ = แนวตั้ง | การวางแนวตามธรรมชาติ = แนวนอน |
| การวางแนวเซ็นเซอร์ = 90 | การวางแนวเซ็นเซอร์ = 0 |
| Display Rotation = 90 | Display Rotation = 90 |
| การวางแนวจอแสดงผล = แนวนอน | การวางแนวจอแสดงผล = แนวตั้ง |
ขนาดช่องมองภาพ
แอปควรปรับขนาดช่องมองภาพตามการวางแนว การหมุน และความละเอียดของหน้าจอเสมอ โดยทั่วไปแล้ว แอปควรทำให้การวางแนวของช่องมองภาพเหมือนกับการวางแนวการแสดงผลปัจจุบัน กล่าวอีกนัยหนึ่งคือ แอปควรจัดแนวขอบยาวของช่องมองภาพให้ตรงกับขอบยาวของหน้าจอ
ขนาดเอาต์พุตของรูปภาพตามกล้อง
เมื่อเลือกขนาดเอาต์พุตของรูปภาพสำหรับการแสดงตัวอย่าง คุณควรเลือกขนาดที่เท่ากับหรือใหญ่กว่าขนาดของช่องมองภาพเล็กน้อยทุกครั้งที่เป็นไปได้ โดยทั่วไปแล้ว คุณไม่ต้องการให้บัฟเฟอร์เอาต์พุตได้รับการปรับขนาดขึ้น ซึ่งจะทำให้เกิดการแตกพิกเซล นอกจากนี้ คุณไม่ควรเลือกขนาดที่ใหญ่เกินไปซึ่งอาจลดประสิทธิภาพและใช้แบตเตอรี่มากขึ้น
การวางแนว JPEG
มาเริ่มกันด้วยสถานการณ์ที่พบได้บ่อย นั่นคือการถ่ายรูป JPEG ใน Camera2 API คุณสามารถส่ง JPEG_ORIENTATION ในคำขอจับภาพเพื่อระบุจำนวนที่ต้องการให้หมุน JPEG เอาต์พุตตามเข็มนาฬิกา
สรุปสั้นๆ เกี่ยวกับสิ่งที่เรากล่าวถึง
-
หากต้องการจัดการการวางแนวเซ็นเซอร์ คุณต้องหมุนบัฟเฟอร์รูปภาพตามเข็มนาฬิกา
sensorOrientation -
หากต้องการจัดการการหมุนจอแสดงผล คุณต้องหมุนบัฟเฟอร์โดย
displayRotationทวนเข็มนาฬิกาสำหรับกล้องหลัง และตามเข็มนาฬิกาสำหรับกล้องหน้า
เมื่อรวม 2 ปัจจัยเข้าด้วยกัน จำนวนที่คุณต้องการหมุนตามเข็มนาฬิกาคือ
-
sensorOrientation - displayRotationสำหรับกล้องหลัง -
sensorOrientation + displayRotationสำหรับกล้องหน้า
คุณดูตัวอย่างโค้ดสำหรับตรรกะนี้ได้ในเอกสารประกอบ JPEG_ORIENTATION โปรดทราบว่า deviceOrientation ในโค้ดตัวอย่างของเอกสารประกอบใช้การหมุนอุปกรณ์ตามเข็มนาฬิกา ดังนั้นสัญญาณสำหรับการหมุนเวียนการแสดงผลจึงกลับกัน
แสดงตัวอย่าง
แล้วตัวอย่างจากกล้องล่ะ แอปแสดงตัวอย่างกล้องได้ 2 วิธีหลักๆ ได้แก่ SurfaceView และ TextureView ซึ่งแต่ละรายการต้องใช้วิธีการที่แตกต่างกันเพื่อจัดการการวางแนวให้ถูกต้อง
SurfaceView
โดยทั่วไป เราขอแนะนำให้ใช้ SurfaceView สำหรับการแสดงตัวอย่างกล้องในกรณีที่คุณไม่จำเป็นต้องประมวลผลหรือเคลื่อนไหวบัฟเฟอร์การแสดงตัวอย่าง มีประสิทธิภาพมากกว่าและใช้ทรัพยากรน้อยกว่า TextureView
นอกจากนี้ SurfaceView ยังจัดวางได้ง่ายกว่าด้วย คุณเพียงแค่ต้องกังวลเกี่ยวกับสัดส่วนภาพของ SurfaceView ที่คุณกำลังแสดงตัวอย่างกล้อง
แหล่งที่มา
แพลตฟอร์ม Android จะหมุนบัฟเฟอร์เอาต์พุตใต้ SurfaceView ให้ตรงกับการวางแนวการแสดงผลของอุปกรณ์ กล่าวคือ จะพิจารณาทั้งการวางแนวเซ็นเซอร์และการหมุนจอแสดงผล พูดง่ายๆ ก็คือ เมื่อจอแสดงผลเป็นแนวนอน เราจะเห็นตัวอย่างที่เป็นแนวนอนเช่นกัน และในทางกลับกันเมื่อจอแสดงผลเป็นแนวตั้ง เราก็จะเห็นตัวอย่างที่เป็นแนวตั้ง
ตารางต่อไปนี้แสดงให้เห็นถึงความแตกต่างนี้ สิ่งสำคัญที่ต้องจำไว้คือการหมุนจอแสดงผลเพียงอย่างเดียวไม่ได้กำหนดการวางแนวของแหล่งที่มา
| การหมุนจอแสดงผล | โทรศัพท์ (การวางแนวตามธรรมชาติ = แนวตั้ง) | แล็ปท็อป (การวางแนวตามธรรมชาติ = แนวนอน) |
|---|---|---|
| 0 | ![]() |
![]() |
| 90 | ![]() |
![]() |
| 180 | ![]() |
![]() |
| 270 | ![]() |
![]() |
การจัดวาง
ดังที่เห็น SurfaceView จัดการสิ่งต่างๆ ที่ซับซ้อนบางอย่างให้เราอยู่แล้ว แต่ตอนนี้คุณต้องพิจารณาขนาดของช่องมองภาพ หรือขนาดของตัวอย่างที่ต้องการบนหน้าจอ SurfaceView จะปรับขนาดบัฟเฟอร์ต้นทางให้พอดีกับขนาดของตัวเองโดยอัตโนมัติ คุณต้องตรวจสอบว่าสัดส่วนภาพของช่องมองภาพเหมือนกับของ SourceBuffer ตัวอย่างเช่น หากพยายามใส่ตัวอย่างรูปภาพแนวตั้งลงใน SurfaceView แนวนอน คุณจะเห็นภาพที่บิดเบี้ยวคล้ายกับภาพนี้
โดยทั่วไปแล้ว คุณต้องการให้สัดส่วนภาพ (เช่น ความกว้าง/ความสูง) ของช่องมองภาพเหมือนกับสัดส่วนภาพของแหล่งที่มา หากไม่ต้องการครอบตัดรูปภาพในช่องมองภาพ ซึ่งเป็นการตัดพิกเซลบางส่วนออกเพื่อแก้ไขการแสดงผล ให้พิจารณากรณีต่อไปนี้เมื่อ aspectRatioActivity มากกว่า aspectRatioSource และเมื่อ aspectRatioActivity น้อยกว่าหรือเท่ากับ aspectRatioSource
aspectRatioActivity > aspectRatioSource
คุณอาจคิดว่าเคสคือกิจกรรมที่ "กว้างกว่า" ด้านล่างนี้เป็นตัวอย่างกรณีที่คุณมีกิจกรรม 16:9 และแหล่งที่มา 4:3
aspectRatioActivity = 16/9 ≈ 1.78 aspectRatioSource = 4/3 ≈ 1.33
ก่อนอื่น คุณต้องตั้งค่าช่องมองภาพเป็น 4:3 ด้วย จากนั้นคุณจะต้องปรับแหล่งที่มาและช่องมองภาพให้พอดีกับกิจกรรม ดังนี้
ในกรณีนี้ คุณควรทำให้ความสูงของช่องมองภาพตรงกับความสูงของกิจกรรมในขณะที่ทำให้อัตราส่วนภาพของช่องมองภาพเหมือนกับอัตราส่วนภาพของแหล่งที่มา ซูโดโค้ดมีดังนี้
viewfinderHeight = activityHeight; viewfinderWidth = activityHeight * aspectRatioSource;
aspectRatioActivity ≤ aspectRatioSource
อีกกรณีคือเมื่อกิจกรรม "แคบกว่า" หรือ "สูงกว่า" เราสามารถใช้ตัวอย่างก่อนหน้าซ้ำได้ ยกเว้นในตัวอย่างต่อไปนี้ที่คุณหมุนอุปกรณ์ 90 องศา ทำให้กิจกรรมเป็น 9:16 และแหล่งที่มาเป็น 3:4
aspectRatioActivity = 9/16 = 0.5625 aspectRatioSource = 3/4 = 0.75
ในกรณีนี้ คุณจะต้องปรับแหล่งที่มาและช่องมองภาพให้พอดีกับกิจกรรม ดังนี้
คุณควรทำให้ความกว้างของช่องมองภาพตรงกับความกว้างของกิจกรรม (แทนที่จะเป็นความสูงในกรณีที่ผ่านมา) ขณะเดียวกันก็ทำให้อัตราส่วนของช่องมองภาพเหมือนกับอัตราส่วนของแหล่งที่มา ซูโดโค้ด
viewfinderWidth = activityWidth; viewfinderHeight = activityWidth / aspectRatioSource;
เสียงขาดๆ หายๆ
AutoFitSurfaceView.kt (github) จากตัวอย่าง Camera2 จะลบล้าง SurfaceView และจัดการสัดส่วนภาพที่ไม่ตรงกันโดยใช้รูปภาพที่มีขนาดเท่ากับหรือ "ใหญ่กว่าเล็กน้อย" กิจกรรมในทั้ง 2 มิติ แล้วจึงตัดเนื้อหาที่ล้นออกมา ซึ่งจะเป็นประโยชน์สำหรับแอปที่ต้องการให้ตัวอย่างครอบคลุมทั้งกิจกรรมหรือเติมเต็มมุมมองที่มีขนาดคงที่โดยไม่บิดเบือนรูปภาพ
ข้อควรระวัง
ตัวอย่างก่อนหน้าพยายามใช้พื้นที่หน้าจอให้ได้มากที่สุดโดยการทำให้ตัวอย่างมีขนาดใหญ่กว่ากิจกรรมเล็กน้อยเพื่อไม่ให้มีพื้นที่เหลือ ซึ่งอาศัยข้อเท็จจริงที่ว่าเลย์เอาต์หลัก (หรือ ViewGroup) จะตัดส่วนที่ล้นออกโดยค่าเริ่มต้น ลักษณะการทำงานจะสอดคล้องกับ RelativeLayout และ LinearLayout แต่จะไม่สอดคล้องกับ ConstraintLayout ConstraintLayout อาจปรับขนาด View ขององค์ประกอบย่อยเพื่อให้พอดีกับเลย์เอาต์ ซึ่งจะทำให้เอฟเฟกต์ "ครอบตัดตรงกลาง" ที่ตั้งใจไว้ไม่ทำงานและทำให้ตัวอย่างยืด คุณสามารถใช้การเปลี่ยนแปลงนี้เป็นข้อมูลอ้างอิงได้
TextureView
TextureView ช่วยให้ควบคุมเนื้อหาของตัวอย่างกล้องได้สูงสุด แต่มีผลต่อประสิทธิภาพ นอกจากนี้ยังต้องใช้ความพยายามมากขึ้นเพื่อให้แสดงตัวอย่างกล้องได้อย่างถูกต้อง
แหล่งที่มา
ภายใต้ TextureView แพลตฟอร์ม Android จะหมุนบัฟเฟอร์เอาต์พุตตามการวางแนวของเซ็นเซอร์เพื่อให้ตรงกับการวางแนวตามธรรมชาติของอุปกรณ์ แม้ว่า TextureView จะจัดการการวางแนวเซ็นเซอร์ แต่ก็ไม่ได้จัดการการหมุนจอแสดงผล โดยจะจัดแนวบัฟเฟอร์เอาต์พุตให้สอดคล้องกับการวางแนวตามธรรมชาติของอุปกรณ์ ซึ่งหมายความว่าคุณจะต้องจัดการการหมุนจอแสดงผลด้วยตนเอง
ตารางต่อไปนี้แสดงให้เห็นถึงความแตกต่างนี้ ลองหมุนตัวเลขตามการหมุนจอแสดงผลที่เกี่ยวข้อง คุณจะเห็นตัวเลขเดียวกันใน SurfaceView
| การหมุนจอแสดงผล | โทรศัพท์ (การวางแนวตามธรรมชาติ = แนวตั้ง) | แล็ปท็อป (การวางแนวตามธรรมชาติ = แนวนอน) |
|---|---|---|
| 0 | ![]() |
![]() |
| 90 | ![]() |
![]() |
| 180 | ![]() |
![]() |
| 270 | ![]() |
![]() |
การจัดวาง
เลย์เอาต์สำหรับ TextureView อาจซับซ้อนเล็กน้อย ก่อนหน้านี้เราได้แนะนำให้ใช้เมทริกซ์การเปลี่ยนรูปแบบสำหรับ TextureView แต่เมธอดดังกล่าวใช้ไม่ได้กับอุปกรณ์บางรุ่น เราขอแนะนําให้คุณทําตามขั้นตอนที่อธิบายไว้ที่นี่แทน
กระบวนการ 3 ขั้นตอนในการจัดวางตัวอย่างอย่างถูกต้องใน TextureView มีดังนี้
- ตั้งค่าขนาดของ TextureView ให้เหมือนกับขนาดตัวอย่างที่เลือก
- ปรับขนาด TextureView ที่อาจยืดออกกลับไปเป็นขนาดเดิมของตัวอย่าง
-
หมุน TextureView โดย
displayRotationทวนเข็มนาฬิกา
สมมติว่าคุณมีโทรศัพท์ที่หมุนจอแสดงผลได้ 90 องศา
1. ตั้งค่าขนาดของ TextureView ให้เหมือนกับขนาดตัวอย่างที่เลือก
สมมติว่าขนาดตัวอย่างที่คุณเลือกคือ previewWidth × previewHeight โดยที่ previewWidth > previewHeight (เอาต์พุตของเซ็นเซอร์เป็นแนวนอนโดยธรรมชาติ) เมื่อกำหนดค่าเซสชันการจับภาพ ผู้ใช้ควรเรียกใช้ SurfaceTexture#setDefaultBufferSize(int width, height) เพื่อระบุขนาดตัวอย่าง (previewWidth × previewHeight)
ก่อนที่จะเรียกใช้ setDefaultBufferSize คุณต้องตั้งค่าขนาดของ TextureView เป็น `previewWidth × previewHeight` ด้วย View#setLayoutParams(android.view.ViewGroup.LayoutParams) สาเหตุเป็นเพราะ TextureView เรียก SurfaceTexture#setDefaultBufferSize(int width, height) ด้วยความกว้างและความสูงที่วัดได้ หากไม่ได้ตั้งค่าขนาดของ TextureView อย่างชัดเจนล่วงหน้า อาจทำให้เกิด Race Condition ได้ ปัญหานี้จะลดลงได้ด้วยการตั้งค่าขนาดของ TextureView อย่างชัดเจนก่อน
ตอนนี้ TextureView อาจไม่ตรงกับขนาดของแหล่งที่มา ในกรณีของโทรศัพท์ แหล่งที่มาจะเป็นรูปแนวตั้ง แต่ TextureView จะเป็นรูปแนวนอนเนื่องจาก layoutParams ที่คุณเพิ่งตั้งค่า ซึ่งจะส่งผลให้ตัวอย่างยืดออก ดังที่แสดงในภาพนี้
2. ปรับขนาด TextureView ที่อาจยืดออกกลับไปเป็นขนาดเดิมของตัวอย่าง
พิจารณาสิ่งต่อไปนี้เพื่อปรับขนาดตัวอย่างที่ยืดกลับไปเป็นขนาดของแหล่งที่มา
มิติข้อมูลของแหล่งที่มา (sourceWidth × sourceHeight) คือ
-
previewHeight × previewWidthหากการวางแนวตามธรรมชาติเป็นแนวตั้งหรือแนวตั้งกลับด้าน (การวางแนวเซ็นเซอร์คือ 90 หรือ 270 องศา) -
previewWidth × previewHeightหากการวางแนวตามธรรมชาติเป็นแนวนอนหรือแนวนอนกลับด้าน (การวางแนวเซ็นเซอร์เป็น 0 หรือ 180 องศา)
แก้ไขการยืดโดยใช้ View#setScaleX(float) และ View#setScaleY(float)
-
setScaleX(
sourceWidth / previewWidth) -
setScaleY(
sourceHeight / previewHeight)
3. หมุนตัวอย่าง `displayRotation` ทวนเข็มนาฬิกา
ดังที่ได้กล่าวไว้ก่อนหน้านี้ คุณควรหมุนตัวอย่างdisplayRotationทวนเข็มนาฬิกาเพื่อชดเชยการหมุนจอแสดงผล
คุณทำได้โดยView#setRotation(float)
-
setRotation(
-displayRotation) เนื่องจากเป็นการหมุนตามเข็มนาฬิกา
ตัวอย่าง
-
PreviewViewจาก camerax ใน Jetpack จะจัดการเลย์เอาต์ TextureView ตามที่อธิบายไว้ก่อนหน้านี้ ซึ่งจะกำหนดค่าการเปลี่ยนรูปแบบด้วย PreviewCorrector
หมายเหตุ: หากก่อนหน้านี้คุณใช้เมทริกซ์การเปลี่ยนรูปแบบสำหรับ TextureView ในโค้ด ตัวอย่างอาจดูไม่ถูกต้องในอุปกรณ์แนวนอนโดยธรรมชาติ เช่น Chromebook เมทริกซ์การแปลงอาจถือว่าการวางแนวเซ็นเซอร์เป็น 90 หรือ 270 องศาอย่างไม่ถูกต้อง คุณอาจดูคอมมิตนี้ใน GitHub เพื่อดูวิธีแก้ปัญหาชั่วคราว แต่เราขอแนะนำอย่างยิ่งให้คุณย้ายข้อมูลแอปไปใช้วิธีที่อธิบายไว้ที่นี่แทน





















