Announcement

Collapse
No announcement yet.

Discuss TransparentText source code

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Discuss TransparentText source code

    https://forum.powerbasic.com/forum/u...und#post776899
    Example of using graphic controls to apply text with a transparent background
    to a graphic background while retaining dithering effects and porting them to new
    background.
    The module itself is less than thirty lines, if you don't count comments and allow for line stacking of commands.
    Code:
    SUB TransparentText(dlg AS DWORD, ctl AS LONG, strt AS STRING, xpos AS LONG, ypos AS LONG, hfont AS LONG, fgc AS LONG)
        LOCAL textcolor, tx, ty, bufsize, itr8, prcnt, minusp AS LONG
        LOCAL hbmp1 AS DWORD
        LOCAL textbuf, maskbuf AS STRING
        LOCAL lptr_textbuf, lptr_maskbuf AS LONG PTR
        LOCAL bgr_t, bgr_m, bgr_c AS bgra PTR
    ' get bgr value of text color and set bgr pointer to text color
        textcolor = BGR(fgc)
        bgr_c = VARPTR(textcolor)
    ' get size of working area
        GRAPHIC ATTACH dlg, ctl:  GRAPHIC SET FONT hfont:  tx = GRAPHIC(TEXT.SIZE.X, strt):  ty = GRAPHIC(TEXT.SIZE.Y, strt)
    ' create bitmap, print text to mask buffer and get background info
        GRAPHIC BITMAP NEW tx, ty TO hbmp1:  GRAPHIC ATTACH hbmp1, 0:  GRAPHIC SET FONT hfont
        GRAPHIC COLOR %WHITE, %BLACK:  GRAPHIC CLEAR:  GRAPHIC SET POS (0, 0):  GRAPHIC PRINT strt
        GRAPHIC GET BITS TO maskbuf:  GRAPHIC COPY dlg, ctl, (xpos, ypos)-(xpos + tx, ypos + ty) TO (0, 0)
        GRAPHIC GET BITS TO textbuf
    ' set up string buffers for writing text to background
        bufsize = (LEN(textbuf) \ 4) - 3
        lptr_textbuf = STRPTR(textbuf) + 8:  bgr_t = lptr_textbuf
        lptr_maskbuf = STRPTR(maskbuf) + 8:  bgr_m = lptr_maskbuf
    ' using value of text in mask, calculate and apply blending of text and background
        FOR itr8 = 0 TO bufsize
            @bgr_t[itr8].b = ((@bgr_c.b * @bgr_m[itr8].b) + (@bgr_t[itr8].b * (255 - @bgr_m[itr8].b))) \ 255
            @bgr_t[itr8].g = ((@bgr_c.g * @bgr_m[itr8].g) + (@bgr_t[itr8].g * (255 - @bgr_m[itr8].g))) \ 255
            @bgr_t[itr8].r = ((@bgr_c.r * @bgr_m[itr8].r) + (@bgr_t[itr8].r * (255 - @bgr_m[itr8].r))) \ 255
        NEXT
    ' copy edited rectangle back to original control end bitmap and font
        GRAPHIC ATTACH hbmp1, 0:  GRAPHIC SET BITS textbuf
        GRAPHIC ATTACH dlg, ctl, REDRAW:  GRAPHIC COPY hbmp1, 0, (0, 0)-(tx, ty) TO (xpos, ypos):  GRAPHIC REDRAW
        GRAPHIC ATTACH hbmp1, 0:  GRAPHIC BITMAP END:  FONT END hfont
    END SUB
    Example of calling code:
    Code:
        LOCAL hfont AS LONG
        CONTROL GET TEXT CB.HNDL, %dtext TO getvalue
        FONT NEW "Comic Sans MS", 16 TO hfont
        TransparentText CB.HNDL, %grfx, getvalue, 8, 20, hfont, %RGB_INDIGO
    The world is strange and wonderful.*
    I reserve the right to be horrifically wrong.
    Please maintain a safe following distance.
    *wonderful sold separately.

  • #2
    Hey Kurt,
    I'm not clear on something. Isn't this statement all that is required to draw transparent text?

    Code:
    Graphic Color %Black, -2
    Perhaps I'm not clear on what you're trying to demonstrate?

    Comment


    • #3
      Something like this ...

      Click image for larger version  Name:	pb_2080.jpg Views:	1 Size:	9.3 KB ID:	776905

      Code:
      'Compilable Example:
      #Compile Exe
      #Dim All
      %Unicode = 1
      #Include "Win32API.inc"
      %IDC_Graphic = 500
      
      Function PBMain() As Long
         Local hDlg, hFont As Dword, i As Long
         Font New "Tahoma",24,1 To hFont
         Dialog New Pixels, 0, "PowerBASIC",300,300,200,200, %WS_OverlappedWindow To hDlg
         Control Add Graphic, hDlg, %IDC_Graphic,"Push",0,0,200,200
         Graphic Attach hDlg, %IDC_Graphic
         Graphic Set Font hFont
         Graphic Width 2
         For i = 1 To 7 : Graphic Box (i*20,i*20)-(i*20+50,i*20+50) : Next i
         Graphic Color %Red, -2
         Graphic Set Pos(0,50) : Graphic Print "Howdy, Kurt!"
         Dialog Show Modal hDlg
      End Function

      Comment


      • #4
        Maybe this is what I've not understood?

        ... retaining dithering effects and porting them to new background.

        Comment


        • #5
          Originally posted by Gary Beene View Post
          Maybe this is what I've not understood?
          It does reconstruct what is already there, yes.
          But, you can also apply shadows that may be separately blurred.
          I was not even aware of the -2 color capability of graphic print!
          This would be useful for applying hand-drawn characters with dithering
          applied by a call to a blur routine prior to masked application.
          Probably not the most useful thing ever, but I wanted to master the
          graphics techniques used in gradient blending of foreground and background,
          especially as it applies to dithering, which is really just a limited type of a blur.
          I've reinvented the wheel, and put spinner hubs on it.
          The world is strange and wonderful.*
          I reserve the right to be horrifically wrong.
          Please maintain a safe following distance.
          *wonderful sold separately.

          Comment


          • #6
            New blur code. Uses a bit string and returns a bit string.
            Previous out of bounds errors in corner processes fixed.
            Weighting works thus:
            Center pixel to be manipulated has a weight applied, 0-31.
            This is how much it is affected by averaging with surrounding pixels.
            With a weight of three, for instance, you get:
            (center pixel * 28 + surrounding pixels) / number of surround pixels + 28
            This reduces the amount of change to the center pixel.
            With a weight of 31, you get this:
            (center pixel + surrounding pixels) / total number of pixels
            Repetition increases the distance at which blurring is effective.
            Code:
            #COMPILE EXE
            #DIM ALL
            #DEBUG DISPLAY
            #INCLUDE "win32api.inc"
            ENUM ctrls SINGULAR
                grfx = 500
                bgimage
                blur
                mag
                magblur
                strong
                iterations
            END ENUM
            
            TYPE bgra
                b AS BYTE
                g AS BYTE
                r AS BYTE
                a AS BYTE
            END TYPE
            
            FUNCTION PBMAIN () AS LONG
                LOCAL hWin, xitcode AS LONG
                RANDOMIZE
                DIALOG NEW PIXELS, 0, "PB_Blur", , , 400, 230, %WS_BORDER OR %WS_CAPTION OR %WS_SYSMENU TO hWin
                DIALOG SET COLOR hWin, %WHITE, %BLACK
                CONTROL ADD BUTTON, hWin, %bgimage, "New Background", 5, 5, 120, 20
                CONTROL ADD BUTTON, hWin, %blur, "Blur", 130, 5, 40, 20
                CONTROL ADD BUTTON, hWin, %mag, "Mag+", 175, 5, 40, 20
                CONTROL ADD BUTTON, hWin, %magblur, "Blur+", 220, 5, 40, 20
                CONTROL ADD LABEL, hWin, %strong, "Weight: 15", 275, 6, 60, 15, %SS_SUNKEN OR %SS_NOTIFY
                CONTROL SET COLOR hWin, %strong, %YELLOW, %GRAY
                CONTROL ADD LABEL, hWin, %iterations, "Iterate: 0", 340, 6, 55, 15, %SS_SUNKEN OR %SS_NOTIFY
                CONTROL SET COLOR hWin, %iterations, %YELLOW, %GRAY
                CONTROL ADD GRAPHIC, hWin, %grfx, "", 0, 30, 400, 200
                GRAPHIC ATTACH hWin, %grfx
                GRAPHIC CLEAR %BLACK
                DIALOG SHOW MODAL hWin, CALL dlgproc() TO xitcode
                FUNCTION = xitcode
            END FUNCTION
            
            CALLBACK FUNCTION dlgproc()
                LOCAL getvalue AS STRING, wgt, itr AS LONG, hbmp AS DWORD
                SELECT CASE CB.MSG
                    CASE %WM_INITDIALOG
                        make_background(CB.HNDL, %grfx)
                    CASE %WM_COMMAND
                        SELECT CASE CB.CTL
                            CASE %bgimage
                                IF CB.CTLMSG = %BN_CLICKED THEN
                                    make_background CB.HNDL, %grfx
                                END IF
                            CASE %blur
                                IF CB.CTLMSG = %BN_CLICKED THEN
                                    CONTROL GET TEXT CB.HNDL, %strong TO getvalue: wgt = VAL(MID$(getvalue, 8))
                                    CONTROL GET TEXT CB.HNDL, %iterations TO getvalue: itr = VAL(MID$(getvalue, 9))
                                    GRAPHIC ATTACH CB.HNDL, %grfx, REDRAW
                                    GRAPHIC GET BITS TO getvalue
                                    getvalue = PB_AVG_blur(getvalue, wgt, itr) 'changing the numbers here changes blur effect
                                    GRAPHIC SET BITS getvalue
                                    GRAPHIC REDRAW
                                END IF
                            CASE %mag
                                'graphic control size is 400 X 200
                                IF CB.CTLMSG = %BN_CLICKED THEN
                                    CONTROL GET TEXT CB.HNDL, %strong TO getvalue: wgt = VAL(MID$(getvalue, 8))
                                    CONTROL GET TEXT CB.HNDL, %iterations TO getvalue: itr = VAL(MID$(getvalue, 9))
                                    GRAPHIC ATTACH CB.HNDL, %grfx, REDRAW
                                    GRAPHIC STRETCH CB.HNDL, %grfx, (0, 0)-(99, 49) TO (0, 0)-(399,199), 0, %HALFTONE
                                    GRAPHIC REDRAW
                                END IF
                            CASE %magblur
                                'graphic control size is 400 X 200
                                IF CB.CTLMSG = %BN_CLICKED THEN
                                    CONTROL GET TEXT CB.HNDL, %strong TO getvalue: wgt = VAL(MID$(getvalue, 8))
                                    CONTROL GET TEXT CB.HNDL, %iterations TO getvalue: itr = VAL(MID$(getvalue, 9))
                                    GRAPHIC BITMAP NEW 201, 101 TO hbmp
                                    GRAPHIC ATTACH hbmp, 0
                                    GRAPHIC STRETCH CB.HNDL, %grfx, (0, 0)-(99, 49) TO (0, 0)-(200,100), 0, %HALFTONE
                                    GRAPHIC GET BITS TO getvalue
                                    getvalue = PB_AVG_blur(getvalue, wgt, itr) 'changing the numbers here changes blur effect
                                    GRAPHIC SET BITS getvalue
                                    GRAPHIC ATTACH CB.HNDL, %grfx, REDRAW
                                    GRAPHIC STRETCH PAGE hbmp, 0, 0, %HALFTONE
                                    GRAPHIC REDRAW
                                    GRAPHIC ATTACH hbmp, 0
                                    GRAPHIC BITMAP END
                                END IF
                            CASE %strong
                                IF CB.CTLMSG = %STN_CLICKED THEN
                                    getvalue = INPUTBOX$("Enter a value from 0 to 31","Set Blur Weight", "0")
                                    IF getvalue <> "" THEN CONTROL SET TEXT CB.HNDL, CB.CTL, "Weight:" + STR$(VAL(getvalue) AND 31)
                                END IF
                            CASE %iterations
                                IF CB.CTLMSG = %STN_CLICKED THEN
                                    getvalue = INPUTBOX$("Enter a value from 0 to 31","Set Reiterations", "1")
                                    IF getvalue <> "" THEN CONTROL SET TEXT CB.HNDL, CB.CTL, "Iterate:" + STR$((VAL(getvalue) AND 31))
                                END IF
                        END SELECT
                END SELECT
            END FUNCTION
            
            SUB make_background(dlg AS DWORD, ctl AS LONG)
                LOCAL bginit, x, y, xll, xhl, yll, yhl, c_rad, fgc, bgc AS LONG
                CONTROL GET SIZE dlg, ctl TO x, y
                xll = -70: xhl = x - 70
                yll = -50: yhl = y - 50
                GRAPHIC ATTACH dlg, ctl, REDRAW
                FOR bginit = 0 TO 200
                    c_rad = RND(20, 50)
                    fgc = RGB(RND(90, 120), RND(90, 120), RND(90, 120))
                    bgc = RGB(RND(150, 220), RND(150, 220), RND(150, 220))
                    x = RND(xll, xhl): y = RND(yll, yhl)
                    GRAPHIC BOX (x, y)-(x + RND(80, 100), y + RND(50, 80)), c_rad, fgc, bgc
                NEXT
                GRAPHIC SET POS (10,20)
                GRAPHIC COLOR %BLACK, -2
                GRAPHIC PRINT "TEST Text"
                GRAPHIC REDRAW
            END SUB
            
            FUNCTION PB_AVG_blur(StrBMP AS STRING, strength AS LONG, iterations AS LONG) AS STRING
                ' adjusting number of iterations extends the blur by bleeding into an extended area.
                ' adjusting strength of blur reduces bleedover.
                LOCAL STR_work, STR_ref AS STRING
                LOCAL x, y, xl, yl, wgt, dvzr, avg AS LONG
                LOCAL LPTR_ref AS LONG POINTER
                LOCAL bg0(), bg1() AS bgra
                STR_ref = Strbmp
                LPTR_ref = STRPTR(StrBMP) + 8
                xl = @LPTR_ref[-2] - 1
                yl = @LPTR_ref[-1] - 1
                wgt = 32 - (strength AND 31)
                REDIM bg0(xl, yl) AT STRPTR(STR_ref) + 8
                FOR avg = 0 TO iterations
                    ' Using a separate copy of the image, average from the original and store in the edited version.
                    ' By updating the reference copy for each iteration, the reiteratioin bleed-thru is made possible.
                    STR_work = STR_ref
                    REDIM bg1(xl, yl) AT STRPTR(STR_work) + 8
                    'corners
                    dvzr = wgt + 3
                    'upper left corner
                    bg1(0,0).b = ((wgt*bg0(0,0).b) +bg0(0,1).b+bg0(1,0).b+bg0(1,1).b) \dvzr
                    bg1(0,0).g = ((wgt*bg0(0,0).g) +bg0(0,1).g+bg0(1,0).g+bg0(1,1).g) \dvzr
                    bg1(0,0).r = ((wgt*bg0(0,0).r) +bg0(0,1).r+bg0(1,0).r+bg0(1,1).r) \dvzr
                    'upper right corner
                    bg1(xl,0).b = ((wgt*bg0(xl,0).b) +bg0(xl,1).b+bg0(xl-1,0).b+bg0(xl-1,1).b) \dvzr
                    bg1(xl,0).g = ((wgt*bg0(xl,0).g) +bg0(xl,1).g+bg0(xl-1,0).g+bg0(xl-1,1).g) \dvzr
                    bg1(xl,0).r = ((wgt*bg0(xl,0).r) +bg0(xl,1).r+bg0(xl-1,0).r+bg0(xl-1,1).r) \dvzr
                    'lower left corner
                    bg1(0,yl).b = ((wgt*bg0(0,yl).b) +bg0(0,yl-1).b+bg0(1,yl).b+bg0(1,yl-1).b) \dvzr
                    bg1(0,yl).g = ((wgt*bg0(0,yl).g) +bg0(0,yl-1).g+bg0(1,yl).g+bg0(1,yl-1).g) \dvzr
                    bg1(0,yl).r = ((wgt*bg0(0,yl).r) +bg0(0,yl-1).r+bg0(1,yl).r+bg0(1,yl-1).r) \dvzr
                    'lower right corner
                    bg1(xl,yl).b = ((wgt*bg0(xl,yl).b) +bg0(xl,yl-1).b+bg0(xl-1,yl).b+bg0(xl-1,yl-1).b) \dvzr
                    bg1(xl,yl).g = ((wgt*bg0(xl,yl).g) +bg0(xl,yl-1).g+bg0(xl-1,yl).g+bg0(xl-1,yl-1).g) \dvzr
                    bg1(xl,yl).r = ((wgt*bg0(xl,yl).r) +bg0(xl,yl-1).r+bg0(xl-1,yl).r+bg0(xl-1,yl-1).r) \dvzr
                    'left edge
                    dvzr = wgt + 5
                    FOR y = 1 TO yl - 1
                        bg1(0,y).b = ((wgt*bg0(0,y).b) +bg0(0,y-1).b+bg0(0,y+1).b+bg0(1,y-1).b+bg0(1,y).b+bg0(1,y+1).b) \dvzr
                        bg1(0,y).g = ((wgt*bg0(0,y).g) +bg0(0,y-1).g+bg0(0,y+1).g+bg0(1,y-1).g+bg0(1,y).g+bg0(1,y+1).g) \dvzr
                        bg1(0,y).r = ((wgt*bg0(0,y).r) +bg0(0,y-1).r+bg0(0,y+1).r+bg0(1,y-1).r+bg0(1,y).r+bg0(1,y+1).r) \dvzr
                    NEXT
                    'right edge
                    FOR y = 1 TO yl - 1
                        bg1(xl,y).b = ((wgt*bg0(xl,y).b) +bg0(xl,y-1).b+bg0(xl,y+1).b+bg0(xl-1,y-1).b+bg0(xl-1,y).b+bg0(xl-1,y+1).b) \dvzr
                        bg1(xl,y).g = ((wgt*bg0(xl,y).g) +bg0(xl,y-1).g+bg0(xl,y+1).g+bg0(xl-1,y-1).g+bg0(xl-1,y).g+bg0(xl-1,y+1).g) \dvzr
                        bg1(xl,y).r = ((wgt*bg0(xl,y).r) +bg0(xl,y-1).r+bg0(xl,y+1).r+bg0(xl-1,y-1).r+bg0(xl-1,y).r+bg0(xl-1,y+1).r) \dvzr
                    NEXT
                    'top edge
                    dvzr = wgt + 5
                    FOR x = 1 TO xl - 1
                        bg1(x,0).b = ((wgt*bg0(x,0).b) +bg0(x-1,0).b+bg0(x+1,0).b+bg0(x,1).b+bg0(x-1,1).b+bg0(x+1,1).b) \dvzr
                        bg1(x,0).g = ((wgt*bg0(x,0).g) +bg0(x-1,0).g+bg0(x+1,0).g+bg0(x,1).g+bg0(x-1,1).g+bg0(x+1,1).g) \dvzr
                        bg1(x,0).r = ((wgt*bg0(x,0).r) +bg0(x-1,0).r+bg0(x+1,0).r+bg0(x,1).r+bg0(x-1,1).r+bg0(x+1,1).r) \dvzr
                    NEXT
                    'bottom edge
                    FOR x = 1 TO xl - 1
                        bg1(x,yl).b = ((wgt*bg0(x,yl).b) +bg0(x-1,yl).b+bg0(x+1,yl).b+bg0(x,yl-1).b+bg0(x-1,yl-1).b+bg0(x+1,yl-1).b) \dvzr
                        bg1(x,yl).g = ((wgt*bg0(x,yl).g) +bg0(x-1,yl).g+bg0(x+1,yl).g+bg0(x,yl-1).g+bg0(x-1,yl-1).g+bg0(x+1,yl-1).g) \dvzr
                        bg1(x,yl).r = ((wgt*bg0(x,yl).r) +bg0(x-1,yl).r+bg0(x+1,yl).r+bg0(x,yl-1).r+bg0(x-1,yl-1).r+bg0(x+1,yl-1).r) \dvzr
                    NEXT
                    'center image
                    dvzr = wgt + 8
                    FOR x = 1 TO xl - 1
                        FOR y = 1 TO yl - 1
                            bg1(x,y).b = ((wgt*bg0(x,y).b) +bg0(x-1,y).b+bg0(x+1,y).b +bg0(x-1,y-1).b+bg0(x,y-1).b+bg0(x+1,y-1).b +bg0(x-1,y+1).b+bg0(x,y+1).b+bg0(x+1,y+1).b) \ dvzr
                            bg1(x,y).g = ((wgt*bg0(x,y).g) +bg0(x-1,y).g+bg0(x+1,y).g +bg0(x-1,y-1).g+bg0(x,y-1).g+bg0(x+1,y-1).g +bg0(x-1,y+1).g+bg0(x,y+1).g+bg0(x+1,y+1).g) \ dvzr
                            bg1(x,y).r = ((wgt*bg0(x,y).r) +bg0(x-1,y).r+bg0(x+1,y).r +bg0(x-1,y-1).r+bg0(x,y-1).r+bg0(x+1,y-1).r +bg0(x-1,y+1).r+bg0(x,y+1).r+bg0(x+1,y+1).r) \ dvzr
                        NEXT
                    NEXT
                    STR_ref = STR_work
                NEXT
                FUNCTION = STR_work
            END FUNCTION
            The world is strange and wonderful.*
            I reserve the right to be horrifically wrong.
            Please maintain a safe following distance.
            *wonderful sold separately.

            Comment

            Working...
            X