You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从.pgm文件提取并显示隐藏文本?求代码实现建议

问题描述

需要读取P5格式的灰度PGM文件,提取每个像素的最低有效位(LSB),每8个像素的LSB组合成1字节隐藏文本,转换为ASCII字符后显示隐藏消息。目前已编写部分C语言代码,但在以下环节存在困惑:

  • 正确提取单个像素的LSB
  • 将LSB分组转换为ASCII字符
  • 实现读取到特定标识后停止的逻辑
  • 正确显示提取出的字符
现有代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

//Clear PGM (XV) comments.
void pgmCommentClear(FILE *disk){
unsigned char  ch;
   fread(&ch, 1, 1, disk);
   if (ch != '#') {
      fseek(disk, -1, SEEK_CUR);
      return;
   }
   do {
      while (ch != '\n') fread(&ch, 1, 1, disk);
   } while (ch == '#');
   pgmCommentClear(disk);
}

//Read PGM formatted image (1D array). 
unsigned char *PGM_FILE_READ_1D(char *FileName, int *Width, int *Height, int *color) { 
int   pmax;
char  ch;
char  type[3];
unsigned char *Image;
FILE *disk;
   if ((disk = fopen(FileName, "rb")) == NULL) {
      return NULL;
   }
   fscanf(disk, "%s", type);
   if (!strcmp(type, "P6")) *color = 1;
                       else *color = 0;
   fread(&ch, 1, 1, disk); 
   pgmCommentClear(disk);
   fscanf(disk, "%d", Width);
   fscanf(disk, "%d", Height);
   fscanf(disk, "%d", &pmax);
   fread(&ch, 1, 1, disk);
   if (*color == 1) {
      Image = (unsigned char *)calloc(*Height * *Width * 3, sizeof(unsigned char));
      fread(Image, 1, (*Height * *Width * 3), disk);
   } else {
      Image = (unsigned char *)calloc(*Height * *Width, sizeof(unsigned char));
      fread(Image, 1, (*Height * *Width), disk);
  }
   fclose(disk);
   return Image;
}

//function to convert binary to decimal
int BinaryToDec(int array[]) {
  int decimal=0;
  int m=1;
  for(int i=7; i>=0; i--){
    decimal+= array[i]*m;
    m *= 2;
  }
  if(array[0] == 1) decimal *= -1;
  printf("decimal: %d\n", decimal);
  return decimal;
}

void DecToBinary(int dec){
    int binary[8];
    for(int i=0; i<=8; i++){
        if(dec & (1 << i)) binary[i] = 1;
            else binary[i] = 0;
    }
    printf("binaryform:");
    for(int i=7; i>=0; i--){
        printf("%d", binary[i]);
    }
    printf("\n");
}

int main(void){
   char *fileName = "hw10.pgm";
  
   int Width, Height, color;

   unsigned char *Image;
   Image = PGM_FILE_READ_1D(fileName, &Width, &Height, &color);     

   //int size = Width*Height;
   int size = 50;
   
   int array[8];
  
   int xCount =0;
   
   for(int i=0; i<size; i++){
      int mask=1;
      for(int k=0; k<8; k++){
         array[k] = Image[i]&mask;
         mask<<1;
      }
      
      printf("Image: %d\n", Image[i]);
      DecToBinary(Image[i]); 
      BinaryToDec(array);  
     
   } 
}
部分运行输出
Image: 214
binaryform:11010110
decimal: 0
Image: 213
binaryform:11010101
decimal: -255
Image: 208
binaryform:11010000
decimal: 0
Image: 214
binaryform:11010110
decimal: 0
Image: 215
实现建议

1. 正确提取单个像素的LSB

每个像素仅需提取最低位,无需读取8位。单个像素的LSB提取方式为:

// 取当前像素的最低有效位,结果为0或1
int lsb = Image[i] & 0x01;

你当前代码中对每个像素循环取8位是错误的,这是读取单个像素的所有二进制位,而非逐个像素取LSB。

2. 分组LSB生成ASCII字符

需要维护计数器和字符变量,每收集8个LSB就组合成一个完整的ASCII字符:

  • 初始化char hidden_char = 0,int bit_count = 0
  • 每获取一个LSB,将hidden_char左移1位,再与LSB进行按位或操作
  • 当bit_count达到8时,输出该字符,然后重置计数器和字符变量

示例代码片段:

char hidden_char = 0;
int bit_count = 0;
int total_pixels = Width * Height;

for (int i = 0; i < total_pixels; i++) {
    int lsb = Image[i] & 0x01;
    hidden_char = (hidden_char << 1) | lsb;
    bit_count++;

    if (bit_count == 8) {
        // 输出字符,可添加停止判断
        printf("%c", hidden_char);
        // 重置状态
        hidden_char = 0;
        bit_count = 0;
    }
}

3. 实现停止逻辑

常见的停止方式有两种:

  • 空字符终止:当生成的hidden_char为'\0'时,立即停止提取
  • 自定义标识终止:比如检测到连续的"END"字符,需要维护缓冲区记录最近生成的几个字符,匹配时停止

空字符终止的示例:

if (bit_count == 8) {
    if (hidden_char == '\0') {
        break; // 遇到结束符停止
    }
    printf("%c", hidden_char);
    hidden_char = 0;
    bit_count = 0;
}

4. 修复现有代码的错误

  • BinaryToDec函数中的符号位处理多余:ASCII字符是无符号的,不需要将最高位作为符号位计算负数
  • DecToBinary函数的循环条件错误:i<=8应改为i<8,避免越界访问数组
  • mask<<1未赋值:应改为mask <<= 1,否则mask值不会更新
  • 主函数中size硬编码为50:应改为Width * Height以遍历所有像素

5. 完整提取逻辑示例

修改后的main函数核心部分:

int main(void){
   char *fileName = "hw10.pgm";
   int Width, Height, color;
   unsigned char *Image = PGM_FILE_READ_1D(fileName, &Width, &Height, &color);     
   if (!Image) {
       printf("Failed to read image\n");
       return 1;
   }

   char hidden_char = 0;
   int bit_count = 0;
   int total_pixels = Width * Height;
   printf("Hidden message: ");

   for (int i = 0; i < total_pixels; i++) {
       int lsb = Image[i] & 0x01;
       hidden_char = (hidden_char << 1) | lsb;
       bit_count++;

       if (bit_count == 8) {
           if (hidden_char == '\0') {
               break;
           }
           printf("%c", hidden_char);
           hidden_char = 0;
           bit_count = 0;
       }
   }
   printf("\n");
   free(Image); // 记得释放内存
   return 0;
}

内容的提问来源于stack exchange,提问作者brocoli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 15:40:48