Android Bitmap Processing: Rounded Corners and Creative Filter Effects

Rounded Corner Bitmaps

public static Bitmap createRoundedBitmap(Bitmap sourceBitmap, float cornerRadius) {
    Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(resultBitmap);
    
    final int maskColor = 0xff424242;
    final Paint paint = new Paint();
    final Rect imageBounds = new Rect(0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight());
    final RectF boundsF = new RectF(imageBounds);
    
    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(maskColor);
    canvas.drawRoundRect(boundsF, cornerRadius, cornerRadius, paint);
    
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(sourceBitmap, imageBounds, imageBounds, paint);
    
    return resultBitmap;
}

Filter Effects

Grayscale (Black and White) Conversion

public static Bitmap convertToGrayscale(Bitmap sourceBitmap) {
    int width = sourceBitmap.getWidth();
    int height = sourceBitmap.getHeight();
    int[] pixelArray = new int[width * height];
    
    sourceBitmap.getPixels(pixelArray, 0, width, 0, 0, width, height);
    final int fullAlpha = 0xFF << 24;
    
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int currentPixel = pixelArray[y * width + x];
            int red = (currentPixel & 0x00FF0000) >> 16;
            int green = (currentPixel & 0x0000FF00) >> 8;
            int blue = currentPixel & 0x000000FF;
            
            int grayscaleValue = (int) (red * 0.3 + green * 0.59 + blue * 0.11);
            int grayscalePixel = fullAlpha | (grayscaleValue << 16) | (grayscaleValue << 8) | grayscaleValue;
            pixelArray[y * width + x] = grayscalePixel;
        }
    }
    
    Bitmap resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
    resultBitmap.setPixels(pixelArray, 0, width, 0, 0, width, height);
    return resultBitmap;
}

Gaussian Blur

public static Bitmap applyGaussianBlur(Bitmap sourceBitmap) {
    int[] blurKernel = new int[] {1, 2, 1, 2, 4, 2, 1, 2, 1};
    int width = sourceBitmap.getWidth();
    int height = sourceBitmap.getHeight();
    Bitmap resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
    
    int[] pixelArray = new int[width * height];
    sourceBitmap.getPixels(pixelArray, 0, width, 0, 0, width, height);
    final int normalizationFactor = 16;
    
    for (int y = 1; y < height -1; y++) {
        for (int x =1; x < width -1; x++) {
            int kernelIndex =0;
            int totalRed =0, totalGreen=0, totalBlue=0;
            
            for (int dy = -1; dy <=1; dy++) {
                for (int dx=-1; dx <=1; dx++) {
                    int currentPixel = pixelArray[(y+dy)*width + (x+dx)];
                    totalRed += Color.red(currentPixel) * blurKernel[kernelIndex];
                    totalGreen += Color.green(currentPixel) * blurKernel[kernelIndex];
                    totalBlue += Color.blue(currentPixel) * blurKernel[kernelIndex];
                    kernelIndex++;
                }
            }
            
            totalRed /= normalizationFactor;
            totalGreen /= normalizationFactor;
            totalBlue /= normalizationFactor;
            
            totalRed = Math.min(255, Math.max(0, totalRed));
            totalGreen = Math.min(255, Math.max(0, totalGreen));
            totalBlue = Math.min(255, Math.max(0, totalBlue));
            
            pixelArray[y*width +x] = Color.argb(255, totalRed, totalGreen, totalBlue);
        }
    }
    
    resultBitmap.setPixels(pixelArray, 0, width, 0,0, width, height);
    return resultBitmap;
}

Sketch Effect

public static Bitmap applySketchEffect(Bitmap sourceBitmap) {
    int width = sourceBitmap.getWidth();
    int height = sourceBitmap.getHeight();
    int[] sourcePixels = new int[width*height];
    int[] invertedPixels = new int[width*height];
    
    sourceBitmap.getPixels(sourcePixels,0, width,0,0,width,height);
    
    // Convert to grayscale and invert
    for (int y=0; y<height; y++) {
        for(int x=0; x<width; x++) {
            int idx = y*width +x;
            int r = Color.red(sourcePixels[idx]);
            int g = Color.green(sourcePixels[idx]);
            int b = Color.blue(sourcePixels[idx]);
            int gray = (r+g+b)/3;
            sourcePixels[idx] = gray;
            invertedPixels[idx] = 255 - gray;
        }
    }
    
    // Apply Gaussian blur to inverted grayscale
    applyGaussianBlurToGrayscale(invertedPixels,5.0,5.0,width,height);
    
    // Blend original and blurred inverted
    for(int y=0; y<height; y++) {
        for(int x=0; x<width; x++) {
            int idx = y*width +x;
            int gray = sourcePixels[idx];
            int blurredInv = invertedPixels[idx];
            int sketchValue = (gray <<8) / (256 - blurredInv);
            sketchValue = Math.min(255, Math.max(0, sketchValue));
            sourcePixels[idx] = Color.rgb(sketchValue, sketchValue, sketchValue);
        }
    }
    
    sourceBitmap.setPixels(sourcePixels,0,width,0,0,width,height);
    return sourceBitmap;
}

private static int applyGaussianBlurToGrayscale(int[] pixels, double horizontalSigma, double verticalSigma, int width, int height) {
    int[] tempSrc = new int[Math.max(width, height)];
    int[] tempDst = new int[Math.max(width, height)];
    double[] posVals = new double[Math.max(width, height)];
    double[] negVals = new double[Math.max(width, height)];
    
    double[] posN = new double[5], negN = new double[5];
    double[] posD = new double[5], negD = new double[5];
    double[] posBd = new double[5], negBd = new double[5];
    
    // Process vertical direction
    if (verticalSigma >0) {
        verticalSigma = Math.abs(verticalSigma)+1.0;
        double stdDev = Math.sqrt(-(verticalSigma*verticalSigma)/(2*Math.log(1.0/255.0)));
        calculateBlurConstants(posN, negN, posD, negD, posBd, negBd, stdDev);
        
        for(int col=0; col<width; col++) {
            Arrays.fill(posVals, 0);
            Arrays.fill(negVals, 0);
            
            for(int y=0; y<height; y++) {
                tempSrc[y] = pixels[y*width +col];
            }
            
            int posSrcIdx=0, negSrcIdx=height-1;
            int posValIdx=0, negValIdx=height-1;
            int[] posInit = new int[4], negInit = new int[4];
            posInit[0] = tempSrc[0];
            negInit[0] = tempSrc[height-1];
            
            for(int y=0; y<height; y++) {
                int terms = y<4 ? y :4;
                for(int i=0; i<=terms; i++) {
                    posVals[posValIdx] += posN[i] * tempSrc[posSrcIdx -i] - posD[i] * posVals[posValIdx -i];
                    negVals[negValIdx] += negN[i] * tempSrc[negSrcIdx +i] - negD[i] * negVals[negValIdx +i];
                }
                for(int i=terms+1; i<=4; i++) {
                    posVals[posValIdx] += (posN[i] - posBd[i]) * posInit[0];
                    negVals[negValIdx] += (negN[i] - negBd[i]) * negInit[0];
                }
                posSrcIdx++; negSrcIdx--;
                posValIdx++; negValIdx--;
            }
            
            mergeBlurResults(posVals, negVals, tempDst, 1, height);
            for(int y=0; y<height; y++) {
                pixels[y*width +col] = tempDst[y];
            }
        }
    }
    
    // Process horizontal direction
    if (horizontalSigma>0) {
        horizontalSigma = Math.abs(horizontalSigma)+1.0;
        double stdDev;
        if (horizontalSigma != verticalSigma) {
            stdDev = Math.sqrt(-(horizontalSigma*horizontalSigma)/(2*Math.log(1.0/255.0)));
            calculateBlurConstants(posN, negN, posD, negD, posBd, negBd, stdDev);
        }
        
        for(int y=0; y<height; y++) {
            Arrays.fill(posVals,0);
            Arrays.fill(negVals,0);
            
            for(int x=0; x<width; x++) {
                tempSrc[x] = pixels[y*width +x];
            }
            
            int posSrcIdx=0, negSrcIdx=width-1;
            int posValIdx=0, negValIdx=width-1;
            int[] posInit = new int[4], negInit = new int[4];
            posInit[0] = tempSrc[0];
            negInit[0] = tempSrc[width-1];
            
            for(int x=0; x<width; x++) {
                int terms = x<4 ?x:4;
                for(int i=0; i<=terms; i++) {
                    posVals[posValIdx] += posN[i] * tempSrc[posSrcIdx -i] - posD[i] * posVals[posValIdx -i];
                    negVals[negValIdx] += negN[i] * tempSrc[negSrcIdx +i] - negD[i] * negVals[negValIdx +i];
                }
                for(int i=terms+1; i<=4; i++) {
                    posVals[posValIdx] += (posN[i]-posBd[i])*posInit[0];
                    negVals[negValIdx] += (negN[i]-negBd[i])*negInit[0];
                }
                posSrcIdx++; negSrcIdx--;
                posValIdx++; negValIdx--;
            }
            
            mergeBlurResults(posVals, negVals, tempDst,1, width);
            for(int x=0; x<width; x++) {
                pixels[y*width +x] = tempDst[x];
            }
        }
    }
    return 0;
}

private static void mergeBlurResults(double[] src1, double[] src2, int[] dest, int bytes, int length) {
    int idx=0;
    for(int i=0; i<length*bytes; i++) {
        double sum = src1[idx] + src2[idx];
        sum = Math.min(255, Math.max(0, sum));
        dest[idx] = (int)sum;
        idx++;
    }
}

private static void calculateBlurConstants(double[] posN, double[] negN, double[] posD, double[] negD, double[] posBd, double[] negBd, double stdDev) {
    double div = Math.sqrt(2*Math.PI)*stdDev;
    double x0 = -1.783/stdDev;
    double x1 = -1.723/stdDev;
    double x2 = 0.6318/stdDev;
    double x3 =1.997/stdDev;
    double x4=1.6803/div;
    double x5=3.735/div;
    double x6=-0.6803/div;
    double x7=-0.2598/div;
    
    posN[0] = x4+x6;
    posN[1] = Math.exp(x1)*(x7*Math.sin(x3)-(x6+2*x4)*Math.cos(x3)) + Math.exp(x0)*(x5*Math.sin(x2)-(2*x6+x4)*Math.cos(x2));
    posN[2] = 2*Math.exp(x0+x1)*((x4+x6)*Math.cos(x3)*Math.cos(x2) -x5*Math.cos(x3)*Math.sin(x2)-x7*Math.cos(x2)*Math.sin(x3)) +x6*Math.exp(2*x0)+x4*Math.exp(2*x1);
    posN[3] = Math.exp(x1+2*x0)*(x7*Math.sin(x3)-x6*Math.cos(x3)) + Math.exp(x0+2*x1)*(x5*Math.sin(x2)-x4*Math.cos(x2));
    posN[4] =0.0;
    
    posD[0] =0.0;
    posD[1] = -2*Math.exp(x1)*Math.cos(x3) -2*Math.exp(x0)*Math.cos(x2);
    posD[2] =4*Math.cos(x3)*Math.cos(x2)*Math.exp(x0+x1)+Math.exp(2*x1)+Math.exp(2*x0);
    posD[3] =-2*Math.cos(x2)*Math.exp(x0+2*x1)-2*Math.cos(x3)*Math.exp(x1+2*x0);
    posD[4] =Math.exp(2*x0+2*x1);
    
    System.arraycopy(posD,0,negD,0,5);
    negN[0] =0.0;
    for(int i=1; i<5; i++) {
        negN[i] = posN[i] - posD[i]*posN[0];
    }
    
    double sumPosN=0, sumNegN=0, sumD=0;
    for(int i=0; i<5; i++) {
        sumPosN += posN[i];
        sumNegN += negN[i];
        sumD += posD[i];
    }
    
    double a = sumPosN/(1+sumD);
    double b = sumNegN/(1+sumD);
    
    for(int i=0; i<5; i++) {
        posBd[i] = posD[i]*a;
        negBd[i] = negD[i]*b;
    }
}

Laplacien Sharpening

public static Bitmap applyLaplacianSharpening(Bitmap sourceBitmap) {
    int[] sharpenKernel = new int[] {-1,-1,-1, -1,9,-1, -1,-1,-1};
    int width = sourceBitmap.getWidth();
    int height = sourceBitmap.getHeight();
    Bitmap resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
    
    int[] pixelArray = new int[width*height];
    sourceBitmap.getPixels(pixelArray,0,width,0,0,width,height);
    final float sharpenStrength =0.3f;
    
    for(int y=1; y<height-1; y++) {
        for(int x=1; x<width-1; x++) {
            int kernelIdx=0;
            int totalRed=0, totalGreen=0, totalBlue=0;
            
            for(int dy=-1; dy<=1; dy++) {
                for(int dx=-1; dx<=1; dx++) {
                    int currentPixel = pixelArray[(y+dy)*width + (x+dx)];
                    totalRed += (int)(Color.red(currentPixel)*sharpenKernel[kernelIdx]*sharpenStrength);
                    totalGreen += (int)(Color.green(currentPixel)*sharpenKernel[kernelIdx]*sharpenStrength);
                    totalBlue += (int)(Color.blue(currentPixel)*sharpenKernel[kernelIdx]*sharpenStrength);
                    kernelIdx++;
                }
            }
            
            totalRed = Math.min(255, Math.max(0, totalRed));
            totalGreen = Math.min(255, Math.max(0, totalGreen));
            totalBlue = Math.min(255, Math.max(0, totalBlue));
            
            pixelArray[y*width +x] = Color.argb(255, totalRed, totalGreen, totalBlue);
        }
    }
    
    resultBitmap.setPixels(pixelArray,0,width,0,0,width,height);
    return resultBitmap;
}

Embosss Effect

public static Bitmap applyEmbossEffect(Bitmap sourceBitmap) {
    int width = sourceBitmap.getWidth();
    int height = sourceBitmap.getHeight();
    Bitmap resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
    
    int[] pixelArray = new int[width*height];
    sourceBitmap.getPixels(pixelArray,0,width,0,0,width,height);
    
    for(int y=1; y<height-1; y++) {
        for(int x=1; x<width-1; x++) {
            int currentIdx = y*width +x;
            int currentPixel = pixelArray[currentIdx];
            int rightPixel = pixelArray[currentIdx +1];
            
            int red = Color.red(rightPixel) - Color.red(currentPixel) +127;
            int green = Color.green(rightPixel) - Color.green(currentPixel) +127;
            int blue = Color.blue(rightPixel) - Color.blue(currentPixel) +127;
            
            red = Math.min(255, Math.max(0, red));
            green = Math.min(255, Math.max(0, green));
            blue = Math.min(255, Math.max(0, blue));
            
            pixelArray[currentIdx] = Color.argb(255, red, green, blue);
        }
    }
    
    resultBitmap.setPixels(pixelArray,0,width,0,0,width,height);
    return resultBitmap;
}

Tags: Android Development Bitmap Processing Image Filters Android UI Customization

Posted on Fri, 08 May 2026 08:27:30 +0000 by bryanptcs