I am new to sdl. I have basically have the following codes which can load the images. I know how to access the pixel as below. What I need it to convert the image to 8 bit grey level and 1 bit monochrome separately. I know it got to do with pixel manipulation. Any hint or idea how to to this? I am not too sure what to set for SDL_CreateRGBSurface and also once I get the pixel what manipulation to be done?
Essentially you're just looking for a conversion function, i.e. breaking down a three component color into a one component color. This can be done different ways, probably easiest one being a simple average function:
gray(r, g, b) = (r + g + b) / 3
In C/C++ this could be done the following way (assuming you've got 24/32 bit colors with alpha being unused/occupying the most significant byte; one byte per color; i.e. RGB888 or RGBA8888):
int source_color = SDL_GetPixel(...); // some color const unsigned int component1 = source_color & 0xff; // red or blue const unsigned int component2 = (source_color >> 8) & 0xff; // green const unsigned int component3 = (source_color >> 16) & 0xff; // blue or red // calculating the average component/color (i.e. grayscale) const unsigned int gray = (component1 + component2 + component3) / 3; // back to SDL's RGB color (optional) const int gray_rgb = 0xff000000 | (gray << 16) | (gray << 8) | gray; // There are multiple ways to get the monochrom image, based on the format you'd like (e.g. just a boolean value or just a RGB value). // First version (actually not recommended, but might save you code e.g. having one fixed conversion function): // calculating the monochromatic color with a given threshold (127) const unsigned int mono = gray > 127 ? 255 : 0; // once again back to SDL's RGB model (optional) const int mono_rgb = 0xff000000 | (mono << 16) | (mono << 8) | mono; // Second version: // just return the final color in one step // this returns pure white or pure black const int mono_rgb = gray > 127 ? 0xffffffff : 0xff000000;
Note that there are similar approaches using different weightings applied to the color components. Also you can try different thresholds for the monochrome conversion to lighten/darken the image.
As for the actual SDL Surface, that's up to you. I'd just stick with
SDL_PIXELFORMAT_RGBA8888 to avoid further conversions, unless it understands grayscale images now (which I don't think?).
Further explanation on the conversions:
If you're storing a color in an integer value, you'll usually use one byte per color. In hex notation this will mean that you've got two digits per color, essentially translating to something like
AA are the byte for alpha,
BB the byte for blue, etc. If you're familiar with the hexadecimal notation of colors in HTML/CSS (like
#ff0000 for red), then this should sound familiar to you.
If you'd like to store a grayscale value
x in (A)RGB notation, you'd end up setting all three color components (red, green, and blue) to the same value (of
x). This happens in this line:
const int gray_rgb = 0xff000000 | (gray << 16) | (gray << 8) | gray;
- The logical or (
|) essentially adds the various components.
0xff000000represents full opacity (alpha = 255).
gray << 16moves the value of
grayto the correct position for red or blue (depends on pixel format). This is known as a left shift, e.g.
0x00000012 << 8will result in
0x00001200(values moved to the left by 8 bits).
gray << 8moves the value of
grayto the correct position for green.
grayfinally stays as is, which will be the value for blue or red (again depending on the pixel format).
const unsigned int mono = gray > 127 ? 255 : 0; will set the monochrome color (which is actually grayscale again, 256 different values!) based on the grayscale value.
255 represents white,
0 represents black.