generate monochrome bitmap image using c - c

I am writing code to generate monochrome bmp image out of array. there are plenty of tools to generate bmp to array but i want it in reverse way. i found lots of code but it was color image.
here is code i am trying...
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#define _height 64
#define _width 128
#define _bitsperpixel 1
#define _planes 1
#define _compression 0
#define _pixelbytesize _height*_width*_bitsperpixel/8
#define _filesize _pixelbytesize+sizeof(bitmap)
#define _xpixelpermeter 0x130B //2835 , 72 DPI
#define _ypixelpermeter 0x130B //2835 , 72 DPI
#define pixel 0x55
#pragma pack(push,1)
unsigned char arr[8192]={0};
typedef struct{
uint8_t signature[2];
uint32_t filesize;
uint32_t reserved;
uint32_t fileoffset_to_pixelarray;
} fileheader;
typedef struct{
uint32_t dibheadersize;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bitsperpixel;
uint32_t compression;
uint32_t imagesize;
uint32_t ypixelpermeter;
uint32_t xpixelpermeter;
uint32_t numcolorspallette;
uint32_t mostimpcolor;
} bitmapinfoheader;
typedef struct {
fileheader fileheader;
bitmapinfoheader bitmapinfoheader;
} bitmap;
#pragma pack(pop)
int main (int argc , char *argv[]) {
int i;
FILE *fp = fopen("test.bmp","wb");
bitmap *pbitmap = (bitmap*)calloc(1,sizeof(bitmap));
uint8_t *pixelbuffer = (uint8_t*)malloc(_pixelbytesize);
strcpy(pbitmap->fileheader.signature,"BM");
pbitmap->fileheader.filesize = _filesize;
pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap);
pbitmap->bitmapinfoheader.dibheadersize =sizeof(bitmapinfoheader);
pbitmap->bitmapinfoheader.width = _width;
pbitmap->bitmapinfoheader.height = _height;
pbitmap->bitmapinfoheader.planes = _planes;
pbitmap->bitmapinfoheader.bitsperpixel = _bitsperpixel;
pbitmap->bitmapinfoheader.compression = _compression;
pbitmap->bitmapinfoheader.imagesize = _pixelbytesize;
pbitmap->bitmapinfoheader.ypixelpermeter = _ypixelpermeter ;
pbitmap->bitmapinfoheader.xpixelpermeter = _xpixelpermeter ;
pbitmap->bitmapinfoheader.numcolorspallette = 0;
fwrite (pbitmap, 1, sizeof(bitmap),fp);
for(i=0;i<8192;i++)
{
pixelbuffer[i] = arr[i];
}
// memset(pixelbuffer,pixel,_pixelbytesize);
fwrite(pixelbuffer,1,_pixelbytesize,fp);
fclose(fp);
free(pbitmap);
free(pixelbuffer);
}
i am giving bits per pixel is 1 bit (i want either black or white), and not sure about other parameters which has to be change.
if i use _bitsperpixel as 24 then it is working properly but if i assign as 1 then getting it is getting crashed..

When _bitsperpixel == 1, then _pixelbytesize == 1024. Your loop runs till 8192, thus writing beyond the allocated memory.
Depending on what you store in your arr, you should either reduce the number of iterations of the loop to _pixelbytesize, or convert your bytes in arr into bits:
for(int i = 0; i < _pixelbytesize; ++i)
{
uint8_t b = 0;
for(int j = 0; j < 8; ++j)
b |= arr[8*i + j] >> 7 << j;
pixelbuffer[i] = b;
}
Note that this is a simple code that works only for image widths that are divisible by eight.

Related

Reading and Plotting BMP Image In C from Scratch

I am developing my own OS, with GNU-EFI, I am written a small BMP Image loader program.
I can Successfully read its headers and data ( not sure ) when I plot that on my Screen that is only showing blue color on pixels.
// Blue Pixels are Plotted BMP Image
How can I load this with Colours?
PlotPixel(x,y,color) Color takes Value as 0xFFFFFFFF;
Following is my bmp loader:
BMP.h
// bmp.h
#define WIN_BITMAP_SIGNATURE 0x4D42 // BM [ASCII]
#define BMP_HEADER_SIZE 54
#define DIB_HEADER_SIZE 40
#pragma pack(push, 1)
typedef struct
{
uint16_t bfType; // The characters "BM" - 2 Bytes
uint32_t bfSize; // The size of the file in bytes - 4 Bytes
uint16_t bfReserved1; // Unused - must be zero - 2 Bytes
uint16_t bfReserved2; // Unused - must be zero - 2 Bytes
uint32_t bfOffBits; // Offset to start of Pixel Data - 4 Bytes
uint32_t biSize; // DIB Header Size - 4 Bytes
int32_t biWidth; // Width - 4 Bytes
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPexelsPerMeter;
int32_t biYPexelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
} BITMAP_HEADER;
typedef struct
{
BITMAP_HEADER* header;
uint8_t* data;
} BITMAP_IMG;
typedef struct
{
uint32_t red_mask;
uint32_t green_mask;
uint32_t blue_mask;
uint32_t alpha_mask;
uint32_t color_space_type;
uint32_t unused[16];
} BMPColorHeader;
#pragma pack(pop)
unsigned long createRGBA(int r, int g, int b, int a);
unsigned long createRGB(int r, int g, int b);
BITMAP_IMG* LoadBMPImage(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable);
BMP.c
// bmp.c
#include "bmp.h"
unsigned long createRGB(int r, int g, int b)
{
return ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff);
}
unsigned long createRGBA(int r, int g, int b, int a)
{
return ((r & 0xff) << 24) + ((g & 0xff) << 16) + ((b & 0xff) << 8)
+ (a & 0xff);
}
BITMAP_IMG* LoadBMPImage(EFI_FILE* Directory, CHAR16* Path, EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable)
{
EFI_FILE* BMPImage = LoadFile(Directory, Path, ImageHandle, SystemTable);
if(BMPImage == NULL) return NULL;
BITMAP_HEADER* BMPImageHeader;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BITMAP_HEADER), (void**)&BMPImageHeader);
UINTN size = sizeof(BITMAP_HEADER);
BMPImage->Read(BMPImage, &size, BMPImageHeader);
// Verify Signature
if(BMPImageHeader->bfType != WIN_BITMAP_SIGNATURE)
{
// Signature not Matched
Print(L"Signature Not Matched!");
Print(L"BMP Type [ Signature ] : ", BMPImageHeader->bfType);
return NULL;
}
else
{
Print(L"Signature Found");
}
if(BMPImageHeader->biBitCount == 32)
{
Print(L"BMP 32 Bit");
BMPColorHeader* BmpColor;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BMPColorHeader), (void**)&BmpColor);
UINTN size = sizeof(BITMAP_HEADER);
BMPImage->Read(BMPImage, &size, BmpColor);
// Check Color Header
if(0x00ff0000 != BmpColor->red_mask || 0x000000ff != BmpColor->blue_mask || 0x0000ff00 != BmpColor->green_mask)
{
Print(L"Unexpected Color Format");
}
if(0x73524742 != BmpColor->color_space_type)
{
Print(L"Unexcepted Color Space Type : %d", BmpColor->color_space_type);
}
}
else
{
Print(L"BMP Not 32 Bit : %d", BMPImageHeader->biBitCount);
}
uint8_t* BMPData;
{
BMPImage->SetPosition(BMPImage, sizeof(BITMAP_HEADER));
SystemTable->BootServices->AllocatePool(EfiLoaderData, size, (void**)&BMPData);
BMPImage->Read(BMPImage, &size, BMPData);
}
BITMAP_IMG* finishedImage;
SystemTable->BootServices->AllocatePool(EfiLoaderData, sizeof(BITMAP_IMG), (void**)&finishedImage);
finishedImage->header = BMPImageHeader;
finishedImage->data = BMPData;
int offset = 0;
int channels = finishedImage->header->biBitCount / 8;
for (int i = 0; i < finishedImage->header->biHeight; i++)
{
for (int j = 0; j < finishedImage->header->biWidth; j++)
{
//// I thinks following are wrong
// Red
int red = finishedImage->data[offset] & 0xFF;
int green = finishedImage->data[offset+1] & 0xFF;
int blue = finishedImage->data[offset+2] & 0xFF;
int alpha = 0x00;
// I thinks CreateRGBA can be also wrong
int hex_calculated = createRGBA(red, green, blue, alpha);
// This function is surely right ; It takes color value as 0xFFFFFFFF
PlotPixel(120+i, 120+j, hex_calculated);
offset += 3;
}
}
return finishedImage;
}

How to turn an argb pixel array into an SDL surface?

Using C and SDL2, I have a pixel array with an ARGB8888 format.
Uint32 *pixels = (Uint32 *) malloc (sizeof(Uint32)*(Uint32)windowWidth*(Uint32)windowHeight);
I want to put all that pixel information into a new SDL_Surface ready to save as a .bmp. How do I do this?
I'm unsure because new surfaces have RGBA8888 format and sdl convert functions require an existing surface to convert to a new surface. And there is no function which simply passes all pixel array values to a surface, so I know it will involve some sort of loop which assigns the pixels one by one.
You can manually save bitmap bits to a file. Bitmap files are usually 24bit or less, and bitmap viewers tend to ignore alpha. The code below assumes bits is 32-bit pixels. If you need 24-bit format, the input has to be converted from ARGB to RGB, and you must also account for padding.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#pragma pack(push, 1)
typedef struct my_BITMAPFILEHEADER {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
}my_BITMAPFILEHEADER;
typedef struct my_BITMAPINFOHEADER {
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
}my_BITMAPINFOHEADER;
#pragma pack(pop)
int copy(uint8_t* bits, int width, int height, int bitcount)
{
//compiler test:
if(sizeof(my_BITMAPFILEHEADER) != 14 && sizeof(my_BITMAPINFOHEADER) != 40)
{
printf("bitmap structures not packed properly\n");
return 0;
}
//width_in_bytes is roughly w * bytes_per_pixel, it takes padding in to account
int width_in_bytes = ((width * bitcount + 31) / 32) * 4;
uint32_t imagesize = width_in_bytes * height;
my_BITMAPFILEHEADER filehdr = { 0 };
my_BITMAPINFOHEADER infohdr = { 0 };
memcpy(&filehdr, "BM", 2);
filehdr.bfSize = 54 + imagesize;
filehdr.bfOffBits = 54;
infohdr.biSize = 40;
infohdr.biPlanes = 1;
infohdr.biWidth = width;
infohdr.biHeight = height;
infohdr.biBitCount = bitcount;
infohdr.biSizeImage = imagesize;
FILE *fout = fopen("test.bmp", "wb");
fwrite(&filehdr, sizeof(filehdr), 1, fout);
fwrite(&infohdr, sizeof(infohdr), 1, fout);
fwrite((char*)bits, 1, imagesize, fout);
fclose(fout);
return 1;
}
Usage:
copy(bits, width, height, 32);
//or
copy(bits, width, height, 24);

Bit field memory usage in C

Why does it return with 96 and not 64?
If I sum bit of bit field I will get 64.
Edited:
The var variable has 0xFFFFFF and not 0xFFFFFFFF. -> The var variable has 0x3FFFFFFF00FFFFFF and not 0xFFFFFFFFFFFFFFFF.*
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct{
uint32_t a : 24;
uint32_t b : 20;
uint32_t c : 10;
uint32_t d : 6;
uint32_t e : 4;
}MyType_t;
int main(){
MyType_t test;
test.a = -1;
test.b = -1;
test.c = -1;
test.d = -1;
test.e = -1;
uint64_t var = *((uint64_t*)&test);
printf("MyType_t: %d bit\n", sizeof(MyType_t) * 8);//96 bit
printf("Var: %#llX\n", var);//0x3FFFFFFF00FFFFFF
return 0;
}
This code will be worked correctly:
typedef struct{
uint32_t a : 16;
uint32_t b : 16;
uint32_t c : 16;
uint32_t d : 8;
uint32_t e : 8;
}MyType_t;
The fields a and b cannot possibly fit into a single type of uint32_t:
typedef struct{
uint32_t a : 24; //first 32 bits
uint32_t b : 20; //second 32 bits
uint32_t c : 10; //
uint32_t d : 6; //third 32 bits
uint32_t e : 4; //
}MyType_t;
so the size of the struct is three times the size of uint32_t.
The behavior of the code uint64_t var = *((uint64_t*)&test); is not defined.

multi-precision multiplication in CUDA

I am trying to implement multi-precision multiplication in CUDA. For doing that, I have implemented a kernel which should compute multiplication of uint32_t type operand with 256-bit operand and put the result in 288-bit array. So far, I have came up with this code:
__device__ __constant__ UN_256fe B_const;
__global__ void multiply32x256Kernel(uint32_t A, UN_288bite* result){
uint8_t tid = blockIdx.x * blockDim.x + threadIdx.x;
//for managing warps
//uint8_t laineid = tid % 32;
//allocate partial products into array of uint64_t
__shared__ uint64_t partialMuls[8];
uint32_t carry, r;
if((tid < 8) && (tid != 0)){
//compute partial products
partialMuls[tid] = A * B_const.uint32[tid];
//add partial products and propagate carry
result->uint32[8] = (uint32_t)partialMuls[7];
r = (partialMuls[tid] >> 32) + ((uint32_t)partialMuls[tid - 1]);
carry = r < (partialMuls[tid] >> 32);
result->uint32[0] = (partialMuls[0] >> 32);
while(__any(carry)){
r = r + carry;
//new carry?
carry = r < carry;
}
result->uint32[tid] = r;
}
and my data-type is :
typedef struct UN_256fe{
uint32_t uint32[8];
}UN_256fe;
typedef struct UN_288bite{
uint32_t uint32[9];
}UN_288bite;
My kernel works, but it gives me wrong result. I cannot debug inside the kernel, so I would appreciate if someone let me know where the problem is or how I can debug my code inside the kernel on tegra-ubuntu with cuda-6.0.
Thanks
This answer has nothing to do with CUDA itself, but is a general C implementation.
I can't quite follow what you are doing (especially with carry) but you could try this snippet based on my own big num functions. I defined dtype to make it easier to test with smaller fields. Note that I don't specifically use a carry, but carry forward the partial product.
// little-endian
#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#define dtype uint8_t // for testing
//#define dtype uint32_t // for proper ver
#define SHIFTS (sizeof(dtype)*CHAR_BIT)
#define NIBBLES (SHIFTS/4)
#define ARRLEN 8
typedef struct UN_256fe {
dtype uint[ARRLEN];
} UN_256fe;
typedef struct UN_288bite {
dtype uint[ARRLEN+1];
} UN_288bite;
void multiply(UN_288bite *product, UN_256fe *operand, dtype multiplier)
{
int i;
uint64_t partial = 0;
for (i=0; i<ARRLEN; i++) {
partial = partial + (uint64_t)multiplier * operand->uint[i];
product->uint[i] = (dtype)partial;
partial >>= SHIFTS; // carry
}
product->uint[i] = (dtype)partial;
}
int main(void)
{
int i;
dtype multiplier = 0xAA;
UN_256fe operand = { 1, 2, 3, 4, 5, 6, 7, 8};
UN_288bite product;
multiply(&product, &operand, multiplier);
for(i=ARRLEN-1; i>=0; i--)
printf("%0*X", NIBBLES, operand.uint[i]);
printf("\n * %0*X = \n", NIBBLES, multiplier);
for(i=ARRLEN; i>=0; i--)
printf("%0*X", NIBBLES, product.uint[i]);
printf("\n");
return 0;
}
Program output for uint8_t
0807060504030201
* AA =
0554A9FF54A9FF54AA

Creating a BMP file (bitmap) in C

I'm trying to make a bitmap in C, just from code. I'm currently trying to make a very easy .bmp image, with a height of 1px and a width of 4 pixels, with all white pixels. I have read the format description and tried to apply it. This resulted in the following code:
char bitmap[1000];
void BMPmake()
{
// -- FILE HEADER -- //
// bitmap signature
bitmap[0] = 'B';
bitmap[1] = 'M';
// file size
bitmap[2] = 66; // 40 + 14 + 12
bitmap[3] = 0;
bitmap[4] = 0;
bitmap[5] = 0;
// reserved field (in hex. 00 00 00 00)
for(int i = 6; i < 10; i++) bitmap[i] = 0;
// offset of pixel data inside the image
for(int i = 10; i < 14; i++) bitmap[i] = 0;
// -- BITMAP HEADER -- //
// header size
bitmap[14] = 40;
for(int i = 15; i < 18; i++) bitmap[i] = 0;
// width of the image
bitmap[18] = 4;
for(int i = 19; i < 22; i++) bitmap[i] = 0;
// height of the image
bitmap[22] = 1;
for(int i = 23; i < 26; i++) bitmap[i] = 0;
// reserved field
bitmap[26] = 1;
bitmap[27] = 0;
// number of bits per pixel
bitmap[28] = 24; // 3 byte
bitmap[29] = 0;
// compression method (no compression here)
for(int i = 30; i < 34; i++) bitmap[i] = 0;
// size of pixel data
bitmap[34] = 12; // 12 bits => 4 pixels
bitmap[35] = 0;
bitmap[36] = 0;
bitmap[37] = 0;
// horizontal resolution of the image - pixels per meter (2835)
bitmap[38] = 0;
bitmap[39] = 0;
bitmap[40] = 0b00110000;
bitmap[41] = 0b10110001;
// vertical resolution of the image - pixels per meter (2835)
bitmap[42] = 0;
bitmap[43] = 0;
bitmap[44] = 0b00110000;
bitmap[45] = 0b10110001;
// color pallette information
for(int i = 46; i < 50; i++) bitmap[i] = 0;
// number of important colors
for(int i = 50; i < 54; i++) bitmap[i] = 0;
// -- PIXEL DATA -- //
for(int i = 54; i < 66; i++) bitmap[i] = 0;
}
void BMPwrite()
{
FILE *file;
file = fopen("bitmap.bmp", "w+");
for(int i = 0; i < 66; i++)
{
fputc(bitmap[i], file);
}
fclose(file);
}
When I try to open this image, it says that the image is damaged. Am I missing something here?
I also noticed that the encoding of the .bmp integers is little endian. I thought that this mean that I have to reverse the order of the bytes. For example, 256 in four bytes is: 00000000 00000000 00000001 00000000, and I think in little endian this would be: 00000000 00000001 00000000 00000000
Can anyone give me a hand here? Am I using a right approach? Any help would be appreciated!
Thanks in advance!
Your pixel offset (bytes 10..13) is zero, but the pixel data don't actually start at the beginning of the file, they start at byte 54.
Also:
Your comment on byte 34 says "bits" but means "bytes", but of course that doesn't matter.
Your horizontal and vertical resolutions have the wrong byte order, but I very much doubt that that matters.
If I were doing this I'd define structs for the header data (indeed, if you're on Windows, Microsoft have already done this) and use a macro or something for putting bytes into the right order portably.
Whether you "have to reverse the order of the bytes" depends on the endianity of the processor you're using. Writing separate bytes separately, as you're doing, is an effective way to avoid having to worry about this.
Here is the code tested on linux.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#define _height 600
#define _width 800
#define _bitsperpixel 24
#define _planes 1
#define _compression 0
#define _pixelbytesize _height*_width*_bitsperpixel/8
#define _filesize _pixelbytesize+sizeof(bitmap)
#define _xpixelpermeter 0x130B //2835 , 72 DPI
#define _ypixelpermeter 0x130B //2835 , 72 DPI
#define pixel 0xFF
#pragma pack(push,1)
typedef struct{
uint8_t signature[2];
uint32_t filesize;
uint32_t reserved;
uint32_t fileoffset_to_pixelarray;
} fileheader;
typedef struct{
uint32_t dibheadersize;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bitsperpixel;
uint32_t compression;
uint32_t imagesize;
uint32_t ypixelpermeter;
uint32_t xpixelpermeter;
uint32_t numcolorspallette;
uint32_t mostimpcolor;
} bitmapinfoheader;
typedef struct {
fileheader fileheader;
bitmapinfoheader bitmapinfoheader;
} bitmap;
#pragma pack(pop)
int main (int argc , char *argv[]) {
FILE *fp = fopen("test.bmp","wb");
bitmap *pbitmap = (bitmap*)calloc(1,sizeof(bitmap));
uint8_t *pixelbuffer = (uint8_t*)malloc(_pixelbytesize);
strcpy(pbitmap->fileheader.signature,"BM");
pbitmap->fileheader.filesize = _filesize;
pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap);
pbitmap->bitmapinfoheader.dibheadersize =sizeof(bitmapinfoheader);
pbitmap->bitmapinfoheader.width = _width;
pbitmap->bitmapinfoheader.height = _height;
pbitmap->bitmapinfoheader.planes = _planes;
pbitmap->bitmapinfoheader.bitsperpixel = _bitsperpixel;
pbitmap->bitmapinfoheader.compression = _compression;
pbitmap->bitmapinfoheader.imagesize = _pixelbytesize;
pbitmap->bitmapinfoheader.ypixelpermeter = _ypixelpermeter ;
pbitmap->bitmapinfoheader.xpixelpermeter = _xpixelpermeter ;
pbitmap->bitmapinfoheader.numcolorspallette = 0;
fwrite (pbitmap, 1, sizeof(bitmap),fp);
memset(pixelbuffer,pixel,_pixelbytesize);
fwrite(pixelbuffer,1,_pixelbytesize,fp);
fclose(fp);
free(pbitmap);
free(pixelbuffer);
}
Open your file with a hex editor to see what is actually there. This will help you determine if your code is doing something unexpected.

Resources