gpt4 book ai didi

c - 关于 BMP 文件。我如何写入/更改像素颜色? (在C中)

转载 作者:行者123 更新时间:2023-11-30 15:18:14 25 4
gpt4 key购买 nike

我正在尝试更改图片中的像素(bmp 格式,24 位)。

我有这 3 个结构:

文件头:

#pragma pack(2)
typedef struct {
unsigned short int typeID;
unsigned int size;
unsigned short int reserved1, reserved2;
unsigned int offset;
}BITMAPFILEHEADER;
#pragma pack(0)

信息标题:

typedef struct {
unsigned int headerSize;
signed int widthPixel, heightPixel;
unsigned short int colorPlanes;
unsigned short int bitsPerPixel;
unsigned int compressionMethod;
unsigned int imagesize;
signed int xResolution, yResolution; // pixel per meter
unsigned int nbColor;
unsigned int importantColor;
}BITMAPINFOHEADER;

对于 RGB 颜色:

typedef struct {
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
} RGBCOLOR;

然后是主要代码:

int main(void) {
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER infoHeader;
FILE *inFileImage = NULL;

unsigned char *pBitsData = NULL;
int rowSize = 0;
int nImageSize = 0;


inFileImage = fopen("panda.bmp", "r+");
if (inFileImage == NULL)
{
fprintf(stderr, "Unable to open image");
return 0;
}

fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, inFileImage);
rewind(inFileImage);
pBitsData = (unsigned char *)calloc( fileHeader.size, sizeof(unsigned char) );

if( NULL == pBitsData )
{
printf("NO memory!!!!!\n");
}
else
{
fread(pBitsData, fileHeader.size * sizeof(unsigned char), 1, inFileImage);

memcpy(&fileHeader,pBitsData,sizeof(BITMAPFILEHEADER));

printf("Type ID: %x\n", fileHeader.typeID);
printf("File size: %d\n", fileHeader.size);
printf("Offset: %d\n", fileHeader.offset);
printf("**********************\n");

memcpy(&infoHeader, (pBitsData + sizeof(BITMAPFILEHEADER)), sizeof(BITMAPINFOHEADER));

printf("Header size: %u\n", infoHeader.headerSize);
printf("Width: %d\n", infoHeader.widthPixel);
printf("Height: %d\n", infoHeader.heightPixel);
printf("Nb planes: %d\n", infoHeader.colorPlanes);
printf("Bits per pixel: %d\n", infoHeader.bitsPerPixel);
printf("Compression method: %u\n", infoHeader.compressionMethod);
printf("Image size: %u\n", infoHeader.imagesize);
printf("Horizontal pixel per metre: %d\n", infoHeader.xResolution);
printf("Vertical pixel per metre: %d\n", infoHeader.yResolution);
printf("Number color in color table: %u\n", infoHeader.nbColor);
printf("Color important count: %u\n", infoHeader.importantColor);
printf("**********************\n");

rowSize = ((infoHeader.bitsPerPixel * infoHeader.widthPixel + 31) / 32) * 4;
printf("Row Size: %d\n", rowSize);
nImageSize = rowSize * abs(infoHeader.heightPixel);
printf("Pixel Array Size: %d\n", nImageSize);
printf("**********************\n");

RGBCOLOR* pixelData = (RGBCOLOR*)(pBitsData + fileHeader.offset);

// M is define with the value 5 - the 5 pixel from image
printf("Pixel %x, %x, %x\n", pixelData[M].blue, pixelData[M].green, pixelData[M].red);

//fseek(inFileImage, fileHeader.offset, SEEK_CUR);
//fread(pixelData, sizeof(RGBCOLOR), 1, inFileImage);

pixelData[M].red = 0x00;
pixelData[M].blue = 0xef;
pixelData[M].green = 0x00;

//memcpy((pBitsData + fileHeader.offset), &pixelData, sizeof(RGBCOLOR)); // <= here seems to be my problem
//fwrite(pixelData, sizeof(RGBCOLOR), 1, inFileImage); // how can i copy to image from a memory

printf("Pixel %x, %x, %x\n", pixelData[M].blue, pixelData[M].green, pixelData[M].red);
}


fclose(inFileImage);
if(NULL != pBitsData)
{
free(pBitsData);
}

return 0;

}

我想更改图像中的第五个像素(其中之一:蓝色->红色、绿色->蓝色等)。你能告诉我我的代码哪里有错误吗?我怎样才能改变我的代码才能正常工作?谢谢

编辑:

而不是

RGBCOLOR* pixelData = (RGBCOLOR*)(pBitsData + fileHeader.offset);

// M is define with the value 5 - the 5 pixel from image
printf("Pixel %x, %x, %x\n", pixelData[M].blue, pixelData[M].green, pixelData[M].red);

//fseek(inFileImage, fileHeader.offset, SEEK_CUR);
//fread(pixelData, sizeof(RGBCOLOR), 1, inFileImage);

pixelData[M].red = 0x00;
pixelData[M].blue = 0xef;
pixelData[M].green = 0x00;

//memcpy((pBitsData + fileHeader.offset), &pixelData, sizeof(RGBCOLOR)); // <= here seems to be my problem
//fwrite(pixelData, sizeof(RGBCOLOR), 1, inFileImage); // how can i copy to image from a memory

printf("Pixel %x, %x, %x\n", pixelData[M].blue, pixelData[M].green, pixelData[M].red);

如果我写

    RGBCOLOR img;
fseek(inFileImage, fileHeader.offset, SEEK_SET);
img.blue = 0x00;
img.green = 0x00;
img.red = 0xff;
fwrite(&img, sizeof(RGBCOLOR), 1, inFileImage);

这将更改第一个像素。但我想复制到内存中,并从那里更改像素。

最佳答案

我使用 MinGW,因此您需要更改用于结构对齐的#pragma。这是一个一体化的来源,可以

  • 读取图像
  • 更改指定像素
  • 将修改后的图像输出到新文件

为了简洁起见,我没有费心进行任何错误检查。我已经用 24/32 位图像对其进行了测试。与 32 位图像一起使用时,它不会输出有效图像。

首先,这是之前和之后的图像。图像本身为 2x2 像素,为了清晰起见,我只是将其放大了。

之前:

enter image description here enter image description here

之后:

enter image description here enter image description here

如果仔细观察,您会发现两个图像之间唯一不同的字节是文件中 0x3E 处的字节。我们已将红色像素 (00 00 FF) 更改为紫色像素 (FF 00 FF)。由于图像是自下而上的,因此像素数据的前 3 个字节用于黄色像素,接下来的 3 个字节用于蓝色像素,后面是 2 个字节的填充,然后我们有 3 个用于红色,3 个用于绿色,另外 2 个填充字节。

以下是进行更改的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#ifndef WORD
#define WORD unsigned short
#endif

#ifndef DWORD
#define DWORD unsigned long
#endif

#ifndef BYTE
#define BYTE unsigned char
#endif

#ifndef LONG
#define LONG long
#endif


#define minGW 1

#ifdef minGW
#pragma pack(push,2)
#endif
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;
#ifdef minGW
#pragma pack(pop)
#endif

typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;

typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD,*LPRGBQUAD;

typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO;

typedef struct tagBITMAP
{
BITMAPINFOHEADER bmInfo;
unsigned char *pBits;
} BITMAP, *PBITMAP;

PBITMAP readBitmapFile(const char *filename)
{
FILE *fp;
PBITMAP result;
BITMAPFILEHEADER fileHeader;
BITMAPINFO bmpInfo;

fp = fopen(filename, "rb");

fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fp);

fread(&bmpInfo, sizeof(BITMAPINFO), 1, fp);

fseek(fp, fileHeader.bfOffBits, SEEK_SET);
unsigned char *pBits = (unsigned char *)calloc(bmpInfo.bmiHeader.biSizeImage, sizeof(unsigned char) );
fread(pBits, sizeof(char), bmpInfo.bmiHeader.biSizeImage, fp);
fclose(fp);

result = (PBITMAP) calloc(1, sizeof(*result) );
memcpy(&result->bmInfo, &bmpInfo, sizeof(bmpInfo) );
result->pBits = pBits;
return result;
}

void saveBitmapFile(const char *filename, PBITMAP img)
{
FILE *fp;
BITMAPFILEHEADER fileHeader;
memset(&fileHeader, 0, sizeof(fileHeader));
fileHeader.bfType = 0x4d42; //'BM'
fileHeader.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
fileHeader.bfSize = fileHeader.bfOffBits + (img->bmInfo.biSizeImage);

fp = fopen(filename, "wb");
fwrite(&fileHeader, sizeof(fileHeader), 1, fp);
fwrite(&img->bmInfo, sizeof(img->bmInfo), 1, fp);
fwrite(img->pBits, 1, img->bmInfo.biSizeImage, fp);
fclose(fp);
}


void myPixel(int x, int y, char r, char g, char b, PBITMAP image)
{
unsigned char *ptrToPixel;
int rowSize = ((image->bmInfo.biBitCount * image->bmInfo.biWidth + 31) / 32) * 4;
int curRow, bytesPerPixel;
if (image->bmInfo.biHeight < 0)
{
curRow = y;
}
else if (image->bmInfo.biHeight > 0)
{
curRow = (image->bmInfo.biHeight-1) - y;
}
bytesPerPixel = image->bmInfo.biBitCount / 8;
ptrToPixel = (curRow * rowSize) + (x*bytesPerPixel) + image->pBits;

ptrToPixel[0] = b;
ptrToPixel[1] = g;
ptrToPixel[2] = r;
}

int main()
{
PBITMAP inImage = readBitmapFile("colorTile.bmp");
myPixel(0,0, 255,0,255, inImage);
saveBitmapFile("colorTileOut.bmp", inImage);
}

编辑:看完Can someone provide me a specification of 32 bit BMP image format?https://forums.adobe.com/message/3272950#3272950很明显,32 位位图使用的是 V3 header - 该 header 包含 4 个长整型来指定 4 个 channel 中每个 channel 的位掩码。随后,我修改了 saveBitmapFilemyPixel 例程,并且可以确认代码现在似乎也可以在 32 位位图上正常运行。

void saveBitmapFile(const char *filename, PBITMAP img)
{
FILE *fp;
BITMAPFILEHEADER fileHeader;
unsigned long maskArray[] = {0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF};
memset(&fileHeader, 0, sizeof(fileHeader));
fileHeader.bfType = 0x4d42; //'BM'
fileHeader.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
if (img->bmInfo.biBitCount == 32)
fileHeader.bfOffBits += sizeof(maskArray);
fileHeader.bfSize = fileHeader.bfOffBits + (img->bmInfo.biSizeImage);

fp = fopen(filename, "wb");
fwrite(&fileHeader, sizeof(fileHeader), 1, fp);
fwrite(&img->bmInfo, sizeof(img->bmInfo), 1, fp);
if (img->bmInfo.biBitCount == 32)
fwrite(&maskArray, sizeof(long), 4, fp);
fwrite(img->pBits, 1, img->bmInfo.biSizeImage, fp);
fclose(fp);
}

void myPixel(int x, int y, char r, char g, char b, PBITMAP image)
{
unsigned char *ptrToPixel;
int rowSize = ((image->bmInfo.biBitCount * image->bmInfo.biWidth + 31) / 32) * 4;
int curRow, bytesPerPixel;
if (image->bmInfo.biHeight < 0)
{
curRow = y;
}
else if (image->bmInfo.biHeight > 0)
{
curRow = (image->bmInfo.biHeight-1) - y;
}
bytesPerPixel = image->bmInfo.biBitCount / 8;
ptrToPixel = (curRow * rowSize) + (x*bytesPerPixel) + image->pBits;

if (image->bmInfo.biBitCount == 24)
{
ptrToPixel[0] = b;
ptrToPixel[1] = g;
ptrToPixel[2] = r;
}

else if (image->bmInfo.biBitCount == 32)
{
// ptrToPixel[0] = a;
ptrToPixel[1] = b;
ptrToPixel[2] = g;
ptrToPixel[3] = r;
}
}

关于c - 关于 BMP 文件。我如何写入/更改像素颜色? (在C中),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31608867/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com