I am currently doing my first programming assignment in C++, and my objective is to Scale a Bitmap image using just the basic IO headers.
I've used http://en.wikipedia.org/wiki/BMP_file_format#DIB_header_.28bitmap_information_header.29 as my reference guide to finding the Header information.
My problem is creating an algorithm to scale the image up in terms of adding in individual pixels. I have made a series of for loops which are commented (They use the header information to determine how much they need to run), but I have no idea what to do next in terms of manipulating the actual pixels, this is where I need help
When I run the program, a new BMP file (called Image2) is created, however it is corrupt and 1kb in size (Most likely because the program isn't finished).
Here is the code, if anyone can also critique me on this or let me know any bad practices to avoid that I'm currently doing I would appreciate it.
int main()
{
FILE* pFile = NULL;
FILE* pFile2 = NULL;
//Open Image.bmp (In directory) as read binary
pFile = fopen("Image.bmp, "rb");
//Scan through the program and set to send.
fseek (pFile, 0, SEEK_END);
//Read file data
int fileData = ftell (pFile);
//set back to start of char pointer
rewind (pFile);
//Create a Char Filebuffer, this will be where data is viewed.
char* FileBuffer = new char[fileData];
//Read pFile into Filebuffer
fread(FileBuffer, fileData, 1, pFile);
//Read out BMP Header Data and Cast to Int
int ImageSize = *(int*)&FileBuffer[2];
int ImageOffset = *(int*)&FileBuffer[10]; //ImageOffset = Image Header Size
int ImageHeight = *(int*)&FileBuffer[18];
int ImageWidth = *(int*)&FileBuffer[20];
int BitsPerPixel = *(int*)&FileBuffer[24];
//Create a New Buffer that starts off at Pixel Data
char* NewFileBuffer = FileBuffer + ImageOffset;
std::cout << "Enter the amount of times you want to scale the image by." << std::endl;
std::cin >> ScaleValue;
std::cout << "\n";
//Create New Image row/height/size variables
int RowSizeOld = (BitsPerPixel * ImageWidth +31)/32 * 4;
int RowSizeNew = (BitsPerPixel *(ImageWidth * ScaleValue) + 31) / 32 * 4;
int NewImageSize = ImageOffset + (RowSizeNew * (ScaleValue * ImageHeight) );
int NewImageHeight = ImageHeight * ScaleValue;
int NewImageWidth = ImageWidth * ScaleValue;
// These ints define the colour values for RGB and Padding
int r = ImageOffset + 1;
int g = ImageOffset + 2;
int b= ImageOffset + 3;
int p = ImageOffset + 4;
//Rescale Image here, for (Newfile buffer [0])
// This for loop figures out how many times the newHeight variable must iterate
for (int newHeight = 0 ; newHeight < NewImageHeight ; newHeight++)
{
//This line scales up the amount of rows in terms of scale value
for(int doubleLine = 0 ; doubleLine < ScaleValue ; doubleLine++)
{
//This for loop then figures out the width of the new image in pixels as an int value
for (int newWidth = 0 ; newWidth < NewImageWidth ; newWidth++)
{
//This loop figures out how many times you need to increase the pixel density (for each pixel)
for (int pixelMultiplier = 0 ; pixelMultiplier < ScaleValue ; pixelMultiplier++)
{
//Move pixel data around to scale image (This is where I'm having trouble)
}
}
}
}
//Create a new File pointer, add image name + bmp string
FILE* pFile2;
pFile2 = fopen("Image2.bmp", "wb");
fwrite(NewFileBuffer, (NewImageSize + ImageOffset), sizeof(char) , pFile2);
return 0;
}
This is my first post on SE, so my apologies if the format of the code is a bit chunky or the question is hard to understand (I've read through the forum and have trimmed my code to make it more readable)
Doing a simple nearest re-sample is probably the easiest way to do it. To do this you simply calculate a ratio between the new and old sizes as follows:
Now you know that as you step 1 pixel in the x direction for the new image you would step "xStep" pixels in the old image. You then round the sampling position to the nearest integer location and sample that from the old image and write it to the new! You now have a simple re-sampled image.
For even better results you can Bi-linear filter as you re-sample. This is a very simple 2D linear interpolation.
To give you a 1D example of filtering float values you would write some code something like as follows:
Of course I'm not taking care of edge cases, but taking care of those and extending to 2D ought to be left as an exercise in the case of an assignment.
Its also worth noting that this sort of filtering will look a bit wrong if you scale the image more than 2x downwards due to the fact that you still step over pixels completely. This is usually solved by pre-filtering the image into a set of images of half the width and height at each step. This is known as mip-mapping.
Good luck!
The idea is rather to multiply existing Pixels instead of adding completly new ones. For positive scaling, you could create a new Bitmap, that's x-times the old one. Then fill the new Bitmap with the old Pixels and Duplicates.
The scheme looks as follows:
|o1|d1|o2|d2|...
|d1|d1|d2|d2|...
Where o1 is old Pixel and d1 is its duplicate.
So you'll have to go through all the Pixels and determine, how often and where they are filled in the new Bitmap.