Source code for fibomat.default_backends.bitmap_backend
from fibomat.shapes.polyline import Polyline
from typing import Optional, Dict
import io
from PIL import Image, ImageDraw
import numpy as np
import svgwrite
import svgwrite.container
import svgwrite.shapes
import svgwrite.extensions
from fibomat.backend import BackendBase
from fibomat.site import Site
from fibomat.units import U_, Q_, scale_factor
from fibomat.utils import PathLike
from fibomat.pattern import Pattern
from fibomat.shapes import Rect, Polygon, Circle
from fibomat.linalg import DimBoundingBox, scale, translate, Vector, DimVector
[docs]class BitmapBackend(BackendBase):
[docs] def __init__(self, pixel_size: Q_ = Q_('2 nm'), description: Optional[str] = None):
super().__init__()
self._description = description
self._pixel_size = pixel_size
self._site = None
# self._current_layer: Optional[Dict] = None
self._center: Optional[Vector] = None
self._image: Optional = None
self._total_bounding_box = None
[docs] def save(self, filename: str):
if self._image:
self._image.save(filename)
else:
raise RuntimeError('No site added.')
[docs] def image(self):
return self._image
[docs] def process_site(self, new_site: Site) -> None:
if self._image:
raise RuntimeError('Only one site is allowed in bitmap backend.')
self._site = new_site
self._shift = DimVector(new_site.fov[0] / 2, new_site.fov[1] / 2)
width = int(np.rint((new_site.fov[0] / self._pixel_size).to_base_units()))
height = int(np.rint((new_site.fov[1] / self._pixel_size).to_base_units()))
self._image = Image.new("L", (width, height), 'black')
super().process_site(new_site)
def _to_pixel(self, value):
return int(np.rint((value / self._pixel_size).to_base_units()))
# def _pixel_scale_factor(self, other_unit):
# return scale_factor(self._pixel_scale, other_unit) / self._pixel_scale.m
# def _scale_and_shift_shape(self, ptn: Pattern):
# fak = self._pixel_scale_factor(ptn.dim_shape.unit)
# return ptn.dim_shape.shape.transformed(scale(fak) | translate(self._current_layer_center))
[docs] def rect(self, ptn: Pattern[Rect]) -> None:
# return super().rect(ptn)
ptn = ptn.translated(self._shift)
# print(self._image.size)
points = ptn.dim_shape.shape.to_arc_spline().vertices[:, :2]
pixel_points = [(self._to_pixel(x * ptn.dim_shape.unit), self._image.size[1] -self._to_pixel(y * ptn.dim_shape.unit)) for x, y in points]
# print(pixel_points)
draw = ImageDraw.Draw(self._image)
draw.polygon(pixel_points, 'white')
# def polygon(self, ptn: Pattern[Polygon]) -> None:
# return super().polygon(ptn)