ব্রাশ: গ্রেডিয়েন্ট এবং শেডার

কম্পোজে একটি Brush বর্ণনা করে যে কীভাবে স্ক্রিনে কিছু আঁকা হয়: এটি অঙ্কন এলাকায় আঁকা রঙ(গুলি) নির্ধারণ করে (যেমন একটি বৃত্ত, বর্গক্ষেত্র, পথ)। কিছু অন্তর্নির্মিত ব্রাশ রয়েছে যা আঁকার জন্য উপযোগী, যেমন LinearGradient , RadialGradient বা একটি প্লেইন SolidColor ব্রাশ।

আঁকানো বিষয়বস্তুতে পেইন্টিং শৈলী প্রয়োগ করতে Modifier.background() , TextStyle বা DrawScope ড্র কলের সাথে ব্রাশ ব্যবহার করা যেতে পারে।

উদাহরণস্বরূপ, DrawScope একটি বৃত্ত আঁকার জন্য একটি অনুভূমিক গ্রেডিয়েন্ট ব্রাশ প্রয়োগ করা যেতে পারে:

val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue))
Canvas(
    modifier = Modifier.size(200.dp),
    onDraw = {
        drawCircle(brush)
    }
)
অনুভূমিক গ্রেডিয়েন্ট দিয়ে বৃত্ত আঁকা
চিত্র 1 : অনুভূমিক গ্রেডিয়েন্ট দিয়ে বৃত্ত আঁকা

গ্রেডিয়েন্ট ব্রাশ

অনেকগুলি অন্তর্নির্মিত গ্রেডিয়েন্ট ব্রাশ রয়েছে যা বিভিন্ন গ্রেডিয়েন্ট প্রভাব অর্জন করতে ব্যবহার করা যেতে পারে। এই ব্রাশগুলি আপনাকে রংগুলির তালিকা নির্দিষ্ট করতে দেয় যেগুলি থেকে আপনি একটি গ্রেডিয়েন্ট তৈরি করতে চান।

উপলব্ধ গ্রেডিয়েন্ট ব্রাশের একটি তালিকা এবং তাদের সংশ্লিষ্ট আউটপুট:

গ্রেডিয়েন্ট ব্রাশের ধরন আউটপুট
Brush.horizontalGradient(colorList) অনুভূমিক গ্রেডিয়েন্ট
Brush.linearGradient(colorList) লিনিয়ার গ্রেডিয়েন্ট
Brush.verticalGradient(colorList) উল্লম্ব গ্রেডিয়েন্ট
Brush.sweepGradient(colorList)
দ্রষ্টব্য: রঙের মধ্যে একটি মসৃণ রূপান্তর পেতে - শেষ রঙটি শুরুর রঙে সেট করুন।
সুইপ গ্রেডিয়েন্ট
Brush.radialGradient(colorList) রেডিয়াল গ্রেডিয়েন্ট

colorStops দিয়ে রঙের ডিস্ট্রিবিউশন পরিবর্তন করুন

গ্রেডিয়েন্টে রঙগুলি কীভাবে প্রদর্শিত হবে তা কাস্টমাইজ করতে, আপনি প্রতিটির জন্য colorStops মান পরিবর্তন করতে পারেন। colorStops একটি ভগ্নাংশ হিসাবে নির্দিষ্ট করা উচিত, 0 এবং 1 এর মধ্যে। 1-এর বেশি মানগুলির ফলে সেই রংগুলি গ্রেডিয়েন্টের অংশ হিসাবে রেন্ডার হবে না।

আপনি রঙের স্টপগুলিকে বিভিন্ন পরিমাণে কনফিগার করতে পারেন, যেমন এক রঙের কম বা বেশি:

val colorStops = arrayOf(
    0.0f to Color.Yellow,
    0.2f to Color.Red,
    1f to Color.Blue
)
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .background(Brush.horizontalGradient(colorStops = colorStops))
)

কালার colorStop পেয়ারে সংজ্ঞায়িত হিসাবে প্রদত্ত অফসেটে রং ছড়িয়ে দেওয়া হয়, লাল এবং নীলের চেয়ে কম হলুদ।

বিভিন্ন রঙের স্টপ দিয়ে কনফিগার করা ব্রাশ
চিত্র 2 : ব্রাশ বিভিন্ন রঙের স্টপ দিয়ে কনফিগার করা হয়েছে

TileMode দিয়ে একটি প্যাটার্ন পুনরাবৃত্তি করুন

প্রতিটি গ্রেডিয়েন্ট ব্রাশে একটি TileMode সেট করার বিকল্প রয়েছে। আপনি যদি গ্রেডিয়েন্টের জন্য একটি শুরু এবং শেষ সেট না করে থাকেন তবে আপনি TileMode লক্ষ্য করবেন না, কারণ এটি পুরো এলাকাটি পূরণ করতে ডিফল্ট হবে। একটি TileMode শুধুমাত্র গ্রেডিয়েন্টকে টাইল করবে যদি এলাকার আকার ব্রাশের আকারের চেয়ে বড় হয়।

নিম্নলিখিত কোডটি গ্রেডিয়েন্ট প্যাটার্নটি 4 বার পুনরাবৃত্তি করবে, যেহেতু endX 50.dp এ সেট করা হয়েছে এবং আকারটি 200.dp এ সেট করা হয়েছে:

val listColors = listOf(Color.Yellow, Color.Red, Color.Blue)
val tileSize = with(LocalDensity.current) {
    50.dp.toPx()
}
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .background(
            Brush.horizontalGradient(
                listColors,
                endX = tileSize,
                tileMode = TileMode.Repeated
            )
        )
)

উপরের HorizontalGradient উদাহরণের জন্য বিভিন্ন টাইল মোডগুলি কী করে তার বিশদ বিবরণ এখানে একটি টেবিল রয়েছে:

টাইলমোড আউটপুট
TileMode.Repeated : প্রান্তটি শেষ রঙ থেকে প্রথম পর্যন্ত পুনরাবৃত্তি হয়। টাইলমোড পুনরাবৃত্তি
TileMode.Mirror : প্রান্তটি শেষ রঙ থেকে প্রথম পর্যন্ত মিরর করা হয়। টাইলমোড মিরর
TileMode.Clamp : প্রান্তটি চূড়ান্ত রঙে আটকানো হয়। তারপরে এটি বাকি অঞ্চলের জন্য নিকটতম রঙটি আঁকবে। টাইল মোড বাতা
TileMode.Decal : শুধুমাত্র সীমার আকার পর্যন্ত রেন্ডার করুন। TileMode.Decal মূল সীমার বাইরে নমুনা সামগ্রীতে স্বচ্ছ কালো ব্যবহার করে যেখানে TileMode.Clamp প্রান্তের রঙের নমুনা দেয়। টাইল মোড ডেকাল

TileMode অন্যান্য দিকনির্দেশক গ্রেডিয়েন্টের জন্য একইভাবে কাজ করে, যে দিকটি পুনরাবৃত্তি ঘটে তার পার্থক্য।

ব্রাশের আকার পরিবর্তন করুন

আপনার ব্রাশ যে এলাকায় আঁকা হবে তার মাপ যদি আপনি জানেন, আপনি টাইল endX সেট করতে পারেন যেমনটি আমরা উপরে TileMode বিভাগে দেখেছি। আপনি যদি একটি DrawScope এ থাকেন, তাহলে আপনি এলাকার আকার পেতে এর size বৈশিষ্ট্য ব্যবহার করতে পারেন।

আপনি যদি আপনার অঙ্কন এলাকার আকার না জানেন (উদাহরণস্বরূপ যদি Brush টেক্সটে বরাদ্দ করা থাকে), আপনি Shader প্রসারিত করতে পারেন এবং createShader ফাংশনে অঙ্কন এলাকার আকার ব্যবহার করতে পারেন।

এই উদাহরণে, প্যাটার্নটি 4 বার পুনরাবৃত্তি করতে আকারটিকে 4 দ্বারা ভাগ করুন:

val listColors = listOf(Color.Yellow, Color.Red, Color.Blue)
val customBrush = remember {
    object : ShaderBrush() {
        override fun createShader(size: Size): Shader {
            return LinearGradientShader(
                colors = listColors,
                from = Offset.Zero,
                to = Offset(size.width / 4f, 0f),
                tileMode = TileMode.Mirror
            )
        }
    }
}
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .background(customBrush)
)

শেডারের আকার 4 দ্বারা বিভক্ত
চিত্র 3 : শেডারের আকার 4 দ্বারা বিভক্ত

আপনি রেডিয়াল গ্রেডিয়েন্টের মতো অন্য যে কোনও গ্রেডিয়েন্টের ব্রাশের আকারও পরিবর্তন করতে পারেন। যদি আপনি একটি আকার এবং কেন্দ্র নির্দিষ্ট না করেন, তাহলে গ্রেডিয়েন্টটি DrawScope এর সম্পূর্ণ সীমানা দখল করবে, এবং রেডিয়াল গ্রেডিয়েন্টের কেন্দ্রটি DrawScope সীমার কেন্দ্রে ডিফল্ট হবে। এর ফলে রেডিয়াল গ্রেডিয়েন্টের কেন্দ্রটি ছোট মাত্রার কেন্দ্র হিসাবে প্রদর্শিত হয় (প্রস্থ বা উচ্চতা):

Box(
    modifier = Modifier
        .fillMaxSize()
        .background(
            Brush.radialGradient(
                listOf(Color(0xFF2be4dc), Color(0xFF243484))
            )
        )
)

আকার পরিবর্তন ছাড়া রেডিয়াল গ্রেডিয়েন্ট সেট
চিত্র 4 : আকার পরিবর্তন ছাড়া রেডিয়াল গ্রেডিয়েন্ট সেট

ব্যাসার্ধের আকার সর্বোচ্চ মাত্রায় সেট করতে রেডিয়াল গ্রেডিয়েন্ট পরিবর্তন করা হলে, আপনি দেখতে পাবেন যে এটি একটি ভাল রেডিয়াল গ্রেডিয়েন্ট প্রভাব তৈরি করে:

val largeRadialGradient = object : ShaderBrush() {
    override fun createShader(size: Size): Shader {
        val biggerDimension = maxOf(size.height, size.width)
        return RadialGradientShader(
            colors = listOf(Color(0xFF2be4dc), Color(0xFF243484)),
            center = size.center,
            radius = biggerDimension / 2f,
            colorStops = listOf(0f, 0.95f)
        )
    }
}

Box(
    modifier = Modifier
        .fillMaxSize()
        .background(largeRadialGradient)
)

ক্ষেত্রফলের আকারের উপর ভিত্তি করে রেডিয়াল গ্রেডিয়েন্টে বড় ব্যাসার্ধ
চিত্র 5 : ক্ষেত্রফলের আকারের উপর ভিত্তি করে রেডিয়াল গ্রেডিয়েন্টে বড় ব্যাসার্ধ

এটা লক্ষনীয় যে শেডার তৈরিতে যে প্রকৃত আকারটি প্রেরণ করা হয় তা নির্ধারণ করা হয় যেখান থেকে এটি আহ্বান করা হয়েছে। ডিফল্টরূপে, Brush তার Shader অভ্যন্তরীণভাবে পুনঃনির্ধারণ করবে যদি আকারটি Brush শেষ সৃষ্টির থেকে আলাদা হয়, অথবা যদি শেডার তৈরিতে ব্যবহৃত কোনো স্টেট অবজেক্ট পরিবর্তিত হয়।

নিচের কোডটি বিভিন্ন আকারের সাথে তিনটি ভিন্ন বার শেডার তৈরি করে, যেমন অঙ্কন এলাকার আকার পরিবর্তন হয়:

val colorStops = arrayOf(
    0.0f to Color.Yellow,
    0.2f to Color.Red,
    1f to Color.Blue
)
val brush = Brush.horizontalGradient(colorStops = colorStops)
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .drawBehind {
            drawRect(brush = brush) // will allocate a shader to occupy the 200 x 200 dp drawing area
            inset(10f) {
      /* Will allocate a shader to occupy the 180 x 180 dp drawing area as the
       inset scope reduces the drawing  area by 10 pixels on the left, top, right,
      bottom sides */
                drawRect(brush = brush)
                inset(5f) {
        /* will allocate a shader to occupy the 170 x 170 dp drawing area as the
         inset scope reduces the  drawing area by 5 pixels on the left, top,
         right, bottom sides */
                    drawRect(brush = brush)
                }
            }
        }
)

একটি ব্রাশ হিসাবে একটি ছবি ব্যবহার করুন

একটি Brush হিসাবে একটি ImageBitmap ব্যবহার করতে, একটি ImageBitmap হিসাবে ছবিটি লোড করুন, এবং একটি ImageShader ব্রাশ তৈরি করুন:

val imageBrush =
    ShaderBrush(ImageShader(ImageBitmap.imageResource(id = R.drawable.dog)))

// Use ImageShader Brush with background
Box(
    modifier = Modifier
        .requiredSize(200.dp)
        .background(imageBrush)
)

// Use ImageShader Brush with TextStyle
Text(
    text = "Hello Android!",
    style = TextStyle(
        brush = imageBrush,
        fontWeight = FontWeight.ExtraBold,
        fontSize = 36.sp
    )
)

// Use ImageShader Brush with DrawScope#drawCircle()
Canvas(onDraw = {
    drawCircle(imageBrush)
}, modifier = Modifier.size(200.dp))

ব্রাশটি কয়েকটি ভিন্ন ধরণের অঙ্কনে প্রয়োগ করা হয়: একটি পটভূমি, পাঠ্য এবং ক্যানভাস। এটি নিম্নলিখিত আউটপুট:

ImageShader ব্রাশ বিভিন্ন উপায়ে ব্যবহার করা হয়
চিত্র 6 : ইমেজশেডার ব্রাশ ব্যবহার করে একটি পটভূমি আঁকুন, পাঠ্য আঁকুন এবং একটি বৃত্ত আঁকুন

লক্ষ্য করুন যে পাঠ্যটি এখন ImageBitmap ব্যবহার করে পাঠ্যের জন্য পিক্সেল আঁকার জন্য রেন্ডার করা হয়েছে।

উন্নত উদাহরণ: কাস্টম ব্রাশ

AGSL RuntimeShader ব্রাশ

AGSL GLSL Shader ক্ষমতার একটি উপসেট অফার করে। শেডার্স এজিএসএল-এ লেখা এবং কম্পোজে ব্রাশ দিয়ে ব্যবহার করা যেতে পারে।

একটি শেডার ব্রাশ তৈরি করতে, প্রথমে শেডারটিকে AGSL শেডার স্ট্রিং হিসাবে সংজ্ঞায়িত করুন:

@Language("AGSL")
val CUSTOM_SHADER = """
    uniform float2 resolution;
    layout(color) uniform half4 color;
    layout(color) uniform half4 color2;

    half4 main(in float2 fragCoord) {
        float2 uv = fragCoord/resolution.xy;

        float mixValue = distance(uv, vec2(0, 1));
        return mix(color, color2, mixValue);
    }
""".trimIndent()

উপরের শেডারটি দুটি ইনপুট রঙ নেয়, অঙ্কন এলাকার নীচের বাম দিক থেকে দূরত্ব গণনা করে ( vec2(0, 1) ) এবং দূরত্বের উপর ভিত্তি করে দুটি রঙের মধ্যে একটি mix করে। এটি একটি গ্রেডিয়েন্ট প্রভাব তৈরি করে।

তারপরে, শেডার ব্রাশ তৈরি করুন এবং resolution জন্য ইউনিফর্ম সেট করুন - অঙ্কন এলাকার আকার, এবং color এবং color2 আপনি আপনার কাস্টম গ্রেডিয়েন্টে ইনপুট হিসাবে ব্যবহার করতে চান:

val Coral = Color(0xFFF3A397)
val LightYellow = Color(0xFFF8EE94)

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
@Preview
fun ShaderBrushExample() {
    Box(
        modifier = Modifier
            .drawWithCache {
                val shader = RuntimeShader(CUSTOM_SHADER)
                val shaderBrush = ShaderBrush(shader)
                shader.setFloatUniform("resolution", size.width, size.height)
                onDrawBehind {
                    shader.setColorUniform(
                        "color",
                        android.graphics.Color.valueOf(
                            LightYellow.red, LightYellow.green,
                            LightYellow
                                .blue,
                            LightYellow.alpha
                        )
                    )
                    shader.setColorUniform(
                        "color2",
                        android.graphics.Color.valueOf(
                            Coral.red,
                            Coral.green,
                            Coral.blue,
                            Coral.alpha
                        )
                    )
                    drawRect(shaderBrush)
                }
            }
            .fillMaxWidth()
            .height(200.dp)
    )
}

এটি চালালে, আপনি স্ক্রিনে নিম্নলিখিত রেন্ডার করা দেখতে পারেন:

কাস্টম AGSL Shader কম্পোজে চলছে
চিত্র 7 : কাস্টম AGSL শেডার কম্পোজে চলছে

এটি লক্ষণীয় যে আপনি কেবল গ্রেডিয়েন্টের চেয়ে শেডারগুলির সাথে আরও অনেক কিছু করতে পারেন, কারণ এটি সমস্ত গণিত-ভিত্তিক গণনা। AGSL সম্পর্কে আরও তথ্যের জন্য, AGSL ডকুমেন্টেশন দেখুন।

অতিরিক্ত সম্পদ

রচনায় ব্রাশ ব্যবহারের আরও উদাহরণের জন্য, নিম্নলিখিত সংস্থানগুলি দেখুন:

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}