diff --git a/test/fixtures/page_generation/page.py b/test/fixtures/page_generation/page.py index e9e4e23..e106104 100644 --- a/test/fixtures/page_generation/page.py +++ b/test/fixtures/page_generation/page.py @@ -344,7 +344,7 @@ def size(dpi, orientation): def superimpose_texture_with_transparency(page: Image, texture: Image) -> Image: """Superimposes a noise image with transparency onto a page image.""" if page.size != texture.size: - logger.debug(f"Padding image before pasting to fit size {page.size}") + logger.trace(f"Padding image before pasting to fit size {page.size}") texture = pad_image_to_size(texture, page.size) assert page.size == texture.size assert texture.mode == "RGBA" @@ -460,9 +460,13 @@ class RandomContentRectangle(ContentRectangle): class Size(Enum): - SMALL = sqrt(100**2) - MEDIUM = sqrt((100 * 5) ** 2) - LARGE = sqrt((100 * 10) ** 2) + # SMALL = sqrt(100**2) + # MEDIUM = sqrt((100 * 3) ** 2) + # LARGE = sqrt((100 * 10) ** 2) + + SMALL = 100 + MEDIUM = 170 + LARGE = 200 def get_size_class(rectangle: Rectangle): @@ -490,7 +494,7 @@ class RecursiveRandomTable(RandomContentRectangle): self.content = Image.new("RGBA", (self.width, self.height), (255, 255, 255, 255)) self.background_color = tuple([random.randint(0, 100) for _ in range(4)]) self.cell_border_color = (*map(lambda x: int(x * 0.8), self.background_color[:3]), 255) - self.draw_single_cell_borders(self, border_width) + self.draw_single_cell_borders(self, border_width, fill=self.background_color) def generate_random_table(self): cells = list(self.generate_cells_with_content()) @@ -499,27 +503,30 @@ class RecursiveRandomTable(RandomContentRectangle): def generate_cells_with_content(self): for cell in self.generate_table(): - self.draw_single_cell_borders(cell) + self.draw_single_cell_borders(cell, fill=self.background_color, width=2) def inner(cell): - inner_region = shrink_rectangle(cell, 0.1) + inner_region = shrink_rectangle(cell, 0.2) choice = random.choice(["text", "plot", "recurse", "plain_table", "blank"]) size = get_size(inner_region) if size <= Size.SMALL.value: - return generate_random_text_block(inner_region) + words = generate_random_words(4, 6) + return generate_text_block(cell, " ".join(words)) elif size <= Size.MEDIUM.value: if choice == "plain_table": - return generate_random_table(cell) - elif choice == "plot": + return generate_random_table(inner_region) + # cell.content = generate_random_table(inner_region).content + # return cell + elif choice == "plot" and is_square_like(cell): return generate_random_plot(cell) else: - cell = generate_text_block(cell, f"{choice} {size:.0f} {get_size_class(cell).name}") - return cell + return generate_text_block(cell, f"{choice} {size:.0f} {get_size_class(cell).name}") elif size <= Size.LARGE.value: + logger.debug(f"Generating {choice} {size:.0f} {get_size_class(cell).name}") if choice == "plot" and is_square_like(cell): return generate_random_plot(cell) # elif choice == "plain_table": @@ -527,12 +534,13 @@ class RecursiveRandomTable(RandomContentRectangle): elif choice == "blank": return cell else: - return generate_recursive_random_table(cell, border_width=0) + logger.debug(f"recurse {size:.0f} {get_size_class(cell).name}") + return generate_recursive_random_table(inner_region, border_width=5) else: - cell = generate_text_block(cell, f"{choice} {size:.0f} {get_size_class(cell).name}") - return cell + return generate_text_block(cell, f"{choice} {size:.0f} {get_size_class(cell).name}") - cell.content = inner(cell).content + cell = inner(cell) + # self.draw_single_cell_borders(cell, fill=None, width=2) assert cell.content.mode == "RGBA" @@ -540,14 +548,14 @@ class RecursiveRandomTable(RandomContentRectangle): def draw_cell_borders(self, cells: List[ContentRectangle]): for cell in cells: - self.draw_single_cell_borders(cell) + self.draw_single_cell_borders(cell, fill=self.background_color) - def draw_single_cell_borders(self, cell: ContentRectangle, width=1): + def draw_single_cell_borders(self, cell: ContentRectangle, width=1, fill=None): + fill = (0, 0, 0, 0) if fill is None else fill image = cell.content or Image.new("RGBA", (cell.width, cell.height), (255, 255, 255)) + assert image.mode == "RGBA" draw = ImageDraw.Draw(image) - draw.rectangle( - (0, 0, cell.width, cell.height), fill=self.background_color, outline=self.cell_border_color, width=width - ) + draw.rectangle((0, 0, cell.width, cell.height), fill=fill, outline=self.cell_border_color, width=width) cell.content = image assert cell.content.mode == "RGBA" return cell @@ -556,7 +564,7 @@ class RecursiveRandomTable(RandomContentRectangle): yield from mapcat(self.generate_column, range(self.n_columns)) def generate_column(self, column_index) -> Iterable[ContentRectangle]: - logger.debug(f"Generating column {column_index}.") + logger.trace(f"Generating column {column_index}.") generate_cell_content_for_row = partial(self.generate_cell, column_index) yield from map(generate_cell_content_for_row, range(self.n_rows)) @@ -564,7 +572,7 @@ class RecursiveRandomTable(RandomContentRectangle): w, h = self.cell_size x1, y1 = (column_index * w), (row_index * h) x2, y2 = x1 + w, y1 + h - logger.debug(f"Generating cell ({row_index}, {column_index}) at ({x1}, {y1}, {x2}, {y2}).") + logger.trace(f"Generating cell ({row_index}, {column_index}) at ({x1}, {y1}, {x2}, {y2}).") return ContentRectangle(x1, y1, x2, y2) def generate_column_names(self): @@ -572,26 +580,71 @@ class RecursiveRandomTable(RandomContentRectangle): return column_names def generate_column_name(self): - column_name = Faker().words(random.randint(1, 3)) + column_name = generate_random_words(1, 3) return column_name +def generate_random_words(n_min, n_max): + column_name = Faker().words(random.randint(n_min, n_max)) + return column_name + + def shrink_rectangle(rectangle: Rectangle, factor: float) -> Rectangle: x1, y1, x2, y2 = compute_scaled_coordinates(rectangle, factor) + + logger.trace(f"Shrinking {rectangle} by {factor} to ({x1}, {y1}, {x2}, {y2}).") + + assert x1 > rectangle.x1 + assert y1 > rectangle.y1 + assert x2 < rectangle.x2 + assert y2 < rectangle.y2 + shrunk_rectangle = Rectangle(x1, y1, x2, y2) + if isinstance(rectangle, ContentRectangle): # TODO: Refactor shrunk_rectangle = ContentRectangle(*shrunk_rectangle.coords, rectangle.content) + return shrunk_rectangle def compute_scaled_coordinates(rectangle: Rectangle, factor: float) -> Tuple[int, int, int, int]: - width = rectangle.width * (1 - factor) - height = rectangle.height * (1 - factor) - x1 = rectangle.x1 + (rectangle.width - width) / 2 - y1 = rectangle.y1 + (rectangle.height - height) / 2 - x2 = x1 + width - y2 = y1 + height - return tuple(lmap(int, (x1, y1, x2, y2))) + # TODO: Refactor: Using image to compute coordinates is not clean + image = Image.new("RGBA", (rectangle.width, rectangle.height)) + scaled = image.resize((int(rectangle.width * (1 - factor)), int(rectangle.height * (1 - factor)))) + + x1, y1 = compute_pasting_coordinates(scaled, image) + x1 = rectangle.x1 + x1 + y1 = rectangle.y1 + y1 + x2, y2 = x1 + scaled.width, y1 + scaled.height + return x1, y1, x2, y2 + + # return tuple( + # map( + # int, + # ( + # rectangle.x1 + factor * rectangle.width, + # rectangle.y1 + factor * rectangle.height, + # rectangle.x2 - factor * rectangle.width, + # rectangle.y2 - factor * rectangle.height, + # ), + # ) + # ) + + # x1, y1, x2, y2 = rectangle.coords + # width, height = rectangle.width, rectangle.height + # x1 += width * (1 - factor) / 2 + # y1 += height * (1 - factor) / 2 + # x2 -= width * (1 - factor) / 2 + # y2 -= height * (1 - factor) / 2 + # return int(x1), int(y1), int(x2), int(y2) + + # width = rectangle.width * (1 - factor) + # height = rectangle.height * (1 - factor) + # x1 = rectangle.x1 + (rectangle.width - width) // 2 + # y1 = rectangle.y1 + (rectangle.height - height) // 2 + # x2 = x1 + width + # y2 = y1 + height + # return tuple(lmap(int, (x1, y1, x2, y2))) class RandomTable(RandomContentRectangle): @@ -684,7 +737,7 @@ class RandomFontPicker: fonts = filter(self.font_is_renderable, fonts) # FIXME: this does not work font = first(fonts) - logger.debug(f"Using font: {font}") + logger.trace(f"Using font: {font}") return font def shuffle_fonts(self): @@ -886,10 +939,14 @@ class TextBlock(ContentRectangle): text_width, text_height = self.font.getsize(text) - assert text_width <= rectangle.width - assert text_height <= rectangle.height + width_delta = text_width - rectangle.width + height_delta = text_height - rectangle.height image = Image.new("RGBA", (text_width, text_height), (0, 255, 255, 0)) + + if width_delta > 0 or height_delta > 0: + image = image.resize((rectangle.width, text_height)) + draw = ImageDraw.Draw(image) draw.text((0, 0), text, font=self.font, fill=(0, 0, 0, 255)) return self.__put_content(image)