我有一个复制图像和调整亮度的主题。这是我的代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define xsize 570
#define ysize 456
#define input_filename "robot2.bmp"
#define output_filename "test_image.bmp"
int is_success_open_file(FILE* filename); // 파일을 성공적으로 열었는지 확인하는 함수
//void is_BMP(BITMAPFILEHEADER hf); // open한 파일의 형식이 BMP가 맞는지 확인하는 함수
void read_color_img(BITMAPFILEHEADER* hf, BITMAPINFOHEADER* hInfo, RGBQUAD hRGB[256], unsigned char InputImg[xsize][ysize]); // open한 이미지의 픽셀을 읽는 함수
void read_no_color_img(BITMAPFILEHEADER* hf, BITMAPINFOHEADER* hInfo, RGBQUAD hRGB[256], unsigned char InputImg[xsize][ysize]);
void copy_image(unsigned char InputImg[xsize][ysize], unsigned char OutputImg[xsize][ysize]); // read_color_img 함수에서 읽은 픽셀값을 쓰기 전에 저장하는 함수
void write_color_img(BITMAPFILEHEADER* hf, BITMAPINFOHEADER* hInfo, RGBQUAD hRGB[256], unsigned char OutputImg[xsize][ysize]); // copy_image에서 저장한 픽셀을 통해 이미지 파일을 만드는 함수
void write_no_color_img(BITMAPFILEHEADER* hf, BITMAPINFOHEADER* hInfo, RGBQUAD hRGB[256], unsigned char OutputImg[xsize][ysize]);
void print_result(BITMAPFILEHEADER hf, BITMAPINFOHEADER hInfo, RGBQUAD hRGB[256]);
int main(void)
{
// 밑의 값들은 Windows.h 헤더파일에서 값이 정해져있음
BITMAPFILEHEADER hf; // "파일정보헤드" 구조체 변수 선언
BITMAPINFOHEADER hInfo; // "이미지정보헤드" 구조체 변수 선언
RGBQUAD hRGB[256]; // 팔레트 정보를 위한 배열 선언
unsigned char InputImg[xsize][ysize]; // 입력 이미지
unsigned char OutputImg[xsize][ysize]; // 출력 이미지
int is_color;
printf("no color image : 0, color image : 1\n");
scanf("%d", &is_color);
if(is_color == 0)
{
printf("no color\n");
read_no_color_img(&hf, &hInfo, hRGB, InputImg);
print_result(hf, hInfo, hRGB);
copy_image(InputImg, OutputImg);
write_no_color_img(&hf, &hInfo, hRGB, OutputImg);
}
else
{
// 이미지 파일 읽기 (Windows.h 헤더파일의 내장 함수 fread를 통해서)
read_color_img(&hf, &hInfo, hRGB, InputImg);
print_result(hf, hInfo, hRGB);
// 이미지 값들에 +alpha
// 읽은 이미지 파일의 픽셀들을 복사, OutputImg에 저장
copy_image(InputImg, OutputImg);
// 픽셀값이 저장된 OutputImg를 통해서 이미지 저장
write_color_img(&hf, &hInfo, hRGB, OutputImg);
}
return 0;
}
int is_success_open_file(FILE* filename)
{
if (filename == NULL)
{
printf("failed to open file\n\n");
return 1;
}
else
{
printf("successed to open file\n\n");
return 0;
}
}
void read_color_img(BITMAPFILEHEADER* hf, BITMAPINFOHEADER* hInfo, RGBQUAD hRGB[256], unsigned char InputImg[xsize][ysize])
{
FILE* fp; // 파일 포인터 선언
// 이미지 파일 open (파일을 읽거나 쓰기 위한 선행 작업). 아래의 코드로 fp는 다룰 파일을 지칭게 됨. rb의 뜻 : "r" : 읽기, "b" : 이진수로
fp = fopen(input_filename, "rb");
// 이미지 파일 열기를 성공적으로 마쳤는지 판단
if (is_success_open_file(fp) == 1)
{
printf("EXIT program");
exit(1);
}
/*
fread 함수의 첫 번째 인자는 각 구조체의 포인터
2번째는 byte크기로 각 구조체의 크기를 byte 단위로 반환
3번째에 있는 숫자는 읽기의 반복 횟수, 4번째는 읽을 파일을 가리킴
*/
fread(hf, sizeof(BITMAPFILEHEADER), 1, fp); // hf : BITMAPFILEHEADER 구조체의 포인터
fread(hInfo, sizeof(BITMAPINFOHEADER), 1, fp); // hInfo : BITMAPINFOHEADER의 구조체의 포인터
fread(hRGB, sizeof(RGBQUAD), 256, fp); // hRGB : RGBQUA 구조체의 포인터
// fread(InputImg, xsize * ysize , 1, fp); 왼쪽의 코드를 아래의 코드로 바꾸자, 이미지 파일이 깨지긴 하지만 열리긴 함
fread(InputImg, xsize * ysize* (hInfo->biBitCount / 8) , 1, fp); // InputImg는 main함수에서 선언됐고, 배열명은 포인터기 때문에 InputImg는 포인터
// 작업을 마쳤으니 close
fclose(fp);
}
void read_no_color_img(BITMAPFILEHEADER* hf, BITMAPINFOHEADER* hInfo, RGBQUAD hRGB[256], unsigned char InputImg[xsize][ysize])
{
FILE* fp; // 파일 포인터 선언
// 이미지 파일 open (파일을 읽거나 쓰기 위한 선행 작업). 아래의 코드로 fp는 다룰 파일을 지칭게 됨. rb의 뜻 : "r" : 읽기, "b" : 이진수로
fp = fopen(input_filename, "rb");
// 이미지 파일 열기를 성공적으로 마쳤는지 판단
if (is_success_open_file(fp) == 1)
{
printf("EXIT program");
exit(1);
}
/*
fread 함수의 첫 번째 인자는 각 구조체의 포인터
2번째는 byte크기로 각 구조체의 크기를 byte 단위로 반환
3번째에 있는 숫자는 읽기의 반복 횟수, 4번째는 읽을 파일을 가리킴
*/
fread(hf, sizeof(BITMAPFILEHEADER), 1, fp); // hf : BITMAPFILEHEADER 구조체의 포인터
fread(hInfo, sizeof(BITMAPINFOHEADER), 1, fp); // hInfo : BITMAPINFOHEADER의 구조체의 포인터
fread(hRGB, sizeof(RGBQUAD), 256, fp); // hRGB : RGBQUA 구조체의 포인터
// fread(InputImg, xsize * ysize , 1, fp); 왼쪽의 코드를 아래의 코드로 바꾸자, 이미지 파일이 깨지긴 하지만 열리긴 함
fread(InputImg, xsize * ysize , 1, fp); // InputImg는 main함수에서 선언됐고, 배열명은 포인터기 때문에 InputImg는 포인터
// 작업을 마쳤으니 close
fclose(fp);
}
void copy_image(unsigned char InputImg[xsize][ysize], unsigned char OutputImg[xsize][ysize])
{
// 이미지의 픽셀을 2차원으로 분해, OutputImg에 저장
for (int i = 0; i < xsize; i++)
{
for (int j = 0; j < ysize; j++)
{
OutputImg[i][j] = InputImg[i][j] ; // 픽셀 하나당 RGB 값을 가지고 있다.
}
}
}
// 함수 : 사용자의 입력값을 RGB 입력값을 받아서 하나의 값으로 반환
void write_color_img(BITMAPFILEHEADER* hf, BITMAPINFOHEADER* hInfo, RGBQUAD hRGB[256], unsigned char OutputImg[xsize][ysize])
{
FILE* fp; // 파일 포인터 선언
// 이미지 파일을 저장하기 위해서 다시 open. "w" : 쓰기
fp = fopen(output_filename, "wb");
if (is_success_open_file(fp) == 1)
{
printf("EXIT program\n");
exit(1); // 파일 열기 실패 시 프로그램 종료
}
// read_color_img에서 설명한 바와 같다. 다만, 3번째 인자는 쓰는 횟수
fwrite(hf, sizeof(BITMAPFILEHEADER), 1, fp);
fwrite(hInfo, sizeof(BITMAPINFOHEADER), 1, fp);
fwrite(hRGB, sizeof(RGBQUAD), 256, fp);
fwrite(OutputImg, xsize * ysize* (hInfo->biBitCount / 8) , 1, fp);
// 작업을 마쳤으니 close
fclose(fp);
}
void write_no_color_img(BITMAPFILEHEADER* hf, BITMAPINFOHEADER* hInfo, RGBQUAD hRGB[256], unsigned char OutputImg[xsize][ysize])
{
FILE* fp; // 파일 포인터 선언
// 이미지 파일을 저장하기 위해서 다시 open. "w" : 쓰기
fp = fopen(output_filename, "wb");
if (is_success_open_file(fp) == 1)
{
printf("EXIT program\n");
exit(1); // 파일 열기 실패 시 프로그램 종료
}
// read_color_img에서 설명한 바와 같다. 다만, 3번째 인자는 쓰는 횟수
fwrite(hf, sizeof(BITMAPFILEHEADER), 1, fp);
fwrite(hInfo, sizeof(BITMAPINFOHEADER), 1, fp);
fwrite(hRGB, sizeof(RGBQUAD), 256, fp);
fwrite(OutputImg, xsize * ysize, 1, fp);
// 작업을 마쳤으니 close
fclose(fp);
}
void print_result(BITMAPFILEHEADER hf, BITMAPINFOHEADER hInfo, RGBQUAD hRGB[256])
{
printf("size of BITMAPINFOHEADER = %d\n", hInfo.biSize); // BITMAPINFOHEADER 구조체의 크기
printf("WIDTH OF IMG = %d\n", hInfo.biWidth); // 이미지의 가로 크기
printf("HEIGHT OF IMG = %d\n", hInfo.biHeight); // 이미지의 세로 크기
printf("BYTE SIZE OF IMG = %d\n", hf.bfSize); // byte 단위로 파일 전체 크기
printf("IS IMG BMP? = %hx. if result : 4d42, it means BMP\n", hf.bfType); // "파일이 BMP"가 맞는지
printf("NUMBER OF USED COLORS = %d\n", hInfo.biClrUsed); // 실제 사용 색상 수
printf("BIT PER PIXEL = %d\n\n", hInfo.biBitCount); // 픽셀당 비트 수 (컬러, 흑백 구별)
}
robot2 文件是一张黑白照片。然后这段代码可以正常工作并且文件保存得很好。但是robot2文件改为robot(彩色图像),有问题,所以我无法打开保存的文件。
另外,即使文件打开,大部分图片都被剪切或像素扭曲并保存,但我使用了另一个彩色图像,我不小心输入了0(没有彩色图像),文件已保存为彩色。差异仅为每个像素位。
机器人文件的每像素位数是 24,而另一张图像是 32。有什么问题吗?
文件需要妥善保存。我更改了 BMP 文件(两种颜色),但一张图像无法保存得很好,但另一张图像保存得很好。没有彩色图像保存完好,但彩色图像 BMP 文件有问题。
如果我明白了,那么编写彩色 BMP 是唯一需要克服的障碍。 这不是一个微不足道的任务!这段代码将为您编写一个24位颜色位图,但它确实很麻烦。
通过更多的编辑和添加,它也可以适用于 32 位位图...此处包含的模板适用于 24 位和 32 位之外的其他每像素位 - 特别参见 WriteDIBimageData()。
此代码是可移植的——位图结构当然非常类似于 Windows,但它们包含在此代码中,因此可以将其移植到其他平台。我们永远不想排除我们的“尼克斯朋友”;欢迎大家来参加聚会。
此代码已由我编译并经过我的充分测试;无法保证安全性和有效性。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
///////////////////////////////////////
#ifndef _WINDEF_
/* typdefs and defines to make this code portable/platform independent.
* The BMP format is somewhat proprietary, so all this stuff is windows.h compatable.*/
#define FAR
#define VOID void
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
typedef signed short BOOL;
typedef unsigned int UINT; //Updated 2023
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
#define TRUE 1
#define FALSE 0
/* Bitmap Header structures */
/* structures for defining DIBs */
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; /* = sizeof (BITMAPINFOHEADER) */
LONG biWidth; /* Image wdth */
LONG biHeight; /* Image hgt */
WORD biPlanes; /* Always 1 for our purposes */
WORD biBitCount; /* Image bits per pixel */
DWORD biCompression; /* zero for no compression */
DWORD biSizeImage; /* Ttl image bytes: WIDTHBYTES((WORD)dwWidth,nBitsPP) * dwHeight */
LONG biXPelsPerMeter; /* Always zero for our purposes */
LONG biYPelsPerMeter; /* Always zero for our purposes */
DWORD biClrUsed; /* Always zero for our purposes */
DWORD biClrImportant; /* Always zero for our purposes */
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
#pragma pack(push,2)
typedef struct tagBITMAPFILEHEADER {
WORD bfType; /* "BM" */
DWORD bfSize; /* palette size */
WORD bfReserved1; /* Always zero for our purposes */
WORD bfReserved2; /* Always zero for our purposes */
DWORD bfOffBits; /* Offset image data begins: sizeof(BITMAPFILEHEADER) + lpbi->biSize + PaletteSize*/
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
#pragma pack(pop)
#endif // _WINDEF_
///////////////////////////////////////
typedef struct tagImageInfo
{
DWORD ImageW; //Image X dims
DWORD ImageH; //Image Y dims
WORD BitsPP; //Same as Gplanes OR'd into GifH.Flags
}IMINFO;
typedef struct tagImageObject
{
DWORD dwSIZE; //Total number of Bytes used by memory object
UCHAR *imBuff; //Actual image bits
IMINFO image; //IMAGE data structure
}IMAGEOBJECT, *pIMAGE;
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
#define BITS_TO_BYTES(BITS) (((BITS)+7)>>3)
#define WIDTHBYTES(w, bitcount) ((((w)*(bitcount)+31)& ~31) >> 3)
/* Zero for anything higher than 8 bits */
WORD DIBNumColors (void *lpbi){ return 0; }
/* No palette in anything higher than 8 bits */
WORD PaletteSize(void * lpbi){ return 0; /*(DIBNumColors (lpbi) * sizeof (RGBQUAD));*/}
VOID *GetLineMem(pIMAGE pi, DWORD Y)
{
return &pi->imBuff[Y * WIDTHBYTES(pi->image.ImageW, pi->image.BitsPP)];
}
/*---------------------------------------------------------------------------------
InitBitmapInfoHeader()
Purpose: Generic initialization of a BITMAPINFOHEADER,
given the Width, Height, and Bits per Pixel for the DIB.
biCompression is set to "no compression," and all
other unused fields are 0.
Parms: lpBmInfoHdr == pointer to a BITMAPINFOHEADER structure to be filled in.
dwWidth == Width of DIB
dwHeight == Height of DIB
nBitsPP == Bits per Pixel for the DIB.
*--------------------------------------------------------------------------------*/
void InitBitmapInfoHeader (LPBITMAPINFOHEADER lpBmInfoHdr, DWORD dwWidth,DWORD dwHeight, int nBitsPP)
{
memset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER));
lpBmInfoHdr->biSize = sizeof (BITMAPINFOHEADER);
lpBmInfoHdr->biWidth = dwWidth;
lpBmInfoHdr->biHeight = dwHeight;
lpBmInfoHdr->biPlanes = 1;
lpBmInfoHdr->biBitCount = nBitsPP;
if(lpBmInfoHdr->biBitCount != 24 )
{
printf("Only 24 bits per pixel supported in this implementation, exiting\n");
exit(0);
}
lpBmInfoHdr->biSizeImage = WIDTHBYTES((WORD)dwWidth,nBitsPP) * dwHeight;
}
/*----------------------------------------------------------------------------
WriteDIBimageData()
PURPOSE : Writes data in upside down (BMP style) 'til all the data is written.
RETURNS : FALSE - If write did not proceed correctly or any issue
TRUE on success
*----------------------------------------------------------------------------*/
DWORD WriteDIBimageData( FILE *hFile, LPBITMAPINFOHEADER lpbi, pIMAGE pi)
{
DWORD ImageH = pi->image.ImageH;
DWORD ImageW = pi->image.ImageW;
int outbitspp, bytesw, Y;
BYTE *psrc = NULL;
BYTE *write_buff = NULL;
DWORD num_bytes_dest;
outbitspp = lpbi->biBitCount;
bytesw = WIDTHBYTES(ImageW,outbitspp);
#if 1
printf("WriteDIBimageData() details: ------------------\n");
printf("ImageW = %d \n",ImageW);
printf("ImageH = %d \n",ImageH);
printf("OutBitsPP = %d \n",outbitspp );
printf("InBitsPP = %d \n",pi->image.BitsPP );
printf("WBytes = %d \n", bytesw);
#endif
if(!(write_buff=(UCHAR *)malloc(bytesw)) )
{
printf("Memory error!\n");
return FALSE;
}
num_bytes_dest = BITS_TO_BYTES(outbitspp)*ImageW;
Y = (int)(ImageH-1L);
do
{
memset(write_buff, 0, bytesw);
if(Y < (int)pi->image.ImageH )
{
if(!(psrc = (UCHAR *)GetLineMem(pi, Y)))
{
printf("Memory error!\n");
break;
}
switch(outbitspp)
{
/*Bit conversions are not supported in this example, but this is where
** the routines would go. From 8 bits input to 32 bits output, or vise versa, etc..
** ... convert each image row on-the-fly */
case 1:
//PackBits(write_buff,psrc, ImageW);
case 4:
//PackNybbles(write_buff, psrc, ImageW);
case 8:
case 16:
case 32:
printf("Bit conversions not supported this example.\n");
break;
case 24: /* Just 24 bits in and 24 bits out, this example */
/* copy image bits from source to dest */
memcpy(write_buff, psrc, bytesw);
break;
default:
printf("Bit conversions not supported this example.\n");
//color_convert_line(psrc,write_buff,GetImBitsPP(pi), outbitspp, GetImPalettePtr(pi),num_bytes_dest);
break;
}
}
if (fwrite(write_buff, 1, bytesw, hFile) != bytesw)
{
printf("Write error!\n");
free(write_buff);
return FALSE;
}
}while(Y--);
free(write_buff);
return TRUE;
}
/*----------------------------------------------------------------------------
WriteDIB()
PURPOSE: Write Device-independent bitmap to a BMP file.
RETURNS: TRUE - if successful.
FALSE - otherwise
*----------------------------------------------------------------------------*/
BOOL WriteDIB(char *pFileName, LPBITMAPINFOHEADER lpbi, pIMAGE pi)
{
BITMAPFILEHEADER hdr;
FILE * hFile;
hFile = fopen(pFileName, "wb");
if (!hFile)
return FALSE;
/* Fill in the fields of the file header */
hdr.bfType = DIB_HEADER_MARKER;
hdr.bfSize = sizeof(BITMAPFILEHEADER) + lpbi->biSize + PaletteSize(lpbi) + lpbi->biSizeImage;
hdr.bfReserved1 = hdr.bfReserved2 = 0;
hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpbi->biSize + PaletteSize(lpbi);
#if 1
printf("WriteDIB() details:---------------------------\n");
printf("sizeof(BITMAPFILEHEADER) = %d (should be 14)\n", sizeof(BITMAPFILEHEADER) );
printf("sizeof(BITMAPINFOHEADER) = %d (should be 40)\n", sizeof(BITMAPINFOHEADER) );
printf("sizeof(WORD) = %d (should be 2)\n", sizeof(WORD) );
printf("sizeof(DWORD) = %d (should be 4)\n", sizeof(DWORD) );
printf("sizeof(UINT) = %d (should be 4)\n", sizeof(UINT) );
printf("hdr.bfType = %c%c \n", hdr.bfType&0xFF, (hdr.bfType>>8)&0xFF );
printf("hdr.bfSize = %ld \n",hdr.bfSize );
printf("hdr.bfReserved1 = %d \n",hdr.bfReserved1 );
printf("hdr.bfReserved2 = %d \n",hdr.bfReserved2 );
printf("hdr.bfOffBits = %ld \n",hdr.bfOffBits );
printf("lpbi->biHeight = %d \n",lpbi->biHeight);
printf("lpbi->biWidth = %ld \n",lpbi->biWidth);
printf("lpbi->biBitCount = %d \n",lpbi->biBitCount);
printf("WIDTHBYTES() = %d \n",WIDTHBYTES(lpbi->biWidth, lpbi->biBitCount));
printf("PaletteSize (lpbi) = %d \n",PaletteSize (lpbi));
printf("\n");
#endif
/* Write the file header */
if (fwrite((void *)&hdr, 1, sizeof(BITMAPFILEHEADER), hFile) != sizeof (BITMAPFILEHEADER))
{
printf("Write error!\n");
fclose (hFile);
return FALSE;
}
/* Write the DIB header */
if(fwrite ((void *)lpbi, 1, sizeof (BITMAPINFOHEADER), hFile) != sizeof (BITMAPINFOHEADER))
{
printf("Write error!\n");
fclose (hFile);
return FALSE;
}
/* Write the bits */
if (!WriteDIBimageData (hFile, lpbi, pi))
{
fclose (hFile);
return FALSE;
}
fclose (hFile);
return TRUE;
}
/*----------------------------------------------------------------------------
Function: SaveDIBFile()
Purpose: Main entry for the module. Writes DIB/BMP out in format specified.
Returns: FALSE if no file is opened, or an error occurs writing the file.
TRUE if successful
*----------------------------------------------------------------------------*/
BOOL SaveDIBFile( pIMAGE pi, char *szFileName, int desired_bitspp)
{
BITMAPINFOHEADER bi;
DWORD dwWidth, dwHeight;
if(!pi)
{
printf("Memory error! pi is NULL in SaveDIBFile()\n");
return 0;
}
if(pi->image.BitsPP > 8 && desired_bitspp < 9)
{
/* Image quantization, (ie: from input 24 bits per pixel down to 8bits) would go here */
printf("Image quantization not suipport this example!\n");
return FALSE;
}
dwWidth = pi->image.ImageW;
dwHeight = pi->image.ImageH;
InitBitmapInfoHeader(&bi, dwWidth, dwHeight, desired_bitspp);
return WriteDIB(szFileName, &bi,pi);
}
#define IMAGE_W 500
#define IMAGE_H 500
#define IMAGE_BITS_PER_PIXEL 24
int main()
{
IMAGEOBJECT im;
int xxx,yyy, row;
UCHAR *ptrImageData;
int red=0, green=0, blue=0;
memset(&im, 0, sizeof(im));
im.dwSIZE = IMAGE_H * WIDTHBYTES(IMAGE_W, IMAGE_BITS_PER_PIXEL);
im.image.BitsPP = IMAGE_BITS_PER_PIXEL;
im.image.ImageW = IMAGE_W;
im.image.ImageH = IMAGE_H;
im.imBuff = malloc(im.dwSIZE);
if(!im.imBuff)
{
printf("Couldn't allocate %d bytes memory!\n", im.dwSIZE );
return 0;
}
printf("Successfully allocated %d bytes memory!\n", im.dwSIZE );
ptrImageData = im.imBuff;
srand((unsigned)time(NULL));
/* This logic will create an image of random color horizontal stripes,
** each stripe being row(max) pixels wide. **/
for(yyy = 0; yyy < IMAGE_H; yyy+=row)
{
/* Just playing with the color channels here; do what you want*/
red+=5;
green=0;
blue+=2;
if(red > 255)
red = 0;
if(blue > 255)
blue = 0;
for(row = 0; row < 3; row++)
{
for(xxx = 0; xxx < IMAGE_W; xxx++)
{
/*Do each color channel: B then G then R */
*(ptrImageData++)= blue;
*(ptrImageData++)= green;
*(ptrImageData++)= red;
}
}
}
if(SaveDIBFile(&im, "myBMP.bmp", 24))
{
printf("SaveDIBFile() reports success.\n");
}
else
{
printf("SaveDIBFile() failed!\n");
}
return 0;
}
输出:
Successfully allocated 750000 bytes memory!
WriteDIB() details:---------------------------
sizeof(BITMAPFILEHEADER) = 14 (should be 14)
sizeof(BITMAPINFOHEADER) = 40 (should be 40)
sizeof(WORD) = 2 (should be 2)
sizeof(DWORD) = 4 (should be 4)
sizeof(UINT) = 4 (should be 4)
hdr.bfType = BM
hdr.bfSize = 750054
hdr.bfReserved1 = 0
hdr.bfReserved2 = 0
hdr.bfOffBits = 54
lpbi->biHeight = 500
lpbi->biWidth = 500
lpbi->biBitCount = 24
WIDTHBYTES() = 1500
PaletteSize (lpbi) = 0
WriteDIBimageData() details: ------------------
ImageW = 500
ImageH = 500
OutBitsPP = 24
InBitsPP = 24
WBytes = 1500
SaveDIBFile() reports success.
[![This is the output 500x500 24 bit bitmap:'myBMP.bmp'][1]][1]
[1]: https://i.stack.imgur.com/5mmbx.png