Skip to content

Instantly share code, notes, and snippets.

@vxhviet
Last active April 5, 2025 15:16
Show Gist options
  • Save vxhviet/e62c85de9ba5692f74bc1c0e809596b0 to your computer and use it in GitHub Desktop.
Save vxhviet/e62c85de9ba5692f74bc1c0e809596b0 to your computer and use it in GitHub Desktop.
How to Apply Color LUT to bitmap images for filter effects in Android?

Source: StackOverflow, StackOverflow

Question: How to Apply Color LUT to bitmap images for filter effects in Android?

Answer:

    final static int X_DEPTH = 64;
    final static int Y_DEPTH = 64; //One little square in the LUT has 64x64 pixels in it
    final static int ROW_DEPTH = 8;
    final static int COLUMN_DEPTH = 8; // the LUT consists of 8x8 little squares
    final static int COLOR_DISTORTION = 4; // for new LUT size, update this so 255/COLOR_DISTORTION < X_DEPTH since we dont want to look for color outside of 1 row of the LUT square (0-63).
    
public Bitmap applyLutToBitmap(Bitmap src, Bitmap lutBitmap) {
        int mWidth = src.getWidth();
        int mHeight = src.getHeight();
        int[] imgArray = new int[mWidth * mHeight];
        src.getPixels(imgArray, 0, mWidth, 0, 0, mWidth, mHeight);

        int lutWidth = lutBitmap.getWidth();
        int lutArray[] = new int[lutWidth * lutBitmap.getHeight()];
        lutBitmap.getPixels(lutArray , 0, lutWidth, 0, 0, lutWidth, lutBitmap.getHeight());

        int R, G, B;
        for(int y = 0; y < mHeight; y++) {
            for(int x = 0; x < mWidth; x++) {

                int index = y * mWidth + x;

                // Get pixels by R, G, B
                int r = Color.red(imgArray[index]) / COLOR_DISTORTION;
                int g = Color.green(imgArray[index]) / COLOR_DISTORTION;
                int b = Color.blue(imgArray[index]) / COLOR_DISTORTION;

                //logic for altering the pixels;
                int lutIndex = getLutIndex(lutWidth, r, g, b);

                R = Color.red(lutArray[lutIndex]);
                G = Color.green(lutArray[lutIndex]);
                B = Color.blue(lutArray[lutIndex]);
                imgArray[index] = 0xff000000 | (R << 16) | (G << 8) | B;
            }
        }
        Bitmap filteredBitmap = Bitmap.createBitmap(mWidth, mHeight, src.getConfig());
        filteredBitmap.setPixels(imgArray, 0, mWidth, 0, 0, mWidth, mHeight);
        return filteredBitmap;
    }

    //the magic happens here
    private int getLutIndex(int lutWidth, int redDepth, int greenDepth, int blueDepth) {
        /*int lutX = (greenDepth % ROW_DEPTH) * X_DEPTH + blueDepth;
        int lutY = (greenDepth / COLUMN_DEPTH) * Y_DEPTH + redDepth;
        return lutY * lutWidth + lutX;*/

        int lutX = (blueDepth % ROW_DEPTH) * X_DEPTH + redDepth;
        int lutY = (blueDepth / COLUMN_DEPTH) * Y_DEPTH + greenDepth;
        return lutY * lutWidth + lutX;
    }
@NinhPhamHai
Copy link

crash app do ArrayIndexOutOfBoundsException rồi bạn ơi
CubeB

@Irfanlesnar
Copy link

not working
srctest
luttest
image

my input , my lut and see my out put

BitToLut java file
`package lut.generator.luts.lutGenerator;

import android.graphics.Bitmap;
import android.graphics.Color;

public class BitToLut {

int X_DEPTH = 64;
int Y_DEPTH = 64 ;//One little square in the LUT has 64x64 pixels in it

int ROW_DEPTH = 8;
int COLUMN_DEPTH = 8 ;// the LUT consists of 8x8 little squares

int COLOR_DISTORTION = 8;

public Bitmap applyLutToBitmap(Bitmap src, Bitmap lutBitmap) {
    int mWidth = src.getWidth();
    int mHeight = src.getHeight();
    int[] imgArray = new int[mWidth * mHeight];
    src.getPixels(imgArray, 0, mWidth, 0, 0, mWidth, mHeight);

    int lutWidth = lutBitmap.getWidth();
    int lutArray[] = new int[lutWidth * lutBitmap.getHeight()];
    lutBitmap.getPixels(lutArray , 0, lutWidth, 0, 0, lutWidth, lutBitmap.getHeight());

    int R, G, B;
    for(int y = 0; y < mHeight; y++) {
        for(int x = 0; x < mWidth; x++) {

            int index = y * mWidth + x;

            // Get pixels by R, G, B
            int r = Color.red(imgArray[index]) / COLOR_DISTORTION;
            int g = Color.green(imgArray[index]) / COLOR_DISTORTION;
            int b = Color.blue(imgArray[index]) / COLOR_DISTORTION;

            //logic for altering the pixels;
            int lutIndex = getLutIndex(lutWidth, r, g, b);

            R = Color.red(lutArray[lutIndex]);
            G = Color.green(lutArray[lutIndex]);
            B = Color.blue(lutArray[lutIndex]);
            imgArray[index] = 0xff000000 | (R << 16) | (G << 8) | B;
        }
    }
    Bitmap filteredBitmap = Bitmap.createBitmap(mWidth, mHeight, src.getConfig());
    filteredBitmap.setPixels(imgArray, 0, mWidth, 0, 0, mWidth, mHeight);
    return filteredBitmap;
}
private int getLutIndex(int lutWidth, int redDepth, int greenDepth, int blueDepth) {
    /*int lutX = (greenDepth % ROW_DEPTH) * X_DEPTH + blueDepth;
    int lutY = (greenDepth / COLUMN_DEPTH) * Y_DEPTH + redDepth;
    return lutY * lutWidth + lutX;*/

    int lutX = (blueDepth % ROW_DEPTH) * X_DEPTH + redDepth;
    int lutY = (blueDepth / COLUMN_DEPTH) * Y_DEPTH + greenDepth;
    return lutY * lutWidth + lutX;
}

}
`

Luttest Fragment
`package lut.generator.luts.lutGenerator

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import lut.generator.luts.R
import lut.generator.luts.databinding.FragmentLuttestBinding

// for new LUT size, update this so 255/COLOR_DISTORTION < X_DEPTH since we dont want to look for color outside of 1 row of the LUT square (0-63).

class Luttest : Fragment() {
private var _binding: FragmentLuttestBinding? = null
private val binding get() = _binding!!

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

}

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = FragmentLuttestBinding.inflate(inflater, container, false)

    binding.luttestimg.setImageBitmap(BitToLut().applyLutToBitmap( BitmapFactory.decodeResource(resources, R.drawable.srctest),BitmapFactory.decodeResource(resources, R.drawable.luttest)))

    return binding.root

}

}

`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment