Skip to content

Commit

Permalink
Fix #160
Browse files Browse the repository at this point in the history
Now with super-long annotations and backgrounds!
  • Loading branch information
waveform80 committed Sep 3, 2014
1 parent a9e4532 commit bfa707f
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 17 deletions.
8 changes: 5 additions & 3 deletions docs/recipes1.rst
Expand Up @@ -866,7 +866,7 @@ interfaces.
Overlaying text on the output
=============================

The camera includes a rudimentary annotation facility which permits up to 31
The camera includes a rudimentary annotation facility which permits up to 255
characters of ASCII text to be overlayed on all output (including the preview,
image captures and video recordings). To achieve this, simply assign a string
to the :attr:`~picamera.PiCamera.annotate_text` attribute::
Expand Down Expand Up @@ -900,8 +900,9 @@ With a little ingenuity, it's possible to display longer strings::
camera.annotate_text = camera.annotate_text[1:31] + c
time.sleep(0.1)

And of course, it can be used to display (and embed) a timestamp in
recordings::
And of course, it can be used to display (and embed) a timestamp in recordings
(this recipe also demonstrates drawing a background behind the timestamp for
contrast with the :attr:`~picamera.PiCamera.annotate_bg` attribute)::

import picamera
import datetime as dt
Expand All @@ -910,6 +911,7 @@ recordings::
camera.resolution = (1280, 720)
camera.framerate = 24
camera.start_preview()
camera.annotate_bg = True
camera.annotate_text = dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
camera.start_recording('timestamped.h264')
start = dt.datetime.now()
Expand Down
99 changes: 87 additions & 12 deletions picamera/camera.py
Expand Up @@ -2908,7 +2908,8 @@ def _set_image_effect_params(self, value):
mmal.mmal_port_parameter_set(self._camera[0].control, mp.hdr),
prefix="Failed to set image effect parameters")
self._image_effect_params = value
image_effect_params = property(_get_image_effect_params, _set_image_effect_params, doc="""
image_effect_params = property(
_get_image_effect_params, _set_image_effect_params, doc="""
Retrieves or sets the parameters for the current :attr:`effect
<image_effect>`.
Expand Down Expand Up @@ -3372,26 +3373,29 @@ def _set_preview_window(self, value):

def _get_annotate_text(self):
self._check_camera_open()
mp = mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_T(
mp = mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T(
mmal.MMAL_PARAMETER_HEADER_T(
mmal.MMAL_PARAMETER_ANNOTATE,
ct.sizeof(mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_T)
ct.sizeof(mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T)
))
mmal_check(
mmal.mmal_port_parameter_get(self._camera[0].control, mp.hdr),
prefix="Failed to get annotation status")
prefix="Failed to get annotation text")
if mp.enable:
return mp.text.decode('ascii')
else:
return ''
def _set_annotate_text(self, value):
self._check_camera_open()
mp = mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_T(
mp = mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T(
mmal.MMAL_PARAMETER_HEADER_T(
mmal.MMAL_PARAMETER_ANNOTATE,
ct.sizeof(mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_T)
ct.sizeof(mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T)
))
if value:
mmal_check(
mmal.mmal_port_parameter_get(self._camera[0].control, mp.hdr),
prefix="Failed to get annotation status")
if value or bool(mp.show_frame_num):
mp.enable = True
try:
mp.text = value.encode('ascii')
Expand All @@ -3401,17 +3405,88 @@ def _set_annotate_text(self, value):
mp.enable = False
mmal_check(
mmal.mmal_port_parameter_set(self._camera[0].control, mp.hdr),
prefix="Failed to set annotation status")
prefix="Failed to set annotation text")
annotate_text = property(_get_annotate_text, _set_annotate_text, doc="""
Retrieves or sets a text annotation for all output.
When queried, :attr:`annotate_text` property returns returns the
current annotation (if no annotation has been set, this is simply
a blank string).
When queried, the :attr:`annotate_text` property returns the current
annotation (if no annotation has been set, this is simply a blank
string).
When set, the property immediately applies the annotation to the
preview (if it is running) and to any future captures or video
recording. Strings longer than 31 characters, or strings containing
recording. Strings longer than 255 characters, or strings containing
non-ASCII characters will raise a :exc:`PiCameraValueError`. The
default value is ``''``.
""")

def _get_annotate_frame_num(self):
self._check_camera_open()
mp = mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T(
mmal.MMAL_PARAMETER_HEADER_T(
mmal.MMAL_PARAMETER_ANNOTATE,
ct.sizeof(mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T)
))
mmal_check(
mmal.mmal_port_parameter_get(self._camera[0].control, mp.hdr),
prefix="Failed to get annotation frame number")
return mp.show_frame_num != mmal.MMAL_FALSE
def _set_annotate_frame_num(self, value):
self._check_camera_open()
mp = mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T(
mmal.MMAL_PARAMETER_HEADER_T(
mmal.MMAL_PARAMETER_ANNOTATE,
ct.sizeof(mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T)
))
mmal_check(
mmal.mmal_port_parameter_get(self._camera[0].control, mp.hdr),
prefix="Failed to get annotation status")
mp.enable = bool(value) or bool(mp.text)
mp.show_frame_num = bool(value)
mmal_check(
mmal.mmal_port_parameter_set(self._camera[0].control, mp.hdr),
prefix="Failed to set annotation frame number")
annotate_frame_num = property(
_get_annotate_frame_num, _set_annotate_frame_num, doc="""
Controls whether the current frame number is drawn as an annotation.
The :attr:`annotate_frame_num` attribute is a bool indicating whether
or not the current frame number is rendered as an annotation, similar
to :attr:`annotate_text`. The default is ``False``.
""")

def _get_annotate_background(self):
self._check_camera_open()
mp = mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T(
mmal.MMAL_PARAMETER_HEADER_T(
mmal.MMAL_PARAMETER_ANNOTATE,
ct.sizeof(mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T)
))
mmal_check(
mmal.mmal_port_parameter_get(self._camera[0].control, mp.hdr),
prefix="Failed to get annotation background")
return mp.black_text_background != mmal.MMAL_FALSE
def _set_annotate_background(self, value):
self._check_camera_open()
mp = mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T(
mmal.MMAL_PARAMETER_HEADER_T(
mmal.MMAL_PARAMETER_ANNOTATE,
ct.sizeof(mmal.MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T)
))
mmal_check(
mmal.mmal_port_parameter_get(self._camera[0].control, mp.hdr),
prefix="Failed to get annotation status")
mp.black_text_background = bool(value)
mmal_check(
mmal.mmal_port_parameter_set(self._camera[0].control, mp.hdr),
prefix="Failed to set annotation background")
annotate_background = property(
_get_annotate_background, _set_annotate_background, doc="""
Controls whether a black background is drawn behind the annotation.
The :attr:`annotate_bg` attribute is a bool indicating whether or not a
black background will be drawn behind the :attr:`annotation text
<annotate_text>`. The background will appear in all output including
image captures and video recording. The default is ``False``.
""")

16 changes: 16 additions & 0 deletions picamera/mmal.py
Expand Up @@ -1134,6 +1134,22 @@ class MMAL_PARAMETER_CAMERA_ANNOTATE_T(ct.Structure):
('show_motion', MMAL_BOOL_T),
]

MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2 = 256

class MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T(ct.Structure):
_fields_ = [
('hdr', MMAL_PARAMETER_HEADER_T),
('enable', MMAL_BOOL_T),
('show_shutter', MMAL_BOOL_T),
('show_analog_gain', MMAL_BOOL_T),
('show_lens', MMAL_BOOL_T),
('show_caf', MMAL_BOOL_T),
('show_motion', MMAL_BOOL_T),
('show_frame_num', MMAL_BOOL_T),
('black_text_background', MMAL_BOOL_T),
('text', ct.c_char * MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2),
]

MMAL_STEREOSCOPIC_MODE_T = ct.c_uint32 # enum
(
MMAL_STEREOSCOPIC_MODE_NONE,
Expand Down
2 changes: 1 addition & 1 deletion picamera/renderers.py
Expand Up @@ -219,7 +219,7 @@ def _set_fullscreen(self, value):
ct.sizeof(mmal.MMAL_DISPLAYREGION_T)
),
set=mmal.MMAL_DISPLAY_SET_FULLSCREEN,
fullscreen=(mmal.MMAL_FALSE, mmal.MMAL_TRUE)[bool(value)]
fullscreen=bool(value)
)
mmal_check(
mmal.mmal_port_parameter_set(self.renderer[0].input[0], mp.hdr),
Expand Down
8 changes: 7 additions & 1 deletion tests/test_attr.py
Expand Up @@ -90,10 +90,16 @@ def test_annotate_text(camera, previewing):
camera.annotate_text = 'foo bar baz quux xyzzy'
assert camera.annotate_text == u'foo bar baz quux xyzzy'
with pytest.raises(picamera.PiCameraValueError):
camera.annotate_text = 'this value is way too long for this attribute'
camera.annotate_text = 'abcd' * 64
with pytest.raises(picamera.PiCameraValueError):
camera.annotate_text = 'Oh lá lá'

def test_annotate_background(camera, previewing):
boolean_attr(camera, 'annotate_background')

def test_annotate_frame_num(camera, previewing):
boolean_attr(camera, 'annotate_frame_num')

def test_awb_mode(camera, previewing):
keyword_attr(camera, 'awb_mode', camera.AWB_MODES)

Expand Down

0 comments on commit bfa707f

Please sign in to comment.