C++ Tips & Tricks - Bitmap Tutorial - Loading and Saving Bitmaps
C++ Tips & Tricks - Bitmap Tutorial - Loading and Saving Bitmaps
C++ Tips & Tricks - Bitmap Tutorial - Loading and Saving Bitmaps
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