Menyesuaikan gambar

Anda dapat menyesuaikan gambar menggunakan properti pada composable Image (contentScale, colorFilter). Anda juga dapat menerapkan pengubah yang ada untuk menerapkan efek yang berbeda ke Image. Pengubah dapat digunakan pada composable mana pun, bukan hanya composable Image, sedangkan contentScale dan colorFilter adalah parameter eksplisit pada composable Image.

Skala konten

Tentukan opsi contentScale untuk memangkas atau mengubah cara gambar diskalakan di dalam batasnya. Secara default, jika Anda tidak menentukan opsi contentScale, ContentScale.Fit akan digunakan.

Pada contoh berikut, composable Image dibatasi hingga ukuran 150 dp dengan batas, dan latar belakang disetel ke kuning pada composable Image untuk menampilkan berbagai opsi ContentScale pada tabel di bawah.

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
)

Menyetel opsi ContentScale yang berbeda akan menghasilkan output yang berbeda. Tabel berikut membantu Anda memilih mode ContentScale yang benar:

Gambar sumber Sumber potret, yang menampilkan seekor anjing. Sumber lanskap, yang menampilkan anjing yang berbeda.
ContentScale Hasil - Gambar Potret: Hasil - Gambar Lanskap:
ContentScale.Fit: Menskalakan gambar secara seragam, dengan tetap mempertahankan rasio aspek (default). Jika konten lebih kecil dari ukuran, skala gambar akan ditingkatkan agar sesuai dengan batas. Potret anjing yang diskalakan secara seragam. Lanskap anjing yang diskalakan secara seragam.
ContentScale.Crop: Memangkas tengah gambar ke ruang yang tersedia. Gambar potret yang dipangkas untuk mengisi bingkai persegi, hanya menampilkan bagian tengah gambar. Gambar lanskap yang dipangkas untuk mengisi bingkai persegi, hanya menampilkan bagian tengah gambar.
ContentScale.FillHeight: Menskalakan sumber yang mempertahankan rasio aspek sehingga batas cocok dengan tinggi tujuan. Gambar potret yang diskalakan untuk mengisi tinggi frame persegi, menampilkan gambar penuh dengan latar belakang kuning yang terlihat di kiri dan kanan. Gambar lanskap yang diskalakan untuk mengisi tinggi bingkai persegi, dengan sisi yang dipangkas.
ContentScale.FillWidth: Menskalakan sumber yang mempertahankan rasio aspek agar batas cocok dengan lebar tujuan. Gambar potret yang diskalakan untuk mengisi lebar bingkai persegi, dengan bagian atas dan bawah dipangkas. Gambar lanskap yang diskalakan untuk mengisi lebar frame persegi, menampilkan gambar penuh dengan latar belakang kuning yang terlihat di bagian atas dan bawah.
ContentScale.FillBounds: Menskalakan konten secara vertikal dan horizontal secara tidak seragam untuk mengisi batas tujuan. (Catatan: Ini akan mendistorsi gambar jika Anda meletakkannya dalam penampung yang tidak sama persis dengan rasio gambar). Gambar potret yang terdistorsi untuk mengisi bingkai persegi sepenuhnya, meregangkan gambar. Gambar lanskap yang terdistorsi untuk mengisi bingkai persegi sepenuhnya, sehingga meregangkan gambar.
ContentScale.Inside: Menskalakan sumber untuk mempertahankan rasio aspek di dalam batas tujuan. Jika sumbernya lebih kecil dari atau sama dengan tujuan di kedua dimensi, mode ini akan berperilaku serupa dengan None. Konten akan selalu berada dalam batas. Jika konten lebih kecil dari batas, tidak ada penskalaan yang akan diterapkan. Gambar sumber lebih besar dari batas: Gambar potret, yang awalnya lebih besar dari batas persegi, diperkecil agar sesuai dengan tetap mempertahankan rasio aspek, yang menampilkan latar belakang kuning di samping. Gambar sumber lebih kecil dari batas: Gambar potret, yang awalnya lebih kecil dari batas persegi, ditampilkan dalam ukuran aslinya di dalam bingkai, dengan latar belakang kuning di sekitarnya. Gambar sumber lebih besar dari batas: Gambar lanskap, yang awalnya lebih besar dari batas persegi, diperkecil agar pas sambil mempertahankan rasio aspek, menampilkan latar belakang kuning di bagian atas dan bawah. Gambar sumber lebih kecil dari batas: Gambar lanskap, yang awalnya lebih kecil dari batas persegi, ditampilkan dalam ukuran aslinya di dalam frame, dengan latar belakang kuning di sekitarnya.
ContentScale.None: Jangan terapkan penskalaan apa pun ke sumber. Jika konten lebih kecil dari batas tujuan, konten tidak akan ditingkatkan skalanya agar sesuai dengan area tersebut. Gambar sumber lebih besar dari batas: Gambar potret, yang awalnya lebih besar dari batas persegi, ditampilkan dalam ukuran aslinya, dengan bagian-bagian yang melampaui bagian atas dan bawah frame. Gambar sumber lebih kecil dari batas: Gambar potret, yang awalnya lebih kecil dari batas persegi, ditampilkan dalam ukuran aslinya di dalam bingkai, dengan latar belakang kuning di sekitarnya. Gambar sumber lebih besar dari batas: Gambar lanskap, yang awalnya lebih besar dari batas persegi, ditampilkan dalam ukuran aslinya, dengan bagian-bagian yang melampaui kiri dan kanan frame. Gambar sumber lebih kecil dari batas: Gambar lanskap, yang awalnya lebih kecil dari batas persegi, ditampilkan dalam ukuran aslinya di dalam frame, dengan latar belakang kuning di sekitarnya.

Memotong composable Image ke sebuah bentuk

Agar gambar sesuai dengan bentuk, gunakan pengubah clip bawaan. Untuk memangkas gambar menjadi bentuk lingkaran, gunakan 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)
)

Gambar anjing yang dipangkas menjadi lingkaran sempurna.
Gambar 1. Memotong gambar dengan CircleShape.

Untuk bentuk sudut bulat, gunakan Modifier.clip(RoundedCornerShape(16.dp)), dengan ukuran sudut yang ingin dibulatkan:

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

Gambar persegi seekor anjing yang diklip dengan sudut membulat.
Gambar 2. Memotong gambar dengan RoundedCornerShape.

Anda juga dapat membuat bentuk pemotongan sendiri dengan memperluas Shape, dan memberikan Path untuk bentuk yang akan dipotong:

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

Gambar persegi seekor anjing yang dipotong menjadi bentuk oval kustom.
Gambar 3. Memotong gambar dengan bentuk jalur kustom.

Menambahkan batas ke composable Image

Operasi yang umum adalah dengan menggabungkan Modifier.border() dengan Modifier.clip() untuk membuat batas di sekitar gambar:

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

Gambar persegi anjing, diklip menjadi lingkaran, dengan batas kuning di sekeliling bentuk lingkaran.
Gambar 4. Gambar yang dipangkas dengan batas di sekelilingnya.

Untuk membuat batas gradien, Anda dapat menggunakan Brush API untuk menggambar batas gradien pelangi di sekitar gambar:

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

Gambar melingkar seekor anjing dengan batas gradien pelangi di sekitar bentuk melingkar.
Gambar 5. Batas lingkaran gradien pelangi.

Menetapkan rasio aspek kustom

Untuk mengubah gambar menjadi rasio aspek kustom, gunakan Modifier.aspectRatio(16f/9f) untuk memberikan rasio kustom bagi gambar (atau composable apa pun).

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

Gambar persegi seekor anjing, diubah menjadi rasio aspek 16:9, sehingga menjadi lebih lebar dan lebih pendek.
Gambar 6. Menggunakan Modifier.aspectRatio(16f/9f) di Image.

Filter warna: mengubah warna piksel gambar

Composable Image memiliki parameter colorFilter yang dapat mengubah output setiap piksel gambar Anda.

Mewarnai gambar

Penggunaan ColorFilter.tint(color, blendMode) akan menerapkan mode gabungan dengan warna tertentu ke composable Image Anda. ColorFilter.tint(color, blendMode) menggunakan BlendMode.SrcIn untuk menambahkan tint konten, yang berarti warna yang diberikan akan ditampilkan di tempat gambar ditampilkan di layar. Hal ini berguna untuk ikon dan vektor yang perlu diberi tema secara berbeda.

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

Gambar bus dengan warna kuning.
Gambar 7. ColorFilter.tint diterapkan dengan BlendMode.SrcIn.

BlendMode lain memberikan efek yang berbeda. Misalnya, menyetel BlendMode.Darken dengan Color.Green pada gambar akan memberikan hasil berikut:

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

Seekor anjing dengan tint hijau yang diterapkan menggunakan BlendMode.Darken, sehingga menghasilkan warna hijau yang lebih gelap.
Gambar 8. Color.Green tint dengan BlendMode.Darken.

Lihat dokumentasi referensi BlendMode untuk mengetahui informasi selengkapnya tentang berbagai mode campuran yang tersedia.

Menerapkan filter Image dengan matriks warna

Ubah gambar Anda menggunakan opsi ColorFilter matriks warna. Misalnya, untuk menerapkan filter hitam dan putih ke gambar, Anda dapat menggunakan ColorMatrix dan menyetel saturasi ke 0f.

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

Seekor anjing dengan filter hitam putih diterapkan, sehingga menghilangkan semua saturasi warna.
Gambar 9. Matriks warna dengan saturasi 0 (gambar hitam putih).

Menyesuaikan kontras atau kecerahan composable Image

Untuk mengubah kontras dan kecerahan gambar, Anda dapat menggunakan ColorMatrix untuk mengubah nilainya:

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

Seekor anjing dengan kecerahan dan kontras yang ditingkatkan, sehingga tampak lebih jelas.
Gambar 10. Kecerahan dan kontras gambar yang disesuaikan menggunakan ColorMatrix.

Melakukan inversi warna composable Image

Untuk melakukan inversi warna gambar, setel ColorMatrix untuk membalik warna:

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

Seekor anjing dengan warna yang dibalik, menunjukkan efek seperti negatif.
Gambar 11. Inversi warna gambar.

Memberikan efek blur pada composable Image

Untuk memberikan efek blur pada gambar, gunakan Modifier.blur(), yang menyediakan radiusX dan radiusY, yang menentukan radius blur dalam arah horizontal dan vertikal.

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

Seekor anjing dengan efek buram kuat diterapkan, sehingga tampak tidak jelas dan tidak fokus.
Gambar 12. BlurEffect diterapkan pada gambar.

Saat memberikan efek blur pada Images, sebaiknya gunakan BlurredEdgeTreatment(Shape). Jangan gunakan BlurredEdgeTreatment.Unbounded karena digunakan untuk memberikan efek blur pada rendering arbitrer yang diharapkan dirender di luar batas konten asli. Untuk gambar, kemungkinan gambar tidak akan dirender di luar batas konten, sementara memberikan efek blur pada persegi panjang bulat mungkin membutuhkan perbedaan ini.

Misalnya, jika kita menyetel BlurredEdgeTreatment ke Unbounded pada gambar sebelumnya, tepi gambar akan tampak blur, bukan tajam:

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

Gambar anjing yang diburamkan, dengan buram yang melampaui batas gambar asli, sehingga membuat tepi gambar menjadi tidak jelas.
Gambar 13. BlurEdgeTreatment.Unbounded.