Personnaliser une image

Vous pouvez personnaliser les images à l'aide des propriétés sur un composable Image (contentScale, colorFilter). Vous pouvez également appliquer les Modifiers existants pour appliquer différents effets à votre Image. Vous pouvez utiliser les modificateurs sur n'importe quel composable, pas seulement sur le composable Image, tandis que contentScale et colorFilter sont des paramètres explicites sur le composable Image.

Échelle de contenu

Spécifiez une option contentScale pour recadrer ou modifier l'ajustement d'une image dans ses limites. Par défaut, si vous ne spécifiez pas l'option contentScale, ContentScale.Fit est utilisé.

Dans l'exemple ci-dessous, la taille du composable Image est limitée à 150 dp avec une bordure, et l'arrière-plan est défini sur jaune sur le composable Image, pour présenter les différentes options ContentScale du tableau ci-dessous.

val imageModifier = Modifier
    .size(150.dp)
    .border(BorderStroke(1.dp, Color.Black))
    .background(Color.Yellow)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Fit,
    modifier = imageModifier
)

Si vous définissez d'autres options ContentScale, les résultats seront différents. Le tableau ci-dessous peut vous aider à choisir le mode ContentScale adapté :

Image source Image source au format Portrait Image source au format Paysage
ContentScale Résultat – Image au format Portrait : Résultat – Image au format Paysage :
ContentScale.Fit : ajuste l'image de manière uniforme, en conservant le format (par défaut). Si le contenu est plus petit, l'image est ajustée pour respecter les limites. ContentScale.Fit format Portrait ContentScale.Fit format Paysage
ContentScale.Crop : recadre et centre l'image dans l'espace disponible. ContentScale.Crop format Portrait ContentScale.Crop format Paysage
ContentScale.FillHeight : ajuste la source en conservant le format afin que les limites correspondent à la hauteur de la destination. ContentScale.FillHeight format Portrait ContentScale.FillHeight format Paysage
ContentScale.FillWidth : ajuste la source en conservant le format afin que les limites correspondent à la largeur de la destination. ContentScale.FillWidth format Portrait ContentScale.FillWidth format Paysage
ContentScale.FillBounds : ajuste le contenu verticalement et horizontalement de manière non uniforme afin de remplir les limites de la destination. Remarque : cela entraîne une distorsion des images si vous les placez dans des conteneurs dont le format ne correspond pas exactement à celui de l'image. ContentScale.FillBounds format Portrait ContentScale.FillBounds format Paysage
ContentScale.Inside : ajuste la source pour conserver le format dans les limites de la destination. Si la source est de taille inférieure ou égale à celle de la destination dans les deux dimensions, le comportement est le même qu'avec l'option "Aucun". Le contenu sera toujours contenu dans les limites. Si le contenu est plus petit que les limites, aucun ajustement ne sera réalisé. Image source plus grande que les limites : ContentScale.Inside format Portrait, image source plus grande que les limites Image source plus petite que les limites : ContentScale.Inside format Portrait, image source plus petite que les limites Image source plus grande que les limites : ContentScale.Inside format Paysage, image source plus grande que les limites Image source plus petite que les limites : ContentScale.Inside format Paysage, image source plus petite que les limites
ContentScale.None : n'ajuste pas la source. Si le contenu est plus petit que les limites de la destination, il ne sera pas ajusté pour s'adapter à la zone. Image source plus grande que les limites : ContentScale.None format Portrait, image source plus grande que les limites Image source plus petite que les limites : ContentScale.None format Portrait, image source plus petite que les limites Image source plus grande que les limites : ContentScale.None format Paysage, image source plus grande que les limites Image source plus petite que les limites : ContentScale.None format Paysage, image source plus petite que les limites

Découper un composable Image selon une forme

Pour ajuster une image à une forme, utilisez le modificateur clip intégré. Pour recadrer une image dans un cercle, utilisez Modifier.clip(CircleShape) :

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(CircleShape)
)

Découpe d'une image avec CircleShape
Figure 1 : Découpe d'une image avec CircleShape

Forme d'angle arrondie (utilisez Modifier.clip(RoundedCornerShape(16.dp)) avec la taille des angles que vous souhaitez arrondir :

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(RoundedCornerShape(16.dp))
)

Découpe d'une image avec RoundedCornerShape
Figure 2 : Découpe d'une image avec RoundedCornerShape

Vous pouvez également créer votre propre forme de découpage en étendant Shape et en fournissant un Path pour que l'image soit découpée selon la forme spécifiée :

class SquashedOval : Shape {
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        val path = Path().apply {
            // We create an Oval that starts at ¼ of the width, and ends at ¾ of the width of the container.
            addOval(
                Rect(
                    left = size.width / 4f,
                    top = 0f,
                    right = size.width * 3 / 4f,
                    bottom = size.height
                )
            )
        }
        return Outline.Generic(path = path)
    }
}

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(200.dp)
        .clip(SquashedOval())
)

Découpe d'une image selon un contour personnalisé
Figure 3 : Découpe d'une image selon un contour personnalisé

Ajouter une bordure à un composable Image

Une opération courante consiste à combiner Modifier.border() et Modifier.clip() pour créer une bordure autour d'une image :

val borderWidth = 4.dp
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(borderWidth, Color.Yellow),
            CircleShape
        )
        .padding(borderWidth)
        .clip(CircleShape)
)

Découpe et encadrement d'une image
Figure 4 : Découpe et encadrement d'une image

Si vous souhaitez créer une bordure en dégradé, vous pouvez utiliser l'API Brush pour dessiner une bordure en dégradé arc-en-ciel autour de l'image :

val rainbowColorsBrush = remember {
    Brush.sweepGradient(
        listOf(
            Color(0xFF9575CD),
            Color(0xFFBA68C8),
            Color(0xFFE57373),
            Color(0xFFFFB74D),
            Color(0xFFFFF176),
            Color(0xFFAED581),
            Color(0xFF4DD0E1),
            Color(0xFF9575CD)
        )
    )
}
val borderWidth = 4.dp
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .border(
            BorderStroke(borderWidth, rainbowColorsBrush),
            CircleShape
        )
        .padding(borderWidth)
        .clip(CircleShape)
)

Bordure circulaire en dégradé arc-en-ciel
Figure 5 : Bordure circulaire en dégradé arc-en-ciel

Définir un format personnalisé

Pour convertir une image dans un format personnalisé, utilisez Modifier.aspectRatio(16f/9f) pour fournir un format personnalisé pour une image (ou tout autre composable).

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    modifier = Modifier.aspectRatio(16f / 9f)
)

Utilisation de Modifier.aspectRatio(16f/9f) sur une image
Figure 6 : Utilisation de Modifier.aspectRatio(16f/9f) sur une image

Filtre de couleur : Transformer la couleur des pixels d'une image

Le composable Image possède un paramètre colorFilter, qui peut modifier le rendu de chaque pixel de votre image.

Teinter une image

L'utilisation de ColorFilter.tint(color, blendMode) applique à votre composable Image un mode de fusion avec la couleur donnée. ColorFilter.tint(color, blendMode) utilise BlendMode.SrcIn pour teinter le contenu, ce qui signifie que la couleur fournie sera affichée là où l'image est affichée à l'écran. Cette fonction est utile pour les icônes et les vecteurs qui doivent être traités selon un thème différent.

Image(
    painter = painterResource(id = R.drawable.baseline_directions_bus_24),
    contentDescription = stringResource(id = R.string.bus_content_description),
    colorFilter = ColorFilter.tint(Color.Yellow)
)

ColorFilter.tint appliqué avec BlendMode.SrcIn
Figure 7 : ColorFilter.tint appliqué avec BlendMode.SrcIn

Les autres BlendMode produisent des effets différents. Par exemple, si vous définissez BlendMode.Darken avec Color.Green sur une image, vous obtenez le résultat suivant :

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.tint(Color.Green, blendMode = BlendMode.Darken)
)

Teinte Color.Green avec BlendMode.Darken
Figure 8 : Teinte Color.Green avec BlendMode.Darken

Pour en savoir plus sur les différents modes de fusion disponibles, consultez la documentation de référence pour BlendMode.

Appliquer un filtre Image avec une matrice de couleurs

Transformez votre image avec l'option ColorFilter de la matrice de couleur. Par exemple, pour appliquer un filtre noir et blanc à vos images, vous pouvez utiliser ColorMatrix et régler la saturation sur 0f.

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) })
)

Matrice de couleur avec saturation 0 (image en noir et blanc)
Figure 9 : Matrice de couleur avec saturation 0 (image en noir et blanc)

Ajuster le contraste ou la luminosité d'un composable Image

Pour modifier le contraste et la luminosité d'une image, vous pouvez utiliser la ColorMatrix pour modifier les valeurs :

val contrast = 2f // 0f..10f (1 should be default)
val brightness = -180f // -255f..255f (0 should be default)
val colorMatrix = floatArrayOf(
    contrast, 0f, 0f, 0f, brightness,
    0f, contrast, 0f, 0f, brightness,
    0f, 0f, contrast, 0f, brightness,
    0f, 0f, 0f, 1f, 0f
)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix(colorMatrix))
)

Réglage de la luminosité et du contraste de l'image à l'aide de ColorMatrix
Figure 10 : Réglage de la luminosité et du contraste de l'image à l'aide de ColorMatrix

Inverser les couleurs d'un composable Image

Pour inverser les couleurs d'une image, définissez la ColorMatrix de manière à inverser les couleurs :

val colorMatrix = floatArrayOf(
    -1f, 0f, 0f, 0f, 255f,
    0f, -1f, 0f, 0f, 255f,
    0f, 0f, -1f, 0f, 255f,
    0f, 0f, 0f, 1f, 0f
)
Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    colorFilter = ColorFilter.colorMatrix(ColorMatrix(colorMatrix))
)

Couleurs inversées sur l'image
Figure 11 : Couleurs inversées sur l'image

Flouter un composable Image

Pour flouter une image, utilisez Modifier.blur(), en fournissant les valeurs radiusX et radiusY pour spécifier le rayon de floutage horizontal et vertical, respectivement.

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .blur(
            radiusX = 10.dp,
            radiusY = 10.dp,
            edgeTreatment = BlurredEdgeTreatment(RoundedCornerShape(8.dp))
        )
)

BlurEffect appliqué à l'image
Figure 12 : BlurEffect appliqué à l'image

Lors du floutage d'Images, il est recommandé d'utiliser BlurredEdgeTreatment(Shape) au lieu de BlurredEdgeTreatment.Unbounded. En effet, ce dernier est utilisé pour flouter les rendus arbitraires censés s'afficher en dehors des limites du contenu d'origine. Pour ce qui est des images, il est probable qu'elles s'affichent en dehors des limites du contenu. En revanche, flouter un rectangle arrondi peut nécessiter cette distinction.

Par exemple, si vous définissez BlurredEdgeTreatment sur "Unbounded" pour l'image ci-dessus, les bords de l'image seront flous au lieu d'être nets :

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(150.dp)
        .blur(
            radiusX = 10.dp,
            radiusY = 10.dp,
            edgeTreatment = BlurredEdgeTreatment.Unbounded
        )
        .clip(RoundedCornerShape(8.dp))
)

BlurEdgeTreatment.Unbounded
Figure 13 : BlurEdgeTreatment.Unbounded