В этом вопросе много недостатков - & ndash; слишком много, чтобы разобраться в комментариях ...
Этот вопрос помечен как 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";
Обеспечить хранение данных пикселей с (в случае OP) фиксированным размером 512 раз; 512 байт, самое простое будет:
unsigned char pixeldata[512 * 512];
Хранение массива такого размера (512 & times; 512 = 262144 байт = 256 КБайт) в локальной переменной может рассматриваться как потенциальная проблема для некоторых людей. Альтернативой было бы использовать 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;
: SO: Почему «использование пространства имен std» считается плохой практикой?
Я добавил проверку успешности файловых операций. Файловые операции - это то, что всегда хорошо для отказа по многим причинам. Для записи в файл следует проверить даже fclose()
. Записанные данные могут кэшироваться до тех пор, пока файл не будет закрыт, и простая запись кэшированных данных в файл может завершиться ошибкой (поскольку это может привести к переполнению доступного пространства тома).
OP использовал магические числа (ширина и размер изображения), что считается плохой практикой. Это делает обслуживание кода недружественным и может быть труднее понять для других читателей: SO: Что такое магическое число и почему оно плохо?