【问题标题】:RLE algorithm applied to bmp fileRLE 算法应用于 bmp 文件
【发布时间】:2026-01-21 07:00:01
【问题描述】:

我目前在尝试将运行长度算法应用于 .bmp 图片时遇到问题。当我进行编码时,一切正常,但在解码时出现问题,我无法弄清楚,即我无法读取重复像素的数量,因此我的输出是空白图像。当我使用调试器时,无法从二进制文件中正确读取重复像素的数量(在位图文件上应用 RLE 的结果)。这是我的代码

#include<stdlib.h>
#include <stdint.h>

//structure defiens bitmap header
struct BITMAPFILEHEADER{
   uint8_t type[2];//type of file (bit map)
   uint32_t size;//size of file
   uint16_t reserved1;//
   uint16_t reserved2;//
   uint32_t offsetbits;//off set bits
} __attribute__ ((packed));

struct BITMAPINFOHEADER{
   uint32_t size;//bitmap size
  // uint16_t w2;
   uint32_t width;//width of bitmap
  //uint16_t h2;
   uint32_t height;//hight of bitmap

   uint16_t planes;
   uint16_t bitcount;
   uint32_t compression;// compression ratio (zero for no compression)
   uint32_t sizeimage;//size of image
   long xpelspermeter;
   long ypelspermeter;
   uint32_t colorsused;
   uint32_t colorsimportant;
} __attribute__ ((packed));


 //const char* INPUT_FILE = "/home/bogdan/bee.bmp";
const char* INPUT_FILE = "/home/bogdan/Linux.bmp";
const char* ENCODED_FILE = "/home/bogdan/encoded.bin";
const char* DECODED_FILE = "/home/bogdan/decoded.bmp";

typedef struct SINGLE_PIXEL{
    uint8_t green;//Green level 0-255
    uint8_t red;  //Red level 0-255
} PIXEL;

int comparePixels(PIXEL, PIXEL);
void encode();
void decode(char*);

int main()
{
    encode();
    decode(ENCODED_FILE);
    return 0;
}

void encode() {
    uint32_t i=0;//to count pixels read
    uint32_t pixno=0;//number of pixels to read

    struct BITMAPFILEHEADER source_head;//to store file header
    struct BITMAPINFOHEADER source_info;//to store bitmap info header
    PIXEL pixel;// the current pixel

    FILE *in;// bitmap imput pointer file
    FILE *out;//output file pointer

    if(!(in=fopen(INPUT_FILE,"rb")))//open in binary read mode
    {
    printf("\ncan not open file");//error at opening file
    exit(-1);
    }


out=fopen(ENCODED_FILE,"wb");//opne in binary write mode
//read the headers to source file
fread(&source_head,sizeof(struct BITMAPFILEHEADER),1,in);
fread(&source_info,sizeof(struct BITMAPINFOHEADER),1,in);

//write the headers to the output file
fwrite(&source_head,sizeof(struct BITMAPFILEHEADER),1,out);
fwrite(&source_info,sizeof(struct BITMAPINFOHEADER),1,out);

//cumpute the number of pixels to read
pixno=source_info.width*source_info.height;

// init list of pixels
PIXEL pixArr[pixno];
printf("total pixels: %d", pixno);

//printf("w:%f h:%u pn:%lu", (source_head.size/1024.0/1024), source_info.height, pixno);
uint32_t sum = 0;
//read, modify and write pixels
for(i=0;i<pixno;++i)
{
    //read pixel form source file
    fread(&pixel,sizeof(PIXEL),1,in);
    pixArr[i] = pixel;
}
for (i = 0; i < pixno; i++) {
   // printf ("i = %d\tred = %d green = %d blue = %d\n",i, pixArr[i].red, pixArr[i].green, pixArr[i].blue);
    int runlength = 1;
    while ((i + 1) < pixno) {
        if (comparePixels(pixArr[i], pixArr[i+1]) == 0){
        // printf ("i = %d\t red = %d green = %d blue = %d\n",i, pixArr[i].red, pixArr[i].green, pixArr[i].blue);
            runlength++;
            i++;
        } else {
            break;
        }
    }

    //fprintf(out, "%d", runlength);
    fwrite(&runlength, sizeof(runlength), 1, out);
    fwrite(&pixel,sizeof(PIXEL),1,out);
    sum += runlength;
    runlength = 0;
}
    //write the modification to the output file
    //close all fiels
    fclose(in);
    fclose(out);
    printf("sum = %d",sum);
}

void decode(char * filePath) {
    uint32_t i=0;//to count pixels read
    uint32_t j=0;
    uint32_t totalPixels=0;//number of pixels to read
    uint32_t pixelRepetition = 1;
    struct BITMAPFILEHEADER source_head;//to store file header
    struct BITMAPINFOHEADER source_info;//to store bitmap info header
    PIXEL pixel;// the current pixel

    FILE *in;// bitmap encoded pointer file
    FILE *out;//decoded bitmap file pointer
    if (!(in = fopen(filePath, "rb"))) {
        printf("\ncan not open file");
        exit(-1);
    }
    out = fopen(DECODED_FILE, "wb");
    //read the headers to source file
   fread(&source_head,sizeof(struct BITMAPFILEHEADER),1,in);
   fread(&source_info,sizeof(struct BITMAPINFOHEADER),1,in);

   //write the headers to the output file
   fwrite(&source_head,sizeof(struct BITMAPFILEHEADER),1,out);
   fwrite(&source_info,sizeof(struct BITMAPINFOHEADER),1,out);

   totalPixels=source_info.width*source_info.height;

   while(i < totalPixels) {

        fread(&pixelRepetition, sizeof(pixelRepetition), 1, out);
        fread(&pixel,sizeof(PIXEL),1,in);

       for (j = 0; j < pixelRepetition; j++) {
            fwrite(&pixel,sizeof(PIXEL),1,out);
       }
       i += pixelRepetition;
    }

    fclose(in);
    fclose(out);
}

int comparePixels(PIXEL px1, PIXEL px2) {
    if (px1.red == px2.red && px1.green == px2.green && px1.blue == px2.blue) {
      return 0;
    } else {
        return -1;
    }
}

我的实现工作如下:我读取了一个 bmp 文件的标题并将其直接放到另一个文件中。之后,我比较像素以查看它们是否具有相同的 RGB 值。如果这是真的(根据 comparePixels 函数),我将连续相同像素的数量和一个像素(重复的像素)放入文件中。这是编码阶段。在解码时,我正在读取图像的标题,然后我试图读取重复次数(默认为 1,表示没有重复像素)和重复的像素。我将非常感谢任何类型的帮助。谢谢。

【问题讨论】:

  • 嗨。要求人们发现代码中的错误并不是特别有效。您应该使用调试器(或添加打印语句)来隔离问题,方法是跟踪程序的进度,并将其与预期发生的情况进行比较。一旦两者发生分歧,你就发现了你的问题。 (然后如果有必要,你应该构造一个minimal test-case。)
  • 另外,“有问题”不是一个有用的描述。您应该准确地描述您看到的输出,以及它与您预期的比较。
  • 相信我,我在这里发布代码的原因是我没有设法使用调试器发现错误。您没有注意我的描述,我说:“我的第一个想法是我没有正确地从二进制文件中读取 int”。如果你知道一些可以帮助我的事情,如果你愿意,请说出来,否则让我们避免这些讨论。
  • 恐怕这不是 SO 的工作方式;它不是众包调试器。我鼓励您改进您的问题,以便更快地获得更好的帮助,而不是被关闭。另外,请注意“我的第一个想法……”不是对您程序的行为/症状的描述。
  • 尝试一个小的手工构建示例,您知道您希望阅读代码做什么。在调试器中观察它,看看它在哪里做了你没想到的事情。 (或者“玩电脑”,在纸上逐行逐个变量地处理代码。)找出原因,修复它,继续下一个错误。这是 C,三重检查指针或数组引用的使用情况,以确保它们在界限内。

标签: c bitmap


【解决方案1】:

您只是在重复写入 out 您读取的最后一个像素in

fwrite(&runlength, sizeof(runlength), 1, out);
fwrite(&pixel,sizeof(PIXEL),1,out);

您需要写出您的 当前 像素:

fwrite(pixArr[i], sizeof(PIXEL),1,out);

【讨论】:

  • 输出的十六进制转储应该立即显示错误。
  • @Matt:同意。 OP 认为 repetition 值读错了,但代码表明这不应该是问题。
  • 首先,谢谢大家的好回答!!我发现,确实,我的编码程序是错误的,我已经纠正了它。现在我有另一个问题,如何从二进制文件中读取 int?因为我没有使用 fscanf(in, "%d", &amp;pixelRepetition); 之类的东西提前谢谢。
  • @Costy: ..??您在这里使用了fread (&amp;pixelRepetition ..,这“从二进制文件中读取int”的相对好方法。 (还有其他一些好方法;fscanf 不是。)如有疑问,请发布新问题。
  • 如果您想要可移植的代码和可移植的文件格式,请注意字节序。