def add_destination_box(self, page, direction, destination_name):
        """Add destination boxes to page.

        Args:
            page (Image): Page to add image to.
            direction (str): Direction boat is travelling.
            destination_name (str): Name of destination island.
        """
        draw = ImageDraw.Draw(page)
        textbox_drawer = TextBoxDrawer(page, draw)
        if direction == "left":
            x_position = 0
        else:
            x_position = BOX_WIDTH
        vertices = calculate_box_vertices(
            (x_position, BOX_HEIGHT * 3),
            BOX_WIDTH,
            BOX_HEIGHT,
        )
        text_box = TextBox(
            vertices,
            BOX_WIDTH,
            BOX_HEIGHT,
            font_path=FONT_PATH,
            font_size=50,
            color=FONT_COLOUR,
        )
        textbox_drawer.write_text_box(
            text_box,
            destination_name,
            horiz_just="center",
            vert_just="center",
        )
    def add_island_box(self, page, island_id, island_data):
        """Add island label to top of page.

        Args:
            page (Image): Page to add image to.
            island_id (str): ID of island.
            island_data (dict): Data of island.
        """
        draw = ImageDraw.Draw(page)
        textbox_drawer = TextBoxDrawer(page, draw)
        island_image = Image.open(BASE_PATH.format(island_id))
        island_width, island_height = island_image.size
        coords = (int(BOX_WIDTH - (island_width / 2)),
                  int(((BOX_HEIGHT * 2 * 0.7) - island_height) / 2))
        page.paste(island_image, box=coords)
        island_name_width = BOX_WIDTH * 2
        island_name_height = BOX_HEIGHT * 2 * 0.3
        vertices = calculate_box_vertices(
            (0, BOX_HEIGHT * 2 * 0.7), island_name_width, island_name_height)
        box = TextBox(
            vertices,
            island_name_width,
            island_name_height,
            font_path=FONT_PATH,
            font_size=200,
            color=FONT_COLOUR,
        )
        textbox_drawer.write_text_box(
            box,
            island_data["name"],
            horiz_just="center",
            vert_just="top",
        )
 def test_default_font_override_he(self):
     image = Image.new("RGB", (2000, 4000))
     draw = ImageDraw.Draw(image)
     tbd = TextBoxDrawer(image, draw)
     with translation.override("he"):
         self.assertEqual(tbd.get_default_font(),
                          "static/fonts/OpenSansHebrew-Regular.ttf")
 def test_write_text_box_object_justification_smoke_test(self):
     image = Image.new("RGB", (1000, 1000))
     draw = ImageDraw.Draw(image)
     vertices = [(0, 0), (200, 0), (200, 100), (0, 100)]
     width = 200
     height = 100
     box = TextBox(vertices, width, height)
     for horiz_just in ["left", "center", "right"]:
         for vert_just in ["top", "center", "bottom"]:
             TextBoxDrawer.write_text_box_object(
                 image,
                 draw,
                 box,
                 "This is a string",
                 horiz_just=horiz_just,
                 vert_just=vert_just,
             )
     with translation.override("he"):
         for horiz_just in ["left", "center", "right"]:
             for vert_just in ["top", "center", "bottom"]:
                 TextBoxDrawer.write_text_box_object(
                     image,
                     draw,
                     box,
                     "עברית‬",
                     horiz_just=horiz_just,
                     vert_just=vert_just,
                 )
 def test_default_font_override_ja(self):
     image = Image.new("RGB", (2000, 4000))
     draw = ImageDraw.Draw(image)
     tbd = TextBoxDrawer(image, draw)
     with translation.override("ja"):
         self.assertEqual(tbd.get_default_font(),
                          "static/fonts/NotoSansCJKjp-Regular.otf")
    def test_get_box_core(self):
        svg = os.path.join(BASE_PATH, "basic.svg")
        # In PNG Space, x is *2, and y is *4 from SVG Space
        image = Image.new("RGB", (2000, 4000))
        tbd = TextBoxDrawer(image, None, svg)
        box = tbd.get_box("box1")

        self.assertIsInstance(box, TextBox)
        self.assertIsInstance(box.vertices, list)
        self.assertEqual(4, len(box.vertices))
        x, y = box.vertices[0]
        # SVG x=100, *2 to convert into PNG space
        self.assertAlmostEqual(2 * 100, x)
        # SVG y=200, *4 to convert into PNG space
        self.assertAlmostEqual(4 * 200, y)
        # SVG width=50, *2 to convert into PNG space
        self.assertAlmostEqual(2 * 50.0, box.width)
        # SVG height=75, *4 to convert into PNG space
        self.assertAlmostEqual(4 * 75.0, box.height)
        self.assertEqual("#006838", box.color)
        self.assertEqual("static/fonts/PatrickHand-Regular.ttf", box.font_path)
        # SVG font size is 48px, converted into PNG space
        self.assertEqual(4 * 48, box.font_size)
        self.assertIsInstance(box.font_size, int)
        self.assertEqual(0, box.angle)
    def data(self):
        """Create data for a copy of the Left and Right Cards resource.

        Returns:
            A dictionary of the one page for the resource.
        """
        image_path = "static/img/resources/left-right-cards/left-right-cards.png"
        image = Image.open(image_path)
        draw = ImageDraw.Draw(image)
        textbox_drawer = TextBoxDrawer(image, draw)
        for label, label_data in LABEL_DATA.items():
            label_text = label_data["text"]
            for (top_left, width, height) in label_data["areas"]:
                vertices = calculate_box_vertices(top_left, width, height)
                box = TextBox(vertices,
                              width,
                              height,
                              font_path=FONT_PATH,
                              font_size=FONT_SIZE,
                              angle=label_data["rotation"])
                textbox_drawer.write_text_box(
                    box,
                    label_text,
                    horiz_just="center",
                )
        image = image.rotate(90, expand=True)
        return {"type": "image", "data": image}
 def test_default_font_override_ar(self):
     image = Image.new("RGB", (2000, 4000))
     draw = ImageDraw.Draw(image)
     tbd = TextBoxDrawer(image, draw)
     with translation.override("ar"):
         self.assertEqual(tbd.get_default_font(),
                          "static/fonts/DejaVuSans.ttf")
    def label_keys(self, image, label_type):
        """Label keys on image.

        Args:
            image (Image): PillowImage of image.
            label_type (str): Key of label type.
        """
        draw = ImageDraw.Draw(image)
        textbox_drawer = TextBoxDrawer(image, draw)
        labels = KEY_LABELS[label_type]
        for index, (vertices, width, height) in enumerate(KEY_AREAS):
            position = index % 7
            box = TextBox(
                vertices,
                width,
                height,
                color=LABEL_COLOURS[position],
                font_path="static/fonts/PatrickHand-Regular.ttf",
                font_size=120,
            )
            textbox_drawer.write_text_box(
                box,
                labels[position],
                horiz_just="center",
            )
 def test_fallback_font_if_required_valid_font(self):
     svg = os.path.join(BASE_PATH, "basic.svg")
     image = Image.new("RGB", (1000, 1000))
     tbd = TextBoxDrawer(image, None, svg)
     font_path = "static/fonts/PatrickHand-Regular.ttf"
     font = tbd.fallback_font_if_required(font_path, "abc")
     self.assertEqual(font_path, font)
    def create_map_page(self):
        """Create map page for students.

        Returns:
            A dictionary of the data for the page.
        """
        path = BASE_PATH.format(MAP_TYPE)
        image = Image.open(path)
        draw = ImageDraw.Draw(image)
        textbox_drawer = TextBoxDrawer(image, draw)

        for island_id, island_data in ISLANDS.items():
            box_data = island_data["map-location"]
            top_left_coords = box_data["top-left-coords"]
            width = box_data["width"]
            height = box_data["height"]
            vertices = calculate_box_vertices(top_left_coords, width, height)
            box = TextBox(
                vertices,
                width,
                height,
                font_path=FONT_PATH,
                font_size=80,
                color=FONT_COLOUR,
            )
            textbox_drawer.write_text_box(
                box,
                island_data["name"],
                horiz_just="center",
                vert_just="top",
            )

        image = image.rotate(90, expand=True)
        page_data = {"type": "image", "data": image}
        return page_data
 def test_fallback_font_if_required_ordinal_too_high(self):
     svg = os.path.join(BASE_PATH, "basic.svg")
     image = Image.new("RGB", (1000, 1000))
     tbd = TextBoxDrawer(image, None, svg)
     font_path = "static/fonts/PatrickHand-Regular.ttf"
     new_font_path = tbd.fallback_font_if_required(font_path, chr(300))
     self.assertNotEqual(font_path, new_font_path)
     self.assertEqual(DEFAULT_FONT, new_font_path)
 def text_get_box_without_style(self):
     svg = os.path.join(BASE_PATH, "basic.svg")
     image = Image.new("RGB", (1000, 1000))
     tbd = TextBoxDrawer(image, None, svg)
     box = tbd.get_box("withoutstyle")
     self.assertEqual(None, box.color)
     self.assertEqual(None, box.font_path)
     self.assertEqual(None, box.font_size)
 def text_get_box_with_tspan(self):
     svg = os.path.join(BASE_PATH, "basic.svg")
     image = Image.new("RGB", (1000, 1000))
     tbd = TextBoxDrawer(image, None, svg)
     box = tbd.get_box("withtspan")
     self.assertEqual("#414042", box.color)
     self.assertEqual("static/fonts/PatrickHand-Regular.ttf", box.font_path)
     self.assertEqual(48, box.font_size)
     self.assertIsInstance(box.font_size, int)
 def test_write_text_box_defaults_smoke_test(self):
     image = Image.new("RGB", (2000, 4000))
     draw = ImageDraw.Draw(image)
     tbd = TextBoxDrawer(image, draw)
     vertices = [(0, 0), (200, 0), (200, 100), (0, 100)]
     width = 200
     height = 100
     box = TextBox(vertices, width, height)
     tbd.write_text_box(
         box,
         "This is a string",
     )
 def test_write_text_box_object_rotated_smoke_test(self):
     image = Image.new("RGB", (1000, 1000))
     draw = ImageDraw.Draw(image)
     vertices = [(0, 200), (0, 0), (100, 0), (100, 200)]
     width = 200
     height = 100
     rotation = 90
     box = TextBox(vertices, width, height, angle=rotation)
     TextBoxDrawer.write_text_box_object(
         image,
         draw,
         box,
         "This is a string",
     )
    def test_get_box_rotated(self):
        svg = os.path.join(BASE_PATH, "basic.svg")
        image = Image.new("RGB", (1000, 1000))
        tbd = TextBoxDrawer(image, None, svg)
        box = tbd.get_box("rotated")
        self.assertAlmostEqual(math.radians(45.0), box.angle, places=3)

        # Check location of bottom left corner
        bottomleft_x, bottomleft_y = box.vertices[3]
        self.assertAlmostEqual(bottomleft_x,
                               1 / math.sqrt(2) * box.width,
                               places=1)
        self.assertAlmostEqual(bottomleft_y,
                               1 / math.sqrt(2) * box.height,
                               places=1)
 def test_initialisation_basic_svg(self):
     svg = os.path.join(BASE_PATH, "basic.svg")
     image = Image.new("RGB", (2000, 4000))
     tbd = TextBoxDrawer(image, None, svg)
     self.assertIsInstance(tbd.svg, ET._Element)
     self.assertAlmostEqual(tbd.width_ratio, 2)
     self.assertAlmostEqual(tbd.height_ratio, 4)
 def test_write_text_box_object_params_smoke_test(self):
     image = Image.new("RGB", (1000, 1000))
     draw = ImageDraw.Draw(image)
     vertices = [(0, 0), (200, 0), (200, 100), (0, 100)]
     width = 200
     height = 100
     box = TextBox(vertices, width, height)
     TextBoxDrawer.write_text_box_object(
         image,
         draw,
         box,
         "This is a string",
         font_path="static/fonts/PatrickHand-Regular",
         font_size=17,
         line_spacing=10,
         color="#013291")
 def test_fit_text_smoke_test_one_word(self):
     font_path = "static/fonts/PatrickHand-Regular.ttf"
     font_size = 10
     text = "word"
     font = ImageFont.truetype(font_path, font_size)
     text_width, text_height = font.getsize(text)
     new_font_size, lines, new_text_width, new_text_height = TextBoxDrawer.fit_text(
         text, text_width, text_height, font_path, font_size, 4)
 def test_fit_text_valid_fontsize(self):
     font_path = "static/fonts/PatrickHand-Regular.ttf"
     font_size = 10
     text = "This is a string"
     font = ImageFont.truetype(font_path, font_size * 2)
     text_width, text_height = font.getsize(text)
     new_font_size, lines, new_text_width, new_text_height = TextBoxDrawer.fit_text(
         text, text_width, text_height, font_path, font_size, 4)
     self.assertEqual(new_font_size, font_size)
    def data(self):
        """Create data for a copy of the Job Badges resource.

        Returns:
            A dictionary of the one page for the resource.
        """
        image_path = "static/img/resources/job-badges/job-badges.png"
        image = Image.open(image_path)
        draw = ImageDraw.Draw(image)
        textbox_drawer = TextBoxDrawer(image, draw)

        # coordinates of top left point of text box
        top_left_x_coords = [50, 1200]
        top_left_y_coord = 100

        # Add text labels
        for label, label_text in LABEL_DATA.items():
            for top_left_x_coord in top_left_x_coords:
                vertices = calculate_box_vertices(
                    (top_left_x_coord, top_left_y_coord),
                    TEXTBOX_WIDTH,
                    TEXTBOX_HEIGHT
                )
                box = TextBox(
                    vertices=vertices,
                    width=TEXTBOX_WIDTH,
                    height=TEXTBOX_HEIGHT,
                    font_path=FONT_PATH,
                    font_size=FONT_SIZE,
                )
                textbox_drawer.write_text_box(
                    box,
                    label_text,
                    horiz_just="center",
                    vert_just="center",
                )

            # increase y coord for next name tag down
            top_left_y_coord += 675

        return {"type": "image", "data": image}
示例#23
0
    def data(self):
        """Create data for a copy of the Job Badges resource.

        Returns:
            A dictionary of the one page for the resource.
        """
        path = "static/img/resources/job-badges/job-badges"
        image_path = "{}.png".format(path)
        svg_path = "{}.svg".format(path)
        image = Image.open(image_path)

        draw = ImageDraw.Draw(image)
        textbox_drawer = TextBoxDrawer(image, draw, svg_path)

        hello_ids = [
            "programmer_hello1",
            "programmer_hello2",
            "tester_hello1",
            "tester_hello2",
            "bot_hello1",
            "bot_hello2",
        ]

        for hello_id in hello_ids:
            textbox_drawer.write_text_box(hello_id,
                                          _("Hello, I'm a"),
                                          horiz_just="center")

        for i in range(1, 3):
            textbox_drawer.write_text_box("programmer{}".format(i),
                                          _("Programmer"),
                                          horiz_just="center")
            textbox_drawer.write_text_box("tester{}".format(i),
                                          _("Tester"),
                                          horiz_just="center")
            textbox_drawer.write_text_box("bot{}".format(i),
                                          _("Bot"),
                                          horiz_just="center")

        return {"type": "image", "data": image}
 def test_fit_text_multiple_decrease_loop(self):
     font_path = "static/fonts/PatrickHand-Regular.ttf"
     font_size = 100
     text = "This is a string"
     font = ImageFont.truetype(font_path, font_size)
     text_width, text_height = font.getsize(text)
     new_font_size, lines, new_text_width, new_text_height = TextBoxDrawer.fit_text(
         text,
         text_width * 0.5,  # Force many decrease loops
         text_height,
         font_path,
         font_size,
         4)
     self.assertTrue(new_font_size < font_size)
    def test_fit_text_one_line(self):
        font_path = "static/fonts/PatrickHand-Regular.ttf"
        font_size = 50
        font = ImageFont.truetype(font_path, font_size)
        text = "This is a string"
        text_width, text_height = font.getsize(text)
        new_font_size, lines, new_text_width, new_text_height = TextBoxDrawer.fit_text(
            text, text_width * 2, text_height * 2, font_path, font_size, 4)

        self.assertEqual(1, len(lines))
        self.assertEqual(text, lines[0])
        self.assertEqual(font_size, new_font_size)
        self.assertIsInstance(new_text_width, int)
        self.assertIsInstance(new_text_height, int)
示例#26
0
    def data(self):
        """Create data for a copy of the Grid resource.

        Returns:
            A dictionary of the one page for the resource.
        """
        path = "static/img/resources/barcode-checksum-poster/{}-digits"
        barcode_length = self.options["barcode_length"].value
        path = path.format(barcode_length)
        image_path = "{}.png".format(path)
        svg_path = "{}.svg".format(path)
        image = Image.open(image_path)

        draw = ImageDraw.Draw(image)
        textbox_drawer = TextBoxDrawer(image, draw, svg_path)

        textbox_drawer.write_text_box(
            "title",
            _("{} Digit Barcode".format(barcode_length)),
            horiz_just="center",
        )

        headings = {
            "heading1": _("Separate!"),
            "heading2": _("Operate!"),
            "heading3": _("Calculate!")
        }

        for heading_id, heading in headings.items():
            textbox_drawer.write_text_box(
                heading_id,
                heading,
            )

        textbox_drawer.write_text_box(
            "paragraph",
            _("Remember that this algorithm uses modulo 10, so we are only "
              "interested in the number in the one's column."),
        )

        return {"type": "image", "data": image}
 def test_fit_text_decrease_fontsize(self):
     font_path = "static/fonts/PatrickHand-Regular.ttf"
     font_size = 50
     font = ImageFont.truetype(font_path, font_size)
     text = "This is a string"
     text_width, text_height = font.getsize(text)
     new_font_size, lines, new_text_width, new_text_height = TextBoxDrawer.fit_text(
         text,
         text_width *
         0.8,  # Make box slightly narrower than text, to force 2 lines
         text_height,  # Make box too short to force smaller text
         font_path,
         font_size,
         4)
     self.assertEqual(text, "".join(lines))
     self.assertTrue(new_font_size < font_size)
     self.assertTrue(new_font_size > 1)
     self.assertIsInstance(new_text_width, int)
     self.assertIsInstance(new_text_height, int)
    def data(self):
        """Create data for a copy of the Number Hunt resource.

        Returns:
            A dictionary of the two pages for the resource.
        """
        pages = []

        prefilled_values = self.options["prefilled_values"].value
        number_order = self.options["number_order"].value

        image = Image.open(IMAGE_PATH.format("template"))
        draw = ImageDraw.Draw(image)
        textbox_drawer = TextBoxDrawer(image, draw)

        # Add text labels
        for label_id, label_data in LABEL_DATA.items():
            if label_id == "subtitle":
                label_text = self.subtitle_text()
            else:
                label_text = label_data["text"]
            top_left_coords = label_data["top-left-coords"]
            width = label_data["width"]
            height = label_data["height"]
            vertices = calculate_box_vertices(top_left_coords, width, height)
            box = TextBox(
                vertices,
                width,
                height,
                font_path=FONT_PATH,
                font_size=label_data["font-size"],
                color=label_data["font-colour"],
            )
            textbox_drawer.write_text_box(
                box,
                label_text,
                horiz_just=label_data["horiz-just"],
                vert_just=label_data["vert-just"],
            )

        # Add numbers to image (if required)
        if prefilled_values != "blank":
            range_min, range_max, font_size = self.get_number_range(
                prefilled_values)
            total_numbers = 31
            numbers = sample(range(range_min, range_max), total_numbers)
            if number_order == "sorted":
                numbers.sort()

            coord_x = 106
            base_coord_y = 161
            coord_y_increment = 107.8
            width = 264
            height = 88
            for i, number in enumerate(numbers):
                coord_y = base_coord_y + (coord_y_increment * i)
                vertices = calculate_box_vertices((coord_x, coord_y), width,
                                                  height)
                box = TextBox(
                    vertices,
                    width,
                    height,
                    font_path=FONT_PATH,
                    font_size=font_size,
                )
                textbox_drawer.write_text_box(
                    box,
                    str(number),
                    horiz_just="center",
                    vert_just="center",
                )
        pages.append({
            "type": "resource-number-hunt",
            "data": [image, INSTRUCTIONS_HTML],
            "thumbnail": True
        })
        return pages
 def test_get_box_id_with_underscore(self):
     svg = os.path.join(BASE_PATH, "basic.svg")
     image = Image.new("RGB", (2000, 4000))
     tbd = TextBoxDrawer(image, None, svg)
     tbd.get_box("element_2")
 def test_get_box_id_start_with_digit(self):
     svg = os.path.join(BASE_PATH, "basic.svg")
     image = Image.new("RGB", (2000, 4000))
     tbd = TextBoxDrawer(image, None, svg)
     tbd.get_box("123")