mirror of https://github.com/BOINC/boinc.git
191 lines
5.3 KiB
C
191 lines
5.3 KiB
C
#ifdef _WIN32
|
|
#include "boinc_win.h"
|
|
#else
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "bmplib.h"
|
|
|
|
// Returns true for success -- false otherwise
|
|
bool DIB_BITMAP::set_size(int width, int height, int channels)
|
|
{
|
|
|
|
// If DIB_BITMAP has already been set -- clear it out first
|
|
FreeDIB_BMP();
|
|
|
|
// Create a temporary compatible device context
|
|
HDC temp_hdc = CreateCompatibleDC(NULL);
|
|
|
|
// Error Check
|
|
if(!temp_hdc)
|
|
return false;
|
|
|
|
bmp_width = width; // Set the width
|
|
bmp_height = height; // Set the height
|
|
bmp_channels = channels; // Set the channels (3 == 24-bit, 4 == 32-bit)
|
|
|
|
// Set stride -- The stride is the TRUE number of bytes in a line of pixels
|
|
// Windows makes all the .bmps DWORD aligned (divisible evenly by 4)
|
|
// So if you bitmap say was 103x103 pixels, Windows would add 1 "padding byte" to it
|
|
// so in memory it would be 104x103 pixels. The "padding bytes" do not get blit (drawn)
|
|
// to the screen, they're just there so again everything is DWORD aligned which makes
|
|
// blitting (drawing to the screen) easier for the OS
|
|
bmp_stride = bmp_width * bmp_channels;
|
|
|
|
while((bmp_stride % 4) != 0) // Ensure bmp_stride is DWORD aligned
|
|
bmp_stride++;
|
|
|
|
BITMAPINFO bmp_info = {0};
|
|
|
|
// Initialize the parameters that we care about
|
|
bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bmp_info.bmiHeader.biWidth = width;
|
|
bmp_info.bmiHeader.biHeight = height;
|
|
bmp_info.bmiHeader.biPlanes = 1; // Always equal 1
|
|
bmp_info.bmiHeader.biBitCount = channels * 8;
|
|
bmp_info.bmiHeader.biCompression = BI_RGB; // No compression
|
|
bmp_info.bmiHeader.biClrUsed = 0; // Always equals 0 with a 24 or 32-bit .bmp
|
|
|
|
// Create a DIBSection -- This returns us two things, an HBITMAP handle and
|
|
// a memory pointer (pointer to the pixels) in surface_bits
|
|
hbitmap = CreateDIBSection(temp_hdc, &bmp_info, DIB_RGB_COLORS,
|
|
(void**)&surface_bits, 0, 0);
|
|
|
|
// Release our temporary HDC
|
|
DeleteDC(temp_hdc);
|
|
|
|
// Error Check -- Make sure the call to CreateDIBSection() DID NOT fail
|
|
if(!hbitmap)
|
|
return false;
|
|
|
|
return true; // We're sized :)
|
|
|
|
} // end of set_size(int width, int height, int channels)
|
|
|
|
bool DIB_BITMAP::loadBMP(const char *file_name)
|
|
{
|
|
// If DIB_BITMAP has already been set -- clear it out first
|
|
FreeDIB_BMP();
|
|
|
|
// Error Check -- Make sure they passed in a valid file name
|
|
if(!file_name)
|
|
return false;
|
|
|
|
FILE *bmp_file = fopen(file_name, "rb");
|
|
|
|
// Error Check -- Make sure the file could be opened
|
|
if(!bmp_file)
|
|
return false;
|
|
|
|
BITMAPFILEHEADER bmp_fileheader;
|
|
|
|
// Read the BITMAPFILEHEADER
|
|
if(!fread(&bmp_fileheader, sizeof(BITMAPFILEHEADER), 1, bmp_file))
|
|
{
|
|
fclose(bmp_file);
|
|
return false;
|
|
}
|
|
|
|
// Check the type field to make sure we have a .bmp file
|
|
if(memcmp(&bmp_fileheader.bfType, "BM", 2))
|
|
{
|
|
fclose(bmp_file);
|
|
return false;
|
|
}
|
|
|
|
BITMAPINFOHEADER bmp_infoheader;
|
|
|
|
// Read the BITMAPINFOHEADER.
|
|
if(!fread(&bmp_infoheader, sizeof(BITMAPINFOHEADER), 1, bmp_file))
|
|
{
|
|
fclose(bmp_file);
|
|
return false;
|
|
}
|
|
|
|
// We only support 24-bit and 32-bit .bmps so make sure that's what we have
|
|
if((bmp_infoheader.biBitCount != 24) && (bmp_infoheader.biBitCount != 32))
|
|
{
|
|
fclose(bmp_file);
|
|
return false;
|
|
}
|
|
|
|
// Set the size of our DIB_BITMAP, once we do this we're ready to store the pixel
|
|
// data in it
|
|
if(set_size(bmp_infoheader.biWidth,bmp_infoheader.biHeight,bmp_infoheader.biBitCount / 8) == false)
|
|
{
|
|
fclose(bmp_file);
|
|
return false;
|
|
}
|
|
|
|
// Jump to the location where the pixel data is stored
|
|
if(fseek(bmp_file, bmp_fileheader.bfOffBits, SEEK_SET))
|
|
{
|
|
fclose(bmp_file);
|
|
return false;
|
|
}
|
|
|
|
unsigned int bytesPerLine = bmp_width * bmp_channels; // Bytes per line (number of bytes
|
|
// in a scan line)
|
|
|
|
// Calculate how many "padding" bytes there are -- WE DO NOT want to read in the
|
|
// padding bytes (we will just skip over those)
|
|
// **Remember** Windows adds padding bytes to ensure ALL .bmps are DWORD aligned
|
|
// (divisible evenly by 4)
|
|
unsigned int padding = bmp_stride - bytesPerLine;
|
|
|
|
// Loop over all the scan lines (all the rows of pixels in the image)
|
|
for(int y = bmp_height-1; y >= 0; y--)
|
|
{
|
|
// Get the "current" line pointer
|
|
uchar *LinePtr = getLinePtr(y);
|
|
|
|
// Read the precise number of bytes that the scan line requires into the bitmap
|
|
if(!fread(LinePtr, bytesPerLine, 1, bmp_file))
|
|
{
|
|
fclose(bmp_file);
|
|
return false;
|
|
}
|
|
|
|
// Skip over any padding bytes.
|
|
if(fseek(bmp_file, padding, SEEK_CUR))
|
|
{
|
|
fclose(bmp_file);
|
|
return false;
|
|
}
|
|
|
|
} // end of for (int y = 0; y < bmp_infoheader.biHeight; y++)
|
|
|
|
|
|
fclose(bmp_file);
|
|
return true; // If we get here .bmp was read in successfully
|
|
|
|
} // end of loadBMP(char *file_name, HDC hdc)
|
|
|
|
// Returns the address in memory of the specified line. This gives you a pointer to at least
|
|
// width * channels bytes. Lines are numbered such that when the bitmap
|
|
// is displayed line zero is at the top.
|
|
uchar* DIB_BITMAP::getLinePtr(int which_line)
|
|
{
|
|
return (surface_bits + bmp_stride * which_line);
|
|
}
|
|
|
|
// Release the memory
|
|
void DIB_BITMAP::FreeDIB_BMP()
|
|
{
|
|
// If we created an HBITMAP, delete it
|
|
if(hbitmap)
|
|
DeleteObject(hbitmap);
|
|
|
|
// Zero out all data associated with DIB_BITMAP
|
|
hbitmap = NULL;
|
|
surface_bits = NULL;
|
|
bmp_width = bmp_height = bmp_channels = bmp_stride = 0;
|
|
return;
|
|
}
|
|
|
|
// Deconstructor
|
|
DIB_BITMAP::~DIB_BITMAP() { FreeDIB_BMP(); }
|
|
|
|
|
|
const char *BOINC_RCSID_1051ce617a = "$Id$";
|