Drawing pixels in C: OSdev - c

I’m totally beginner in osdeving. for now i’ve just implemented keyboard and vga screen following the osdevwiki. Now i’d like to draw proper pixel like this
void drawPixel(int x, int y, int rgb)
in freestanding C language.
now, in vga mode the address for printing text and colors is 0xB8000. To paint pixels in the screen how can i do? i don’t have any clue.

Text mode is discussed here:
https://wiki.osdev.org/Text_mode
It has an example here to write a colored character in text mode:
void WriteCharacter(unsigned char c, unsigned char forecolour, unsigned char backcolour, int x, int y)
{
uint16_t attrib = (backcolour << 4) | (forecolour & 0x0F);
volatile uint16_t * where;
where = (volatile uint16_t *)0xB8000 + (y * 80 + x) ;
*where = c | (attrib << 8);
}
If you want to write an RGB pixel in graphics mode you have to switch to a different video mode first.
That is explained here:
https://wiki.osdev.org/Drawing_In_Protected_Mode
Here is the code from that page on how to draw a pixel in graphics mode:
/* only valid for 800x600x16M */
static void putpixel(unsigned char* screen, int x,int y, int color) {
unsigned where = x*3 + y*2400;
screen[where] = color & 255; // BLUE
screen[where + 1] = (color >> 8) & 255; // GREEN
screen[where + 2] = (color >> 16) & 255; // RED
}
/* only valid for 800x600x32bpp */
static void putpixel(unsigned char* screen, int x,int y, int color) {
unsigned where = x*4 + y*3200;
screen[where] = color & 255; // BLUE
screen[where + 1] = (color >> 8) & 255; // GREEN
screen[where + 2] = (color >> 16) & 255; // RED
}
Basically you need to write the three color values to three bytes starting from the video memory and offset by the coordinates multiplied by some values to get to the right line and column.
The values are different for the different video modes.
Be aware that even the video memory address is different for VGA/CGA/EGA modes!

I use this method to draw pixels from text mode.
Set the character to a space character and use the color as the color of the pixel eg.
char* video = (char*)0xb8000;
video [0] = 0x20; // space character
video [1] = 0x12; // color of the pixel

Related

Convert C-Source image dump from RGB565 into RGB888

I have created with GIMP a C-Source image dump like the following:
/* GIMP RGBA C-Source image dump (example.c) */
static const struct {
guint width;
guint height;
guint bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
guint8 pixel_data[304 * 98 * 2 + 1];
} example= {
304, 98, 2,
"\206\061\206\061..... }
Is there a way to convert this image from RG565 to RGB888?
I mean , I have found a way to covert pixel by pixel:
for (i = 0; i < w * h; i++)
{
uint16_t color = *RGB565p++;
uint8_t r = ((color >> 11) & 0x1F);
uint8_t g = ((color >> 5) & 0x3F);
uint8_t b = (color & 0x1F);
r = ((((color >> 11) & 0x1F) * 527) + 23) >> 6;
g = ((((color >> 5) & 0x3F) * 259) + 33) >> 6;
b = (((color & 0x1F) * 527) + 23) >> 6;
uint32_t RGB888 = r << 16 | g << 8 | b;
printf("%d \n", RGB888);
}
the problem is that using this logic I get numbers that are not represented as the one used n the original image:
P3
304 98
255
3223857
3223857
3223857
3223857
3223857
3223857
3223857
3223857
Did I miss something?
EDIT: here you can find the original image:
https://drive.google.com/file/d/1YBphg5_V6M2FA3HWcaFZT4fHqD6yeEOl/view
There are two things you need to do to create a C file similar to the original.
Increase the size of the pixel buffer, because you are creating three bytes per pixel from the original's two bytes.
Write strings that represent the new pixel data
The first part means simply changing the 2 to 3, so you get:
guint8 pixel_data[304 * 98 * 3 + 1];
} example= {
304, 98, 3,
In the second part the simplest method would be to print ALL characters in hexadecimal or octal representation. (The original code has the "printable" characters visible, but the non-printable as octal escape sequences.)
To print ALL the characters in hexadecimal representation, do similar to
for (i = 0; i < w * h; i++)
{
...
R, G and B calculation goes here
...
// Print start of line and string (every 16 pixels)
if (i % 16 == 0)
printf("\n\"");
printf("\\x%02x\\x%02x\\x%02x", r, g, b);
// Print end of string and line (every 16 pixels)
if ((i+1) % 16 == 0)
printf("\"\n");
}
printf("\"\n"); // Termination of last line
This prints three bytes in hex representation \xab\xcd\xef and after 16 pixels, prints end of string and newline.
Note that the byte order might need changing depending on your implementation. So b, g, r instead of r, g, b.

Color gradient in C

I'm taking my first steps in C, and was trying to make a gradient color function, that draws a bunch of rectangles to the screen (vertically).
This is the code so far:
void draw_gradient(uint32_t start_color, uint32_t end_color) {
int steps = 8;
int draw_height = window_height / 8;
//Change this value inside the loop to write different color
uint32_t loop_color = start_color;
for (int i = 0; i < steps; i++) {
draw_rect(0, i * draw_height, window_width, draw_height, loop_color);
}
}
Ignoring the end_color for now, I want to try and pass a simple red color in like 0xFFFF0000 (ARGB)..and then take the red 'FF' and convert it to an integer or decrease it using the loop_color variable.
I'm not sure how to go get the red value from the hexcode and then minipulate it as a number and then write it back to hex..any ideas?
So in 8 steps the code should for example go in hex from FF to 00 or as integer from 255 to 0.
As you have said, your color is in RGB format. This calculation assumes vertical gradient - meaning from top to the bottom (linear lines).
Steps to do are:
Get number of lines to draw; this is your rectangle height
Get A, R, G, B color components from your start and end colors
uint8_t start_a = start_color >> 24;
uint8_t start_r = start_color >> 16;
uint8_t start_g = start_color >> 8;
uint8_t start_b = start_color >> 0;
uint8_t end_a = end_color >> 24;
uint8_t end_r = end_color >> 16;
uint8_t end_g = end_color >> 8;
uint8_t end_b = end_color >> 0;
Calculate step for each of the components
float step_a = (float)(end_a - start_a) / (float)height;
float step_r = (float)(end_r - start_r) / (float)height;
float step_g = (float)(end_g - start_g) / (float)height;
float step_b = (float)(end_b - start_b) / (float)height;
Run for loop and apply different step for each color
for (int i = 0; i < height; ++i) {
uint32_t color = 0 |
((start_a + i * step_a) & 0xFF) << 24 |
((start_r + i * step_r) & 0xFF) << 16 |
((start_g + i * step_g) & 0xFF) << 8 |
((start_b + i * step_b) & 0xFF) << 0
draw_horizontal_line(i, color);
}
It is better to use float for step_x and multiply/add on each iteration. Otherwise with integer rounding, you may never increase number as it will always get rounded down.

jni- extract pixels with bitmap.h and store them in 3D array not working

I wanna pass a bitmap to native, extract the pixels with the help of bitmap.h, than store the pixels in 3D array( x and y and color channel), do some processing on the array by calling other c functions, when done, I write back the array to pixels of bitmap. The problem is: I can extract the pixels but I can't store them in an array. also If you can tell me how to write back array to bitmap's pixels.
My c code is:
#include <jni.h>
#include <time.h>
#include <android/log.h>
#include <android/bitmap.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define LOG_TAG "libimageprocessing"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
static void process(AndroidBitmapInfo* info, void* pixels){
int xx, yy, red, green, blue;
int w = info->width;
int h = info->height;
uint32_t* line;
int rgb[h][w][3];
for(yy = 0; yy < info->height; yy++){
line = (uint32_t*)pixels;
for(xx =0; xx < info->width; xx++){
red = (int) ((line[xx] & 0x00FF0000) >> 16);
green = (int)((line[xx] & 0x0000FF00) >> 8);
blue = (int) (line[xx] & 0x00000FF );
red = 255 - red;
green = 255 - green;
blue = 255 - blue ;
rgb[yy][xx][0] = red; ////THIS LINE CAUSES THE CRASH, If removed the app returns the inverted image. I WANT TO IMPLEMENT SUCH THING, THEN I DON'T KNOW HOW TO WRITE IT BACK TO BITMAP PIXELS.
line[xx] =
((red << 16) & 0x00FF0000) |
((green << 8) & 0x0000FF00) |
(blue & 0x000000FF);
}
pixels = (char*)pixels + info->stride;
}
}
JNIEXPORT void JNICALL Java_com_example_ibm_MainActivity_process(JNIEnv* env, jobject obj, jobject bitmap)
{
AndroidBitmapInfo info;
int ret;
void* pixels;
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
LOGE("Bitmap format is not RGBA_8888 !");
return;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
}
process(&info,pixels);
AndroidBitmap_unlockPixels(env, bitmap);
}

How to draw picture in GUI window using it's pixel values in c?

I want to read bmp image and draw the pixel values in GUI window but it is
not giving me the correct result,the picture it is showing is completely different then the original image I don't know where I am going wrong.
any help?
int main() {
char filename[100];
printf("Enter the bitmap image name:");
scanf("%s",filename);
int i;
FILE* f = fopen(filename, "rb");
if(f == NULL)
throw "Argument Exception";
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int gdriver = DETECT, gmode;
initgraph (&gdriver, &gmode,"");
cout << " Name: " << filename << endl;
cout << " Width: " << width << endl;
cout << "Height: " << height << endl;
int row_padded = (width*3 + 3) & (~3);
unsigned char* data = new unsigned char[row_padded];
unsigned char tmp;
for(int i = 0; i < height; i++)
{
fread(data, sizeof(unsigned char), row_padded, f);
for(int j = 0; j < width; j += 3)
{
// Convert (B, G, R) to (R, G, B)
tmp = data[j];
data[j] = data[j+2];
data[j+2] = tmp;
int last=width*height;
int index=last;
cout << "R: "<< (int)data[j] << " G: " << (int)data[j+1]<< " B: " << (int)data[j+2]<< endl;
cout <<((data[j] & 0xff) << 16) + ((data[j+1] & 0xff) << 8) + (data[j+2] & 0xff);
cout<<"number of time" <<i;
unsigned long rgb = 0xFA09CA;
rgb =((data[j] & 0xff) << 16) + ((data[j+1] & 0xff) << 8) + (data[j+2] & 0xff);
putpixel(j,i,data[j]);
putpixel(j,i,data[j+1]);
putpixel(j,i,data[j+1]);
}
}
getch();
}
putpixel(j,i,data[j]);
putpixel(j,i,data[j+1]);
putpixel(j,i,data[j+1]);
You are very insistent that the pixel at [j][i] be changed, so much, that you are writing to the same pixel location 3 times.
Is there a pixel stream, where by each write puts the pixel into a queue or stream (like the SPI bus interface)?
The last line doesn't look correct either. I believe it should be data[j+2], but I dunno.
There may be other issues, but I can't use my debugger on your code.
This code seems to be using the BGI library from Borland to draw graphics under MS DOS. You have, in fact, specified to autodetect your graphics card, which will initialize it into VGA 16 paletized colors and planar mode (unless you are using an EGA card or older).
Later, you are reading what it seems to be a 24-bit color image from the BMP and putpixeling as if BGI would support 24 bits (which does not).
So your program needs a massive rewritting:
Init graphics and check result values to see what graphics mode the computer is.
Open BMP, read its properties and reject it if it doesn't fit your screen in the current graphics mode, or if it isn't a palettized image, or if the number of colors (palette entries) is greater than your graphics mode supports.
Read palette from BMP, adjust it to be 6 bits per primary color and update palette registers
Read pixels from BMP, and putpixel them, taking into account that BMP pictures are stored upside down
This is just for a basic display program. A more general solution would require you to add code to either resize of pan the image to display it in your screen. Besides, you would have to check if the picture is in true color format and if so, perform some dithering to reduce the number of colors to the maximum available in your graphics mode, and then assign a palette entry to each of them.
Consider, for example, this simple program to display RAW image files. The RAW file is assumed to be 640x480 pixels, and each pixel to have 3 bytes corresponding to its level of red, green and blue, in this order. The picture needs to be color downgraded previously, to have up to 16 different colors. The program reads pixels and assign its colors to palette index. If a new pixel is already present in the palette, its index is used in putpixel. If not, its color is added to the palette, the hardware palette is updated, and the new index is used in putpixel.
#include <conio.h>
#include <graphics.h>
#include <stdio.h>
#include <dos.h>
typedef struct
{
unsigned char r;
unsigned char g;
unsigned char b;
} RGB;
void setvgapalette (int entry, RGB *val);
int main()
{
int gdriver = VGA;
int gmodo = VGAHI;
RGB palette[16];
int indxp = 0;
FILE *f;
RGB pixel;
int x, y, i;
initgraph (&gdriver, &gmodo, "c:\\comp\\tc\\bgi");
f = fopen ("PICTURE.RAW", "rb");
fread (&pixel.r, 1, 1, f); //
fread (&pixel.g, 1, 1, f); // Read one pixel (first one)
fread (&pixel.b, 1, 1, f); //
x = 0;
y = 0;
while (!feof(f))
{
for (i=0;i<indxp;i++) // search pixel color in current palette
{
if (palette[i].r == pixel.r &&
palette[i].g == pixel.g &&
palette[i].b == pixel.b)
break; // if found, finish search
}
if (i==indxp) // if not found, add its color to the palette
{
palette[i] = pixel;
setvgapalette (i, &pixel);
indxp++;
}
putpixel (x, y, i); // put pixel with color from palette index
// Update coordinates for next pixel and exit if screen full
x++;
if (x==640)
{
x = 0;
y++;
if (y==480)
break;
}
fread (&pixel.r, 1, 1, f); //
fread (&pixel.g, 1, 1, f); // Read next pixel
fread (&pixel.b, 1, 1, f); //
}
fclose (f);
getch();
closegraph();
return 0;
}
void setvgapalette (int entry, RGB *val)
{
outp (0x3c8, entry); // palette entry to write to
outp (0x3c9, val->r/4); // 6 MSb of R
outp (0x3c9, val->g/4); // 6 MSb of G
outp (0x3c9, val->b/4); // 6 MSb of B
}
Use following getcol function to get correct color.
In your putpixel function replace data[i] by getcol(data[i]).
Color code for EGAVGA and bitmap are different.
int getcol(int col)
{
switch(col)
{
case 0: return 0; //BLACK;
case 1: return 4; //RED;
case 2: return 2; //GREEN
case 3: return 6; //BROWN
case 4: return 1; //BLUE;
case 5: return 5; //MAGENTA;
case 6: return 3; //CYAN;
case 7: return 7; //LIGHTGRAY;
case 8: return 8; //DARKGRAY;
case 9: return 12; //LIGHTRED;
case 10:return 10; //LIGHTGREEN
case 11:return 14; //YELLOW;
case 12:return 9; //LIGHTBLUE;
case 13:return 13; //LIGHTMAGENTA
case 14:return 11; //LIGHTCYAN;
case 15:return 15; //WHITE;
}
return col;
}

Writing images with an Arduino

I have an SD card, SD card shield, and Arduino Uno R3. I need to write an image onto the SD card. I would much rather prefer going from a raw array to JPEG/PNG/BMP/etc, rather than using the formats that are easy to write, but not really openable (PPM, PGM, etc).
Is the image writing function included in the Arduino standard libraries? If not, what library should I use? I've looked at lodePNG, but ran into weird errors (vector is not a member of std).
I take zero credit for this code as I pulled it from a thread on the Arduino forums (http://forum.arduino.cc/index.php?topic=112733.0). It writes a .bmp file to an SD card.
Another discussion indicated that because of the compression algorithms associated with JPG and PNG files, the amount of code to make those work would be more difficult to fit on an Arduino, which makes sense in my head (http://forum.arduino.cc/index.php?topic=76376.0).
Hope this helps. Definitely not an expert with Arduino - just tinkered a bit.
#include <SdFat.h>
#include <SdFatUtil.h>
/*
WRITE BMP TO SD CARD
Jeff Thompson
Summer 2012
TO USE MEGA:
The SdFat library must be edited slightly to use a Mega - in line 87
of SdFatConfig.h, change to:
#define MEGA_SOFT_SPI 1
(this uses pins 10-13 for writing to the card)
Writes pixel data to an SD card, saved as a BMP file. Lots of code
via the following...
BMP header and pixel format:
http://stackoverflow.com/a/2654860
SD save:
http://arduino.cc/forum/index.php?topic=112733 (lots of thanks!)
... and the SdFat example files too
www.jeffreythompson.org
*/
char name[] = "9px_0000.bmp"; // filename convention (will auto-increment)
const int w = 16; // image width in pixels
const int h = 9; // " height
const boolean debugPrint = true; // print details of process over serial?
const int imgSize = w*h;
int px[w*h]; // actual pixel data (grayscale - added programatically below)
SdFat sd;
SdFile file;
const uint8_t cardPin = 8; // pin that the SD is connected to (d8 for SparkFun MicroSD shield)
void setup() {
// iteratively create pixel data
int increment = 256/(w*h); // divide color range (0-255) by total # of px
for (int i=0; i<imgSize; i++) {
px[i] = i * increment; // creates a gradient across pixels for testing
}
// SD setup
Serial.begin(9600);
if (!sd.init(SPI_FULL_SPEED, cardPin)) {
sd.initErrorHalt();
Serial.println("---");
}
// if name exists, create new filename
for (int i=0; i<10000; i++) {
name[4] = (i/1000)%10 + '0'; // thousands place
name[5] = (i/100)%10 + '0'; // hundreds
name[6] = (i/10)%10 + '0'; // tens
name[7] = i%10 + '0'; // ones
if (file.open(name, O_CREAT | O_EXCL | O_WRITE)) {
break;
}
}
// set fileSize (used in bmp header)
int rowSize = 4 * ((3*w + 3)/4); // how many bytes in the row (used to create padding)
int fileSize = 54 + h*rowSize; // headers (54 bytes) + pixel data
// create image data; heavily modified version via:
// http://stackoverflow.com/a/2654860
unsigned char *img = NULL; // image data
if (img) { // if there's already data in the array, clear it
free(img);
}
img = (unsigned char *)malloc(3*imgSize);
for (int y=0; y<h; y++) {
for (int x=0; x<w; x++) {
int colorVal = px[y*w + x]; // classic formula for px listed in line
img[(y*w + x)*3+0] = (unsigned char)(colorVal); // R
img[(y*w + x)*3+1] = (unsigned char)(colorVal); // G
img[(y*w + x)*3+2] = (unsigned char)(colorVal); // B
// padding (the 4th byte) will be added later as needed...
}
}
// print px and img data for debugging
if (debugPrint) {
Serial.print("\nWriting \"");
Serial.print(name);
Serial.print("\" to file...\n");
for (int i=0; i<imgSize; i++) {
Serial.print(px[i]);
Serial.print(" ");
}
}
// create padding (based on the number of pixels in a row
unsigned char bmpPad[rowSize - 3*w];
for (int i=0; i<sizeof(bmpPad); i++) { // fill with 0s
bmpPad[i] = 0;
}
// create file headers (also taken from StackOverflow example)
unsigned char bmpFileHeader[14] = { // file header (always starts with BM!)
'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };
unsigned char bmpInfoHeader[40] = { // info about the file (size, etc)
40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0 };
bmpFileHeader[ 2] = (unsigned char)(fileSize );
bmpFileHeader[ 3] = (unsigned char)(fileSize >> 8);
bmpFileHeader[ 4] = (unsigned char)(fileSize >> 16);
bmpFileHeader[ 5] = (unsigned char)(fileSize >> 24);
bmpInfoHeader[ 4] = (unsigned char)( w );
bmpInfoHeader[ 5] = (unsigned char)( w >> 8);
bmpInfoHeader[ 6] = (unsigned char)( w >> 16);
bmpInfoHeader[ 7] = (unsigned char)( w >> 24);
bmpInfoHeader[ 8] = (unsigned char)( h );
bmpInfoHeader[ 9] = (unsigned char)( h >> 8);
bmpInfoHeader[10] = (unsigned char)( h >> 16);
bmpInfoHeader[11] = (unsigned char)( h >> 24);
// write the file (thanks forum!)
file.write(bmpFileHeader, sizeof(bmpFileHeader)); // write file header
file.write(bmpInfoHeader, sizeof(bmpInfoHeader)); // " info header
for (int i=0; i<h; i++) { // iterate image array
file.write(img+(w*(h-i-1)*3), 3*w); // write px data
file.write(bmpPad, (4-(w*3)%4)%4); // and padding as needed
}
file.close(); // close file when done writing
if (debugPrint) {
Serial.print("\n\n---\n");
}
}
void loop() { }

Resources