[英]how can I write pixel color data to a bmp image file with stb_image?
我已经打开了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 ++。 为什么容易出错的fprintf()
? 为什么不std::fstream
? 它具有相似的功能(甚至更多),但是增加了类型安全性( printf()
系列无法提供)。
fprintf()
的对应部分是fscanf()
。 格式器类似,但是与fprintf()
相比,必须在格式器中更仔细地配置存储类型。
如果第一个代码示例是尝试从datafile.x
读取像素的原因...为什么datafile = fopen("pixeldata.x" , "w");
? 要使用fopen()
打开文件进行读取,该文件应为"r"
。
char Image2[14] = "image_out.bmp";
是正确的(如果我计算正确),但维护不友好。 让编译器为您完成工作:
char Image2[] = "image_out.bmp";
为了为像素数据提供固定大小为512×512字节的像素数据存储,最简单的方法是:
unsigned char pixeldata[512 * 512];
将某些大小的数组(512×512 = 262144字节= 256 KB)存储在局部变量中可能被某些人视为潜在问题。 另一种方法是使用std::vector<unsigned char> pixeldata;
代替。 ( std::vector
在堆内存中动态分配存储,其中局部变量通常位于一种堆栈存储器中,而堆栈存储器的大小通常有限。)
关于std::vector<unsigned char> pixeldata;
,我看到两个选择:
预先分配的定义:
std::vector<unsigned char> pixeldata(512 * 512);
这样就可以像上面的数组一样使用它。
没有预分配的定义:
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;
}
一些附加说明:
请将此代码加一粒盐。 我还没有编译或测试它。 (我将其作为任务留给OP,但将对“错误报告”做出反应。)
我using namespace std;
静默删除了using namespace std;
: SO:为什么“使用命名空间标准”被认为是不好的做法?
我添加了文件操作成功检查。 由于很多原因,文件操作总是很容易失败。 对于文件写入,甚至应测试fclose()
。 写入的数据可能会一直缓存到文件关闭,而仅将缓存的数据写入文件可能会失败(因为这可能会使可用的卷空间溢出)。
OP使用了魔术数字(图像宽度和大小),这被认为是不好的做法。 它使代码维护变得不友好,并且可能使其他读者更难理解: SO:什么是幻数,为什么不好?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.