Depending on color depth, each pixel needed 1 bit (for black and white), 1 byte (for 256 color), 3 bytes (for RGB - 16 billions color), and so on
Like many other file types, the BMP has a specific structure.
First is a file header (which begins with the file signature), followed by the data (in this case the pixels).
The file header is well described [1]
The data (the matrix of pixels) is stored row by row, in the BMP file, from bottom to top.
Which means that right after the file header comes the row of pixels from the bottom of the picture, the the one right above him, and so on.
Because the header is fixed, I've created a class for that. The class attach to this header the pixels matrix, expressed as a string of RGB values and save it to a binary file with BMP as extension.
In the first example, let's create a small white 10 x 5 bitmap, i.e a picture with five rows, each row containing 10 white pixels.
****************************
* Creating a 10 x 5 bitmap
****************************
****************************************************
* The midmap look like this:
* WWWWWWWWWW
* WWWWWWWWWW
* WWWWWWWWWW
* WWWWWWWWWW
* WWWWWWWWWW
* One W is a white pixel
****************************************************
LOCAL loBmp,
lcTrailerZeros, lcWhitePixel, lcWhiteRow
loBmp = CREATEOBJECT("bmpcreator")
loBmp.nWidth = 10
loBmp.nHeight = 5
* Each row of pixels must have as
a length in bytes a multiple of 4. If necessary a few CHR(0) are added
lcTrailerZeros = IIF(MOD( m.loBmp.nWidth
* 3,4) <> 0, REPLICATE(CHR(0),4 - MOD( m.loBmp.nWidth * 3,4)), "")
* One pixel has three bytes,
corresponding to RGB
lcWhitePixel = CHR(255) + CHR(255) + CHR(255)
* One row contain loBmp.nWidth
npixels; DO NOT FORGET the trailing zeroes
lcWhiteRow = REPLICATE(m.lcWhitePixel,
m.loBmp.nWidth) + m.lcTrailerZeros
* The BITMAP is a loBmp.nHeight
of rows
loBmp.cBitmap = REPLICATE(m.lcWhiteRow,
m.loBmp.nHeight)
loBmp.genbmp("01")
DEFINE CLASS bmpcreator as Custom
* Generic
properties
nWidth = 1 &&
Bitmap width in pixels
nHeight = 1 &&
bitmap height in pixels
cBitmap = '' && the
bitmap as a string of RGB triplets
**************************************************************************************
*
generic procedure that writes the bitmap to a BMp file, stored in cBitmap
property
**************************************************************************************
PROCEDURE genbmp
*
*
Returns the name of the bmp file
*
*
Parameters:
*
- tcFile (optional) file name. By default sys(2015)
*
LPARAMETERS tcFile
LOCAL lni,lnByteLength,lcSa,lnNumber
IF PCOUNT() < 1
tcFile
= SYS(2015)
ENDIF
tcFile = FORCEEXT(m.tcFile,
'bmp')
lnByteLength
= LEN(This.cBitmap)
* Header
*
Bitmap header field: BM (CHR(0x42)+CHR(0x4D))
lcSa = CHR(0x42) + CHR(0x4D)
* File length
(file dimension in bytes in hexadecimal)
lnNumber = This.DecTohex(m.lnByteLength
+ 56)
lcSa
= m.lcSa + m.lnNumber
FOR lni = 1 TO 8 - LEN(m.lnNumber)
lcSa
= m.lcSa + CHR(0)
NEXT
*CHR(0x36)=3*16+6=56=header
length in bytes
*CHR(0x28)=2*16+8=40=number
of bytes taken by the structure that follows the header
lcSa = m.lcSa + CHR(0x36) + CHR(0) + CHR(0) + CHR(0) + CHR(0x28) + CHR(0) + CHR(0) + CHR(0)
* bitmap width
and height in pixels
*
bitmap width
lnNumber = This.DecTohex(This.nWidth) &&(lnByteLength/lnSize-2)/3
lcSa= m.lcSa +
m.lnNumber
FOR lni = 1 TO 4 - LEN(m.lnNumber)
lcSa
= m.lcSa + CHR(0)
NEXT
* bitmap height
lnNumber = This.DecTohex(This.nHeight)
lcSa
= m.lcSa + m.lnNumber && +CHR(0x0C)+CHR(0)+CHR(0)+CHR(0)
FOR lni = 1 TO 4 - LEN(m.lnNumber)
lcSa
= m.lcSa + CHR(0)
NEXT
* Number of
layers, must be 1
lcSa = m.lcSa + CHR(0x1) + CHR(0)
* Color depth:
1, 4, 8 sau 24 (0x18) bits
lcSa = m.lcSa + CHR(0x18) + CHR(0)
* Information
regarding compression
lcSa = m.lcSa + CHR(0) + CHR(0) + CHR(0) + CHR(0)
* Image length in bytes (can be 0 if is not
compressed)
lnNumber = This.DecTohex(m.lnByteLength)
lcSa
= m.lcSa + m.lnNumber
FOR lni = 1 TO 8 - LEN(m.lnNumber)
lcSa = m.lcSa + CHR(0)
NEXT
* the device
horizontal resolution in pixels
lcSa = m.lcSa + CHR(0) + CHR(0) + CHR(0) + CHR(0)
* the device
vertical resolution in pixels
lcSa = m.lcSa + CHR(0) + CHR(0) + CHR(0) + CHR(0)
* 0 means the
entire color set
lcSa = m.lcSa + CHR(0) + CHR(0)
* 0 means all
the color counts in bitmap representation
lcSa = m.lcSa + CHR(0) + CHR(0)
STRTOFILE(m.lcSa + This.cBitmap,
m.tcFile)
RETURN m.tcFile
ENDPROC
* function used
to represend numbers as char
PROCEDURE DecTohex
LPARAMETERS tnNo
LOCAL lcS,lnC,lnI
lnI
= FLOOR(m.tnNo)
lcS
= ''
DO WHILE m.lnI != 0
lnC
= m.lnI % 256
lcS
= m.lcS + CHR(m.lnC)
lnI
= FLOOR(m.lnI / 256)
ENDDO
IF
LEN(m.lcS)=0
&&
representation of 0
lcS = CHR(0)
ENDIF
RETURN
m.lcS
ENDPROC
ENDDEFINE
Biblio
[1] https://en.wikipedia.org/wiki/BMP_file_format
Related posts
http://praisachion.blogspot.com/2017/09/creating-bitmap-bmp-pictures-without_45.html
http://praisachion.blogspot.com/2017/09/creating-bitmap-bmp-pictures-without_44.html
http://praisachion.blogspot.com/2017/09/creating-bitmap-bmp-pictures-without_97.html
http://praisachion.blogspot.com/2017/09/creating-bitmap-bmp-pictures-without_11.html
http://praisachion.blogspot.com/2017/09/creating-bitmap-bmp-pictures-without.html
Niciun comentariu:
Trimiteți un comentariu