我正在尝试更改图片中的像素(格式为bmp,24位)。
我有这三种结构:
表示文件标题:
#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;
}
我想从图像中更改第5个像素(其中之一:蓝色 - >红色,绿色 - >蓝色等)。 你能告诉我我的代码在哪里有错误吗?我怎样才能改变我的代码正常工作? THX
编辑:
而不是
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);
这将改变第一个像素。但我想在内存中复制,并从那里更改像素。
答案 0 :(得分:1)
我使用MinGW,因此您需要更改用于结构对齐的#pragma
。
这是
为了简洁起见,我没有为任何错误检查而烦恼。我用24/32位图像测试了它。与32位图像一起使用时,它不会输出有效图像。
首先,这里是之前和之后的图像。图像本身是2x2像素,为了可见性,我在这里只是将它显示得更大。
<强>之前:强>
<强>后:强>
如果仔细观察,可以看到2个图像之间唯一不同的字节是文件中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标头 - 包含4个长的标头,用于指定4个通道中每个通道的位掩码。我随后修改了saveBitmapFile
和myPixel
例程,并且可以确认代码现在看起来也能正常运行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;
}
}