Converting image to Vector Drawing commands
Posted: Mon Apr 13, 2020 9:27 am
I was quite impressed with the work davido did in creating a scalable set of chess pieces. I'm familiar with the design he used but unfortunately for me it isn't my favorite. I wanted to create a similar set with the pieces I'm used to using so I tried to find a simple, as automated as possible, way to do it. I pm'd davido and asked how he did it and I confess to being disappointed with his answer. He said he did it all by hand. I tried with no luck to find alternatives and eventually gave in to the reality that I'm going to have to do the same. I started with the white king, copied it out from my sprite set and set to work. Here is the method I used:
-Load the image into Photoshop and mark all corners with red dots.
-Use the rectangular selection tool to find the precise locations of the dots and record them.
-Load the image into PB, remove the fill color leaving just the lines and display in a window at a reduced alpha.
-Use AddPathCurve and AddPathLine to go around the outside of the image, one curve or line at a time. This took about two hours of trial and error.
-I wrote all my path commands with hardcoded numbers. The image is 300x300 so most of the numbers were inside those dimensions.
-Once I was able to trace a path that would fill correctly, I added fill commands.
-Then I added the rest of the interior lines.
At this point I had a set of commands that would draw a nice white king at 300x300 pixels in size. But it needs to be scalable. To this end I wrote a helper program that I could plug my hardcoded numbers into and it would give a scalable equivalent.
Plug:into it and it would reply withOnce the helper was written, converting the commands didn't take much time at all. Anyway, if you're interested in this kind of thing, here's what I did:
Design program:
Helper:
And the final product:
Only 11 more pieces to go. What the heck, I've got nothing better to do these days. Can't go outside or run my business, might as well fill the time with something.
-Load the image into Photoshop and mark all corners with red dots.
-Use the rectangular selection tool to find the precise locations of the dots and record them.
-Load the image into PB, remove the fill color leaving just the lines and display in a window at a reduced alpha.
-Use AddPathCurve and AddPathLine to go around the outside of the image, one curve or line at a time. This took about two hours of trial and error.
-I wrote all my path commands with hardcoded numbers. The image is 300x300 so most of the numbers were inside those dimensions.
-Once I was able to trace a path that would fill correctly, I added fill commands.
-Then I added the rest of the interior lines.
At this point I had a set of commands that would draw a nice white king at 300x300 pixels in size. But it needs to be scalable. To this end I wrote a helper program that I could plug my hardcoded numbers into and it would give a scalable equivalent.
Plug:
Code: Select all
AddPathCurve(92,26,-42,140,77,199)Code: Select all
AddpathCurve(0.3067*sz,0.0867*sz,-0.1400*sz,0.4667*sz,0.2567*sz,0.6633*sz)Design program:
Code: Select all
Procedure Transparency(x,y, sourcecolor, targetcolor)
If sourcecolor=RGBA(255,255,255,255)
ProcedureReturn targetcolor
Else
ProcedureReturn sourcecolor
EndIf
EndProcedure
imagefile$ = GetTemporaryDirectory()+"netmaestro-wk.png"
If FileSize(imagefile$) = -1
InitNetwork()
If Not ReceiveHTTPFile("https://lloydsplace.com/wk.png", imagefile$)
MessageRequester("oops", "Could not download the image")
End
EndIf
EndIf
Global sz.d=700
UsePNGImageDecoder()
img0 = LoadImage(#PB_Any, imagefile$)
; First remove the fill color
CreateImage(0,300,300,32,#PB_Image_Transparent)
StartDrawing(ImageOutput(0))
DrawingMode(#PB_2DDrawing_CustomFilter)
CustomFilterCallback(@Transparency())
DrawAlphaImage(ImageID(img0),0,0)
StopDrawing()
; Create a new image, draw the picture on it with a low alpha to trace our lines on
CreateImage(1, sz, sz, 32, #PB_Image_Transparent)
StartVectorDrawing(ImageVectorOutput(1))
MovePathCursor(0,0)
DrawVectorImage(ImageID(0),50,sz,sz)
MovePathCursor(0.5*sz,0.5*sz)
AddPathCurve(0.6933*sz,0.0867*sz,1.1400*sz,0.4667*sz,0.7433*sz,0.6633*sz)
AddPathLine(0.7447*sz,0.8366*sz)
AddPathCurve(0.6333*sz,0.9100*sz,0.3666*sz,0.9100*sz,0.2533*sz,0.8366*sz) ;0.2533*sz,0.8366*sz
AddPathLine(0.2567*sz,0.6633*sz)
AddPathCurve(-0.1400*sz,0.4667*sz,0.3067*sz,0.0867*sz,0.5*sz,0.5*sz)
VectorSourceLinearGradient(0.0933*sz,0.4733*sz,0.9067*sz,0.4733*sz)
VectorSourceGradientColor(RGBA(255,255, 255, 255), 0.0)
VectorSourceGradientColor(RGBA(230, 230, 230, 255), 0.8)
VectorSourceGradientColor(RGBA(200,200, 200, 255), 1.0)
FillPath(#PB_Path_Preserve)
VectorSourceColor(RGBA(0,0,0,255))
StrokePath(0.0100*sz) ; I use this width at design time
;StrokePath(0.0366*sz) ; This width is for the finished product
MovePathCursor(0.4300*sz,0.3900*sz)
AddPathCurve(0.4333*sz,0.3600*sz,0.3833*sz,0.2600*sz,0.5*sz,0.22*sz)
AddPathCurve(0.6166*sz,0.2600*sz,0.5666*sz,0.3600*sz,0.5700*sz,0.3900*sz)
AddPathLine(0.5*sz,0.5*sz)
AddPathLine(0.4300*sz,0.3900*sz)
VectorSourceLinearGradient(0.4200*sz,0.3200*sz,0.5800*sz,0.3200*sz)
VectorSourceGradientColor(RGBA(255,255, 255, 255), 0.0)
VectorSourceGradientColor(RGBA(220, 220, 220, 255), 0.8)
VectorSourceGradientColor(RGBA(190,190, 190, 255), 1.0)
FillPath(#PB_Path_Preserve)
MovePathCursor(0.5*sz,0.49*sz)
AddPathLine(0.5*sz,0.6033*sz)
MovePathCursor(0.5*sz,0.073*sz)
AddPathLine(0.5*sz,0.22*sz)
MovePathCursor(0.44*sz,0.121*sz)
AddPathLine(0.56*sz,0.121*sz)
VectorSourceColor(RGBA(0,0,0,255))
StrokePath(0.0100*sz) ; I use this width at design time
;StrokePath(0.0366*sz,#PB_Path_RoundEnd) ; This width is for the finished product
MovePathCursor(0.2533*sz,0.6633*sz)
AddPathCurve(0.3666*sz,0.5900*sz,0.6333*sz,0.5900*sz,0.7433*sz,0.6633*sz)
MovePathCursor(0.2533*sz,0.7466*sz)
AddPathCurve(0.3666*sz,0.6766*sz,0.6333*sz,0.6766*sz,0.7433*sz,0.7433*sz)
MovePathCursor(0.2533*sz,0.8366*sz)
AddPathCurve(0.3666*sz,0.7633*sz,0.6333*sz,0.7633*sz,0.7433*sz,0.8366*sz)
StrokePath(0.0100*sz) ; I use this width at design time
;StrokePath(0.0366*sz) ; This width is for the finished product
StopVectorDrawing()
OpenWindow(0,0,0,sz,sz,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StickyWindow(0,1)
ImageGadget(0,0,0,0,0,ImageID(1))
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
Code: Select all
Global sz.d=300
Procedure.s ReplaceCurve(a.d,b.d,c.d,d.d,e.d,f.d)
a.d = a/sz
b.d = b/sz
c.d = c/sz
d.d = d/sz
e.d = e/sz
f.d = f/sz
a$ = StrD(a,4) + "*sz,"
b$ = StrD(b,4) + "*sz,"
c$ = StrD(c,4) + "*sz,"
d$ = StrD(d,4) + "*sz,"
e$ = StrD(e,4) + "*sz,"
f$ = StrD(f,4) + "*sz"
ProcedureReturn "AddpathCurve("+a$+b$+c$+d$+e$+f$+")"
EndProcedure
Debug ReplaceCurve(92,26,-42,140,77,199)
Code: Select all
Procedure DrawWhiteKing(sz.d, linecolor.q, fillcolor.q = 0, gradient.b = 0)
result = CreateImage(#PB_Any, sz, sz, 32, #PB_Image_Transparent)
StartVectorDrawing(ImageVectorOutput(result))
MovePathCursor(0.5*sz,0.5*sz)
AddPathCurve(0.6933*sz,0.0867*sz,1.1400*sz,0.4667*sz,0.7433*sz,0.6633*sz)
AddPathLine(0.7447*sz,0.8366*sz)
AddPathCurve(0.6333*sz,0.9100*sz,0.3666*sz,0.9100*sz,0.2533*sz,0.8366*sz)
AddPathLine(0.2567*sz,0.6633*sz)
AddPathCurve(-0.1400*sz,0.4667*sz,0.3067*sz,0.0867*sz,0.5*sz,0.5*sz)
FillPath(#PB_Path_Preserve)
VectorSourceColor(linecolor)
StrokePath(0.0366*sz,#PB_Path_Preserve)
MovePathCursor(0.4300*sz,0.3900*sz)
AddPathCurve(0.4333*sz,0.3600*sz,0.3833*sz,0.2600*sz,0.5*sz,0.22*sz)
AddPathCurve(0.6166*sz,0.2600*sz,0.5666*sz,0.3600*sz,0.5700*sz,0.3900*sz)
AddPathLine(0.5*sz,0.5*sz)
AddPathLine(0.4300*sz,0.3900*sz)
If gradient
VectorSourceLinearGradient(0.0000*sz,0.5000*sz,1.0000*sz,0.5000*sz)
VectorSourceGradientColor(RGBA(255,255, 255, 255), 0.0)
VectorSourceGradientColor(RGBA(220, 220, 220, 255), 0.8)
VectorSourceGradientColor(RGBA(190,190, 190, 255), 1.0)
Else
VectorSourceColor(fillcolor)
EndIf
FillPath(#PB_Path_Preserve)
MovePathCursor(0.5*sz,0.5*sz)
AddPathLine(0.5*sz,0.6033*sz)
MovePathCursor(0.5*sz,0.073*sz)
AddPathLine(0.5*sz,0.22*sz)
MovePathCursor(0.44*sz,0.121*sz)
AddPathLine(0.56*sz,0.121*sz)
VectorSourceColor(linecolor)
StrokePath(0.0366*sz,#PB_Path_RoundEnd)
MovePathCursor(0.2533*sz,0.6633*sz)
AddPathCurve(0.3666*sz,0.5900*sz,0.6333*sz,0.5900*sz,0.7433*sz,0.6633*sz)
MovePathCursor(0.2533*sz,0.7466*sz)
AddPathCurve(0.3666*sz,0.6766*sz,0.6333*sz,0.6766*sz,0.7433*sz,0.7433*sz)
MovePathCursor(0.2533*sz,0.8366*sz)
AddPathCurve(0.3666*sz,0.7633*sz,0.6333*sz,0.7633*sz,0.7433*sz,0.8366*sz)
StrokePath(0.0366*sz)
StopVectorDrawing()
ProcedureReturn result
EndProcedure
;test
sz=1000
result = DrawWhiteKing(sz,RGBA(0,0,0,255),RGBA(255,255,255,255),1)
; UsePNGImageEncoder()
; SaveImage(result,"wk.png",#PB_ImagePlugin_PNG)
OpenWindow(0,0,0,sz,sz,"",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StickyWindow(0,1)
ImageGadget(0,0,0,0,0,ImageID(result))
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow