C++ Tips & Tricks - Bitmap Tutorial - Loading and Saving Bitmaps

Download as pdf or txt
Download as pdf or txt
You are on page 1of 10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

ProgrammingTips&Tricks
HomeCategories:C#|C++|General|Other

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

1.Introduction
2.LoadingabitmaptoaDC
3.Loadingabitmap
4.ConvertingBitmapdatatoanRGBarray
5.SavingaBitmap
6.ConvertingRGBdatatosaveablebmpdata
7.Conclusion
8.Downloadthecode

1.Introduction
Thewindowsbitmapfileformat(.bmp)isthemostwidelyusedimagefileformatonwindows(nextto.jpg),and
therearemanyoccasionsaprogramorgamehastobeabletoloadorsavebitmaps(raytracersandothernon
realtimerenderersshouldbeabletosavetheiroutputin.bmpformat,gamesmighthavetoloadthemastextures
etc.).
Unfortunately.bmpfilesarenotasstraightforwardasforexample.pngimagefilesandprovidequiteaproblemfor
newbiessinceit'snotthateasytofigureouthowtousethemwhenwithoutalibraryorAPI.
Twonotesbeforewestart:
1)Inthistutorialwe'redealingwith24bitbmpsonly.Butitshouldn'tbehardtochangethecodetosupportother
formats.
2)Forclarity'ssakei'monlyshowingthecodeimportanttothetaskathand,withonlyminimalerrorchecking.Ifyou
wanttousethiscodeinarealprogram,youshouldaddsomeexceptionhandling.

2.LoadingabitmaptoaDC
I'mgoingtostartthiseasybyshowingyouhowtousetheWinAPItoloadabitmapontoadevicecontext.
Firstwedeclarethefunctionthattakesasinputadevicecontextandafilename:
boolLoadBMPIntoDC(HDChDC,LPCTSTRbmpfile)
{
Nowwecheckifthesuppliedargumentsarevalid.Ifnotwereturnfalse.

if((NULL==hDC)||(NULL==bmpfile))

returnfalse;

WethenusethewindowsfunctionLoadImagetoloadthebitmapintoaBitmapHandle:

HANDLEhBmp=LoadImage(NULL,bmpfile,IMAGE_BITMAP,0,0,

LR_LOADFROMFILE);

Thefirstparameteristheinstancethatcontainstheimage,butsinceweareloadingitfromafileandnotfroma
resource,thisisNULL.Thesecondparamisthefilename.Withthethirdonewetellthefunctiontoloadabitmap(it
canalsoloadiconsandcursors).Thenexttwoparamsaredesiredwidthandheight.0meansthatwewantthe
actualbitmapsizereadfromthefile.Finallywehavetotellthefunctionthatwewanttoloadthebitmapfromafile.
Toloadanimagefromaresourcefilewewouldusethefunctionlikethis:

HANDLEhBmp=LoadImage(hInstance,MAKEINTRESOURCE(imageid),

http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

1/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

IMAGE_BITMAP,0,0,LR_DEFAULTCOLOR);

wherehInstanceisthehandleoftheinstanceoftheprogram(theHINSTANCEinWinMain),imageidisthe
identifieroftheimageintheresourcefileandLR_DEFAULTCOLORisthestandarddonothingflag.
Nowwedoaquickcheckifthefunctionreturnedausablehandle:

if(NULL==hBmp)

returnfalse;

Atthispointwehaveavalidimagehandle.Nowwewanttoselectitintoadevicecontext.Unfortunatelyitisnot
possibletoselectitdirectlyintoavisibleDC,butonlyintoamemoryDC,sowehavetocreatethatfirst:

HDCdcmem=CreateCompatibleDC(NULL);

Thisfunctioncreatedamemorydevicecontextthatiscompatibletothescreen.
Nowwecanselectthebitmapintoit:

if(NULL==SelectObject(dcmem,hBmp))
{
//failedtoloadbitmapintodevicecontext

DeleteDC(dcmem);

returnfalse;
}

Ifthefunctionfailsitdeletesthememorydcandreturnsfromthefunction.
Ifitwassuccessfulwecannowblittheimagefromthememorydctothevisibledcwesuppliedasthefirst
parametertoourLoadBMPIntoDCfunction.
Toblittheentireimagewefirsthavetofindoutit'ssizethough,buttheWinAPIsuppliesuswithaneasywaytoget
thewidthandheightofabitmaphandle:

BITMAPbm;
GetObject(hBmp,sizeof(bm),&bm);

Thisfunctionloadstheinformationfromthehandle,whichisnotmuchmorethenapointer,intoaBITMAP
structurethatletsusaccessthewidthandheightoftheimage,storedinbm.bmWidthandbm.bmHeight.With
thosevalueswecannowblitthewholeimagetothevisibleDC:

//andblitittothevisibledc
if(BitBlt(hDC,0,0,bm.bmWidth,bm.bmHeight,dcmem,

0,0,SRCCOPY)==0)
{
//failedtheblit

DeleteDC(dcmem);

returnfalse;
}

ThefunctionblitstheentireimagetotheupperleftofthevisibleDCandcleansuponfailure.
Onsuccesswecannowseetheimageonthescreen.
Nowwedon'tneedthememorydcanymoreandcanfinishthefunction:

DeleteDC(dcmem);//clearupthememorydc
returntrue;

Todisplayanimage,wecanusethefunctionlikethis(hWndisthewindowhandle):
HDCdc=GetDC(hWnd);//getdevicecontext
LoadBMPIntoDC(dc,L"test.bmp");//displaytest.bmponit
ReleaseDC(hWnd,dc);//releasedc
Youcanofcoursemodifythecodetosuityourneeds,forexampleyoucanchangetheBitBlttoonlycopypartsof
theimageortocopyittoapositiondifferentfrom(0,0)onthedestinationDC.

3.LoadingaBitmap
Mostofthetimewewanttoworkwiththebitmapdatadirectly(e.g.useitasatexture),andnotjustdisplayitona
windowdc,sothenextthingi'llshowyouishowtoloadabitmap.
http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

2/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

Beforeweattempttoloaditweshouldtakeashortlookatthestructureofa.bmpfile.
A24bitbmpconsistsof3parts:
1)Thefileheader,thatholdsinformationabouttype,sizeandlayoutofthefile
2)Theinfoheader,thatholdsinformationaboutdimensionandcolorformatoftheimage
3)Theimagedata
Apalettized.bmp(4or8bit)additionallyholdsacolorpalettebetweeninfoheaderandimagedata,butwe'reonly
lookingattheusual24bitbmpinthistutorial.
TheWinAPIisagainniceenoughtosupplyuswiththestructsforthefileandinfoheader,butyoucanaswell
declarethemyourselfifyoudon'twanttouseanywindowsfunctionsorwanttoload.bmpsonanotherOS.They
looklikethis:
typedefstructtagBITMAPFILEHEADER
{
WORDbfType;//mustbe'BM'
DWORDbfSize;//sizeofthewhole.bmpfile
WORDbfReserved1;//mustbe0
WORDbfReserved2;//mustbe0
DWORDbfOffBits;
}BITMAPFILEHEADER;
ThebfOffBitsmemberisabitconfusingduetoit'sname.Actuallyitisthedistancetothebeginningoftheimage
data,inbytes,fromthebeginningofthefile.Thisisduetothefactthatthesizeoftheinfoheaderisnotfixedtoa
certainsize,sinceonnewerwindowsversionstheremightbeanextendedversionoftheheader,thusitisnot
guaranteedthattheimagadatastartsatsizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)
(althoughyoucanalwaysreadinaBITMAPINFOHEADERsincetheexpandedinfoheadershavethesame
layout).So,toreadtheimagedatalateronwewillmovethefilepointertobfOffBitsandstartreadingthere.
Nowletstakealookattheinfoheader:
typedefstructtagBITMAPINFOHEADER
{
DWORDbiSize;//sizeofthestructure
LONGbiWidth;//imagewidth
LONGbiHeight;//imageheight
WORDbiPlanes;//bitplanes
WORDbiBitCount//resolution
DWORDbiCompression;//compression
DWORDbiSizeImage;//sizeoftheimage
LONGbiXPelsPerMeter;//pixelspermeterX
LONGbiYPelsPerMeter;//pixelspermeterY
DWORDbiClrUsed;//colorsused
DWORDbiClrImportant;//importantcolors
}BITMAPINFOHEADER;
Alittlenote:ifyoudon'tusethestructdeclarationsfromwindows.hbutpastetheaboveintoyourcode,youneedto
makesurethatyourcompileralignsdatastructureson2byteboundaries,elsetheloadingandsavingwillnotwork
correctlysincethecompilerusuallypadsthestructurestothenext4byteboundary.Settinga2bytealignisluckily
veryeasywithVC++:justadd#pragmapack(2)beforethestructdeclaration.Ifyouuseanothercompileryouwill
havetoconsultit'sdocumentsonhowtochangethealignment.
Oknowwecanwriteafunctiontoloadthebitmap(i'musingwindowsfileI/Ohere,butyoucanusefopen/fread
etc.orSTLfunctionsaswell..whateveryoulike.)
Letsdeclarethefunctionandsomevariables:
BYTE*LoadBMP(int*width,int*height,long*size,LPCTSTRbmpfile)
{

BITMAPFILEHEADERbmpheader;

BITMAPINFOHEADERbmpinfo;

DWORDbytesread;
Notethatwetakethreepointersasparametersforwidth,heightandsize,sincewewillreturntheimage
dimensionsandsizeinthesevariables.bmpfileisofcoursethefilenameofthebitmap,andthereturnvalueofthe
functionwillbeapointertotheimagedata.
Firstletstrytoopenthefile:

HANDLEfile=CreateFile(bmpfile,GENERIC_READ,FILE_SHARE_READ,

NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);

http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

3/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

if(NULL==file)

returnNULL;

Justaquicknotehere:it'susefultowriteif(NULL==file)insteadofif(file==NULL)topreventbugs,sinceon
accidentlytypingif(file=NULL)thecompilerwillnotcomplainbutassignNULLtothefilehandle.if(NULL=file)
willspawnacompilererror,soyoucanpreventbugseasilythisway.
Backtothetopic:nowweopenedthefileandcanreadthefileheader.Onerrorwewillclosethefileandreturn
fromthefunction.

if(ReadFile(file,&bmpheader,sizeof(BITMAPFILEHEADER),

&bytesread,NULL)==false)
{

CloseHandle(file);

returnNULL;
}

Nowwecanreadtheinfoheader:

if(ReadFile(file,&bmpinfo,sizeof(BITMAPINFOHEADER),

&bytesread,NULL)==false)
{

CloseHandle(file);

returnNULL;
}

Sinceweareonlygoingtoload24bit.bmpsherewenowdosomecheckingoftheheadercontents.
Firstcheckifthefileisactuallyabitmap:

if(bmpheader.bfType!='MB')
{

CloseHandle(file);

returnNULL;
}

checkifit'suncompressed

if(bmpinfo.biCompression!=BI_RGB)
{

CloseHandle(file);

returnNULL;
}

andcheckifit's24bit

if(bmpinfo.biBitCount!=24)
{

CloseHandle(file);

returnNULL;
}

Whenwearehereweactuallyhavea24bitbmp,soletsgetitssizeanddimensions.We'llstoretheminthe
suppliedvariables:

*width=bmpinfo.biWidth;
*height=abs(bmpinfo.biHeight);
*size=bmpheader.bfSizebmpheader.bfOffBits;

Tobeindependentofthetypeofinfoheader,wecomputetheimagadatasizeasthewholefilesizeminusthe
distancefromfileorigintostartofimagedata.
Nowwecreateabuffertoholdthedata

BYTE*Buffer=newBYTE[*size];

Again,tobeindependentofinfoheaderversion,wesetthefilepointertothestartofimagedataastoldbythe
bfOffBits:

SetFilePointer(file,bmpheader.bfOffBits,NULL,FILE_BEGIN);

http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

4/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

Andnowwecanreadinthedata.WemakesurethatonerrortheBuffergetsdeletedsowedon'tcreatememory
leaks:

if(ReadFile(file,Buffer,*size,&bytesread,NULL)==false)
{

delete[]Buffer;

CloseHandle(file);

returnNULL;
}

andfinishthefunction

CloseHandle(file);
returnBuffer;

Aquickexampleofhowtousethefunction:
intx,y;
longsize;
BYTE*Buffer=LoadBMP(&x,&y,&size,L"test.bmp");
Unfortunatelywehaveaproblemnow.Thedatawereadfromtheimageandreturnedfromthefunctionisn'tquite
whatonemightexpectittobe.
Onewouldexpectthatwenowhaveabufferofwidth*heightRGBtriplets,butunfortunatelybitmapsstoretheir
dataalittlebitunstraightforward:
Basicallytheystoreeverythingfrombacktofront:theimageisstoredupsidedowninthefile,andnotinRGB
triplets,butinBGRtriplets.
Andanotherthingcomesintoplay:scanlinesin.bmpsareDWORDaligned.Thismeansthateveryscanline(there
are(height)scanlinesinanimage)whichisnotamultipleof4byteslong(DWORD==4bytes)isfilledupwith
zerostothenextmultipleof4.
ThusiftheimagewouldbejustoneblackpixelitisnotstoredasoneRGBtriplet(FF,FF,FF)inthefile,butasa
DWORD(FF,FF,FF,00).Thismeans,thatifwetreatthedataasanRGBarraywegetsomewrongcolors,
sincewemustnotinterpretetheaddedzerosascolorvalues.
LuckilythegraphicsAPIscandealwiththeunusualstructureof.bmpimagedata:
InOpenGLitispossibletoassignthebufferreturnedbyLoadBMPdirectlytoatextureifweaddthefollowingcode
beforecallstoglTexImage2D:
glPixelStorei(GL_UNPACK_ALIGNMENT,4);
glPixelStorei(GL_UNPACK_ROW_LENGTH,0);
glPixelStorei(GL_UNPACK_SKIP_ROWS,0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);
Idon'tknowhowtodoitwithD3D,butitshouldbepossibletheretoo.
Butthistutorialisalsoforpeoplewhodon'tuseanAPIforit,soletsmoveontothenextsection.

4.ConvertingBitmapdatatoanRGBarray
NowiwillshowyouhowtotakethepaddedupsidedownBGRimagedataandconvertitintoanRGBbuffer.
ThefunctionwilltakeasargumentstheBYTEarray,thewidthandtheheightreturnedfromLoadBMP.Theoutput
willbeanarrayofRGBtripletsandthushavethesize3*width*height.
ThismeansifBufferistheoutputofthefunction,theRGBcolorofthefirstpixelintheimagewillbe(Buffer[0],
Buffer[1],Buffer[2]),thesecondpixel's(Buffer[3],Buffer[4],Buffer[5])etc.
Itispossible,andperhapsmorestraightforward,tocreateastructlikethis:
typedefstructtagRGBTriplet
{

BYTEred;

BYTEgreen;

BYTEblue;
}RGBTriplet;
andthenmakeanarrayofsuchstructsandassigntheoutputfromthefunctiontoitlikethis:
RGBTriplet*buffer=(RGBTriplet*)ConvertBMPToRGBBuffer

(imagedata,width,height);
http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

5/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

bufferwillthenconsistofwidth*heightRGBTripletstructuresandthecolorofthefirstpixelintheimagewouldbe(
buffer[0].red,buffer[0].green,buffer[0].blue).
Nowletslookatthecode:
Firstwedeclarethefunctionandmakesurewehavenoinvalidparams:
BYTE*ConvertBMPToRGBBuffer(BYTE*Buffer,intwidth,intheight)
{

if((NULL==Buffer)||(width==0)||(height==0))

returnNULL;
Nowwehavetofindoutthenumberofbyteseveryscanlineispaddedwith

intpadding=0;
intscanlinebytes=width*3;
while((scanlinebytes+padding)%4!=0)

padding++;

Attheendofthewhilelooppaddingwillholdthenumberofpaddingbytes.
Nowwecangetthelengthinbytesofapaddedscanline:

intpsw=scanlinebytes+padding;

Andconstructthebuffertoholdtheoutput

BYTE*newbuf=newBYTE[width*height*3];

The3standsforthenumberofbytesinoneRGBTripletofcourse.
Nowcomestheheartofthefunction:

longbufpos=0;
longnewpos=0;
for(inty=0;y<height;y++)

for(intx=0;x<3*width;x+=3)

newpos=y*3*width+x;

bufpos=(heighty1)*psw+x;

newbuf[newpos]=Buffer[bufpos+2];
newbuf[newpos+1]=Buffer[bufpos+1];
newbuf[newpos+2]=Buffer[bufpos];

Whatexactlyhappensinthisloop?
Forclearcodeandsomemorespeedwedeclaretwovariablesthatwillholdthebufferindices.
Thefirstforlooploopstrougheachscanlineintheimagedata,thesecondloophitsevery3rdbyteinascanline,
meaningthestartofeveryRGBtriplet(representingapixel).
ThenwecomputetheindexthecurrentpixelwillhaveinthenewRGBbufferascurrentscanline*imagewidth*
numberofbytesperpixel+positionofcurrentpixel.
Nextwecomputethepositionwehavetolookatforthecurrentpixelintheimagedata.Theimagewasstored
upsidedowninthe.bmp,thusifwewanttofindapixelcolorinthefirstlinewehavetolookatthelastscanlinein
theimagedata.Becausewestartindexingarrayswith0,thescanlinetolookforisimageheightcurrentscanline
(theyvariableoftheloop)1.
Togettheexactpixelposition,wehavetomultiplythescanlinenumberbytheamountofbytesperscanlineinthe
buffer,whichwealreadycomputedinpsw.Andfinallyweaddthexpositionofthecurrentpixel.
Sonowwehavethepositionthepixel(x,y)willhaveinthenewbufferinnewpos,andthepositionthecolorvalues
forthispixelareatintheimagedataisinbufpos.
Nowwecouldjustassignthosevalues,butrememberthatthecolorvaluesthemselvesarestoredinBGRformatin
theimage,andwewanttheminRGBformat,sowehavetoswapthebytesatourposition(redvalue)andtheone
atourpoition+2(bluevalue).
Ihopethatwashalfwayclear:)
Nowwecanfinishthefunction:

returnnewbuf;

http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

6/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

Ihavetwomorethingstoadd:
1)Asistatedintheintroductioni'monlydoingrudimentaryerrorcheckinghere.Youcanseethatifthebuffer
passedtothefunctionissmallerthenwidth*height*3,theloopwilltrytoaccessdatathatdoesn'tbelongtothearray
whichmightcrashtheprogram.
Topreventthisfromhappeningitwouldbegoodtodosomeexceptionhandlingandwrapthefunctionoratleatthe
loopina__try__catchblockandmakesureyoupasstheexactoutputfromLoadBMPtothefunction.
2)Thefunctioncreatesanewbufferwhichitthenreturns,thusthecallingfunctionhastomakesurethisbufferis[]
deletedwhennotlongerneededtopreventmemoryleaks.

5.SavingaBitmap
Nowthaticoveredhowtoloadanimage,thenexttopicishowtosaveanimageasabitmap.
Ialreadydescribedthestructureof.bmpfilesinsection3,solookthereagainifanythingisunclear.
Letsbeginbydeclaringthefunction
boolSaveBMP(BYTE*Buffer,intwidth,intheight,longpaddedsize,LPCTSTRbmpfile)
{
Bufferisanarraythatcontainstheimagedata,widthandheightarethedimensionsoftheimagetosave,and
paddedsizeisthesizeofBufferinbytes.bmpfileisthefilenametosaveto.
Firstwedeclaretheheaderstructsandclearthem:

BITMAPFILEHEADERbmfh;
BITMAPINFOHEADERinfo;
memset(&bmfh,0,sizeof(BITMAPFILEHEADER));
memset(&info,0,sizeof(BITMAPINFOHEADER));

Nextwefillthefileheaderwithdata:

bmfh.bfType=0x4d42;//0x4d42='BM'
bmfh.bfReserved1=0;
bmfh.bfReserved2=0;
bmfh.bfSize=sizeof(BITMAPFILEHEADER)+

sizeof(BITMAPINFOHEADER)+paddedsize;
bmfh.bfOffBits=0x36;

andtheinfoheader:

info.biSize=sizeof(BITMAPINFOHEADER);
info.biWidth=width;
info.biHeight=height;
info.biPlanes=1;
info.biBitCount=24;
info.biCompression=BI_RGB;
info.biSizeImage=0;
info.biXPelsPerMeter=0x0ec4;
info.biYPelsPerMeter=0x0ec4;
info.biClrUsed=0;
info.biClrImportant=0;

Someexplanations:wewanttosaveasa24bitRGBimage,sowehavetosetbiCompressiontoBI_RGB,
biBitCountto24andbiPlanesto1.
In24bitimageswecansetthebiSizeImagevalueto0sinceitisignored.
ForPelsPerMeterisimplyusethevaluesthatPaintuseswhensavingbitmaps.
Sincewehavenopalette,wesetthebiClrUsedto0,andbiClrImportantbeingzeromeansthatallcolorsare
important.
Nowwecanopenafiletosaveto(againi'musingwindowsfunctionsbutitdoesntmatterwhatfileI/Ofunctions
youuseofcourse)

HANDLEfile=CreateFile(bmpfile,GENERIC_WRITE,FILE_SHARE_READ,

NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(NULL==file)
{

CloseHandle(file);

returnfalse;

http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

7/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

Nowwewritethefileheaderandinfoheader:

unsignedlongbwritten;
if(WriteFile(file,&bmfh,sizeof(BITMAPFILEHEADER),

&bwritten,NULL)==false)
{

CloseHandle(file);

returnfalse;
}

if(WriteFile(file,&info,sizeof(BITMAPINFOHEADER),

&bwritten,NULL)==false)
{

CloseHandle(file);

returnfalse;
}

andfinallytheimagedata:

if(WriteFile(file,Buffer,paddedsize,&bwritten,NULL)==false)
{

CloseHandle(file);

returnfalse;
}

Nowwecancloseourfunctionwith

CloseHandle(file);
returntrue;

Tosaveabufferwithimagedataasa.bmpfileyouusethefunctionlikethis:(Bufferholdsthedata,issbytesin
sizeandofdimensionwidth*height)
SaveBMP(Buffer,width,height,s,L"test.bmp");
Unfortunatelywenowhavethesameproblemasabove:theweirdformatoftheimagedata.Tobeopenedand
displayedintherightwaybyotherprogramswecan'tsaveanRGBbuffertoabmpfile,butfirsthavetoconvertit
toBGR,flipitupsidedownandDWORDalignthescanlines.

6.ConvertingRGBdatatosaveablebmpdata
BasicallythisfunctionistheoppositeoftheConvertBMPToRGBBufferfromabove,soi'mnotgoingtoexplain
everydetailagain.
Firstdeclarethefunctionandcheckparamsforvalidity:
BYTE*ConvertRGBToBMPBuffer(BYTE*Buffer,intwidth,intheight,

long*newsize)
{

if((NULL==Buffer)||(width==0)||(height==0))

returnNULL;
findthenumberofbytesthebufferhastobepaddedwithandlengthofpaddedscanline:

intpadding=0;
intscanlinebytes=width*3;
while((scanlinebytes+padding)%4!=0)

padding++;
intpsw=scanlinebytes+padding;

calculatethesizeofthepaddedbufferandcreateit:

*newsize=height*psw;

http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

8/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

BYTE*newbuf=newBYTE[*newsize];

Nowwecouldofcoursecopytheoldbuffertothenewone,flipitandchangeRGBtoGRBandthenfillevery
scanlinewithzeroestothenextDWORDboundary,butwearesmartcodersofcourse,sowedon'tbotherwith
anyactualpaddingatall,butjustinitializethewholebufferwithzeroesandthencopythecolorvaluestotheirnew
positionswithouttouchingthosepaddingbytesanymore:)

memset(newbuf,0,*newsize);

longbufpos=0;
longnewpos=0;
for(inty=0;y<height;y++)

for(intx=0;x<3*width;x+=3)

bufpos=y*3*width+x;//positioninoriginalbuffer

newpos=(heighty1)*psw+x;//positioninpaddedbuffer

newbuf[newpos]=Buffer[bufpos+2];//swaprandb

newbuf[newpos+1]=Buffer[bufpos+1];//gstays

newbuf[newpos+2]=Buffer[bufpos];//swapbandr

}
returnnewbuf;

Remembertodeleteallbuffersattheendoftheprogramandconsideraddingsomeexceptionhandling.

7.Conclusion
Andthat'sallthereisto.bmps.Andthatinlessthen200linesofcode:)
Toconcludethistutorial,herearesomeexamplesthatshowhowtousethefunctionswe'vewrittenabove:
ThisfunctioncopiestheinputfiletotheoutputfilewiththeSaveBMPandLoadBMPfunctions:
voidTestBMPCopy(LPCTSTRinput,LPCTSTRoutput)
{

intx,y;

longs;

BYTE*b=LoadBMP(&x,&y,&s,input);

SaveBMP(b,x,y,s,output);

delete[]b;
}
Thisfunctiondoesthesame,butalsoteststheconvertfunctions:
voidTestBMPCopy2(LPCTSTRinput,LPCTSTRoutput)
{

intx,y;

longs,s2;

BYTE*a=LoadBMP(&x,&y,&s,input);

BYTE*b=ConvertBMPToRGBBuffer(a,x,y);

BYTE*c=ConvertRGBToBMPBuffer(b,x,y,&s2);

SaveBMP(c,x,y,s2,output);

delete[]a;

delete[]b;

delete[]c;
}
Ifyouhaveaprogramthatrenderedanimageofdimensionx*yintoanRGBbuffer,youcansaveittoa.bmpfile
likethis:

longs;
BYTE*b=ConvertRGBToBMPBuffer(buffer,x,y,&s);
SaveBMP(b,x,y,s,L"image.bmp");
delete[]b;

andtoloadanimage,e.g.asatexture,intoanRGBbuffer:
http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

9/10

12/5/2015

C++Tips&Tricks:BitmapTutorial:LoadingandSavingBitmaps

intx,y;
longs;
BYTE*a=LoadBMP(&x,&y,&s,L"texture.bmp");
BYTE*TexBuf=ConvertBMPToRGBBuffer(a,x,y);
delete[]a;

8.Downloadthecode
Tomakeyourlifeeasier,soyoudon'thavetocopy/pasteeverythingfromthispage,youcangetone.cppfilewith
thewholecode(documented)here:
BMP.cpp

AndreasHartl,20102011
Runicsoft.com

http://tipsandtricks.runicsoft.com/Cpp/BitmapTutorial.html

10/10

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy