An icon (file with the "ico" extension( is a container, so it contains one or more pictures. To manage these pictures, the ico file has a simple header.
As you can see below, the same code can be used to generate a static cursor (a file with the "cur" extension), because there are only a few differences between icons and cursors.
The images must be no bigger than 256x256 pixels.
The images used can be bitmap (BMP) files or Portable Network Graphic (PNG) files, but the following code can be used only for PNG images.
**********************************************
* Generates an ico file from one or more png *
**********************************************
* Parameters
* - array with the name (and path) of the png files (passed by reference)
* - name of the output file
* - llCur (optional) .F. (default) the result is icon /.T. the result is cursor
* - lnHotX (optional) the x coordinate for the hotspot (cursor only, where the mouse clicks)
* - lnHotY (optional) the y coordinate for the hotspot (cursor only, where the mouse clicks)
**********************************************
LPARAMETERS laIcons,lcFileName,llCur,lnHotX,lnHotY
LOCAL lcResult,lcResult2,lnIcos,lni,lcImg,lnWidth,lnHeight,lnSize,lcS,llRes,lnOffset
IF PCOUNT() < 5 OR VARTYPE(m.lnHotY) <> "N"
lnHotY = 0
ENDIF
lnHotY = FLOOR(MIN(MAX(m.lnHotY,0),65535))
IF PCOUNT() < 4 OR VARTYPE(m.lnHotX) <> "N"
lnHotX = 0
ENDIF
lnHotX = FLOOR(MIN(MAX(m.lnHotX,0),65535))
IF PCOUNT() < 3 OR VARTYPE(m.llCur) <> "L"
llCur = .F.
ENDIF
llRes = .T.
lnIcos = ALEN(laIcons)
lcResult = CHR(0) + CHR(0) + CHR(IIF(m.llCur,2,1)) + CHR(0) + BINTOC(m.lnIcos, "2RS")
lcResult2 = ""
lnOffset = 6 + m.lnIcos * 16
FOR lni = 1 TO m.lnIcos
STORE 0 TO lnWidth,lnHeight,lnSize
lcS = ""
IF FILE(m.laIcons[m.lni])
IF is_png2(m.laIcons[m.lni],256,256,@lnWidth,@lnHeight,@lnSize,@lcS) = 0
IF !m.llCur
lcResult = m.lcResult + CHR(m.lnWidth) + CHR(m.lnHeight) + CHR(0) + CHR(0) + CHR(1) + CHR(0) + CHR(32) + CHR(0) + BINTOC(m.lnSize, "4RS") + BINTOC(m.lnOffset, "4RS")
ELSE
lcResult = m.lcResult + CHR(m.lnWidth) + CHR(m.lnHeight) + CHR(0) + CHR(0) + BINTOC(MIN(m.lnHotX,m.lnWidth), "2RS") + BINTOC(MIN(m.lnHotY,m.lnHeight), "2RS") + BINTOC(m.lnSize, "4RS") + BINTOC(m.lnOffset, "4RS")
ENDIF
lcResult2 = m.lcResult2 + m.lcS
lnOffset = m.lnOffset + m.lnSize
ELSE
llRes = .F.
EXIT
ENDIF
ELSE
llRes = .F.
EXIT
ENDIF
NEXT
IF m.llRes
STRTOFILE(m.lcResult + m.lcResult2,FORCEEXT(m.lcFileName,IIF(!m.llCur,"ico","cur")))
ENDIF
RETURN m.llRes
******************************************************************
* Check if a file is png
* Compare width and height of the image is compared with maximum values
* Return the current width and height in pixels, the file size in bytes and the picture in the last parameters
******************************************************************
* Return value is
* 0 - success
* 1 - not a PNG
* 2 - too wide
* 4 - too high
* 8 - incorect number of parameters
******************************************************************
* is_png2 must be called with 7 parameters:
* - image file
* - maximum width
* - maximum height
* - (output) width in pixels
* - (output) height in pixels
* - (outut) size in bytes of the file
* - (output) the image file as a string
******************************************************************
FUNCTION is_png2
LPARAMETERS lcFil,lnWidthm,lnHeightm,lnWidth,lnHeight,lnSize,lcS
LOCAL llSgn,llIspng
llIspng=0
IF PCOUNT() < 6 OR VARTYPE(m.lnWidthm) <> "N" OR VARTYPE(m.lnHeightm) <> "N" OR VARTYPE(m.lcFil) <> "C"
RETURN 8
ENDIF
lcs = FILETOSTR(FULLPATH(m.lcfil))
lnSize = LEN(m.lcs)
llsgn = ASC(SUBSTR(m.lcs,1,1))=137 and ASC(SUBSTR(m.lcs,2,1))=80 and ASC(SUBSTR(m.lcs,3,1))=78 and ASC(SUBSTR(m.lcs,4,1))=71 and ASC(SUBSTR(m.lcs,5,1))=13 and ASC(SUBSTR(m.lcs,6,1))=10 and ASC(SUBSTR(m.lcs,7,1))=26 and ASC(SUBSTR(m.lcs,8,1))=10
IF m.llsgn
lnWidth = ASC(SUBSTR(m.lcs,17))*256*256*256+ASC(SUBSTR(m.lcs,18))*256*256+ASC(SUBSTR(m.lcs,19))*256+ASC(SUBSTR(m.lcs,20))
IF m.lnWidth > m.lnWidthm
llIspng = m.llIspng + 2
ENDIF
IF m.lnWidth = 256
lnWidth = 0
ENDIF
lnHeight = ASC(SUBSTR(m.lcs,21))*256*256*256+ASC(SUBSTR(m.lcs,22))*256*256+ASC(SUBSTR(m.lcs,23))*256+ASC(SUBSTR(m.lcs,24))
IF m.lnHeight > m.lnHeightm
llIspng = m.llIspng + 4
ENDIF
IF m.lnHeight = 256
lnHeight = 0
ENDIF
ELSE
llIspng = m.llIspng + 1
ENDIF
RETURN m.llIspng