Writing Bmp Image in Pure C/C++ Without Other Libraries

Writing BMP image in pure c/c++ without other libraries

Without the use of any other library you can look at the BMP file format. I've implemented it in the past and it can be done without too much work.

Bitmap-File Structures

Each bitmap file contains a
bitmap-file header, a
bitmap-information header, a color
table, and an array of bytes that
defines the bitmap bits. The file has
the following form:

BITMAPFILEHEADER bmfh;

BITMAPINFOHEADER bmih;

RGBQUAD aColors[];

BYTE aBitmapBits[];

... see the file format for more details

How to load to C++ 8-bit bitmap image without using external libraries?

What do you mean by "bitmap"? There are several image formats. Do you mean a .bmp - file?

In any case, you should find the format specification of the particular file and read the dimensions from the header first. Then read the data.
The dimensions are not the only important values. An image could contain more bytes per row then actual pixels i.e. Or the coordinates could be flipped, etc.
In general, not using an image library is not a good idea.

But, maybe you have to (possibly because you use some exotic CPU-architecture)
Here you can find routines e.g for reading png-files. All examples are self contained and don't use libraries. http://www.ipol.im/

EDIT:

since you've specified, that it should be BMP-format, this question should be of help for you: Getting the pixel value of BMP file

How to make a bmp header in c++?

Look at this link:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx

typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;

BITMAPFILEHEADER header;
// Fill your header;
std::ofstream of(/*your file name...*/);
of.write(&header, sizeof(header));

You can use any other file implementation instead of std::ofstream.

Writing BMP data getting garbage

Shouldn't you open the file in a compound mode i.e. writable & binary as in wb+?

Notice the start of the distortion with the "0d"

That's ASCII code for Carriage Return (CR) -- added on some OSes with newline (where a newline is actually a sequence of CR/LF). This should go away once you start writing the output in binary mode.

Your code looks neat otherwise. Cheers!

C++: Convert text file of integers into a bitmap image file in BMP format

Here's an app which generates a text file of random integers, reads them back, and writes them to disk as a (roughly square) 32-bit-per-pixel .BMP image.

Note, I made a number of assumptions on things like the format of the original text file, the range of numbers, etc., but they are documented in the code. With this working example you should be able to tweak them easily, if necessary.

// IntToBMP.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <cstdint>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <random>
#include <ctime>
#include <memory>

#pragma pack( push, 1 )
struct BMP
{
BMP();
struct
{
uint16_t ID;
uint32_t fileSizeInBytes;
uint16_t reserved1;
uint16_t reserved2;
uint32_t pixelArrayOffsetInBytes;
} FileHeader;

enum class CompressionMethod : uint32_t { BI_RGB = 0x00,
BI_RLE8 = 0x01,
BI_RLE4 = 0x02,
BI_BITFIELDS = 0x03,
BI_JPEG = 0x04,
BI_PNG = 0x05,
BI_ALPHABITFIELDS = 0x06 };

struct
{
uint32_t headerSizeInBytes;
uint32_t bitmapWidthInPixels;
uint32_t bitmapHeightInPixels;
uint16_t colorPlaneCount;
uint16_t bitsPerPixel;
CompressionMethod compressionMethod;
uint32_t bitmapSizeInBytes;
int32_t horizontalResolutionInPixelsPerMeter;
int32_t verticalResolutionInPixelsPerMeter;
uint32_t paletteColorCount;
uint32_t importantColorCount;
} DIBHeader;
};
#pragma pack( pop )

BMP::BMP()
{
//Initialized fields
FileHeader.ID = 0x4d42; // == 'BM' (little-endian)
FileHeader.reserved1 = 0;
FileHeader.reserved2 = 0;
FileHeader.pixelArrayOffsetInBytes = sizeof( FileHeader ) + sizeof( DIBHeader );
DIBHeader.headerSizeInBytes = 40;
DIBHeader.colorPlaneCount = 1;
DIBHeader.bitsPerPixel = 32;
DIBHeader.compressionMethod = CompressionMethod::BI_RGB;
DIBHeader.horizontalResolutionInPixelsPerMeter = 2835; // == 72 ppi
DIBHeader.verticalResolutionInPixelsPerMeter = 2835; // == 72 ppi
DIBHeader.paletteColorCount = 0;
DIBHeader.importantColorCount = 0;
}

void Exit( void )
{
std::cout << "Press a key to exit...";
std::getchar();

exit( 0 );
}

void MakeIntegerFile( const std::string& integerFilename )
{
const uint32_t intCount = 1 << 20; //Generate 1M (2^20) integers
std::unique_ptr< int32_t[] > buffer( new int32_t[ intCount ] );

std::mt19937 rng;
uint32_t rngSeed = static_cast< uint32_t >( time( NULL ) );
rng.seed( rngSeed );

std::uniform_int_distribution< int32_t > dist( INT32_MIN, INT32_MAX );

for( size_t i = 0; i < intCount; ++i )
{
buffer[ i ] = dist( rng );
}

std::ofstream writeFile( integerFilename, std::ofstream::binary );

if( !writeFile )
{
std::cout << "Error writing " << integerFilename << ".\n";
Exit();
}

writeFile << buffer[ 0 ];
for( size_t i = 1; i < intCount; ++i )
{
writeFile << " " << buffer[ i ];
}
}

int _tmain(int argc, _TCHAR* argv[]) //Replace with int main( int argc, char* argv[] ) if you're not under Visual Studio
{
//Assumption: 32-bit signed integers
//Assumption: Distribution of values range from INT32_MIN through INT32_MAX, inclusive
//Assumption: number of integers contained in file are unknown
//Assumption: source file of integers is a series of space-delimitied strings representing integers
//Assumption: source file's contents are valid
//Assumption: non-rectangular numbers of integers yield non-rectangular bitmaps (final scanline may be short)
// This may cause some .bmp parsers to fail; others may pad with 0's. For simplicity, this implementation
// attempts to render square bitmaps.

const std::string integerFilename = "integers.txt";
const std::string bitmapFilename = "bitmap.bmp";

std::cout << "Creating file of random integers...\n";
MakeIntegerFile( integerFilename );

std::vector< int32_t >integers; //If quantity of integers being read is known, reserve or resize vector or use array

//Read integers from file
std::cout << "Reading integers from file...\n";
{ //Nested scope will release ifstream resource when no longer needed
std::ifstream readFile( integerFilename );

if( !readFile )
{
std::cout << "Error reading " << integerFilename << ".\n";
Exit();
}

std::string number;
while( readFile.good() )
{
std::getline( readFile, number, ' ' );
integers.push_back( std::stoi( number ) );
}

if( integers.size() == 0 )
{
std::cout << "No integers read from " << integerFilename << ".\n";
Exit();
}
}

//Construct .bmp
std::cout << "Constructing .BMP...\n";
BMP bmp;
size_t intCount = integers.size();
bmp.DIBHeader.bitmapSizeInBytes = intCount * sizeof( integers[ 0 ] );
bmp.FileHeader.fileSizeInBytes = bmp.FileHeader.pixelArrayOffsetInBytes + bmp.DIBHeader.bitmapSizeInBytes;
bmp.DIBHeader.bitmapWidthInPixels = static_cast< uint32_t >( ceil( sqrt( intCount ) ) );
bmp.DIBHeader.bitmapHeightInPixels = static_cast< uint32_t >( ceil( intCount / static_cast< float >( bmp.DIBHeader.bitmapWidthInPixels ) ) );

//Write integers to .bmp file
std::cout << "Writing .BMP...\n";
{
std::ofstream writeFile( bitmapFilename, std::ofstream::binary );

if( !writeFile )
{
std::cout << "Error writing " << bitmapFilename << ".\n";
Exit();
}

writeFile.write( reinterpret_cast< char * >( &bmp ), sizeof( bmp ) );
writeFile.write( reinterpret_cast< char * >( &integers[ 0 ] ), bmp.DIBHeader.bitmapSizeInBytes );
}

//Exit
Exit();
}

Hope this helps.

After writing BMP file, image is flipped upside down

Bitmaps are stored "upside-down", see more about that here:

Why are bmps stored upside down?

You could set the height as a negative value to have it displayed correctly. (-height)

From MSDN site, BITMAPINFOHEADER:

If biHeight is negative, the bitmap is a top-down DIB with the
origin at the upper left corner.



Related Topics



Leave a reply



Submit