我想把bmp文件读入一个结构,然后写回去,但是图像总是黑色的,标题是可以的。但是像素写错了。我比较了十六进制值,它们是相同的,直到标题完成。剩下的就不一样了,而且更短了。
typedef uint16_t ImageType;
typedef struct
{
uint32_t size;
uint16_t additionalFeature;
uint16_t copy;
uint32_t offset;
} ImageHeader;
typedef struct
{
uint32_t headerSize;
int width;
int height;
uint16_t colorSpaces;
uint16_t bitsPerPixel;
uint32_t compression;
uint32_t size;
int verticalResolution;
int horizontalResolution;
uint32_t totalColors;
uint32_t importantColors;
} ImageMetadata;
typedef struct {
uint8_t blue;
uint8_t green;
uint8_t red;
} ImageColors;
typedef struct {
ImageType type;
ImageHeader header;
ImageMetadata metadata;
ImageColors **pixels;
} Image;这是我的形象结构。目前,它只是一个24 bpp图像以后,我想改变它。但我的问题是,在我写完图片后,它没有正确地显示出来。头数据正常,但图像不正确。

行是正确的,只有列是如何复制和压缩的。
我的包括:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdbool.h>我就是这样读取像素的
void readImage(char *filename, Image *image)
{
FILE *imageFile = fopen(filename, "rb");
if (!imageFile)
{
perror("ReadImageFileException");
fclose(imageFile);
exit(EXIT_FAILURE);
}
fread(&(image->type), sizeof(ImageType), 1, imageFile);
//validate for correct image type
if (image->type != BMP_IMAGE_TYPE)
{
fprintf(stderr, "%hu", image->type);
perror("ReadImageTypeException");
fclose(imageFile);
exit(EXIT_FAILURE);
}
fread(&(image->header), sizeof(ImageHeader), 1, imageFile);
fread(&(image->metadata), sizeof(ImageMetadata), 1, imageFile);
// Allocate space for the pixels.
image->pixels = malloc( image->metadata.height * sizeof(ImageColors *) );
for(int i = 0; i < image->metadata.height; i++){
image->pixels[i] = malloc(image->metadata.width * sizeof(ImageColors));
}
// Read in each pixel
for (int i = 0; i < image->metadata.height; i++){
for(int j = 0; j < image->metadata.width; j++){
ImageColors px;
if( fread(&px, sizeof(ImageColors), 1, imageFile) < 1 ) {
printf("Error while reading bmp pixel.\n");
return;
}
image->pixels[i][j] = px;
}
}
fclose(imageFile);
}我就是这样写的。
void writeImage(char *filename, Image *image)
{
FILE *imageFile = fopen(filename, "wb+");
if (!imageFile)
{
perror("WriteImageFileException");
fclose(imageFile);
exit(EXIT_FAILURE);
}
size_t typeWritten = fwrite(&(image->type), sizeof(image->type), 1, imageFile);
if (typeWritten == 0)
{
perror("WriteImageTypeException");
fclose(imageFile);
exit(EXIT_FAILURE);
}
size_t headerWritten = fwrite(&(image->header), sizeof(image->header), 1, imageFile);
if (headerWritten == 0)
{
perror("WriteImageHeaderException");
fclose(imageFile);
exit(EXIT_FAILURE);
}
size_t metadataWritten = fwrite(&(image->metadata), sizeof(image->metadata), 1, imageFile);
if (metadataWritten == 0)
{
perror("WriteImageMetadataException");
fclose(imageFile);
exit(EXIT_FAILURE);
}
fseek(imageFile, image->header.offset, SEEK_SET);
// Read in each pixel
for (int i = 0; i < image->metadata.height; i++){
for(int j = 0; j < image->metadata.width; j++){
if( fwrite(&image->pixels[i][j], sizeof(ImageColors), 1, imageFile) < 1 ) {
printf("Error while wr bmp pixel.\n");
fclose(imageFile);
exit(EXIT_FAILURE);
}
}
}
fclose(imageFile);
}谢谢你已经进阶了。我只包括负责读和写bmp的方法,因为将来我想添加一些其他特性。
@tshiono谢谢,我在其中添加了行,但是如果我比较了十六进制文件,我可以看到图像仍然有一些不同:

输出图像看起来还是一样的。
我的主要功能如下:
int main(int argc, char **argv) {
int ch;
char *inputFile = "sample.bmp";
char *outputFile = "image-copy.bmp";
Image image;
// try to use port and password from parameter
while ( (ch = getopt_long_only(argc, argv, "", long_options, NULL)) != -1 ) {
switch (ch) {
case 'i':
inputFile = optarg;
break;
case 'o':
outputFile = optarg;
break;
default:
break;
}
}
printf("input File: %s\n", inputFile);
readImage(inputFile, &image);
writeImage(outputFile, &image);
return 0;
}发布于 2022-10-17 13:13:02
感谢您的更新。
IMHO,bmp文件格式是愚蠢设计的,其中包括一些导致意外行为的陷阱。您可能已经发现,如果我们将2字节的MagicNumber "BM“放在标头结构中,大多数编译器会自动地为边界对齐再放2字节。
另一个缺陷是,我们需要将一行(行)的字节计数保持为字对齐的4的倍数。然后,每一行的起始地址都位于单词边界,尽管我不确定它能使程序运行得更快。无论如何,如果行的字节数不是4的倍数(即宽度不是4的倍数),我们需要在每行的末尾放置额外的虚拟字节来进行调整。那么,请将您的读写功能修改为:
readImage:
// Read in each pixel
int padding = image->metadata.width % 4; // add this line
for (int i = 0; i < image->metadata.height; i++){
for(int j = 0; j < image->metadata.width; j++){
ImageColors px;
if( fread(&px, sizeof(ImageColors), 1, imageFile) < 1 ) {
printf("Error while reading bmp pixel.\n");
return;
}
image->pixels[i][j] = px;
}
for (int j = 0; j < padding; j++) getc(imageFile); // add this line
}
writeImage:
// Read in each pixel
int padding = image->metadata.width % 4; // add this line
for (int i = 0; i < image->metadata.height; i++){
for(int j = 0; j < image->metadata.width; j++){
if( fwrite(&image->pixels[i][j], sizeof(ImageColors), 1, imageFile) < 1 ) {
printf("Error while wr bmp pixel.\n");
fclose(imageFile);
exit(EXIT_FAILURE);
}
}
for (int j = 0; j < padding; j++) putc(0, imageFile); // add this line
}其中变量padding是字节填充的计数,可以根据width的值进行计算。
更新
尝试添加这一行:
fseek(imageFile, image->header.offset, SEEK_SET);就在台词前:
// Read in each pixel在readImage()中和在writeImage()中一样。
解释
bmp文件格式有几个版本,它们的头大小不同(这是另一个缺陷):
version header.offset (starting address of pixel data)
BMP v2 54
BMP v3 122
BMP v4 138虽然结构的定义是基于BMP v2的,但提供的bmp文件是在BMP v4中创建的。这样会导致头部数据与像素数据位置之间的冲突。这就是为什么您的文件比较显示了差异。
折叠图像文件的可查看性将取决于查看器软件。在我的环境中,查看图像是没有问题的。
理想情况下,我们应该准备几种类型的头结构,并根据版本使用其中的一种。实际上,扩展区域包含不太重要的数据,在大多数情况下我们可以跳过它们。
https://stackoverflow.com/questions/74047148
复制相似问题