Faceți căutări pe acest blog

luni, 11 septembrie 2017

Creating bitmap BMP pictures without API calls (3)

Going a step further, lets change the color of a single pixel.
Will create a 7 x 5 bitmap with a red dot in the middle of a yellow background.



****************************************************
* Creating a 7 x 5 bitmap with yellow background and a red pixel in the middle
****************************************************
* The midmap look like this:
* YYYYYYY
* YYYYYYY
* YYYRYYY - a yellow pixel in the middle
* YYYYYYY
* YYYYYYY
****************************************************
LOCAL loBmp, lcTrailerZeros, lcRedPixel, lcRedRow
loBmp = CREATEOBJECT("bmpcreator")
loBmp.nWidth = 7
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 (Red is the rightmost, blue is the leftmost)
lcRedPixel = CHR(0) + CHR(0) + CHR(255)
* One pixel has three bytes, corresponding to RGB (Red is the rightmost, blue is the leftmost)
lcYellowPixel = CHR(0) + CHR(255) + CHR(255)
* One row contain loBmp.nWidth npixels; DO NOT FORGET the trailing zeroes
* The yellow row
lcYellowRow = REPLICATE(m.lcYellowPixel, m.loBmp.nWidth) + m.lcTrailerZeros
* The row with a red pixel in the middle
lcYellowRowWithARedDot = REPLICATE(m.lcYellowPixel, FLOOR(m.loBmp.nWidth / 2)) + ; && three yellow pixels to the left
                                   m.lcRedPixel + ;                                                             && one red pixel
                                   REPLICATE(m.lcYellowPixel, FLOOR(m.loBmp.nWidth / 2)) + ;  && three yellow pixels to the right
                                   m.lcTrailerZeros
* The BITMAP
loBmp.cBitmap = REPLICATE(m.lcYellowRow, FLOOR(m.loBmp.nHeight / 2)) + ; &&  two yellow rows below
                        m.lcYellowRowWithARedDot + ;                                    && the row aith a red pixel
                        REPLICATE(m.lcYellowRow, FLOOR(m.loBmp.nHeight / 2)) &&  two yellow rows above
     
loBmp.genbmp("03")


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

Niciun comentariu:

Trimiteți un comentariu