Add imagedata to Bitmap in raw bytes - c

I am trying to add imagedata to an existing bitmap.
The existing bitmap is stored in an byte array:
That's how the image looks like:
If I want to add, let's say 2 lines of blue to the bottom, how could I do that?
#include <Windows.h>
const char tred[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC8,0xD1,0xF8,0x95,0xA7,0xF4,0x65,0x80,0xED,0xB0,0xBC,0xF6,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xD0,0xD7,0xFA,0x48,0x68,0xEB,0x01,0x2E,0xE2,0x06,0x30,0xE4,
0x12,0x3A,0xE4,0x0D,0x36,0xE5,0x71,0x8A,0xEF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF4,
0xF6,0xFD,0x35,0x58,0xE9,0x00,0x2B,0xE3,0x19,0x40,0xE6,0x21,0x46,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xAD,0xBA,0xF6,0x00,0x27,0xE3,0x1A,0x41,0xE6,0x21,0x47,0xE7,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x94,0xA6,0xF2,0x00,0x28,0xE3,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xC6,0xF7,0x00,0x27,0xE2,0x22,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0x00,0x2C,0xE3,0x20,0x46,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0x67,0x82,0xEE,0x13,0x3C,0xE5,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,
0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x2C,0xE3,0x20,0x46,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xC3,0xCD,0xF8,0x07,0x31,
0xE4,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0x8B,0x9F,0xF1,0x13,0x3B,0xE5,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,
0x00,0x00,0x78,0x90,0xF0,0x17,0x3E,0xE5,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0x79,0x8F,0xF0,0x17,0x3E,0xE5,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,
0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0x8E,0xA2,0xF2,0x12,0x3A,0xE5,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xC9,
0xD1,0xF9,0x05,0x30,0xE4,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0x04,0x2F,0xE3,0x20,0x46,0xE6,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,
0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0x75,0x8C,0xEF,0x11,0x3A,0xE5,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0x05,0x2F,0xE3,0x20,0x46,0xE6,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xD0,0xD7,0xF9,0x00,0x25,0xE3,0x21,0x47,
0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,
0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xAE,0xBC,0xF6,0x00,0x26,0xE3,0x20,0x46,0xE6,0x21,0x47,0xE7,0x21,0x47,0xE7,
0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xC8,0xD1,0xF8,0x02,0x2D,0xE3,0x15,0x3D,0xE6,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,0x47,0xE7,0x21,
0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFE,0x51,0x6F,0xEB,0x00,0x27,0xE3,0x16,0x3D,0xE6,0x1F,0x46,0xE6,0x22,0x47,0xE7,0x21,0x47,0xE7,0x17,0x3E,0xE6,0x78,0x90,0xF0,0x00,0x00,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xEF,0xFC,0x65,0x7E,0xEE,
0x0C,0x36,0xE3,0x00,0x2A,0xE3,0x0D,0x36,0xE4,0x0A,0x34,0xE4,0x70,0x89,0xEF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE4,0xE8,0xFC,0xAE,0xBC,0xF6,0x7E,
0x94,0xF0,0xBD,0xC7,0xF7,0x00,0x00 };
int main(int argc, char* argv[]) {
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);;
bmih.biWidth = 14;
bmih.biHeight = 96;
bmih.biPlanes = 1;
bmih.biBitCount = 24;
bmih.biCompression = 0;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
bmfh.bfType = 19778;
bmfh.bfSize = ((bmih.biWidth * bmih.biBitCount + 31) / 32) * 4 * bmih.biHeight;
bmfh.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); // 54
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
char* bmpData = (char*)malloc(bmfh.bfSize);
memcpy(bmpData, tred, sizeof(tred));
HANDLE h = CreateFile("C:\\tmp\\a.bmp", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
DWORD d;
WriteFile(h, &bmfh, sizeof(bmfh), &d, 0);
WriteFile(h, &bmih, sizeof(bmih), &d, 0);
WriteFile(h, bmpData, bmfh.bfSize, &d, 0);
CloseHandle(h);
delete[] bmpData;
return 0;
}
What I do not understand: Original file is 14px*24px = 366px in total. In a 24bit Bitmap, there is RGB (3 Bytes) for each pixel, so that would be 366*3=1008bytes. The original file (without header) has 1056bytes.
Maybe that's the reason why my approach, by adding 14*3=42bytes of 0xFF did not add an extra line?

Related

PNG file are truncated and cannot be shown by every application

I have a code that produce PNG file (using libpng).
I can open these files with EOG (Eye Of Gnome) but with GIMP, imagemagic and others I have an error.
Exiftool tells me that png file is truncated, but I don't see where. On EOG everything is ok.
The code:
int savepng(const char *name, fits *fit, uint32_t bytes_per_sample,
gboolean is_colour) {
int32_t ret = -1;
png_structp png_ptr;
png_infop info_ptr;
const uint32_t width = fit->rx;
const uint32_t height = fit->ry;
char *filename = strdup(name);
if (!ends_with(filename, ".png")) {
filename = str_append(&filename, ".png");
}
FILE *p_png_file = g_fopen(name, "wb");
if (p_png_file == NULL) {
return ret;
}
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also check that
* the library version is compatible with the one used at compile time,
* in case we are using dynamically linked libraries. REQUIRED.
*/
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(p_png_file);
return ret;
}
/* Allocate/initialize the image information data. REQUIRED */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(p_png_file);
png_destroy_write_struct(&png_ptr, NULL);
return ret;
}
/* Set error handling. REQUIRED if you aren't supplying your own
* error handling functions in the png_create_write_struct() call.
*/
if (setjmp(png_jmpbuf(png_ptr))) {
/* If we get here, we had a problem writing the file */
fclose(p_png_file);
png_destroy_write_struct(&png_ptr, &info_ptr);
return ret;
}
/* Set up the output control if you are using standard C streams */
png_init_io(png_ptr, p_png_file);
/* Set the image information here. Width and height are up to 2^31,
* bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
* the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
* PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
* or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
* PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
* currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
*/
if (is_colour) {
png_set_IHDR(png_ptr, info_ptr, width, height, bytes_per_sample * 8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_DEFAULT);
uint32_t profile_len;
const unsigned char *profile = get_sRGB_profile_data(&profile_len);
if (profile_len > 0) {
png_set_iCCP(png_ptr, info_ptr, *name ? name : "icc", 0, (png_const_bytep) profile, profile_len);
}
} else {
png_set_IHDR(png_ptr, info_ptr, width, height, bytes_per_sample * 8,
PNG_COLOR_TYPE_GRAY,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_DEFAULT);
}
/* Write the file header information. REQUIRED */
png_write_info(png_ptr, info_ptr);
png_bytep *row_pointers = malloc((size_t) height * sizeof(png_bytep));
int samples_per_pixel;
if (is_colour) {
samples_per_pixel = 3;
} else {
samples_per_pixel = 1;
}
if (bytes_per_sample == 2) {
/* swap bytes of 16 bit files to most significant bit first */
png_set_swap(png_ptr);
WORD *data = convert_data(fit);
for (unsigned i = 0, j = height - 1; i < height; i++)
row_pointers[j--] = (png_bytep) ((uint16_t*) data + (size_t) samples_per_pixel * i * width);
} else {
uint8_t *data = convert_data8(fit);
for (unsigned i = 0, j = height - 1; i < height; i++)
row_pointers[j--] = (uint8_t*) data + (size_t) samples_per_pixel * i * width;
}
png_write_image(png_ptr, row_pointers);
/* Clean up after the write, and free any memory allocated */
png_destroy_write_struct(&png_ptr, &info_ptr);
/* Close the file */
fclose(p_png_file);
free(row_pointers);
free(filename);
return 0;
}
Could someone point me out my error? Software that can't read the image just display an error dialog. That's all. So it is difficult for me to know where is the error.
As proposed by #MarkSetchell, one line was missing:
/* Clean up after the write, and free any memory allocated */
png_write_end(png_ptr, info_ptr); // this line was missing
png_destroy_write_struct(&png_ptr, &info_ptr);
That's all.
Thank you.
I think that png_write_image() only writes the image row data, so various headers or elements of meta-data are missing. I normally use png_write_png() to write the whole file.
I've attached some code that definitely works for me, in that the output can be read by Gimp, etc. I don't claim it's production-quality ;)
int bitmap_write_png (const bitmap_t *bitmap, const char *path)
{
int ret = -1;
size_t x, y;
int pixel_size = 3;
int depth = 8;
FILE *fp = fopen (path, "wb");
if (fp)
{
ret = 0;
png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
png_infop info_ptr = info_ptr = png_create_info_struct (png_ptr);
png_set_IHDR (png_ptr,
info_ptr,
bitmap->width,
bitmap->height,
depth,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_byte ** row_pointers = png_malloc (png_ptr,
bitmap->height * sizeof (png_byte *));
for (y = 0; y < bitmap->height; y++)
{
png_byte *row =
png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width * pixel_size);
row_pointers[y] = row;
for (x = 0; x < bitmap->width; x++)
{
pixel_t *pixel = pixel_at_const (bitmap, x, y);
*row++ = pixel->red * 255;
*row++ = pixel->green * 255;
*row++ = pixel->blue * 255;
}
}
png_init_io (png_ptr, fp);
png_set_rows (png_ptr, info_ptr, row_pointers);
png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
for (y = 0; y < bitmap->height; y++)
{
png_free (png_ptr, row_pointers[y]);
}
png_free (png_ptr, row_pointers);
close (fp);
}
else
{
ret = errno;
}
return ret;
}

SZ_ERROR_DATA from LzmaDecode function (C lzma)

I have an array of numbers which i want to compress and store in a file then decompress and put data in a buffer.
RAM->FILE compressing
FILE->RAM decompressing
I used LzmaEncode for compressing and then write compress buffer in a file.
lzmaencoder.c
int main(void){
int data[] = {1,2,3,4,5};
size_t src_len = sizeof(data);
const Byte * src = (Byte *) data;
size_t compressed_size = src_len*1.5;
Byte * compressed_data = malloc(compressed_size);
CLzmaEncProps props;
LzmaEncProps_Init(&props);
Byte header[LZMA_PROPS_SIZE];
size_t headerSize = LZMA_PROPS_SIZE;
// Call encoding function:
SRes res;
res = LzmaEncode(compressed_data, &compressed_size, src, src_len,
&props, header, &headerSize, 0, NULL, &g_Alloc, &g_Alloc);
if(res == SZ_OK){
FILE * file = fopen("lzma_file","wb");
fwrite(compressed_data, sizeof(Byte), compressed_size, file);
}
free(compressed_data);
return (0);
}
I read compress file and write data in a buffer, then use LzmaDecode for decompressing.
lzmadecoder.c
int main(int argc, char * argv[]){
// I know the original data size
size_t uncompress_size = 20;
Byte * uncompress = malloc(uncompress_size);
// open compressed file
size_t compress_size;
FILE * compress_file = fopen("lzma_file", "rb");
if(!compress_file){
printf("Error: can not open lzma_file file.");
}
// get compressed file size
fseek(compress_file, 0, SEEK_END);
compress_size = ftell(compress_file);
fseek(compress_file, 0, SEEK_SET);
Byte *compress_data = malloc(compress_size);
// put compressed file data on RAM
if(!fread(compress_data, sizeof(Byte), compress_size, compress_file)){
printf("Error: can not read lzma_file file.");
}
fclose(compress_file);
ELzmaStatus status;
// RAM->RAM decompressing
int res = LzmaDecode(uncompress, &uncompress_size,
compress_data, &compress_size,
compress_data, 5,
LZMA_FINISH_END, &status, &g_Alloc);
if(res==SZ_OK){
printf("SZ_OK!\n");
} else if(res==SZ_ERROR_DATA){
printf("SZ_ERROR_DATA!\n");
}
free(uncompress);
free(compress_data);
return (0);
}
but LzmaDecode return SZ_ERROR_DATA. I cant find my problem.
LZMA compression---------------- Version: 9.35
Use the Lib API generated by the project "lzma1900\C\Util\LzmaLib": LzmaCompress and LzmaUncompress.
int main()
{
Byte outProps[5];
size_t outPropsSize = 5; /* *outPropsSize must be = 5 */
int r =RawEncode(out,&tmpLen,bnInfo, len1,outProps,&outPropsSize);
Pkt init =RawDecode(out2,$outLen2, out, tmpLen, &outPropsSize);
return 0;
}
int RawEncode(char* out, int *ol, char *buf, uint32_t l, char* outProps, size_t* outPropsSize)
{
int res = 0;
m_l = 8;
int level = m_level; /* 0 <= level <= 9, default = 5 */
unsigned dictSize = 1 << 24; /* default = (1 << 24) */
int lc = 3; /* 0 <= lc <= 8, default = 3 */
int lp = 0; /* 0 <= lp <= 4, default = 0 */
int pb = 2; /* 0 <= pb <= 4, default = 2 */
int fb = 32; /* 5 <= fb <= 273, default = 32 */
int numThreads = 1; /* 1 or 2, default = 2 */
int r = LzmaCompress(out,ol,buf,l,outProps, outPropsSize, m_level, dictSize, lc, lp, pb, fb, 1);
olen = l;
return r;
}
void RawDecode(char* out, int* oLen, char* buf, int len, unsigned char* props, size_t* propsSize)
{
char out[outLen];
SizeT srcLen = pkt.first.len - 8;
int r = LzmaUncompress(out, oLen, buf, &len, props, *propsSize);
if(SZ_OK != r)
{
printf("LzmaUncompress error %d.", r);
delete [] tmp.second;
tmp.second = NULL;
}
}

C: Trouble when trying to comvert HBITMAP into .bmp file

I am creating a function to save a screenshot into a .bmp file, I've managed to save the screen into an HBITMAP but I'm having trouble when saving it. I would appreciate some help.
Here is the header with the function:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <stdbool.h>
#include <wingdi.h>
#include <winuser.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned long long u64;
void getScreen()
{
u16 screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
u16 screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
HDC hdc = GetDC(NULL); //get a desktop dc (NULL for entire screen)
HDC hDest = CreateCompatibleDC(hdc); //create a dc for capture
ReleaseDC(NULL, hdc);
HBITMAP hbCapture = CreateCompatibleBitmap(hdc, screenWidth, screenHeight);
SelectObject(hDest, hbCapture);
//Copy screen to bitmap
BitBlt(hDest, 0, 0, screenWidth, screenHeight, hdc, 0, 0, SRCCOPY);
//test
ReleaseDC(NULL, hdc);
char memBuffer[10000];
BITMAPINFO bitmapInfo;
bitmapInfo.bmiHeader.biHeight = screenHeight;
bitmapInfo.bmiHeader.biWidth = screenWidth;
bitmapInfo.bmiHeader.biSize = screenWidth * screenHeight * 3;
bitmapInfo.bmiHeader.biCompression = BI_RGB;//NOT SURE
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 8; //NOT SURE
bitmapInfo.bmiHeader.biClrImportant = 0;
GetDIBits(hDest, hbCapture, 0, screenHeight, &memBuffer, &bitmapInfo, DIB_RGB_COLORS);
FILE * fPointer = fopen("screen.png", "wb");//TO CHANGE
WriteFile(fPointer, &memBuffer, (WORD) sizeof(memBuffer), 0, NULL);
fclose(fPointer);
//test
//Clean up
ReleaseDC(NULL, hdc);
DeleteDC(hDest);
DeleteObject(hbCapture);
}
And here is also the main.c:
#include "main.h"
int main()
{
getScreen();
return 0;
}
I've already read all the questions about this topic in StackOverflow and none of them has clarified the issue for me.
bitmapInfo.bmiHeader.biSize = screenWidth * screenHeight * 3;
biSize is not the total pixel count, it's the size of bitmap info structure, it's always sizeof(BITMAPINFOHEADER).
You want to set bitmapInfo.bmiHeader.biSizeImage instead. This value is roughly (width * height * bits_per_pixel/8) but it has to be adjusted because each row is padded. Also don't mix fopen handle with CreateFile handle as noted in comments.
fopen("screen.png", "wb");
You cannot save to png format using this method. You need a different library like Gdiplus for png format.
To save as bitmap, you have to setup BITMAFILEHEADER, BITMAPINFOHEADER and write them to file, and then write the bits obtained from GetDIBits
You may want to avoid using typedef unsigned char u8; etc. You can include <stdint.h> and use standard types uint8_t, uint16_t, uint32_t etc. Or you can use standard Windows types like BYTE
void getScreen()
{
int screenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int screenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
HDC hdc = GetDC(NULL);
HDC hDest = CreateCompatibleDC(hdc);
HBITMAP hbCapture = CreateCompatibleBitmap(hdc, screenWidth , screenHeight );
HBITMAP oldbmp = (HBITMAP)SelectObject(hDest, hbCapture);
BitBlt(hDest, 0, 0, screenWidth , screenHeight , hdc, 0, 0, SRCCOPY);
WORD bpp = 24; //<- bits per pixel
int size = ((screenWidth * bpp + 31) / 32) * 4 * screenHeight ;
BITMAPINFOHEADER bmp_info_hdr;
bmp_info_hdr.biSize = sizeof(bmp_info_hdr);
bmp_info_hdr.biHeight = screenHeight ;
bmp_info_hdr.biWidth = screenWidth ;
bmp_info_hdr.biPlanes = 1;
bmp_info_hdr.biBitCount = bpp;
bmp_info_hdr.biCompression = BI_RGB;
bmp_info_hdr.biSizeImage = size;
BITMAPFILEHEADER bmp_file_hdr;
bmp_file_hdr.bfType = (WORD)'MB';
bmp_file_hdr.bfOffBits = sizeof(bmp_file_hdr) + sizeof(bmp_info_hdr);
bmp_file_hdr.bfSize = bmp_file_hdr.bfOffBits + size;
char *buffer = malloc(size);
GetDIBits(hDest, hbCapture, 0, screenHeight , buffer,
(BITMAPINFO*)&bmp_info_hdr, DIB_RGB_COLORS);
FILE * fPointer = fopen("screen.bmp", "wb");
fwrite((char*)&bmp_file_hdr, sizeof(bmp_file_hdr), 1, fPointer);
fwrite((char*)&bmp_info_hdr, sizeof(bmp_info_hdr), 1, fPointer);
fwrite(buffer, size, 1, fPointer);
fclose(fPointer);
free(buffer);
SelectObject(hDest, oldbmp);
DeleteObject(hbCapture);
DeleteDC(hDest);
ReleaseDC(NULL, hdc);
}

Serialization of packages with C

Im new here and Ill love your help.
Im trying to serialize and deserialize a package (to use it in sockets) and the results are not the ones that I expect but I cant find the mistake. HereĀ“s the code.
typedef struct {
int32_t size;
char data[1024];
} t_socket_buffer;
typedef struct {
int16_t payloadLength;
int8_t type;
char *path;
} ReadRequestPackage;
The function that serializes
t_socket_buffer *Open_serializer(ReadRequestPackage *ReadPackage){
char data[1024];
t_socket_buffer *stream = malloc(sizeof(t_socket_buffer));
int8_t offset = 0, tmp_size = 0;
memcpy(data, &ReadPackage->payloadLength, tmp_size = sizeof(int16_t));
offset = tmp_size;
memcpy(data + offset,&ReadPackage->type, tmp_size = sizeof(int8_t));
offset+= tmp_size;
memcpy(data + offset, ReadPackage->path,tmp_size = strlen(ReadPackage->path)+1);
stream->size = offset + tmp_size;
memcpy(stream->data, data,strlen(data)+1);
return stream;
}
The function that DEserializes
ReadRequestPackage *Open_deserializer(t_socket_buffer *stream)
{
ReadRequestPackage *ReadPackage = malloc(sizeof(ReadRequestPackage));
int32_t offset = 0, tmp_size = 0;
memcpy(&ReadPackage->payloadLength,stream->data,tmp_size = sizeof(int16_t));
offset = tmp_size;
memcpy(&ReadPackage->type, stream->data + offset, tmp_size = sizeof(int8_t));
offset += tmp_size;
for(tmp_size = 1; (stream->data + offset)[tmp_size-1]!='\0';tmp_size++);
ReadPackage->path = malloc(tmp_size);
memcpy(ReadPackage->path, stream->data + offset, tmp_size);
return ReadPackage;
}
When I test it with this main()
int main (void){
ReadRequestPackage *pqt1 = malloc(sizeof(ReadRequestPackage));
ReadRequestPackage *pqt2;
t_socket_buffer *stream;
pqt1->path=malloc(sizeof("directory"));
strcpy(pqt1->path,"directory");
pqt1->payloadLength = strlen("directory")+1+sizeof(int8_t);
pqt1->type = 1;
stream = Open_serializer(pqt1);
pqt2 = Open_deserializer(stream);
printf("path 1: ");
puts(pqt1->path);
printf("path 2: ");
puts(pqt2->path);
printf("\ntype1:%d ",pck1->type);
printf("\ntype2:%d ",pck2->type);
printf("\nize:%d ",pck1->payloadLength);
printf("\nsize:%d ",pck2->payloadLength);
return 1;
}
The results are not the same and they should!
Thank you very much!
memcpy(stream->data, data,strlen(data)+1);
This line is not doing what you think it's doing. data is not a string.
BTW, have you thought about using a proper serialization library?

Mouse cursor bitmap

I am trying to get bitmap from mouse cursor, but with next code, i just can't get colors.
CURSORINFO cursorInfo = { 0 };
cursorInfo.cbSize = sizeof(cursorInfo);
if (GetCursorInfo(&cursorInfo)) {
ICONINFO ii = {0};
int p = GetIconInfo(cursorInfo.hCursor, &ii);
// get screen
HDC dc = GetDC(NULL);
HDC memDC = CreateCompatibleDC(dc);
//SelectObject(memDC, ii.hbmColor);
int counter = 0;
//
byte* bits[1000];// = new byte[w * 4];
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 16;
bmi.bmiHeader.biHeight = 16;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 0;
bmi.bmiHeader.biYPelsPerMeter = 0;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
int rv = ::GetDIBits(memDC, ii.hbmColor, 0, 1, (void**)&bits, &bmi, DIB_RGB_COLORS);
}
Start by getting the parameters of the bitmap as recorded by Windows:
BITMAP bitmap = {0};
GetObject(ii.hbmColor, sizeof(bitmap), &bitmap);
You can use the returned values to populate the bmi structure.
And about the bmi structure: BITMAPINFO does not reserve enough space for a palette. You should create your own structure for this:
struct BitmapPlusPalette
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD palette[256];
};
Calculating the number of bytes needed for the bitmap is a bit tricky because it needs to be rounded up:
w = ((bitmap.bmWidth * bitmap.bmBitsPixel) + 31) / 8;
byte* bits = new byte[w * bitmap.bmHeight];
And here's a corrected version of your final line:
int rv = ::GetDIBits(dc, ii.hbmColor, 0, bitmap.bmHeight, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS);
The problem with your code I think is in the way you allocated memory for 'bits' variable and how you used it then in GetDIBits function.
Firstly, the commented part byte* bits = new byte[w*4] was better than byte* bits[1000]. When you write byte* bits[1000] computer allocates 1000 POINTERS to byte. Each of these pointers doesn't point to anything.
Secondly, GetDIBits accepts LPVOID lpvBits as a 5th param. So, its a pointer to void.
In most platforms sizeof(void *) > sizeof(byte), so you can't just pass it a byte array, probably it would be better to pass a pointer to int or unsigned int (I'm not good at Windows types, so maybe something more appropriate should be better, sorry).
So, my guess is this:
unsigned bits[1000];
memset(bits, 0, sizeof(bits));
//...
int tv = GetDIBits(memDC, ii.hmbColor, 0, 1, (LPVOID)bits, /* ... */);

Resources