ปรับแต่งรูปภาพ

คุณสามารถปรับแต่งรูปภาพโดยใช้พร็อพเพอร์ตี้ใน Composable Image (contentScale, colorFilter) และยังใช้ตัวแก้ไขที่มีอยู่เพื่อใช้เอฟเฟกต์ต่างๆ กับ Image ได้ด้วย คุณสามารถใช้ตัวปรับแต่งกับ Composable ใดก็ได้ ไม่ใช่แค่ Composable Image เท่านั้น ส่วน contentScale และ colorFilter เป็นพารามิเตอร์ที่ชัดเจนใน Composable Image

ขนาดเนื้อหา

ระบุตัวเลือก contentScale เพื่อครอบตัดหรือเปลี่ยนวิธีปรับขนาดรูปภาพภายในขอบเขตของรูปภาพ โดยค่าเริ่มต้น หากคุณไม่ได้ระบุตัวเลือก contentScale ระบบจะใช้ ContentScale.Fit

ในตัวอย่างต่อไปนี้ คอมโพสิเบิล Image ถูกจำกัดให้มีขนาด 150dp พร้อมเส้นขอบ และพื้นหลังตั้งค่าเป็นสีเหลืองในคอมโพสิเบิล Image เพื่อแสดงตัวเลือก ContentScale ต่างๆ ในตารางต่อไปนี้

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
)

การตั้งค่าตัวเลือก ContentScale ที่แตกต่างกันจะทำให้ได้เอาต์พุตที่แตกต่างกัน ตารางต่อไปนี้จะช่วยคุณเลือกโหมด ContentScale ที่ถูกต้อง

รูปภาพต้นฉบับ แหล่งที่มาของภาพบุคคลซึ่งแสดงรูปสุนัข แหล่งที่มาแนวนอนซึ่งแสดงสุนัขตัวอื่น
ContentScale ผลลัพธ์ - รูปภาพแนวตั้ง: ผลลัพธ์ - รูปภาพแนวนอน:
ContentScale.Fit: ปรับขนาดรูปภาพให้สม่ำเสมอโดยคงสัดส่วนภาพไว้ (ค่าเริ่มต้น) หากเนื้อหามีขนาดเล็กกว่าขนาดที่กำหนด ระบบจะปรับขนาดรูปภาพให้พอดีกับขอบเขต ภาพสุนัขที่ปรับขนาดอย่างสม่ำเสมอ ภาพสุนัขแนวนอนที่ปรับขนาดอย่างสม่ำเสมอ
ContentScale.Crop: ครอบตัดรูปภาพให้อยู่ตรงกลางในพื้นที่ที่ใช้ได้ รูปภาพแนวตั้งที่ครอบตัดให้พอดีกับกรอบสี่เหลี่ยมจัตุรัส โดยแสดงเฉพาะส่วนตรงกลางของรูปภาพ รูปภาพแนวนอนที่ครอบตัดให้พอดีกับเฟรมสี่เหลี่ยมจัตุรัส โดยแสดงเฉพาะส่วนตรงกลางของรูปภาพ
ContentScale.FillHeight: ปรับขนาดแหล่งที่มาโดยคงสัดส่วนภาพไว้เพื่อให้ขอบเขตตรงกับความสูงของปลายทาง รูปภาพแนวตั้งที่ปรับขนาดให้พอดีกับความสูงของเฟรมสี่เหลี่ยมจัตุรัส โดยแสดงรูปภาพเต็มที่มีพื้นหลังสีเหลืองปรากฏทางด้านซ้ายและขวา รูปภาพแนวนอนที่ปรับขนาดให้พอดีกับความสูงของเฟรมสี่เหลี่ยมจัตุรัส โดยมีการครอบตัดด้านข้าง
ContentScale.FillWidth: ปรับขนาดแหล่งที่มาโดยคงสัดส่วนภาพไว้เพื่อให้ขอบเขตตรงกับความกว้างของปลายทาง รูปภาพแนวตั้งที่ปรับขนาดให้พอดีกับความกว้างของเฟรมสี่เหลี่ยมจัตุรัส โดยครอบตัดด้านบนและด้านล่าง รูปภาพแนวนอนที่ปรับขนาดให้พอดีกับความกว้างของเฟรมสี่เหลี่ยมจัตุรัส โดยแสดงรูปภาพแบบเต็มพร้อมพื้นหลังสีเหลืองที่ด้านบนและด้านล่าง
ContentScale.FillBounds: ปรับขนาดเนื้อหาในแนวตั้งและแนวนอนไม่สม่ำเสมอเพื่อเติมขอบเขตปลายทาง (หมายเหตุ: การดำเนินการนี้จะทำให้รูปภาพบิดเบี้ยวหากคุณวางรูปภาพในคอนเทนเนอร์ที่มีสัดส่วนไม่ตรงกับรูปภาพ) รูปภาพแนวตั้งที่บิดเบี้ยวเพื่อเติมเฟรมสี่เหลี่ยมจัตุรัสให้เต็ม ซึ่งทำให้รูปภาพยืดออก รูปภาพแนวนอนที่บิดเบี้ยวเพื่อเติมเต็มกรอบสี่เหลี่ยมจัตุรัส ซึ่งทำให้รูปภาพยืดออก
ContentScale.Inside: ปรับขนาดแหล่งที่มาเพื่อรักษาสัดส่วนภาพภายในขอบเขตปลายทาง หากแหล่งที่มามีขนาดเล็กกว่าหรือเท่ากับปลายทางในทั้ง 2 มิติ ระบบจะทำงานคล้ายกับ None เนื้อหาจะอยู่ภายในขอบเขตเสมอ หากเนื้อหามีขนาดเล็กกว่าขอบเขต ระบบจะไม่ปรับขนาด รูปภาพต้นฉบับใหญ่กว่าขอบเขต: รูปภาพแนวตั้งซึ่งเดิมมีขนาดใหญ่กว่าขอบเขตสี่เหลี่ยมจัตุรัสถูกปรับขนาดให้พอดีโดยยังคงสัดส่วนภาพไว้ โดยแสดงพื้นหลังสีเหลืองที่ด้านข้าง รูปภาพต้นฉบับเล็กกว่าขอบเขต: รูปภาพแนวตั้งซึ่งเดิมมีขนาดเล็กกว่าขอบเขตสี่เหลี่ยมจัตุรัสจะแสดงในขนาดเดิมภายในกรอบ โดยมีพื้นหลังสีเหลืองล้อมรอบ รูปภาพต้นฉบับใหญ่กว่าขอบเขต: รูปภาพแนวนอนซึ่งเดิมมีขนาดใหญ่กว่าขอบเขตสี่เหลี่ยมจัตุรัสถูกปรับขนาดให้พอดีโดยยังคงสัดส่วนภาพไว้ โดยแสดงพื้นหลังสีเหลืองที่ด้านบนและด้านล่าง รูปภาพต้นฉบับเล็กกว่าขอบเขต: รูปภาพแนวนอนซึ่งเดิมมีขนาดเล็กกว่าขอบเขตสี่เหลี่ยมจัตุรัสจะแสดงในขนาดเดิมภายในเฟรม โดยมีพื้นหลังสีเหลืองอยู่รอบๆ
ContentScale.None: ไม่ใช้การปรับขนาดกับแหล่งที่มา หากเนื้อหามีขนาดเล็กกว่าขอบเขตปลายทาง ระบบจะไม่ปรับขนาดให้พอดีกับพื้นที่ รูปภาพต้นฉบับใหญ่กว่าขอบเขต: รูปภาพแนวตั้งซึ่งเดิมมีขนาดใหญ่กว่าขอบเขตสี่เหลี่ยมจัตุรัสจะแสดงในขนาดเดิม โดยมีบางส่วนขยายออกไปเกินด้านบนและด้านล่างของเฟรม รูปภาพต้นฉบับเล็กกว่าขอบเขต: รูปภาพแนวตั้งซึ่งเดิมมีขนาดเล็กกว่าขอบเขตสี่เหลี่ยมจัตุรัสจะแสดงในขนาดเดิมภายในกรอบ โดยมีพื้นหลังสีเหลืองล้อมรอบ รูปภาพต้นฉบับใหญ่กว่าขอบเขต: รูปภาพแนวนอนซึ่งเดิมมีขนาดใหญ่กว่าขอบเขตสี่เหลี่ยมจัตุรัส แสดงในขนาดต้นฉบับ โดยมีบางส่วนขยายออกไปนอกกรอบด้านซ้ายและขวา รูปภาพต้นฉบับเล็กกว่าขอบเขต: รูปภาพแนวนอนซึ่งเดิมมีขนาดเล็กกว่าขอบเขตสี่เหลี่ยมจัตุรัสจะแสดงในขนาดเดิมภายในเฟรม โดยมีพื้นหลังสีเหลืองอยู่รอบๆ

ตัดคลิป Image Composable ให้เป็นรูปร่าง

หากต้องการปรับรูปภาพให้พอดีกับรูปร่าง ให้ใช้ตัวแก้ไข clip ในตัว หากต้องการครอบตัดรูปภาพเป็นรูปวงกลม ให้ใช้ 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)
)

รูปภาพสุนัขที่ถูกตัดเป็นวงกลมสมบูรณ์แบบ
รูปที่ 1 กำลังตัดรูปภาพด้วย CircleShape

สำหรับรูปร่างมุมมน ให้ใช้ Modifier.clip(RoundedCornerShape(16.dp)) พร้อมขนาดของมุมที่ต้องการให้โค้งมน ดังนี้

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

รูปภาพสี่เหลี่ยมจัตุรัสของสุนัขที่ตัดมุมให้โค้งมน
รูปที่ 2 กำลังตัดรูปภาพด้วย RoundedCornerShape

นอกจากนี้ คุณยังสร้างรูปร่างการตัดคลิปของคุณเองได้โดยขยาย Shape และระบุ Path สำหรับรูปร่างที่จะตัดคลิปโดยรอบ ดังนี้

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

รูปภาพสี่เหลี่ยมจัตุรัสของสุนัขที่ครอบตัดเป็นรูปวงรีที่กำหนดเอง
รูปที่ 3 การครอบตัดรูปภาพด้วยรูปร่างเส้นทางที่กำหนดเอง

เพิ่มเส้นขอบให้กับ Composable Image

การดำเนินการที่พบบ่อยคือการรวม Modifier.border() กับ Modifier.clip() เพื่อสร้างเส้นขอบรอบรูปภาพ ดังนี้

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

รูปภาพสี่เหลี่ยมจัตุรัสของสุนัขที่ถูกครอบตัดเป็นวงกลม โดยมีเส้นขอบสีเหลืองรอบรูปทรงวงกลม
รูปที่ 4 รูปภาพที่ถูกครอบตัดและมีเส้นขอบล้อมรอบ

หากต้องการสร้างเส้นขอบแบบไล่ระดับสี คุณสามารถใช้ Brush API เพื่อวาดเส้นขอบแบบไล่ระดับสีรุ้งรอบรูปภาพได้ ดังนี้

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

รูปภาพสุนัขทรงกลมที่มีเส้นขอบไล่ระดับสีรุ้งรอบรูปทรงกลม
รูปที่ 5 เส้นขอบวงกลมไล่ระดับสีรุ้ง

ตั้งค่าสัดส่วนภาพที่กำหนดเอง

หากต้องการเปลี่ยนรูปภาพเป็นสัดส่วนภาพที่กำหนดเอง ให้ใช้ Modifier.aspectRatio(16f/9f) เพื่อระบุสัดส่วนภาพที่กำหนดเองสำหรับรูปภาพ (หรือ Composable ใดๆ)

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

รูปภาพสี่เหลี่ยมจัตุรัสของสุนัขที่เปลี่ยนเป็นสัดส่วนภาพ 16:9 ทำให้รูปภาพกว้างขึ้นและสั้นลง
รูปที่ 6 การใช้ Modifier.aspectRatio(16f/9f) ใน Image

ฟิลเตอร์สี: เปลี่ยนสีพิกเซลของรูปภาพ

คอมโพสิเบิล Image มีพารามิเตอร์ colorFilter ที่สามารถเปลี่ยนเอาต์พุตของพิกเซลแต่ละพิกเซลของรูปภาพได้

ปรับสมดุลสีเขียว-แดงของรูปภาพ

การใช้ ColorFilter.tint(color, blendMode) จะใช้โหมดผสมกับสีที่กำหนดกับ Composable Image ColorFilter.tint(color, blendMode) ใช้ BlendMode.SrcIn เพื่อปรับสีเนื้อหา ซึ่งหมายความว่าสีที่ระบุจะแสดงในตำแหน่งที่รูปภาพแสดงบนหน้าจอ ซึ่งมีประโยชน์สำหรับไอคอนและเวกเตอร์ที่ต้องมีธีมแตกต่างกัน

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

รูปภาพรถบัสที่มีการใช้สีเหลือง
รูปที่ 7 ColorFilter.tint ใช้กับ BlendMode.SrcIn

BlendMode อื่นๆ จะส่งผลแตกต่างกัน ตัวอย่างเช่น การตั้งค่า BlendMode.Darken ด้วย Color.Green ในรูปภาพจะให้ผลลัพธ์ต่อไปนี้

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

สุนัขที่มีสีเขียวอ่อนซึ่งใช้ BlendMode.Darken ทำให้ได้เฉดสีเขียวที่เข้มขึ้น
รูปที่ 8 Color.Green tint ด้วย BlendMode.Darken

ดูข้อมูลเพิ่มเติมเกี่ยวกับโหมดการผสมต่างๆ ที่มีได้ในเอกสารอ้างอิง BlendMode

ใช้ตัวกรอง Image กับเมทริกซ์สี

เปลี่ยนรูปแบบรูปภาพโดยใช้ตัวเลือกเมทริกซ์สี ColorFilter เช่น หากต้องการใช้ฟิลเตอร์ขาวดำกับรูปภาพ คุณสามารถใช้ ColorMatrix และตั้งค่าความอิ่มตัวเป็น 0f

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

สุนัขที่ใช้ฟิลเตอร์ขาวดำ ซึ่งจะนำความอิ่มตัวของสีทั้งหมดออก
รูปที่ 9 เมตริกซ์สีที่มีความอิ่มตัว 0 (รูปภาพขาวดำ)

ปรับคอนทราสต์หรือความสว่างของ Image Composable

หากต้องการเปลี่ยนคอนทราสต์และความสว่างของรูปภาพ คุณสามารถใช้ ColorMatrix เพื่อเปลี่ยนค่าได้ ดังนี้

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

สุนัขที่มีความสว่างและคอนทราสต์เพิ่มขึ้น ทำให้ดูสดใสยิ่งขึ้น
รูปที่ 10 ปรับความสว่างและคอนทราสต์ของรูปภาพโดยใช้ ColorMatrix แล้ว

สลับสีของ Image ที่ประกอบกันได้

หากต้องการกลับสีของรูปภาพ ให้ตั้งค่า ColorMatrix เพื่อกลับสี ดังนี้

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

สุนัขที่มีการสลับสี ซึ่งแสดงเอฟเฟกต์คล้ายฟิล์มเนกาทีฟ
รูปที่ 11 สลับสีในรูปภาพ

เบลอ Image ที่ประกอบกันได้

หากต้องการเบลอรูปภาพ ให้ใช้ Modifier.blur() โดยระบุ radiusX และ radiusY ซึ่งจะระบุรัศมีการเบลอในแนวนอนและแนวตั้งตามลำดับ

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

สุนัขที่ใช้เอฟเฟกต์เบลออย่างชัดเจน ทำให้ดูไม่ชัดเจนและอยู่นอกโฟกัส
รูปที่ 12 ใช้ BlurEffect กับรูปภาพแล้ว

เมื่อเบลอ Images ขอแนะนำให้ใช้ BlurredEdgeTreatment(Shape) แทน BlurredEdgeTreatment.Unbounded เนื่องจากอย่างหลังใช้สำหรับการเบลอการแสดงผลที่กำหนดเองซึ่งคาดว่าจะแสดงผลนอกขอบเขตของเนื้อหาต้นฉบับ สำหรับรูปภาพ มีแนวโน้มว่าจะไม่แสดงผลนอกขอบเขตของเนื้อหา ในขณะที่การเบลอสี่เหลี่ยมผืนผ้าที่มีมุมโค้งมนอาจต้องใช้ความแตกต่างนี้

ตัวอย่างเช่น หากเราตั้งค่า BlurredEdgeTreatment เป็น Unbounded ในรูปภาพก่อนหน้า ขอบของรูปภาพจะเบลอแทนที่จะคมชัด

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

รูปภาพสุนัขที่เบลอ โดยที่การเบลอขยายออกไปนอกขอบเขตของรูปภาพต้นฉบับ ทำให้ขอบไม่ชัดเจน
รูปที่ 13 BlurEdgeTreatment.Unbounded