arrow left
Back to Developer Education

    Extracting Colors from Images using the Palette API in Android

    Extracting Colors from Images using the Palette API in Android

    User Interface (UI) is very important when developing Android apps. Many developers tend to neglect this aspect. A great UI gives the user a great experience. Color selection in an app is very crucial in making it successful. <!--more--> In this tutorial, we will extract colors to use in our app from an image.

    Prerequisites

    To follow along with this tutorial, the reader should:

    • Have Android Studio installed and know how to create Android projects.
    • Have a good understanding of the Kotlin programming language.
    • Have a good understanding of XML.
    • Be able to use ViewBinding.
    • Have a basic knowledge on Android Toolbar.

    Goals

    By the end of this tutorial, the reader should:

    • Have an understanding of what Palette API is.
    • Know how to set up the Palette API library.
    • Know how to extract colors from an image using the Palette API.

    What is Palette?

    Palette is a support library in Android. It extracts prominent colors from Bitmap images. We can use it in styling view components in the app.

    The views matche the prominent color from the image. For instance, the toolbar, background, or even text color.

    Advantages of Using Palette API

    • It provides a helper class to extract prominent colors from an image.
    • We can use colors obtained to make elegant application UI designs.
    • We can customize the color Palette using in-build methods. For instance, adding filters and much more.

    Step 1. Create a new Android project

    Launch Android Studio, select New Project then Empty Activity. Name it Palette Demo. Click finish and wait for it to build.

    Create Project

    Step 2: Set up the Palette library

    Add the following dependency in the app-module level build.gradle file.

    implementation("com.android.support:palette-v7:28.0.0")
    

    Step 3: Set up the layout for our project

    In this step, we will design the UI. This will contain a ToolBar, an ImageView, a Button, and TextViews.

    ActivityMain.xml file

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto"
       xmlns:tools="http://schemas.android.com/tools"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       tools:context=".MainActivity">
    
       <com.google.android.material.appbar.AppBarLayout
    
           android:id="@+id/appBarLayout"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:theme="@style/Theme.MyApplication.AppBarOverlay"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toTopOf="parent">
           
           <androidx.appcompat.widget.Toolbar
               android:id="@+id/toolbar"
               android:layout_width="match_parent"
               android:layout_height="?attr/actionBarSize"
               android:background="?attr/colorPrimary"
               app:popupTheme="@style/Theme.MyApplication.PopupOverlay" />
       </com.google.android.material.appbar.AppBarLayout>
    
       <ImageView
           android:id="@+id/imageView"
           android:layout_width="match_parent"
           android:layout_height="250dp"
           android:src="@drawable/index"
           app:layout_constraintTop_toBottomOf="@+id/appBarLayout"
           tools:layout_editor_absoluteX="26dp" />
    
       <Button
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="Change Toolbar Color"
           android:textSize="18sp"
           android:layout_marginTop="8dp"
           android:textAllCaps="false"
           android:id="@+id/change_toolbar_color_btn"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/imageView"/>
    
       <TextView
           android:id="@+id/lightVibrant"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="8dp"
           android:gravity="center"
           android:text="Light Vibrant"
           android:textAllCaps="false"
           android:textSize="18sp"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/change_toolbar_color_btn" />
    
       <TextView
           android:id="@+id/vibrant"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="8dp"
           android:gravity="center"
           android:text="Vibrant"
           android:textAllCaps="false"
           android:textSize="18sp"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/lightVibrant" />
    
       <TextView
           android:id="@+id/lightMuted"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="8dp"
           android:gravity="center"
           android:text="Light Muted"
           android:textAllCaps="false"
           android:textSize="18sp"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/vibrant" />
    
       <TextView
           android:id="@+id/muted"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="8dp"
           android:gravity="center"
           android:text="Muted"
           android:textSize="18sp"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/lightMuted" />
    
       <TextView
           android:id="@+id/darkMuted"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="8dp"
           android:gravity="center"
           android:text="Dark Muted"
           android:textAllCaps="false"
           android:textSize="18sp"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/muted" />
    
       <TextView
           android:id="@+id/darkVibrant"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="8dp"
           android:gravity="center"
           android:text="Dark Vibrant"
           android:textAllCaps="false"
           android:textSize="18sp"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/darkMuted" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    Step 4: Create a Palette object

    A palette object allows us to access the prominent colors in an image bitmap. We use palettes to style our application by changing the application's color scheme based on the image bitmap.

    To create a palette, we generate an instance using from(bitmap: Bitmap) method. This creates a Builder from a bitmap.

    The builder either generates synchronous or asynchronous palettes. To create a palette on the same thread as the method we are invoking, we use synchronous palette .To create a palette on another thread, we use asynchronous palette.

    TheonGenerated() method is used to access the palette.

    To create a synchronous palette, we use:

    // Synchronous Palette generated and returned
    fun createPaletteSync(bitmap: Bitmap): Palette = Palette.from(bitmap).generate()
    

    To create an asynchronous palette, we use:

    // Palette created asynchronously. We use it on another thread using onGenerated() method
    fun createPaletteAsync(bitmap: Bitmap) {
       Palette.from(bitmap).generate { palette ->
           // Use the generated instance
       }
    }
    

    To generate a palette, I would suggest using asynchronous technique. Synchronous generation may not create a smooth experience. This is evident on older devices or when the Bitmap object is relatively large.

    Step 5: Extracting color profiles

    A Target defines each color extracted. We score the colors against the profile. This is done based on the saturation and the number of pixels in the bitmap image.

    The palette extracts the following six color profiles using the respective methods:

    • Light Vibrant : Palette.getLightVibrantSwatch()
    • Dark Vibrant: Palette.getDarkVibrantSwatch()
    • Vibrant: Palette.getVibrantSwatch()
    • Light Muted: Palette.getLightMutedSwatch()
    • Dark Muted: Palette.getDarkMutedSwatch()
    • Muted: Palette.getMutedSwatch()

    We are going to use swatches to get colors from the bitmap image. We use Palette.Swatch object to get each color profile. The palette has other methods for accessing more information about the color profiles.

    They include:

    • getPopulation gets the amount of pixels represented by this swatch.
    • getRgb gets the color RGB value.
    • getBodyTextColor and getTitleTextColor get text color RGB value for use over the swatch’s color.

    The get<Profile>Swatch method usually needs no parameter. But, it may return null if a particular profile is not present in the bitmap image. Before accessing a swatch, first, check if it is null or not to prevent your app from crashing.

    The following code checks if the swatch is present in the image bitmap. Otherwise, the default background color is set to Gray.

    if(palette?.lightMutedSwatch != null){
       setBackgroundColor(palette?.lightMutedSwatch!!.rgb
    }
    else{
        setBackgroundColor(Color.GRAY)
    }
    

    Here is the main activity's code:

    ActivityMain.kt file

    // Press Alt + Enter to import the libraries
    
    class MainActivity : AppCompatActivity() {
    
       private lateinit var binding: ActivityMainBinding
       private val TAG = "MainActivity"
       
       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
    
           binding = ActivityMainBinding.inflate(layoutInflater)
           setContentView(binding.root)
    
           setSupportActionBar(binding.toolbar)
           createPaletteAsync((ContextCompat.getDrawable(this,R.drawable.index) as BitmapDrawable).bitmap)
       }
    
       private fun createPaletteAsync(bitmap: Bitmap) {
           Palette.from(bitmap).generate(){ palette ->
               // Change toolbar background color
               binding.changeToolbarColorBtn.setOnClickListener {
                   binding.toolbar.setBackgroundColor(palette?.vibrantSwatch!!.rgb)
               }
    
               binding.lightVibrant.apply {
                   setBackgroundColor(palette?.lightVibrantSwatch!!.rgb)
               }
    
               binding.vibrant.apply {
                   setBackgroundColor(palette?.vibrantSwatch!!.rgb)
               }
    
               binding.lightMuted.apply {
                   if(lightVibrantSwatch != null ){
                       setBackgroundColor(palette?.lightMutedSwatch!!.rgb)
                   }
                   else{
                       setBackgroundColor(Color.Grey)
                   }
               }
    
               binding.muted.apply {
                   setBackgroundColor(palette?.mutedSwatch!!.rgb)
               }   
    
               binding.darkMuted.apply {
                   setBackgroundColor(palette?.darkMutedSwatch!!.rgb)
               }
    
               binding.darkVibrant.apply {
                   setBackgroundColor(palette?.darkVibrantSwatch!!.rgb)
               }
           }
       }
    }
    

    Demo Screens

    Upon running the app, this is what to expect:

    Screen one

    Screen two

    Conclusion

    The Palette library is a powerful tool that we can use to make elegant UI designs in Android apps. It opens doors to infinite possibilities when it comes to the set up of colors and themes.

    Use this tool to materialize your application as you continue exploring and learning.

    Check out the entire project on this GitHub repository.

    Happy coding!


    Peer Review Contributions by: Eric Gacoki

    Published on: Sep 13, 2021
    Updated on: Jul 15, 2024
    Start your journey with Cloudzilla
    CTA

    Start your journey with Cloudzilla

    With Cloudzilla, apps freely roam across a global cloud with unbeatable simplicity and cost efficiency