133 lines
4.4 KiB
Python
133 lines
4.4 KiB
Python
import unittest
|
|
import os
|
|
from PIL import Image, ImageDraw, ImageColor, ImageChops
|
|
from math import sqrt
|
|
|
|
from ..path import CubicBezier, QuadraticBezier, Line, Arc
|
|
|
|
|
|
RED = ImageColor.getcolor("red", mode="RGB")
|
|
GREEN = ImageColor.getcolor("limegreen", mode="RGB")
|
|
BLUE = ImageColor.getcolor("cornflowerblue", mode="RGB")
|
|
YELLOW = ImageColor.getcolor("yellow", mode="RGB")
|
|
CYAN = ImageColor.getcolor("cyan", mode="RGB")
|
|
WHITE = ImageColor.getcolor("white", mode="RGB")
|
|
BLACK = ImageColor.getcolor("black", mode="RGB")
|
|
|
|
DOT = 4 + 4j # x+y radius of dot
|
|
|
|
|
|
def c2t(c):
|
|
"""Make a complex number into a tuple"""
|
|
return c.real, c.imag
|
|
|
|
|
|
def magnitude(c):
|
|
return sqrt(c.real**2 + c.imag**2)
|
|
|
|
|
|
class ImageTest(unittest.TestCase):
|
|
"""Creates a PNG image and compares with a correct PNG"""
|
|
|
|
def setUp(self):
|
|
self.image = Image.new(mode="RGB", size=(500, 1200))
|
|
self.draw = ImageDraw.Draw(self.image)
|
|
|
|
def draw_path(self, path):
|
|
lines = [c2t(path.point(x * 0.01)) for x in range(1, 101)]
|
|
self.draw.line(lines, fill=WHITE, width=2)
|
|
|
|
p = path.point(0)
|
|
self.draw.ellipse([c2t(p - DOT), c2t(p + DOT)], fill=BLUE)
|
|
p = path.point(1)
|
|
self.draw.ellipse([c2t(p - DOT), c2t(p + DOT)], fill=GREEN)
|
|
|
|
def draw_tangents(self, path, count):
|
|
count += 1
|
|
for i in range(1, count):
|
|
p = path.point(i / count)
|
|
t = path.tangent(i / count)
|
|
self.draw.line([c2t(p), c2t(p + t)], fill=RED, width=1)
|
|
|
|
# And a nice 90 angle
|
|
tt = complex(t.imag, -t.real)
|
|
# scale it to always be 20px
|
|
tt *= 20 / magnitude(tt)
|
|
|
|
self.draw.line([c2t(p), c2t(tt + p)], fill=YELLOW, width=1)
|
|
|
|
def test_image(self):
|
|
self.draw.text((10, 10), "This is an SVG line:")
|
|
self.draw.text(
|
|
(10, 100),
|
|
"The red line is a tangent, and the yellow is 90 degrees from that.",
|
|
)
|
|
|
|
line1 = Line(40 + 60j, 200 + 80j)
|
|
self.draw_path(line1)
|
|
self.draw_tangents(line1, 1)
|
|
|
|
self.draw.text((10, 140), "This is an Arc segment, almost a whole circle:")
|
|
arc1 = Arc(260 + 320j, 100 + 100j, 0, 1, 1, 260 + 319j)
|
|
self.draw_path(arc1)
|
|
self.draw_tangents(arc1, 5)
|
|
self.draw.text((10, 460), "With five tangents.")
|
|
|
|
self.draw.text(
|
|
(10, 500),
|
|
"Next we have a quadratic bezier curve, with one tangent:",
|
|
)
|
|
start = 30 + 600j
|
|
control = 400 + 540j
|
|
end = 260 + 650j
|
|
qbez1 = QuadraticBezier(start, control, end)
|
|
self.draw_path(qbez1)
|
|
self.draw.ellipse([c2t(control - DOT), c2t(control + DOT)], fill=WHITE)
|
|
self.draw.line([c2t(start), c2t(control), c2t(end)], fill=CYAN)
|
|
self.draw_tangents(qbez1, 1)
|
|
self.draw.text(
|
|
(10, 670),
|
|
"The white dot is the control point, and the cyan lines are ",
|
|
)
|
|
self.draw.text((10, 690), "illustrating the how the control point works.")
|
|
|
|
self.draw.text(
|
|
(10, 730),
|
|
"Lastly is a cubic bezier, with 2 tangents, and 2 control points:",
|
|
)
|
|
|
|
start = 30 + 800j
|
|
control1 = 400 + 780j
|
|
control2 = 50 + 900j
|
|
end = 300 + 980j
|
|
cbez1 = CubicBezier(start, control1, control2, end)
|
|
self.draw_path(cbez1)
|
|
self.draw.ellipse([c2t(control1 - DOT), c2t(control1 + DOT)], fill=WHITE)
|
|
self.draw.ellipse([c2t(control2 - DOT), c2t(control2 + DOT)], fill=WHITE)
|
|
self.draw.line(
|
|
[
|
|
c2t(start),
|
|
c2t(control1),
|
|
],
|
|
fill=CYAN,
|
|
)
|
|
self.draw.line([c2t(control2), c2t(end)], fill=CYAN)
|
|
self.draw_tangents(cbez1, 2)
|
|
|
|
# self.image.show() # Useful when debugging
|
|
|
|
filename = os.path.join(os.path.split(__file__)[0], "test_image.png")
|
|
|
|
# If you have made intentional changes to the test_image.png, save it
|
|
# by uncommenting these lines. Don't forget to comment them out again,
|
|
# or the test will always pass
|
|
# with open(filename, "wb") as fp:
|
|
# self.image.save(fp, format="PNG")
|
|
|
|
with open(filename, "rb") as fp:
|
|
test_image = Image.open(fp, mode="r")
|
|
diff = ImageChops.difference(test_image, self.image)
|
|
self.assertFalse(
|
|
diff.getbbox(), "The resulting image is different from test_image.png"
|
|
)
|