Simple Paint Program

Простейшая программная реализация редактора графики. Мне очень понравилось, как автор построил код этой программы. Все сделано средствами встроенной библиотеки FbGFX.

Платформы: Windows, Linux
Автор: BasicCoder2

Simple Paint Program.png

#INCLUDE "fbgfx.bi"
Using FB
Windowtitle "Simple Paint Program"
Screenres 640,480,32

Dim Shared As Integer cmd
cmd = 0  'draw mode default
Dim Shared As Integer btnID     'id of button pressed
Dim Shared As Integer penSize
penSize = 3 'pen size default
Dim Shared As Integer mirror
mirror = 0  'default to no mirror

'fill in pallete with colors
Dim As Ubyte r,g,b
Dim Shared As Uinteger colors(48)
For i As Integer = 0 To 47
    Read r,g,b
    colors(i) = Rgb(r,g,b)
Next i

Dim Shared As Any Ptr canvas1,canvas2   'displayed image
canvas1 = Imagecreate(640,480,Rgb(255,255,254))  'save image while screen is being worked on
canvas2 = Imagecreate(640,480,Rgb(255,255,254))  'saves saved image for UNDO

Dim Shared As Integer mx,my,ox,oy,sx,sy,dx,dy,mb  'mouse variables
Setmouse(0,0,1,1)

Dim Shared As Integer sColor    'id of selected color in palette
sColor = 0                      'black pen default palette#0

Dim Shared As Integer mode1, mode2  'fill rectangle, fill circle


Sub update()
    Screenlock()
    '=============
    'draw buttons
    '=============
    For x As Integer = 0 To 15
        If cmd=x Or (mirror = 1 And x = 7) Then
            Line (x*40,0)-(x*40+39,20),Rgb(100,100,255),bf
        Else
            Line (x*40,0)-(x*40+39,20),Rgb(10,10,255),bf
        End If
    Next x
    Draw String (4,8),"DRAW RECT CIRC LINE FILL RUB  CLS  HMIR UNDO SAVE LOAD  PEN .... .... .... QUIT",Rgb(255,255,254)
    For i As Integer = 0 To 15
        Line (i*40,0)-(i*40+39,20),Rgb(200,200,200),b
    Next i


    '==================
    '    draw palette
    '==================
    For x As Integer = 0 To 39
        Line (x*16,464)-(x*16+15,479),colors(x),bf
        If x = sColor Or (mirror = 1 And x = 7) Then
            Line (x*16,464)-(x*16+15,479) ,Rgb(255,255,254),b
            Line (x*16+1,464+1)-(x*16+15-1,479-1) ,Rgb(0,0,0),b
        Else
            Line (x*16,464)-(x*16+15,479) ,Rgb(0,0,0),b
        End If
    Next x
    Screenunlock()
    Sleep 2
End Sub

Sub thickLine(x1 As Integer,y1 As Integer,x2 As Integer,y2 As Integer,size As Integer,c As Uinteger)
    Dim As Integer x,y
    If x1 = x2 And y1 = y2 Then
        Circle (x1, y1), size, c, , , , f
    Elseif Abs(x2 - x1) >= Abs(y2 - y1) Then
        Dim K As Single = (y2 - y1) / (x2 - x1)
        For I As Integer = x1 To x2 Step Sgn(x2 - x1)
            x = I
            y = K * (I - x1) + y1
            Circle (x,y), size, c, , , , f
            If mirror = 1 Then
                Circle (640-x,y),size,c,,,,f    'for horizontal mirror
            End If
        Next I
    Else
        Dim L As Single = (x2 - x1) / (y2 - y1)
        For J As Integer = y1 To y2 Step Sgn(y2 - y1)
            x = L * (J - y1) + x1
            y = J
            Circle (x,y), size,c,,,,f
            If mirror = 1 Then
                Circle (640-x,y),size,c,,,,f   'for horizontal mirror
            End If
        Next J
    End If
End Sub

Sub FloodFill (x As Integer, y As Integer, oldcolour As Integer, newcolour As Integer)
    Dim As Integer Ptr p = New Integer[16*1024 * 1024]
    Dim As Integer n = 0
    Dim As Integer x0, y0

    If oldcolour = newcolour Then Exit Sub
    p[n] = x
    p[n+1] = y
    n = n + 2
    While n > 0
        y0 = p[n-1]
        x0 = p[n-2]
        n = n - 2
        If Point(x0, y0) = oldcolour Then
            Pset (x0, y0), newcolour
            p[n] = x0
            p[n+1] = y0-1
            p[n+2] = x0
            p[n+3] = y0+1
            p[n+4] = x0-1
            p[n+5] = y0
            p[n+6] = x0+1
            p[n+7] = y0
            n = n + 8
        End If
    Wend
    Delete p
End Sub

Sub Fill()
    FloodFill  (mx,my,Point(mx,my),colors(sColor))
    update()
    'wait for select button release
    While mb=1
        Getmouse mx,my,,mb
    Wend
    Put canvas2,(0,0),canvas1,Pset    'canvas2 = canvas1
    Get (0,0)-(639,479),canvas1       'canvas1 = screen
End Sub

Sub drawRectangle()
    Dim As Integer r
    Dim As String s
    While mb=1
        Getmouse mx,my,,mb
        If mx<>ox Or my<>oy Then 'mouse has moved so draw erase old draw new
            Screenlock()
            Put (0,0),canvas1,Trans   'restore screen

            'fill rectangle mode?
            If mode1 = 1 Then
                For i As Integer = oy To my
                    Line (ox,i)-(mx,i),colors(sColor)
                Next i
            End If

            thickLine(ox,oy,mx,oy,penSize,colors(sColor))
            thickLine(mx,oy,mx,my,penSize,colors(sColor))
            thickLine(mx,my,ox,my,penSize,colors(sColor))
            thickLine(ox,my,ox,oy,penSize,colors(sColor))
            Screenunlock()
            update()
            Sleep 1
        End If
    Wend
    Put canvas2,(0,0),canvas1,Pset    'canvas2 = canvas1
    Get (0,0)-(639,479),canvas1       'canvas1 = screen
End Sub

Sub drawLine()
    Dim As Integer sx,sy
    sx = mx
    sy = my
    While mb=1
        Getmouse mx,my,,mb
        If mx<>ox Or my<>oy Then 'mouse has moved so draw erase old draw new
            Put (0,0),canvas1,Trans   'restore screen
            thickLine(sx,sy,mx,my,penSize,colors(sColor))  'draw line
            ox = mx
            oy = my
            update()
        End If
    Wend
    Put canvas2,(0,0),canvas1,Pset    'canvas2 = canvas1
    Get (0,0)-(639,479),canvas1       'canvas1 = screen
End Sub

Sub drawPen()
    While mb=1
        Getmouse mx,my,,mb
        If mx<>ox Or my<>oy Then 'mouse has moved so draw erase old draw new
            thickLine(ox,oy,mx,my,penSize,colors(sColor)) 'drawline onto screenBuffer
            ox = mx
            oy = my
            update()
        End If
        Sleep 1
    Wend
    Put canvas2,(0,0),canvas1,Pset    'canvas2 = canvas1
    Get (0,0)-(639,479),canvas1       'canvas1 = screen

End Sub

Sub Ellipse(x0 As Integer, Y0 As Integer, X1 As Integer, y1 As Integer, c As Uinteger)
    'bresenham circle
    'void bresenham_ellipse( x0 As Integer,y0 As Integer, x1 As integer, y1 As integer )
    If x0>x1 Then Swap x0,x1
    If y0>y1 Then Swap y0,y1
    Dim As Integer x,y,a2,b2, S, T,xb,yb,b
    b=(y1-y0)/2
    b2=b*b
    a2=(x1-x0)^2/4
    xb=(x0+x1)/2
    yb=(y0+y1)/2

    x = 0
    y = b
    S = a2*(1-2*b) + 2*b2
    T = b2 - 2*a2*(2*b-1)
    If mode2 = 1 Then  'fill ellipse
        Line ((xb-x),(yb+y))-((xb-x),(yb-y)),c
        Line ((xb+x),(yb+y))-((xb+x),(yb-y)),c
    End If
    Circle ((xb+x),(yb+y)),3,c,,,,f
    Circle ((xb+x),(yb-y)),3,c,,,,f
    Circle ((xb-x),(yb+y)),3,c,,,,f
    Circle ((xb-x),(yb-y)),3,c,,,,f

    Do
        If S<0 Then

            S += 2*b2*(2*x+3)
            T += 4*b2*(x+1)
            x+=1
        Elseif T<0 Then
            S += 2*b2*(2*x+3) - 4*a2*(y-1)
            T += 4*b2*(x+1) - 2*a2*(2*y-3)
            x+=1
            y-=1
        Else
            S -= 4*a2*(y-1)
            T -= 2*a2*(2*y-3)
            y-=1
        End If
        If mode2 = 1 Then  'fill ellipse
            Line ((xb-x),(yb+y))-((xb-x),(yb-y)),c
            Line ((xb+x),(yb+y))-((xb+x),(yb-y)),c
        End If
        Circle ((xb+x),(yb+y)),3,c,,,,f
        Circle ((xb+x),(yb-y)),3,c,,,,f
        Circle ((xb-x),(yb+y)),3,c,,,,f
        Circle ((xb-x),(yb-y)),3,c,,,,f
    Loop While y>0

End Sub

Sub drawCircle()
    Dim As Double r
    Dim As Integer x,y,cx,cy
    While mb=1
        Getmouse mx,my,,mb
        If mx<>ox Or my<>oy Then 'mouse has moved so draw erase old draw new
            Screenlock()
            Put (0,0),canvas1,Trans     'restore screen
            Ellipse(ox,oy,mx,my,colors(sColor)) 'draw onto screen
            If mirror = 1 Then
                Ellipse(640-ox,oy,640-mx,my,colors(sColor))
            End If
            Screenunlock()
            update()
        End If
    Wend
    Put canvas2,(0,0),canvas1,Pset    'canvas2 = canvas1
    Get (0,0)-(639,479),canvas1       'canvas1 = screen
End Sub

Sub Rubber()
    Dim As Double r
    Dim As Integer x,y,cx,cy
    While mb=1
        Getmouse mx,my,,mb
        If mx<>ox Or my<>oy Then 'mouse has moved so draw erase old draw new
            Line(ox,oy)-(ox+20,oy+20),Rgb(255,255,254),bf  'erase box outline
            Line(mx,my)-(mx+20,my+20),Rgb(255,255,254),bf
            Line(mx,my)-(mx+20,my+20),Rgb(0,0,0),b         'draw box outline
            ox = mx
            oy = my
            update()
        End If
    Wend
    Line(ox,oy)-(ox+20,oy+20),Rgb(255,255,254),bf  'erase box outline
    Put canvas2,(0,0),canvas1,Pset    'canvas2 = canvas1
    Get (0,0)-(639,479),canvas1       'canvas1 = screen
End Sub

Sub save()
    Dim fileName As String
    Locate 20,10
    Get (0,0)-(639,479),canvas1  'save into canvas1
    Line (60,140)-(560,172),Rgb(255,255,254),bf
    Line (60,140)-(560,172),Rgb(1,1,1),b
    Line Input "Enter picture name:", fileName
    Locate 26,10
    Print "  ... SAVING"
    Bsave filename + ".bmp",canvas1
    Put (0,0),canvas1,Pset  'copy to screen
    update()
End Sub

Sub load()
    Dim fileName As String
    Locate 20,10
    Line (60,140)-(560,172),Rgb(255,255,254),bf
    Line (60,140)-(560,172),Rgb(1,1,1),b
    Line Input "Enter picture name:",fileName
    Bload filename + ".bmp",canvas1
    Put (0,0),canvas1,Pset  'copy to screen
    update()
End Sub

Color Rgb(0,0,0),Rgb(255,255,254)  'black ink, white paper
Cls   'executes the color change

update()

Dim As String key
Do

    Getmouse mx,my,,mb
    ox = mx
    oy = my


    If mb = 1 Then

        'is it over drawing area?
        If  my>20 And my<480-20 Then
            If cmd = 0 Then
                drawPen()
            End If
            If cmd = 1 Then
                drawRectangle()
            End If
            If cmd = 2 Then
                drawCircle()
            End If
            If cmd = 3 Then
                drawLine()
            End If
            If cmd = 4 Then
                Fill()
            End If
            If cmd = 5 Then
                Rubber()
            End If
        End If
        'is it over buttons
        If my<20 Then

            btnID = mx\40

            If btnID=1 Then  'set rectangle mode

                Get (0,0)-(639,479),canvas1  'save screen into canvas1 to restore
                Locate 18,2
                Print "Release mouse button over fill or not fill icon to select mode"
                update()
                'drop down rectangle examples
                For j As Integer = 0 To 1
                    Line (44,j*32+23)-(44+31,j*32+31+23),Rgb(255,255,254),bf
                    Line (44,j*32+23)-(44+31,j*32+31+23),Rgb(1,1,1),b
                    Line (52,31)-(52+16,31+16),Rgb(1,1,1),b
                    Line (52,63)-(52+16,63+16),Rgb(1,1,1),bf
                Next j
                While mb=1
                    Getmouse mx,my,,mb
                Wend
                'was it released over shape fill mode?
                If mx>44 And mx<75 And my>25 And my<87 Then
                    mode1 = (Int(my-23)\32)
                End If
                Put (0,0),canvas1,Pset  'restore screen
                update()
            End If

            If btnID=2 Then  'set rectangle mode

                Get (0,0)-(639,479),canvas1  'save screen into canvas1 to restore
                Locate 18,2
                Print "Release mouse button over fill or not fill icon to select mode"
                update()
                'drop down ellipse examples
                For j As Integer = 0 To 1
                    Line (84,j*32+25)-(84+31,j*32+31+25),Rgb(255,255,254),bf
                    Line (84,j*32+25)-(84+31,j*32+31+25),Rgb(1,1,1),b
                    Circle (99,40),10,Rgb(1,1,1)
                    Circle (99,73),10,Rgb(1,1,1),,,,f
                Next j
                While mb=1
                    Getmouse mx,my,,mb
                Wend
                'was it released over shape fill mode?
                If mx>84 And mx<115 And my>25 And my<87 Then
                    mode2 = (Int(my-23)\32)
                End If
                Put (0,0),canvas1,Pset  'restore screen
                update()
            End If

            If btnID<6 Then
                cmd = btnID
            End If

            If btnID=6 Then
                Color Rgb(1,1,1),Rgb(255,255,254)  'black ink, white paper
                Line canvas1,(0,0)-(639,479),Rgb(255,255,254),bf  'clear canvas1
                Cls
            End If

            If btnID=7 Then
                mirror = mirror+1
                If mirror=2 Then mirror = 0
            End If

            If btnID=8 Then
                Put canvas1,(0,0),canvas2,Pset  'get previous
                Put (0,0),canvas1,Pset  'copy to screen
                update()
            End If

            If btnID = 9 Then
                save()
                update()
                'btnID = mode  'reset button ID
            End If

            If btnID = 10 Then
                load()
                update()
                'btnID = mode  'reset button ID
            End If

            If btnID = 11 Then  'pen size
                Get (0,0)-(639,479),canvas1  'save screen into canvas1 to restore
                Locate 8,2
                Print "Release mouse button over desired pen size"
                update()
                'drop down pen examples
                For j As Integer = 0 To 3
                    Line (449,j*23+23)-(449+22,j*23+22+23),Rgb(255,255,254),bf
                    Line (449,j*23+23)-(449+22,j*23+22+23),Rgb(1,1,1),b
                    Circle (449+11,j*23+11+23),j*2+1,Rgb(1,1,1),,,,f
                Next j
                While mb=1
                    Getmouse mx,my,,mb
                Wend
                'was it released over pen size?
                If mx>454 And mx<476 And my>23 And my<114 Then
                    penSize = (Int(my-23)\23)*2+1
                End If
                Put (0,0),canvas1,Pset  'restore screen
                update()

            End If


            'wait for button release
            While mb = 1
                Getmouse mx,my,,mb
            Wend

            update()

        End If
        'is it over pallete?
        If my>464 Then
            sColor = mx\16
            While mb = 1
                Getmouse mx,my,,mb
            Wend
        End If
        update()
    End If

Loop Until btnID = 15

Imagedestroy(canvas1)
Imagedestroy(canvas2)

'Custom colors
ColorData:

' === microsoft PAINT standard colors ===
Data 0  ,0  ,  0  'BLACK
Data 127,127,127  'dark gray
Data 195,195,195  'light gray
Data 255,255,254  'WHITE
Data 136,  0, 21  'red brown
Data 185,122, 87  'brown
Data 237, 28, 36  'red
Data 255,174,201  'pink
Data 255,127, 39  'orange
Data 255,201, 14  'deep yellow gold
Data 255,242,  0  'yellow
Data 239,228,176  'light yellow
Data  34,177, 76  'green
Data 181,230, 29  'lime
Data   0,162,232  'turquoise  medium blue
Data 153,217,234  'light blue
Data  63, 72,204  'indigo dark blue
Data 112,146,190  'blue gray
Data 163, 73,164  'purple
Data 200,191,231  'lavenda
'=====================================
Data 255,128,128
Data 255,  0,  0
Data 128, 64, 64
Data 128,  0,  0

Data 255,255,128 'yellow
Data 255,255,  0
Data 255,128, 64 'orange
Data 255,128,  0
Data 128, 64,  0 'brown
Data 128,128,  0

Data 128,255,128  'green
Data 128,255,  0
Data   0,255,  0
Data   0,128,  0
Data   0, 64,  0
Data 128,128, 64

Data   0,255,128
Data   0,255, 64
Data   0,128,128
Data   0,128, 64
Data   0, 64, 64
Data 128,128,128  'gray

Data 128,255,255  'blue
Data   0,255,255
Data   0, 64,128
Data   0,  0,255
Data   0,  0,128
Data  64,128,128

Data   0,128,255
Data   0,128,192
Data 128,128,255
Data   0,  0,160
Data   0,  0, 64
Data 192,192,192  'gray

Data 255,128,192  'red
Data 128,128,192
Data 128,  0, 64
Data 128,  0,128  'purple
Data  64,  0, 64
Data  64,  0,128  'black

Data 255,128,255
Data 255,  0,255
Data 255,  0,128
Data 128,  0,255
Data 64,   0,128
Data 255,255,254  'white