سفارشی‌سازی کردن تصویر

می‌توانید تصاویر را بااستفاده از ویژگی‌های موجود در یک Image ترکیب‌پذیر (contentScale، colorFilter) سفارشی‌سازی کنید. همچنین می‌توانید اصلاح‌کننده‌های موجود را برای اعمال جلوه‌های مختلف به Image خود اعمال کنید. از اصلاح‌کننده‌ها می‌توان در هر ترکیب‌پذیری استفاده کرد، نه فقط ترکیب‌پذیر Image، درحالی‌که contentScale و colorFilter پارامترهای صریح در ترکیب‌پذیر Image هستند.

مقیاس محتوا

گزینه contentScale را برای برش دادن یا تغییر نحوه مقیاس‌بندی تصویر در داخل مرزهای آن مشخص کنید. به‌طور پیش‌فرض، اگر گزینه contentScale را مشخص نکنید، از ContentScale.Fit استفاده می‌شود.

در مثال زیر، Image composable به اندازه ۱۵۰dp با حاشیه محدود شده است و پس‌زمینه روی Image composable به رنگ زرد تنظیم شده است تا گزینه‌های مختلف 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: منبع را مقیاس‌بندی کنید تا نسبت ابعادی در محدوده مقصد حفظ شود. اگر منبع در هر دو بعد کوچک‌تر یا مساوی مقصد باشد، رفتاری مشابه None دارد. محتوا همیشه در محدوده مرزها قرار خواهد گرفت. اگر محتوا کوچک‌تر از مرزها باشد، مقیاس‌بندی اعمال نخواهد شد. تصویر منبع بزرگ‌تر از مرزها: تصویری عمودی که در ابتدا بزرگ‌تر از مرزهای مربعی‌اش بوده است، برای جا شدن در قاب کوچک شده است و نسبت ابعادی آن حفظ شده است، و پس‌زمینه زرد در کناره‌های آن دیده می‌شود. تصویر منبع کوچک‌تر از مرزها: تصویری عمودی که در ابتدا کوچک‌تر از مرزهای مربعی‌اش بود، در اندازه اصلی‌اش در قاب نمایش داده شده است و پس‌زمینه‌ای زرد در اطراف آن دیده می‌شود. تصویر منبع بزرگ‌تر از مرزها: تصویری افقی که در اصل بزرگ‌تر از مرزهای مربعی‌اش است و برای جا شدن در آن کوچک شده است، درحالی‌که نسبت ابعادی‌اش حفظ شده است و پس‌زمینه زردی در بالا و پایین آن نشان داده می‌شود. تصویر منبع کوچک‌تر از مرزها: تصویری افقی که در ابتدا کوچک‌تر از مرزهای مربعی‌اش است، در اندازه اصلی‌اش در قاب نمایش داده می‌شود و پس‌زمینه‌ای زرد در اطراف آن دیده می‌شود.
ContentScale.None: هیچ مقیاس‌بندی‌ای روی منبع اعمال نشود. اگر محتوا کوچک‌تر از مرزهای مقصد باشد، برای جا شدن در آن ناحیه بزرگ‌تر نخواهد شد. تصویر منبع بزرگ‌تر از مرزها: تصویر عمودی، که در ابتدا بزرگ‌تر از مرزهای مربعی‌اش است، در اندازه اصلی‌اش نمایش داده شده است و بخش‌هایی از آن از بالا و پایین قاب فراتر رفته است. تصویر منبع کوچک‌تر از مرزها: تصویری عمودی که در ابتدا کوچک‌تر از مرزهای مربعی‌اش بود، در اندازه اصلی‌اش در قاب نمایش داده شده است و پس‌زمینه‌ای زرد در اطراف آن دیده می‌شود. تصویر منبع بزرگ‌تر از مرزها: تصویری افقی که دراصل بزرگ‌تر از مرزهای مربعی‌اش است، در اندازه اصلی‌اش نمایش داده شده است و بخش‌هایی از آن از سمت چپ و راست قاب فراتر رفته است. تصویر منبع کوچک‌تر از مرزها: تصویری افقی که در ابتدا کوچک‌تر از مرزهای مربعی‌اش بود، در اندازه اصلی خود در قاب نمایش داده می‌شود و پس‌زمینه‌ای زرد در اطراف آن دیده می‌شود.

برش دادن Image ترکیب‌پذیر به شکل

برای اینکه تصویر در شکل جا شود، از اصلاح‌کننده داخلی 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)
)

تصویر سگی که به‌شکل دایره‌ای کامل برش داده شده است.
شکل ۱. درحال برش دادن تصویر با 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))
)

تصویر مربعی از سگی که گوشه‌های آن گرد شده است.
شکل ۲. درحال برش دادن تصویر با 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())
)

تصویر مربعی از سگی که به‌شکل بیضی سفارشی برش داده شده است.
شکل ۳. برش دادن تصویر با شکل مسیر سفارشی.

افزودن حاشیه به ترکیب‌پذیر 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)
)

تصویر مربعی از یک سگ که به‌صورت دایره‌ای برش داده شده است و حاشیه‌ای زرد در اطراف شکل دایره‌ای دارد.
شکل ۴. تصویر برش‌خورده با حاشیه‌ای در اطراف آن.

برای ایجاد حاشیه گرادیان، می‌توانید از میانای برنامه‌سازی کاربردی Brush برای کشیدن حاشیه گرادیان رنگین‌کمانی در اطراف تصویر استفاده کنید:

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

تصویر دایره‌ای از سگی با حاشیه گرادیان رنگین‌کمانی در اطراف شکل دایره‌ای.
شکل ۵. حاشیه دایره‌ای با گرادیان رنگین‌کمان.

تنظیم نسبت ابعادی سفارشی

برای تبدیل تصویر به نسبت ابعادی سفارشی، از Modifier.aspectRatio(16f/9f) برای ارائه نسبت سفارشی برای تصویر (یا هر ترکیب‌پذیر) استفاده کنید.

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

تصویر مربعی از یک سگ که به نسبت ابعادی ۱۶:۹ تبدیل شده است و عریض‌تر و کوتاه‌تر شده است.
شکل ۶. استفاده از Modifier.aspectRatio(16f/9f) در Image.

فیلتر رنگ: تبدیل رنگ‌های پیکسل تصویر

Image ترکیب‌پذیر دارای پارامتر colorFilter است که می‌تواند خروجی پیکسل‌های تکی تصویرتان را تغییر دهد.

سایه‌رنگ دادن به تصاویر

استفاده از ColorFilter.tint(color, blendMode) حالت ترکیبی با رنگ داده‌شده را روی ترکیب‌پذیر 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)
)

تصویر اتوبوسی که سایه‌رنگ زرد به آن اضافه شده است.
شکل ۷. ‫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 اعمال شده است و درنتیجه سایه‌های سبز تیره‌تری ایجاد شده است.
شکل ۸. 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) })
)

سگی با فیلتر سیاه‌وسفید که همه اشباع رنگ را حذف کرده است.
شکل ۹. ماتریس رنگ با اشباع ۰ (تصویر سیاه‌وسفید).

تنظیم کنتراست یا روشنایی 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))
)

سگی با روشنایی و کنتراست افزایش‌یافته که باعث می‌شود واضح‌تر به‌نظر برسد.
شکل ۱۰. روشنایی و کنتراست تصویر بااستفاده از 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))
)

سگی با رنگ‌های معکوس، که جلوه‌ای شبیه به نگاتیو را نشان می‌دهد.
شکل ۱۱. رنگ‌های تصویر معکوس شد.

محو کردن ساختنی 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))
        )
)

سگی با جلوه محو شدید که باعث می‌شود نامشخص و خارج از فوکوس به‌نظر برسد.
شکل ۱۲. 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))
)

تصویر محو سگی که محو بودن آن فراتر از مرزهای تصویر اصلی گسترش یافته و لبه‌ها را تار کرده است.
شکل ۱۳. BlurEdgeTreatment.Unbounded.