Overlay BMP image on top on another with C++ - c++

I'm working on a C++ program that overlays one 8 bit depth BMP image into another one of the same format and size. The program is supposed to read both images and then for every black pixel in the overlay picture, it changes the same pixel in the original picture to white. The essentials parts of my code are shown below:
The class for a BMP picture:
class BMPImage{
int width;
int height;
int size;
unsigned char* data; //Array with all pixels
unsigned char* header; //54 byte header
void setSize();
public:
BMPImage(const char* filename);
BMPImage(unsigned char* header, unsigned char* data);
int getSize();
int getWidth();
int getHeight();
unsigned char* getData();
unsigned char* getHeader();
void createFile(char* filename);
}
Constructors to create an object from a filename or from a header and a data array:
BMPImage::BMPImage(const char* filename){
FILE* f = fopen(filename, "rb");
if(f == NULL)
throw "Argument Exception";
header= new unsigned char[54];
fread(header, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
setSize();
cout << endl;
cout << "Reading file " << filename << endl;
cout << " Width: " << width << endl;
cout << " Height: " << height << endl;
data = new unsigned char[size];
fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once
fclose(f);
}
BMPImage::BMPImage(unsigned char* h, unsigned char* d){
header = new unsigned char[54];
for(int i=0;i<54;i++){
header[i]=h[i];
}
setSize();
data = new unsigned char[size];
for(int i=0;i<size;i++){
data[i]=d[i];
}
}
A function to create a file from a BMPImage object:
void BMPImage::createFile(char* filename){
FILE* f;
f=fopen(filename, "wb");
//write header
fwrite(header,sizeof(unsigned char), 54, f);
//write data
fwrite(data, sizeof(unsigned char), size, f);
//close file
fclose(f);
cout<<endl<<"File "<< filename <<" was successfully created."<<endl;
}
Finally, my function to overlay two images. The overlay is done so that if the pixel of "overlay" is black, the corresponding pixel in the result image will be white, else the pixel will be the same as in the "original" image.
void overlay(char* original, char* overlay, char* result){
BMPImage overlayIm(overlay);
BMPImage originalIm(original);
//Check if the pictures have the same size
if(originalIm.getHeight()!=overlayIm.getHeight() || originalIm.getWidth()!=overlayIm.getWidth())
throw "Files do not have the same size";
int size = overlayIm.getSize();
unsigned char* dataResult = new unsigned char[size];
unsigned char* dataOriginal = originalIm.getData();
unsigned char* dataOverlay = overlayIm.getData();
//If a pixel in overlay is black, change corresponding pixel in original to white
for(int i=0; i<size; i++){
if(dataOverlay[i]!=0){
dataResult[i]=dataOriginal[i];
}else{
dataResult[i]=(unsigned char)255;
}
}
//Create new file with the result
BMPImage resultIm(originalIm.getHeader(), dataResult);
resultIm.createFile(result);
cout<<endl<<"New overlay image created in "<<result <<endl;
}
Although I only check for the pixels in the overlay image, it seems that the program is checking for the pixels in both the overlay and the original image at the same time. So when a pixel is black in the original image, the pixel in the result will be white, and I just want it to be white only if the pixel in overlay image is black.
An example of my problem is shown in this picture. The pictures on the left are the arguments in the overlay function. In the right, the "desired" picture is the one that my program should generate, and the "result" is the one that my program actually generates:
I don't understand why the black pixels in the original are changed to white if I never check the pixels in my original picture when I create the result image. Can anybody point me to the mistake I'm committing so that I can solve my problem?

Related

Corrupted heap while display a BMP image on console

I have a exercise. It says, that the C program should be able to read the information of a bitmap file and after that it should display the picture on console.
I have already written a code but when it does not work correctly.
When I debugged the code it looks like the heap is corrupted. I thinks I have a known glitch/mistake in ScanPixelline function.
I don't know how to fix it. Can someone help me to check it?
I am relatively new to C programming.
#include "stdafx.h"
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include "stdint.h"
#include "windows.h"
#pragma pack(1)
struct BMP
{
char Type[2]; //File type. Set to "BM".
int32_t Size; //Size in BYTES of the file.
int16_t Reserved1; //Reserved. Set to zero.
int16_t Reserved2; //Reserved. Set to zero.
int32_t OffSet; //Offset to the data.
int32_t headsize; //Size of rest of header. Set to 40.
int32_t Width; //Width of bitmap in pixels.
int32_t Height; // Height of bitmap in pixels.
int16_t Planes; //Number of Planes. Set to 1.
int16_t BitsPerPixel; //Number of Bits per pixels.
int32_t Compression; //Compression. Usually set to 0.
int32_t SizeImage; //Size in bytes of the bitmap.
int32_t XPixelsPreMeter; //Horizontal pixels per meter.
int32_t YPixelsPreMeter; //Vertical pixels per meter.
int32_t ColorsUsed; //Number of colors used.
int32_t ColorsImportant; //Number of "important" colors.
};
struct Color
{
unsigned char B;
unsigned char G;
unsigned char R;
};
struct ColorTable
{
Color *colors;
unsigned long length;
};
struct PixelArray
{
Color **pixels;
unsigned long rowCount;
unsigned long columnCount;
};
void readBMP(char *File_Name, BMP &a)
{
FILE *p = fopen(File_Name, "rb");
if (p == NULL)
{
printf("Can't open file!");
fclose(p);
return;
}
else
{
fread(&a, sizeof(BMP), 1, p);
}
fclose(p);
}
void Get_Inf(BMP a)
{
if (a.Type[0] != 'B' || a.Type[1] != 'M')
{
printf("This is not a BMP file");
}
else
{
printf("This is a BMP file\n");
printf("The size of this file is %lu bytes\n", a.Size);
printf("The witdth of this image is %lu pixels\n", a.Width);
printf("The height of this image is %lu pixels\n", a.Height);
printf("The number of bits per pixels in this image is %u\n", a.BitsPerPixel);
}
}
void scanBmpPixelLine(Color *&line, unsigned long length)
{
FILE *pointer_ = fopen("test.bmp", "rb");
line = new Color[length];
fread(line, sizeof(Color), sizeof(Color)*length, pointer_);
fclose(pointer_);
//file.read((char *)line, length * sizeof(Color));
}
void skipBmpPadding(char count)
{
FILE *pointer__ = fopen("test.bmp", "rb");
if (count == 0)
{
fclose(pointer__);
return;
}
char padding[3];
fread(&padding, sizeof(char), count, pointer__);
fclose(pointer__);
//file.read((char *)&padding, count);
}
void ReadPixelArray(BMP a, PixelArray &data)
{
FILE *pointer = fopen("test.bmp", "rb");
data.rowCount = a.Height;
data.columnCount = a.Width;
data.pixels = new Color*[data.rowCount];
char paddingCount = (4 - (a.Width * (a.BitsPerPixel / 8) % 4)) % 4;
fseek(pointer, 54, SEEK_SET);
for (int i = 0; i < data.rowCount; i++)
{
scanBmpPixelLine(data.pixels[data.rowCount - i - 1], a.Width);
skipBmpPadding(paddingCount);
}
}
void drawBmp(BMP a, PixelArray data)
{
HWND console = GetConsoleWindow();
HDC hdc = GetDC(console);
for (int i = 0; i < a.Height; i++)
for (int j = 0; j < a.Width; j++)
{
Color pixel = data.pixels[i][j];
SetPixel(hdc, j, i, RGB(pixel.R, pixel.G, pixel.B));
}
ReleaseDC(console, hdc);
}
void releaseBmpPixelArray(PixelArray data)
{
for (int i = 0; i < data.rowCount; i++)
delete[]data.pixels[i];
delete[]data.pixels;
}
int main()
{
char file_name[] = "test.bmp";
BMP a;
PixelArray data;
readBMP(file_name, a);
Get_Inf(a);
ReadPixelArray(a, data);
drawBmp(a, data);
releaseBmpPixelArray(data);
}
This function:
void scanBmpPixelLine(Color *&line, unsigned long length)
{
FILE *pointer_ = fopen("test.bmp", "rb");
line = new Color[length];
fread(line, sizeof(Color), sizeof(Color)*length, pointer_);
fclose(pointer_);
//file.read((char *)line, length * sizeof(Color));
}
For starters, the intent of the function appears to be to read one line of pixel data from the file. But instead, it's re-opening the file and reading from the beginning (where the header bytes are). I'm not sure if you are aware of that...
But the crash is a result of this line:
fread(line, sizeof(Color), sizeof(Color)*length, pointer_);
The second parameter, sizeof(Color), is the size of each element. The third parameter is the number of elements to read. The total bytes read from the file will be the multiplication of the second parameter by the third parameter. So you've redundantly multiplied by sizeof(Color) one too many times. The result is that it will overwrite the line buffer.
To fix, it should be:
fread(line, sizeof(Color), length, pointer_);
You probably want to pass the FILE* pointer obtained from your ReadPixelArray function into this function instead of re-opening the file for every line.
Another code review comment. You should just read the entire file into memory instead of redundantly opening and closing the file for each operation. Then parse the header and set a pointer to the first "line" after the header.

read and write a bmp file in c++

i am trying to read and write a bmp file in c++.output file is created but is not opening and it's size is 257kb whereas the input file is 258kb.i first read and write the 14 byte header file,40 byte imageheader file,then the 512*512 pixels,here's my code,can anyone help please
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
int main()
{
ifstream iFile;
char ch;
iFile.open("lena.bmp",ios::binary);
ofstream oFile;
oFile.open("lena3.bmp",ios::binary);
//int headerImageHeader=54;
// int imageHeader=40;
int fs[54];
//int ihs[imageHeader];
int tfs[54];
int pixel[512][512];
if(iFile.is_open() && oFile.is_open())
{
for(int i=0;i<54;i++)
{
iFile.get(ch);
fs[i]=ch;
cout<<fs[i]<<" ";
char p;
p=fs[i];
oFile<<p;
}
for(int w=0;w<512;w++)
{
for(int h=0;h<512;h++)
{
iFile.get(ch);
pixel[w][h]=ch;
//cout<<pixel[w][h]<<;
char pi=pixel[w][h];
oFile<<pi;
}
}
oFile.close();
iFile.close();
}
else cout << "Unable to open file"<<endl;
return 0;
}
Your code has multiple problems. Basically, the pixel storage in BMP file is not that simple. It depends on the type of BMP (e.g. Monochrome Bitmap, 16 Color Bitmap, 256 Color Bitmap and 24-bit Bitmap etc).
There are two options to read one Bitmap file and write it in another Bitmap file.
a) Read each byte from the source file and write in destination file
b) Understand Bitmap storage format and write code accordingly.
For option b) good source is available at wiki.
In summary, the calculation of Pixel Array storage (size) is:
PixelArraySize = RowSize x ImageHeight
Where ImageHeight is height of image in pixel. The RowSize is calculated as:
RowSize = [(BitsPerPixelxImageWidth + 31) / 32 ]x4

read image in 2d array C++ and save it

#include <iostream>
#include <fstream> // for file I/O
#define WIDTH 128
#define HEIGHT 128
#include <cmath>
using namespace std;
typedef unsigned char unchar;
class MImage
{
///////////////////////////////////////////////////////////////////////////////////////read
public:
void readimage()
{
imageData = new unchar*[HEIGHT]; // create new array size: height of image.
for (int i = 0; i < HEIGHT; i++)
{
imageData[i] = new unchar[WIDTH]; //create matrix.
}
//image I/O
pInFile = new ifstream;
pInFile->open("L.bmp", ios::in | ios::binary); // open fileName and read as binary.
pInFile->read(reinterpret_cast<char*>(imageHeaderData), 1078); //read bmp header data into array.
for (int i = 0; i < HEIGHT; i++)
{
pInFile->read(reinterpret_cast<char*>(imageData[i]), WIDTH); //read row into each array entry.
}
pInFile->close(); //close stream.
}
public:
void write()
{
//smoothFilter();
pOutFile = new ofstream;
pOutFile->open("output.bmp", ios::out | ios::binary);
pOutFile->write(reinterpret_cast<char*>(imageHeaderData), 1078); //write header data onto output
for (int i = 0; i < HEIGHT; i++)
{
pOutFile->write(reinterpret_cast<char*>(imageData[i]), WIDTH); // write new image data.
}
pOutFile->close(); //close stream
}
public:
ifstream* pInFile;
ofstream* pOutFile;
unchar imageHeaderData[1078]; //.bmp header data with offset 1078. unchar** imageData;
};
int main()
{
MImage abc;
abc.readimage();
abc.write();
return 0;
}
I am unable to read image in a 2d array so that i could do some processing on it. i have used the code above but saved file is giving error.
what i am doing is first reading a .bmp file 128x128 then saving it in an other .bmp file. but when i try to open output file it gives error "file is corrupted or large in size"
Hope it helps ;)
I skipped error checking but you should add it to the final code. For writing a .bmp image, wirte BITMAPFILEHEADER first, then BITMAPINFOHEADER and at the end the actual raw data
FILE* filePtr;
int error;
unsigned int count;
BITMAPFILEHEADER bitmapFileHeader;
BITMAPINFOHEADER bitmapInfoHeader;
int imageSize;
unsigned char* bitmapImage;
// Open the height map file in binary.
error = fopen_s(&filePtr, filename, "rb");
// Read in the file header.
count = fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// Read in the bitmap info header.
count = fread(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// Save the dimensions of the terrain.
Width= bitmapInfoHeader.biWidth;
Height= bitmapInfoHeader.biHeight;
// Calculate the size of the bitmap image data.
imageSize = Width* Height* 3;
// Allocate memory for the bitmap image data.
bitmapImage = new unsigned char[imageSize];
// Move to the beginning of the bitmap data.
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// Read in the bitmap image data.
count = fread(bitmapImage, 1, imageSize, filePtr);
// Close the file.
error = fclose(filePtr);
Don't forget to delete bitmapImage or use std::vector instead

Ifstream reading error

I have been trying to read a bmp file with ifstream, however it works fine without debugging, when I run it in debug mode it fails. At the beginning I read 54 bytes of info, to get the height and the width of the picture, which are unfortunately -858993460 in debug mode, so the whole size of my picture overflows everytime, so I get a bad allocation error. I use VS 2013, could anyone help me out with this one ?
unsigned char* readBMP(char* filename)
{
int i;
char info[54];
std::ifstream ifs(filename, std::ifstream::binary);
ifs.read(info, 54);
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = 3 * width * height;
char* data = new char[size]; // allocate 3 bytes per pixel
ifs.read(data, size);
ifs.close();
return (unsigned char*)data;
}
I guess you failed to open the file, so your read must been failed.
you can check: if (ifs.is_open()) { /* good*/}
you can also check: if(ifs.read(...)){/*good*/}
try this code:
unsigned char* readBMP(char* filename)
{
int i;
char info[54];
std::ifstream ifs(filename, std::ifstream::binary);
if(!ifs.is_open()){
std::cerr<<" failed to open file"<<std::endl;
return NULL;
}
if(!ifs.read(info, 54)) {
std::cerr<<" failed to read from file"<<std::endl;
return NULL;
}
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = 3 * width * height;
char* data = new char[size]; // allocate 3 bytes per pixel
ifs.read(data, size);
ifs.close();
return (unsigned char*)data;
}

FreeImage delete[] bitmap data fails

Please help me with cleaning up my heap after loading bitmap with FreeImage.
Somehow
delete[] data;
causes _ASSERTE(_CrtIsValidHeapPointer(pUserData)) assertion, and I cannot found how to fix it other than commenting this line. Will there memory leak?
Any help and explanation will be appreciated!
Full code at pastebin: http://pastebin.com/dWxz0tjM
Visual Studio 2012 solution (with huge FreeImage static lib): http://rghost.ru/40322357 (15.7 Mbytes!)
Full code here:
#include <iostream>
// FreeImage static linkage
#define FREEIMAGE_LIB
#include "FreeImage/FreeImage.h"
#include "FreeImage/Utilities.h"
#pragma comment(lib, "FreeImage/FreeImaged.lib")
using namespace std;
static const wchar_t* sk_Filename = L"Test.tga";
// Error handler to use in callback
void FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *msg)
{
char buf[1024];
sprintf_s(buf, 1024, "Error: %s", FreeImage_GetFormatFromFIF(fif));
cout << buf;
}
// Bitmap loader from FreeImage samples
FIBITMAP* GenericLoaderU(const wchar_t* lpszPathName, int flag)
{
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
fif = FreeImage_GetFileTypeU(lpszPathName, 0);
if(fif == FIF_UNKNOWN)
{
fif = FreeImage_GetFIFFromFilenameU(lpszPathName);
}
if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif))
{
FIBITMAP *dib = FreeImage_LoadU(fif, lpszPathName, flag);
return dib;
}
return NULL;
}
// Function gets filename and returns bitmap data array, its size and bits per pixel
void GetData(const wchar_t* szFilename, unsigned char* data, unsigned int& width, unsigned int& height, unsigned int& bpp)
{
FIBITMAP* src = GenericLoaderU(szFilename, 0);
if(src == 0)
return;
FIBITMAP* src32 = FreeImage_ConvertTo32Bits(src);
FreeImage_Unload(src);
// Get picture info
width = FreeImage_GetWidth(src32);
height = FreeImage_GetHeight(src32);
bpp = FreeImage_GetBPP(src32);
unsigned int scan_width = width * bpp/8;
if((width == 0) || (height == 0) || (bpp == 0))
return;
memset(data, 0, height * scan_width);
SwapRedBlue32(src32); // Convert BGR to RGB
// Get bitmap data
FreeImage_ConvertToRawBits(data, src32, scan_width, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, TRUE);
FreeImage_Unload(src32);
return;
}
int main()
{
FreeImage_Initialise();
FreeImage_SetOutputMessage(FreeImageErrorHandler);
//Creating bitmap data array (size is unknown here)
unsigned char* data = new unsigned char[];
unsigned int width(0), height(0), bpp(0);
// Loading data here
GetData(sk_Filename, data, width, height, bpp);
//Using data here
cout << width << "x" << height << "x" << bpp << endl;
for (unsigned int i = 0; i < width * height * bpp/8; )
{
cout << "("
<< (unsigned int)data[i] << ", "
<< (unsigned int)data[i+1] << ", "
<< (unsigned int)data[i+2] << ", "
<< (unsigned int)data[i+3] << ")"
<< endl;
i += 4;
}
cout << endl;
//Cleanup
delete[] data; // <-- Breaks with _ASSERTE(_CrtIsValidHeapPointer(pUserData));
// What's wrong here?
system("pause");
return 0;
}
---EDIT--------------------------------
Okay, first possible solution is to use std::vector.
It has nothing to do with the delete.
The thing is that Debug Crt Runtime can check the memory integrity only during calls to memory API like: malloc, free, realloc, new, delete.
You have a memory overrun that is detected by the Crt.
Obviously, new unsigned char[] does not allocate enough bytes for you.
Move the allocation into the GetData() proc and call it like:
unsigned char* data = GetData(sk_Filename, width, height, bpp);
Write a function that calculates the size of data based on the image.
Then allocate data with that size
e.g.
size_z GetDataSize(const wchar_t* szFilename)
It's easy to calculate the required size inside your GetData function, so allocate the array there and return it instead.
You would have
unsigned char* GetData(const wchar_t* szFilename,
unsigned int& width,
unsigned int& height,
unsigned int& bpp);
which contains
unsigned char* data = new unsigned char[height * scan_width];
// Do the conversion...
return data;
and main would say
unsigned char* data = GetData(sk_Filename, width, height, bpp);