0Pricing
Android Academy · บทเรียน

การถ่ายภาพ

บันทึกและจัดเก็บรูปภาพ

การถ่ายภาพ เป็นบทเรียน Android Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Android Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน

การถ่ายภาพ

เมื่อมีภาพตัวอย่างบนหน้าจอแล้ว ขั้นตอนถัดไปคือ ถ่ายภาพ CameRX จัดการเรื่องนี้ด้วยกรณีการใช้งาน ImageCapture

คุณจะเชื่อม ImageCapture ไว้พร้อมกับภาพตัวอย่าง จากนั้นเรียก takePicture() เมื่อผู้ใช้แตะปุ่มชัตเตอร์ และบันทึกผลลัพธ์ลงแกลเลอรีของอุปกรณ์

การสร้างกรณีการใช้งาน ImageCapture

ImageCapture กำหนดค่าด้วย builder ตัวเลือกที่มีประโยชน์คือ โหมดการถ่ายภาพ ซึ่งเป็นการแลกเปลี่ยนระหว่างเวลาแฝงกับคุณภาพ:

  • CAPTURE_MODE_MINIMIZE_LATENCY — ชัตเตอร์ทำงานเร็ว
  • CAPTURE_MODE_MAXIMIZE_QUALITY — ภาพมีคุณภาพดีที่สุดแต่ช้าลงเล็กน้อย
val imageCapture = ImageCapture.Builder()
    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
    .build()

การเชื่อม Preview + ImageCapture

คุณสามารถเชื่อมกรณีการใช้งานหลายรายการพร้อมกันได้ ส่งทั้ง preview และ imageCapture ไปยัง bindToLifecycle เพื่อให้กล้องแสดงภาพสดและพร้อมถ่ายภาพ

cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    preview,
    imageCapture
)

จะบันทึกที่ใด: MediaStore

วิธีสมัยใหม่ที่ทำงานได้ดีกับพื้นที่จัดเก็บแบบกำหนดขอบเขตในการบันทึกภาพคือใช้ MediaStore คุณอธิบายไฟล์ (ชื่อ ประเภท MIME โฟลเดอร์) ด้วย ContentValues แล้วให้ระบบจัดเก็บลงในคอลเลกชัน Pictures ที่ใช้ร่วมกัน

วิธีนี้ทำงานได้โดยไม่ต้องใช้สิทธิ์แบบเดิม WRITE_EXTERNAL_STORAGE บน Android 10 ขึ้นไป

val name = "photo_${System.currentTimeMillis()}"
val contentValues = ContentValues().apply {
    put(MediaStore.MediaColumns.DISPLAY_NAME, name)
    put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
    put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/MyApp")
}

ตัวเลือกเอาต์พุต

หากต้องการบอก CameraX ว่าจะเขียนไฟล์ JPEG ที่ใด ให้สร้าง OutputFileOptions จากตัวแก้ไขเนื้อหา URI ของคอลเลกชันเป้าหมาย และ ContentValues ของคุณ

val outputOptions = ImageCapture.OutputFileOptions
    .Builder(
        context.contentResolver,
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        contentValues
    )
    .build()

การเรียก takePicture()

ถึงเวลาสั่งถ่ายภาพแล้ว takePicture() รับตัวเลือกเอาต์พุต Executor และการเรียกกลับ CameRX จะรายงานความสำเร็จหรือข้อผิดพลาดแบบอะซิงโครนัส

ใช้ ContextCompat.getMainExecutor(context) เพื่อให้การเรียกกลับทำงานบนเธรดหลัก

imageCapture.takePicture(
    outputOptions,
    ContextCompat.getMainExecutor(context),
    object : ImageCapture.OnImageSavedCallback {
        override fun onImageSaved(output: ImageCapture.OutputFileResults) {
            val savedUri = output.savedUri
            // Photo saved! Show a confirmation.
        }
        override fun onError(exc: ImageCaptureException) {
            // Handle the failure.
        }
    }
)

การจัดการผลลัพธ์

เมื่อดำเนินการสำเร็จ OutputFileResults.savedUri จะระบุ URI ของรูปภาพที่บันทึกไว้ คุณสามารถแสดงรูปภาพนั้น (ด้วย Coil) แชร์รูปภาพ หรือแสดง Snackbar เพื่อยืนยันการบันทึกได้

หากเกิดข้อผิดพลาด ImageCaptureException จะบอกว่าเกิดอะไรขึ้น — ให้บันทึกข้อผิดพลาดและแจ้งผู้ใช้

override fun onImageSaved(output: ImageCapture.OutputFileResults) {
    val uri = output.savedUri ?: return
    Toast.makeText(context, "Saved: $uri", Toast.LENGTH_SHORT).show()
}

การเชื่อมต่อปุ่มชัตเตอร์

ใน Compose ให้วางปุ่มชัตเตอร์ทับบนตัวอย่างภาพด้วย Box ย้ายการอ้างอิง ImageCapture ขึ้นไปไว้ในระดับที่เหมาะสม เพื่อให้ onClick ของปุ่มเรียกใช้ takePhoto ได้

Box(modifier = Modifier.fillMaxSize()) {
    CameraPreview(imageCapture = imageCapture)
    IconButton(
        onClick = { takePhoto(context, imageCapture) },
        modifier = Modifier
            .align(Alignment.BottomCenter)
            .padding(32.dp)
    ) {
        Icon(Icons.Default.PhotoCamera, contentDescription = "Take photo")
    }
}

การแยก takePhoto()

ทำให้ composable ของคุณเป็นระเบียบด้วยการย้ายตรรกะการถ่ายภาพไปไว้ในตัวช่วย ฟังก์ชันนี้รับ context และ use case ImageCapture สร้างตัวเลือกผลลัพธ์ แล้วเรียกใช้ takePicture

fun takePhoto(context: Context, imageCapture: ImageCapture) {
    val values = ContentValues().apply {
        put(MediaStore.MediaColumns.DISPLAY_NAME, "IMG_${System.currentTimeMillis()}")
        put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
    }
    val options = ImageCapture.OutputFileOptions.Builder(
        context.contentResolver,
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        values
    ).build()

    imageCapture.takePicture(
        options,
        ContextCompat.getMainExecutor(context),
        object : ImageCapture.OnImageSavedCallback {
            override fun onImageSaved(o: ImageCapture.OutputFileResults) {}
            override fun onError(e: ImageCaptureException) {}
        }
    )
}

แฟลชและการหมุนภาพ

รายละเอียดปิดท้ายสองอย่าง:

  • แฟลช: ตั้งค่า imageCapture.flashMode เป็น FLASH_MODE_ON, OFF หรือ AUTO
  • การหมุนภาพ: CameRX ใช้การหมุนเป้าหมายเพื่อจัดแนว JPEG ที่บันทึกให้ถูกต้อง โปรดอัปเดตค่านี้อยู่เสมอเพื่อให้ทิศทางภาพถูกต้อง
imageCapture.flashMode = ImageCapture.FLASH_MODE_AUTO
// Update target rotation when the device rotates:
imageCapture.targetRotation = display.rotation

ประกอบทุกอย่างเข้าด้วยกัน

ลำดับการทำงานทั้งหมดของการถ่ายภาพคือ สร้าง ImageCapture → ผูกเข้ากับตัวอย่างภาพ → เมื่อแตะชัตเตอร์ ให้สร้าง OutputFileOptions และเรียกใช้ takePicture → จัดการ onImageSaved / onError

เพียงไม่กี่บรรทัด คุณก็จะมีกล้องที่บันทึกรูปภาพลงแกลเลอรีได้อย่างสมบูรณ์

ตรวจสอบความเข้าใจ

ตรวจสอบว่าคุณเข้าใจลำดับการถ่ายและบันทึกรูปภาพแล้ว

ทบทวน

ขณะนี้คุณสามารถถ่ายและบันทึกรูปภาพด้วย CameRX ได้แล้ว:

  • สร้าง use case ImageCapture และผูกเข้ากับตัวอย่างภาพ
  • อธิบายผลลัพธ์ด้วย ContentValues และ MediaStore สำหรับพื้นที่จัดเก็บแบบจำกัดขอบเขต
  • เรียกใช้ takePicture() พร้อม OutputFileOptions ตัวประมวลผล และ OnImageSavedCallback
  • อ่านค่า savedUri เมื่อดำเนินการสำเร็จ และจัดการ ImageCaptureException เมื่อเกิดข้อผิดพลาด

ถัดไป คุณจะได้เรียนรู้การบันทึกวิดีโอด้วย use case VideoCapture

คำถามที่พบบ่อย

บทเรียน “การถ่ายภาพ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การถ่ายภาพ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Android Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การถ่ายภาพ”

บันทึกและจัดเก็บรูปภาพ คุณปฏิบัติ Android Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Android Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Android Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การถ่ายภาพ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Android Academy นี้ได้ไหม

ได้ บทเรียน Android Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ภาพรวม CameraX
  2. การแสดงตัวอย่างจากกล้อง
  3. การถ่ายภาพ
  4. การบันทึกวิดีโอ
← กลับไปที่ Android Academy