Medien-Thumbnails generieren

Medien-Thumbnails bieten Nutzern eine schnelle visuelle Vorschau von Bildern und Videos, schnelleres Surfen und visuelle Darstellung der App-Oberfläche ansprechend und interessant sein. Da Miniaturansichten kleiner sind als Medien in voller Größe, Sie sparen Arbeitsspeicher, Speicherplatz und Bandbreite und optimieren die Medienwiedergabe die Browserleistung.

Je nach Dateityp und Dateizugriff in Ihrer Anwendung und Ihrer Media-Assets können Sie auf unterschiedliche Weise Miniaturansichten erstellen.

Thumbnails mit einer Bildladebibliothek erstellen

Die Bibliotheken für das Laden von Bildern übernehmen einen Großteil der Arbeit für Sie. die sie verarbeiten kann, Caching zusammen mit der Logik zum Abrufen der Quellmedien aus dem lokalen Netzwerk oder dem Netzwerk Ressource basierend auf einem Uri. Im folgenden Code wird die Verwendung des Die Bibliothek für das Laden von Coil-Bildern funktioniert sowohl für Bilder als auch für Videos. und arbeitet auf einer lokalen oder Netzwerkressource.

// 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
)

Erstelle Thumbnails wenn möglich serverseitig. Weitere Informationen finden Sie unter Bilder laden. finden Sie weitere Informationen zum Laden von Bildern mit dem Editor und Große Bitmaps laden finden Sie Anleitungen zum Arbeiten mit großen Bildern.

Miniaturansicht aus einer lokalen Bilddatei erstellen

Für die Erstellung von Thumbnails ist ein effizientes Downscaling bei gleichzeitiger Wahrung der visuellen Qualität erforderlich. Außerdem muss die Speichernutzung begrenzt, mit einer Vielzahl von Bildformaten umgegangen und Exif-Daten richtig verwendet werden.

Die Methode createImageThumbnail übernimmt alle diese Aufgaben, sofern Sie Zugriff auf den Pfad der Image-Datei.

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

Wenn Sie nur das Uri haben, können Sie die Methode loadThumbnail in ContentResolver ab Android 10, API-Level 29.

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

ImageDecoder, das ab Android 9 (API-Level 28) verfügbar ist, hat einige durchgehende Optionen, um das Bild während der Decodierung neu zu codieren, um zusätzlichen Arbeitsspeicher zu vermeiden verwenden.

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);

Sie können BitmapFactory verwenden, um früher Miniaturansichten für das App-Targeting zu erstellen. Android-Releases BitmapFactory.Options verfügt über eine Einstellung, mit der nur der Parameter Grenzen eines Bildes für das Ressampling ein.

Decodieren Sie zuerst nur die Grenzen der Bitmap in 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()

Verwenden Sie width und height aus BitmapFactory.Options, um das Beispiel festzulegen. Größe:

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
        }
    }

Stream decodieren Die Größe des resultierenden Bildes wird mit Zweierpotenzen ermittelt basierend auf inSampleSize.

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

Miniaturansicht aus einer lokalen Videodatei erstellen

Das Erstellen von Video-Thumbnails ist mit vielen der gleichen Herausforderungen verbunden wie bei aber die Dateigrößen können viel größer sein und eines repräsentativen Videoframes ist nicht immer so einfach wie die Auswahl des ersten Frame des Videos.

Die Methode createVideoThumbnail ist eine gute Wahl, wenn Sie Zugriff auf Pfad der Videodatei.

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

Wenn Sie nur Zugriff auf einen Inhalts-URI haben, können Sie Folgendes verwenden: MediaMetadataRetriever

Prüfe zuerst, ob das Video ein Thumbnail hat, und verwende dieses, möglich:

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));
    }

Rufen Sie die Breite und Höhe des Videos von MediaMetadataRetriever ab, Skalierungsfaktor berechnen:

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)

Unter Android 9 und höher (API-Level 28) kann MediaMetadataRetriever eine skalierte Frame:

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
        }
    }

Andernfalls wird der erste Frame unverändert zurückgegeben:

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