Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Create Shadow and Blur Images

by Administrator on ‎04-21-2011 07:35 PM - edited on ‎04-21-2011 07:35 PM by BlackBerry Development Advisor (4,893 Views)

Summary

 

This article applies to the following:

 

  • BlackBerry® smartphones based on Java® technology

 

Description

 

I've recently been using Graphics.drawFilledPath to produced a background shadow effect. Although this function works flawlessly, it does not provide the developer with the ability to apply a linear gradient with an Alpha Channel.

 

After doing some research and several hours of programming I've managed to produced a set of functions that provides a Gaussian Distribution Blur Filter. The function provided allows the user to blur an image with a given radius. It also allows the user to produce shadows.

 

 

/****************************************************************************************
*
* File Name: ImageTools.java
*
* Purpose: Collection of Bitmap Image Processing Tools
*
* Created By: Mitchell Romanuik.
* Date Created: Wednesday December 22, 2010.
* Last Modified: Thursday January 05, 2011.
*
****************************************************************************************/
package program;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Graphics;

public class ImageTools
{
// Variables and Fields
private static int _radius;
private static int _kernelSize;
private static int[] _kernel;
private static int[][] _productTable;

/*************************************************************************************
*
* Required by blur() function to process images. This function merely builds a suitable
* data kernel which is in the form of a Gaussian Distribution. This kernel can be
* changed which will result in a different type of blur produced.
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* !!!!! THIS IS NOT THREAD SAFE !!!!!!!
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* @param radius Radius of Blur
* @return void
*
***************************************************************************************/
public static void buildKernel(int radius){
// Determine if Radius Selected is Valid (Values 64, 128, and 256 are Valid Maxima Values for Radius)
radius = Math.min(64, Math.max(1, radius));

// Initialize Global Variables
_radius = radius;
_kernelSize = 1 + 2*radius; // This is the range for Pixel Selection
_kernel= new int[_kernelSize]; // This is a Gaussian Distribution Dictionary

// This is an added Optimization for Embedded Devices (Reduces CPU Stress)
_productTable = new int[_kernelSize][256];

// Augment Values of Gaussian Curve Excluding Radius Pixel
for(int i=1; i<radius; i++){
// Initialize Temp Variables
int increment = radius - i;

// Gaussian Curve is Symmetric
_kernel[radius+i] = _kernel[increment] = increment*increment;

// Produce Product Table for 'each' Pixel Color 0-255
for(int j=0; j<256; j++)
_productTable[radius+i][j] = _productTable[increment][j] = _kernel[increment]*j;
}

// Augment Values of Gaussian Curve for Radius Pixel
_kernel[radius] = radius*radius;
for(int j=0; j<256; j++)
_productTable[radius][j] = _kernel[radius]*j;
}


/*************************************************************************************
*
* Blurs a Given Bitmap with the Option of Alpha Channel PreProcessing
* ** It is recommended that the AlphaChannel is Processed Before Blurring the Image
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* !!!!! THIS IS NOT THREAD SAFE !!!!!!!
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* @param image Source Bitmap
* @param left,top Start Position of Blur
* @param width,height Amount of Blur to Produce
* @param isAlpha This is an added feature which blurs only the edges of an
* image. Typically the boundary parameters are the entire
* image (not required).
* @return The Blurred Bitmap in a New Object.
*
***************************************************************************************/
public static Bitmap blur(Bitmap image, int left, int top, int width, int height, boolean isAlpha){
// Determine Bitmap Properties
int imgWidth = image.getWidth();
int imgHeight = image.getHeight();
int numPixels = width*height; // Only select the Region Size (Optimization)

// Check Image if Alpha Channel Exists
if(!image.hasAlpha() && isAlpha)
isAlpha = false;

// Determine Region to Blur on 'image'
int topYAxis = 0;
top = Math.min(imgHeight, Math.max(0, top));
left = Math.min(imgWidth, Math.max(0, left));
width = Math.min(imgWidth, Math.max(0, width));
height = Math.min(imgHeight, Math.max(0, height));

// Obtain Bitmap Pixels in ARGB from that Region
int[] data = new int[numPixels];
image.getARGB(data, 0, width, top, left, width, height); // Obtain pixel data from 'image' only the Region Specified

// Separate Color Channels
int a[] = new int[numPixels];
int r[] = new int[numPixels];
int g[] = new int[numPixels];
int b[] = new int[numPixels];
for(int i=0; i<numPixels; i++){
// Initialize Temp Variables
int pixel = data[i];
if(isAlpha)
a[i] = Math.abs((pixel&0xFF000000)>>24);
r[i] = (pixel&0x00FF0000)>>16;
g[i] = (pixel&0x0000FF00)>>8;
b[i] = (pixel&0x000000FF);
}

// Clone Array(s) of Color Channels
int a2[] = new int[numPixels];
int r2[] = new int[numPixels];
int g2[] = new int[numPixels];
int b2[] = new int[numPixels];

// Produce Clone of Bitmap with Horizontal Blurring
for(int y=0; y<height; y++){
for(int x=0; x<width; x++){
// Initialize Temp Variables
int alphaChannel=0, redChannel=0, greenChannel=0, blueChannel=0, summation=0;
int pixel = x - _radius;

// Collect RGB Data from the range [radius-x, radius+x]
for(int i=0; i<_kernelSize; i++){
// Initialize Temp Variables
int tmpPixel = pixel + i;

// Determine if Selected Pixel is within Boundary
if(tmpPixel >= 0 && tmpPixel < width){
// Collect RGB or Alpha Data over Radius
tmpPixel += topYAxis;
if(!isAlpha){
redChannel += _productTable[i][r[tmpPixel]];
greenChannel += _productTable[i][g[tmpPixel]];
blueChannel += _productTable[i][b[tmpPixel]];
}
else
if(a[tmpPixel] != 0)
alphaChannel += _productTable[i][255];

// Increase Color Average
summation += _kernel[i];
}
}
// Store Processed Data into Clone Array(s)
if(isAlpha)
a2[x+topYAxis] = alphaChannel/summation;
else{
r2[x+topYAxis] = redChannel/summation;
g2[x+topYAxis] = greenChannel/summation;
b2[x+topYAxis] = blueChannel/summation;
}
}
// Set New Data Position for Pixel Array
topYAxis += width;
}

// Produce Clone of Bitmap with Vertical Blurring
for(int x=0; x<width; x++){
for(int y=0; y<height; y++){
// Initialize Temp Variables
int alphaChannel=0, redChannel=0, greenChannel=0, blueChannel=0, summation=0;
int pixel = y - _radius;

// Collect RGB Data from the range [radius-y, radius+y]
for(int i=0; i<_kernelSize; i++){
// Initialize Temp Variables
int tmpPixel = (pixel + i)*width + x;

// Determine if Selected Pixel is within Boundary
if(tmpPixel < numPixels && tmpPixel >= 0){
// Collect RGB or Alpha Data over Radius
if(!isAlpha){
redChannel += _productTable[i][r2[tmpPixel]];
greenChannel += _productTable[i][g2[tmpPixel]];
blueChannel += _productTable[i][b2[tmpPixel]];
}
else
if(a[tmpPixel] != 0)
alphaChannel += _productTable[i][a2[tmpPixel]];

// Increase Color Average
summation += _kernel[i];
}
}
// Recombine Color Channels with Full Opacity
if(isAlpha)
data[x+y*width] = (alphaChannel/summation)<<24 | r[x+y*width]<<16 | g[x+y*width]<<8 | b[x+y*width];
else
data[x+y*width] = 0xFF000000 | (redChannel/summation)<<16 | (greenChannel/summation)<<8 | (blueChannel/summation);
}
}

// Replace 'image' Data with PreProcessed Data
image.setARGB(data, 0, width, top, left, width, height);
return image;
}
}

 

^^ code looks ugly :smileysad:

 

How to Blur an image.

 

 

ImageTools.buildKernel(5);
Bitmap _target = Bitmap.getBitmapResource("firefox.png");
_target = ImageTools.blur(_target, 0, 0, 50, 50, false);

 How to create Shadow.

 

 

// Create Bitmap and Alpha Channel
Bitmap _target = new Bitmap(50, 50);
_target.createAlpha(Bitmap.ALPHA_BITDEPTH_8BPP);

// Initialize Alpha Channel
int[] data = new int[50*50];
for(int i=0; i<50*50; i++)
data[i] = 0x00000000;

// Insert Bitmap Data
_target.setARGB(data, 0, 50, 0, 0, 50, 50);

// Prepare Drawing Canvas
Graphics canvas = Graphics.create(_target);

// Shape Properties
canvas.setColor(0x000000);
canvas.setGlobalAlpha(255);
canvas.fillRoundRect(10, 10, 30, 30, 8, 8);

ImageTools.buildKernel(5);
_target = ImageTools.blur(_target, 0, 0, 50, 50, true);

 

Blur.png

 

*Known Issues: Bitmap.createAlpha() creates funky colors.

 

 

Have fun!

 

Mitchell Romanuik.

Comments
by New Developer on ‎05-10-2011 05:58 PM

Thank you very much for this excellent contribution But in this line

 

// Obtain Bitmap Pixels in ARGB from that Region

int[] data = new int[numPixels];

image.getARGB(data, 0, width, top, left, width, height); // Obtain pixel data from 'image' only the Region Specified

 

Try with this

image.getARGB(data, 0, width, left , top , width, height);// Obtain pixel data from 'image' only the Region Specified

 

And this line

// Replace 'image' Data with PreProcessed Data

image.setARGB(data, 0, width, top, left, width, height);

 

Try with this

image.setARGB(data, 0, width, left , top, width, height);