How to load an JPEG image into a char array C++? - c++

i want to store an JPEG image into a normal unsigned char array, i'd used ifstream to store it; however, when i checked if the array i'd stored is correct or not ( by rewrite it again to an JPEG image), the image that i rewrote by using the stored array couldn't show correctly, so i think the problem must come from the technique that i use to store the image into an array is not correct. I want an array which can be stored perfectly so that i can use it to rewrite back into a JPEG image again.I'd really appreciate if anyone can help me solve this problem!
int size = 921600;
unsigned char output[size];
int i = 0;
ifstream DataFile;
DataFile.open("abc.jpeg");
while(!DataFile.eof()){
DataFile >> output[i];
i++;
}
/* i try to rewrite the above array into a new image here */
FILE * image2;
image2 = fopen("def.jpeg", "w");
fwrite(output,1,921600, image2);
fclose(image2);

There are multiple problems in the shown code.
while(!DataFile.eof()){
This is always a bug. See the linked question for a detailed explanation.
DataFile >> output[i];
The formatted extraction operator, >>, by definition, skips over all white space characters and ignores them. Your jpg file surely has bytes 0x09, 0x20, and a few others, somewhere in it, and this automatically skips over and does not read them.
In order to do this correctly, you need to use read() and gcount() to read your binary file. Using gcount() correctly should also result in your code detecting the end-of-file condition properly.

Make sure to add error check when opening files. Find the file size and read in to the buffer according to the filesize.
You might also look in to using std::vector<unsigned char> for character storage.
int main()
{
std::ifstream DataFile("abc.jpeg", std::ios::binary);
if(!DataFile.good())
return 0;
DataFile.seekg(0, std::ios::end);
size_t filesize = (int)DataFile.tellg();
DataFile.seekg(0);
unsigned char output[filesize];
//or std::vector
//or unsigned char *output = new unsigned char[filesize];
if(DataFile.read((char*)output, filesize))
{
std::ofstream fout("def.jpeg", std::ios::binary);
if(!fout.good())
return 0;
fout.write((char*)output, filesize);
}
return 0;
}

Related

Binary open and copy image file c++

I want to copy one image file to another new file. This is my method to do this:
std::ofstream myOutpue;
std::ifstream mySource;
//int i = 0;
mySource.open(ofn.lpstrFile, std::ios::binary);
myOutpue.open("im4.jpg", std::ios::binary);
char buffer;
char bufferToSave[100];
if (mySource.is_open())
{
//client->sendFilePacket(FileStates::START_SAVE, buffer, false,i);
i++;
while (!mySource.eof())
{
mySource >> std::noskipws >> buffer;
myOutpue << buffer;
//client->sendFilePacket(FileStates::CONTINUE_SAVE, buffer, false,i);
i++;
}
}
i++;
//client->sendFilePacket(FileStates::END_SAVE, buffer, true,i);
mySource.close();
//myOutpue.close();
This method work correctly, but my problem is that i want to copy char/bit's and send it to another client. When i doing this by each char , that not work correctly so i want to make a bigger buffor(for example char t[512]) or something like that and copy them to new file.
I try to doing this like that:
std::ofstream myOutpue;
std::ifstream mySource;
mySource.open(ofn.lpstrFile, std::ios::binary);
myOutpue.open("im4.jpg", std::ios::binary);
char buffer;
char bufferToSave[100];
if (mySource.is_open())
{
//client->sendFilePacket(FileStates::START_SAVE, buffer, false,i);
i++;
while (!mySource.eof())
{
if (i == 100)
{
for (int i = 0; i < 100; i++)myOutpue << bufferToSave[i];
i = 0;
}
mySource >> std::noskipws >> buffer;
bufferToSave[i] = buffer;
//myOutpue << buffer;
//client->sendFilePacket(FileStates::CONTINUE_SAVE, buffer, false,i);
i++;
}
}
i++;
//client->sendFilePacket(FileStates::END_SAVE, buffer, true,i);
mySource.close();
myOutpue.close();
But i get image that i can't open.
So my question is how to read file to get more bits from it and that create me the same image as original.
You have an error in your original file copy algorithm in that you should never loop using eof() as the end flag.
See: Why is iostream::eof inside a loop condition considered wrong?
Copying files can be a simple as this:
std::ofstream("output.jpg", std::ios::binary) << std::ifstream("input.jpg", std::ios::binary).rdbuf();
It uses a special overload of the output operator when passing an std::istream buffer (using rdbuf()). It copies the whole stream.
When reading a whole buffer you should use std::istream::read:
std::ifstream ifs("input.jpg", std::ios::binary)
char buffer[1025]; // create a buffer
// keep going as long as the reading succeeds
while(ifs.read(buffer, sizeof(buffer)))
{
// ifs.gcount() is the number of chars read successfully
client->sendFilePacket(buffer, ifs.gcount()); // send all bytes
}
I know it's been a long time, but reading these topic I found the solution:
std::ifstream ifs(ofn.lpstrFile, std::ios::binary);
std::ofstream myOutpue;
char buffer[1024]; // create a buffer
myOutpue.open("output.jpg", std::ios::binary);
//client->sendFilePacket(FileStates::START_SAVE, buffer, false, i);
while (ifs.read(buffer, sizeof(buffer)))
{
myOutpue.write(buffer, ifs.gcount());
}
//
myOutpue.write(buffer, ifs.gcount());
myOutpue.close();
Note: My answer is similar to #dawcza94, but to avoid black screen, after the loop you have to save the rest of the reading, because in the loop you save only what fits in the buffer, and the rest you ignore. Sometimes it happens that the rest can be a few characters long, and it looks like the images are the same size, but they aren't.
Note2: I posted here to help those who are still in trouble as I was!!
C++ FAQ:
You probably want to use iostream’s read() and write() methods instead of its >> and << operators. read() and write() are better for binary mode; >> and << are better for text mode.
You can specify how much you want to read. With gcount you can ask, how much characters are read successfully. Same goes for write.
I try with this code:
std::ifstream ifs(ofn.lpstrFile, std::ios::binary);
std::ofstream myOutpue;
char buffer[1024]; // create a buffer
myOutpue.open("output.jpg", std::ios::binary);
//client->sendFilePacket(FileStates::START_SAVE, buffer, false, i);
while (ifs.read(buffer, sizeof(buffer)))
{
//client->sendFilePacket(FileStates::CONTINUE_SAVE, buffer, false, ifs.gcount());
myOutpue.write(buffer, ifs.gcount());
}
//client->sendFilePacket(FileStates::END_SAVE, buffer, true, i);
myOutpue.close();
But when i doing this like that, in my copy of image i got only half of original image and half of black screen( number of kb is the same like in original file), so i don't know what's a problem with that ?
Instead of using "manual" copy, try using ifstream::read method

How to check whether ifstream is end of file in C++

I need to read all blocks of one large file(about 10GB) sequentially, the file contains many floats with a few strings, like this(each item splited by '\n'):
6.292611
-1.078219E-266
-2.305673E+065
sod;eiwo
4.899747e-237
1.673940e+089
-4.515213
I read MAX_NUM_PER_FILE items each time and process them and write to another file, but i don't know when the ifstream is ended.
Here is my code:
ifstream file_input(path_input); //my file is a text file, but i tried both text and binary mode, both failed.
if(file_input)
{
file_input.seekg(0,file_input.end);
unsigned long long length = file_input.tellg(); //get file size
file_input.seekg(0,file_input.beg);
char * buffer = new char [MAX_NUM_PER_FILE+MAX_NUM_PER_LINE];
int i=1,j;
char c,tmp[3];
while(file_input.tellg()<length)
{
file_input.read(buffer,MAX_NUM_PER_FILE);
j=MAX_NUM_PER_FILE;
while(file_input.get(c)&&c!='\n')
buffer[j++]=c; //get a complete item
//process with buffer...
itoa(i++,tmp,10); //int2char
string out_name="out"+string(tmp)+".txt";
ofstream file_output(out_name);
file_output.write(buffer,j);
file_output.close();
}
file_input.close();
delete[] buffer;
}
My code goes wrong, length is bigger than real file size. I have tried file_input.good() or !file_input.eof(), they didn't work, getline(file_input,s) is good, but it is much slower than read, i want read, but i don't know how to check whether ifstream is end-of-file.
I do my work in WINDOWS 7 with VS2010.
I have searched, but there are not any answer about it, How to open a file using ifstream and keep reading it until the end this link can't answer my question.
Update, Problem solved
Hi everyone, I have figured it out that it's my fault. Both while(file_input.tellg()<length) and while(file_input.peek()!=EOF) work fine! while(file_input.peek()!=EOF) is recommended.
The extra items written after the end-of-file is the left items in buffer written in the last time.
Here is the correct code:
ifstream file_input(path_input);
if(file_input)
{
//file_input.seekg(0,file_input.end);
//unsigned long long length = file_input.tellg(); //get file size
//file_input.seekg(0,file_input.beg);
char * buffer = new char [MAX_NUM_PER_FILE+MAX_NUM_PER_LINE];
int i=1,j;
char c,tmp[3];
while(file_input.peek()!=EOF)
{
memset(buffer,0,sizeof(char)*(MAX_NUM_PER_FILE+MAX_NUM_PER_LINE)); //clear first!
file_input.read(buffer,MAX_NUM_PER_FILE);
j=MAX_NUM_PER_FILE;
while(file_input.get(c)&&c!='\n')
buffer[j++]=c;
itoa(i++,tmp,10);//int2char
string out_name="out"+string(tmp)+".txt";
ofstream file_output(out_name);
file_output.write(buffer,strlen(buffer)); //use the correct buffer size instead of j
file_output.close();
}
file_input.close();
delete[] buffer;
}
while( file_input.peek() != EOF )
{
// code
}
Basically peek() will read the next char without extracting it.
So you can simply compare it to EOF.

Quickly convert raw data to hex string in c++

I'm reading data from a file and trying to display the raw data as 2 digit hex strings.
I'm using the Qt framework, specifically the QTextEdit.
I've tried a bunch of different approaches and have almost accomplished what I want it to do, however it has some unexpected errors I don't know anything about.
Currently this is my implementation:
1) Read in the data:
ifstream file (filePath, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size+1];
file.seekg(0, ios::beg);
file.read(memblock, size);
file.close();
}
2) Create a single QString that will be used (because QTextEdit requires a QString):
QString s;
3) Loop through the array appending each successive character to the QString s.
int count = 0;
for(i=0;i<size;i++)
{
count++;;
s.append(QString::number(memblock[i], 16).toUpper());
s.append("\t");
if (count == 16)
{
s.append("\n");
count -= 16;
}
}
Now this works fine, except when it reaches a character FF, it appears as FFFFFFFFFFFFFFFF
So my main questions are:
Why do only the 'FF' characters appear as 'FFFFFFFFFFFFFFFF' instead?
Is there a way to convert the char data to base 16 strings without using QString::number?
I want this implementation to be as fast as possible, so if something like sprintf could work, please let me know, as I would guess that might be faster that QString::number.
QString can't be used for binary data. You should use QByteArray instead. It can be easily created from char* buffer and can be easily converted to hex string using toHex.
QByteArray array(memblock, size);
textEdit->setText(QString(array.toHex()));
QString::number doesn't have an overload that takes a char, so your input is being promoted to an int; consequently you're seeing the effects of sign extension. You should be seeing similar behavior for any input greater than 0x7F.
Try casting the data prior to calling the function.
s.append(QString::number(static_cast<unsigned char>(memblock[i]), 16).toUpper());

Problems while trying to Read Binary File C++

I'm writing a simple console application in Visual Studio C++. I want to read a binary file with .cer extension to a byte array.
ifstream inFile;
size_t size = 0;
char* oData = 0;
inFile.open(path, ios::in|ios::binary);
if (inFile.is_open())
{
size = inFile.tellg(); // get the length of the file
oData = new char[size+1]; // for the '\0'
inFile.read( oData, size );
oData[size] = '\0' ; // set '\0'
inFile.close();
buff.CryptoContext = (byte*)oData;
delete[] oData;
}
But when I launch it, I receive in all the oData characters the same char, every time another one, For example:
oData = "##################################################...".
Then I tried another way:
std::ifstream in(path, std::ios::in | std::ios::binary);
if (in)
{
std::string contents;
in.seekg(0, std::ios::end);
contents.resize(in.tellg());
in.seekg(0, std::ios::beg);
in.read(&contents[0], contents.size());
in.close();
}
Now the content has very strange values: a part of the values is correct, and a part is negative and strange values (maybe it is related to signed char and unsigned char?).
Does anyone have any idea?
Thanks ahead!
Looking at the first version:
What makes you think that tellg gets the size of the stream? It does not, it returns the current read position. You then go on to give a pointer to your data to buff.CryptoContents and promptly delete the data pointed to! This is very dangerous practice; you need to copy the data, use a smart pointer or otherwise ensure the data has the correct lifespan. It is likely the deletion is stomping your data with a marker to show it has been deleted if you're running in debug mode which is why you are getting the stream of identical characters.
I suspect your suggestion about signed and unsigned may be correct for the second but I can't say without seeing your file and data.
You are setting CryptoContext to point to your data by byte pointer, and after that you delete that data!
buff.CryptoContext = (byte*)oData;
delete[] oData;
After this lines CryptoContext is pointing to released and invalid data. Just keep oData array longer in memory and delete it after you are done with decoding or whatever you are doing with it.

Reading binary text into array?

I have a program that I need to read binary text into. I read the binary text via a redirection:
readData will be an executable made by my Makefile.
Example: readData < binaryText.txt
What I want to do is read the binary text, and store each character in the binary text file as a character inside a char array. The binary text is made up of 32 This is my attempt at doing so...
unsigned char * buffer;
char d;
cin.seekg(0, ios::end);
int length = cin.tellg();
cin.seekg(0, ios::beg);
buffer = new unsigned char [length];
while(cin.get(d))
{
cin.read((char*)&buffer, length);
cout << buffer[(int)d] << endl;
}
However, I keep getting a segmentation fault on this. Might anyone have any ideas on how to read binary text into a char array? Thanks!
I'm more a C programmer rather than a C++, but I think that you should have started your while loop
while(cin.get(&d)){
The easiest would be like this:
std::istringstream iss;
iss << std::cin.rdbuf();
// now use iss.str()
Or, all in one line:
std::string data(static_cast<std::istringstream&>(std::istringstream() << std::cin.rdbuf()).str());
Something like this should do the trick.
You retrieve the filename from the arguments and then read the whole file in one shot.
const char *filename = argv[0];
vector<char> buffer;
// open the stream
std::ifstream is(filename);
// determine the file length
is.seekg(0, ios_base::end);
std::size_t size = is.tellg();
is.seekg(0, std::ios_base::beg);
// make sure we have enough memory space
buffer.reserve(size);
buffer.resize(size, 0);
// load the data
is.read((char *) &buffer[0], size);
// close the file
is.close();
You then just need to iterate over the vector to read characters.
The reason why you are getting segmentation fault is because you are trying to access an array variable using a character value.
Problem:
buffer[(int)d] //d is a ASCII character value, and if the value exceeds the array's range, there comes the segfault.
If what you want is an character array, you already have that from cin.read()
Solution:
cin.read(reinterpret_cast<char*>(buffer), length);
If you want to print out, just use printf
printf("%s", buffer);
I used reinterpret_cast because it thought it is safe to convert to signed character pointer since most characters that are used would range from 0 ~ 127. You should know that character values from 128 to 255 would be converted wrongly.