从 PIL 中绘制点线或虚线矩形

Shr*_*rey 2 python python-imaging-library python-3.x

我想用PIL画一个虚线矩形。

我知道我可以绘制 4 条不同的虚线,使其看起来像一个矩形:

for x in range(0, Width_of_image, 5):
    d.line([(x, 30), (x + 2, 30)],fill ="black", width =2) 
Run Code Online (Sandbox Code Playgroud)

但是有没有办法使用 绘制一个矩形draw.rectangle,即不绘制 4 条不同的线?

and*_*nds 9

正如其他用户所说,PIL 库(特别是PIL.ImageDraw.ImageDraw)不提供绘制虚线的功能。我查看了有关 PIL 中虚线的 StackOverflow 问题(以及其他地方),但我还没有找到在 PIL 中绘制虚线的令人满意的方法。我找到的答案都没有以预期的方式绘制虚线(其他Python库提供虚线的方式,例如使用Tkinter canvas)。

\n

所以我编写了一个类DashedImageDraw(它扩展了PIL.ImageDraw.ImageDraw),它具有绘制虚线和虚线矩形的功能。以下是代码和如何使用它的示例:

\n
from PIL import Image, ImageDraw\nimport math\n\n\nclass DashedImageDraw(ImageDraw.ImageDraw):\n\n    def thick_line(self, xy, direction, fill=None, width=0):\n        #xy \xe2\x80\x93 Sequence of 2-tuples like [(x, y), (x, y), ...]\n        #direction \xe2\x80\x93 Sequence of 2-tuples like [(x, y), (x, y), ...]\n        if xy[0] != xy[1]:\n            self.line(xy, fill = fill, width = width)\n        else:\n            x1, y1 = xy[0]            \n            dx1, dy1 = direction[0]\n            dx2, dy2 = direction[1]\n            if dy2 - dy1 < 0:\n                x1 -= 1\n            if dx2 - dx1 < 0:\n                y1 -= 1\n            if dy2 - dy1 != 0:\n                if dx2 - dx1 != 0:\n                    k = - (dx2 - dx1)/(dy2 - dy1)\n                    a = 1/math.sqrt(1 + k**2)\n                    b = (width*a - 1) /2\n                else:\n                    k = 0\n                    b = (width - 1)/2\n                x3 = x1 - math.floor(b)\n                y3 = y1 - int(k*b)\n                x4 = x1 + math.ceil(b)\n                y4 = y1 + int(k*b)\n            else:\n                x3 = x1\n                y3 = y1 - math.floor((width - 1)/2)\n                x4 = x1\n                y4 = y1 + math.ceil((width - 1)/2)\n            self.line([(x3, y3), (x4, y4)], fill = fill, width = 1)\n        return   \n        \n    def dashed_line(self, xy, dash=(2,2), fill=None, width=0):\n        #xy \xe2\x80\x93 Sequence of 2-tuples like [(x, y), (x, y), ...]\n        for i in range(len(xy) - 1):\n            x1, y1 = xy[i]\n            x2, y2 = xy[i + 1]\n            x_length = x2 - x1\n            y_length = y2 - y1\n            length = math.sqrt(x_length**2 + y_length**2)\n            dash_enabled = True\n            postion = 0\n            while postion <= length:\n                for dash_step in dash:\n                    if postion > length:\n                        break\n                    if dash_enabled:\n                        start = postion/length\n                        end = min((postion + dash_step - 1) / length, 1)\n                        self.thick_line([(round(x1 + start*x_length),\n                                          round(y1 + start*y_length)),\n                                         (round(x1 + end*x_length),\n                                          round(y1 + end*y_length))],\n                                        xy, fill, width)\n                    dash_enabled = not dash_enabled\n                    postion += dash_step\n        return\n\n    def dashed_rectangle(self, xy, dash=(2,2), outline=None, width=0):\n        #xy - Sequence of [(x1, y1), (x2, y2)] where (x1, y1) is top left corner and (x2, y2) is bottom right corner\n        x1, y1 = xy[0]\n        x2, y2 = xy[1]\n        halfwidth1 = math.floor((width - 1)/2)\n        halfwidth2 = math.ceil((width - 1)/2)\n        min_dash_gap = min(dash[1::2])\n        end_change1 = halfwidth1 + min_dash_gap + 1\n        end_change2 = halfwidth2 + min_dash_gap + 1\n        odd_width_change = (width - 1)%2        \n        self.dashed_line([(x1 - halfwidth1, y1), (x2 - end_change1, y1)],\n                         dash, outline, width)       \n        self.dashed_line([(x2, y1 - halfwidth1), (x2, y2 - end_change1)],\n                         dash, outline, width)\n        self.dashed_line([(x2 + halfwidth2, y2 + odd_width_change),\n                          (x1 + end_change2, y2 + odd_width_change)],\n                         dash, outline, width)\n        self.dashed_line([(x1 + odd_width_change, y2 + halfwidth2),\n                          (x1 + odd_width_change, y1 + end_change2)],\n                         dash, outline, width)\n        return\n        \n\n\nimage = Image.new(\'RGB\', (300, 200), (255, 255, 255))\nd = DashedImageDraw(image)\n\nd.dashed_rectangle([(20, 20), (280, 180)],\n                   dash = (5, 3), outline  = \'black\', width = 2)\n\nimage.save("image.png", "PNG")\n
Run Code Online (Sandbox Code Playgroud)\n

这条线绘制了矩形:

\n
d.dashed_rectangle([(20, 20), (280, 180)], dash = (5, 3), outline  = \'black\', width = 2)\n
Run Code Online (Sandbox Code Playgroud)\n

(20, 20)是左上角,(280, 180)是右下角,outline是线条的颜色,width是线条的宽度,dash 是表示虚线图案的元组。例如:

\n
    \n
  • dash = (5, 3) 将画线:

    \n

    ----- ----- ----- ----- ----- -----

    \n
  • \n
  • dash = (4, 2, 3, 1) 将画线:

    \n

    ---- --- ---- --- ---- --- ---- --- ----

    \n
  • \n
\n

这是上面代码生成的虚线矩形的图像:

\n

虚线矩形

\n