Text is now vertically aligned and GPIO channel for lamp added
This commit is contained in:
12
Front.svg
12
Front.svg
@@ -35,9 +35,9 @@
|
|||||||
borderopacity="1.0"
|
borderopacity="1.0"
|
||||||
inkscape:pageopacity="0.0"
|
inkscape:pageopacity="0.0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="0.8262427"
|
inkscape:zoom="0.58424182"
|
||||||
inkscape:cx="1134.3559"
|
inkscape:cx="667.80608"
|
||||||
inkscape:cy="701.47771"
|
inkscape:cy="717.44673"
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
inkscape:current-layer="layer5"
|
inkscape:current-layer="layer5"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:type
|
<dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
transform="translate(0,-1084.252)">
|
transform="translate(0,-1084.252)">
|
||||||
<g
|
<g
|
||||||
id="g4161"
|
id="g4161"
|
||||||
transform="matrix(0,-1.0006094,1.0009564,0,-484.38195,1945.4764)"
|
transform="matrix(0,-1.0006094,1.0009564,0,-484.38195,1941.4764)"
|
||||||
style="display:inline;stroke:#0000ff;stroke-width:0.99921769;stroke-opacity:1">
|
style="display:inline;stroke:#0000ff;stroke-width:0.99921769;stroke-opacity:1">
|
||||||
<rect
|
<rect
|
||||||
y="642.01733"
|
y="642.01733"
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
<rect
|
<rect
|
||||||
transform="matrix(0,-1,1,0,0,0)"
|
transform="matrix(0,-1,1,0,0,0)"
|
||||||
y="168.53157"
|
y="168.53157"
|
||||||
x="-1898.7059"
|
x="-1893.5669"
|
||||||
height="332.38846"
|
height="332.38846"
|
||||||
width="555.63757"
|
width="555.63757"
|
||||||
id="rect4246"
|
id="rect4246"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
@@ -49,6 +49,9 @@ gpio_shutdown_channel = 24 # pin 18 in all Raspi-Versions
|
|||||||
# GPIO channel of switch to take pictures
|
# GPIO channel of switch to take pictures
|
||||||
gpio_trigger_channel = 23 # pin 16 in all Raspi-Versions
|
gpio_trigger_channel = 23 # pin 16 in all Raspi-Versions
|
||||||
|
|
||||||
|
# GPIO output channel for (blinking) lamp
|
||||||
|
gpio_lamp_channel = 4 # pin 7 in all Raspi-Versions
|
||||||
|
|
||||||
# PyGame event used to detect GPIO triggers
|
# PyGame event used to detect GPIO triggers
|
||||||
gpio_pygame_event = pygame.USEREVENT
|
gpio_pygame_event = pygame.USEREVENT
|
||||||
|
|
||||||
@@ -102,7 +105,7 @@ class TextRectException:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.message
|
return self.message
|
||||||
|
|
||||||
def render_textrect(string, font, rect, text_color, background_color, justification=0):
|
def render_textrect(string, font, rect, text_color, background_color, justification=0, valign=0):
|
||||||
"""Returns a surface containing the passed text string, reformatted
|
"""Returns a surface containing the passed text string, reformatted
|
||||||
to fit within the given rect, word-wrapping as necessary. The text
|
to fit within the given rect, word-wrapping as necessary. The text
|
||||||
will be anti-aliased.
|
will be anti-aliased.
|
||||||
@@ -120,6 +123,9 @@ def render_textrect(string, font, rect, text_color, background_color, justificat
|
|||||||
justification - 0 (default) left-justified
|
justification - 0 (default) left-justified
|
||||||
1 horizontally centered
|
1 horizontally centered
|
||||||
2 right-justified
|
2 right-justified
|
||||||
|
valign - 0 (default) top aligned
|
||||||
|
1 vertically centered
|
||||||
|
2 bottom aligned
|
||||||
|
|
||||||
Returns the following values:
|
Returns the following values:
|
||||||
|
|
||||||
@@ -134,6 +140,7 @@ def render_textrect(string, font, rect, text_color, background_color, justificat
|
|||||||
# Create a series of lines that will fit on the provided
|
# Create a series of lines that will fit on the provided
|
||||||
# rectangle.
|
# rectangle.
|
||||||
|
|
||||||
|
accumulated_height = 0
|
||||||
for requested_line in requested_lines:
|
for requested_line in requested_lines:
|
||||||
if font.size(requested_line)[0] > rect.width:
|
if font.size(requested_line)[0] > rect.width:
|
||||||
words = requested_line.split(' ')
|
words = requested_line.split(' ')
|
||||||
@@ -149,12 +156,29 @@ def render_textrect(string, font, rect, text_color, background_color, justificat
|
|||||||
if font.size(test_line)[0] < rect.width:
|
if font.size(test_line)[0] < rect.width:
|
||||||
accumulated_line = test_line
|
accumulated_line = test_line
|
||||||
else:
|
else:
|
||||||
|
accumulated_height += font.size(test_line)[1]
|
||||||
final_lines.append(accumulated_line)
|
final_lines.append(accumulated_line)
|
||||||
accumulated_line = word + " "
|
accumulated_line = word + " "
|
||||||
|
accumulated_height += font.size(accumulated_line)[1]
|
||||||
final_lines.append(accumulated_line)
|
final_lines.append(accumulated_line)
|
||||||
else:
|
else:
|
||||||
|
accumulated_height += font.size(requested_line)[1]
|
||||||
final_lines.append(requested_line)
|
final_lines.append(requested_line)
|
||||||
|
|
||||||
|
# Check height of the text and align vertically
|
||||||
|
|
||||||
|
if accumulated_height >= rect.height:
|
||||||
|
raise TextRectException, "Once word-wrapped, the text string was too tall to fit in the rect."
|
||||||
|
|
||||||
|
if valign == 0:
|
||||||
|
voffset = 0
|
||||||
|
elif valign == 1:
|
||||||
|
voffset = int((rect.height - accumulated_height) / 2)
|
||||||
|
elif valign == 2:
|
||||||
|
voffset = rect.height - accumulated_height
|
||||||
|
else:
|
||||||
|
raise TextRectException, "Invalid valign argument: " + str(valign)
|
||||||
|
|
||||||
# Let's try to write the text out on the surface.
|
# Let's try to write the text out on the surface.
|
||||||
|
|
||||||
surface = pygame.Surface(rect.size)
|
surface = pygame.Surface(rect.size)
|
||||||
@@ -162,16 +186,14 @@ def render_textrect(string, font, rect, text_color, background_color, justificat
|
|||||||
|
|
||||||
accumulated_height = 0
|
accumulated_height = 0
|
||||||
for line in final_lines:
|
for line in final_lines:
|
||||||
if accumulated_height + font.size(line)[1] >= rect.height:
|
|
||||||
raise TextRectException, "Once word-wrapped, the text string was too tall to fit in the rect."
|
|
||||||
if line != "":
|
if line != "":
|
||||||
tempsurface = font.render(line, 1, text_color)
|
tempsurface = font.render(line, 1, text_color)
|
||||||
if justification == 0:
|
if justification == 0:
|
||||||
surface.blit(tempsurface, (0, accumulated_height))
|
surface.blit(tempsurface, (0, voffset + accumulated_height))
|
||||||
elif justification == 1:
|
elif justification == 1:
|
||||||
surface.blit(tempsurface, ((rect.width - tempsurface.get_width()) / 2, accumulated_height))
|
surface.blit(tempsurface, ((rect.width - tempsurface.get_width()) / 2, voffset + accumulated_height))
|
||||||
elif justification == 2:
|
elif justification == 2:
|
||||||
surface.blit(tempsurface, (rect.width - tempsurface.get_width(), accumulated_height))
|
surface.blit(tempsurface, (rect.width - tempsurface.get_width(), voffset + accumulated_height))
|
||||||
else:
|
else:
|
||||||
raise TextRectException, "Invalid justification argument: " + str(justification)
|
raise TextRectException, "Invalid justification argument: " + str(justification)
|
||||||
accumulated_height += font.size(line)[1]
|
accumulated_height += font.size(line)[1]
|
||||||
@@ -227,9 +249,9 @@ class GUI_PyGame:
|
|||||||
# Choose font
|
# Choose font
|
||||||
font = pygame.font.Font(None, 144)
|
font = pygame.font.Font(None, 144)
|
||||||
# Create rectangle for text
|
# Create rectangle for text
|
||||||
rect = pygame.Rect((40, 40, self.size[0] - 40, self.size[1] - 40))
|
rect = pygame.Rect((0, 0, self.size[0], self.size[1]))
|
||||||
# Render text
|
# Render text
|
||||||
text = render_textrect(msg, font, rect, color, bg, 1)
|
text = render_textrect(msg, font, rect, color, bg, 1, 1)
|
||||||
self.screen.blit(text, rect.topleft)
|
self.screen.blit(text, rect.topleft)
|
||||||
|
|
||||||
def mainloop(self, filename):
|
def mainloop(self, filename):
|
||||||
@@ -241,7 +263,7 @@ class GUI_PyGame:
|
|||||||
# Show idle-picture and message
|
# Show idle-picture and message
|
||||||
if filename != None:
|
if filename != None:
|
||||||
self.show_picture(filename)
|
self.show_picture(filename)
|
||||||
self.show_message("\n\nHit the button!")
|
self.show_message("Hit the button!")
|
||||||
# Render everything
|
# Render everything
|
||||||
self.apply()
|
self.apply()
|
||||||
# Wait for event
|
# Wait for event
|
||||||
@@ -300,10 +322,13 @@ class Camera:
|
|||||||
|
|
||||||
def assemble_pictures(input_filenames, output_filename):
|
def assemble_pictures(input_filenames, output_filename):
|
||||||
"""Assembles four pictures into a 2x2 grid"""
|
"""Assembles four pictures into a 2x2 grid"""
|
||||||
|
|
||||||
# Thumbnail size of pictures
|
# Thumbnail size of pictures
|
||||||
size = (int(image_size[0]/2),int(image_size[1]/2))
|
size = (int(image_size[0]/2),int(image_size[1]/2))
|
||||||
|
|
||||||
# Create output image
|
# Create output image
|
||||||
output_image = Image.new('RGB', image_size)
|
output_image = Image.new('RGB', image_size)
|
||||||
|
|
||||||
# Load images and resize them
|
# Load images and resize them
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
for j in range(2):
|
for j in range(2):
|
||||||
@@ -312,10 +337,14 @@ def assemble_pictures(input_filenames, output_filename):
|
|||||||
img.thumbnail(size)
|
img.thumbnail(size)
|
||||||
offset = (j * size[0], i * size[1])
|
offset = (j * size[0], i * size[1])
|
||||||
output_image.paste(img, offset)
|
output_image.paste(img, offset)
|
||||||
|
|
||||||
output_image.save(output_filename, "JPEG")
|
output_image.save(output_filename, "JPEG")
|
||||||
|
|
||||||
def take_picture():
|
def take_picture():
|
||||||
"""Implements the picture taking routine"""
|
"""Implements the picture taking routine"""
|
||||||
|
# Disable the lamp
|
||||||
|
set_lamp(0)
|
||||||
|
|
||||||
# Show pose message
|
# Show pose message
|
||||||
display.clear()
|
display.clear()
|
||||||
if image_pose != None:
|
if image_pose != None:
|
||||||
@@ -327,13 +356,13 @@ def take_picture():
|
|||||||
# Countdown
|
# Countdown
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
display.clear()
|
display.clear()
|
||||||
display.show_message("\n\n" + str(3 - i))
|
display.show_message(str(3 - i))
|
||||||
display.apply()
|
display.apply()
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
# Show 'Cheese'
|
# Show 'Cheese'
|
||||||
display.clear()
|
display.clear()
|
||||||
display.show_message("\n\nS M I L E !")
|
display.show_message("S M I L E !")
|
||||||
display.apply()
|
display.apply()
|
||||||
|
|
||||||
# Extract display and image sizes
|
# Extract display and image sizes
|
||||||
@@ -360,11 +389,16 @@ def take_picture():
|
|||||||
display.apply()
|
display.apply()
|
||||||
sleep(display_time)
|
sleep(display_time)
|
||||||
|
|
||||||
|
# Reenable lamp
|
||||||
|
set_lamp(1)
|
||||||
|
|
||||||
def handle_keypress(key):
|
def handle_keypress(key):
|
||||||
"""Implements the actions for the different keypress events"""
|
"""Implements the actions for the different keypress events"""
|
||||||
|
|
||||||
# Exit the application
|
# Exit the application
|
||||||
if key == ord('q'):
|
if key == ord('q'):
|
||||||
teardown()
|
teardown()
|
||||||
|
|
||||||
# Take pictures
|
# Take pictures
|
||||||
elif key == ord('c'):
|
elif key == ord('c'):
|
||||||
take_picture()
|
take_picture()
|
||||||
@@ -377,12 +411,14 @@ def handle_mousebutton(key, pos):
|
|||||||
|
|
||||||
def handle_gpio_event(channel):
|
def handle_gpio_event(channel):
|
||||||
"""Implements the actions taken for a GPIO event"""
|
"""Implements the actions taken for a GPIO event"""
|
||||||
|
|
||||||
if channel == gpio_trigger_channel:
|
if channel == gpio_trigger_channel:
|
||||||
take_picture()
|
take_picture()
|
||||||
|
|
||||||
elif channel == gpio_shutdown_channel:
|
elif channel == gpio_shutdown_channel:
|
||||||
display.clear()
|
display.clear()
|
||||||
print("Shutting down!")
|
print("Shutting down!")
|
||||||
display.show_message("\n\nShutting down!")
|
display.show_message("Shutting down!")
|
||||||
display.apply()
|
display.apply()
|
||||||
sleep(1)
|
sleep(1)
|
||||||
teardown()
|
teardown()
|
||||||
@@ -401,13 +437,19 @@ def setup_gpio():
|
|||||||
# Display initial information
|
# Display initial information
|
||||||
print("Your Raspberry Pi is board revision " + str(GPIO.RPI_INFO['P1_REVISION']))
|
print("Your Raspberry Pi is board revision " + str(GPIO.RPI_INFO['P1_REVISION']))
|
||||||
print("RPi.GPIO version is " + str(GPIO.VERSION))
|
print("RPi.GPIO version is " + str(GPIO.VERSION))
|
||||||
|
|
||||||
# Choose BCM numbering system
|
# Choose BCM numbering system
|
||||||
GPIO.setmode(GPIO.BCM)
|
GPIO.setmode(GPIO.BCM)
|
||||||
|
|
||||||
# Setup the trigger channel as input and listen for events
|
# Setup the trigger channel as input and listen for events
|
||||||
GPIO.setup(gpio_trigger_channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
GPIO.setup(gpio_trigger_channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||||
GPIO.setup(gpio_shutdown_channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
GPIO.setup(gpio_shutdown_channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||||
GPIO.add_event_detect(gpio_trigger_channel, GPIO.RISING, callback=handle_gpio, bouncetime=200)
|
GPIO.add_event_detect(gpio_trigger_channel, GPIO.RISING, callback=handle_gpio, bouncetime=200)
|
||||||
GPIO.add_event_detect(gpio_shutdown_channel, GPIO.RISING, callback=handle_gpio, bouncetime=200)
|
GPIO.add_event_detect(gpio_shutdown_channel, GPIO.RISING, callback=handle_gpio, bouncetime=200)
|
||||||
|
|
||||||
|
# Setup the lamp channel as output
|
||||||
|
GPIO.setup(gpio_lamp_channel, GPIO.OUT)
|
||||||
|
GPIO.output(gpio_lamp_channel, GPIO.LOW)
|
||||||
else:
|
else:
|
||||||
print("Warning: RPi.GPIO could not be loaded. GPIO disabled.")
|
print("Warning: RPi.GPIO could not be loaded. GPIO disabled.")
|
||||||
|
|
||||||
@@ -415,6 +457,11 @@ def handle_gpio(channel):
|
|||||||
"""Interrupt handler for GPIO events"""
|
"""Interrupt handler for GPIO events"""
|
||||||
display.trigger_event(gpio_pygame_event, channel)
|
display.trigger_event(gpio_pygame_event, channel)
|
||||||
|
|
||||||
|
def set_lamp(status=0):
|
||||||
|
"""Switch the lamp on"""
|
||||||
|
if gpio_enabled:
|
||||||
|
GPIO.output(gpio_lamp_channel, GPIO.HIGH if status==1 else GPIO.LOW)
|
||||||
|
|
||||||
def teardown(exit_code=0):
|
def teardown(exit_code=0):
|
||||||
display.teardown()
|
display.teardown()
|
||||||
if gpio_enabled:
|
if gpio_enabled:
|
||||||
@@ -425,6 +472,7 @@ def main():
|
|||||||
setup_gpio()
|
setup_gpio()
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
set_lamp(1)
|
||||||
display.mainloop(image_idle)
|
display.mainloop(image_idle)
|
||||||
except CameraException as e:
|
except CameraException as e:
|
||||||
handle_exception(e.message)
|
handle_exception(e.message)
|
||||||
|
|||||||
Reference in New Issue
Block a user