Сохранение изображения с камеры Android2 в формат PNG без потерь

Я пытаюсь сохранить изображения android.hardware.camera2 в формате без потерь.

У меня это работает для JPEG (с потерями) и DMG (необработанных, но огромных и трудных для работы) с использованием выделенных фрагментов кода:

private fun save(image: Image, captureResult: TotalCaptureResult) {
    val fileWithoutExtension = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "myimage_${System.currentTimeMillis()}")
    val file: File = when (image.format) {
        ImageFormat.JPEG -> {
            val buffer = image.planes[0].buffer
            val bytes = ByteArray(buffer.remaining())
            buffer.get(bytes)
            val file = File("$fileWithoutExtension.jpg")
            file.writeBytes(bytes)
            file
        }
        ImageFormat.RAW_SENSOR -> {
            val dngCreator = DngCreator(mode.characteristics, captureResult)
            val file = File("$fileWithoutExtension.dmg")
            FileOutputStream(file).use { os ->
                dngCreator.writeImage(os, image)
            }
            file
        }
        else -> TODO("Unsupported image format: ${image.format}")
    }
    Log.i(TAG, "Wrote image:${file.canonicalPath} ${file.length() / 1024}k")
    image.close() // necessary when taking a few shots
}

но то, на чем я застрял, - это заменить этот раздел RAW_SENSOR чем-то, что сохраняет более разумный PNG. Это

  1. плохая идея, потому что RAW_SENSOR настолько отличается от обычного формата изображения, что мне придется пройти через слишком много боли, чтобы преобразовать его?
  2. плохая идея, потому что я должен был установить входной захват, чтобы захватить что-то более разумное, например, FLEX_RGB_888?
  3. хорошая идея, потому что в следующем коде есть какая-то глупая ошибка? (который умирает с Buffer not large enough for pixels at android.graphics.Bitmap.copyPixelsFromBuffer(Bitmap.java:593)

моя попытка:

fun writeRawImageToPng(image: Image, pngFile: File) {
    Bitmap.createBitmap(image.width, image.height, Bitmap.Config.ARGB_8888).let { latestBitmap->
        latestBitmap.copyPixelsFromBuffer(image.planes[0].buffer!!)
        ByteArrayOutputStream().use { baos ->
            latestBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos)
            pngFile.writeBytes(baos.toByteArray())
        }
    }
}

2 ответа

Вы хотите захватить данные в формате YUV_420_888; это то, с чего начинается компрессор JPEG в любом случае.

Вы должны будете преобразовать это в Растровое изображение RGB самостоятельно, для этого нет удобного метода.

RAW_SENSOR действительно сложно. Спецификации говорят нам, что параметры базовой мозаики Байера могут быть получены из CameraDevice, но нет публичного API для преобразования в Bitmap,

Во всяком случае, нет смысла запрашивать этот сложный формат, если ваша цель - преобразовать его в 8-битное для каждого канала растровое изображение.

Кроме того, ARGB_8888 Растровое изображение для захваченного изображения может быть огромным и приводить к нехватке памяти, если вы недостаточно осторожны.

Другие вопросы по тегам