สร้างภาพขนาดย่อของสื่อ

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

ทั้งนี้ขึ้นอยู่กับประเภทไฟล์และการเข้าถึงไฟล์ของคุณในแอปพลิเคชัน และ เนื้อหาสื่อของคุณ คุณสามารถสร้างภาพขนาดย่อได้หลายวิธี

สร้างภาพขนาดย่อโดยใช้ไลบรารีการโหลดรูปภาพ

ไลบรารีการโหลดรูปภาพจะทํางานหนักให้คุณมากมาย ไลบรารีสามารถจัดการแคชพร้อมกับตรรกะในการดึงข้อมูลสื่อต้นทางจากทรัพยากรในเครื่องหรือเครือข่ายตาม Uri โค้ดต่อไปนี้แสดงการใช้ ไลบรารีการโหลดรูปภาพCilใช้ได้กับทั้งรูปภาพและวิดีโอ และทำงานกับทรัพยากรภายในหรือเครือข่าย

// Use Coil to create and display a thumbnail of a video or image with a specific height
// ImageLoader has its own memory and storage cache, and this one is configured to also
// load frames from videos
val videoEnabledLoader = ImageLoader.Builder(context)
    .components {
        add(VideoFrameDecoder.Factory())
    }.build()
// Coil requests images that match the size of the AsyncImage composable, but this allows
// for precise control of the height
val request = ImageRequest.Builder(context)
    .data(mediaUri)
    .size(Int.MAX_VALUE, THUMBNAIL_HEIGHT)
    .build()
AsyncImage(
    model = request,
    imageLoader = videoEnabledLoader,
    modifier = Modifier
        .clip(RoundedCornerShape(20))    ,
    contentDescription = null
)

สร้างภาพปกฝั่งเซิร์ฟเวอร์หากเป็นไปได้ ดูการโหลดรูปภาพ เพื่อดูรายละเอียดเกี่ยวกับวิธีโหลดรูปภาพโดยใช้การเขียน และการโหลดบิตแมปขนาดใหญ่ อย่างมีประสิทธิภาพสำหรับคำแนะนำเกี่ยวกับวิธีทำงานกับรูปภาพขนาดใหญ่

สร้างภาพปกจากไฟล์ภาพในเครื่อง

การใช้ภาพขนาดย่อเกี่ยวข้องกับการลดขนาดลงอย่างมีประสิทธิภาพโดยยังคงรักษาภาพไว้ได้ คุณภาพ หลีกเลี่ยงการใช้หน่วยความจำมากเกินไป การจัดการกับรูปภาพที่หลากหลาย รูปแบบเหล่านี้ และการใช้ข้อมูล Exif อย่างถูกต้อง

เมธอด createImageThumbnail จะทําสิ่งเหล่านี้ทั้งหมดหากคุณมีสิทธิ์เข้าถึงเส้นทางของไฟล์รูปภาพ

val bitmap = ThumbnailUtils.createImageThumbnail(File(file_path), Size(640, 480), null)

หากมีเฉพาะ Uri คุณสามารถใช้เมธอด loadThumbnail ใน ContentesRevr เริ่มต้นด้วย Android 10, API ระดับ 29

val thumbnail: Bitmap =
        applicationContext.contentResolver.loadThumbnail(
        content-uri, Size(640, 480), null)

ImageDecoder พร้อมให้ใช้งานตั้งแต่ Android 9, API ระดับ 28 เป็นต้นไป ตัวเลือกที่เสถียรในการสุ่มตัวอย่างรูปภาพอีกครั้งเมื่อคุณถอดรหัสเพื่อไม่ให้มีหน่วยความจำเพิ่มเติม

class DecodeResampler(val size: Size, val signal: CancellationSignal?) : OnHeaderDecodedListener {
    private val size: Size

   override fun onHeaderDecoded(decoder: ImageDecoder, info: ImageInfo, source:
       // sample down if needed.
        val widthSample = info.size.width / size.width
        val heightSample = info.size.height / size.height
        val sample = min(widthSample, heightSample)
        if (sample > 1) {
            decoder.setTargetSampleSize(sample)
        }
    }
}

val resampler = DecoderResampler(size, null)
val source = ImageDecoder.createSource(context.contentResolver, imageUri)
val bitmap = ImageDecoder.decodeBitmap(source, resampler);

คุณใช้ Bitmapfactor เพื่อสร้างภาพขนาดย่อสำหรับการกำหนดเป้าหมายแอปได้เร็วขึ้นได้ รุ่นต่างๆ ของ Android Bitmapfactor.Options มีการตั้งค่าเพื่อถอดรหัสเฉพาะ ขอบเขตของรูปภาพเพื่อวัตถุประสงค์ในการสุ่มตัวอย่างใหม่

ก่อนอื่น ให้ถอดรหัสเฉพาะขอบเขตของบิตแมปลงใน BitmapFactory.Options ดังนี้

private fun decodeResizedBitmap(context: Context, uri: Uri, size: Size): Bitmap?{
    val boundsStream = context.contentResolver.openInputStream(uri)
    val options = BitmapFactory.Options()
    options.inJustDecodeBounds = true
    BitmapFactory.decodeStream(boundsStream, null, options)
    boundsStream?.close()

ใช้ width และ height จาก BitmapFactory.Options เพื่อตั้งค่าตัวอย่าง ขนาด:

if ( options.outHeight != 0 ) {
        // we've got bounds
        val widthSample = options.outWidth / size.width
        val heightSample = options.outHeight / size.height
        val sample = min(widthSample, heightSample)
        if (sample > 1) {
            options.inSampleSize = sample
        }
    }

ถอดรหัสสตรีม ขนาดของภาพผลลัพธ์จะถูกสุ่มตัวอย่างด้วยเลขสอง อิงตาม inSampleSize

    options.inJustDecodeBounds = false
    val decodeStream = context.contentResolver.openInputStream(uri)
    val bitmap =  BitmapFactory.decodeStream(decodeStream, null, options)
    decodeStream?.close()
    return bitmap
}

สร้างภาพปกจากไฟล์วิดีโอในเครื่อง

การรับภาพขนาดย่อของวิดีโอเกี่ยวข้องกับความท้าทายหลายอย่างเช่นเดียวกับ แต่ขนาดไฟล์อาจใหญ่กว่ามาก เฟรมวิดีโอตัวแทนอาจจะไม่ตรงไปตรงมา เหมือนการเลือกเฟรมแรก เฟรมของวิดีโอได้

เมธอด createVideoThumbnail เป็นตัวเลือกที่ดีหากคุณมีสิทธิ์เข้าถึง เส้นทางของไฟล์วิดีโอ

val bitmap = ThumbnailUtils.createVideoThumbnail(File(file_path), Size(640, 480), null)

หากคุณมีสิทธิ์เข้าถึงเนื้อหา URI เท่านั้น คุณสามารถใช้ MediaMetadataRetriever

ขั้นแรก ให้ตรวจสอบว่าวิดีโอมีภาพขนาดย่อฝังไว้หรือไม่ และใช้ภาพนั้นหาก ที่เป็นไปได้:

private suspend fun getVideoThumbnailFromMediaMetadataRetriever(context: Context, uri: Uri, size: Size): Bitmap? {
    val mediaMetadataRetriever = MediaMetadataRetriever()
    mediaMetadataRetriever.setDataSource(context, uri)
    val thumbnailBytes = mediaMetadataRetriever.embeddedPicture
    val resizer = Resizer(size, null)
    ImageDecoder.createSource(context.contentResolver, uri)
    // use a built-in thumbnail if the media file has it
    thumbnailBytes?.let {
        return ImageDecoder.decodeBitmap(ImageDecoder.createSource(it));
    }

ดึงข้อมูลความกว้างและความสูงของวิดีโอจาก MediaMetadataRetriever ไปยัง คำนวณค่าตัวคูณมาตราส่วน:

val width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)
            ?.toFloat() ?: size.width.toFloat()
    val height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)
            ?.toFloat() ?: size.height.toFloat()
    val widthRatio = size.width.toFloat() / width
    val heightRatio = size.height.toFloat() / height
    val ratio = max(widthRatio, heightRatio)

ใน Android 9 ขึ้นไป (API ระดับ 28) MediaMetadataRetriever จะแสดงเฟรมที่ปรับขนาดแล้วได้ ดังนี้

if (ratio > 1) {
        val requestedWidth = width * ratio
        val requestedHeight = height * ratio
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val frame = mediaMetadataRetriever.getScaledFrameAtTime(
                -1, OPTION_PREVIOUS_SYNC,
                requestedWidth.toInt(), requestedHeight.toInt())
            mediaMetadataRetriever.close()
            return frame
        }
    }

หรือจะแสดงเฟรมแรกแบบไม่ปรับขนาดก็ได้

    // consider scaling this after the fact
    val frame = mediaMetadataRetriever.frameAtTime
    mediaMetadataRetriever.close()
    return frame
}