diff --git a/README.md b/README.md index f1b7029..a8698f3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ # Led-Badge-44x11 Upload tool for an led name tag with USB-HID interface -![LED Mini Board](photos/green_badge.jpg) +![LED Mini Board](photos/blueBadge.jpg) + +Added Accentuated french Characters + +![French LED Mini Board](photos/accentuated.gif) ## Hardware @@ -129,6 +133,10 @@ shows a bicycle crossing the display in left-to-right and right-to-left (as a se shows a simple animation of a slowly beating heart on the first message, and a blinking heart on the second message. + ./led-badge-11x44.py -B 50 -m 0 -s 8 "Bonjour à toutes et à tous" "Bienvenu(e)s en Master 2 EEA ISHM" "Ingénierie des systèmes Humains Machines" "Bonne réussite à votre promotion 2023-2024" + +![M2 ishm](photos/m2ishm.gif) + python3 ./led-badge-11x44.py --list-names prints the list of builtin icon names, including :happy: :happy2: :heart: :HEART: :heart2: :HEART2: :fablab: :bicycle: :bicycle_r: :owncloud: :: @@ -138,36 +146,27 @@ prints the list of builtin icon names, including :happy: :happy2: :heart: :HEART prints some condensed help:
-usage: led-badge-11x44.py [-h] [-t TYPE] [-s SPEED] [-m MODE] [-b BLINK]
-			  [-a ANTS] [-p FILE] [-l]
-                          MESSAGE [MESSAGE ...]
+usage: led-badge-11x44.py [-h] [-t TYPE] [-s SPEED] [-B BRIGHTNESS] [-m MODE] [-b BLINK] [-a ANTS] [-l] MESSAGE [MESSAGE ...]
 
-Upload messages or graphics to a 44x11 led badge via USB HID.
-Version 0.6 from https://github.com/jnweiger/led-badge-44x11
+Upload messages or graphics to a 11x44 led badge via USB HID.
+Version 0.12 from https://github.com/jnweiger/led-name-badge-ls32
  -- see there for more examples and for updates.
 
 positional arguments:
-  MESSAGE               Up to 8 message texts with embedded builtin icons or
-                        loaded images within colons(:) -- See -l for a list of
-                        builtins
+  MESSAGE               Up to 8 message texts with embedded builtin icons or loaded images within colons(:) -- See -l for a list of builtins
 
-optional arguments:
+options:
   -h, --help            show this help message and exit
-  -t TYPE, --type TYPE
-			Type of display: supported values are 12x48 or
-			(default) 11x44. Rename the program to led-badge-12x48,
-			to switch the default.
+  -t TYPE, --type TYPE  Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.
   -s SPEED, --speed SPEED
-                        Scroll speed (Range 1..8). Up to 8 comma-seperated
-                        values
-  -m MODE, --mode MODE  Up to 8 mode values: Scroll-left(0) -right(1) -up(2)
-                        -down(3); still-centered(4); animation(5); drop-
-                        down(6); curtain(7); laser(8); See '--mode-help' for
-                        more details.
+                        Scroll speed (Range 1..8). Up to 8 comma-separated values
+  -B BRIGHTNESS, --brightness BRIGHTNESS
+                        Brightness for the display in percent: 25, 50, 75, or 100
+  -m MODE, --mode MODE  Up to 8 mode values: Scroll-left(0) -right(1) -up(2) -down(3); still-centered(4); animation(5); drop-down(6); curtain(7);
+                        laser(8); See '--mode-help' for more details.
   -b BLINK, --blink BLINK
-                        1: blinking, 0: normal. Up to 8 comma-seperated values
-  -a ANTS, --ants ANTS  1: animated border, 0: normal. Up to 8 comma-seperated
-                        values
+                        1: blinking, 0: normal. Up to 8 comma-separated values
+  -a ANTS, --ants ANTS  1: animated border, 0: normal. Up to 8 comma-separated values
   -l, --list-names      list named icons to be embedded in messages and exit
 
 Example combining image and text:
diff --git a/led-badge-11x44.py b/led-badge-11x44.py
index ac66a8f..f61c849 100755
--- a/led-badge-11x44.py
+++ b/led-badge-11x44.py
@@ -52,39 +52,41 @@
 import sys, os, re, time, argparse
 from datetime import datetime
 from array import array
+
 try:
-  if sys.version_info[0] < 3: raise Exception("prefer usb.core with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9")
-  import pyhidapi
-  pyhidapi.hid_init()
-  have_pyhidapi = True
+    if sys.version_info[0] < 3: raise Exception(
+        "prefer usb.core with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9")
+    import pyhidapi
+
+    pyhidapi.hid_init()
+    have_pyhidapi = True
 except:
-  have_pyhidapi = False
-  try:
-    import usb.core
-  except:
-    print("ERROR: Need the pyhidapi or usb.core module.")
-    if sys.platform == "darwin":
-      print("""Please try
+    have_pyhidapi = False
+    try:
+        import usb.core
+    except:
+        print("ERROR: Need the pyhidapi or usb.core module.")
+        if sys.platform == "darwin":
+            print("""Please try
   pip3 install pyhidapi
   pip install pyhidapi
   brew install hidapi""")
-    elif sys.platform == "linux":
-      print("""Please try
+        elif sys.platform == "linux":
+            print("""Please try
   sudo pip3 install pyhidapi
   sudo pip install pyhidapi
   sudo apt-get install libhidapi-hidraw0
   sudo ln -s /usr/lib/x86_64-linux-gnu/libhidapi-hidraw.so.0  /usr/local/lib/
 or
   sudo apt-get install python3-usb""")
-    else:       # windows?
-      print("""Please with Linux or MacOS or help us implement support for """ + sys.platform)
-    sys.exit(1)
-
+        else:  # windows?
+            print("""Please with Linux or MacOS or help us implement support for """ + sys.platform)
+        sys.exit(1)
 
 __version = "0.12"
 
 font_11x44 = (
-  # 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+    # 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
   0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
   0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00,
   0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0xc6, 0x7c, 0x00,
@@ -201,94 +203,129 @@ font_11x44 = (
   0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
   0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
   0x00, 0x3c, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x6c, 0x60,
+
+  # "àäòöùüèéêëôöûîïÿç"
+  0x00, 0x60, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+  0x00, 0x6c, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+  0x00, 0x60, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
+  0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
+  0x00, 0x60, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+  0x00, 0x6c, 0x6c, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+  0x00, 0x60, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
+  0x00, 0x18, 0x60, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
+  0x00, 0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
+  0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
+  0x00, 0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
+  0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
+  0x00, 0x10, 0x6c, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+  0x00, 0x10, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
+  0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
+  0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8,
+  0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x10, 0x30,
+
+  # "ÀÅÄÉÈÊËÖÔÜÛÙŸ"
+  0x60, 0x18, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
+  0x10, 0x6c, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
+  0x6c, 0x6c, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
+  0x18, 0x60, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
+  0x60, 0x18, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
+  0x10, 0x6c, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
+  0x6c, 0x6c, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
+  0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,  # Ö
+  0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,  # Ô
+  0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,  # Ü
+  0x10, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,  # Û
+  0x60, 0x18, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,  # Ù
+  0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00,  # Ÿ
 )
 
 charmap = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
           u'abcdefghijklmnopqrstuvwxyz' + \
           u'0987654321^ !"\0$%&/()=?` °\\}][{' + \
           u"@ ~ |<>,;.:-_#'+* " + \
-          u"äöüÄÖÜß"
+          u"äöüÄÖÜß" + \
+          u"àäòöùüèéêëôöûîïÿç" + \
+          u"ÀÅÄÉÈÊËÖÔÜÛÙŸ"
 
 char_offset = {}
 for i in range(len(charmap)):
-  char_offset[charmap[i]] = 11 * i
-  # print(i, charmap[i], char_offset[charmap[i]])
+    char_offset[charmap[i]] = 11 * i
+    # print(i, charmap[i], char_offset[charmap[i]])
 
-
-bitmap_preloaded = [ ([],0) ]
+bitmap_preloaded = [([], 0)]
 bitmaps_preloaded_unused = False
 
 bitmap_named = {
-  'ball':    (array('B', (
-                0b00000000,
-                0b00000000,
-                0b00111100,
-                0b01111110,
-                0b11111111,
-                0b11111111,
-                0b11111111,
-                0b11111111,
-                0b01111110,
-                0b00111100,
-                0b00000000
-                )), 1, '\x1e'),
-  'happy':    (array('B', (
-                0b00000000,     # 0x00
-                0b00000000,     # 0x00
-                0b00111100,     # 0x3c
-                0b01000010,     # 0x42
-                0b10100101,     # 0xa5
-                0b10000001,     # 0x81
-                0b10100101,     # 0xa5
-                0b10011001,     # 0x99
-                0b01000010,     # 0x42
-                0b00111100,     # 0x3c
-                0b00000000      # 0x00
-                )), 1, '\x1d'),
-  'happy2':   (array('B', (0x00, 0x08, 0x14, 0x08, 0x01, 0x00, 0x00, 0x61, 0x30, 0x1c, 0x07,
+    'ball': (array('B', (
+        0b00000000,
+        0b00000000,
+        0b00111100,
+        0b01111110,
+        0b11111111,
+        0b11111111,
+        0b11111111,
+        0b11111111,
+        0b01111110,
+        0b00111100,
+        0b00000000
+    )), 1, '\x1e'),
+    'happy': (array('B', (
+        0b00000000,  # 0x00
+        0b00000000,  # 0x00
+        0b00111100,  # 0x3c
+        0b01000010,  # 0x42
+        0b10100101,  # 0xa5
+        0b10000001,  # 0x81
+        0b10100101,  # 0xa5
+        0b10011001,  # 0x99
+        0b01000010,  # 0x42
+        0b00111100,  # 0x3c
+        0b00000000  # 0x00
+    )), 1, '\x1d'),
+    'happy2': (array('B', (0x00, 0x08, 0x14, 0x08, 0x01, 0x00, 0x00, 0x61, 0x30, 0x1c, 0x07,
                            0x00, 0x20, 0x50, 0x20, 0x00, 0x80, 0x80, 0x86, 0x0c, 0x38, 0xe0)), 2, '\x1c'),
-  'heart':    (array('B', (0x00, 0x00, 0x6c, 0x92, 0x82, 0x82, 0x44, 0x28, 0x10, 0x00, 0x00)), 1, '\x1b'),
-  'HEART':    (array('B', (0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00)), 1, '\x1a'),
-  'heart2':   (array('B', (0x00, 0x0c, 0x12, 0x21, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
+    'heart': (array('B', (0x00, 0x00, 0x6c, 0x92, 0x82, 0x82, 0x44, 0x28, 0x10, 0x00, 0x00)), 1, '\x1b'),
+    'HEART': (array('B', (0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00)), 1, '\x1a'),
+    'heart2': (array('B', (0x00, 0x0c, 0x12, 0x21, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
                            0x00, 0x60, 0x90, 0x08, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00)), 2, '\x19'),
-  'HEART2':   (array('B', (0x00, 0x0c, 0x1e, 0x3f, 0x3f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01,
+    'HEART2': (array('B', (0x00, 0x0c, 0x1e, 0x3f, 0x3f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01,
                            0x00, 0x60, 0xf0, 0xf8, 0xf8, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00)), 2, '\x18'),
-  'fablab':   (array('B', (0x07, 0x0e, 0x1b, 0x03, 0x21, 0x2c, 0x2e, 0x26, 0x14, 0x1c, 0x06,
+    'fablab': (array('B', (0x07, 0x0e, 0x1b, 0x03, 0x21, 0x2c, 0x2e, 0x26, 0x14, 0x1c, 0x06,
                            0x80, 0x60, 0x30, 0x80, 0x88, 0x38, 0xe8, 0xc8, 0x10, 0x30, 0xc0)), 2, '\x17'),
-  'bicycle':  (array('B', (0x01, 0x02, 0x00, 0x01, 0x07, 0x09, 0x12, 0x12, 0x10, 0x08, 0x07,
-                           0x00, 0x87, 0x81, 0x5f, 0x22, 0x94, 0x49, 0x5f, 0x49, 0x80, 0x00,
-                           0x00, 0x80, 0x00, 0x80, 0x70, 0xc8, 0x24, 0xe4, 0x04, 0x88, 0x70)), 3, '\x16'),
-  'bicycle_r':(array('B', (0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x12, 0x13, 0x10, 0x08, 0x07,
-                           0x00, 0xf0, 0x40, 0xfd, 0x22, 0x94, 0x49, 0xfd, 0x49, 0x80, 0x00,
-                           0x40, 0xa0, 0x80, 0x40, 0x70, 0xc8, 0x24, 0x24, 0x04, 0x88, 0x70)), 3, '\x15'),
-  'owncloud': (array('B', (0x00, 0x01, 0x02, 0x03, 0x06, 0x0c, 0x1a, 0x13, 0x11, 0x19, 0x0f,
-                           0x78, 0xcc, 0x87, 0xfc, 0x42, 0x81, 0x81, 0x81, 0x81, 0x43, 0xbd,
-                           0x00, 0x00, 0x00, 0x80, 0x80, 0xe0, 0x30, 0x10, 0x28, 0x28, 0xd0)), 3, '\x14'),
+    'bicycle': (array('B', (0x01, 0x02, 0x00, 0x01, 0x07, 0x09, 0x12, 0x12, 0x10, 0x08, 0x07,
+                            0x00, 0x87, 0x81, 0x5f, 0x22, 0x94, 0x49, 0x5f, 0x49, 0x80, 0x00,
+                            0x00, 0x80, 0x00, 0x80, 0x70, 0xc8, 0x24, 0xe4, 0x04, 0x88, 0x70)), 3, '\x16'),
+    'bicycle_r': (array('B', (0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x12, 0x13, 0x10, 0x08, 0x07,
+                              0x00, 0xf0, 0x40, 0xfd, 0x22, 0x94, 0x49, 0xfd, 0x49, 0x80, 0x00,
+                              0x40, 0xa0, 0x80, 0x40, 0x70, 0xc8, 0x24, 0x24, 0x04, 0x88, 0x70)), 3, '\x15'),
+    'owncloud': (array('B', (0x00, 0x01, 0x02, 0x03, 0x06, 0x0c, 0x1a, 0x13, 0x11, 0x19, 0x0f,
+                             0x78, 0xcc, 0x87, 0xfc, 0x42, 0x81, 0x81, 0x81, 0x81, 0x43, 0xbd,
+                             0x00, 0x00, 0x00, 0x80, 0x80, 0xe0, 0x30, 0x10, 0x28, 0x28, 0xd0)), 3, '\x14'),
 }
 bitmap_builtin = {}
 for i in bitmap_named:
-  bitmap_builtin[bitmap_named[i][2]] = bitmap_named[i]
+    bitmap_builtin[bitmap_named[i][2]] = bitmap_named[i]
 
 
 def bitmap_char(ch):
-  """ Returns a tuple of 11 bytes,
+    """ Returns a tuple of 11 bytes,
       ch = '_' returns (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255)
       The bits in each byte are horizontal, highest bit is left.
   """
-  if ord(ch) < 32:
-    if ch in bitmap_builtin:
-      return bitmap_builtin[ch][:2]
+    if ord(ch) < 32:
+        if ch in bitmap_builtin:
+            return bitmap_builtin[ch][:2]
 
-    global bitmaps_preloaded_unused
-    bitmaps_preloaded_unused = False
-    return bitmap_preloaded[ord(ch)]
+        global bitmaps_preloaded_unused
+        bitmaps_preloaded_unused = False
+        return bitmap_preloaded[ord(ch)]
 
-  o = char_offset[ch]
-  return (font_11x44[o:o+11],1)
+    o = char_offset[ch]
+    return (font_11x44[o:o + 11], 1)
 
 
 def bitmap_text(text):
-  """ returns a tuple of (buffer, length_in_byte_columns_aka_chars)
+    """ returns a tuple of (buffer, length_in_byte_columns_aka_chars)
       We preprocess the text string for substitution patterns
       "::" is replaced with a single ":"
       ":1: is replaced with CTRL-A referencing the first preloaded or loaded image.
@@ -296,137 +333,145 @@ def bitmap_text(text):
       ":heart:" is replaced with a reference to a builtin heart glyph
       ":gfx/logo.png:" preloads the file gfx/logo.png and is replaced the corresponding control char.
   """
-  def colonrepl(m):
-    name = m.group(1)
-    if name == '':
-       return ':'
-    if re.match('^[0-9]*$', name):      # py3 name.isdecimal()
-      return chr(int(name))
-    if '.' in name:
-      bitmap_preloaded.append(bitmap_img(name))
-      return chr(len(bitmap_preloaded)-1)
-    b = bitmap_named[name]
-    return b[2]
-
-  text = re.sub(r':([^:]*):', colonrepl, text)
-  buf = array('B')
-  cols = 0
-  for c in text:
-    (b,n) = bitmap_char(c)
-    buf.extend(b)
-    cols += n
-  return (buf, cols)
+
+    def colonrepl(m):
+        name = m.group(1)
+        if name == '':
+            return ':'
+        if re.match('^[0-9]*$', name):  # py3 name.isdecimal()
+            return chr(int(name))
+        if '.' in name:
+            bitmap_preloaded.append(bitmap_img(name))
+            return chr(len(bitmap_preloaded) - 1)
+        b = bitmap_named[name]
+        return b[2]
+
+    text = re.sub(r':([^:]*):', colonrepl, text)
+    buf = array('B')
+    cols = 0
+    for c in text:
+        (b, n) = bitmap_char(c)
+        buf.extend(b)
+        cols += n
+    return (buf, cols)
 
 
 def bitmap_img(file):
-  """ returns a tuple of (buffer, length_in_byte_columns)
+    """ returns a tuple of (buffer, length_in_byte_columns)
   """
-  from PIL import Image
-
-  im = Image.open(file)
-  print("fetching bitmap from file %s -> (%d x %d)" % (file, im.width, im.height))
-  if im.height != 11:
-    sys.exit("%s: image height must be 11px. Seen %d" % (file, im.height))
-  buf = array('B')
-  cols = int((im.width+7)/8)
-  for col in range(cols):
-    for row in range(11):       # [0..10]
-      byte_val = 0
-      for bit in range(8):      # [0..7]
-        bit_val = 0
-        x = 8*col+bit
-        if x < im.width and row < im.height:
-          pixel_color = im.getpixel( (x, row) )
-          if isinstance(pixel_color, tuple):
-            monochrome_color = sum(pixel_color[:3]) / len(pixel_color[:3])
-          elif isinstance(pixel_color, int):
-            monochrome_color = pixel_color
-          else:
-            sys.exit("%s: Unknown pixel format detected (%s)!" % (file, pixel_color))
-          if monochrome_color > 127:
-            bit_val = 1 << (7-bit)
-          byte_val += bit_val
-      buf.append(byte_val)
-  im.close()
-  return (buf, cols)
+    from PIL import Image
+
+    im = Image.open(file)
+    print("fetching bitmap from file %s -> (%d x %d)" % (file, im.width, im.height))
+    if im.height != 11:
+        sys.exit("%s: image height must be 11px. Seen %d" % (file, im.height))
+    buf = array('B')
+    cols = int((im.width + 7) / 8)
+    for col in range(cols):
+        for row in range(11):  # [0..10]
+            byte_val = 0
+            for bit in range(8):  # [0..7]
+                bit_val = 0
+                x = 8 * col + bit
+                if x < im.width and row < im.height:
+                    pixel_color = im.getpixel((x, row))
+                    if isinstance(pixel_color, tuple):
+                        monochrome_color = sum(pixel_color[:3]) / len(pixel_color[:3])
+                    elif isinstance(pixel_color, int):
+                        monochrome_color = pixel_color
+                    else:
+                        sys.exit("%s: Unknown pixel format detected (%s)!" % (file, pixel_color))
+                    if monochrome_color > 127:
+                        bit_val = 1 << (7 - bit)
+                    byte_val += bit_val
+            buf.append(byte_val)
+    im.close()
+    return (buf, cols)
 
 
 def bitmap(arg):
-  """ if arg is a valid and existing path name, we load it as an image.
+    """ if arg is a valid and existing path name, we load it as an image.
       Otherwise we take it as a string.
   """
-  if os.path.exists(arg):
-    return bitmap_img(arg)
-  return bitmap_text(arg)
+    if os.path.exists(arg):
+        return bitmap_img(arg)
+    return bitmap_text(arg)
 
 
 proto_header = (
-  0x77, 0x61, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    0x77, 0x61, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 )
 
 
 def header(lengths, speeds, modes, blink, ants, brightness=100):
-  """ lengths[0] is the number of chars of the first text
+    """ lengths[0] is the number of chars of the first text
 
       Speeds come in as 1..8, but are needed 0..7 here.
   """
-  a = [int(x) for x in re.split(r'[\s,]+', ants)]
-  a = a + [a[-1]]*(8-len(a))    # repeat last element
+    a = [int(x) for x in re.split(r'[\s,]+', ants)]
+    a = a + [a[-1]] * (8 - len(a))  # repeat last element
 
-  b = [int(x) for x in re.split(r'[\s,]+', blink)]
-  b = b + [b[-1]]*(8-len(b))    # repeat last element
+    b = [int(x) for x in re.split(r'[\s,]+', blink)]
+    b = b + [b[-1]] * (8 - len(b))  # repeat last element
 
-  s = [int(x)-1 for x in re.split(r'[\s,]+', speeds)]
-  s = s + [s[-1]]*(8-len(s))    # repeat last element
+    s = [int(x) - 1 for x in re.split(r'[\s,]+', speeds)]
+    s = s + [s[-1]] * (8 - len(s))  # repeat last element
 
-  m = [int(x) for x in re.split(r'[\s,]+', modes)]
-  m = m + [m[-1]]*(8-len(m))    # repeat last element
+    m = [int(x) for x in re.split(r'[\s,]+', modes)]
+    m = m + [m[-1]] * (8 - len(m))  # repeat last element
 
-  h = list(proto_header)
+    h = list(proto_header)
 
-  if brightness <= 25:
-    h[5] = 0x40
-  elif brightness <= 50:
-    h[5] = 0x20
-  elif brightness <= 75:
-    h[5] = 0x10
+    if brightness <= 25:
+        h[5] = 0x40
+    elif brightness <= 50:
+        h[5] = 0x20
+    elif brightness <= 75:
+        h[5] = 0x10
 
-  for i in range(8):
-    h[6] += b[i]< 8192:
-  print ("Writing more than 8192 bytes damages the display!")
-  sys.exit(1)
+    print("Writing more than 8192 bytes damages the display!")
+    sys.exit(1)
 
 if have_pyhidapi:
-  pyhidapi.hid_write(dev, buf)
+    pyhidapi.hid_write(dev, buf)
 else:
-  for i in range(int(len(buf)/64)):
-    time.sleep(0.1)
-    dev.write(1, buf[i*64:i*64+64])
+    for i in range(int(len(buf) / 64)):
+        time.sleep(0.1)
+        dev.write(1, buf[i * 64:i * 64 + 64])
 
 if have_pyhidapi:
-  pyhidapi.hid_close(dev)
+    pyhidapi.hid_close(dev)
diff --git a/photos/accentuated.gif b/photos/accentuated.gif
new file mode 100644
index 0000000..2071331
Binary files /dev/null and b/photos/accentuated.gif differ
diff --git a/photos/blueBadge.jpg b/photos/blueBadge.jpg
new file mode 100644
index 0000000..9503da3
Binary files /dev/null and b/photos/blueBadge.jpg differ
diff --git a/photos/m2ishm.gif b/photos/m2ishm.gif
new file mode 100644
index 0000000..70f1d37
Binary files /dev/null and b/photos/m2ishm.gif differ