Reading and Writing to BMP file - c++

I'm new to C++ and programming. I have the following flawed code to read from a BMP file and Write to another BMP file. I did not want to use any external libraries.
I have an 800kb 24bit bmp file. mybmp.bmp. Will try and upload it to dropbox.
`#include <iostream>
#include <conio.h>
#include <fstream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
unsigned char* editing(char* filename)
{
int i;
int j;
FILE* mybmpfilespointer;
mybmpfilespointer = fopen(filename, "rb");
unsigned char headerinfo[54];
fread(headerinfo, sizeof(unsigned char), 54, mybmpfilespointer); // read the 54-byte header size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
// extract image height and width from header
int width = *(int*)&headerinfo[18];
int height = *(int*)&headerinfo[22];
int size = 3 * width * height;
unsigned char* imagesdata = new unsigned char[size]; // allocate 3 bytes per pixel
fread(imagesdata, sizeof(unsigned char), size, mybmpfilespointer); // read the rest of the imagesdata at once
// display image height and width from header
cout << " width:" << width << endl;
cout << " height:" << height << endl;
ofstream arrayfile("bmpofstream.bmp"); // File Creation
for(int a = 0; a < 53; a++) //bgr to rgb
{
arrayfile << headerinfo[a];
}
for(int k=0; k<size; k++)
{
arrayfile<<imagesdata[k]<<endl; //Outputs array to file
}
arrayfile.close();
delete[] mybmpfilespointer;
delete[] imagesdata;
fclose(mybmpfilespointer);
return imagesdata;
return headerinfo;
}
int main()
{
FILE* mybmpfilespointer = fopen("mybmp.bmp", "rb");
if (mybmpfilespointer)
{
editing("mybmp.bmp");
}
else
{
cout << "Cant Read File";
}
}`
As you can see I read from mybmp.bmp which is 819680bytes
and write to bmpofstream.bmp as it is.
But somehow the resulting file is exactly 3x times the size of the mybmp around 2460826bytes.
I read header from mybmp file as headerinfo.
and
data from mybmp as imagesdata.
When I write to bmpofstream.bmp these arrays it is a messed up bmp file.
1) I'm guessing the increase in filesize is related to reading individual pixels and writing them 3 times or something but couldnt figure out. Why do you think this would be?
2) Once I figure out how to read and write this file as it is, I wanted to modify it. So I might as well ask this now:
I wanted to modify this image so that I can increase the value of each pixel by 50, so this would end up in a darker image. Can I do this directly as:
for(j = 0; j < size; j++)
{
imagesdata[j]=imagesdata[j]+50;
}
thank you.

I suggest taking a look at some existing library, even if you want to code yourself you may learn a lot. See for example libbmp source code,
https://code.google.com/p/libbmp/

try this
#include <iostream>
#include <conio.h>
#include <fstream>
#include <vector>
#include <iterator>
void editing( char* filename )
{
std::ifstream input( filename, std::ios::binary );
if( !input.is_open() )
{
std::cout << "Can`t open file" << std::endl;
return;
}
// copies all data into buffer
std::vector<char> buffer( ( std::istreambuf_iterator<char>( input ) ), ( std::istreambuf_iterator<char>() ) );
input.close();
std::vector<char> headerinfo;
{
auto it = std::next( buffer.begin(), 54 );
std::move( buffer.begin(), it, std::back_inserter( headerinfo ) );
buffer.erase( buffer.begin(), it );
}
// extract image height and width from header
int width = *reinterpret_cast<int*>( (char*)headerinfo.data() + 18 );
int height = *reinterpret_cast<int*>( (char*)headerinfo.data() + 22 );
int size = 3 * width * height;
std::vector<char> imagesdata;
{
auto it = std::next( buffer.begin(), size );
std::move( buffer.begin(), it, std::back_inserter( imagesdata ) );
buffer.erase( buffer.begin(), it );
}
// display image height and width from header
std::cout << " width:" << width << std::endl;
std::cout << " height:" << height << std::endl;
// paste your code here
// ...
std::ofstream arrayfile( "bmpofstream.bmp" ); // File Creation
std::ostream_iterator<char> output_iterator( arrayfile );
std::copy( headerinfo.begin(), headerinfo.end(), output_iterator ); // write header to file
std::copy( imagesdata.begin(), imagesdata.end(), output_iterator ); // write image data to file
}
int main(int argc, char**argv)
{
editing( argv[1] );
}

Related

Splitting csv large files into small files with dynamic names using C++

I am a beginner, so I apologise if my question looks childish. I have 38 large files in a folder. I want to split each of the files into smaller parts with dynamic name. Line 1 to line 13 works well. The challenge is in line 16-19. The output shows that the whole data from the ifstream is not appearing as char. This error makes it difficult to split the files. Please what am I getting wrong
#define SEGMENT 728300 //approximate target size of small file
using namespace std;
long file_size(char *name);//function definition below
int main(int argc, char **argv)
{
char input_file_1[100]; // input file
strcpy(input_file_1,argv[1]);
string PathToData = "path to the files";
TString name = PathToData+input_file_1;
std::cout << "Reading file " << name << endl;
char getdata[35000];
ifstream csv_db(name);
while(csv_db.getline(getdata,sizeof(csv_db)))
if (csv_db.eof())
csv_db.close();
int segments=0, i, accum;
FILE *fp1, *fp2;
unsigned int huga=strlen(getdata);
char largeFileName[huga + 100]; // Make sure there's enough space
strcpy(largeFileName, getdata);
std::cout << largeFileName << endl;
std::cout << largeFileName << endl;
long sizeFile = file_size(largeFileName);
segments = sizeFile/SEGMENT + 1980;//ensure end of file
char filename[360]={"path to folder where to keep the result"};
char smallFileName[360];
char line[1080];
fp1 = fopen(largeFileName, "r");
if(fp1)
{
for(i=1980;i<segments;i++)
{
accum = 0;
sprintf(smallFileName, "%s%d.csv", filename, i);
fp2 = fopen(smallFileName, "w");
if(fp2)
{
while(fgets(line, 1080, fp1) && accum <= SEGMENT)
{
accum += strlen(line);//track size of growing file
fputs(line, fp2);
}
fclose(fp2);
}
}
fclose(fp1);
}
return 0;
}
long file_size(char *name)
{
FILE *fp = fopen(name, "rb"); //must be binary read to get bytes
long size=-1;
if(fp)
{
fseek (fp, 0, SEEK_END);
size = ftell(fp)+1;
fclose(fp);
}
return size;
}

write a float buffer to a binary file

I have a float buffer with the data of the ppm file. The buffer[0][0] is the 1st element and the buffer[3*width*height][0] is the last element of the data.
Buffer has elements like this. 1st = 117 2st= 135 3st = 122. It's red, green and blue.
The point is to write this data into a binary file!
I try this, getHeight() returns the Height and getWidth() the width of the data.
ofstream output(filename, ios::out | ios::binary);
output.write((char *)buffer, img.getHeight() * img.getWidth() * 3);
Also i try this, for i=0 to i=3*height*width
fp = fopen(filename, "wb");
fwrite(reinterpret_cast<char*>(&buffer[i][0]), 1, 3*height*width, fp);
A float is 4 bytes each.
fwrite() doesn't know of the type you're writing, so for the size, you need to also multiply by the size of each element.
fwrite(reinterpret_cast<char*>(&buffer[i][0]), 1, 3*height*width * sizeof(float), fp);
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main() {
ofstream out("blah.txt");
float val = 10.0f;
out << fixed << setprecision(5) << val << endl;
out.close();
return 0;
}

how to make 10 copies of initial file, if first file is as-1.txt second should be as-2.txt and so on

Loop isn't making 10 copies and i have no idea how to change file names
#include "iostream"
#include "fstream"
#include "windows.h"
using namespace std;
void main()
{
char str[200];
ifstream myfile("as-1.txt");
if (!myfile)
{
cerr << "file not opening";
exit(1);
}
for (int i = 0; i < 10; i++)
{
ofstream myfile2("as-2.txt");
while (!myfile.eof())
{
myfile.getline(str, 200);
myfile2 << str << endl;
}
}
system("pause");
}
Solution using plain C API from <cstdio>. Easily customizable.
const char* file_name_format = "as-%d.txt"; //Change that if you need different name pattern
const char* original_file_name = "as-1.txt"; //Original file
const size_t max_file_name = 255;
FILE* original_file = fopen(original_file_name, "r+");
if(!original_file)
//file not found, handle error
fseek(original_file, 0, SEEK_END); //(*)
long file_size = ftell(original_file);
fseek(original_file, 0, SEEK_SET);
char* original_content = (char*)malloc(file_size);
fread(original_content, file_size, 1, original_file);
fclose(original_file);
size_t copies_num = 10;
size_t first_copy_number = 2;
char file_name[max_file_name];
for(size_t n = first_copy_number; n < first_copy_number + copies_num; ++n)
{
snprintf(file_name, max_file_name, file_name_format, n);
FILE* file = fopen(file_name, "w");
fwrite(original_content, file_size, 1, file);
fclose(file);
}
free(original_content);
(*) As noted on this page, SEEK_END may not necessarily be supported (i.e. it is not a portable solution). However most POSIX-compliant systems (including the most popular Linux distros), Windows family and OSX support this without any problems.
Oh, and one more thing. This line
while (!myfile.eof())
is not quite correct. Read this question - it explains why you shouldn't write such code.
int main()
{
const int copies_of_file = 10;
for (int i = 1; i <= copies_of_file; ++i)
{
std::ostringstream name;
name << "filename as-" << i << ".txt";
std::ofstream ofile(name.str().c_str());
ofile.close();
}
return 0;
}
That will make 10 copies of a blank .txt file named "filename as-1.txt" "filename as-2.txt" etc.
Note also the use of int main: main always has a return of int, never void

C++: Store read binary file into buffer

I'm trying to read a binary file and store it in a buffer. The problem is, that in the binary file are multiple null-terminated characters, but they are not at the end, instead they are before other binary text, so if I store the text after the '\0' it just deletes it in the buffer.
Example:
char * a = "this is a\0 test";
cout << a;
This will just output: this is a
here's my real code:
this function reads one character
bool CStream::Read (int * _OutChar)
{
if (!bInitialized)
return false;
int iReturn = 0;
*_OutChar = fgetc (pFile);
if (*_OutChar == EOF)
return false;
return true;
}
And this is how I use it:
char * SendData = new char[4096 + 1];
for (i = 0; i < 4096; i++)
{
if (Stream.Read (&iChar))
SendData[i] = iChar;
else
break;
}
I just want to mention that there is a standard way to read from a binary file into a buffer.
Using <cstdio>:
char buffer[BUFFERSIZE];
FILE * filp = fopen("filename.bin", "rb");
int bytes_read = fread(buffer, sizeof(char), BUFFERSIZE, filp);
Using <fstream>:
std::ifstream fin("filename.bin", ios::in | ios::binary );
fin.read(buffer, BUFFERSIZE);
What you do with the buffer afterwards is all up to you of course.
Edit: Full example using <cstdio>
#include <cstdio>
const int BUFFERSIZE = 4096;
int main() {
const char * fname = "filename.bin";
FILE* filp = fopen(fname, "rb" );
if (!filp) { printf("Error: could not open file %s\n", fname); return -1; }
char * buffer = new char[BUFFERSIZE];
while ( (int bytes = fread(buffer, sizeof(char), BUFFERSIZE, filp)) > 0 ) {
// Do something with the bytes, first elements of buffer.
// For example, reversing the data and forget about it afterwards!
for (char *beg = buffer, *end=buffer + bytes; beg < end; beg++, end-- ) {
swap(*beg, *end);
}
}
// Done and close.
fclose(filp);
return 0;
}
static std::vector<unsigned char> read_binary_file (const std::string filename)
{
// binary mode is only for switching off newline translation
std::ifstream file(filename, std::ios::binary);
file.unsetf(std::ios::skipws);
std::streampos file_size;
file.seekg(0, std::ios::end);
file_size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<unsigned char> vec;
vec.reserve(file_size);
vec.insert(vec.begin(),
std::istream_iterator<unsigned char>(file),
std::istream_iterator<unsigned char>());
return (vec);
}
and then
auto vec = read_binary_file(filename);
auto src = (char*) new char[vec.size()];
std::copy(vec.begin(), vec.end(), src);
The problem is definitievely the writing of your buffer, because you read a byte at a time.
If you know the length of the data in your buffer, you could force cout to go on:
char *bf = "Hello\0 world";
cout << bf << endl;
cout << string(bf, 12) << endl;
This should give the following output:
Hello
Hello world
However this is a workaround, as cout is foreseent to output printable data. Be aware that the output of non printable chars such as '\0' is system dependent.
Alternative solutions:
But if you manipulate binary data, you should define ad-hoc data structures and printing. Here some hints, with a quick draft for the general principles:
struct Mybuff { // special strtucture to manage buffers of binary data
static const int maxsz = 512;
int size;
char buffer[maxsz];
void set(char *src, int sz) // binary copy of data of a given length
{ size = sz; memcpy(buffer, src, max(sz, maxsz)); }
} ;
Then you could overload the output operator function:
ostream& operator<< (ostream& os, Mybuff &b)
{
for (int i = 0; i < b.size; i++)
os.put(isprint(b.buffer[i]) ? b.buffer[i]:'*'); // non printables replaced with *
return os;
}
ANd you could use it like this:
char *bf = "Hello\0 world";
Mybuff my;
my.set(bf, 13); // physical copy of memory
cout << my << endl; // special output
I believe your problem is not in reading the data, but rather in how you try to print it.
char * a = "this is a\0 test";
cout << a;
This example you show us prints a C-string. Since C-string is a sequence of chars ended by '\0', the printing function stops at the first null char.
This is because you need to know where the string ends either by using special terminating character (like '\0' here) or knowing its length.
So, to print whole data, you must know the length of it and use a loop similar to the one you use for reading it.
Are you on Windows? If so you need to execute _setmode(_fileno(stdout), _O_BINARY);
Include <fcntl.h> and <io.h>

Blank frames when explicitly copying pixel values in OpenCV

I have been porting some video processing code to C++ using OpenCV 2.4.3. The following test program closely mimics how my code will read each frame from a video, operate on its contents, and then write new frames to a new video file.
Strangely, the output frames are entirely black when the pixels are set individually, but are written correctly when the entire frame is cloned.
In practice, I'd use the two macros to access and assign desired values, but the sequential scan used in the example shows the idea more clearly.
Does anyone know where I'm going wrong?
test.cpp:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace cv;
#define RGB_REF(PR,NC,R,C,CH) (*((PR) + ((3*(NC)*(R)+(C))+(CH))))
#define GRAY_REF(PR,NC,R,C) (*((PR) + (NC)*(R)+(C)))
int main(int argc, char* argv[])
{
string video_path(argv[1]);
cerr << "Video path is " + video_path + "\n";
VideoCapture capture(video_path);
if ( !capture.isOpened() )
{
cerr << "Input file could not be opened\n";
return 1;
} else
{
string output_path(argv[2]);
VideoWriter output;
int ex = (int)capture.get(CV_CAP_PROP_FOURCC);
Size S = Size((int) capture.get(CV_CAP_PROP_FRAME_WIDTH),
(int) capture.get(CV_CAP_PROP_FRAME_HEIGHT));
output.open(output_path,ex,capture.get(CV_CAP_PROP_FPS),S,true);
if ( !output.isOpened() )
{
cerr << "Output file could not be opened\n";
return 1;
}
unsigned int numFrames = (unsigned int) capture.get(CV_CAP_PROP_FRAME_COUNT);
unsigned int m = (unsigned int) capture.get(CV_CAP_PROP_FRAME_HEIGHT);
unsigned int n = (unsigned int) capture.get(CV_CAP_PROP_FRAME_WIDTH);
unsigned char* im = (unsigned char*) malloc(m*n*3*sizeof(unsigned char));
unsigned char* bw = (unsigned char*) malloc(m*n*3*sizeof(unsigned char));
Mat frame(m,n,CV_8UC3,im);
Mat outputFrame(m,n,CV_8UC3,bw);
for (size_t i=0; i<numFrames; i++)
{
capture >> frame;
for (size_t x=0;x<(3*m*n);x++)
{
bw[x] = im[x];
}
output << outputFrame; // blank frames
// output << frame; // works
// output << (outputFrame = frame); // works
}
}
}
When you query a frame from VideoCapture as capture >> frame;, frame is modified. Say, it has a new data buffer. So im no longer points to the buffer of frame.
Try
bm[x] = frame.ptr()[x];