{
    "file_diffs": [
        {
            "old_file_content": "import os.path\n\nimport pytest\nfrom PIL import Image, ImageColor, ImageDraw, ImageFont\n\nfrom .helper import (\n    assert_image_equal,\n    assert_image_similar,\n    hopper,\n    skip_unless_feature,\n)\n\nBLACK = (0, 0, 0)\nWHITE = (255, 255, 255)\nGRAY = (190, 190, 190)\nDEFAULT_MODE = \"RGB\"\nIMAGES_PATH = os.path.join(\"Tests\", \"images\", \"imagedraw\")\n\n# Image size\nW, H = 100, 100\n\n# Bounding box points\nX0 = int(W / 4)\nX1 = int(X0 * 3)\nY0 = int(H / 4)\nY1 = int(X0 * 3)\n\n# Two kinds of bounding box\nBBOX1 = [(X0, Y0), (X1, Y1)]\nBBOX2 = [X0, Y0, X1, Y1]\n\n# Two kinds of coordinate sequences\nPOINTS1 = [(10, 10), (20, 40), (30, 30)]\nPOINTS2 = [10, 10, 20, 40, 30, 30]\n\nKITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)]\n\n\ndef test_sanity():\n    im = hopper(\"RGB\").copy()\n\n    draw = ImageDraw.ImageDraw(im)\n    draw = ImageDraw.Draw(im)\n\n    draw.ellipse(list(range(4)))\n    draw.line(list(range(10)))\n    draw.polygon(list(range(100)))\n    draw.rectangle(list(range(4)))\n\n\ndef test_valueerror():\n    with Image.open(\"Tests/images/chi.gif\") as im:\n\n        draw = ImageDraw.Draw(im)\n        draw.line((0, 0), fill=(0, 0, 0))\n\n\ndef test_mode_mismatch():\n    im = hopper(\"RGB\").copy()\n\n    with pytest.raises(ValueError):\n        ImageDraw.ImageDraw(im, mode=\"L\")\n\n\ndef helper_arc(bbox, start, end):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.arc(bbox, start, end)\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_arc.png\"), 1)\n\n\ndef test_arc1():\n    helper_arc(BBOX1, 0, 180)\n    helper_arc(BBOX1, 0.5, 180.4)\n\n\ndef test_arc2():\n    helper_arc(BBOX2, 0, 180)\n    helper_arc(BBOX2, 0.5, 180.4)\n\n\ndef test_arc_end_le_start():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    start = 270.5\n    end = 0\n\n    # Act\n    draw.arc(BBOX1, start=start, end=end)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_arc_end_le_start.png\"))\n\n\ndef test_arc_no_loops():\n    # No need to go in loops\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    start = 5\n    end = 370\n\n    # Act\n    draw.arc(BBOX1, start=start, end=end)\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_arc_no_loops.png\"), 1)\n\n\ndef test_arc_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_pieslice_large():\n    # Tests an arc with a large enough width that it is a pieslice\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_pieslice.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, fill=\"yellow\", width=100)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_fill.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, fill=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_non_whole_angle():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_non_whole_angle.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 259.5, width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_bitmap():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    with Image.open(\"Tests/images/pil123rgba.png\") as small:\n        small = small.resize((50, 50), Image.NEAREST)\n\n        # Act\n        draw.bitmap((10, 10), small)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_bitmap.png\"))\n\n\ndef helper_chord(mode, bbox, start, end):\n    # Arrange\n    im = Image.new(mode, (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_{}.png\".format(mode)\n\n    # Act\n    draw.chord(bbox, start, end, fill=\"red\", outline=\"yellow\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord1():\n    for mode in [\"RGB\", \"L\"]:\n        helper_chord(mode, BBOX1, 0, 180)\n        helper_chord(mode, BBOX1, 0.5, 180.4)\n\n\ndef test_chord2():\n    for mode in [\"RGB\", \"L\"]:\n        helper_chord(mode, BBOX2, 0, 180)\n        helper_chord(mode, BBOX2, 0.5, 180.4)\n\n\ndef test_chord_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_width.png\"\n\n    # Act\n    draw.chord(BBOX1, 10, 260, outline=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_width_fill.png\"\n\n    # Act\n    draw.chord(BBOX1, 10, 260, fill=\"red\", outline=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.chord(BBOX1, 10, 260, fill=\"red\", outline=\"yellow\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_chord_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_ellipse(mode, bbox):\n    # Arrange\n    im = Image.new(mode, (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_{}.png\".format(mode)\n\n    # Act\n    draw.ellipse(bbox, fill=\"green\", outline=\"blue\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse1():\n    for mode in [\"RGB\", \"L\"]:\n        helper_ellipse(mode, BBOX1)\n\n\ndef test_ellipse2():\n    for mode in [\"RGB\", \"L\"]:\n        helper_ellipse(mode, BBOX2)\n\n\ndef test_ellipse_translucent():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im, \"RGBA\")\n\n    # Act\n    draw.ellipse(BBOX1, fill=(0, 255, 0, 127))\n\n    # Assert\n    expected = Image.open(\"Tests/images/imagedraw_ellipse_translucent.png\")\n    assert_image_similar(im, expected, 1)\n\n\ndef test_ellipse_edge():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.ellipse(((0, 0), (W - 1, H)), fill=\"white\")\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_ellipse_edge.png\"), 1)\n\n\ndef test_ellipse_symmetric():\n    for bbox in [(25, 25, 76, 76), (25, 25, 75, 75)]:\n        im = Image.new(\"RGB\", (101, 101))\n        draw = ImageDraw.Draw(im)\n        draw.ellipse(bbox, fill=\"green\", outline=\"blue\")\n        assert_image_equal(im, im.transpose(Image.FLIP_LEFT_RIGHT))\n\n\ndef test_ellipse_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width.png\"\n\n    # Act\n    draw.ellipse(BBOX1, outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_width_large():\n    # Arrange\n    im = Image.new(\"RGB\", (500, 500))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width_large.png\"\n\n    # Act\n    draw.ellipse((25, 25, 475, 475), outline=\"blue\", width=75)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width_fill.png\"\n\n    # Act\n    draw.ellipse(BBOX1, fill=\"green\", outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.ellipse(BBOX1, fill=\"green\", outline=\"blue\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_ellipse_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_line(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.line(points, fill=\"yellow\", width=2)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_line.png\"))\n\n\ndef test_line1():\n    helper_line(POINTS1)\n\n\ndef test_line2():\n    helper_line(POINTS2)\n\n\ndef test_shape1():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 100), \"white\")\n    draw = ImageDraw.Draw(im)\n    x0, y0 = 5, 5\n    x1, y1 = 5, 50\n    x2, y2 = 95, 50\n    x3, y3 = 95, 5\n\n    # Act\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    draw.shape(s, fill=1)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_shape1.png\"))\n\n\ndef test_shape2():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 100), \"white\")\n    draw = ImageDraw.Draw(im)\n    x0, y0 = 95, 95\n    x1, y1 = 95, 50\n    x2, y2 = 5, 50\n    x3, y3 = 5, 95\n\n    # Act\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    draw.shape(s, outline=\"blue\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_shape2.png\"))\n\n\ndef helper_pieslice(bbox, start, end):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.pieslice(bbox, start, end, fill=\"white\", outline=\"blue\")\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_pieslice.png\"), 1)\n\n\ndef test_pieslice1():\n    helper_pieslice(BBOX1, -90, 45)\n    helper_pieslice(BBOX1, -90.5, 45.4)\n\n\ndef test_pieslice2():\n    helper_pieslice(BBOX2, -90, 45)\n    helper_pieslice(BBOX2, -90.5, 45.4)\n\n\ndef test_pieslice_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_pieslice_width.png\"\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_pieslice_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_pieslice_width_fill.png\"\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, fill=\"white\", outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_pieslice_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, fill=\"white\", outline=\"blue\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_pieslice_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_point(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.point(points, fill=\"yellow\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_point.png\"))\n\n\ndef test_point1():\n    helper_point(POINTS1)\n\n\ndef test_point2():\n    helper_point(POINTS2)\n\n\ndef helper_polygon(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.polygon(points, fill=\"red\", outline=\"blue\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_polygon.png\"))\n\n\ndef test_polygon1():\n    helper_polygon(POINTS1)\n\n\ndef test_polygon2():\n    helper_polygon(POINTS2)\n\n\ndef test_polygon_kite():\n    # Test drawing lines of different gradients (dx>dy, dy>dx) and\n    # vertical (dx==0) and horizontal (dy==0) lines\n    for mode in [\"RGB\", \"L\"]:\n        # Arrange\n        im = Image.new(mode, (W, H))\n        draw = ImageDraw.Draw(im)\n        expected = \"Tests/images/imagedraw_polygon_kite_{}.png\".format(mode)\n\n        # Act\n        draw.polygon(KITE_POINTS, fill=\"blue\", outline=\"yellow\")\n\n        # Assert\n        assert_image_equal(im, Image.open(expected))\n\n\ndef helper_rectangle(bbox):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(bbox, fill=\"black\", outline=\"green\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_rectangle.png\"))\n\n\ndef test_rectangle1():\n    helper_rectangle(BBOX1)\n\n\ndef test_rectangle2():\n    helper_rectangle(BBOX2)\n\n\ndef test_big_rectangle():\n    # Test drawing a rectangle bigger than the image\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    bbox = [(-1, -1), (W + 1, H + 1)]\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_big_rectangle.png\"\n\n    # Act\n    draw.rectangle(bbox, fill=\"orange\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_rectangle_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_rectangle_width.png\"\n\n    # Act\n    draw.rectangle(BBOX1, outline=\"green\", width=5)\n\n    # Assert\n    assert_image_equal(im, Image.open(expected))\n\n\ndef test_rectangle_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_rectangle_width_fill.png\"\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"blue\", outline=\"green\", width=5)\n\n    # Assert\n    assert_image_equal(im, Image.open(expected))\n\n\ndef test_rectangle_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"blue\", outline=\"green\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_rectangle_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef test_rectangle_I16():\n    # Arrange\n    im = Image.new(\"I;16\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"black\", outline=\"green\")\n\n    # Assert\n    assert_image_equal(\n        im.convert(\"I\"), Image.open(\"Tests/images/imagedraw_rectangle_I.png\")\n    )\n\n\ndef test_floodfill():\n    red = ImageColor.getrgb(\"red\")\n\n    for mode, value in [(\"L\", 1), (\"RGBA\", (255, 0, 0, 0)), (\"RGB\", red)]:\n        # Arrange\n        im = Image.new(mode, (W, H))\n        draw = ImageDraw.Draw(im)\n        draw.rectangle(BBOX2, outline=\"yellow\", fill=\"green\")\n        centre_point = (int(W / 2), int(H / 2))\n\n        # Act\n        ImageDraw.floodfill(im, centre_point, value)\n\n        # Assert\n        expected = \"Tests/images/imagedraw_floodfill_\" + mode + \".png\"\n        with Image.open(expected) as im_floodfill:\n            assert_image_equal(im, im_floodfill)\n\n    # Test that using the same colour does not change the image\n    ImageDraw.floodfill(im, centre_point, red)\n    assert_image_equal(im, im_floodfill)\n\n    # Test that filling outside the image does not change the image\n    ImageDraw.floodfill(im, (W, H), red)\n    assert_image_equal(im, im_floodfill)\n\n    # Test filling at the edge of an image\n    im = Image.new(\"RGB\", (1, 1))\n    ImageDraw.floodfill(im, (0, 0), red)\n    assert_image_equal(im, Image.new(\"RGB\", (1, 1), red))\n\n\ndef test_floodfill_border():\n    # floodfill() is experimental\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.rectangle(BBOX2, outline=\"yellow\", fill=\"green\")\n    centre_point = (int(W / 2), int(H / 2))\n\n    # Act\n    ImageDraw.floodfill(\n        im, centre_point, ImageColor.getrgb(\"red\"), border=ImageColor.getrgb(\"black\"),\n    )\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_floodfill2.png\"))\n\n\ndef test_floodfill_thresh():\n    # floodfill() is experimental\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.rectangle(BBOX2, outline=\"darkgreen\", fill=\"green\")\n    centre_point = (int(W / 2), int(H / 2))\n\n    # Act\n    ImageDraw.floodfill(im, centre_point, ImageColor.getrgb(\"red\"), thresh=30)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_floodfill2.png\"))\n\n\ndef test_floodfill_not_negative():\n    # floodfill() is experimental\n    # Test that floodfill does not extend into negative coordinates\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.line((W / 2, 0, W / 2, H / 2), fill=\"green\")\n    draw.line((0, H / 2, W / 2, H / 2), fill=\"green\")\n\n    # Act\n    ImageDraw.floodfill(im, (int(W / 4), int(H / 4)), ImageColor.getrgb(\"red\"))\n\n    # Assert\n    assert_image_equal(\n        im, Image.open(\"Tests/images/imagedraw_floodfill_not_negative.png\")\n    )\n\n\ndef create_base_image_draw(\n    size, mode=DEFAULT_MODE, background1=WHITE, background2=GRAY\n):\n    img = Image.new(mode, size, background1)\n    for x in range(0, size[0]):\n        for y in range(0, size[1]):\n            if (x + y) % 2 == 0:\n                img.putpixel((x, y), background2)\n    return img, ImageDraw.Draw(img)\n\n\ndef test_square():\n    with Image.open(os.path.join(IMAGES_PATH, \"square.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((10, 10))\n        draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK)\n        assert_image_equal(img, expected, \"square as normal polygon failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.polygon([(7, 7), (7, 2), (2, 2), (2, 7)], BLACK)\n        assert_image_equal(img, expected, \"square as inverted polygon failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.rectangle((2, 2, 7, 7), BLACK)\n        assert_image_equal(img, expected, \"square as normal rectangle failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.rectangle((7, 7, 2, 2), BLACK)\n        assert_image_equal(img, expected, \"square as inverted rectangle failed\")\n\n\ndef test_triangle_right():\n    with Image.open(os.path.join(IMAGES_PATH, \"triangle_right.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK)\n        assert_image_equal(img, expected, \"triangle right failed\")\n\n\ndef test_line_horizontal():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w2px_normal.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight horizontal normal 2px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w2px_inverted.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight horizontal inverted 2px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_horizontal_w3px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight horizontal normal 3px wide failed\"\n        )\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight horizontal inverted 3px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w101px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((200, 110))\n        draw.line((5, 55, 195, 55), BLACK, 101)\n        assert_image_equal(img, expected, \"line straight horizontal 101px wide failed\")\n\n\ndef test_line_h_s1_w2():\n    pytest.skip(\"failing\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_slope1px_w2px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 6), BLACK, 2)\n        assert_image_equal(img, expected, \"line horizontal 1px slope 2px wide failed\")\n\n\ndef test_line_vertical():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_w2px_normal.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 5, 14), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight vertical normal 2px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_w2px_inverted.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 5, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight vertical inverted 2px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_vertical_w3px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 5, 14), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight vertical normal 3px wide failed\"\n        )\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 5, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight vertical inverted 3px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_vertical_w101px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((110, 200))\n        draw.line((55, 5, 55, 195), BLACK, 101)\n        assert_image_equal(img, expected, \"line straight vertical 101px wide failed\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_slope1px_w2px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 6, 14), BLACK, 2)\n        assert_image_equal(img, expected, \"line vertical 1px slope 2px wide failed\")\n\n\ndef test_line_oblique_45():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_oblique_45_w3px_a.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 14), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 normal 3px wide A failed\")\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 14, 5, 5), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 inverted 3px wide A failed\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_oblique_45_w3px_b.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 14), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 normal 3px wide B failed\")\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 14, 5), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 inverted 3px wide B failed\")\n\n\ndef test_wide_line_dot():\n    # Test drawing a wide \"line\" from one point to another just draws a single point\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_wide_line_dot.png\"\n\n    # Act\n    draw.line([(50, 50), (50, 50)], width=3)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_line_joint():\n    im = Image.new(\"RGB\", (500, 325))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_line_joint_curve.png\"\n\n    # Act\n    xy = [\n        (400, 280),\n        (380, 280),\n        (450, 280),\n        (440, 120),\n        (350, 200),\n        (310, 280),\n        (300, 280),\n        (250, 280),\n        (250, 200),\n        (150, 200),\n        (150, 260),\n        (50, 200),\n        (150, 50),\n        (250, 100),\n    ]\n    draw.line(xy, GRAY, 50, \"curve\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 3)\n\n\ndef test_textsize_empty_string():\n    # https://github.com/python-pillow/Pillow/issues/2783\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    # Should not cause 'SystemError: <built-in method getsize of\n    # ImagingFont object at 0x...> returned NULL without setting an error'\n    draw.textsize(\"\")\n    draw.textsize(\"\\n\")\n    draw.textsize(\"test\\n\")\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_textsize_stroke():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 20)\n\n    # Act / Assert\n    assert draw.textsize(\"A\", font, stroke_width=2) == (16, 20)\n    assert draw.multiline_textsize(\"ABC\\nAaaa\", font, stroke_width=2) == (52, 44)\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke():\n    for suffix, stroke_fill in {\"same\": None, \"different\": \"#0f0\"}.items():\n        # Arrange\n        im = Image.new(\"RGB\", (120, 130))\n        draw = ImageDraw.Draw(im)\n        font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n        # Act\n        draw.text((10, 10), \"A\", \"#f00\", font, stroke_width=2, stroke_fill=stroke_fill)\n\n        # Assert\n        assert_image_similar(\n            im, Image.open(\"Tests/images/imagedraw_stroke_\" + suffix + \".png\"), 3.1\n        )\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke_descender():\n    # Arrange\n    im = Image.new(\"RGB\", (120, 130))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n    # Act\n    draw.text((10, 0), \"y\", \"#f00\", font, stroke_width=2, stroke_fill=\"#0f0\")\n\n    # Assert\n    assert_image_similar(\n        im, Image.open(\"Tests/images/imagedraw_stroke_descender.png\"), 6.76\n    )\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke_multiline():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 250))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n    # Act\n    draw.multiline_text(\n        (10, 10), \"A\\nB\", \"#f00\", font, stroke_width=2, stroke_fill=\"#0f0\"\n    )\n\n    # Assert\n    assert_image_similar(\n        im, Image.open(\"Tests/images/imagedraw_stroke_multiline.png\"), 3.3\n    )\n\n\ndef test_same_color_outline():\n    # Prepare shape\n    x0, y0 = 5, 5\n    x1, y1 = 5, 50\n    x2, y2 = 95, 50\n    x3, y3 = 95, 5\n\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    # Begin\n    for mode in [\"RGB\", \"L\"]:\n        for fill, outline in [[\"red\", None], [\"red\", \"red\"], [\"red\", \"#f00\"]]:\n            for operation, args in {\n                \"chord\": [BBOX1, 0, 180],\n                \"ellipse\": [BBOX1],\n                \"shape\": [s],\n                \"pieslice\": [BBOX1, -90, 45],\n                \"polygon\": [[(18, 30), (85, 30), (60, 72)]],\n                \"rectangle\": [BBOX1],\n            }.items():\n                # Arrange\n                im = Image.new(mode, (W, H))\n                draw = ImageDraw.Draw(im)\n\n                # Act\n                draw_method = getattr(draw, operation)\n                args += [fill, outline]\n                draw_method(*args)\n\n                # Assert\n                expected = \"Tests/images/imagedraw_outline_{}_{}.png\".format(\n                    operation, mode\n                )\n                assert_image_similar(im, Image.open(expected), 1)\n",
            "new_file_content": "import os.path\n\nimport pytest\nfrom PIL import Image, ImageColor, ImageDraw, ImageFont\n\nfrom .helper import (\n    assert_image_equal,\n    assert_image_similar,\n    hopper,\n    skip_unless_feature,\n)\n\nBLACK = (0, 0, 0)\nWHITE = (255, 255, 255)\nGRAY = (190, 190, 190)\nDEFAULT_MODE = \"RGB\"\nIMAGES_PATH = os.path.join(\"Tests\", \"images\", \"imagedraw\")\n\n# Image size\nW, H = 100, 100\n\n# Bounding box points\nX0 = int(W / 4)\nX1 = int(X0 * 3)\nY0 = int(H / 4)\nY1 = int(X0 * 3)\n\n# Two kinds of bounding box\nBBOX1 = [(X0, Y0), (X1, Y1)]\nBBOX2 = [X0, Y0, X1, Y1]\n\n# Two kinds of coordinate sequences\nPOINTS1 = [(10, 10), (20, 40), (30, 30)]\nPOINTS2 = [10, 10, 20, 40, 30, 30]\n\nKITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)]\n\n\ndef test_sanity():\n    im = hopper(\"RGB\").copy()\n\n    draw = ImageDraw.ImageDraw(im)\n    draw = ImageDraw.Draw(im)\n\n    draw.ellipse(list(range(4)))\n    draw.line(list(range(10)))\n    draw.polygon(list(range(100)))\n    draw.rectangle(list(range(4)))\n\n\ndef test_valueerror():\n    with Image.open(\"Tests/images/chi.gif\") as im:\n\n        draw = ImageDraw.Draw(im)\n        draw.line((0, 0), fill=(0, 0, 0))\n\n\ndef test_mode_mismatch():\n    im = hopper(\"RGB\").copy()\n\n    with pytest.raises(ValueError):\n        ImageDraw.ImageDraw(im, mode=\"L\")\n\n\ndef helper_arc(bbox, start, end):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.arc(bbox, start, end)\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_arc.png\"), 1)\n\n\ndef test_arc1():\n    helper_arc(BBOX1, 0, 180)\n    helper_arc(BBOX1, 0.5, 180.4)\n\n\ndef test_arc2():\n    helper_arc(BBOX2, 0, 180)\n    helper_arc(BBOX2, 0.5, 180.4)\n\n\ndef test_arc_end_le_start():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    start = 270.5\n    end = 0\n\n    # Act\n    draw.arc(BBOX1, start=start, end=end)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_arc_end_le_start.png\"))\n\n\ndef test_arc_no_loops():\n    # No need to go in loops\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    start = 5\n    end = 370\n\n    # Act\n    draw.arc(BBOX1, start=start, end=end)\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_arc_no_loops.png\"), 1)\n\n\ndef test_arc_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_pieslice_large():\n    # Tests an arc with a large enough width that it is a pieslice\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_pieslice.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, fill=\"yellow\", width=100)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_fill.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, fill=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_non_whole_angle():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_non_whole_angle.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 259.5, width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_bitmap():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    with Image.open(\"Tests/images/pil123rgba.png\") as small:\n        small = small.resize((50, 50), Image.NEAREST)\n\n        # Act\n        draw.bitmap((10, 10), small)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_bitmap.png\"))\n\n\ndef helper_chord(mode, bbox, start, end):\n    # Arrange\n    im = Image.new(mode, (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_{}.png\".format(mode)\n\n    # Act\n    draw.chord(bbox, start, end, fill=\"red\", outline=\"yellow\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord1():\n    for mode in [\"RGB\", \"L\"]:\n        helper_chord(mode, BBOX1, 0, 180)\n        helper_chord(mode, BBOX1, 0.5, 180.4)\n\n\ndef test_chord2():\n    for mode in [\"RGB\", \"L\"]:\n        helper_chord(mode, BBOX2, 0, 180)\n        helper_chord(mode, BBOX2, 0.5, 180.4)\n\n\ndef test_chord_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_width.png\"\n\n    # Act\n    draw.chord(BBOX1, 10, 260, outline=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_width_fill.png\"\n\n    # Act\n    draw.chord(BBOX1, 10, 260, fill=\"red\", outline=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.chord(BBOX1, 10, 260, fill=\"red\", outline=\"yellow\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_chord_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_ellipse(mode, bbox):\n    # Arrange\n    im = Image.new(mode, (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_{}.png\".format(mode)\n\n    # Act\n    draw.ellipse(bbox, fill=\"green\", outline=\"blue\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse1():\n    for mode in [\"RGB\", \"L\"]:\n        helper_ellipse(mode, BBOX1)\n\n\ndef test_ellipse2():\n    for mode in [\"RGB\", \"L\"]:\n        helper_ellipse(mode, BBOX2)\n\n\ndef test_ellipse_translucent():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im, \"RGBA\")\n\n    # Act\n    draw.ellipse(BBOX1, fill=(0, 255, 0, 127))\n\n    # Assert\n    expected = Image.open(\"Tests/images/imagedraw_ellipse_translucent.png\")\n    assert_image_similar(im, expected, 1)\n\n\ndef test_ellipse_edge():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.ellipse(((0, 0), (W - 1, H)), fill=\"white\")\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_ellipse_edge.png\"), 1)\n\n\ndef test_ellipse_symmetric():\n    for bbox in [(25, 25, 76, 76), (25, 25, 75, 75)]:\n        im = Image.new(\"RGB\", (101, 101))\n        draw = ImageDraw.Draw(im)\n        draw.ellipse(bbox, fill=\"green\", outline=\"blue\")\n        assert_image_equal(im, im.transpose(Image.FLIP_LEFT_RIGHT))\n\n\ndef test_ellipse_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width.png\"\n\n    # Act\n    draw.ellipse(BBOX1, outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_width_large():\n    # Arrange\n    im = Image.new(\"RGB\", (500, 500))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width_large.png\"\n\n    # Act\n    draw.ellipse((25, 25, 475, 475), outline=\"blue\", width=75)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width_fill.png\"\n\n    # Act\n    draw.ellipse(BBOX1, fill=\"green\", outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.ellipse(BBOX1, fill=\"green\", outline=\"blue\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_ellipse_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_line(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.line(points, fill=\"yellow\", width=2)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_line.png\"))\n\n\ndef test_line1():\n    helper_line(POINTS1)\n\n\ndef test_line2():\n    helper_line(POINTS2)\n\n\ndef test_shape1():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 100), \"white\")\n    draw = ImageDraw.Draw(im)\n    x0, y0 = 5, 5\n    x1, y1 = 5, 50\n    x2, y2 = 95, 50\n    x3, y3 = 95, 5\n\n    # Act\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    draw.shape(s, fill=1)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_shape1.png\"))\n\n\ndef test_shape2():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 100), \"white\")\n    draw = ImageDraw.Draw(im)\n    x0, y0 = 95, 95\n    x1, y1 = 95, 50\n    x2, y2 = 5, 50\n    x3, y3 = 5, 95\n\n    # Act\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    draw.shape(s, outline=\"blue\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_shape2.png\"))\n\n\ndef helper_pieslice(bbox, start, end):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.pieslice(bbox, start, end, fill=\"white\", outline=\"blue\")\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_pieslice.png\"), 1)\n\n\ndef test_pieslice1():\n    helper_pieslice(BBOX1, -90, 45)\n    helper_pieslice(BBOX1, -90.5, 45.4)\n\n\ndef test_pieslice2():\n    helper_pieslice(BBOX2, -90, 45)\n    helper_pieslice(BBOX2, -90.5, 45.4)\n\n\ndef test_pieslice_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_pieslice_width.png\"\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_pieslice_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_pieslice_width_fill.png\"\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, fill=\"white\", outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_pieslice_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, fill=\"white\", outline=\"blue\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_pieslice_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_point(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.point(points, fill=\"yellow\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_point.png\"))\n\n\ndef test_point1():\n    helper_point(POINTS1)\n\n\ndef test_point2():\n    helper_point(POINTS2)\n\n\ndef helper_polygon(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.polygon(points, fill=\"red\", outline=\"blue\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_polygon.png\"))\n\n\ndef test_polygon1():\n    helper_polygon(POINTS1)\n\n\ndef test_polygon2():\n    helper_polygon(POINTS2)\n\n\ndef test_polygon_kite():\n    # Test drawing lines of different gradients (dx>dy, dy>dx) and\n    # vertical (dx==0) and horizontal (dy==0) lines\n    for mode in [\"RGB\", \"L\"]:\n        # Arrange\n        im = Image.new(mode, (W, H))\n        draw = ImageDraw.Draw(im)\n        expected = \"Tests/images/imagedraw_polygon_kite_{}.png\".format(mode)\n\n        # Act\n        draw.polygon(KITE_POINTS, fill=\"blue\", outline=\"yellow\")\n\n        # Assert\n        assert_image_equal(im, Image.open(expected))\n\n\ndef helper_rectangle(bbox):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(bbox, fill=\"black\", outline=\"green\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_rectangle.png\"))\n\n\ndef test_rectangle1():\n    helper_rectangle(BBOX1)\n\n\ndef test_rectangle2():\n    helper_rectangle(BBOX2)\n\n\ndef test_big_rectangle():\n    # Test drawing a rectangle bigger than the image\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    bbox = [(-1, -1), (W + 1, H + 1)]\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_big_rectangle.png\"\n\n    # Act\n    draw.rectangle(bbox, fill=\"orange\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_rectangle_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_rectangle_width.png\"\n\n    # Act\n    draw.rectangle(BBOX1, outline=\"green\", width=5)\n\n    # Assert\n    assert_image_equal(im, Image.open(expected))\n\n\ndef test_rectangle_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_rectangle_width_fill.png\"\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"blue\", outline=\"green\", width=5)\n\n    # Assert\n    assert_image_equal(im, Image.open(expected))\n\n\ndef test_rectangle_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"blue\", outline=\"green\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_rectangle_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef test_rectangle_I16():\n    # Arrange\n    im = Image.new(\"I;16\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"black\", outline=\"green\")\n\n    # Assert\n    assert_image_equal(\n        im.convert(\"I\"), Image.open(\"Tests/images/imagedraw_rectangle_I.png\")\n    )\n\n\ndef test_floodfill():\n    red = ImageColor.getrgb(\"red\")\n\n    for mode, value in [(\"L\", 1), (\"RGBA\", (255, 0, 0, 0)), (\"RGB\", red)]:\n        # Arrange\n        im = Image.new(mode, (W, H))\n        draw = ImageDraw.Draw(im)\n        draw.rectangle(BBOX2, outline=\"yellow\", fill=\"green\")\n        centre_point = (int(W / 2), int(H / 2))\n\n        # Act\n        ImageDraw.floodfill(im, centre_point, value)\n\n        # Assert\n        expected = \"Tests/images/imagedraw_floodfill_\" + mode + \".png\"\n        with Image.open(expected) as im_floodfill:\n            assert_image_equal(im, im_floodfill)\n\n    # Test that using the same colour does not change the image\n    ImageDraw.floodfill(im, centre_point, red)\n    assert_image_equal(im, im_floodfill)\n\n    # Test that filling outside the image does not change the image\n    ImageDraw.floodfill(im, (W, H), red)\n    assert_image_equal(im, im_floodfill)\n\n    # Test filling at the edge of an image\n    im = Image.new(\"RGB\", (1, 1))\n    ImageDraw.floodfill(im, (0, 0), red)\n    assert_image_equal(im, Image.new(\"RGB\", (1, 1), red))\n\n\ndef test_floodfill_border():\n    # floodfill() is experimental\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.rectangle(BBOX2, outline=\"yellow\", fill=\"green\")\n    centre_point = (int(W / 2), int(H / 2))\n\n    # Act\n    ImageDraw.floodfill(\n        im, centre_point, ImageColor.getrgb(\"red\"), border=ImageColor.getrgb(\"black\"),\n    )\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_floodfill2.png\"))\n\n\ndef test_floodfill_thresh():\n    # floodfill() is experimental\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.rectangle(BBOX2, outline=\"darkgreen\", fill=\"green\")\n    centre_point = (int(W / 2), int(H / 2))\n\n    # Act\n    ImageDraw.floodfill(im, centre_point, ImageColor.getrgb(\"red\"), thresh=30)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_floodfill2.png\"))\n\n\ndef test_floodfill_not_negative():\n    # floodfill() is experimental\n    # Test that floodfill does not extend into negative coordinates\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.line((W / 2, 0, W / 2, H / 2), fill=\"green\")\n    draw.line((0, H / 2, W / 2, H / 2), fill=\"green\")\n\n    # Act\n    ImageDraw.floodfill(im, (int(W / 4), int(H / 4)), ImageColor.getrgb(\"red\"))\n\n    # Assert\n    assert_image_equal(\n        im, Image.open(\"Tests/images/imagedraw_floodfill_not_negative.png\")\n    )\n\n\ndef create_base_image_draw(\n    size, mode=DEFAULT_MODE, background1=WHITE, background2=GRAY\n):\n    img = Image.new(mode, size, background1)\n    for x in range(0, size[0]):\n        for y in range(0, size[1]):\n            if (x + y) % 2 == 0:\n                img.putpixel((x, y), background2)\n    return img, ImageDraw.Draw(img)\n\n\ndef test_square():\n    with Image.open(os.path.join(IMAGES_PATH, \"square.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((10, 10))\n        draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK)\n        assert_image_equal(img, expected, \"square as normal polygon failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.polygon([(7, 7), (7, 2), (2, 2), (2, 7)], BLACK)\n        assert_image_equal(img, expected, \"square as inverted polygon failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.rectangle((2, 2, 7, 7), BLACK)\n        assert_image_equal(img, expected, \"square as normal rectangle failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.rectangle((7, 7, 2, 2), BLACK)\n        assert_image_equal(img, expected, \"square as inverted rectangle failed\")\n\n\ndef test_triangle_right():\n    with Image.open(os.path.join(IMAGES_PATH, \"triangle_right.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK)\n        assert_image_equal(img, expected, \"triangle right failed\")\n\n\ndef test_line_horizontal():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w2px_normal.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight horizontal normal 2px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w2px_inverted.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight horizontal inverted 2px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_horizontal_w3px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight horizontal normal 3px wide failed\"\n        )\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight horizontal inverted 3px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w101px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((200, 110))\n        draw.line((5, 55, 195, 55), BLACK, 101)\n        assert_image_equal(img, expected, \"line straight horizontal 101px wide failed\")\n\n\ndef test_line_h_s1_w2():\n    pytest.skip(\"failing\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_slope1px_w2px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 6), BLACK, 2)\n        assert_image_equal(img, expected, \"line horizontal 1px slope 2px wide failed\")\n\n\ndef test_line_vertical():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_w2px_normal.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 5, 14), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight vertical normal 2px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_w2px_inverted.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 5, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight vertical inverted 2px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_vertical_w3px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 5, 14), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight vertical normal 3px wide failed\"\n        )\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 5, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight vertical inverted 3px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_vertical_w101px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((110, 200))\n        draw.line((55, 5, 55, 195), BLACK, 101)\n        assert_image_equal(img, expected, \"line straight vertical 101px wide failed\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_slope1px_w2px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 6, 14), BLACK, 2)\n        assert_image_equal(img, expected, \"line vertical 1px slope 2px wide failed\")\n\n\ndef test_line_oblique_45():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_oblique_45_w3px_a.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 14), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 normal 3px wide A failed\")\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 14, 5, 5), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 inverted 3px wide A failed\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_oblique_45_w3px_b.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 14), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 normal 3px wide B failed\")\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 14, 5), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 inverted 3px wide B failed\")\n\n\ndef test_wide_line_dot():\n    # Test drawing a wide \"line\" from one point to another just draws a single point\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_wide_line_dot.png\"\n\n    # Act\n    draw.line([(50, 50), (50, 50)], width=3)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_line_joint():\n    for xy in [\n        [\n            (400, 280),\n            (380, 280),\n            (450, 280),\n            (440, 120),\n            (350, 200),\n            (310, 280),\n            (300, 280),\n            (250, 280),\n            (250, 200),\n            (150, 200),\n            (150, 260),\n            (50, 200),\n            (150, 50),\n            (250, 100),\n        ],\n        (\n            400,\n            280,\n            380,\n            280,\n            450,\n            280,\n            440,\n            120,\n            350,\n            200,\n            310,\n            280,\n            300,\n            280,\n            250,\n            280,\n            250,\n            200,\n            150,\n            200,\n            150,\n            260,\n            50,\n            200,\n            150,\n            50,\n            250,\n            100,\n        ),\n        [\n            400,\n            280,\n            380,\n            280,\n            450,\n            280,\n            440,\n            120,\n            350,\n            200,\n            310,\n            280,\n            300,\n            280,\n            250,\n            280,\n            250,\n            200,\n            150,\n            200,\n            150,\n            260,\n            50,\n            200,\n            150,\n            50,\n            250,\n            100,\n        ],\n    ]:\n        im = Image.new(\"RGB\", (500, 325))\n        draw = ImageDraw.Draw(im)\n        expected = \"Tests/images/imagedraw_line_joint_curve.png\"\n\n        # Act\n        draw.line(xy, GRAY, 50, \"curve\")\n\n        # Assert\n        assert_image_similar(im, Image.open(expected), 3)\n\n\ndef test_textsize_empty_string():\n    # https://github.com/python-pillow/Pillow/issues/2783\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    # Should not cause 'SystemError: <built-in method getsize of\n    # ImagingFont object at 0x...> returned NULL without setting an error'\n    draw.textsize(\"\")\n    draw.textsize(\"\\n\")\n    draw.textsize(\"test\\n\")\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_textsize_stroke():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 20)\n\n    # Act / Assert\n    assert draw.textsize(\"A\", font, stroke_width=2) == (16, 20)\n    assert draw.multiline_textsize(\"ABC\\nAaaa\", font, stroke_width=2) == (52, 44)\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke():\n    for suffix, stroke_fill in {\"same\": None, \"different\": \"#0f0\"}.items():\n        # Arrange\n        im = Image.new(\"RGB\", (120, 130))\n        draw = ImageDraw.Draw(im)\n        font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n        # Act\n        draw.text((10, 10), \"A\", \"#f00\", font, stroke_width=2, stroke_fill=stroke_fill)\n\n        # Assert\n        assert_image_similar(\n            im, Image.open(\"Tests/images/imagedraw_stroke_\" + suffix + \".png\"), 3.1\n        )\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke_descender():\n    # Arrange\n    im = Image.new(\"RGB\", (120, 130))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n    # Act\n    draw.text((10, 0), \"y\", \"#f00\", font, stroke_width=2, stroke_fill=\"#0f0\")\n\n    # Assert\n    assert_image_similar(\n        im, Image.open(\"Tests/images/imagedraw_stroke_descender.png\"), 6.76\n    )\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke_multiline():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 250))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n    # Act\n    draw.multiline_text(\n        (10, 10), \"A\\nB\", \"#f00\", font, stroke_width=2, stroke_fill=\"#0f0\"\n    )\n\n    # Assert\n    assert_image_similar(\n        im, Image.open(\"Tests/images/imagedraw_stroke_multiline.png\"), 3.3\n    )\n\n\ndef test_same_color_outline():\n    # Prepare shape\n    x0, y0 = 5, 5\n    x1, y1 = 5, 50\n    x2, y2 = 95, 50\n    x3, y3 = 95, 5\n\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    # Begin\n    for mode in [\"RGB\", \"L\"]:\n        for fill, outline in [[\"red\", None], [\"red\", \"red\"], [\"red\", \"#f00\"]]:\n            for operation, args in {\n                \"chord\": [BBOX1, 0, 180],\n                \"ellipse\": [BBOX1],\n                \"shape\": [s],\n                \"pieslice\": [BBOX1, -90, 45],\n                \"polygon\": [[(18, 30), (85, 30), (60, 72)]],\n                \"rectangle\": [BBOX1],\n            }.items():\n                # Arrange\n                im = Image.new(mode, (W, H))\n                draw = ImageDraw.Draw(im)\n\n                # Act\n                draw_method = getattr(draw, operation)\n                args += [fill, outline]\n                draw_method(*args)\n\n                # Assert\n                expected = \"Tests/images/imagedraw_outline_{}_{}.png\".format(\n                    operation, mode\n                )\n                assert_image_similar(im, Image.open(expected), 1)\n",
            "header": {
                "file": {
                    "path": "Tests/test_imagedraw.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "f6eabb21a",
                "new_commit_hash": "5aa9599ec",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_imagedraw.py"
            },
            "plus_file": {
                "path": "b/Tests/test_imagedraw.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 874,
                            "length": 31
                        },
                        "new_range": {
                            "start": 874,
                            "length": 93
                        },
                        "section": "def test_wide_line_dot():"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def test_line_joint():",
                                "type": "context"
                            },
                            {
                                "content": "    im = Image.new(\"RGB\", (500, 325))",
                                "type": "deleted"
                            },
                            {
                                "content": "    draw = ImageDraw.Draw(im)",
                                "type": "deleted"
                            },
                            {
                                "content": "    expected = \"Tests/images/imagedraw_line_joint_curve.png\"",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "    # Act",
                                "type": "deleted"
                            },
                            {
                                "content": "    xy = [",
                                "type": "deleted"
                            },
                            {
                                "content": "        (400, 280),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (380, 280),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (450, 280),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (440, 120),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (350, 200),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (310, 280),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (300, 280),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (250, 280),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (250, 200),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (150, 200),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (150, 260),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (50, 200),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (150, 50),",
                                "type": "deleted"
                            },
                            {
                                "content": "        (250, 100),",
                                "type": "deleted"
                            },
                            {
                                "content": "    ]",
                                "type": "deleted"
                            },
                            {
                                "content": "    draw.line(xy, GRAY, 50, \"curve\")",
                                "type": "deleted"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "    # Assert",
                                "type": "deleted"
                            },
                            {
                                "content": "    assert_image_similar(im, Image.open(expected), 3)",
                                "type": "deleted"
                            },
                            {
                                "content": "    for xy in [",
                                "type": "added"
                            },
                            {
                                "content": "        [",
                                "type": "added"
                            },
                            {
                                "content": "            (400, 280),",
                                "type": "added"
                            },
                            {
                                "content": "            (380, 280),",
                                "type": "added"
                            },
                            {
                                "content": "            (450, 280),",
                                "type": "added"
                            },
                            {
                                "content": "            (440, 120),",
                                "type": "added"
                            },
                            {
                                "content": "            (350, 200),",
                                "type": "added"
                            },
                            {
                                "content": "            (310, 280),",
                                "type": "added"
                            },
                            {
                                "content": "            (300, 280),",
                                "type": "added"
                            },
                            {
                                "content": "            (250, 280),",
                                "type": "added"
                            },
                            {
                                "content": "            (250, 200),",
                                "type": "added"
                            },
                            {
                                "content": "            (150, 200),",
                                "type": "added"
                            },
                            {
                                "content": "            (150, 260),",
                                "type": "added"
                            },
                            {
                                "content": "            (50, 200),",
                                "type": "added"
                            },
                            {
                                "content": "            (150, 50),",
                                "type": "added"
                            },
                            {
                                "content": "            (250, 100),",
                                "type": "added"
                            },
                            {
                                "content": "        ],",
                                "type": "added"
                            },
                            {
                                "content": "        (",
                                "type": "added"
                            },
                            {
                                "content": "            400,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            380,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            450,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            440,",
                                "type": "added"
                            },
                            {
                                "content": "            120,",
                                "type": "added"
                            },
                            {
                                "content": "            350,",
                                "type": "added"
                            },
                            {
                                "content": "            200,",
                                "type": "added"
                            },
                            {
                                "content": "            310,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            300,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            250,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            250,",
                                "type": "added"
                            },
                            {
                                "content": "            200,",
                                "type": "added"
                            },
                            {
                                "content": "            150,",
                                "type": "added"
                            },
                            {
                                "content": "            200,",
                                "type": "added"
                            },
                            {
                                "content": "            150,",
                                "type": "added"
                            },
                            {
                                "content": "            260,",
                                "type": "added"
                            },
                            {
                                "content": "            50,",
                                "type": "added"
                            },
                            {
                                "content": "            200,",
                                "type": "added"
                            },
                            {
                                "content": "            150,",
                                "type": "added"
                            },
                            {
                                "content": "            50,",
                                "type": "added"
                            },
                            {
                                "content": "            250,",
                                "type": "added"
                            },
                            {
                                "content": "            100,",
                                "type": "added"
                            },
                            {
                                "content": "        ),",
                                "type": "added"
                            },
                            {
                                "content": "        [",
                                "type": "added"
                            },
                            {
                                "content": "            400,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            380,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            450,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            440,",
                                "type": "added"
                            },
                            {
                                "content": "            120,",
                                "type": "added"
                            },
                            {
                                "content": "            350,",
                                "type": "added"
                            },
                            {
                                "content": "            200,",
                                "type": "added"
                            },
                            {
                                "content": "            310,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            300,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            250,",
                                "type": "added"
                            },
                            {
                                "content": "            280,",
                                "type": "added"
                            },
                            {
                                "content": "            250,",
                                "type": "added"
                            },
                            {
                                "content": "            200,",
                                "type": "added"
                            },
                            {
                                "content": "            150,",
                                "type": "added"
                            },
                            {
                                "content": "            200,",
                                "type": "added"
                            },
                            {
                                "content": "            150,",
                                "type": "added"
                            },
                            {
                                "content": "            260,",
                                "type": "added"
                            },
                            {
                                "content": "            50,",
                                "type": "added"
                            },
                            {
                                "content": "            200,",
                                "type": "added"
                            },
                            {
                                "content": "            150,",
                                "type": "added"
                            },
                            {
                                "content": "            50,",
                                "type": "added"
                            },
                            {
                                "content": "            250,",
                                "type": "added"
                            },
                            {
                                "content": "            100,",
                                "type": "added"
                            },
                            {
                                "content": "        ],",
                                "type": "added"
                            },
                            {
                                "content": "    ]:",
                                "type": "added"
                            },
                            {
                                "content": "        im = Image.new(\"RGB\", (500, 325))",
                                "type": "added"
                            },
                            {
                                "content": "        draw = ImageDraw.Draw(im)",
                                "type": "added"
                            },
                            {
                                "content": "        expected = \"Tests/images/imagedraw_line_joint_curve.png\"",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        # Act",
                                "type": "added"
                            },
                            {
                                "content": "        draw.line(xy, GRAY, 50, \"curve\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        # Assert",
                                "type": "added"
                            },
                            {
                                "content": "        assert_image_similar(im, Image.open(expected), 3)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def test_textsize_empty_string():",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_imagedraw.py",
                            "type": "function",
                            "name": "test_line_joint",
                            "content": "def test_line_joint():\n    im = Image.new(\"RGB\", (500, 325))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_line_joint_curve.png\"\n\n    # Act\n    xy = [\n        (400, 280),\n        (380, 280),\n        (450, 280),\n        (440, 120),\n        (350, 200),\n        (310, 280),\n        (300, 280),\n        (250, 280),\n        (250, 200),\n        (150, 200),\n        (150, 260),\n        (50, 200),\n        (150, 50),\n        (250, 100),\n    ]\n    draw.line(xy, GRAY, 50, \"curve\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 3)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 876,
                            "end_lineno": 901,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "#\n# The Python Imaging Library\n# $Id$\n#\n# drawing interface operations\n#\n# History:\n# 1996-04-13 fl   Created (experimental)\n# 1996-08-07 fl   Filled polygons, ellipses.\n# 1996-08-13 fl   Added text support\n# 1998-06-28 fl   Handle I and F images\n# 1998-12-29 fl   Added arc; use arc primitive to draw ellipses\n# 1999-01-10 fl   Added shape stuff (experimental)\n# 1999-02-06 fl   Added bitmap support\n# 1999-02-11 fl   Changed all primitives to take options\n# 1999-02-20 fl   Fixed backwards compatibility\n# 2000-10-12 fl   Copy on write, when necessary\n# 2001-02-18 fl   Use default ink for bitmap/text also in fill mode\n# 2002-10-24 fl   Added support for CSS-style color strings\n# 2002-12-10 fl   Added experimental support for RGBA-on-RGB drawing\n# 2002-12-11 fl   Refactored low-level drawing API (work in progress)\n# 2004-08-26 fl   Made Draw() a factory function, added getdraw() support\n# 2004-09-04 fl   Added width support to line primitive\n# 2004-09-10 fl   Added font mode handling\n# 2006-06-19 fl   Added font bearing support (getmask2)\n#\n# Copyright (c) 1997-2006 by Secret Labs AB\n# Copyright (c) 1996-2006 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\nimport math\nimport numbers\n\nfrom . import Image, ImageColor\n\n\n\"\"\"\nA simple 2D drawing interface for PIL images.\n<p>\nApplication code should use the <b>Draw</b> factory, instead of\ndirectly.\n\"\"\"\n\n\nclass ImageDraw:\n    def __init__(self, im, mode=None):\n        \"\"\"\n        Create a drawing instance.\n\n        :param im: The image to draw in.\n        :param mode: Optional mode to use for color values.  For RGB\n           images, this argument can be RGB or RGBA (to blend the\n           drawing into the image).  For all other modes, this argument\n           must be the same as the image mode.  If omitted, the mode\n           defaults to the mode of the image.\n        \"\"\"\n        im.load()\n        if im.readonly:\n            im._copy()  # make it writeable\n        blend = 0\n        if mode is None:\n            mode = im.mode\n        if mode != im.mode:\n            if mode == \"RGBA\" and im.mode == \"RGB\":\n                blend = 1\n            else:\n                raise ValueError(\"mode mismatch\")\n        if mode == \"P\":\n            self.palette = im.palette\n        else:\n            self.palette = None\n        self.im = im.im\n        self.draw = Image.core.draw(self.im, blend)\n        self.mode = mode\n        if mode in (\"I\", \"F\"):\n            self.ink = self.draw.draw_ink(1)\n        else:\n            self.ink = self.draw.draw_ink(-1)\n        if mode in (\"1\", \"P\", \"I\", \"F\"):\n            # FIXME: fix Fill2 to properly support matte for I+F images\n            self.fontmode = \"1\"\n        else:\n            self.fontmode = \"L\"  # aliasing is okay for other modes\n        self.fill = 0\n        self.font = None\n\n    def getfont(self):\n        \"\"\"\n        Get the current default font.\n\n        :returns: An image font.\"\"\"\n        if not self.font:\n            # FIXME: should add a font repository\n            from . import ImageFont\n\n            self.font = ImageFont.load_default()\n        return self.font\n\n    def _getink(self, ink, fill=None):\n        if ink is None and fill is None:\n            if self.fill:\n                fill = self.ink\n            else:\n                ink = self.ink\n        else:\n            if ink is not None:\n                if isinstance(ink, str):\n                    ink = ImageColor.getcolor(ink, self.mode)\n                if self.palette and not isinstance(ink, numbers.Number):\n                    ink = self.palette.getcolor(ink)\n                ink = self.draw.draw_ink(ink)\n            if fill is not None:\n                if isinstance(fill, str):\n                    fill = ImageColor.getcolor(fill, self.mode)\n                if self.palette and not isinstance(fill, numbers.Number):\n                    fill = self.palette.getcolor(fill)\n                fill = self.draw.draw_ink(fill)\n        return ink, fill\n\n    def arc(self, xy, start, end, fill=None, width=0):\n        \"\"\"Draw an arc.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_arc(xy, start, end, ink, width)\n\n    def bitmap(self, xy, bitmap, fill=None):\n        \"\"\"Draw a bitmap.\"\"\"\n        bitmap.load()\n        ink, fill = self._getink(fill)\n        if ink is None:\n            ink = fill\n        if ink is not None:\n            self.draw.draw_bitmap(xy, bitmap.im, ink)\n\n    def chord(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a chord.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_chord(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_chord(xy, start, end, ink, 0, width)\n\n    def ellipse(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw an ellipse.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_ellipse(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_ellipse(xy, ink, 0, width)\n\n    def line(self, xy, fill=None, width=0, joint=None):\n        \"\"\"Draw a line, or a connected sequence of line segments.\"\"\"\n        ink = self._getink(fill)[0]\n        if ink is not None:\n            self.draw.draw_lines(xy, ink, width)\n            if joint == \"curve\" and width > 4:\n                for i in range(1, len(xy) - 1):\n                    point = xy[i]\n                    angles = [\n                        math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))\n                        % 360\n                        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))\n                    ]\n                    if angles[0] == angles[1]:\n                        # This is a straight line, so no joint is required\n                        continue\n\n                    def coord_at_angle(coord, angle):\n                        x, y = coord\n                        angle -= 90\n                        distance = width / 2 - 1\n                        return tuple(\n                            [\n                                p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))\n                                for p, p_d in (\n                                    (x, distance * math.cos(math.radians(angle))),\n                                    (y, distance * math.sin(math.radians(angle))),\n                                )\n                            ]\n                        )\n\n                    flipped = (\n                        angles[1] > angles[0] and angles[1] - 180 > angles[0]\n                    ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])\n                    coords = [\n                        (point[0] - width / 2 + 1, point[1] - width / 2 + 1),\n                        (point[0] + width / 2 - 1, point[1] + width / 2 - 1),\n                    ]\n                    if flipped:\n                        start, end = (angles[1] + 90, angles[0] + 90)\n                    else:\n                        start, end = (angles[0] - 90, angles[1] - 90)\n                    self.pieslice(coords, start - 90, end - 90, fill)\n\n                    if width > 8:\n                        # Cover potential gaps between the line and the joint\n                        if flipped:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] + 90),\n                                point,\n                                coord_at_angle(point, angles[1] + 90),\n                            ]\n                        else:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] - 90),\n                                point,\n                                coord_at_angle(point, angles[1] - 90),\n                            ]\n                        self.line(gapCoords, fill, width=3)\n\n    def shape(self, shape, fill=None, outline=None):\n        \"\"\"(Experimental) Draw a shape.\"\"\"\n        shape.close()\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_outline(shape, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_outline(shape, ink, 0)\n\n    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a pieslice.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_pieslice(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_pieslice(xy, start, end, ink, 0, width)\n\n    def point(self, xy, fill=None):\n        \"\"\"Draw one or more individual pixels.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_points(xy, ink)\n\n    def polygon(self, xy, fill=None, outline=None):\n        \"\"\"Draw a polygon.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_polygon(xy, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_polygon(xy, ink, 0)\n\n    def rectangle(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw a rectangle.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_rectangle(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_rectangle(xy, ink, 0, width)\n\n    def _multiline_check(self, text):\n        \"\"\"Draw text.\"\"\"\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return split_character in text\n\n    def _multiline_split(self, text):\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return text.split(split_character)\n\n    def text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n        *args,\n        **kwargs\n    ):\n        if self._multiline_check(text):\n            return self.multiline_text(\n                xy,\n                text,\n                fill,\n                font,\n                anchor,\n                spacing,\n                align,\n                direction,\n                features,\n                language,\n                stroke_width,\n                stroke_fill,\n            )\n\n        if font is None:\n            font = self.getfont()\n\n        def getink(fill):\n            ink, fill = self._getink(fill)\n            if ink is None:\n                return fill\n            return ink\n\n        def draw_text(ink, stroke_width=0, stroke_offset=None):\n            coord = xy\n            try:\n                mask, offset = font.getmask2(\n                    text,\n                    self.fontmode,\n                    direction=direction,\n                    features=features,\n                    language=language,\n                    stroke_width=stroke_width,\n                    *args,\n                    **kwargs,\n                )\n                coord = coord[0] + offset[0], coord[1] + offset[1]\n            except AttributeError:\n                try:\n                    mask = font.getmask(\n                        text,\n                        self.fontmode,\n                        direction,\n                        features,\n                        language,\n                        stroke_width,\n                        *args,\n                        **kwargs,\n                    )\n                except TypeError:\n                    mask = font.getmask(text)\n            if stroke_offset:\n                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]\n            self.draw.draw_bitmap(coord, mask, ink)\n\n        ink = getink(fill)\n        if ink is not None:\n            stroke_ink = None\n            if stroke_width:\n                stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink\n\n            if stroke_ink is not None:\n                # Draw stroked text\n                draw_text(stroke_ink, stroke_width)\n\n                # Draw normal text\n                draw_text(ink, 0, (stroke_width, stroke_width))\n            else:\n                # Only draw normal text\n                draw_text(ink)\n\n    def multiline_text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n    ):\n        widths = []\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line,\n                font,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n            )\n            widths.append(line_width)\n            max_width = max(max_width, line_width)\n        left, top = xy\n        for idx, line in enumerate(lines):\n            if align == \"left\":\n                pass  # left = x\n            elif align == \"center\":\n                left += (max_width - widths[idx]) / 2.0\n            elif align == \"right\":\n                left += max_width - widths[idx]\n            else:\n                raise ValueError('align must be \"left\", \"center\" or \"right\"')\n            self.text(\n                (left, top),\n                line,\n                fill,\n                font,\n                anchor,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n                stroke_fill=stroke_fill,\n            )\n            top += line_spacing\n            left = xy[0]\n\n    def textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        \"\"\"Get the size of a given string, in pixels.\"\"\"\n        if self._multiline_check(text):\n            return self.multiline_textsize(\n                text, font, spacing, direction, features, language, stroke_width\n            )\n\n        if font is None:\n            font = self.getfont()\n        return font.getsize(text, direction, features, language, stroke_width)\n\n    def multiline_textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line, font, spacing, direction, features, language, stroke_width\n            )\n            max_width = max(max_width, line_width)\n        return max_width, len(lines) * line_spacing - spacing\n\n\ndef Draw(im, mode=None):\n    \"\"\"\n    A simple 2D drawing interface for PIL images.\n\n    :param im: The image to draw in.\n    :param mode: Optional mode to use for color values.  For RGB\n       images, this argument can be RGB or RGBA (to blend the\n       drawing into the image).  For all other modes, this argument\n       must be the same as the image mode.  If omitted, the mode\n       defaults to the mode of the image.\n    \"\"\"\n    try:\n        return im.getdraw(mode)\n    except AttributeError:\n        return ImageDraw(im, mode)\n\n\n# experimental access to the outline API\ntry:\n    Outline = Image.core.outline\nexcept AttributeError:\n    Outline = None\n\n\ndef getdraw(im=None, hints=None):\n    \"\"\"\n    (Experimental) A more advanced 2D drawing interface for PIL images,\n    based on the WCK interface.\n\n    :param im: The image to draw in.\n    :param hints: An optional list of hints.\n    :returns: A (drawing context, drawing resource factory) tuple.\n    \"\"\"\n    # FIXME: this needs more work!\n    # FIXME: come up with a better 'hints' scheme.\n    handler = None\n    if not hints or \"nicest\" in hints:\n        try:\n            from . import _imagingagg as handler\n        except ImportError:\n            pass\n    if handler is None:\n        from . import ImageDraw2 as handler\n    if im:\n        im = handler.Draw(im)\n    return im, handler\n\n\ndef floodfill(image, xy, value, border=None, thresh=0):\n    \"\"\"\n    (experimental) Fills a bounded region with a given color.\n\n    :param image: Target image.\n    :param xy: Seed position (a 2-item coordinate tuple). See\n        :ref:`coordinate-system`.\n    :param value: Fill color.\n    :param border: Optional border value.  If given, the region consists of\n        pixels with a color different from the border color.  If not given,\n        the region consists of pixels having the same color as the seed\n        pixel.\n    :param thresh: Optional threshold value which specifies a maximum\n        tolerable difference of a pixel value from the 'background' in\n        order for it to be replaced. Useful for filling regions of\n        non-homogeneous, but similar, colors.\n    \"\"\"\n    # based on an implementation by Eric S. Raymond\n    # amended by yo1995 @20180806\n    pixel = image.load()\n    x, y = xy\n    try:\n        background = pixel[x, y]\n        if _color_diff(value, background) <= thresh:\n            return  # seed point already has fill color\n        pixel[x, y] = value\n    except (ValueError, IndexError):\n        return  # seed point outside image\n    edge = {(x, y)}\n    # use a set to keep record of current and previous edge pixels\n    # to reduce memory consumption\n    full_edge = set()\n    while edge:\n        new_edge = set()\n        for (x, y) in edge:  # 4 adjacent method\n            for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):\n                # If already processed, or if a coordinate is negative, skip\n                if (s, t) in full_edge or s < 0 or t < 0:\n                    continue\n                try:\n                    p = pixel[s, t]\n                except (ValueError, IndexError):\n                    pass\n                else:\n                    full_edge.add((s, t))\n                    if border is None:\n                        fill = _color_diff(p, background) <= thresh\n                    else:\n                        fill = p != value and p != border\n                    if fill:\n                        pixel[s, t] = value\n                        new_edge.add((s, t))\n        full_edge = edge  # discard pixels processed\n        edge = new_edge\n\n\ndef _color_diff(color1, color2):\n    \"\"\"\n    Uses 1-norm distance to calculate difference between two values.\n    \"\"\"\n    if isinstance(color2, tuple):\n        return sum([abs(color1[i] - color2[i]) for i in range(0, len(color2))])\n    else:\n        return abs(color1 - color2)\n",
            "new_file_content": "#\n# The Python Imaging Library\n# $Id$\n#\n# drawing interface operations\n#\n# History:\n# 1996-04-13 fl   Created (experimental)\n# 1996-08-07 fl   Filled polygons, ellipses.\n# 1996-08-13 fl   Added text support\n# 1998-06-28 fl   Handle I and F images\n# 1998-12-29 fl   Added arc; use arc primitive to draw ellipses\n# 1999-01-10 fl   Added shape stuff (experimental)\n# 1999-02-06 fl   Added bitmap support\n# 1999-02-11 fl   Changed all primitives to take options\n# 1999-02-20 fl   Fixed backwards compatibility\n# 2000-10-12 fl   Copy on write, when necessary\n# 2001-02-18 fl   Use default ink for bitmap/text also in fill mode\n# 2002-10-24 fl   Added support for CSS-style color strings\n# 2002-12-10 fl   Added experimental support for RGBA-on-RGB drawing\n# 2002-12-11 fl   Refactored low-level drawing API (work in progress)\n# 2004-08-26 fl   Made Draw() a factory function, added getdraw() support\n# 2004-09-04 fl   Added width support to line primitive\n# 2004-09-10 fl   Added font mode handling\n# 2006-06-19 fl   Added font bearing support (getmask2)\n#\n# Copyright (c) 1997-2006 by Secret Labs AB\n# Copyright (c) 1996-2006 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\nimport math\nimport numbers\n\nfrom . import Image, ImageColor\n\n\n\"\"\"\nA simple 2D drawing interface for PIL images.\n<p>\nApplication code should use the <b>Draw</b> factory, instead of\ndirectly.\n\"\"\"\n\n\nclass ImageDraw:\n    def __init__(self, im, mode=None):\n        \"\"\"\n        Create a drawing instance.\n\n        :param im: The image to draw in.\n        :param mode: Optional mode to use for color values.  For RGB\n           images, this argument can be RGB or RGBA (to blend the\n           drawing into the image).  For all other modes, this argument\n           must be the same as the image mode.  If omitted, the mode\n           defaults to the mode of the image.\n        \"\"\"\n        im.load()\n        if im.readonly:\n            im._copy()  # make it writeable\n        blend = 0\n        if mode is None:\n            mode = im.mode\n        if mode != im.mode:\n            if mode == \"RGBA\" and im.mode == \"RGB\":\n                blend = 1\n            else:\n                raise ValueError(\"mode mismatch\")\n        if mode == \"P\":\n            self.palette = im.palette\n        else:\n            self.palette = None\n        self.im = im.im\n        self.draw = Image.core.draw(self.im, blend)\n        self.mode = mode\n        if mode in (\"I\", \"F\"):\n            self.ink = self.draw.draw_ink(1)\n        else:\n            self.ink = self.draw.draw_ink(-1)\n        if mode in (\"1\", \"P\", \"I\", \"F\"):\n            # FIXME: fix Fill2 to properly support matte for I+F images\n            self.fontmode = \"1\"\n        else:\n            self.fontmode = \"L\"  # aliasing is okay for other modes\n        self.fill = 0\n        self.font = None\n\n    def getfont(self):\n        \"\"\"\n        Get the current default font.\n\n        :returns: An image font.\"\"\"\n        if not self.font:\n            # FIXME: should add a font repository\n            from . import ImageFont\n\n            self.font = ImageFont.load_default()\n        return self.font\n\n    def _getink(self, ink, fill=None):\n        if ink is None and fill is None:\n            if self.fill:\n                fill = self.ink\n            else:\n                ink = self.ink\n        else:\n            if ink is not None:\n                if isinstance(ink, str):\n                    ink = ImageColor.getcolor(ink, self.mode)\n                if self.palette and not isinstance(ink, numbers.Number):\n                    ink = self.palette.getcolor(ink)\n                ink = self.draw.draw_ink(ink)\n            if fill is not None:\n                if isinstance(fill, str):\n                    fill = ImageColor.getcolor(fill, self.mode)\n                if self.palette and not isinstance(fill, numbers.Number):\n                    fill = self.palette.getcolor(fill)\n                fill = self.draw.draw_ink(fill)\n        return ink, fill\n\n    def arc(self, xy, start, end, fill=None, width=0):\n        \"\"\"Draw an arc.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_arc(xy, start, end, ink, width)\n\n    def bitmap(self, xy, bitmap, fill=None):\n        \"\"\"Draw a bitmap.\"\"\"\n        bitmap.load()\n        ink, fill = self._getink(fill)\n        if ink is None:\n            ink = fill\n        if ink is not None:\n            self.draw.draw_bitmap(xy, bitmap.im, ink)\n\n    def chord(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a chord.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_chord(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_chord(xy, start, end, ink, 0, width)\n\n    def ellipse(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw an ellipse.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_ellipse(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_ellipse(xy, ink, 0, width)\n\n    def line(self, xy, fill=None, width=0, joint=None):\n        \"\"\"Draw a line, or a connected sequence of line segments.\"\"\"\n        ink = self._getink(fill)[0]\n        if ink is not None:\n            self.draw.draw_lines(xy, ink, width)\n            if joint == \"curve\" and width > 4:\n                if not isinstance(xy[0], (list, tuple)):\n                    xy = [tuple(xy[i : i + 2]) for i in range(0, len(xy), 2)]\n                for i in range(1, len(xy) - 1):\n                    point = xy[i]\n                    angles = [\n                        math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))\n                        % 360\n                        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))\n                    ]\n                    if angles[0] == angles[1]:\n                        # This is a straight line, so no joint is required\n                        continue\n\n                    def coord_at_angle(coord, angle):\n                        x, y = coord\n                        angle -= 90\n                        distance = width / 2 - 1\n                        return tuple(\n                            [\n                                p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))\n                                for p, p_d in (\n                                    (x, distance * math.cos(math.radians(angle))),\n                                    (y, distance * math.sin(math.radians(angle))),\n                                )\n                            ]\n                        )\n\n                    flipped = (\n                        angles[1] > angles[0] and angles[1] - 180 > angles[0]\n                    ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])\n                    coords = [\n                        (point[0] - width / 2 + 1, point[1] - width / 2 + 1),\n                        (point[0] + width / 2 - 1, point[1] + width / 2 - 1),\n                    ]\n                    if flipped:\n                        start, end = (angles[1] + 90, angles[0] + 90)\n                    else:\n                        start, end = (angles[0] - 90, angles[1] - 90)\n                    self.pieslice(coords, start - 90, end - 90, fill)\n\n                    if width > 8:\n                        # Cover potential gaps between the line and the joint\n                        if flipped:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] + 90),\n                                point,\n                                coord_at_angle(point, angles[1] + 90),\n                            ]\n                        else:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] - 90),\n                                point,\n                                coord_at_angle(point, angles[1] - 90),\n                            ]\n                        self.line(gapCoords, fill, width=3)\n\n    def shape(self, shape, fill=None, outline=None):\n        \"\"\"(Experimental) Draw a shape.\"\"\"\n        shape.close()\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_outline(shape, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_outline(shape, ink, 0)\n\n    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a pieslice.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_pieslice(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_pieslice(xy, start, end, ink, 0, width)\n\n    def point(self, xy, fill=None):\n        \"\"\"Draw one or more individual pixels.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_points(xy, ink)\n\n    def polygon(self, xy, fill=None, outline=None):\n        \"\"\"Draw a polygon.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_polygon(xy, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_polygon(xy, ink, 0)\n\n    def rectangle(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw a rectangle.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_rectangle(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_rectangle(xy, ink, 0, width)\n\n    def _multiline_check(self, text):\n        \"\"\"Draw text.\"\"\"\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return split_character in text\n\n    def _multiline_split(self, text):\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return text.split(split_character)\n\n    def text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n        *args,\n        **kwargs\n    ):\n        if self._multiline_check(text):\n            return self.multiline_text(\n                xy,\n                text,\n                fill,\n                font,\n                anchor,\n                spacing,\n                align,\n                direction,\n                features,\n                language,\n                stroke_width,\n                stroke_fill,\n            )\n\n        if font is None:\n            font = self.getfont()\n\n        def getink(fill):\n            ink, fill = self._getink(fill)\n            if ink is None:\n                return fill\n            return ink\n\n        def draw_text(ink, stroke_width=0, stroke_offset=None):\n            coord = xy\n            try:\n                mask, offset = font.getmask2(\n                    text,\n                    self.fontmode,\n                    direction=direction,\n                    features=features,\n                    language=language,\n                    stroke_width=stroke_width,\n                    *args,\n                    **kwargs,\n                )\n                coord = coord[0] + offset[0], coord[1] + offset[1]\n            except AttributeError:\n                try:\n                    mask = font.getmask(\n                        text,\n                        self.fontmode,\n                        direction,\n                        features,\n                        language,\n                        stroke_width,\n                        *args,\n                        **kwargs,\n                    )\n                except TypeError:\n                    mask = font.getmask(text)\n            if stroke_offset:\n                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]\n            self.draw.draw_bitmap(coord, mask, ink)\n\n        ink = getink(fill)\n        if ink is not None:\n            stroke_ink = None\n            if stroke_width:\n                stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink\n\n            if stroke_ink is not None:\n                # Draw stroked text\n                draw_text(stroke_ink, stroke_width)\n\n                # Draw normal text\n                draw_text(ink, 0, (stroke_width, stroke_width))\n            else:\n                # Only draw normal text\n                draw_text(ink)\n\n    def multiline_text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n    ):\n        widths = []\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line,\n                font,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n            )\n            widths.append(line_width)\n            max_width = max(max_width, line_width)\n        left, top = xy\n        for idx, line in enumerate(lines):\n            if align == \"left\":\n                pass  # left = x\n            elif align == \"center\":\n                left += (max_width - widths[idx]) / 2.0\n            elif align == \"right\":\n                left += max_width - widths[idx]\n            else:\n                raise ValueError('align must be \"left\", \"center\" or \"right\"')\n            self.text(\n                (left, top),\n                line,\n                fill,\n                font,\n                anchor,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n                stroke_fill=stroke_fill,\n            )\n            top += line_spacing\n            left = xy[0]\n\n    def textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        \"\"\"Get the size of a given string, in pixels.\"\"\"\n        if self._multiline_check(text):\n            return self.multiline_textsize(\n                text, font, spacing, direction, features, language, stroke_width\n            )\n\n        if font is None:\n            font = self.getfont()\n        return font.getsize(text, direction, features, language, stroke_width)\n\n    def multiline_textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line, font, spacing, direction, features, language, stroke_width\n            )\n            max_width = max(max_width, line_width)\n        return max_width, len(lines) * line_spacing - spacing\n\n\ndef Draw(im, mode=None):\n    \"\"\"\n    A simple 2D drawing interface for PIL images.\n\n    :param im: The image to draw in.\n    :param mode: Optional mode to use for color values.  For RGB\n       images, this argument can be RGB or RGBA (to blend the\n       drawing into the image).  For all other modes, this argument\n       must be the same as the image mode.  If omitted, the mode\n       defaults to the mode of the image.\n    \"\"\"\n    try:\n        return im.getdraw(mode)\n    except AttributeError:\n        return ImageDraw(im, mode)\n\n\n# experimental access to the outline API\ntry:\n    Outline = Image.core.outline\nexcept AttributeError:\n    Outline = None\n\n\ndef getdraw(im=None, hints=None):\n    \"\"\"\n    (Experimental) A more advanced 2D drawing interface for PIL images,\n    based on the WCK interface.\n\n    :param im: The image to draw in.\n    :param hints: An optional list of hints.\n    :returns: A (drawing context, drawing resource factory) tuple.\n    \"\"\"\n    # FIXME: this needs more work!\n    # FIXME: come up with a better 'hints' scheme.\n    handler = None\n    if not hints or \"nicest\" in hints:\n        try:\n            from . import _imagingagg as handler\n        except ImportError:\n            pass\n    if handler is None:\n        from . import ImageDraw2 as handler\n    if im:\n        im = handler.Draw(im)\n    return im, handler\n\n\ndef floodfill(image, xy, value, border=None, thresh=0):\n    \"\"\"\n    (experimental) Fills a bounded region with a given color.\n\n    :param image: Target image.\n    :param xy: Seed position (a 2-item coordinate tuple). See\n        :ref:`coordinate-system`.\n    :param value: Fill color.\n    :param border: Optional border value.  If given, the region consists of\n        pixels with a color different from the border color.  If not given,\n        the region consists of pixels having the same color as the seed\n        pixel.\n    :param thresh: Optional threshold value which specifies a maximum\n        tolerable difference of a pixel value from the 'background' in\n        order for it to be replaced. Useful for filling regions of\n        non-homogeneous, but similar, colors.\n    \"\"\"\n    # based on an implementation by Eric S. Raymond\n    # amended by yo1995 @20180806\n    pixel = image.load()\n    x, y = xy\n    try:\n        background = pixel[x, y]\n        if _color_diff(value, background) <= thresh:\n            return  # seed point already has fill color\n        pixel[x, y] = value\n    except (ValueError, IndexError):\n        return  # seed point outside image\n    edge = {(x, y)}\n    # use a set to keep record of current and previous edge pixels\n    # to reduce memory consumption\n    full_edge = set()\n    while edge:\n        new_edge = set()\n        for (x, y) in edge:  # 4 adjacent method\n            for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):\n                # If already processed, or if a coordinate is negative, skip\n                if (s, t) in full_edge or s < 0 or t < 0:\n                    continue\n                try:\n                    p = pixel[s, t]\n                except (ValueError, IndexError):\n                    pass\n                else:\n                    full_edge.add((s, t))\n                    if border is None:\n                        fill = _color_diff(p, background) <= thresh\n                    else:\n                        fill = p != value and p != border\n                    if fill:\n                        pixel[s, t] = value\n                        new_edge.add((s, t))\n        full_edge = edge  # discard pixels processed\n        edge = new_edge\n\n\ndef _color_diff(color1, color2):\n    \"\"\"\n    Uses 1-norm distance to calculate difference between two values.\n    \"\"\"\n    if isinstance(color2, tuple):\n        return sum([abs(color1[i] - color2[i]) for i in range(0, len(color2))])\n    else:\n        return abs(color1 - color2)\n",
            "header": {
                "file": {
                    "path": "src/PIL/ImageDraw.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "7abd459f9",
                "new_commit_hash": "cbecf652d",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/ImageDraw.py"
            },
            "plus_file": {
                "path": "b/src/PIL/ImageDraw.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 156,
                            "length": 6
                        },
                        "new_range": {
                            "start": 156,
                            "length": 8
                        },
                        "section": "class ImageDraw:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        if ink is not None:",
                                "type": "context"
                            },
                            {
                                "content": "            self.draw.draw_lines(xy, ink, width)",
                                "type": "context"
                            },
                            {
                                "content": "            if joint == \"curve\" and width > 4:",
                                "type": "context"
                            },
                            {
                                "content": "                if not isinstance(xy[0], (list, tuple)):",
                                "type": "added"
                            },
                            {
                                "content": "                    xy = [tuple(xy[i : i + 2]) for i in range(0, len(xy), 2)]",
                                "type": "added"
                            },
                            {
                                "content": "                for i in range(1, len(xy) - 1):",
                                "type": "context"
                            },
                            {
                                "content": "                    point = xy[i]",
                                "type": "context"
                            },
                            {
                                "content": "                    angles = [",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/ImageDraw.py",
                            "type": "method",
                            "name": "ImageDraw.line",
                            "content": "class ImageDraw:\n    def __init__(self, im, mode=None):\n        \"\"\"\n        Create a drawing instance.\n\n        :param im: The image to draw in.\n        :param mode: Optional mode to use for color values.  For RGB\n           images, this argument can be RGB or RGBA (to blend the\n           drawing into the image).  For all other modes, this argument\n           must be the same as the image mode.  If omitted, the mode\n           defaults to the mode of the image.\n        \"\"\"\n        im.load()\n        if im.readonly:\n            im._copy()  # make it writeable\n        blend = 0\n        if mode is None:\n            mode = im.mode\n        if mode != im.mode:\n            if mode == \"RGBA\" and im.mode == \"RGB\":\n                blend = 1\n            else:\n                raise ValueError(\"mode mismatch\")\n        if mode == \"P\":\n            self.palette = im.palette\n        else:\n            self.palette = None\n        self.im = im.im\n        self.draw = Image.core.draw(self.im, blend)\n        self.mode = mode\n        if mode in (\"I\", \"F\"):\n            self.ink = self.draw.draw_ink(1)\n        else:\n            self.ink = self.draw.draw_ink(-1)\n        if mode in (\"1\", \"P\", \"I\", \"F\"):\n            # FIXME: fix Fill2 to properly support matte for I+F images\n            self.fontmode = \"1\"\n        else:\n            self.fontmode = \"L\"  # aliasing is okay for other modes\n        self.fill = 0\n        self.font = None\n\n    def getfont(self):\n        \"\"\"\n        Get the current default font.\n\n        :returns: An image font.\"\"\"\n        if not self.font:\n            # FIXME: should add a font repository\n            from . import ImageFont\n\n            self.font = ImageFont.load_default()\n        return self.font\n\n    def _getink(self, ink, fill=None):\n        if ink is None and fill is None:\n            if self.fill:\n                fill = self.ink\n            else:\n                ink = self.ink\n        else:\n            if ink is not None:\n                if isinstance(ink, str):\n                    ink = ImageColor.getcolor(ink, self.mode)\n                if self.palette and not isinstance(ink, numbers.Number):\n                    ink = self.palette.getcolor(ink)\n                ink = self.draw.draw_ink(ink)\n            if fill is not None:\n                if isinstance(fill, str):\n                    fill = ImageColor.getcolor(fill, self.mode)\n                if self.palette and not isinstance(fill, numbers.Number):\n                    fill = self.palette.getcolor(fill)\n                fill = self.draw.draw_ink(fill)\n        return ink, fill\n\n    def arc(self, xy, start, end, fill=None, width=0):\n        \"\"\"Draw an arc.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_arc(xy, start, end, ink, width)\n\n    def bitmap(self, xy, bitmap, fill=None):\n        \"\"\"Draw a bitmap.\"\"\"\n        bitmap.load()\n        ink, fill = self._getink(fill)\n        if ink is None:\n            ink = fill\n        if ink is not None:\n            self.draw.draw_bitmap(xy, bitmap.im, ink)\n\n    def chord(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a chord.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_chord(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_chord(xy, start, end, ink, 0, width)\n\n    def ellipse(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw an ellipse.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_ellipse(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_ellipse(xy, ink, 0, width)\n\n    def line(self, xy, fill=None, width=0, joint=None):\n        \"\"\"Draw a line, or a connected sequence of line segments.\"\"\"\n        ink = self._getink(fill)[0]\n        if ink is not None:\n            self.draw.draw_lines(xy, ink, width)\n            if joint == \"curve\" and width > 4:\n                if not isinstance(xy[0], (list, tuple)):\n                    xy = [tuple(xy[i : i + 2]) for i in range(0, len(xy), 2)]\n                for i in range(1, len(xy) - 1):\n                    point = xy[i]\n                    angles = [\n                        math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))\n                        % 360\n                        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))\n                    ]\n                    if angles[0] == angles[1]:\n                        # This is a straight line, so no joint is required\n                        continue\n\n                    def coord_at_angle(coord, angle):\n                        x, y = coord\n                        angle -= 90\n                        distance = width / 2 - 1\n                        return tuple(\n                            [\n                                p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))\n                                for p, p_d in (\n                                    (x, distance * math.cos(math.radians(angle))),\n                                    (y, distance * math.sin(math.radians(angle))),\n                                )\n                            ]\n                        )\n\n                    flipped = (\n                        angles[1] > angles[0] and angles[1] - 180 > angles[0]\n                    ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])\n                    coords = [\n                        (point[0] - width / 2 + 1, point[1] - width / 2 + 1),\n                        (point[0] + width / 2 - 1, point[1] + width / 2 - 1),\n                    ]\n                    if flipped:\n                        start, end = (angles[1] + 90, angles[0] + 90)\n                    else:\n                        start, end = (angles[0] - 90, angles[1] - 90)\n                    self.pieslice(coords, start - 90, end - 90, fill)\n\n                    if width > 8:\n                        # Cover potential gaps between the line and the joint\n                        if flipped:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] + 90),\n                                point,\n                                coord_at_angle(point, angles[1] + 90),\n                            ]\n                        else:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] - 90),\n                                point,\n                                coord_at_angle(point, angles[1] - 90),\n                            ]\n                        self.line(gapCoords, fill, width=3)\n\n    def shape(self, shape, fill=None, outline=None):\n        \"\"\"(Experimental) Draw a shape.\"\"\"\n        shape.close()\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_outline(shape, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_outline(shape, ink, 0)\n\n    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a pieslice.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_pieslice(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_pieslice(xy, start, end, ink, 0, width)\n\n    def point(self, xy, fill=None):\n        \"\"\"Draw one or more individual pixels.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_points(xy, ink)\n\n    def polygon(self, xy, fill=None, outline=None):\n        \"\"\"Draw a polygon.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_polygon(xy, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_polygon(xy, ink, 0)\n\n    def rectangle(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw a rectangle.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_rectangle(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_rectangle(xy, ink, 0, width)\n\n    def _multiline_check(self, text):\n        \"\"\"Draw text.\"\"\"\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return split_character in text\n\n    def _multiline_split(self, text):\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return text.split(split_character)\n\n    def text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n        *args,\n        **kwargs\n    ):\n        if self._multiline_check(text):\n            return self.multiline_text(\n                xy,\n                text,\n                fill,\n                font,\n                anchor,\n                spacing,\n                align,\n                direction,\n                features,\n                language,\n                stroke_width,\n                stroke_fill,\n            )\n\n        if font is None:\n            font = self.getfont()\n\n        def getink(fill):\n            ink, fill = self._getink(fill)\n            if ink is None:\n                return fill\n            return ink\n\n        def draw_text(ink, stroke_width=0, stroke_offset=None):\n            coord = xy\n            try:\n                mask, offset = font.getmask2(\n                    text,\n                    self.fontmode,\n                    direction=direction,\n                    features=features,\n                    language=language,\n                    stroke_width=stroke_width,\n                    *args,\n                    **kwargs,\n                )\n                coord = coord[0] + offset[0], coord[1] + offset[1]\n            except AttributeError:\n                try:\n                    mask = font.getmask(\n                        text,\n                        self.fontmode,\n                        direction,\n                        features,\n                        language,\n                        stroke_width,\n                        *args,\n                        **kwargs,\n                    )\n                except TypeError:\n                    mask = font.getmask(text)\n            if stroke_offset:\n                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]\n            self.draw.draw_bitmap(coord, mask, ink)\n\n        ink = getink(fill)\n        if ink is not None:\n            stroke_ink = None\n            if stroke_width:\n                stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink\n\n            if stroke_ink is not None:\n                # Draw stroked text\n                draw_text(stroke_ink, stroke_width)\n\n                # Draw normal text\n                draw_text(ink, 0, (stroke_width, stroke_width))\n            else:\n                # Only draw normal text\n                draw_text(ink)\n\n    def multiline_text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n    ):\n        widths = []\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line,\n                font,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n            )\n            widths.append(line_width)\n            max_width = max(max_width, line_width)\n        left, top = xy\n        for idx, line in enumerate(lines):\n            if align == \"left\":\n                pass  # left = x\n            elif align == \"center\":\n                left += (max_width - widths[idx]) / 2.0\n            elif align == \"right\":\n                left += max_width - widths[idx]\n            else:\n                raise ValueError('align must be \"left\", \"center\" or \"right\"')\n            self.text(\n                (left, top),\n                line,\n                fill,\n                font,\n                anchor,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n                stroke_fill=stroke_fill,\n            )\n            top += line_spacing\n            left = xy[0]\n\n    def textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        \"\"\"Get the size of a given string, in pixels.\"\"\"\n        if self._multiline_check(text):\n            return self.multiline_textsize(\n                text, font, spacing, direction, features, language, stroke_width\n            )\n\n        if font is None:\n            font = self.getfont()\n        return font.getsize(text, direction, features, language, stroke_width)\n\n    def multiline_textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line, font, spacing, direction, features, language, stroke_width\n            )\n            max_width = max(max_width, line_width)\n        return max_width, len(lines) * line_spacing - spacing",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 153,
                            "end_lineno": 213,
                            "parent": {
                                "file_name": "src/PIL/ImageDraw.py",
                                "type": "class",
                                "name": "ImageDraw",
                                "content": "class ImageDraw:\n    def __init__(self, im, mode=None):\n        \"\"\"\n        Create a drawing instance.\n\n        :param im: The image to draw in.\n        :param mode: Optional mode to use for color values.  For RGB\n           images, this argument can be RGB or RGBA (to blend the\n           drawing into the image).  For all other modes, this argument\n           must be the same as the image mode.  If omitted, the mode\n           defaults to the mode of the image.\n        \"\"\"\n        im.load()\n        if im.readonly:\n            im._copy()  # make it writeable\n        blend = 0\n        if mode is None:\n            mode = im.mode\n        if mode != im.mode:\n            if mode == \"RGBA\" and im.mode == \"RGB\":\n                blend = 1\n            else:\n                raise ValueError(\"mode mismatch\")\n        if mode == \"P\":\n            self.palette = im.palette\n        else:\n            self.palette = None\n        self.im = im.im\n        self.draw = Image.core.draw(self.im, blend)\n        self.mode = mode\n        if mode in (\"I\", \"F\"):\n            self.ink = self.draw.draw_ink(1)\n        else:\n            self.ink = self.draw.draw_ink(-1)\n        if mode in (\"1\", \"P\", \"I\", \"F\"):\n            # FIXME: fix Fill2 to properly support matte for I+F images\n            self.fontmode = \"1\"\n        else:\n            self.fontmode = \"L\"  # aliasing is okay for other modes\n        self.fill = 0\n        self.font = None\n\n    def getfont(self):\n        \"\"\"\n        Get the current default font.\n\n        :returns: An image font.\"\"\"\n        if not self.font:\n            # FIXME: should add a font repository\n            from . import ImageFont\n\n            self.font = ImageFont.load_default()\n        return self.font\n\n    def _getink(self, ink, fill=None):\n        if ink is None and fill is None:\n            if self.fill:\n                fill = self.ink\n            else:\n                ink = self.ink\n        else:\n            if ink is not None:\n                if isinstance(ink, str):\n                    ink = ImageColor.getcolor(ink, self.mode)\n                if self.palette and not isinstance(ink, numbers.Number):\n                    ink = self.palette.getcolor(ink)\n                ink = self.draw.draw_ink(ink)\n            if fill is not None:\n                if isinstance(fill, str):\n                    fill = ImageColor.getcolor(fill, self.mode)\n                if self.palette and not isinstance(fill, numbers.Number):\n                    fill = self.palette.getcolor(fill)\n                fill = self.draw.draw_ink(fill)\n        return ink, fill\n\n    def arc(self, xy, start, end, fill=None, width=0):\n        \"\"\"Draw an arc.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_arc(xy, start, end, ink, width)\n\n    def bitmap(self, xy, bitmap, fill=None):\n        \"\"\"Draw a bitmap.\"\"\"\n        bitmap.load()\n        ink, fill = self._getink(fill)\n        if ink is None:\n            ink = fill\n        if ink is not None:\n            self.draw.draw_bitmap(xy, bitmap.im, ink)\n\n    def chord(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a chord.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_chord(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_chord(xy, start, end, ink, 0, width)\n\n    def ellipse(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw an ellipse.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_ellipse(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_ellipse(xy, ink, 0, width)\n\n    def line(self, xy, fill=None, width=0, joint=None):\n        \"\"\"Draw a line, or a connected sequence of line segments.\"\"\"\n        ink = self._getink(fill)[0]\n        if ink is not None:\n            self.draw.draw_lines(xy, ink, width)\n            if joint == \"curve\" and width > 4:\n                if not isinstance(xy[0], (list, tuple)):\n                    xy = [tuple(xy[i : i + 2]) for i in range(0, len(xy), 2)]\n                for i in range(1, len(xy) - 1):\n                    point = xy[i]\n                    angles = [\n                        math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))\n                        % 360\n                        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))\n                    ]\n                    if angles[0] == angles[1]:\n                        # This is a straight line, so no joint is required\n                        continue\n\n                    def coord_at_angle(coord, angle):\n                        x, y = coord\n                        angle -= 90\n                        distance = width / 2 - 1\n                        return tuple(\n                            [\n                                p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))\n                                for p, p_d in (\n                                    (x, distance * math.cos(math.radians(angle))),\n                                    (y, distance * math.sin(math.radians(angle))),\n                                )\n                            ]\n                        )\n\n                    flipped = (\n                        angles[1] > angles[0] and angles[1] - 180 > angles[0]\n                    ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])\n                    coords = [\n                        (point[0] - width / 2 + 1, point[1] - width / 2 + 1),\n                        (point[0] + width / 2 - 1, point[1] + width / 2 - 1),\n                    ]\n                    if flipped:\n                        start, end = (angles[1] + 90, angles[0] + 90)\n                    else:\n                        start, end = (angles[0] - 90, angles[1] - 90)\n                    self.pieslice(coords, start - 90, end - 90, fill)\n\n                    if width > 8:\n                        # Cover potential gaps between the line and the joint\n                        if flipped:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] + 90),\n                                point,\n                                coord_at_angle(point, angles[1] + 90),\n                            ]\n                        else:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] - 90),\n                                point,\n                                coord_at_angle(point, angles[1] - 90),\n                            ]\n                        self.line(gapCoords, fill, width=3)\n\n    def shape(self, shape, fill=None, outline=None):\n        \"\"\"(Experimental) Draw a shape.\"\"\"\n        shape.close()\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_outline(shape, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_outline(shape, ink, 0)\n\n    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a pieslice.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_pieslice(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_pieslice(xy, start, end, ink, 0, width)\n\n    def point(self, xy, fill=None):\n        \"\"\"Draw one or more individual pixels.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_points(xy, ink)\n\n    def polygon(self, xy, fill=None, outline=None):\n        \"\"\"Draw a polygon.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_polygon(xy, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_polygon(xy, ink, 0)\n\n    def rectangle(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw a rectangle.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_rectangle(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_rectangle(xy, ink, 0, width)\n\n    def _multiline_check(self, text):\n        \"\"\"Draw text.\"\"\"\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return split_character in text\n\n    def _multiline_split(self, text):\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return text.split(split_character)\n\n    def text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n        *args,\n        **kwargs\n    ):\n        if self._multiline_check(text):\n            return self.multiline_text(\n                xy,\n                text,\n                fill,\n                font,\n                anchor,\n                spacing,\n                align,\n                direction,\n                features,\n                language,\n                stroke_width,\n                stroke_fill,\n            )\n\n        if font is None:\n            font = self.getfont()\n\n        def getink(fill):\n            ink, fill = self._getink(fill)\n            if ink is None:\n                return fill\n            return ink\n\n        def draw_text(ink, stroke_width=0, stroke_offset=None):\n            coord = xy\n            try:\n                mask, offset = font.getmask2(\n                    text,\n                    self.fontmode,\n                    direction=direction,\n                    features=features,\n                    language=language,\n                    stroke_width=stroke_width,\n                    *args,\n                    **kwargs,\n                )\n                coord = coord[0] + offset[0], coord[1] + offset[1]\n            except AttributeError:\n                try:\n                    mask = font.getmask(\n                        text,\n                        self.fontmode,\n                        direction,\n                        features,\n                        language,\n                        stroke_width,\n                        *args,\n                        **kwargs,\n                    )\n                except TypeError:\n                    mask = font.getmask(text)\n            if stroke_offset:\n                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]\n            self.draw.draw_bitmap(coord, mask, ink)\n\n        ink = getink(fill)\n        if ink is not None:\n            stroke_ink = None\n            if stroke_width:\n                stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink\n\n            if stroke_ink is not None:\n                # Draw stroked text\n                draw_text(stroke_ink, stroke_width)\n\n                # Draw normal text\n                draw_text(ink, 0, (stroke_width, stroke_width))\n            else:\n                # Only draw normal text\n                draw_text(ink)\n\n    def multiline_text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n    ):\n        widths = []\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line,\n                font,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n            )\n            widths.append(line_width)\n            max_width = max(max_width, line_width)\n        left, top = xy\n        for idx, line in enumerate(lines):\n            if align == \"left\":\n                pass  # left = x\n            elif align == \"center\":\n                left += (max_width - widths[idx]) / 2.0\n            elif align == \"right\":\n                left += max_width - widths[idx]\n            else:\n                raise ValueError('align must be \"left\", \"center\" or \"right\"')\n            self.text(\n                (left, top),\n                line,\n                fill,\n                font,\n                anchor,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n                stroke_fill=stroke_fill,\n            )\n            top += line_spacing\n            left = xy[0]\n\n    def textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        \"\"\"Get the size of a given string, in pixels.\"\"\"\n        if self._multiline_check(text):\n            return self.multiline_textsize(\n                text, font, spacing, direction, features, language, stroke_width\n            )\n\n        if font is None:\n            font = self.getfont()\n        return font.getsize(text, direction, features, language, stroke_width)\n\n    def multiline_textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line, font, spacing, direction, features, language, stroke_width\n            )\n            max_width = max(max_width, line_width)\n        return max_width, len(lines) * line_spacing - spacing",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 47,
                                "end_lineno": 452,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "src/PIL/ImageDraw.py",
                            "type": "class",
                            "name": "ImageDraw",
                            "content": "class ImageDraw:\n    def __init__(self, im, mode=None):\n        \"\"\"\n        Create a drawing instance.\n\n        :param im: The image to draw in.\n        :param mode: Optional mode to use for color values.  For RGB\n           images, this argument can be RGB or RGBA (to blend the\n           drawing into the image).  For all other modes, this argument\n           must be the same as the image mode.  If omitted, the mode\n           defaults to the mode of the image.\n        \"\"\"\n        im.load()\n        if im.readonly:\n            im._copy()  # make it writeable\n        blend = 0\n        if mode is None:\n            mode = im.mode\n        if mode != im.mode:\n            if mode == \"RGBA\" and im.mode == \"RGB\":\n                blend = 1\n            else:\n                raise ValueError(\"mode mismatch\")\n        if mode == \"P\":\n            self.palette = im.palette\n        else:\n            self.palette = None\n        self.im = im.im\n        self.draw = Image.core.draw(self.im, blend)\n        self.mode = mode\n        if mode in (\"I\", \"F\"):\n            self.ink = self.draw.draw_ink(1)\n        else:\n            self.ink = self.draw.draw_ink(-1)\n        if mode in (\"1\", \"P\", \"I\", \"F\"):\n            # FIXME: fix Fill2 to properly support matte for I+F images\n            self.fontmode = \"1\"\n        else:\n            self.fontmode = \"L\"  # aliasing is okay for other modes\n        self.fill = 0\n        self.font = None\n\n    def getfont(self):\n        \"\"\"\n        Get the current default font.\n\n        :returns: An image font.\"\"\"\n        if not self.font:\n            # FIXME: should add a font repository\n            from . import ImageFont\n\n            self.font = ImageFont.load_default()\n        return self.font\n\n    def _getink(self, ink, fill=None):\n        if ink is None and fill is None:\n            if self.fill:\n                fill = self.ink\n            else:\n                ink = self.ink\n        else:\n            if ink is not None:\n                if isinstance(ink, str):\n                    ink = ImageColor.getcolor(ink, self.mode)\n                if self.palette and not isinstance(ink, numbers.Number):\n                    ink = self.palette.getcolor(ink)\n                ink = self.draw.draw_ink(ink)\n            if fill is not None:\n                if isinstance(fill, str):\n                    fill = ImageColor.getcolor(fill, self.mode)\n                if self.palette and not isinstance(fill, numbers.Number):\n                    fill = self.palette.getcolor(fill)\n                fill = self.draw.draw_ink(fill)\n        return ink, fill\n\n    def arc(self, xy, start, end, fill=None, width=0):\n        \"\"\"Draw an arc.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_arc(xy, start, end, ink, width)\n\n    def bitmap(self, xy, bitmap, fill=None):\n        \"\"\"Draw a bitmap.\"\"\"\n        bitmap.load()\n        ink, fill = self._getink(fill)\n        if ink is None:\n            ink = fill\n        if ink is not None:\n            self.draw.draw_bitmap(xy, bitmap.im, ink)\n\n    def chord(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a chord.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_chord(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_chord(xy, start, end, ink, 0, width)\n\n    def ellipse(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw an ellipse.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_ellipse(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_ellipse(xy, ink, 0, width)\n\n    def line(self, xy, fill=None, width=0, joint=None):\n        \"\"\"Draw a line, or a connected sequence of line segments.\"\"\"\n        ink = self._getink(fill)[0]\n        if ink is not None:\n            self.draw.draw_lines(xy, ink, width)\n            if joint == \"curve\" and width > 4:\n                if not isinstance(xy[0], (list, tuple)):\n                    xy = [tuple(xy[i : i + 2]) for i in range(0, len(xy), 2)]\n                for i in range(1, len(xy) - 1):\n                    point = xy[i]\n                    angles = [\n                        math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))\n                        % 360\n                        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))\n                    ]\n                    if angles[0] == angles[1]:\n                        # This is a straight line, so no joint is required\n                        continue\n\n                    def coord_at_angle(coord, angle):\n                        x, y = coord\n                        angle -= 90\n                        distance = width / 2 - 1\n                        return tuple(\n                            [\n                                p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))\n                                for p, p_d in (\n                                    (x, distance * math.cos(math.radians(angle))),\n                                    (y, distance * math.sin(math.radians(angle))),\n                                )\n                            ]\n                        )\n\n                    flipped = (\n                        angles[1] > angles[0] and angles[1] - 180 > angles[0]\n                    ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])\n                    coords = [\n                        (point[0] - width / 2 + 1, point[1] - width / 2 + 1),\n                        (point[0] + width / 2 - 1, point[1] + width / 2 - 1),\n                    ]\n                    if flipped:\n                        start, end = (angles[1] + 90, angles[0] + 90)\n                    else:\n                        start, end = (angles[0] - 90, angles[1] - 90)\n                    self.pieslice(coords, start - 90, end - 90, fill)\n\n                    if width > 8:\n                        # Cover potential gaps between the line and the joint\n                        if flipped:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] + 90),\n                                point,\n                                coord_at_angle(point, angles[1] + 90),\n                            ]\n                        else:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] - 90),\n                                point,\n                                coord_at_angle(point, angles[1] - 90),\n                            ]\n                        self.line(gapCoords, fill, width=3)\n\n    def shape(self, shape, fill=None, outline=None):\n        \"\"\"(Experimental) Draw a shape.\"\"\"\n        shape.close()\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_outline(shape, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_outline(shape, ink, 0)\n\n    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a pieslice.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_pieslice(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_pieslice(xy, start, end, ink, 0, width)\n\n    def point(self, xy, fill=None):\n        \"\"\"Draw one or more individual pixels.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_points(xy, ink)\n\n    def polygon(self, xy, fill=None, outline=None):\n        \"\"\"Draw a polygon.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_polygon(xy, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_polygon(xy, ink, 0)\n\n    def rectangle(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw a rectangle.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_rectangle(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_rectangle(xy, ink, 0, width)\n\n    def _multiline_check(self, text):\n        \"\"\"Draw text.\"\"\"\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return split_character in text\n\n    def _multiline_split(self, text):\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return text.split(split_character)\n\n    def text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n        *args,\n        **kwargs\n    ):\n        if self._multiline_check(text):\n            return self.multiline_text(\n                xy,\n                text,\n                fill,\n                font,\n                anchor,\n                spacing,\n                align,\n                direction,\n                features,\n                language,\n                stroke_width,\n                stroke_fill,\n            )\n\n        if font is None:\n            font = self.getfont()\n\n        def getink(fill):\n            ink, fill = self._getink(fill)\n            if ink is None:\n                return fill\n            return ink\n\n        def draw_text(ink, stroke_width=0, stroke_offset=None):\n            coord = xy\n            try:\n                mask, offset = font.getmask2(\n                    text,\n                    self.fontmode,\n                    direction=direction,\n                    features=features,\n                    language=language,\n                    stroke_width=stroke_width,\n                    *args,\n                    **kwargs,\n                )\n                coord = coord[0] + offset[0], coord[1] + offset[1]\n            except AttributeError:\n                try:\n                    mask = font.getmask(\n                        text,\n                        self.fontmode,\n                        direction,\n                        features,\n                        language,\n                        stroke_width,\n                        *args,\n                        **kwargs,\n                    )\n                except TypeError:\n                    mask = font.getmask(text)\n            if stroke_offset:\n                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]\n            self.draw.draw_bitmap(coord, mask, ink)\n\n        ink = getink(fill)\n        if ink is not None:\n            stroke_ink = None\n            if stroke_width:\n                stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink\n\n            if stroke_ink is not None:\n                # Draw stroked text\n                draw_text(stroke_ink, stroke_width)\n\n                # Draw normal text\n                draw_text(ink, 0, (stroke_width, stroke_width))\n            else:\n                # Only draw normal text\n                draw_text(ink)\n\n    def multiline_text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n    ):\n        widths = []\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line,\n                font,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n            )\n            widths.append(line_width)\n            max_width = max(max_width, line_width)\n        left, top = xy\n        for idx, line in enumerate(lines):\n            if align == \"left\":\n                pass  # left = x\n            elif align == \"center\":\n                left += (max_width - widths[idx]) / 2.0\n            elif align == \"right\":\n                left += max_width - widths[idx]\n            else:\n                raise ValueError('align must be \"left\", \"center\" or \"right\"')\n            self.text(\n                (left, top),\n                line,\n                fill,\n                font,\n                anchor,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n                stroke_fill=stroke_fill,\n            )\n            top += line_spacing\n            left = xy[0]\n\n    def textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        \"\"\"Get the size of a given string, in pixels.\"\"\"\n        if self._multiline_check(text):\n            return self.multiline_textsize(\n                text, font, spacing, direction, features, language, stroke_width\n            )\n\n        if font is None:\n            font = self.getfont()\n        return font.getsize(text, direction, features, language, stroke_width)\n\n    def multiline_textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line, font, spacing, direction, features, language, stroke_width\n            )\n            max_width = max(max_width, line_width)\n        return max_width, len(lines) * line_spacing - spacing",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 47,
                            "end_lineno": 452,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "f5e9252b12890502f3c9b24d32941ab09e297523^",
    "new_commit_hash": "f5e9252b12890502f3c9b24d32941ab09e297523",
    "commit_message": "Fixed drawing a jointed line with a sequence of numeric values",
    "commit_date": "2020-04-24T18:48:10+10:00",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "f5e9252b12890502f3c9b24d32941ab09e297523",
    "test_file_codes": [
        "import os.path\n\nimport pytest\nfrom PIL import Image, ImageColor, ImageDraw, ImageFont\n\nfrom .helper import (\n    assert_image_equal,\n    assert_image_similar,\n    hopper,\n    skip_unless_feature,\n)\n\nBLACK = (0, 0, 0)\nWHITE = (255, 255, 255)\nGRAY = (190, 190, 190)\nDEFAULT_MODE = \"RGB\"\nIMAGES_PATH = os.path.join(\"Tests\", \"images\", \"imagedraw\")\n\n# Image size\nW, H = 100, 100\n\n# Bounding box points\nX0 = int(W / 4)\nX1 = int(X0 * 3)\nY0 = int(H / 4)\nY1 = int(X0 * 3)\n\n# Two kinds of bounding box\nBBOX1 = [(X0, Y0), (X1, Y1)]\nBBOX2 = [X0, Y0, X1, Y1]\n\n# Two kinds of coordinate sequences\nPOINTS1 = [(10, 10), (20, 40), (30, 30)]\nPOINTS2 = [10, 10, 20, 40, 30, 30]\n\nKITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)]\n\n\ndef test_sanity():\n    im = hopper(\"RGB\").copy()\n\n    draw = ImageDraw.ImageDraw(im)\n    draw = ImageDraw.Draw(im)\n\n    draw.ellipse(list(range(4)))\n    draw.line(list(range(10)))\n    draw.polygon(list(range(100)))\n    draw.rectangle(list(range(4)))\n\n\ndef test_valueerror():\n    with Image.open(\"Tests/images/chi.gif\") as im:\n\n        draw = ImageDraw.Draw(im)\n        draw.line((0, 0), fill=(0, 0, 0))\n\n\ndef test_mode_mismatch():\n    im = hopper(\"RGB\").copy()\n\n    with pytest.raises(ValueError):\n        ImageDraw.ImageDraw(im, mode=\"L\")\n\n\ndef helper_arc(bbox, start, end):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.arc(bbox, start, end)\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_arc.png\"), 1)\n\n\ndef test_arc1():\n    helper_arc(BBOX1, 0, 180)\n    helper_arc(BBOX1, 0.5, 180.4)\n\n\ndef test_arc2():\n    helper_arc(BBOX2, 0, 180)\n    helper_arc(BBOX2, 0.5, 180.4)\n\n\ndef test_arc_end_le_start():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    start = 270.5\n    end = 0\n\n    # Act\n    draw.arc(BBOX1, start=start, end=end)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_arc_end_le_start.png\"))\n\n\ndef test_arc_no_loops():\n    # No need to go in loops\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    start = 5\n    end = 370\n\n    # Act\n    draw.arc(BBOX1, start=start, end=end)\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_arc_no_loops.png\"), 1)\n\n\ndef test_arc_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_pieslice_large():\n    # Tests an arc with a large enough width that it is a pieslice\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_pieslice.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, fill=\"yellow\", width=100)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_fill.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 260, fill=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_arc_width_non_whole_angle():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_arc_width_non_whole_angle.png\"\n\n    # Act\n    draw.arc(BBOX1, 10, 259.5, width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_bitmap():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    with Image.open(\"Tests/images/pil123rgba.png\") as small:\n        small = small.resize((50, 50), Image.NEAREST)\n\n        # Act\n        draw.bitmap((10, 10), small)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_bitmap.png\"))\n\n\ndef helper_chord(mode, bbox, start, end):\n    # Arrange\n    im = Image.new(mode, (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_{}.png\".format(mode)\n\n    # Act\n    draw.chord(bbox, start, end, fill=\"red\", outline=\"yellow\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord1():\n    for mode in [\"RGB\", \"L\"]:\n        helper_chord(mode, BBOX1, 0, 180)\n        helper_chord(mode, BBOX1, 0.5, 180.4)\n\n\ndef test_chord2():\n    for mode in [\"RGB\", \"L\"]:\n        helper_chord(mode, BBOX2, 0, 180)\n        helper_chord(mode, BBOX2, 0.5, 180.4)\n\n\ndef test_chord_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_width.png\"\n\n    # Act\n    draw.chord(BBOX1, 10, 260, outline=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_chord_width_fill.png\"\n\n    # Act\n    draw.chord(BBOX1, 10, 260, fill=\"red\", outline=\"yellow\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_chord_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.chord(BBOX1, 10, 260, fill=\"red\", outline=\"yellow\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_chord_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_ellipse(mode, bbox):\n    # Arrange\n    im = Image.new(mode, (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_{}.png\".format(mode)\n\n    # Act\n    draw.ellipse(bbox, fill=\"green\", outline=\"blue\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse1():\n    for mode in [\"RGB\", \"L\"]:\n        helper_ellipse(mode, BBOX1)\n\n\ndef test_ellipse2():\n    for mode in [\"RGB\", \"L\"]:\n        helper_ellipse(mode, BBOX2)\n\n\ndef test_ellipse_translucent():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im, \"RGBA\")\n\n    # Act\n    draw.ellipse(BBOX1, fill=(0, 255, 0, 127))\n\n    # Assert\n    expected = Image.open(\"Tests/images/imagedraw_ellipse_translucent.png\")\n    assert_image_similar(im, expected, 1)\n\n\ndef test_ellipse_edge():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.ellipse(((0, 0), (W - 1, H)), fill=\"white\")\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_ellipse_edge.png\"), 1)\n\n\ndef test_ellipse_symmetric():\n    for bbox in [(25, 25, 76, 76), (25, 25, 75, 75)]:\n        im = Image.new(\"RGB\", (101, 101))\n        draw = ImageDraw.Draw(im)\n        draw.ellipse(bbox, fill=\"green\", outline=\"blue\")\n        assert_image_equal(im, im.transpose(Image.FLIP_LEFT_RIGHT))\n\n\ndef test_ellipse_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width.png\"\n\n    # Act\n    draw.ellipse(BBOX1, outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_width_large():\n    # Arrange\n    im = Image.new(\"RGB\", (500, 500))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width_large.png\"\n\n    # Act\n    draw.ellipse((25, 25, 475, 475), outline=\"blue\", width=75)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_ellipse_width_fill.png\"\n\n    # Act\n    draw.ellipse(BBOX1, fill=\"green\", outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_ellipse_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.ellipse(BBOX1, fill=\"green\", outline=\"blue\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_ellipse_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_line(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.line(points, fill=\"yellow\", width=2)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_line.png\"))\n\n\ndef test_line1():\n    helper_line(POINTS1)\n\n\ndef test_line2():\n    helper_line(POINTS2)\n\n\ndef test_shape1():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 100), \"white\")\n    draw = ImageDraw.Draw(im)\n    x0, y0 = 5, 5\n    x1, y1 = 5, 50\n    x2, y2 = 95, 50\n    x3, y3 = 95, 5\n\n    # Act\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    draw.shape(s, fill=1)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_shape1.png\"))\n\n\ndef test_shape2():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 100), \"white\")\n    draw = ImageDraw.Draw(im)\n    x0, y0 = 95, 95\n    x1, y1 = 95, 50\n    x2, y2 = 5, 50\n    x3, y3 = 5, 95\n\n    # Act\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    draw.shape(s, outline=\"blue\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_shape2.png\"))\n\n\ndef helper_pieslice(bbox, start, end):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.pieslice(bbox, start, end, fill=\"white\", outline=\"blue\")\n\n    # Assert\n    assert_image_similar(im, Image.open(\"Tests/images/imagedraw_pieslice.png\"), 1)\n\n\ndef test_pieslice1():\n    helper_pieslice(BBOX1, -90, 45)\n    helper_pieslice(BBOX1, -90.5, 45.4)\n\n\ndef test_pieslice2():\n    helper_pieslice(BBOX2, -90, 45)\n    helper_pieslice(BBOX2, -90.5, 45.4)\n\n\ndef test_pieslice_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_pieslice_width.png\"\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_pieslice_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_pieslice_width_fill.png\"\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, fill=\"white\", outline=\"blue\", width=5)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_pieslice_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.pieslice(BBOX1, 10, 260, fill=\"white\", outline=\"blue\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_pieslice_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef helper_point(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.point(points, fill=\"yellow\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_point.png\"))\n\n\ndef test_point1():\n    helper_point(POINTS1)\n\n\ndef test_point2():\n    helper_point(POINTS2)\n\n\ndef helper_polygon(points):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.polygon(points, fill=\"red\", outline=\"blue\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_polygon.png\"))\n\n\ndef test_polygon1():\n    helper_polygon(POINTS1)\n\n\ndef test_polygon2():\n    helper_polygon(POINTS2)\n\n\ndef test_polygon_kite():\n    # Test drawing lines of different gradients (dx>dy, dy>dx) and\n    # vertical (dx==0) and horizontal (dy==0) lines\n    for mode in [\"RGB\", \"L\"]:\n        # Arrange\n        im = Image.new(mode, (W, H))\n        draw = ImageDraw.Draw(im)\n        expected = \"Tests/images/imagedraw_polygon_kite_{}.png\".format(mode)\n\n        # Act\n        draw.polygon(KITE_POINTS, fill=\"blue\", outline=\"yellow\")\n\n        # Assert\n        assert_image_equal(im, Image.open(expected))\n\n\ndef helper_rectangle(bbox):\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(bbox, fill=\"black\", outline=\"green\")\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_rectangle.png\"))\n\n\ndef test_rectangle1():\n    helper_rectangle(BBOX1)\n\n\ndef test_rectangle2():\n    helper_rectangle(BBOX2)\n\n\ndef test_big_rectangle():\n    # Test drawing a rectangle bigger than the image\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    bbox = [(-1, -1), (W + 1, H + 1)]\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_big_rectangle.png\"\n\n    # Act\n    draw.rectangle(bbox, fill=\"orange\")\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_rectangle_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_rectangle_width.png\"\n\n    # Act\n    draw.rectangle(BBOX1, outline=\"green\", width=5)\n\n    # Assert\n    assert_image_equal(im, Image.open(expected))\n\n\ndef test_rectangle_width_fill():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_rectangle_width_fill.png\"\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"blue\", outline=\"green\", width=5)\n\n    # Assert\n    assert_image_equal(im, Image.open(expected))\n\n\ndef test_rectangle_zero_width():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"blue\", outline=\"green\", width=0)\n\n    # Assert\n    with Image.open(\"Tests/images/imagedraw_rectangle_zero_width.png\") as expected:\n        assert_image_equal(im, expected)\n\n\ndef test_rectangle_I16():\n    # Arrange\n    im = Image.new(\"I;16\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    draw.rectangle(BBOX1, fill=\"black\", outline=\"green\")\n\n    # Assert\n    assert_image_equal(\n        im.convert(\"I\"), Image.open(\"Tests/images/imagedraw_rectangle_I.png\")\n    )\n\n\ndef test_floodfill():\n    red = ImageColor.getrgb(\"red\")\n\n    for mode, value in [(\"L\", 1), (\"RGBA\", (255, 0, 0, 0)), (\"RGB\", red)]:\n        # Arrange\n        im = Image.new(mode, (W, H))\n        draw = ImageDraw.Draw(im)\n        draw.rectangle(BBOX2, outline=\"yellow\", fill=\"green\")\n        centre_point = (int(W / 2), int(H / 2))\n\n        # Act\n        ImageDraw.floodfill(im, centre_point, value)\n\n        # Assert\n        expected = \"Tests/images/imagedraw_floodfill_\" + mode + \".png\"\n        with Image.open(expected) as im_floodfill:\n            assert_image_equal(im, im_floodfill)\n\n    # Test that using the same colour does not change the image\n    ImageDraw.floodfill(im, centre_point, red)\n    assert_image_equal(im, im_floodfill)\n\n    # Test that filling outside the image does not change the image\n    ImageDraw.floodfill(im, (W, H), red)\n    assert_image_equal(im, im_floodfill)\n\n    # Test filling at the edge of an image\n    im = Image.new(\"RGB\", (1, 1))\n    ImageDraw.floodfill(im, (0, 0), red)\n    assert_image_equal(im, Image.new(\"RGB\", (1, 1), red))\n\n\ndef test_floodfill_border():\n    # floodfill() is experimental\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.rectangle(BBOX2, outline=\"yellow\", fill=\"green\")\n    centre_point = (int(W / 2), int(H / 2))\n\n    # Act\n    ImageDraw.floodfill(\n        im, centre_point, ImageColor.getrgb(\"red\"), border=ImageColor.getrgb(\"black\"),\n    )\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_floodfill2.png\"))\n\n\ndef test_floodfill_thresh():\n    # floodfill() is experimental\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.rectangle(BBOX2, outline=\"darkgreen\", fill=\"green\")\n    centre_point = (int(W / 2), int(H / 2))\n\n    # Act\n    ImageDraw.floodfill(im, centre_point, ImageColor.getrgb(\"red\"), thresh=30)\n\n    # Assert\n    assert_image_equal(im, Image.open(\"Tests/images/imagedraw_floodfill2.png\"))\n\n\ndef test_floodfill_not_negative():\n    # floodfill() is experimental\n    # Test that floodfill does not extend into negative coordinates\n\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    draw.line((W / 2, 0, W / 2, H / 2), fill=\"green\")\n    draw.line((0, H / 2, W / 2, H / 2), fill=\"green\")\n\n    # Act\n    ImageDraw.floodfill(im, (int(W / 4), int(H / 4)), ImageColor.getrgb(\"red\"))\n\n    # Assert\n    assert_image_equal(\n        im, Image.open(\"Tests/images/imagedraw_floodfill_not_negative.png\")\n    )\n\n\ndef create_base_image_draw(\n    size, mode=DEFAULT_MODE, background1=WHITE, background2=GRAY\n):\n    img = Image.new(mode, size, background1)\n    for x in range(0, size[0]):\n        for y in range(0, size[1]):\n            if (x + y) % 2 == 0:\n                img.putpixel((x, y), background2)\n    return img, ImageDraw.Draw(img)\n\n\ndef test_square():\n    with Image.open(os.path.join(IMAGES_PATH, \"square.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((10, 10))\n        draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK)\n        assert_image_equal(img, expected, \"square as normal polygon failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.polygon([(7, 7), (7, 2), (2, 2), (2, 7)], BLACK)\n        assert_image_equal(img, expected, \"square as inverted polygon failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.rectangle((2, 2, 7, 7), BLACK)\n        assert_image_equal(img, expected, \"square as normal rectangle failed\")\n        img, draw = create_base_image_draw((10, 10))\n        draw.rectangle((7, 7, 2, 2), BLACK)\n        assert_image_equal(img, expected, \"square as inverted rectangle failed\")\n\n\ndef test_triangle_right():\n    with Image.open(os.path.join(IMAGES_PATH, \"triangle_right.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK)\n        assert_image_equal(img, expected, \"triangle right failed\")\n\n\ndef test_line_horizontal():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w2px_normal.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight horizontal normal 2px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w2px_inverted.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight horizontal inverted 2px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_horizontal_w3px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight horizontal normal 3px wide failed\"\n        )\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight horizontal inverted 3px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_w101px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((200, 110))\n        draw.line((5, 55, 195, 55), BLACK, 101)\n        assert_image_equal(img, expected, \"line straight horizontal 101px wide failed\")\n\n\ndef test_line_h_s1_w2():\n    pytest.skip(\"failing\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_horizontal_slope1px_w2px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 6), BLACK, 2)\n        assert_image_equal(img, expected, \"line horizontal 1px slope 2px wide failed\")\n\n\ndef test_line_vertical():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_w2px_normal.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 5, 14), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight vertical normal 2px wide failed\"\n        )\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_w2px_inverted.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 5, 5), BLACK, 2)\n        assert_image_equal(\n            img, expected, \"line straight vertical inverted 2px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_vertical_w3px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 5, 14), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight vertical normal 3px wide failed\"\n        )\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 5, 5), BLACK, 3)\n        assert_image_equal(\n            img, expected, \"line straight vertical inverted 3px wide failed\"\n        )\n    with Image.open(os.path.join(IMAGES_PATH, \"line_vertical_w101px.png\")) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((110, 200))\n        draw.line((55, 5, 55, 195), BLACK, 101)\n        assert_image_equal(img, expected, \"line straight vertical 101px wide failed\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_vertical_slope1px_w2px.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 6, 14), BLACK, 2)\n        assert_image_equal(img, expected, \"line vertical 1px slope 2px wide failed\")\n\n\ndef test_line_oblique_45():\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_oblique_45_w3px_a.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 5, 14, 14), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 normal 3px wide A failed\")\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 14, 5, 5), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 inverted 3px wide A failed\")\n    with Image.open(\n        os.path.join(IMAGES_PATH, \"line_oblique_45_w3px_b.png\")\n    ) as expected:\n        expected.load()\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((14, 5, 5, 14), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 normal 3px wide B failed\")\n        img, draw = create_base_image_draw((20, 20))\n        draw.line((5, 14, 14, 5), BLACK, 3)\n        assert_image_equal(img, expected, \"line oblique 45 inverted 3px wide B failed\")\n\n\ndef test_wide_line_dot():\n    # Test drawing a wide \"line\" from one point to another just draws a single point\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    expected = \"Tests/images/imagedraw_wide_line_dot.png\"\n\n    # Act\n    draw.line([(50, 50), (50, 50)], width=3)\n\n    # Assert\n    assert_image_similar(im, Image.open(expected), 1)\n\n\ndef test_line_joint():\n    for xy in [\n        [\n            (400, 280),\n            (380, 280),\n            (450, 280),\n            (440, 120),\n            (350, 200),\n            (310, 280),\n            (300, 280),\n            (250, 280),\n            (250, 200),\n            (150, 200),\n            (150, 260),\n            (50, 200),\n            (150, 50),\n            (250, 100),\n        ],\n        (\n            400,\n            280,\n            380,\n            280,\n            450,\n            280,\n            440,\n            120,\n            350,\n            200,\n            310,\n            280,\n            300,\n            280,\n            250,\n            280,\n            250,\n            200,\n            150,\n            200,\n            150,\n            260,\n            50,\n            200,\n            150,\n            50,\n            250,\n            100,\n        ),\n        [\n            400,\n            280,\n            380,\n            280,\n            450,\n            280,\n            440,\n            120,\n            350,\n            200,\n            310,\n            280,\n            300,\n            280,\n            250,\n            280,\n            250,\n            200,\n            150,\n            200,\n            150,\n            260,\n            50,\n            200,\n            150,\n            50,\n            250,\n            100,\n        ],\n    ]:\n        im = Image.new(\"RGB\", (500, 325))\n        draw = ImageDraw.Draw(im)\n        expected = \"Tests/images/imagedraw_line_joint_curve.png\"\n\n        # Act\n        draw.line(xy, GRAY, 50, \"curve\")\n\n        # Assert\n        assert_image_similar(im, Image.open(expected), 3)\n\n\ndef test_textsize_empty_string():\n    # https://github.com/python-pillow/Pillow/issues/2783\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n\n    # Act\n    # Should not cause 'SystemError: <built-in method getsize of\n    # ImagingFont object at 0x...> returned NULL without setting an error'\n    draw.textsize(\"\")\n    draw.textsize(\"\\n\")\n    draw.textsize(\"test\\n\")\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_textsize_stroke():\n    # Arrange\n    im = Image.new(\"RGB\", (W, H))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 20)\n\n    # Act / Assert\n    assert draw.textsize(\"A\", font, stroke_width=2) == (16, 20)\n    assert draw.multiline_textsize(\"ABC\\nAaaa\", font, stroke_width=2) == (52, 44)\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke():\n    for suffix, stroke_fill in {\"same\": None, \"different\": \"#0f0\"}.items():\n        # Arrange\n        im = Image.new(\"RGB\", (120, 130))\n        draw = ImageDraw.Draw(im)\n        font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n        # Act\n        draw.text((10, 10), \"A\", \"#f00\", font, stroke_width=2, stroke_fill=stroke_fill)\n\n        # Assert\n        assert_image_similar(\n            im, Image.open(\"Tests/images/imagedraw_stroke_\" + suffix + \".png\"), 3.1\n        )\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke_descender():\n    # Arrange\n    im = Image.new(\"RGB\", (120, 130))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n    # Act\n    draw.text((10, 0), \"y\", \"#f00\", font, stroke_width=2, stroke_fill=\"#0f0\")\n\n    # Assert\n    assert_image_similar(\n        im, Image.open(\"Tests/images/imagedraw_stroke_descender.png\"), 6.76\n    )\n\n\n@skip_unless_feature(\"freetype2\")\ndef test_stroke_multiline():\n    # Arrange\n    im = Image.new(\"RGB\", (100, 250))\n    draw = ImageDraw.Draw(im)\n    font = ImageFont.truetype(\"Tests/fonts/FreeMono.ttf\", 120)\n\n    # Act\n    draw.multiline_text(\n        (10, 10), \"A\\nB\", \"#f00\", font, stroke_width=2, stroke_fill=\"#0f0\"\n    )\n\n    # Assert\n    assert_image_similar(\n        im, Image.open(\"Tests/images/imagedraw_stroke_multiline.png\"), 3.3\n    )\n\n\ndef test_same_color_outline():\n    # Prepare shape\n    x0, y0 = 5, 5\n    x1, y1 = 5, 50\n    x2, y2 = 95, 50\n    x3, y3 = 95, 5\n\n    s = ImageDraw.Outline()\n    s.move(x0, y0)\n    s.curve(x1, y1, x2, y2, x3, y3)\n    s.line(x0, y0)\n\n    # Begin\n    for mode in [\"RGB\", \"L\"]:\n        for fill, outline in [[\"red\", None], [\"red\", \"red\"], [\"red\", \"#f00\"]]:\n            for operation, args in {\n                \"chord\": [BBOX1, 0, 180],\n                \"ellipse\": [BBOX1],\n                \"shape\": [s],\n                \"pieslice\": [BBOX1, -90, 45],\n                \"polygon\": [[(18, 30), (85, 30), (60, 72)]],\n                \"rectangle\": [BBOX1],\n            }.items():\n                # Arrange\n                im = Image.new(mode, (W, H))\n                draw = ImageDraw.Draw(im)\n\n                # Act\n                draw_method = getattr(draw, operation)\n                args += [fill, outline]\n                draw_method(*args)\n\n                # Assert\n                expected = \"Tests/images/imagedraw_outline_{}_{}.png\".format(\n                    operation, mode\n                )\n                assert_image_similar(im, Image.open(expected), 1)\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Pillow installation attempts...\nVerifying Pillow installation...\n✅ Pillow installation successful!\nSuccessfully installed Pillow\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 12 packages in 15ms\nInstalled 12 packages in 176ms\n + coverage==7.6.10\n + exceptiongroup==1.2.2\n + iniconfig==2.0.0\n + packaging==24.2\n + pluggy==1.5.0\n + pyqt5==5.15.11\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.16.1\n + pytest==8.3.4\n + pytest-cov==6.0.0\n + setuptools==75.8.0\n + tomli==2.2.1\nResolved 1 package in 743ms\nPrepared 1 package in 35.24s\nInstalled 1 package in 1ms\n + pillow==7.2.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_f5e9252b12890502f3c9b24d32941ab09e297523)\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_f5e9252b12890502f3c9b24d32941ab09e297523\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 65 items\n\nr2e_tests/test_1.py .................................................... [ 80%]\n..s.....ssss.                                                            [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_sanity\nPASSED r2e_tests/test_1.py::test_valueerror\nPASSED r2e_tests/test_1.py::test_mode_mismatch\nPASSED r2e_tests/test_1.py::test_arc1\nPASSED r2e_tests/test_1.py::test_arc2\nPASSED r2e_tests/test_1.py::test_arc_end_le_start\nPASSED r2e_tests/test_1.py::test_arc_no_loops\nPASSED r2e_tests/test_1.py::test_arc_width\nPASSED r2e_tests/test_1.py::test_arc_width_pieslice_large\nPASSED r2e_tests/test_1.py::test_arc_width_fill\nPASSED r2e_tests/test_1.py::test_arc_width_non_whole_angle\nPASSED r2e_tests/test_1.py::test_bitmap\nPASSED r2e_tests/test_1.py::test_chord1\nPASSED r2e_tests/test_1.py::test_chord2\nPASSED r2e_tests/test_1.py::test_chord_width\nPASSED r2e_tests/test_1.py::test_chord_width_fill\nPASSED r2e_tests/test_1.py::test_chord_zero_width\nPASSED r2e_tests/test_1.py::test_ellipse1\nPASSED r2e_tests/test_1.py::test_ellipse2\nPASSED r2e_tests/test_1.py::test_ellipse_translucent\nPASSED r2e_tests/test_1.py::test_ellipse_edge\nPASSED r2e_tests/test_1.py::test_ellipse_symmetric\nPASSED r2e_tests/test_1.py::test_ellipse_width\nPASSED r2e_tests/test_1.py::test_ellipse_width_large\nPASSED r2e_tests/test_1.py::test_ellipse_width_fill\nPASSED r2e_tests/test_1.py::test_ellipse_zero_width\nPASSED r2e_tests/test_1.py::test_line1\nPASSED r2e_tests/test_1.py::test_line2\nPASSED r2e_tests/test_1.py::test_shape1\nPASSED r2e_tests/test_1.py::test_shape2\nPASSED r2e_tests/test_1.py::test_pieslice1\nPASSED r2e_tests/test_1.py::test_pieslice2\nPASSED r2e_tests/test_1.py::test_pieslice_width\nPASSED r2e_tests/test_1.py::test_pieslice_width_fill\nPASSED r2e_tests/test_1.py::test_pieslice_zero_width\nPASSED r2e_tests/test_1.py::test_point1\nPASSED r2e_tests/test_1.py::test_point2\nPASSED r2e_tests/test_1.py::test_polygon1\nPASSED r2e_tests/test_1.py::test_polygon2\nPASSED r2e_tests/test_1.py::test_polygon_kite\nPASSED r2e_tests/test_1.py::test_rectangle1\nPASSED r2e_tests/test_1.py::test_rectangle2\nPASSED r2e_tests/test_1.py::test_big_rectangle\nPASSED r2e_tests/test_1.py::test_rectangle_width\nPASSED r2e_tests/test_1.py::test_rectangle_width_fill\nPASSED r2e_tests/test_1.py::test_rectangle_zero_width\nPASSED r2e_tests/test_1.py::test_rectangle_I16\nPASSED r2e_tests/test_1.py::test_floodfill\nPASSED r2e_tests/test_1.py::test_floodfill_border\nPASSED r2e_tests/test_1.py::test_floodfill_thresh\nPASSED r2e_tests/test_1.py::test_floodfill_not_negative\nPASSED r2e_tests/test_1.py::test_square\nPASSED r2e_tests/test_1.py::test_triangle_right\nPASSED r2e_tests/test_1.py::test_line_horizontal\nPASSED r2e_tests/test_1.py::test_line_vertical\nPASSED r2e_tests/test_1.py::test_line_oblique_45\nPASSED r2e_tests/test_1.py::test_wide_line_dot\nPASSED r2e_tests/test_1.py::test_line_joint\nPASSED r2e_tests/test_1.py::test_textsize_empty_string\nPASSED r2e_tests/test_1.py::test_same_color_outline\nSKIPPED [1] r2e_tests/test_1.py:784: failing\nSKIPPED [1] r2e_tests/test_1.py:980: freetype2 not available\nSKIPPED [1] r2e_tests/test_1.py:992: freetype2 not available\nSKIPPED [1] r2e_tests/test_1.py:1009: freetype2 not available\nSKIPPED [1] r2e_tests/test_1.py:1025: freetype2 not available\n======================== 60 passed, 5 skipped in 0.34s =========================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_f5e9252b12890502f3c9b24d32941ab09e297523\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 65 items\n\nr2e_tests/test_1.py .................................................... [ 80%]\n..s...F.ssss.                                                            [100%]\n\n=================================== FAILURES ===================================\n_______________________________ test_line_joint ________________________________\n\n    def test_line_joint():\n        for xy in [\n            [\n                (400, 280),\n                (380, 280),\n                (450, 280),\n                (440, 120),\n                (350, 200),\n                (310, 280),\n                (300, 280),\n                (250, 280),\n                (250, 200),\n                (150, 200),\n                (150, 260),\n                (50, 200),\n                (150, 50),\n                (250, 100),\n            ],\n            (\n                400,\n                280,\n                380,\n                280,\n                450,\n                280,\n                440,\n                120,\n                350,\n                200,\n                310,\n                280,\n                300,\n                280,\n                250,\n                280,\n                250,\n                200,\n                150,\n                200,\n                150,\n                260,\n                50,\n                200,\n                150,\n                50,\n                250,\n                100,\n            ),\n            [\n                400,\n                280,\n                380,\n                280,\n                450,\n                280,\n                440,\n                120,\n                350,\n                200,\n                310,\n                280,\n                300,\n                280,\n                250,\n                280,\n                250,\n                200,\n                150,\n                200,\n                150,\n                260,\n                50,\n                200,\n                150,\n                50,\n                250,\n                100,\n            ],\n        ]:\n            im = Image.new(\"RGB\", (500, 325))\n            draw = ImageDraw.Draw(im)\n            expected = \"Tests/images/imagedraw_line_joint_curve.png\"\n    \n            # Act\n>           draw.line(xy, GRAY, 50, \"curve\")\n\nr2e_tests/test_1.py:960: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/ImageDraw.py:161: in line\n    angles = [\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n.0 = <tuple_iterator object at 0x7b6547bddfa0>\n\n    angles = [\n>       math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))\n        % 360\n        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))\n    ]\nE   TypeError: 'int' object is not subscriptable\n\nsrc/PIL/ImageDraw.py:162: TypeError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_sanity\nPASSED r2e_tests/test_1.py::test_valueerror\nPASSED r2e_tests/test_1.py::test_mode_mismatch\nPASSED r2e_tests/test_1.py::test_arc1\nPASSED r2e_tests/test_1.py::test_arc2\nPASSED r2e_tests/test_1.py::test_arc_end_le_start\nPASSED r2e_tests/test_1.py::test_arc_no_loops\nPASSED r2e_tests/test_1.py::test_arc_width\nPASSED r2e_tests/test_1.py::test_arc_width_pieslice_large\nPASSED r2e_tests/test_1.py::test_arc_width_fill\nPASSED r2e_tests/test_1.py::test_arc_width_non_whole_angle\nPASSED r2e_tests/test_1.py::test_bitmap\nPASSED r2e_tests/test_1.py::test_chord1\nPASSED r2e_tests/test_1.py::test_chord2\nPASSED r2e_tests/test_1.py::test_chord_width\nPASSED r2e_tests/test_1.py::test_chord_width_fill\nPASSED r2e_tests/test_1.py::test_chord_zero_width\nPASSED r2e_tests/test_1.py::test_ellipse1\nPASSED r2e_tests/test_1.py::test_ellipse2\nPASSED r2e_tests/test_1.py::test_ellipse_translucent\nPASSED r2e_tests/test_1.py::test_ellipse_edge\nPASSED r2e_tests/test_1.py::test_ellipse_symmetric\nPASSED r2e_tests/test_1.py::test_ellipse_width\nPASSED r2e_tests/test_1.py::test_ellipse_width_large\nPASSED r2e_tests/test_1.py::test_ellipse_width_fill\nPASSED r2e_tests/test_1.py::test_ellipse_zero_width\nPASSED r2e_tests/test_1.py::test_line1\nPASSED r2e_tests/test_1.py::test_line2\nPASSED r2e_tests/test_1.py::test_shape1\nPASSED r2e_tests/test_1.py::test_shape2\nPASSED r2e_tests/test_1.py::test_pieslice1\nPASSED r2e_tests/test_1.py::test_pieslice2\nPASSED r2e_tests/test_1.py::test_pieslice_width\nPASSED r2e_tests/test_1.py::test_pieslice_width_fill\nPASSED r2e_tests/test_1.py::test_pieslice_zero_width\nPASSED r2e_tests/test_1.py::test_point1\nPASSED r2e_tests/test_1.py::test_point2\nPASSED r2e_tests/test_1.py::test_polygon1\nPASSED r2e_tests/test_1.py::test_polygon2\nPASSED r2e_tests/test_1.py::test_polygon_kite\nPASSED r2e_tests/test_1.py::test_rectangle1\nPASSED r2e_tests/test_1.py::test_rectangle2\nPASSED r2e_tests/test_1.py::test_big_rectangle\nPASSED r2e_tests/test_1.py::test_rectangle_width\nPASSED r2e_tests/test_1.py::test_rectangle_width_fill\nPASSED r2e_tests/test_1.py::test_rectangle_zero_width\nPASSED r2e_tests/test_1.py::test_rectangle_I16\nPASSED r2e_tests/test_1.py::test_floodfill\nPASSED r2e_tests/test_1.py::test_floodfill_border\nPASSED r2e_tests/test_1.py::test_floodfill_thresh\nPASSED r2e_tests/test_1.py::test_floodfill_not_negative\nPASSED r2e_tests/test_1.py::test_square\nPASSED r2e_tests/test_1.py::test_triangle_right\nPASSED r2e_tests/test_1.py::test_line_horizontal\nPASSED r2e_tests/test_1.py::test_line_vertical\nPASSED r2e_tests/test_1.py::test_line_oblique_45\nPASSED r2e_tests/test_1.py::test_wide_line_dot\nPASSED r2e_tests/test_1.py::test_textsize_empty_string\nPASSED r2e_tests/test_1.py::test_same_color_outline\nSKIPPED [1] r2e_tests/test_1.py:784: failing\nSKIPPED [1] r2e_tests/test_1.py:980: freetype2 not available\nSKIPPED [1] r2e_tests/test_1.py:992: freetype2 not available\nSKIPPED [1] r2e_tests/test_1.py:1009: freetype2 not available\nSKIPPED [1] r2e_tests/test_1.py:1025: freetype2 not available\nFAILED r2e_tests/test_1.py::test_line_joint - TypeError: 'int' object is not ...\n=================== 1 failed, 59 passed, 5 skipped in 0.27s ====================\n",
    "old_commit_res_stderr": ""
}
Tests/test_imagedraw.py src/PIL/ImageDraw.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** TypeError When Drawing Jointed Lines with Flat Numeric Sequences

**Description:**
When using a flat sequence of numeric values to draw a jointed line with a width greater than 4, a `TypeError` is raised. The drawing function expects each coordinate to be a tuple or list of two integers, but it fails when provided with a flat list or tuple.

**Example Buggy Code:**
```python
from PIL import Image, ImageDraw

im = Image.new("RGB", (500, 325))
draw = ImageDraw.Draw(im)
# Using a flat tuple of integers instead of a list of coordinate pairs
xy = (400, 280, 380, 280, 450, 280, 440, 120, 350, 200, 310, 280)
draw.line(xy, fill="gray", width=50, joint="curve")
```

**Expected Behavior:**
The jointed line should be drawn correctly without errors, handling both flat sequences and sequences of coordinate pairs seamlessly.

**Actual Behavior:**
A `TypeError` is raised with the message: `'int' object is not subscriptable`.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### src/PIL/ImageDraw.py
#
# The Python Imaging Library
# $Id$
#
# drawing interface operations
#
# History:
# 1996-04-13 fl   Created (experimental)
# 1996-08-07 fl   Filled polygons, ellipses.
# 1996-08-13 fl   Added text support
# 1998-06-28 fl   Handle I and F images
# 1998-12-29 fl   Added arc; use arc primitive to draw ellipses
# 1999-01-10 fl   Added shape stuff (experimental)
# 1999-02-06 fl   Added bitmap support
# 1999-02-11 fl   Changed all primitives to take options
# 1999-02-20 fl   Fixed backwards compatibility
# 2000-10-12 fl   Copy on write, when necessary
# 2001-02-18 fl   Use default ink for bitmap/text also in fill mode
# 2002-10-24 fl   Added support for CSS-style color strings
# 2002-12-10 fl   Added experimental support for RGBA-on-RGB drawing
# 2002-12-11 fl   Refactored low-level drawing API (work in progress)
# 2004-08-26 fl   Made Draw() a factory function, added getdraw() support
# 2004-09-04 fl   Added width support to line primitive
# 2004-09-10 fl   Added font mode handling
# 2006-06-19 fl   Added font bearing support (getmask2)
#
# Copyright (c) 1997-2006 by Secret Labs AB
# Copyright (c) 1996-2006 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#

import math
import numbers

from . import Image, ImageColor


"""
A simple 2D drawing interface for PIL images.
<p>
Application code should use the <b>Draw</b> factory, instead of
directly.
"""


class ImageDraw:
    def __init__(self, im, mode=None):
        """
        Create a drawing instance.

        :param im: The image to draw in.
        :param mode: Optional mode to use for color values.  For RGB
           images, this argument can be RGB or RGBA (to blend the
           drawing into the image).  For all other modes, this argument
           must be the same as the image mode.  If omitted, the mode
           defaults to the mode of the image.
        """
        im.load()
        if im.readonly:
            im._copy()  # make it writeable
        blend = 0
        if mode is None:
            mode = im.mode
        if mode != im.mode:
            if mode == "RGBA" and im.mode == "RGB":
                blend = 1
            else:
                raise ValueError("mode mismatch")
        if mode == "P":
            self.palette = im.palette
        else:
            self.palette = None
        self.im = im.im
        self.draw = Image.core.draw(self.im, blend)
        self.mode = mode
        if mode in ("I", "F"):
            self.ink = self.draw.draw_ink(1)
        else:
            self.ink = self.draw.draw_ink(-1)
        if mode in ("1", "P", "I", "F"):
            # FIXME: fix Fill2 to properly support matte for I+F images
            self.fontmode = "1"
        else:
            self.fontmode = "L"  # aliasing is okay for other modes
        self.fill = 0
        self.font = None

    def getfont(self):
        """
        Get the current default font.

        :returns: An image font."""
        if not self.font:
            # FIXME: should add a font repository
            from . import ImageFont

            self.font = ImageFont.load_default()
        return self.font

    def _getink(self, ink, fill=None):
        if ink is None and fill is None:
            if self.fill:
                fill = self.ink
            else:
                ink = self.ink
        else:
            if ink is not None:
                if isinstance(ink, str):
                    ink = ImageColor.getcolor(ink, self.mode)
                if self.palette and not isinstance(ink, numbers.Number):
                    ink = self.palette.getcolor(ink)
                ink = self.draw.draw_ink(ink)
            if fill is not None:
                if isinstance(fill, str):
                    fill = ImageColor.getcolor(fill, self.mode)
                if self.palette and not isinstance(fill, numbers.Number):
                    fill = self.palette.getcolor(fill)
                fill = self.draw.draw_ink(fill)
        return ink, fill

    def arc(self, xy, start, end, fill=None, width=0):
        """Draw an arc."""
        ink, fill = self._getink(fill)
        if ink is not None:
            self.draw.draw_arc(xy, start, end, ink, width)

    def bitmap(self, xy, bitmap, fill=None):
        """Draw a bitmap."""
        bitmap.load()
        ink, fill = self._getink(fill)
        if ink is None:
            ink = fill
        if ink is not None:
            self.draw.draw_bitmap(xy, bitmap.im, ink)

    def chord(self, xy, start, end, fill=None, outline=None, width=1):
        """Draw a chord."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_chord(xy, start, end, fill, 1)
        if ink is not None and ink != fill and width != 0:
            self.draw.draw_chord(xy, start, end, ink, 0, width)

    def ellipse(self, xy, fill=None, outline=None, width=1):
        """Draw an ellipse."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_ellipse(xy, fill, 1)
        if ink is not None and ink != fill and width != 0:
            self.draw.draw_ellipse(xy, ink, 0, width)

    def line(self, xy, fill=None, width=0, joint=None):
        """Draw a line, or a connected sequence of line segments."""
        ink = self._getink(fill)[0]
        if ink is not None:
            self.draw.draw_lines(xy, ink, width)
            if joint == "curve" and width > 4:
                for i in range(1, len(xy) - 1):
                    point = xy[i]
                    angles = [
                        math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))
                        % 360
                        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))
                    ]
                    if angles[0] == angles[1]:
                        # This is a straight line, so no joint is required
                        continue

                    def coord_at_angle(coord, angle):
                        x, y = coord
                        angle -= 90
                        distance = width / 2 - 1
                        return tuple(
                            [
                                p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))
                                for p, p_d in (
                                    (x, distance * math.cos(math.radians(angle))),
                                    (y, distance * math.sin(math.radians(angle))),
                                )
                            ]
                        )

                    flipped = (
                        angles[1] > angles[0] and angles[1] - 180 > angles[0]
                    ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])
                    coords = [
                        (point[0] - width / 2 + 1, point[1] - width / 2 + 1),
                        (point[0] + width / 2 - 1, point[1] + width / 2 - 1),
                    ]
                    if flipped:
                        start, end = (angles[1] + 90, angles[0] + 90)
                    else:
                        start, end = (angles[0] - 90, angles[1] - 90)
                    self.pieslice(coords, start - 90, end - 90, fill)

                    if width > 8:
                        # Cover potential gaps between the line and the joint
                        if flipped:
                            gapCoords = [
                                coord_at_angle(point, angles[0] + 90),
                                point,
                                coord_at_angle(point, angles[1] + 90),
                            ]
                        else:
                            gapCoords = [
                                coord_at_angle(point, angles[0] - 90),
                                point,
                                coord_at_angle(point, angles[1] - 90),
                            ]
                        self.line(gapCoords, fill, width=3)

    def shape(self, shape, fill=None, outline=None):
        """(Experimental) Draw a shape."""
        shape.close()
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_outline(shape, fill, 1)
        if ink is not None and ink != fill:
            self.draw.draw_outline(shape, ink, 0)

    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):
        """Draw a pieslice."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_pieslice(xy, start, end, fill, 1)
        if ink is not None and ink != fill and width != 0:
            self.draw.draw_pieslice(xy, start, end, ink, 0, width)

    def point(self, xy, fill=None):
        """Draw one or more individual pixels."""
        ink, fill = self._getink(fill)
        if ink is not None:
            self.draw.draw_points(xy, ink)

    def polygon(self, xy, fill=None, outline=None):
        """Draw a polygon."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_polygon(xy, fill, 1)
        if ink is not None and ink != fill:
            self.draw.draw_polygon(xy, ink, 0)

    def rectangle(self, xy, fill=None, outline=None, width=1):
        """Draw a rectangle."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_rectangle(xy, fill, 1)
        if ink is not None and ink != fill and width != 0:
            self.draw.draw_rectangle(xy, ink, 0, width)

    def _multiline_check(self, text):
        """Draw text."""
        split_character = "\n" if isinstance(text, str) else b"\n"

        return split_character in text

    def _multiline_split(self, text):
        split_character = "\n" if isinstance(text, str) else b"\n"

        return text.split(split_character)

    def text(
        self,
        xy,
        text,
        fill=None,
        font=None,
        anchor=None,
        spacing=4,
        align="left",
        direction=None,
        features=None,
        language=None,
        stroke_width=0,
        stroke_fill=None,
        *args,
        **kwargs
    ):
        if self._multiline_check(text):
            return self.multiline_text(
                xy,
                text,
                fill,
                font,
                anchor,
                spacing,
                align,
                direction,
                features,
                language,
                stroke_width,
                stroke_fill,
            )

        if font is None:
            font = self.getfont()

        def getink(fill):
            ink, fill = self._getink(fill)
            if ink is None:
                return fill
            return ink

        def draw_text(ink, stroke_width=0, stroke_offset=None):
            coord = xy
            try:
                mask, offset = font.getmask2(
                    text,
                    self.fontmode,
                    direction=direction,
                    features=features,
                    language=language,
                    stroke_width=stroke_width,
                    *args,
                    **kwargs,
                )
                coord = coord[0] + offset[0], coord[1] + offset[1]
            except AttributeError:
                try:
                    mask = font.getmask(
                        text,
                        self.fontmode,
                        direction,
                        features,
                        language,
                        stroke_width,
                        *args,
                        **kwargs,
                    )
                except TypeError:
                    mask = font.getmask(text)
            if stroke_offset:
                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]
            self.draw.draw_bitmap(coord, mask, ink)

        ink = getink(fill)
        if ink is not None:
            stroke_ink = None
            if stroke_width:
                stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink

            if stroke_ink is not None:
                # Draw stroked text
                draw_text(stroke_ink, stroke_width)

                # Draw normal text
                draw_text(ink, 0, (stroke_width, stroke_width))
            else:
                # Only draw normal text
                draw_text(ink)

    def multiline_text(
        self,
        xy,
        text,
        fill=None,
        font=None,
        anchor=None,
        spacing=4,
        align="left",
        direction=None,
        features=None,
        language=None,
        stroke_width=0,
        stroke_fill=None,
    ):
        widths = []
        max_width = 0
        lines = self._multiline_split(text)
        line_spacing = (
            self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
        )
        for line in lines:
            line_width, line_height = self.textsize(
                line,
                font,
                direction=direction,
                features=features,
                language=language,
                stroke_width=stroke_width,
            )
            widths.append(line_width)
            max_width = max(max_width, line_width)
        left, top = xy
        for idx, line in enumerate(lines):
            if align == "left":
                pass  # left = x
            elif align == "center":
                left += (max_width - widths[idx]) / 2.0
            elif align == "right":
                left += max_width - widths[idx]
            else:
                raise ValueError('align must be "left", "center" or "right"')
            self.text(
                (left, top),
                line,
                fill,
                font,
                anchor,
                direction=direction,
                features=features,
                language=language,
                stroke_width=stroke_width,
                stroke_fill=stroke_fill,
            )
            top += line_spacing
            left = xy[0]

    def textsize(
        self,
        text,
        font=None,
        spacing=4,
        direction=None,
        features=None,
        language=None,
        stroke_width=0,
    ):
        """Get the size of a given string, in pixels."""
        if self._multiline_check(text):
            return self.multiline_textsize(
                text, font, spacing, direction, features, language, stroke_width
            )

        if font is None:
            font = self.getfont()
        return font.getsize(text, direction, features, language, stroke_width)

    def multiline_textsize(
        self,
        text,
        font=None,
        spacing=4,
        direction=None,
        features=None,
        language=None,
        stroke_width=0,
    ):
        max_width = 0
        lines = self._multiline_split(text)
        line_spacing = (
            self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
        )
        for line in lines:
            line_width, line_height = self.textsize(
                line, font, spacing, direction, features, language, stroke_width
            )
            max_width = max(max_width, line_width)
        return max_width, len(lines) * line_spacing - spacing


def Draw(im, mode=None):
    """
    A simple 2D drawing interface for PIL images.

    :param im: The image to draw in.
    :param mode: Optional mode to use for color values.  For RGB
       images, this argument can be RGB or RGBA (to blend the
       drawing into the image).  For all other modes, this argument
       must be the same as the image mode.  If omitted, the mode
       defaults to the mode of the image.
    """
    try:
        return im.getdraw(mode)
    except AttributeError:
        return ImageDraw(im, mode)


# experimental access to the outline API
try:
    Outline = Image.core.outline
except AttributeError:
    Outline = None


def getdraw(im=None, hints=None):
    """
    (Experimental) A more advanced 2D drawing interface for PIL images,
    based on the WCK interface.

    :param im: The image to draw in.
    :param hints: An optional list of hints.
    :returns: A (drawing context, drawing resource factory) tuple.
    """
    # FIXME: this needs more work!
    # FIXME: come up with a better 'hints' scheme.
    handler = None
    if not hints or "nicest" in hints:
        try:
            from . import _imagingagg as handler
        except ImportError:
            pass
    if handler is None:
        from . import ImageDraw2 as handler
    if im:
        im = handler.Draw(im)
    return im, handler


def floodfill(image, xy, value, border=None, thresh=0):
    """
    (experimental) Fills a bounded region with a given color.

    :param image: Target image.
    :param xy: Seed position (a 2-item coordinate tuple). See
        :ref:`coordinate-system`.
    :param value: Fill color.
    :param border: Optional border value.  If given, the region consists of
        pixels with a color different from the border color.  If not given,
        the region consists of pixels having the same color as the seed
        pixel.
    :param thresh: Optional threshold value which specifies a maximum
        tolerable difference of a pixel value from the 'background' in
        order for it to be replaced. Useful for filling regions of
        non-homogeneous, but similar, colors.
    """
    # based on an implementation by Eric S. Raymond
    # amended by yo1995 @20180806
    pixel = image.load()
    x, y = xy
    try:
        background = pixel[x, y]
        if _color_diff(value, background) <= thresh:
            return  # seed point already has fill color
        pixel[x, y] = value
    except (ValueError, IndexError):
        return  # seed point outside image
    edge = {(x, y)}
    # use a set to keep record of current and previous edge pixels
    # to reduce memory consumption
    full_edge = set()
    while edge:
        new_edge = set()
        for (x, y) in edge:  # 4 adjacent method
            for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
                # If already processed, or if a coordinate is negative, skip
                if (s, t) in full_edge or s < 0 or t < 0:
                    continue
                try:
                    p = pixel[s, t]
                except (ValueError, IndexError):
                    pass
                else:
                    full_edge.add((s, t))
                    if border is None:
                        fill = _color_diff(p, background) <= thresh
                    else:
                        fill = p != value and p != border
                    if fill:
                        pixel[s, t] = value
                        new_edge.add((s, t))
        full_edge = edge  # discard pixels processed
        edge = new_edge


def _color_diff(color1, color2):
    """
    Uses 1-norm distance to calculate difference between two values.
    """
    if isinstance(color2, tuple):
        return sum([abs(color1[i] - color2[i]) for i in range(0, len(color2))])
    else:
        return abs(color1 - color2)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** TypeError When Drawing Jointed Lines with Flat Numeric Sequences

**Description:**
When using a flat sequence of numeric values to draw a jointed line with a width greater than 4, a `TypeError` is raised. The drawing function expects each coordinate to be a tuple or list of two integers, but it fails when provided with a flat list or tuple.

**Example Buggy Code:**
```python
from PIL import Image, ImageDraw

im = Image.new("RGB", (500, 325))
draw = ImageDraw.Draw(im)
# Using a flat tuple of integers instead of a list of coordinate pairs
xy = (400, 280, 380, 280, 450, 280, 440, 120, 350, 200, 310, 280)
draw.line(xy, fill="gray", width=50, joint="curve")
```

**Expected Behavior:**
The jointed line should be drawn correctly without errors, handling both flat sequences and sequences of coordinate pairs seamlessly.

**Actual Behavior:**
A `TypeError` is raised with the message: `'int' object is not subscriptable`.

[/ISSUE]
{
    "test_sanity": "PASSED",
    "test_valueerror": "PASSED",
    "test_mode_mismatch": "PASSED",
    "test_arc1": "PASSED",
    "test_arc2": "PASSED",
    "test_arc_end_le_start": "PASSED",
    "test_arc_no_loops": "PASSED",
    "test_arc_width": "PASSED",
    "test_arc_width_pieslice_large": "PASSED",
    "test_arc_width_fill": "PASSED",
    "test_arc_width_non_whole_angle": "PASSED",
    "test_bitmap": "PASSED",
    "test_chord1": "PASSED",
    "test_chord2": "PASSED",
    "test_chord_width": "PASSED",
    "test_chord_width_fill": "PASSED",
    "test_chord_zero_width": "PASSED",
    "test_ellipse1": "PASSED",
    "test_ellipse2": "PASSED",
    "test_ellipse_translucent": "PASSED",
    "test_ellipse_edge": "PASSED",
    "test_ellipse_symmetric": "PASSED",
    "test_ellipse_width": "PASSED",
    "test_ellipse_width_large": "PASSED",
    "test_ellipse_width_fill": "PASSED",
    "test_ellipse_zero_width": "PASSED",
    "test_line1": "PASSED",
    "test_line2": "PASSED",
    "test_shape1": "PASSED",
    "test_shape2": "PASSED",
    "test_pieslice1": "PASSED",
    "test_pieslice2": "PASSED",
    "test_pieslice_width": "PASSED",
    "test_pieslice_width_fill": "PASSED",
    "test_pieslice_zero_width": "PASSED",
    "test_point1": "PASSED",
    "test_point2": "PASSED",
    "test_polygon1": "PASSED",
    "test_polygon2": "PASSED",
    "test_polygon_kite": "PASSED",
    "test_rectangle1": "PASSED",
    "test_rectangle2": "PASSED",
    "test_big_rectangle": "PASSED",
    "test_rectangle_width": "PASSED",
    "test_rectangle_width_fill": "PASSED",
    "test_rectangle_zero_width": "PASSED",
    "test_rectangle_I16": "PASSED",
    "test_floodfill": "PASSED",
    "test_floodfill_border": "PASSED",
    "test_floodfill_thresh": "PASSED",
    "test_floodfill_not_negative": "PASSED",
    "test_square": "PASSED",
    "test_triangle_right": "PASSED",
    "test_line_horizontal": "PASSED",
    "test_line_vertical": "PASSED",
    "test_line_oblique_45": "PASSED",
    "test_wide_line_dot": "PASSED",
    "test_line_joint": "PASSED",
    "test_textsize_empty_string": "PASSED",
    "test_same_color_outline": "PASSED"
}
diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py
index 7abd459f9..cbecf652d 100644
--- a/src/PIL/ImageDraw.py
+++ b/src/PIL/ImageDraw.py
@@ -156,6 +156,8 @@ class ImageDraw:
         if ink is not None:
             self.draw.draw_lines(xy, ink, width)
             if joint == "curve" and width > 4:
+                if not isinstance(xy[0], (list, tuple)):
+                    xy = [tuple(xy[i : i + 2]) for i in range(0, len(xy), 2)]
                 for i in range(1, len(xy) - 1):
                     point = xy[i]
                     angles = [
 

{"src/PIL/ImageDraw.py": "#\n# The Python Imaging Library\n# $Id$\n#\n# drawing interface operations\n#\n# History:\n# 1996-04-13 fl   Created (experimental)\n# 1996-08-07 fl   Filled polygons, ellipses.\n# 1996-08-13 fl   Added text support\n# 1998-06-28 fl   Handle I and F images\n# 1998-12-29 fl   Added arc; use arc primitive to draw ellipses\n# 1999-01-10 fl   Added shape stuff (experimental)\n# 1999-02-06 fl   Added bitmap support\n# 1999-02-11 fl   Changed all primitives to take options\n# 1999-02-20 fl   Fixed backwards compatibility\n# 2000-10-12 fl   Copy on write, when necessary\n# 2001-02-18 fl   Use default ink for bitmap/text also in fill mode\n# 2002-10-24 fl   Added support for CSS-style color strings\n# 2002-12-10 fl   Added experimental support for RGBA-on-RGB drawing\n# 2002-12-11 fl   Refactored low-level drawing API (work in progress)\n# 2004-08-26 fl   Made Draw() a factory function, added getdraw() support\n# 2004-09-04 fl   Added width support to line primitive\n# 2004-09-10 fl   Added font mode handling\n# 2006-06-19 fl   Added font bearing support (getmask2)\n#\n# Copyright (c) 1997-2006 by Secret Labs AB\n# Copyright (c) 1996-2006 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\nimport math\nimport numbers\n\nfrom . import Image, ImageColor\n\n\n\"\"\"\nA simple 2D drawing interface for PIL images.\n<p>\nApplication code should use the <b>Draw</b> factory, instead of\ndirectly.\n\"\"\"\n\n\nclass ImageDraw:\n    def __init__(self, im, mode=None):\n        \"\"\"\n        Create a drawing instance.\n\n        :param im: The image to draw in.\n        :param mode: Optional mode to use for color values.  For RGB\n           images, this argument can be RGB or RGBA (to blend the\n           drawing into the image).  For all other modes, this argument\n           must be the same as the image mode.  If omitted, the mode\n           defaults to the mode of the image.\n        \"\"\"\n        im.load()\n        if im.readonly:\n            im._copy()  # make it writeable\n        blend = 0\n        if mode is None:\n            mode = im.mode\n        if mode != im.mode:\n            if mode == \"RGBA\" and im.mode == \"RGB\":\n                blend = 1\n            else:\n                raise ValueError(\"mode mismatch\")\n        if mode == \"P\":\n            self.palette = im.palette\n        else:\n            self.palette = None\n        self.im = im.im\n        self.draw = Image.core.draw(self.im, blend)\n        self.mode = mode\n        if mode in (\"I\", \"F\"):\n            self.ink = self.draw.draw_ink(1)\n        else:\n            self.ink = self.draw.draw_ink(-1)\n        if mode in (\"1\", \"P\", \"I\", \"F\"):\n            # FIXME: fix Fill2 to properly support matte for I+F images\n            self.fontmode = \"1\"\n        else:\n            self.fontmode = \"L\"  # aliasing is okay for other modes\n        self.fill = 0\n        self.font = None\n\n    def getfont(self):\n        \"\"\"\n        Get the current default font.\n\n        :returns: An image font.\"\"\"\n        if not self.font:\n            # FIXME: should add a font repository\n            from . import ImageFont\n\n            self.font = ImageFont.load_default()\n        return self.font\n\n    def _getink(self, ink, fill=None):\n        if ink is None and fill is None:\n            if self.fill:\n                fill = self.ink\n            else:\n                ink = self.ink\n        else:\n            if ink is not None:\n                if isinstance(ink, str):\n                    ink = ImageColor.getcolor(ink, self.mode)\n                if self.palette and not isinstance(ink, numbers.Number):\n                    ink = self.palette.getcolor(ink)\n                ink = self.draw.draw_ink(ink)\n            if fill is not None:\n                if isinstance(fill, str):\n                    fill = ImageColor.getcolor(fill, self.mode)\n                if self.palette and not isinstance(fill, numbers.Number):\n                    fill = self.palette.getcolor(fill)\n                fill = self.draw.draw_ink(fill)\n        return ink, fill\n\n    def arc(self, xy, start, end, fill=None, width=0):\n        \"\"\"Draw an arc.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_arc(xy, start, end, ink, width)\n\n    def bitmap(self, xy, bitmap, fill=None):\n        \"\"\"Draw a bitmap.\"\"\"\n        bitmap.load()\n        ink, fill = self._getink(fill)\n        if ink is None:\n            ink = fill\n        if ink is not None:\n            self.draw.draw_bitmap(xy, bitmap.im, ink)\n\n    def chord(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a chord.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_chord(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_chord(xy, start, end, ink, 0, width)\n\n    def ellipse(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw an ellipse.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_ellipse(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_ellipse(xy, ink, 0, width)\n\n    def line(self, xy, fill=None, width=0, joint=None):\n        \"\"\"Draw a line, or a connected sequence of line segments.\"\"\"\n        ink = self._getink(fill)[0]\n        if ink is not None:\n            self.draw.draw_lines(xy, ink, width)\n            if joint == \"curve\" and width > 4:\n                for i in range(1, len(xy) - 1):\n                    point = xy[i]\n                    angles = [\n                        math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))\n                        % 360\n                        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))\n                    ]\n                    if angles[0] == angles[1]:\n                        # This is a straight line, so no joint is required\n                        continue\n\n                    def coord_at_angle(coord, angle):\n                        x, y = coord\n                        angle -= 90\n                        distance = width / 2 - 1\n                        return tuple(\n                            [\n                                p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))\n                                for p, p_d in (\n                                    (x, distance * math.cos(math.radians(angle))),\n                                    (y, distance * math.sin(math.radians(angle))),\n                                )\n                            ]\n                        )\n\n                    flipped = (\n                        angles[1] > angles[0] and angles[1] - 180 > angles[0]\n                    ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])\n                    coords = [\n                        (point[0] - width / 2 + 1, point[1] - width / 2 + 1),\n                        (point[0] + width / 2 - 1, point[1] + width / 2 - 1),\n                    ]\n                    if flipped:\n                        start, end = (angles[1] + 90, angles[0] + 90)\n                    else:\n                        start, end = (angles[0] - 90, angles[1] - 90)\n                    self.pieslice(coords, start - 90, end - 90, fill)\n\n                    if width > 8:\n                        # Cover potential gaps between the line and the joint\n                        if flipped:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] + 90),\n                                point,\n                                coord_at_angle(point, angles[1] + 90),\n                            ]\n                        else:\n                            gapCoords = [\n                                coord_at_angle(point, angles[0] - 90),\n                                point,\n                                coord_at_angle(point, angles[1] - 90),\n                            ]\n                        self.line(gapCoords, fill, width=3)\n\n    def shape(self, shape, fill=None, outline=None):\n        \"\"\"(Experimental) Draw a shape.\"\"\"\n        shape.close()\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_outline(shape, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_outline(shape, ink, 0)\n\n    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):\n        \"\"\"Draw a pieslice.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_pieslice(xy, start, end, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_pieslice(xy, start, end, ink, 0, width)\n\n    def point(self, xy, fill=None):\n        \"\"\"Draw one or more individual pixels.\"\"\"\n        ink, fill = self._getink(fill)\n        if ink is not None:\n            self.draw.draw_points(xy, ink)\n\n    def polygon(self, xy, fill=None, outline=None):\n        \"\"\"Draw a polygon.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_polygon(xy, fill, 1)\n        if ink is not None and ink != fill:\n            self.draw.draw_polygon(xy, ink, 0)\n\n    def rectangle(self, xy, fill=None, outline=None, width=1):\n        \"\"\"Draw a rectangle.\"\"\"\n        ink, fill = self._getink(outline, fill)\n        if fill is not None:\n            self.draw.draw_rectangle(xy, fill, 1)\n        if ink is not None and ink != fill and width != 0:\n            self.draw.draw_rectangle(xy, ink, 0, width)\n\n    def _multiline_check(self, text):\n        \"\"\"Draw text.\"\"\"\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return split_character in text\n\n    def _multiline_split(self, text):\n        split_character = \"\\n\" if isinstance(text, str) else b\"\\n\"\n\n        return text.split(split_character)\n\n    def text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n        *args,\n        **kwargs\n    ):\n        if self._multiline_check(text):\n            return self.multiline_text(\n                xy,\n                text,\n                fill,\n                font,\n                anchor,\n                spacing,\n                align,\n                direction,\n                features,\n                language,\n                stroke_width,\n                stroke_fill,\n            )\n\n        if font is None:\n            font = self.getfont()\n\n        def getink(fill):\n            ink, fill = self._getink(fill)\n            if ink is None:\n                return fill\n            return ink\n\n        def draw_text(ink, stroke_width=0, stroke_offset=None):\n            coord = xy\n            try:\n                mask, offset = font.getmask2(\n                    text,\n                    self.fontmode,\n                    direction=direction,\n                    features=features,\n                    language=language,\n                    stroke_width=stroke_width,\n                    *args,\n                    **kwargs,\n                )\n                coord = coord[0] + offset[0], coord[1] + offset[1]\n            except AttributeError:\n                try:\n                    mask = font.getmask(\n                        text,\n                        self.fontmode,\n                        direction,\n                        features,\n                        language,\n                        stroke_width,\n                        *args,\n                        **kwargs,\n                    )\n                except TypeError:\n                    mask = font.getmask(text)\n            if stroke_offset:\n                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]\n            self.draw.draw_bitmap(coord, mask, ink)\n\n        ink = getink(fill)\n        if ink is not None:\n            stroke_ink = None\n            if stroke_width:\n                stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink\n\n            if stroke_ink is not None:\n                # Draw stroked text\n                draw_text(stroke_ink, stroke_width)\n\n                # Draw normal text\n                draw_text(ink, 0, (stroke_width, stroke_width))\n            else:\n                # Only draw normal text\n                draw_text(ink)\n\n    def multiline_text(\n        self,\n        xy,\n        text,\n        fill=None,\n        font=None,\n        anchor=None,\n        spacing=4,\n        align=\"left\",\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n        stroke_fill=None,\n    ):\n        widths = []\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line,\n                font,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n            )\n            widths.append(line_width)\n            max_width = max(max_width, line_width)\n        left, top = xy\n        for idx, line in enumerate(lines):\n            if align == \"left\":\n                pass  # left = x\n            elif align == \"center\":\n                left += (max_width - widths[idx]) / 2.0\n            elif align == \"right\":\n                left += max_width - widths[idx]\n            else:\n                raise ValueError('align must be \"left\", \"center\" or \"right\"')\n            self.text(\n                (left, top),\n                line,\n                fill,\n                font,\n                anchor,\n                direction=direction,\n                features=features,\n                language=language,\n                stroke_width=stroke_width,\n                stroke_fill=stroke_fill,\n            )\n            top += line_spacing\n            left = xy[0]\n\n    def textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        \"\"\"Get the size of a given string, in pixels.\"\"\"\n        if self._multiline_check(text):\n            return self.multiline_textsize(\n                text, font, spacing, direction, features, language, stroke_width\n            )\n\n        if font is None:\n            font = self.getfont()\n        return font.getsize(text, direction, features, language, stroke_width)\n\n    def multiline_textsize(\n        self,\n        text,\n        font=None,\n        spacing=4,\n        direction=None,\n        features=None,\n        language=None,\n        stroke_width=0,\n    ):\n        max_width = 0\n        lines = self._multiline_split(text)\n        line_spacing = (\n            self.textsize(\"A\", font=font, stroke_width=stroke_width)[1] + spacing\n        )\n        for line in lines:\n            line_width, line_height = self.textsize(\n                line, font, spacing, direction, features, language, stroke_width\n            )\n            max_width = max(max_width, line_width)\n        return max_width, len(lines) * line_spacing - spacing\n\n\ndef Draw(im, mode=None):\n    \"\"\"\n    A simple 2D drawing interface for PIL images.\n\n    :param im: The image to draw in.\n    :param mode: Optional mode to use for color values.  For RGB\n       images, this argument can be RGB or RGBA (to blend the\n       drawing into the image).  For all other modes, this argument\n       must be the same as the image mode.  If omitted, the mode\n       defaults to the mode of the image.\n    \"\"\"\n    try:\n        return im.getdraw(mode)\n    except AttributeError:\n        return ImageDraw(im, mode)\n\n\n# experimental access to the outline API\ntry:\n    Outline = Image.core.outline\nexcept AttributeError:\n    Outline = None\n\n\ndef getdraw(im=None, hints=None):\n    \"\"\"\n    (Experimental) A more advanced 2D drawing interface for PIL images,\n    based on the WCK interface.\n\n    :param im: The image to draw in.\n    :param hints: An optional list of hints.\n    :returns: A (drawing context, drawing resource factory) tuple.\n    \"\"\"\n    # FIXME: this needs more work!\n    # FIXME: come up with a better 'hints' scheme.\n    handler = None\n    if not hints or \"nicest\" in hints:\n        try:\n            from . import _imagingagg as handler\n        except ImportError:\n            pass\n    if handler is None:\n        from . import ImageDraw2 as handler\n    if im:\n        im = handler.Draw(im)\n    return im, handler\n\n\ndef floodfill(image, xy, value, border=None, thresh=0):\n    \"\"\"\n    (experimental) Fills a bounded region with a given color.\n\n    :param image: Target image.\n    :param xy: Seed position (a 2-item coordinate tuple). See\n        :ref:`coordinate-system`.\n    :param value: Fill color.\n    :param border: Optional border value.  If given, the region consists of\n        pixels with a color different from the border color.  If not given,\n        the region consists of pixels having the same color as the seed\n        pixel.\n    :param thresh: Optional threshold value which specifies a maximum\n        tolerable difference of a pixel value from the 'background' in\n        order for it to be replaced. Useful for filling regions of\n        non-homogeneous, but similar, colors.\n    \"\"\"\n    # based on an implementation by Eric S. Raymond\n    # amended by yo1995 @20180806\n    pixel = image.load()\n    x, y = xy\n    try:\n        background = pixel[x, y]\n        if _color_diff(value, background) <= thresh:\n            return  # seed point already has fill color\n        pixel[x, y] = value\n    except (ValueError, IndexError):\n        return  # seed point outside image\n    edge = {(x, y)}\n    # use a set to keep record of current and previous edge pixels\n    # to reduce memory consumption\n    full_edge = set()\n    while edge:\n        new_edge = set()\n        for (x, y) in edge:  # 4 adjacent method\n            for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):\n                # If already processed, or if a coordinate is negative, skip\n                if (s, t) in full_edge or s < 0 or t < 0:\n                    continue\n                try:\n                    p = pixel[s, t]\n                except (ValueError, IndexError):\n                    pass\n                else:\n                    full_edge.add((s, t))\n                    if border is None:\n                        fill = _color_diff(p, background) <= thresh\n                    else:\n                        fill = p != value and p != border\n                    if fill:\n                        pixel[s, t] = value\n                        new_edge.add((s, t))\n        full_edge = edge  # discard pixels processed\n        edge = new_edge\n\n\ndef _color_diff(color1, color2):\n    \"\"\"\n    Uses 1-norm distance to calculate difference between two values.\n    \"\"\"\n    if isinstance(color2, tuple):\n        return sum([abs(color1[i] - color2[i]) for i in range(0, len(color2))])\n    else:\n        return abs(color1 - color2)\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** TypeError When Drawing Jointed Lines with Flat Numeric Sequences

**Description:**
When using a flat sequence of numeric values to draw a jointed line with a width greater than 4, a `TypeError` is raised. The drawing function expects each coordinate to be a tuple or list of two integers, but it fails when provided with a flat list or tuple.

**Example Buggy Code:**
```python
from PIL import Image, ImageDraw

im = Image.new("RGB", (500, 325))
draw = ImageDraw.Draw(im)
# Using a flat tuple of integers instead of a list of coordinate pairs
xy = (400, 280, 380, 280, 450, 280, 440, 120, 350, 200, 310, 280)
draw.line(xy, fill="gray", width=50, joint="curve")
```

**Expected Behavior:**
The jointed line should be drawn correctly without errors, handling both flat sequences and sequences of coordinate pairs seamlessly.

**Actual Behavior:**
A `TypeError` is raised with the message: `'int' object is not subscriptable`.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### src/PIL/ImageDraw.py
#
# The Python Imaging Library
# $Id$
#
# drawing interface operations
#
# History:
# 1996-04-13 fl   Created (experimental)
# 1996-08-07 fl   Filled polygons, ellipses.
# 1996-08-13 fl   Added text support
# 1998-06-28 fl   Handle I and F images
# 1998-12-29 fl   Added arc; use arc primitive to draw ellipses
# 1999-01-10 fl   Added shape stuff (experimental)
# 1999-02-06 fl   Added bitmap support
# 1999-02-11 fl   Changed all primitives to take options
# 1999-02-20 fl   Fixed backwards compatibility
# 2000-10-12 fl   Copy on write, when necessary
# 2001-02-18 fl   Use default ink for bitmap/text also in fill mode
# 2002-10-24 fl   Added support for CSS-style color strings
# 2002-12-10 fl   Added experimental support for RGBA-on-RGB drawing
# 2002-12-11 fl   Refactored low-level drawing API (work in progress)
# 2004-08-26 fl   Made Draw() a factory function, added getdraw() support
# 2004-09-04 fl   Added width support to line primitive
# 2004-09-10 fl   Added font mode handling
# 2006-06-19 fl   Added font bearing support (getmask2)
#
# Copyright (c) 1997-2006 by Secret Labs AB
# Copyright (c) 1996-2006 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#

import math
import numbers

from . import Image, ImageColor


"""
A simple 2D drawing interface for PIL images.
<p>
Application code should use the <b>Draw</b> factory, instead of
directly.
"""


class ImageDraw:
    def __init__(self, im, mode=None):
        """
        Create a drawing instance.

        :param im: The image to draw in.
        :param mode: Optional mode to use for color values.  For RGB
           images, this argument can be RGB or RGBA (to blend the
           drawing into the image).  For all other modes, this argument
           must be the same as the image mode.  If omitted, the mode
           defaults to the mode of the image.
        """
        im.load()
        if im.readonly:
            im._copy()  # make it writeable
        blend = 0
        if mode is None:
            mode = im.mode
        if mode != im.mode:
            if mode == "RGBA" and im.mode == "RGB":
                blend = 1
            else:
                raise ValueError("mode mismatch")
        if mode == "P":
            self.palette = im.palette
        else:
            self.palette = None
        self.im = im.im
        self.draw = Image.core.draw(self.im, blend)
        self.mode = mode
        if mode in ("I", "F"):
            self.ink = self.draw.draw_ink(1)
        else:
            self.ink = self.draw.draw_ink(-1)
        if mode in ("1", "P", "I", "F"):
            # FIXME: fix Fill2 to properly support matte for I+F images
            self.fontmode = "1"
        else:
            self.fontmode = "L"  # aliasing is okay for other modes
        self.fill = 0
        self.font = None

    def getfont(self):
        """
        Get the current default font.

        :returns: An image font."""
        if not self.font:
            # FIXME: should add a font repository
            from . import ImageFont

            self.font = ImageFont.load_default()
        return self.font

    def _getink(self, ink, fill=None):
        if ink is None and fill is None:
            if self.fill:
                fill = self.ink
            else:
                ink = self.ink
        else:
            if ink is not None:
                if isinstance(ink, str):
                    ink = ImageColor.getcolor(ink, self.mode)
                if self.palette and not isinstance(ink, numbers.Number):
                    ink = self.palette.getcolor(ink)
                ink = self.draw.draw_ink(ink)
            if fill is not None:
                if isinstance(fill, str):
                    fill = ImageColor.getcolor(fill, self.mode)
                if self.palette and not isinstance(fill, numbers.Number):
                    fill = self.palette.getcolor(fill)
                fill = self.draw.draw_ink(fill)
        return ink, fill

    def arc(self, xy, start, end, fill=None, width=0):
        """Draw an arc."""
        ink, fill = self._getink(fill)
        if ink is not None:
            self.draw.draw_arc(xy, start, end, ink, width)

    def bitmap(self, xy, bitmap, fill=None):
        """Draw a bitmap."""
        bitmap.load()
        ink, fill = self._getink(fill)
        if ink is None:
            ink = fill
        if ink is not None:
            self.draw.draw_bitmap(xy, bitmap.im, ink)

    def chord(self, xy, start, end, fill=None, outline=None, width=1):
        """Draw a chord."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_chord(xy, start, end, fill, 1)
        if ink is not None and ink != fill and width != 0:
            self.draw.draw_chord(xy, start, end, ink, 0, width)

    def ellipse(self, xy, fill=None, outline=None, width=1):
        """Draw an ellipse."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_ellipse(xy, fill, 1)
        if ink is not None and ink != fill and width != 0:
            self.draw.draw_ellipse(xy, ink, 0, width)

    def line(self, xy, fill=None, width=0, joint=None):
        """Draw a line, or a connected sequence of line segments."""
        ink = self._getink(fill)[0]
        if ink is not None:
            self.draw.draw_lines(xy, ink, width)
            if joint == "curve" and width > 4:
                for i in range(1, len(xy) - 1):
                    point = xy[i]
                    angles = [
                        math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))
                        % 360
                        for start, end in ((xy[i - 1], point), (point, xy[i + 1]))
                    ]
                    if angles[0] == angles[1]:
                        # This is a straight line, so no joint is required
                        continue

                    def coord_at_angle(coord, angle):
                        x, y = coord
                        angle -= 90
                        distance = width / 2 - 1
                        return tuple(
                            [
                                p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))
                                for p, p_d in (
                                    (x, distance * math.cos(math.radians(angle))),
                                    (y, distance * math.sin(math.radians(angle))),
                                )
                            ]
                        )

                    flipped = (
                        angles[1] > angles[0] and angles[1] - 180 > angles[0]
                    ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])
                    coords = [
                        (point[0] - width / 2 + 1, point[1] - width / 2 + 1),
                        (point[0] + width / 2 - 1, point[1] + width / 2 - 1),
                    ]
                    if flipped:
                        start, end = (angles[1] + 90, angles[0] + 90)
                    else:
                        start, end = (angles[0] - 90, angles[1] - 90)
                    self.pieslice(coords, start - 90, end - 90, fill)

                    if width > 8:
                        # Cover potential gaps between the line and the joint
                        if flipped:
                            gapCoords = [
                                coord_at_angle(point, angles[0] + 90),
                                point,
                                coord_at_angle(point, angles[1] + 90),
                            ]
                        else:
                            gapCoords = [
                                coord_at_angle(point, angles[0] - 90),
                                point,
                                coord_at_angle(point, angles[1] - 90),
                            ]
                        self.line(gapCoords, fill, width=3)

    def shape(self, shape, fill=None, outline=None):
        """(Experimental) Draw a shape."""
        shape.close()
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_outline(shape, fill, 1)
        if ink is not None and ink != fill:
            self.draw.draw_outline(shape, ink, 0)

    def pieslice(self, xy, start, end, fill=None, outline=None, width=1):
        """Draw a pieslice."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_pieslice(xy, start, end, fill, 1)
        if ink is not None and ink != fill and width != 0:
            self.draw.draw_pieslice(xy, start, end, ink, 0, width)

    def point(self, xy, fill=None):
        """Draw one or more individual pixels."""
        ink, fill = self._getink(fill)
        if ink is not None:
            self.draw.draw_points(xy, ink)

    def polygon(self, xy, fill=None, outline=None):
        """Draw a polygon."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_polygon(xy, fill, 1)
        if ink is not None and ink != fill:
            self.draw.draw_polygon(xy, ink, 0)

    def rectangle(self, xy, fill=None, outline=None, width=1):
        """Draw a rectangle."""
        ink, fill = self._getink(outline, fill)
        if fill is not None:
            self.draw.draw_rectangle(xy, fill, 1)
        if ink is not None and ink != fill and width != 0:
            self.draw.draw_rectangle(xy, ink, 0, width)

    def _multiline_check(self, text):
        """Draw text."""
        split_character = "\n" if isinstance(text, str) else b"\n"

        return split_character in text

    def _multiline_split(self, text):
        split_character = "\n" if isinstance(text, str) else b"\n"

        return text.split(split_character)

    def text(
        self,
        xy,
        text,
        fill=None,
        font=None,
        anchor=None,
        spacing=4,
        align="left",
        direction=None,
        features=None,
        language=None,
        stroke_width=0,
        stroke_fill=None,
        *args,
        **kwargs
    ):
        if self._multiline_check(text):
            return self.multiline_text(
                xy,
                text,
                fill,
                font,
                anchor,
                spacing,
                align,
                direction,
                features,
                language,
                stroke_width,
                stroke_fill,
            )

        if font is None:
            font = self.getfont()

        def getink(fill):
            ink, fill = self._getink(fill)
            if ink is None:
                return fill
            return ink

        def draw_text(ink, stroke_width=0, stroke_offset=None):
            coord = xy
            try:
                mask, offset = font.getmask2(
                    text,
                    self.fontmode,
                    direction=direction,
                    features=features,
                    language=language,
                    stroke_width=stroke_width,
                    *args,
                    **kwargs,
                )
                coord = coord[0] + offset[0], coord[1] + offset[1]
            except AttributeError:
                try:
                    mask = font.getmask(
                        text,
                        self.fontmode,
                        direction,
                        features,
                        language,
                        stroke_width,
                        *args,
                        **kwargs,
                    )
                except TypeError:
                    mask = font.getmask(text)
            if stroke_offset:
                coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]
            self.draw.draw_bitmap(coord, mask, ink)

        ink = getink(fill)
        if ink is not None:
            stroke_ink = None
            if stroke_width:
                stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink

            if stroke_ink is not None:
                # Draw stroked text
                draw_text(stroke_ink, stroke_width)

                # Draw normal text
                draw_text(ink, 0, (stroke_width, stroke_width))
            else:
                # Only draw normal text
                draw_text(ink)

    def multiline_text(
        self,
        xy,
        text,
        fill=None,
        font=None,
        anchor=None,
        spacing=4,
        align="left",
        direction=None,
        features=None,
        language=None,
        stroke_width=0,
        stroke_fill=None,
    ):
        widths = []
        max_width = 0
        lines = self._multiline_split(text)
        line_spacing = (
            self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
        )
        for line in lines:
            line_width, line_height = self.textsize(
                line,
                font,
                direction=direction,
                features=features,
                language=language,
                stroke_width=stroke_width,
            )
            widths.append(line_width)
            max_width = max(max_width, line_width)
        left, top = xy
        for idx, line in enumerate(lines):
            if align == "left":
                pass  # left = x
            elif align == "center":
                left += (max_width - widths[idx]) / 2.0
            elif align == "right":
                left += max_width - widths[idx]
            else:
                raise ValueError('align must be "left", "center" or "right"')
            self.text(
                (left, top),
                line,
                fill,
                font,
                anchor,
                direction=direction,
                features=features,
                language=language,
                stroke_width=stroke_width,
                stroke_fill=stroke_fill,
            )
            top += line_spacing
            left = xy[0]

    def textsize(
        self,
        text,
        font=None,
        spacing=4,
        direction=None,
        features=None,
        language=None,
        stroke_width=0,
    ):
        """Get the size of a given string, in pixels."""
        if self._multiline_check(text):
            return self.multiline_textsize(
                text, font, spacing, direction, features, language, stroke_width
            )

        if font is None:
            font = self.getfont()
        return font.getsize(text, direction, features, language, stroke_width)

    def multiline_textsize(
        self,
        text,
        font=None,
        spacing=4,
        direction=None,
        features=None,
        language=None,
        stroke_width=0,
    ):
        max_width = 0
        lines = self._multiline_split(text)
        line_spacing = (
            self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
        )
        for line in lines:
            line_width, line_height = self.textsize(
                line, font, spacing, direction, features, language, stroke_width
            )
            max_width = max(max_width, line_width)
        return max_width, len(lines) * line_spacing - spacing


def Draw(im, mode=None):
    """
    A simple 2D drawing interface for PIL images.

    :param im: The image to draw in.
    :param mode: Optional mode to use for color values.  For RGB
       images, this argument can be RGB or RGBA (to blend the
       drawing into the image).  For all other modes, this argument
       must be the same as the image mode.  If omitted, the mode
       defaults to the mode of the image.
    """
    try:
        return im.getdraw(mode)
    except AttributeError:
        return ImageDraw(im, mode)


# experimental access to the outline API
try:
    Outline = Image.core.outline
except AttributeError:
    Outline = None


def getdraw(im=None, hints=None):
    """
    (Experimental) A more advanced 2D drawing interface for PIL images,
    based on the WCK interface.

    :param im: The image to draw in.
    :param hints: An optional list of hints.
    :returns: A (drawing context, drawing resource factory) tuple.
    """
    # FIXME: this needs more work!
    # FIXME: come up with a better 'hints' scheme.
    handler = None
    if not hints or "nicest" in hints:
        try:
            from . import _imagingagg as handler
        except ImportError:
            pass
    if handler is None:
        from . import ImageDraw2 as handler
    if im:
        im = handler.Draw(im)
    return im, handler


def floodfill(image, xy, value, border=None, thresh=0):
    """
    (experimental) Fills a bounded region with a given color.

    :param image: Target image.
    :param xy: Seed position (a 2-item coordinate tuple). See
        :ref:`coordinate-system`.
    :param value: Fill color.
    :param border: Optional border value.  If given, the region consists of
        pixels with a color different from the border color.  If not given,
        the region consists of pixels having the same color as the seed
        pixel.
    :param thresh: Optional threshold value which specifies a maximum
        tolerable difference of a pixel value from the 'background' in
        order for it to be replaced. Useful for filling regions of
        non-homogeneous, but similar, colors.
    """
    # based on an implementation by Eric S. Raymond
    # amended by yo1995 @20180806
    pixel = image.load()
    x, y = xy
    try:
        background = pixel[x, y]
        if _color_diff(value, background) <= thresh:
            return  # seed point already has fill color
        pixel[x, y] = value
    except (ValueError, IndexError):
        return  # seed point outside image
    edge = {(x, y)}
    # use a set to keep record of current and previous edge pixels
    # to reduce memory consumption
    full_edge = set()
    while edge:
        new_edge = set()
        for (x, y) in edge:  # 4 adjacent method
            for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
                # If already processed, or if a coordinate is negative, skip
                if (s, t) in full_edge or s < 0 or t < 0:
                    continue
                try:
                    p = pixel[s, t]
                except (ValueError, IndexError):
                    pass
                else:
                    full_edge.add((s, t))
                    if border is None:
                        fill = _color_diff(p, background) <= thresh
                    else:
                        fill = p != value and p != border
                    if fill:
                        pixel[s, t] = value
                        new_edge.add((s, t))
        full_edge = edge  # discard pixels processed
        edge = new_edge


def _color_diff(color1, color2):
    """
    Uses 1-norm distance to calculate difference between two values.
    """
    if isinstance(color2, tuple):
        return sum([abs(color1[i] - color2[i]) for i in range(0, len(color2))])
    else:
        return abs(color1 - color2)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user