Skip to content

Commit

Permalink
improve(DI): move image_generator, nomenclature_facade declaration to…
Browse files Browse the repository at this point in the history
… DI container
  • Loading branch information
likeinlife committed Feb 18, 2024
1 parent d562e39 commit 738ede2
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 135 deletions.
3 changes: 2 additions & 1 deletion src/cartography/facades/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
"""Facades for making nomenclature images from coordinates and nomenclature title."""
"""Facades for making nomenclature images from coordinates and nomenclature title."""
from .nomenclature_facade import NomenclatureFacade
49 changes: 0 additions & 49 deletions src/cartography/facades/image_facade.py

This file was deleted.

80 changes: 40 additions & 40 deletions src/cartography/facades/nomenclature_facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from cartography.chain.interfaces import ICoordinateChainLink, INomenclatureTitleChainLink
from cartography.enums import Scale
from cartography.image_generator import IImageGenerator
from cartography.models import CoordinatePair, Nomenclature
from cartography.scale_resolver import (
coordinate_chain_link_resolver,
Expand All @@ -15,59 +16,58 @@


class NomenclatureFacade(INomenclatureFacade):
@staticmethod
def generate_from_coordinates(coordinate_pair: CoordinatePair, needed_scale: int) -> list[ImageType]:
def __init__(self, image_generator: IImageGenerator) -> None:
self.image_generator = image_generator

def generate_from_coordinates(self, coordinate_pair: CoordinatePair, needed_scale: int) -> list[ImageType]:
chain_link = coordinate_resolver.get_scale(needed_scale)
nomenclatures_dict = chain_link.resolve(coordinate_pair)
return _generate_image_list(nomenclatures_dict, coordinate_chain_link_resolver.get_chain_link)
return self._generate_image_list(nomenclatures_dict, coordinate_chain_link_resolver.get_chain_link)

@staticmethod
def generate_from_nomenclature(nomenclature: str) -> list[ImageType]:
def generate_from_nomenclature(self, nomenclature: str) -> list[ImageType]:
chain_link, nomenclature_title_dict = nomenclature_title_resolver.parse_nomenclature_string(nomenclature)
nomenclatures_dict = chain_link.resolve(nomenclature_title_dict)

return _generate_image_list(
return self._generate_image_list(
nomenclatures_dict,
nomenclature_title_chain_link_resolver.get_chain_link,
)

def _generate_image_list(
self,
nomenclature_dict: dict[Scale, Nomenclature],
resolver: Callable[[Scale], type[ICoordinateChainLink | INomenclatureTitleChainLink]],
) -> list[ImageType]:
images: list[ImageType] = []
for scale, nomenclature in nomenclature_dict.items():
cur_chain_link = resolver(scale)

def _generate_image_list(
nomenclature_dict: dict[Scale, Nomenclature],
resolver: Callable[[Scale], type[ICoordinateChainLink | INomenclatureTitleChainLink]],
) -> list[ImageType]:
from .image_facade import ImageGeneratorFacade

images: list[ImageType] = []
for scale, nomenclature in nomenclature_dict.items():
cur_chain_link = resolver(scale)
outbound = cur_chain_link.previous_link

outbound = cur_chain_link.previous_link
if outbound:
outbound_nomenclature = nomenclature_dict[outbound.scale]
outbound_info = resolver(outbound.scale)
outer_title = f"{outbound_nomenclature.title} ({outbound_info.name})"
images.append(
self.image_generator.generate(
upper_bound=nomenclature.outer_upper_bound,
lower_bound=nomenclature.outer_lower_bound,
cell_to_fill=nomenclature.cell_to_fill,
title=outer_title,
parts=cur_chain_link.parts,
alphabet=cur_chain_link.alphabet,
)
)

if outbound:
outbound_nomenclature = nomenclature_dict[outbound.scale]
outbound_info = resolver(outbound.scale)
outer_title = f"{outbound_nomenclature.title} ({outbound_info.name})"
title = f"{nomenclature.title} ({cur_chain_link.name})"
images.append(
ImageGeneratorFacade.generate(
upper_bound=nomenclature.outer_upper_bound,
lower_bound=nomenclature.outer_lower_bound,
cell_to_fill=nomenclature.cell_to_fill,
title=outer_title,
parts=cur_chain_link.parts,
alphabet=cur_chain_link.alphabet,
self.image_generator.generate(
upper_bound=nomenclature.upper_bound,
lower_bound=nomenclature.lower_bound,
cell_to_fill=None,
title=title,
parts=1,
alphabet=[" "],
)
)

title = f"{nomenclature.title} ({cur_chain_link.name})"
images.append(
ImageGeneratorFacade.generate(
upper_bound=nomenclature.upper_bound,
lower_bound=nomenclature.lower_bound,
cell_to_fill=None,
title=title,
parts=1,
alphabet=[" "],
)
)
return images
return images
41 changes: 22 additions & 19 deletions src/cartography/image_drawer/labels_drawer.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,43 @@
from pathlib import Path

from container import ImageContainer
from dependency_injector.wiring import Provide, inject
from PIL import Image, ImageDraw, ImageFont

from cartography.math_actions import coordinate_actions
from cartography.models import Coordinate
from cartography.types import ImageColorType


@inject
def draw_labels(
img: Image.Image,
parts: int,
x_values: list[Coordinate],
y_values: list[Coordinate],
padding: int = Provide[ImageContainer.settings.padding],
font_path: Path = Provide[ImageContainer.settings.font_path],
text_color: ImageColorType = Provide[ImageContainer.settings.text_color],
text_size_coefficient: int = Provide[ImageContainer.settings.text_size_coefficient],
text_angle: int = Provide[ImageContainer.settings.text_angle],
bottom_label_offset: int = Provide[ImageContainer.settings.bottom_label_offset],
right_label_offset: int = Provide[ImageContainer.settings.right_label_offset],
padding: int,
font_path: Path,
text_color: ImageColorType,
text_size_coefficient: int,
text_angle: int,
bottom_label_offset: int,
right_label_offset: int,
) -> None:
"""
Generate labels in bottom and right of table.
Generate labels in bottom and right part of table.
Args:
----
table_image (Image): Image with table
parts (int): parts number. Example: 16x16 => parts=16
x_values (list): columns labels
y_values (list): rows labels
x_delta (int): cell width
y_delta (int): cell height
pad (int): padding from image borders
table_image: Image with table
parts: parts number. Example: 16x16 => parts=16
x_values: columns labels
y_values: rows labels
x_delta: cell width
y_delta: cell height
padding: padding from image borders
font_path: path to .otf file
text_color: text color
text_size_coefficient: font size calculates from padding
text_angle: in degrees
bottom_label_offset: offset from bottom
right_label_offset: offset from right
"""
img_draw = ImageDraw.Draw(img)
x_delta = (img.size[0] - padding * 2) // parts
Expand Down
26 changes: 15 additions & 11 deletions src/cartography/image_drawer/table_drawer.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
from pathlib import Path
from typing import Any

from container import ImageContainer
from dependency_injector.wiring import Provide, inject
from PIL import Image, ImageDraw, ImageFont

from cartography.types import ImageColorType


@inject
def draw_table(
img: Image.Image,
parts: int,
alphabet: list[str],
title: str = "Nomenclature",
cell_to_fill: str | None = None,
padding: int = Provide[ImageContainer.settings.padding],
font_path: Path = Provide[ImageContainer.settings.font_path],
text_color: ImageColorType = Provide[ImageContainer.settings.text_color],
inverse_text_color: ImageColorType = Provide[ImageContainer.settings.inverse_text_color],
background_color: ImageColorType = Provide[ImageContainer.settings.background_color],
filling_color: ImageColorType = Provide[ImageContainer.settings.filling_color],
title: str,
cell_to_fill: str | None,
padding: int,
font_path: Path,
text_color: ImageColorType,
inverse_text_color: ImageColorType,
background_color: ImageColorType,
filling_color: ImageColorType,
) -> None:
"""
Draw table with cells content.
Expand All @@ -32,6 +29,13 @@ def draw_table(
title: Table name
alphabet: Alphabet
cell_to_fill: Cell name to fill
padding: padding from image borders
font_path: path to .otf file
text_color: text color
inverse_text_color: text color on filled cell
background_color: background color
filling_color: filled cell color
"""

def need_to_fill(x: Any) -> bool:
Expand Down
2 changes: 2 additions & 0 deletions src/cartography/image_generator/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .interface import IImageGenerator
from .generator import ImageGenerator
86 changes: 86 additions & 0 deletions src/cartography/image_generator/generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from io import BytesIO
from pathlib import Path

from PIL import Image

from cartography.image_drawer import draw_labels, draw_table
from cartography.math_actions import coordinate_actions
from cartography.models import CoordinatePair
from cartography.types import ImageColorType, ImageType

from .interface import IImageGenerator


class ImageGenerator(IImageGenerator):
def __init__(
self,
resolution: tuple[int, int],
background_color: ImageColorType,
font_path: Path,
padding: int,
text_color: ImageColorType,
inverse_text_color: ImageColorType,
filling_color: ImageColorType,
text_size_coefficient: int,
text_angle: int,
bottom_label_offset: int,
right_label_offset: int,
) -> None:
self.resolution = resolution
self.background_color = background_color
self.inverse_text_color = inverse_text_color
self.filling_color = filling_color
self.padding = padding
self.font_path = font_path
self.text_color = text_color
self.text_size_coefficient = text_size_coefficient
self.text_angle = text_angle
self.bottom_label_offset = bottom_label_offset
self.right_label_offset = right_label_offset

def generate(
self,
upper_bound: CoordinatePair,
lower_bound: CoordinatePair,
cell_to_fill: str | None,
title: str,
parts: int,
alphabet: list[str],
) -> ImageType:
in_memory_file = BytesIO()
image = Image.new("RGB", self.resolution, self.background_color)

draw_table(
img=image,
parts=parts,
title=title,
alphabet=alphabet,
cell_to_fill=cell_to_fill,
background_color=self.background_color,
filling_color=self.filling_color,
font_path=self.font_path,
inverse_text_color=self.inverse_text_color,
padding=self.padding,
text_color=self.text_color,
)
x_values = coordinate_actions.get_middle_list(lower_bound.longitude, upper_bound.longitude, parts)
y_values = coordinate_actions.get_middle_list(lower_bound.latitude, upper_bound.latitude, parts)
y_values.reverse()

draw_labels(
img=image,
parts=parts,
x_values=x_values,
y_values=y_values,
bottom_label_offset=self.bottom_label_offset,
font_path=self.font_path,
padding=self.padding,
right_label_offset=self.right_label_offset,
text_angle=self.text_angle,
text_color=self.text_color,
text_size_coefficient=self.text_size_coefficient,
)

image.save(in_memory_file, "JPEG")

return in_memory_file.getvalue()
18 changes: 18 additions & 0 deletions src/cartography/image_generator/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import abc

from cartography.models import CoordinatePair
from cartography.types import ImageType


class IImageGenerator(abc.ABC):
@abc.abstractmethod
def generate(
self,
upper_bound: CoordinatePair,
lower_bound: CoordinatePair,
cell_to_fill: str | None,
title: str,
parts: int,
alphabet: list[str],
) -> ImageType:
"""Generate image with table and labels."""
Loading

0 comments on commit 738ede2

Please sign in to comment.