Les miniatures de contenus multimédias offrent aux utilisateurs un aperçu rapide des images et des vidéos, pour une navigation plus rapide tout en rendant l'interface de l'application plus visuelle. attrayantes et engageantes. Comme les vignettes sont plus petites que les supports en taille réelle, ils permettent d'économiser de la mémoire, de l'espace de stockage et de la bande passante, tout en améliorant les performances de navigation.
En fonction du type de fichier et de l'accès aux fichiers dont vous disposez dans votre application et vos assets multimédias, vous pouvez créer des miniatures de différentes manières.
Créer une vignette à l'aide d'une bibliothèque de chargement d'images
Les bibliothèques de chargement d'images font le gros du travail pour vous. qu'ils peuvent gérer ainsi que la logique permettant d'extraire le contenu multimédia source ressource basée sur un URI. Le code suivant illustre l'utilisation de la classe La bibliothèque de chargement d'images Coil fonctionne aussi bien pour les images que pour les vidéos. et fonctionne sur une ressource locale ou réseau.
// 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
)
Si possible, créez des miniatures côté serveur. Consultez la section Charger des images. pour savoir comment charger des images à l'aide de Compose et Charger des bitmaps volumineux efficacement pour savoir comment utiliser des images volumineuses.
Créer une vignette à partir d'un fichier image local
L'obtention d'images miniatures implique un scaling à la baisse efficace tout en préservant en évitant une utilisation excessive de la mémoire et en gérant diverses et en utilisant correctement les données Exif.
La méthode createImageThumbnail
effectue toutes ces opérations, à condition que vous ayez
au chemin d'accès au fichier image.
val bitmap = ThumbnailUtils.createImageThumbnail(File(file_path), Size(640, 480), null)
Si vous ne disposez que de Uri
, vous pouvez utiliser la méthode loadThumbnail
dans
ContentResolver à partir d'Android 10, niveau d'API 29.
val thumbnail: Bitmap =
applicationContext.contentResolver.loadThumbnail(
content-uri, Size(640, 480), null)
L'outil ImageDecoder, disponible à partir d'Android 9 (niveau d'API 28), comporte des options pleines pour rééchantillonner l'image au fur et à mesure que vous la décodez, afin d'éviter toute quantité de mémoire supplémentaire utiliser.
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);
Vous pouvez utiliser BitmapFactory pour créer des vignettes destinées aux applications ciblées plus tôt. Versions d'Android. BitmapFactory.Options dispose d'un paramètre permettant de ne décoder que les les limites d'une image à des fins de rééchantillonnage.
Tout d'abord, décodez uniquement les limites du bitmap dans 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()
Utilisez width
et height
à partir de BitmapFactory.Options
pour définir la taille de l'échantillon :
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
}
}
Décodez le flux. La taille de l'image résultante est échantillonnée par des puissances de deux
en fonction des inSampleSize
.
options.inJustDecodeBounds = false
val decodeStream = context.contentResolver.openInputStream(uri)
val bitmap = BitmapFactory.decodeStream(decodeStream, null, options)
decodeStream?.close()
return bitmap
}
Créer une vignette à partir d'un fichier vidéo local
Obtenir des images de miniatures de vidéos implique de nombreux défis similaires à ceux rencontrés pour les miniatures d'images, mais les tailles de fichiers peuvent être beaucoup plus importantes, et obtenir un frame vidéo représentatif n'est pas toujours aussi simple que de choisir le premier frame de la vidéo.
La méthode createVideoThumbnail
est un choix judicieux si vous avez accès à
le chemin d'accès au fichier vidéo.
val bitmap = ThumbnailUtils.createVideoThumbnail(File(file_path), Size(640, 480), null)
Si vous n'avez accès qu'à un URI de contenu, vous pouvez utiliser
MediaMetadataRetriever
Tout d'abord, vérifiez si la vidéo dispose d'une miniature intégrée et utilisez-la si possible:
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));
}
Extrayez la largeur et la hauteur de la vidéo de MediaMetadataRetriever
à
calculer le facteur de scaling:
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)
Sous Android 9 ou version ultérieure (niveau d'API 28), MediaMetadataRetriever
peut renvoyer un frame mis à l'échelle :
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
}
}
Sinon, renvoyez le premier frame non mis à l'échelle :
// consider scaling this after the fact
val frame = mediaMetadataRetriever.frameAtTime
mediaMetadataRetriever.close()
return frame
}