forked from anki/vector-python-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathphotos.py
More file actions
145 lines (111 loc) · 5.36 KB
/
photos.py
File metadata and controls
145 lines (111 loc) · 5.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# Copyright (c) 2018 Anki, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License in the file LICENSE.txt or at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Photo related classes, functions, events and values.
"""
# __all__ should order by constants, event classes, other classes, functions.
__all__ = ["PhotographComponent"]
import concurrent
from typing import List
from . import connection, util
from .messaging import protocol
class PhotographComponent(util.Component):
"""Access the photos on Vector.
.. testcode::
import anki_vector
import io
from PIL import Image
with anki_vector.Robot() as robot:
for photo_info in robot.photos.photo_info:
print(f"Opening photo {photo_info.photo_id}")
photo = robot.photos.get_photo(photo_info.photo_id)
image = Image.open(io.BytesIO(photo.image))
image.show()
:param anki_vector.Robot robot: A reference to an instance of the Robot class. Used to make rpc calls.
"""
def __init__(self, robot):
super().__init__(robot)
self._photo_info: List[protocol.PhotoInfo] = []
@property
def photo_info(self) -> List[protocol.PhotoInfo]:
"""The information about what photos are stored on Vector.
If the photo info hasn't been loaded yet, accessing this property will request it from the robot.
.. testcode::
import anki_vector
with anki_vector.Robot() as robot:
for photo_info in robot.photos.photo_info:
print(f"photo_info.photo_id: {photo_info.photo_id}") # the id to use to grab a photo from the robot
print(f"photo_info.timestamp_utc: {photo_info.timestamp_utc}") # utc timestamp of when the photo was taken (according to the robot)
"""
if not self._photo_info:
self.logger.debug("Photo list was empty. Lazy-loading photo list now.")
result = self.load_photo_info()
if isinstance(result, concurrent.futures.Future):
result.result()
return self._photo_info
@connection.on_connection_thread()
async def load_photo_info(self) -> protocol.PhotosInfoResponse:
"""Request the photo information from the robot.
.. testcode::
import anki_vector
with anki_vector.Robot() as robot:
photo_info = robot.photos.load_photo_info()
print(f"photo_info: {photo_info}")
:return: UTC timestamp of the photo and additional data.
"""
req = protocol.PhotosInfoRequest()
result = await self.grpc_interface.PhotosInfo(req)
self._photo_info = result.photo_infos
return result
@connection.on_connection_thread(log_messaging=False)
async def get_photo(self, photo_id: int) -> protocol.PhotoResponse:
"""Download a full-resolution photo from the robot's storage.
.. testcode::
import anki_vector
import io
from PIL import Image
with anki_vector.Robot() as robot:
for photo_info in robot.photos.photo_info:
print(f"Opening photo {photo_info.photo_id}")
photo = robot.photos.get_photo(photo_info.photo_id)
image = Image.open(io.BytesIO(photo.image))
image.show()
:param photo_id: The id of the photo to download. It's recommended to get this
value from the photo_info list first.
:return: A response containing all of the photo bytes which may be rendered using
another library (like :mod:`PIL`)
"""
req = protocol.PhotoRequest(photo_id=photo_id)
return await self.grpc_interface.Photo(req)
@connection.on_connection_thread(log_messaging=False)
async def get_thumbnail(self, photo_id: int) -> protocol.ThumbnailResponse:
"""Download a thumbnail of a given photo from the robot's storage.
You may use this function to pull all of the images off the robot in a smaller format, and
then determine which one to download as full resolution.
.. testcode::
import anki_vector
from PIL import Image
import io
with anki_vector.Robot() as robot:
for photo_info in robot.photos.photo_info:
photo = robot.photos.get_thumbnail(photo_info.photo_id)
image = Image.open(io.BytesIO(photo.image))
image.show()
:param photo_id: The id of the thumbnail to download. It's recommended to get this
value from the photo_info list first.
:return: A response containing all of the thumbnail bytes which may be rendered using
another library (like :mod:`PIL`)
"""
req = protocol.ThumbnailRequest(photo_id=photo_id)
return await self.grpc_interface.Thumbnail(req)