Guest User

softstrip.py

a guest
Dec 1st, 2014
476
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.57 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. import re, struct, sys
  4. from PIL import Image
  5.  
  6. # Author: @doegox
  7. # Original version was from
  8. # https://www.reddit.com/r/programming/comments/1ye0th/i_found_this_in_a_computer_magazine_from_1986/
  9.  
  10. # This version expects a perfect BW image, 1 pixel per dot
  11.  
  12. # Relevant patents:
  13. # https://www.google.com/patents/US4692603
  14. # https://www.google.com/patents/US4728783
  15. # https://www.google.com/patents/US4782221
  16.  
  17. # very first lines: count number of black lines N -> there are (N+4)/2 nibbles in each data line
  18. # here 10 -> (10+4)/2 = 7 nibbles per line
  19. # dibit/bit/dibit_sync/dibit_P1/dibit_nibbles/dibit_P2/bit_or_dibit/dibit/bit_sync
  20. # P1: parity of the even bits
  21. # P2: parity of the odd bits
  22. # First data line should be 00 00 00 LL HH -> total nr of bytes
  23.  
  24. image = Image.open("softstrip_bw.png")
  25.  
  26. w, h = image.size
  27.  
  28. def getcolor(pixel):
  29.     return pixel^1
  30.  
  31. def paritycheck(bits):
  32.     a = bits[::2]
  33.     b = bits[1::2]
  34.     if '?' in a:
  35.         a = False
  36.     else:
  37.         a = (sum(a) % 2 == 0)
  38.     if '?' in b:
  39.         b = False
  40.     else:
  41.         b = (sum(b) % 2 == 0)
  42.     return a and b
  43.  
  44. def getnibbles(bits):
  45.     'return [(nibble, validmask)]'
  46.     ret = []
  47.     par = paritycheck(bits)
  48.     bits = bits[1:-1]  # remove parity bits
  49.     assert len(bits) % 4 == 0
  50.     while len(bits):
  51.         nib, bits = bits[:4], bits[4:]
  52.         n = 0
  53.         invalid = 0
  54.         for b in reversed(nib):
  55.             n <<= 1
  56.             invalid <<= 1
  57.             if b not in (0, 1):
  58.                 invalid |= 1
  59.             else:
  60.                 n |= b
  61.         if not par:
  62.             invalid = 0b1111
  63.         ret.append((n, invalid ^ 0b1111))
  64.     return ret
  65.  
  66. def getbytes(nibbles):
  67.     bytes = []
  68.     while len(nibbles) >= 2:
  69.         a, av = nibbles.pop(0)
  70.         b, bv = nibbles.pop(0)
  71.         c = chr((b << 4) | a)
  72.         v = chr((bv << 4) | av)
  73.         bytes.append((c, v))
  74.     return bytes
  75.  
  76. firstline=[]
  77. nibbles = []
  78. bytes = []
  79. for y in range(h):
  80.     dibits = []
  81.     for x in range(w):
  82.         dibits.append(getcolor(image.getpixel((x,y))))
  83.  
  84.     bits = []
  85.     for i in range(5, len(dibits) - 5, 2):
  86.         a, b = dibits[i:i+2]
  87.         if a != b:
  88.             bits.append(int(a))
  89.         else:
  90.             bits.append('?')
  91.  
  92.     print ''.join(' #'[b] for b in dibits), ''.join(map(str, bits)), ''.join("%x" % c for c, v in getnibbles(bits)), ''.join("%x" % v for c, v in getnibbles(bits))
  93.  
  94.     if nibbles == [] and '?' in bits:
  95.         continue
  96.     if firstline == []:
  97.         firstline = bits
  98.     else:
  99.         if bits != firstline:
  100.             # Start recording data
  101.             nibbles += getnibbles(bits)
  102. bytes += getbytes(nibbles)
  103.  
  104. raw = ''.join(c for c, v in bytes)
  105. valid = ''.join(v for c, v in bytes)
  106. header = raw[:5]
  107. assert header[:3]=='\0\0\0'
  108. size, = struct.unpack('<H', header[3:])
  109. data = raw[5:]
  110. valid = valid[5:]
  111. assert len(data) >= size, 'data length doesn\'t match size given in header'
  112. if len(data) > size:
  113.     print "Truncating data from %i to %i bytes" % (len(data), size)
  114.     data=data[:size]
  115.  
  116. open('out.bin', 'w').write(data)
  117. open('out.valid', 'w').write(valid)
  118.  
  119. fmt = '%-48s %-16s %-32s'
  120.  
  121. allvalid = bool(re.match(r'\xff+$', valid))
  122.  
  123. print
  124. print fmt % ('hex', 'ascii', '' if allvalid else 'valid bits')
  125. for i in range(0, len(data), 16):
  126.     d = data[i:i+16]
  127.     v = valid[i:i+16]
  128.     hex = ' '.join('%02x' % ord(c) for c in d)
  129.     ascii = ''.join((c if 32 <= ord(c) <= 126 else '.') for c in d)
  130.     val = '' if allvalid else ''.join('%02x' % ord(c) for c in v)
  131.     print fmt % (hex, ascii, val)
Add Comment
Please, Sign In to add comment