1 """Image processing for cameras."""
3 from __future__
import annotations
5 from contextlib
import suppress
7 from typing
import TYPE_CHECKING, Literal, cast
9 with suppress(Exception):
14 from turbojpeg
import TurboJPEG
20 SUPPORTED_SCALING_FACTORS = [(7, 8), (3, 4), (5, 8), (1, 2), (3, 8), (1, 4), (1, 8)]
22 _LOGGER = logging.getLogger(__name__)
28 current_width: int, current_height: int, target_width: int, target_height: int
29 ) -> tuple[int, int] |
None:
30 """Find a supported scaling factor to scale the image.
32 If there is no exact match, we use one size up to ensure
33 the image remains crisp.
35 for idx, supported_sf
in enumerate(SUPPORTED_SCALING_FACTORS):
36 ratio = supported_sf[0] / supported_sf[1]
37 width_after_scale = current_width * ratio
38 height_after_scale = current_height * ratio
39 if width_after_scale == target_width
and height_after_scale == target_height:
41 if width_after_scale < target_width
or height_after_scale < target_height:
42 return None if idx == 0
else SUPPORTED_SCALING_FACTORS[idx - 1]
45 return SUPPORTED_SCALING_FACTORS[-1]
49 """Scale a camera image.
51 Scale as close as possible to one of the supported scaling factors.
53 turbo_jpeg = TurboJPEGSingleton.instance()
55 return cam_image.content
58 (current_width, current_height, _, _) = turbo_jpeg.decode_header(
62 return cam_image.content
65 current_width, current_height, width, height
67 if scaling_factor
is None:
68 return cam_image.content
72 turbo_jpeg.scale_with_quality(
74 scaling_factor=scaling_factor,
81 """Load TurboJPEG only once.
83 Ensures we do not log load failures each snapshot
84 since camera image fetches happen every few
88 __instance: TurboJPEG | Literal[
False] |
None =
None
91 def instance() -> TurboJPEG | Literal[False] | None:
92 """Singleton for TurboJPEG."""
93 if TurboJPEGSingleton.__instance
is None:
95 return TurboJPEGSingleton.__instance
98 """Try to create TurboJPEG only once."""
100 TurboJPEGSingleton.__instance = TurboJPEG()
103 "Error loading libturbojpeg; Camera snapshot performance will be sub-optimal"
105 TurboJPEGSingleton.__instance =
False
111 TurboJPEGSingleton.instance()
TurboJPEG|Literal[False]|None instance()
tuple[int, int]|None find_supported_scaling_factor(int current_width, int current_height, int target_width, int target_height)
bytes scale_jpeg_camera_image(Image cam_image, int width, int height)