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
}