Create a Photo-Editing App
This tutorial is going to demonstrate the basics of photo editing with Bada. I am going to create a photo filter that converts colour photo to grayscale photo using popular mathematical formula.
With some mathematical knowledge, you can apply the same technique to create cool photo filters like the one you use in GIMP or photoshop.
To create grayscale filter in Bada we need to:
1- Add FMedia.h and IMAGE privilege to the manifest.xml
2- Load the photo using Image class to a Bitmap object
3- Use BufferInfo class gives you the opportunity to access Bitmap pixels directly in the memory to modify them.
BufferInfo does not have any member functions but has six public attributes which are self explanatory. The most interesting attribute is the (void pointer) void * pPixels which allows you to access the pixels directly in the memory. Void pointer can point to any type of data type but you have to cast the address of it to some other pointer type to be able to manipulate its value or increment the pointer.
I have used a modified nice piece of code posted by Yuuki at the forums here that traverses through the bitmap pixel by pixel/column by column.
The original code posted by Yuuki gets the value of the pixel as shown below
//assuming 4 bytes/pixel
int color = *((int *)((byte *) info.pPixels + y *
info.pitch + x * 4));
For the grayscale filter, I want to access the Red/Green/Blue values of the pixel instead of getting the total value of the RGBA pixel. Therefore, I changed the code to
int* color = ((int *)((byte *) info.pPixels + y *
info.pitch + x * bytesPerPixel));
Instead of receiving the integer value, I modified the code to receive a pointer to the integer. This way I can access the integer value byte by byte to manipulate the Red/Green/Blue components of the pixel. You can create a byte pointer that points to the first byte of (int* color) and then increment the byte pointer to access the next byte and so on.
Maybe you can use Hexadecimal/Bitwise operations to retrieve the values of each byte directly instead of creating byte pointer. However, I used this technique for easier explanation but it is up to you to find the best/fast solution.
The mathematical formula used to convert RGB photo to grayscale is shown below
gray = (Red * 0.3) + (Green * 0.59) + (Blue * 0.11)
Red = gray
Green = gray
Blue = gray
One last thing you need to be aware about that RGBA is stored as BGRA if you choose BITMAP_PIXEL_FORMAT_ARGB8888 parameter when decoding the photo to a bitmap.
The output of applying the filter to the rose photo:
The full code of GrayScale filter application:
void PhotoEdit::GrayScaleFilter() {
result r = E_SUCCESS;
Image image;
Bitmap* pBitmap = null;
BufferInfo info;
int width = 0;
int height = 0;
int bitsPerPixel = 0;
int bytesPerPixel = 0;
String photo(L"/Res/rose.jpg");
String output(L"/Home/rose.jpg");
r = image.Construct(); //check if fails
pBitmap = image.DecodeN(photo, BITMAP_PIXEL_FORMAT_ARGB8888 );
//check if pBitmap is null
pBitmap->Lock(info);
width = info.width;
height = info.height;
bitsPerPixel = info.bitsPerPixel;
if(bitsPerPixel == 32)
bytesPerPixel = 4;
else if(bitsPerPixel == 24)
bytesPerPixel =3;
for(int x=0;x<width;x++) {
for (int y=0;y<height;y++) {
int* color = ((int *)((byte *) info.pPixels + y * info.pitch + x *bytesPerPixel));
byte* blue = (byte*) color;
byte* green = blue+ 1;
byte* red = green+ 1;
byte gray = ((*blue) * 0.11) + ((*green) * 0.59) + ((*red) *0.3);
*red = gray;
*green = gray;
*blue =gray;
}
}
pBitmap->Unlock();
r = image.EncodeToFile(*pBitmap,IMG_FORMAT_JPG,output,true);
//check if fails
delete pBitmap;
}
Related posts:
the Flagship blog & community for App Developers with main focus on Samsung's bada and cross-platform technologies 





26 Responses to “Create a Photo-Editing App”
By EatenBackToLife on Jun 30, 2010 | Reply
i’d rather made that loop like this:
byte* pixel( info.pPixels );
static float coefs[] = { 0.11, 0.59, 0.3 };
for( int count( width * height); 0 != count; –count ) {
byte gray(0);
for( int i(0); i < 3; ++i ) {
gray += pixel[i] * coefs[i];
}
for( int i(0); i < 3; ++i ) {
pixel[i] = gray;
}
pixel += bytesPerPixel;
}
this can save pixel address calculation on each iteration
By EatenBackToLife on Jun 30, 2010 | Reply
oops. don’t read my previous comment: i didn’t take info.pitch into account – it was off the screen
By EatenBackToLife on Jun 30, 2010 | Reply
here’s correct version. at least i hope it’s correct..
static float coefs[] = { 0.11, 0.59, 0.3 };
for( byte* rowPointer( info.pPixels ); –height != 0; rowPointer += info.pitch ) {
byte* pixel( rowPointer );
for( int x( width ); 0 != x; –x ) {
byte gray(0);
for( int i(0); i < 3; ++i ) {
gray += pixel[i] * coefs[i];
}
for( int i(0); i < 3; ++i ) {
pixel[i] = gray;
}
pixel += bytesPerPixel;
}
}
By Nour on Jun 30, 2010 | Reply
Thanks EatenBackToLife
I’d like to give it a try but your code will be hard to debug IMO.
Can you estimate how much this code reduces processing power or memory?
By p.l on Jun 30, 2010 | Reply
It is ridiculous that there is no API for manipulating bitmap as a canvas (so you can’t even put a custom text onto bitmap)
By Nour on Jun 30, 2010 | Reply
p.l
There is Canvas API available!
You can manipulate the bitmap in different ways and draw text on it.
1- Canvas::DrawBitmap()
2- Canvas::DrawText()
3- Bitmap::Construct (Canvas, Rectangle)
By caketuzz on Jun 30, 2010 | Reply
Thanks for the tut.
It may be useful to build photographers tools, such as histograms and levels treatment.
However, do we know how quick is that method when you apply it to large images, such as images made with the camera ?
By Nour on Jun 30, 2010 | Reply
Hi caketuzz
I have tried it on 5 megapixel taken by the phone camera [2560 x 1920] and the speed was good at the simulator.
I think EatenBackToLife code is faster because it uses one large loop only.
You can give it a try and tell us how it goes
By malloth on Jun 30, 2010 | Reply
It’s easier and much faster to use:
GS = (R + G + B) / 3;
R = GS; G = GS; B = GS;
You don’t use floating points and get 8 bit grayscale image (image can be now flatten to 8 bits/color).
By Nour on Jun 30, 2010 | Reply
Thanks malloth
I knew about this formula. I didn’t thought it will be much faster to use it.
Thanks for sharing
By caketuzz on Jun 30, 2010 | Reply
Malloth: your grayscale conversion is somewhat wrong according to the human visual system.
)
Nour: I wish I could test but I lack a Wave – I had to make a choice and purchase a Spica instead. (If someone at Samsung reads me, I’m looking for a test sample
Still I’m not sure we can extrapolate the speed in the emulator to that on the real device.
By Nour on Jun 30, 2010 | Reply
@caketuzz
I don’t have wave either. It has not arrive to my country and may not. I was trying to get for a month now but I failed…. so if they hear us both
I think wave is a decent handset and can handle this solution.
By malloth on Jun 30, 2010 | Reply
This simple algorithm was tested on Windows Mobile based devices when I deveoped simillar application as in the title.
Both algorithms are correct, but both have merits and flaws:
one uses floating point numbers on each pixel which slows down the operation on big images, but looks very good (24bit grayscale),
the other uses integers (bytes actually) which makes it faster to proceed big images, however flatterns the whole image to 8 bit grayscale – which can be seen inaccurate (by human eye) only if image contained gradients (choppy passing from one color to another).
I suppose both algorithms have proper usage.
PS. If You use other factors You can achieve Sepia effect:
void Sepia(int* pixels, int width, int height) { int pixelsLength = width * height; int red, green, blue; BYTE r, g, b; for(int i = 0; i 255) red = 255; if(green>255) green = 255; if(blue>255) blue = 255; if(red<0) red = 0; if(green<0) green = 0; if(blue<0) blue = 0; pixels[i] = (int)RGB(blue, green, red); } }Example is from WM but can be easily remade to Bada.
By malloth on Jun 30, 2010 | Reply
AGAIN! I can’t post from this line: “r = G e t R V a l u e ( p i x e l s [i] );”. We could use a decent code editor in theses comments…
By Nour on Jun 30, 2010 | Reply
Thanks malloth for the explanation. I will see the comments if I can modify them
Thanks for the tip of Sepia effect
By Nour on Jun 30, 2010 | Reply
malloth, you can use tag to post nice code
By malloth on Jul 1, 2010 | Reply
Ok, now with proper tag (I hope it will show up well this time):
void Sepia(int* pixels, int width, int height) { int pixelsLength = width * height; int red, green, blue; BYTE r, g, b; for(int i = 0; i < pixelsLength; i++) { r = GetRValue(pixels[i]); g = GetGValue(pixels[i]); b = GetBValue(pixels[i]); red = ((b * 189) / 1000) + ((g * 769) / 1000) + ((r * 393) / 1000); green = ((b * 168) / 1000) + ((g * 686) / 1000) + ((r * 349) / 1000); blue = ((b * 131) / 1000) + ((g * 534) / 1000) + ((r * 272) / 1000); if(red > 255) red = 255; if(green > 255) green = 255; if(blue > 255) blue = 255; if(red < 0) red = 0; if(green < 0) green = 0; if(blue < 0) blue = 0; pixels[i] = (int)RGB(blue, green, red); } }By malloth on Jul 1, 2010 | Reply
Thanks Nour. It works with that tag now
.
If You’d need any more image effects (like Solarize, Normalize, Pixelate, Sharpen, Blur etc.) or help with convolution filters, I’d be honored to assist You.
By Nour on Jul 1, 2010 | Reply
wow, thanks malloth for your generosity to share your code with us.
I am not working on photo-effects application now, but I shall contact you if I need any assistant in future.
thanks again
By codenode on Jul 1, 2010 | Reply
When you look for performance you should get rid of tempvariables if not needed:
By Nour on Jul 2, 2010 | Reply
Thanks codenode, but I don’t think removing extra byte will improve the performance. Anyway, I should have declared [byte gray] outside the loop but I didn’t pay much attention to the performance in this tutorial.
Thanks for the tip
By Phong Nguyen on Jul 21, 2010 | Reply
dear all
Image image;
image.Construct();
cannot compile and error happen on this
please check your code
By Nour on Jul 21, 2010 | Reply
@Phong Nguyen
search the forums to find the solution
By Kien on Aug 23, 2010 | Reply
How to rotate a image by BufferInfo ?
By HFSDev on Jan 7, 2011 | Reply
Hey guys, what’s up?
First of all, Thx for the code!
But how do you handle transparent images? I mean, how can one achieve the same effect as overlayed calls to Canvas::DrawBitmap(…) with direct memory access?
How could one draw a bitmap with transparency directly into canvas buffer?