Faceți căutări pe acest blog

luni, 11 septembrie 2017

Creating bitmap BMP pictures without API calls (1)

A bitmap (BMP) file is an array of pixels.
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