Convert to a Function#
If we change our script into a function we need to know the start and finish of the line together with a knowledge of the dash and gap sizes. Use a tuple similar to the system from tkinter canvas. So the function's heading will be like:
def line_dashed(im, start_pos, end_pos, dash=(5,5), width = 1, fill='black'):
Where im is the PIL Image alias.
Separate the function parts from the main function in the previous example. Extract the tuple information, compute the length of a single dash and the following gap, derive the line length, from these find out how many times the pattern is repeated, and insert into the linspace functions. Assume for the moment that we are only dealing with vertical lines and add the length of a dash to the y part of the start and end coordinates. Then there should be a script like the following.
Show/Hide Code 05dash_gap_function.py
import sys
sys.path.append('../dims')
from PIL import Image, ImageDraw, ImageFont
from math import dist
from numpy import linspace, concatenate, int_
from DimLinesPIL import angled_text, dims, int_up
def line_dashed(dr, start_pos, end_pos, dash=(5,5), width = 1, fill='black'):
# create dashed lines in PIL
# unpack tuples
x0, y0 = start_pos
x1, y1 = end_pos
dash0, dash1 = dash
dash2 = dash0 - 1
# sort out lengths
dash_gap_length = sum(dash)
line_length = dist(start_pos, end_pos)
# inclusive number of dashes and gaps
dash_amount = int_up(line_length / dash_gap_length) + 1
start_arr = linspace((x0, y0), (x1, y1), dash_amount)
end_arr = linspace((x0, y0 + dash2), (x1, y1 + dash2), dash_amount)
print(start_arr, 'start_arr')
both_arr = concatenate([start_arr, end_arr], axis=0)
fin_arr = int_(both_arr[both_arr[:, 1].argsort()])
nr_lines = len(fin_arr)
[dr.line([tuple(fin_arr[n]), tuple(fin_arr[n+1])], width=width, fill=fill)
for n in range(0, nr_lines, 2)]
if __name__ == "__main__":
Font = ImageFont.truetype('consola.ttf', 12)
arr =[(30, 10),
(30, 24),
(30, 40),
(30, 54),
(30, 70),
(30, 84)]
nr_lines = len(arr)
Dash =(15, 15)
Start_pos = (30, 10)
End_pos = (30, 70)
w, h = 100, 100
image = Image.new('RGB', (w,h), '#FFFFDD')
draw = ImageDraw.Draw(image)
# wide, height = Font.getsize('(30, 84)')
unused1, unused2, wide, height = Font.getbbox('(30, 84)')
for i in range(nr_lines):
angled_text(image, (arr[i][0] + 10 + wide//2, arr[i][1]),text=str(arr[i]),
angle=0, fill='black', font=Font)
for j in range(nr_lines - 1):
dims(image, draw, arr[j], arr[j+1], (8, 2), text='15', font=Font, fill='lightgreen',
textorient='horizontal')
line_dashed(draw, Start_pos, End_pos, dash=Dash, width = 1, fill='black')
image.show()
It should match up to the previous array.
There are several shortcomings in the script.
- Line length
Accommodate lines that do not finish exactly at the pattern end.
- Change orientation
The examples so far were with vertical lines.
- Different line patterns
The dash tuple so far only had 2 entries
- Revisit line lengths
With more complex patterns the lines may go beyond the end position.
As we go along other problems will undoubtedly raise their heads.