如何使用stb_image将像素颜色数据写入bmp图像文件?

问题描述 投票:0回答:1

我已经打开了bmp文件(一个通道灰度),并将每个像素颜色以十六进制的形式存储在一个新行中。在对数据进行一些处理之后(不是这个问题的重点),我需要从我的数据中导出一个bmp图像。如何加载文本文件(数据)并使用stb_image_write

像素到图像:

#include <cstdio>
#include <cstdlib>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"


using namespace std;


int main() {
    FILE* datafile ;
    datafile = fopen("pixeldata.x" , "w");

    unsigned char* pixeldata ;//???

    char Image2[14] = "image_out.bmp";

    stbi_write_bmp(Image2, 512, 512, 1, pixeldata);

图像到像素:

#include <cstdio>
#include <cstdlib>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"


using namespace std;


const size_t total_pixel = 512*512;
int main() {
    FILE* datafile ;
    datafile = fopen("pixeldata.x" , "w");

    char Image[10] = "image.bmp";
    int witdth;
    int height;
    int channels;
    unsigned char *pixeldata = stbi_load( (Image) , &witdth, &height, &channels, 1);

    if(pixeldata != NULL){
        for(int i=0; i<total_pixel; i++)
        {   
            fprintf(datafile,"%x%s", pixeldata[i],"\n");
        }
    }
}
c++ image bmp stb-image
1个回答
1
投票

这个问题有很多弱点 - 在评论中对此进行排序太多了......

  1. 这个问题标记为C ++。为什么容易出错的fprintf()?为什么不std::fstream?它具有类似的功能(如果不是更多),但增加了类型安全性(printf()家族无法提供)。
  2. fprintf()的反对部分是fscanf()。格式化程序类似,但存储类型必须在格式化程序中比在fprintf()中更仔细地配置。
  3. 如果第一个代码示例是尝试从datafile.x读取像素...为什么datafile = fopen("pixeldata.x" , "w");?要使用fopen()打开文件进行阅读,应该是"r"
  4. char Image2[14] = "image_out.bmp";是正确的(如果我计算正确)但维护不友好。让编译器为您完成工作: char Image2[] = "image_out.bmp";

为像素数据提供存储(在OPs情况下)固定大小为512×512字节,最简单的是:

unsigned char pixeldata[512 * 512];

在局部变量中存储该大小的数组(512×512 = 262144字节= 256 KB)可能被某些人视为潜在问题。替代方案是使用std::vector<unsigned char> pixeldata;代替。 (std::vector在堆内存中动态分配存储,其中局部变量通常位于一种堆栈内存上,而堆栈内存的大小通常有限。)

关于std::vector<unsigned char> pixeldata;,我看到两个选择:

  1. 预分配的定义: std::vector<unsigned char> pixeldata(512 * 512); 所以它可以像上面的数组一样使用。
  2. 没有预先分配的定义: std::vector<unsigned char> pixeldata; 这将允许使用std::vector::push_back()将每个读取像素添加到最后。 可能是,值得预先保留最终尺寸,因为它从一开始就知道: std::vector<unsigned char> pixeldata; pixeldata.reserve(512 * 512); // size reserved but not yet used

所以,这就是它最终看起来的样子:

 #include <cstdio>
 #include <cstdlib>
 #include <iostream>
 #include <vector>
 #define STB_IMAGE_WRITE_IMPLEMENTATION
 #include "stb_image_write.h"

 int main()
 {
   const int w = 512, h = 512;
   // read data
   FILE *datafile = fopen("pixeldata.x" , "r");
   if (!datafile) { // success of file open should be tested ALWAYS
     std::cerr << "Cannot open 'pixeldata.x'!\n";
     return -1; // ERROR! (bail out) 
   }
   typedef unsigned char uchar; // for convenience
   std::vector<uchar> pixeldata(w * h);
   char Image2[] = "image_out.bmp";
   for (int i = 0, n = w * h; i < n; ++i) {
     if (fscanf(datafile, "%hhx", &pixeldata[i]) < 1) {
       std::cerr << "Failed to read value " << i << of 'pixeldata.x'!\n";
       return -1; // ERROR! (bail out) 
     }
   }
   fclose(datafile);
   // write BMP image
   stbi_write_bmp(Image2, w, h, 1, pixeldata.data());
   // Actually, success of this should be tested as well.
   // done
   return 0;
 }

一些额外的说明:

  1. 请把这个代码带上一粒盐。我没有编译或测试它。 (我将此作为任务留给OP,但会对“错误报告”做出反应。)
  2. 我默默地删除了using namespace std;SO: Why is “using namespace std” considered bad practice?
  3. 我添加了文件操作成功的检查。由于很多原因,文件操作总是有助于失败。对于文件编写,甚至应该测试fclose()。写入的数据可能会被缓存,直到文件关闭,只是将缓存的数据写入文件可能会失败(因为这可能会溢出可用的卷空间)。
  4. OP使用了魔术数字(图像宽度和大小),这被认为是不好的做法。它使代码维护变得不友好,并且可能更难理解其他读者:SO: What is a magic number, and why is it bad?
© www.soinside.com 2019 - 2024. All rights reserved.