Woking With BMP File in C++, Ubuntu - c++

I am trying to work with a bmp file in linux with g++ compiler. I am using C++ language.
I Need to load a .bmp file from the standard input. for example:
./a.out < test.bmp
So I need a Code to do this job. I think storing the whole .bmp file is good by I don't know how to do this.
I Tried this code but it didn't Work:
vector<int> bitmap;
int b;
while ( cin >> b ) {
bitmap.push_back(b);
cout << "!" << endl;
}
So How should I Do this?

cin >> b reads file in text mode, this is not for binary files. use something like this:
ifstream myFile ("test.bmp", ios::in | ios::binary);
to open stream for file, and then
if (!myFile.read (buffer, 100)) {
// do thomething with data in buffer
}

I Found an answer That Works Correctly.
This Code Reads The bmp_info_header from the *.bmp file from the standard input:
char bmpHeader[54];
cin.get(bmpHeader, 54);
the "54" in cin.get() tells the system to accept the max 54 numbers from the input and ignores the other.
now for example if we want to find the *.bmp size we should use this code:
int filesize = *((int*)(headers + 2));

Related

Editing bmp pixel by pixel [C++]

I want to make a program that will take an image and replace the Blue component of every pixel with 0.
So I wrote this. I have one bmp image in the folder and a copy of it and as the input file i put in the name of the original and as the output name i write the copy. But when i try to open the second one after the program works it doesnt open properly. Could anyone help?
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
ifstream ifs;
ofstream ofs;
char input[80];
char output[80];
cout<<"Input file name"<<endl;
cin>>input;
ifs.open(input, ios::binary);
if(!ifs)
{
cout<<"Error in opening file"<<endl;
system("pause");
return 0;
}
cout<<"Output file name"<<endl;
cin>>output;
ofs.open(output, ios::binary);
ifs.seekg(2);
int file_size;
ifs.read((char*)&file_size, sizeof(int));
ofs<<"Bitmap size: "<<file_size<<"\r\n";
ifs.seekg(10);
int beg;
ifs.read((char*)&beg, sizeof(int));
ofs<<"Beggining of image: "<<beg<<"\r\n";
ifs.seekg(18);
int columns;
ifs.read((char*)&columns, sizeof(int));
ofs<<"Column number: "<<columns<<"\r\n";
ifs.seekg(22);
int rows;
ifs.read((char*)&rows, sizeof(int));
ofs<<"Row number: "<<rows<<"\r\n";
int image_size=0;
columns+=(3*columns)%4;
image_size=3*columns*rows;
ofs<<"Size of image"<<image_size<<"\r\n";
ifs.seekg(beg);
unsigned char R,G,B;
for(int i=beg; i<image_size+beg; i+=3)
{
ofs.seekp(i);
ofs<<char(0);
}
system("pause");
return 0;
}
There is no image file format that contains text like "Bitmap size: ", "Beginning of image: ", "Column number: ", "Row number: ", and "Size of image".
Even if there was such a file format, you are not writing "Beginning", you are writing "Beggining", and that would not work. Computers tend to be very partial to proper spelling.
Even if there was such a file format, it would not be the same as the file format that you are reading, because you are reading an int at offset 2 and interpreting it as some kind of file size, but you are not writing any size at offset 2 of your output file.
So, to cut a long story short, you have to have a very clear specification of the file format you are reading, (which you have told us nothing about,) and you also have to follow this exact same specification in writing the file.
Making up your own file format specification as you go along will not work.
Also, in the future, keep in mind that on stackoverflow, phrases like "it doesnt open properly" are not considered valid descriptions of technical issues. Be specific about precisely what is happening.
Hint: you appear to be trying to edit the file in-place, by seeking to individual bytes and overwriting them with zero. That won't work on an empty file. Copy the entire contents of the original file to the new filename, and then go seeking and overwriting bytes on the copy.
So I'll post my comment as answer:
I don't know much about BMP format, but... does it really contains strings such a "Size of image" or "Row number: "?
If not, remove ofs<<"Beggining of image: "<<beg<<"\r\n"; etc., I think that you meant cout instead of ofs.
Ok so in stead of reading a file to modify I just copy the whole content of the original file to the output file name and modify that. Thanks guys, and thanks Mike, I did that at your suggestion.

Input Output with fstream

Can anyone tell me what is wrong with this code? I always get not open.
#include <iostream>
#include <fstream>
using namespace std;
int main(){
fstream fs;
fs.open("fsfile2",ios::in|ios::out|ios::binary);
if(fs.is_open()){
fs.write("wow",sizeof("wow"));
char str[20];
fs.read((char*)str,sizeof(str));
cout<<str<<endl;}
else
cout<<"Not open\n";
return 0;
}
Try this code
fs.open("fsfile2", ios::app|ios::in|ios::out|ios::binary);
By using the open() like you are that file will not be created if that is your goal.
If you want to create a new file please look at: fstream won't create a file
If the file exists, you are not looking for it in the right path. Or change the file name to the full path or put the executable in the folder where the file is.
Hope this helps.
Probably, you do not have permissions to create files in the directory, where your executable is.
Solution:
Please add a file extension to the filename.
If it's a text file, it will be
"fsfile2.txt"
Then, I tried removing
ios::in
since the first process only writes to file, and by removing that, the file is created and "wow" is also written at it.
In order for these lines
fs.read((char*)str,sizeof(str));
cout<<str<<endl;
to work,
You need to close the stream after writing to it, then open the stream in read mode, then read the contents. Take note that closing the stream will save the edited file.
Additional:
You can also change
fs.write("wow",sizeof("wow"));
to
fs << "wow";
You can do the same when reading from file,
fs >> str;
You can also use the string class of C++, instead of char array so that the number of characters inside the file won't be your problem anymore.
#include <string>
string str;
Checking for EOF (end-of-file) is recommended since files are read line by line. Once you add a new line and add a character to the line, the code that doesn't loop until EOF will only read the first line of the file.
In order to solve this, it is recommended to loop until EOF is reached.
while(!fs.eof()) {
fs >> str;
cout << str << endl;
}
So here is the improved snippet:
#include <string>
fs.open("fsfile2.txt", ios::out); // ios::out for write only
if(fs.is_open()) {
// writes "wow" to file
fs << "wow";
// closes the file
fs.close();
// ios::in for read only
fs.open("fsfile2.txt", ios::in);
// better to define variable just before using it
string str;
// loops until end-of-file
while(!fs.eof()) {
// reads a line from file, stores it to str
fs >> str;
// shows str to screen
cout << str << endl;
}
}
*Note: I removed
ios::binary
Since your code is not dealing with binary files yet.
I tried these and it worked fine! Have a nice day!
fstream fs; does not create a new file for you.
You need to make sure that the file exists in your project directory.
On the other hand, if you were to use ofstream fs("file.txt"); it would create the file for you. Or use only ios::out when you open fstream fs, this will create the file for you.

read and write a binary file in c++ with fstream

I'm trying to write simple c++ code to read and write a file.
The problem is my output file is smaller than the original file, and I'm stuck finding the cause.
I have a image with 6.6 kb and my output image is about 6.4 kb
#include <iostream>
#include <fstream>
using namespace std;
ofstream myOutpue;
ifstream mySource;
int main()
{
mySource.open("im1.jpg", ios_base::binary);
myOutpue.open("im2.jpg", ios_base::out);
char buffer;
if (mySource.is_open())
{
while (!mySource.eof())
{
mySource >> buffer;
myOutpue << buffer;
}
}
mySource.close();
myOutpue.close();
return 1;
}
Why not just:
#include <fstream>
int main()
{
std::ifstream mySource("im1.jpg", std::ios::binary);
std::ofstream myOutpue("im2.jpg", std::ios::binary);
myOutpue << mySource.rdbuf();
}
Or, less chattily:
int main()
{
std::ofstream("im2.jpg", std::ios::binary)
<< std::ifstream("im1.jpg", std::ios::binary).rdbuf();
}
Two things: You forget to open the output in binary mode, and you can't use the input/output operator >> and << for binary data, except if you use the output operator to write the input-streams basic_streambuf (which you can get using rdbuf).
For input use read and for output use write.
There are 3 problems in your code:
1- You have not opened your output file in Binary.
2- Your code return "1", normally you should return "0", if something went wrong then return an error code.
3- You should use "manipulators" and make c++ not to avoid whitespaces, so in order to read from file instead of:
mySource >> buffer;
you should use:
mySource >> std:noskipws >> buffer;
Well, its just because of padding at the end of the image. eof of any file do not include the padded bytes added at the end of file.
Try this
take img1.jpg contains 20 space charecter at the end not visible here (uegfuyregwfyugwrerycgerfcg6ygerbucykgeugcrgfrgeyf ) and run your program (do not include parenthesis in the file, these are used to show the data content)
you will see img2.jpg contains (uegfuyregwfyugwrerycgerfcg6ygerbucykgeugcrgfrgeyf)
So, its better option to read the file byte by byte using the filesize which you can get using stat, and run for loop till filesize. Hope this should resolve your problem you mentioned above

C++ write text to file, how to multiple lines

How do you write multiple lines to a file? ... This is what I have.. Also, some of the lines include text like: #import <Foundation/Foundation.h> How would I go about doing this? The code below is what I have right now..
//Creates Config.h
FILE * pFile;
char *buffer = "//Empty Header File";
char file [256];
sprintf (file , "%s/Desktop/%s/Control.h",homeDir, game_name);
pFile = fopen (file, "w+");
fwrite (buffer , sizeof(char), sizeof(buffer), pFile);
fclose (pFile);
Since this is C++, I suggest you utilize the standard IOStreams library and use the concrete file stream classes std::ifstream and std::ofstream for handling files. They implement RAII to handle the closing of the file, and use built in operators and the read()/write() member functions to perform formatted and unformatted I/O respectively. Moreover, they blend well together with the use of std::basic_string, the standard C++ string class.
With that said, if we implement this in C++ correctly, it should look like this:
std::string path = "/Desktop/";
std::string filename = homeDir + path + game_name + "/Control.h";
std::ofstream file(filename, std::ios_base::app);
This handles opening the file, but as you say you wish to write multiple lines to a file. Well this is simple. Just use '\n' whenever you wish to put a newline:
file << buffer << '\n';
If you give us more information about your issue, I will be able to elaborate more in my answer. But until you do, the above is sufficient.
Change to
sprintf (file , "%s/Desktop/%s/Control.h\n",homeDir, game_name);
\n - is a new-line code.
In C++ you would do it like this:
ofstream fout("someplace/Control.h");
fout << "a line of text" << endl;
fout << "another line of text" << endl;
I've left out some details like how to construct a filename and how to open a file in "append" mode, but you should try to tackle one problem at a time.

C++ edit a binary file with another

Solved! thanks all of you very much. My day has been made!(well morning, its 4am)
I'm trying to write a program in C++ that opens a .dat file in binary and replaces the first 1840 hex characters with that of another .dat file, while leaving the remaining hex values of the first .dat file the same. I have spent about 12 hours on this today and have had little success. I am a beginner programmer, I have taken one semester worth of c++ courses and we did not get to streams.
(it opens a file and everything, but deletes every thing after the new values have been added)
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cmath>
#include <cstring>
using namespace std;
int main (){
string filename;
long size;
char* memblock;
cout << " Enter a file to be modded by Mod.dat ";
cin >> filename;
ofstream infile ( filename ,std::ofstream::binary);
//filename: the file that will be opened and changed)
ifstream modFile ("Mod.dat", ifstream::binary);
// (mod.dat is the file that i get the first 1840 hex values from)
modFile.seekg (0,modFile.end);
size = modFile.tellg();
memblock = new char [size];
modFile.seekg (0, ios::beg);
modFile.read (memblock, size);
infile.write(memblock, 1840);
modFile.close();
infile.close();
cout << endl;
return 0;
}
Any help would be greatly appreciated, I hope there is some simple way to do this.
Solved! thanks all of you very much. My day has been made!(well morning, its 4am)
Edit:
You can modidy your file in place with something like :
std::fstream s(my_file_path, std::ios_base::binary);
s.seekp(position_of_data_to_overwrite, std::ios_base::beg);
s.write(my_data, size_of_data_to_overwrite);
std::fstream will not truncate your input file as std::ofstream does.
The other solution is to not use the same file for reading and writing. Use three files :
One for the output file.
One for the First input file.
One for the second input file.
fstream infile ( filename ,std::ofstream::binary); does not keeps the contents of the original file. Everything you write will erase the contents of the file.
Thus, you should:
open the output file
open the "Mod" file, read the first 1840 bytes from the first file, write them into the output file.
open the "main input file" file, move the cursor to 1840, read the remaining data and write it to the output file.
Depending on the "main input file" size, you may want to buffer you read/write operation.
My preferred fix, although Matthieu Rouget's fix does indeed work, is to just add ofstreeam::in to the opening of the input file:
ofstream infile ( filename.c_str(), std::ofstream::binary | ofstream::in);
(I had to use c_str() in my build, as glibc in my version doesn't take std::string as input).
I tested this on my local system (it took a while to realize that mod.dat is actually "Mod.dat"!)
It is probably a good idea to also check that the files actually opened, so something like this after ofstream infile line:
if (!infile)
{
cout << "Couldn't open " << filename << endl;
}
and similar for the modfile line.
And since you go through the effort of figuring out what the first part of the modfile size is, I would suggest that you also USE that for the writing of the file.