问题描述
我已经打开了bmp文件(一个通道灰度),并将每个像素颜色以十六进制形式存储在新行中.在对数据进行一些处理之后(不是这个问题的重点),我需要从数据中导出一个bmp图像.如何加载文本文件(数据)并使用stb_image_write
?
I've already opened the bmp file( one channel grayscale) and stored each pixel color in a new line as hex.after some doing processes on the data (not the point of this question), I need to export a bmp image from my data.how can I load the textfile(data) and use 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");
}
}
}
推荐答案
这个问题有很多弱点–太多,无法在评论中加以解决...
There are a lot of weaknesses in the question – too much to sort this out in comments...
-
此问题标记为C ++.为什么容易出错的
fprintf()
?为什么不std::fstream
?它具有类似的功能(甚至更多),但是增加了类型安全性(printf()
系列无法提供).
This question is tagged C++. Why the error-prone
fprintf()
? Why notstd::fstream
? It has similar capabilities (if not even more) but adds type-safety (whichprintf()
family cannot provide).
fprintf()
的对应部分是 fscanf()
.格式器类似,但是与fprintf()
相比,必须在格式器中更仔细地配置存储类型.
The counter-part of fprintf()
is fscanf()
. The formatters are similar but the storage type has to be configured in formatters even more carefully than in fprintf()
.
如果第一个代码示例是尝试从datafile.x
读回像素...为什么选择datafile = fopen("pixeldata.x" , "w");
?要使用fopen()
打开文件进行读取,该文件应为"r"
.
If the first code sample is the attempt to read pixels back from datafile.x
... Why datafile = fopen("pixeldata.x" , "w");
? To open a file with fopen()
for reading, it should be "r"
.
char Image2[14] = "image_out.bmp";
是正确的(如果我计算正确),但是维护不友好.让编译器为您完成工作:
char Image2[14] = "image_out.bmp";
is correct (if I counted correctly) but maintenance-unfriendly. Let the compiler do the work for you:
char Image2[] = "image_out.bmp";
为像素数据提供存储(在OP情况下),固定大小为512× 512字节,最简单的是:
To provide storage for pixel data with (in OPs case) fixed size of 512 × 512 bytes, the simplest would be:
unsigned char pixeldata[512 * 512];
将某些大小的数组(512 x 512 = 262144字节= 256 KB)存储在局部变量中可能被某些人视为潜在问题.替代方法是使用std::vector<unsigned char> pixeldata;
. (std::vector
在堆内存中动态分配存储,在这些内存中,局部变量通常位于一种堆栈内存中,而堆栈内存的大小通常有限.)
Storing an array of that size (512 × 512 = 262144 Bytes = 256 KByte) in a local variable might be seen as potential issue by certain people. The alternative would be to use a std::vector<unsigned char> pixeldata;
instead. (std::vector
allocates storage dynamically in heap memory where local variables usually on a kind of stack memory which in turn is usually of limited size.)
关于std::vector<unsigned char> pixeldata;
,我看到两个选择:
Concerning the std::vector<unsigned char> pixeldata;
, I see two options:
-
具有预分配的定义:
definition with pre-allocation:
std::vector<unsigned char> pixeldata(512 * 512);
以便可以像上面的数组一样使用它.
so that it can be used just like the array above.
没有预分配的定义:
std::vector<unsigned char> pixeldata;
这将允许将每个读取的像素添加到std::vector::push_back()
的末尾.
也许值得一开始就保留最终的大小,因为从一开始就知道:
That would allow to add every read pixel just to the end with std::vector::push_back()
.
May be, it's worth to reserve the final size beforehand as it's known from beginning:
std::vector<unsigned char> pixeldata;
pixeldata.reserve(512 * 512); // size reserved but not yet used
所以,这就是最终的样子:
So, this is how it could look finally:
#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,但将对错误报告"做出反应.)
Please, take this code with a grain of salt. I haven't compiled or tested it. (I leave this as task to OP but will react on "bug reports".)
我默默地删除了using namespace std;
: SO:为什么使用命名空间标准"被认为是不好的做法?
我添加了对文件操作成功的检查.由于很多原因,文件操作总是很容易失败.对于文件写入,甚至应测试fclose()
.写入的数据可能会一直缓存到文件关闭,而仅将缓存的数据写入文件可能会失败(因为这可能会使可用的卷空间溢出).
I added checking of success of file operations. File operations are something which are always good for failing for a lot of reasons. For file writing, even the fclose()
should be tested. Written data might be cached until file is closed and just writing the cached data to file might fail (because just this might overflow the available volume space).
OP使用了幻数(图像的宽度和大小),这被认为是不好的做法.它使代码维护变得不友好,并且可能使其他读者更难以理解: SO:什么是幻数,为什么不好?
OP used magic numbers (image width and size) which is considered as bad practice. It makes code maintenance-unfriendly and might be harder to understand for other readers: SO: What is a magic number, and why is it bad?
这篇关于如何使用stb_image将像素颜色数据写入bmp图像文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!