pdsimgtopng 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #!/usr/bin/env python
  2. # $URL: http://pypng.googlecode.com/svn/trunk/code/pdsimgtopng $
  3. # $Rev: 154 $
  4. # PDS Image to PNG
  5. import re
  6. import struct
  7. import png
  8. class FormatError(Exception):
  9. pass
  10. def pdskey(s, k):
  11. """Lookup key `k` in string `s`. Returns value (as a string), or
  12. raises exception if not found.
  13. """
  14. assert re.match(r' *\^?[:\w]+$', k)
  15. safere = '^' + re.escape(k) +r' *= *(\w+)'
  16. m = re.search(safere, s, re.MULTILINE)
  17. if not m:
  18. raise FormatError("Can't find %s." % k)
  19. return m.group(1)
  20. def img(inp):
  21. """Open the PDS IMG file `inp` and return (*pixels*, *info*).
  22. *pixels* is an iterator over the rows, *info* is the information
  23. dictionary.
  24. """
  25. err = __import__('sys').stderr
  26. consumed = 1024
  27. s = inp.read(consumed)
  28. record_type = pdskey(s, 'RECORD_TYPE')
  29. if record_type != 'FIXED_LENGTH':
  30. raise FormatError(
  31. "Can only deal with FIXED_LENGTH record type (found %s)" %
  32. record_type)
  33. record_bytes = int(pdskey(s,'RECORD_BYTES'))
  34. file_records = int(pdskey(s, 'FILE_RECORDS'))
  35. label_records = int(pdskey(s, 'LABEL_RECORDS'))
  36. remaining = label_records * record_bytes - consumed
  37. s += inp.read(remaining)
  38. consumed += remaining
  39. image_pointer = int(pdskey(s, '^IMAGE'))
  40. # "^IMAGE" locates a record. Records are numbered starting from 1.
  41. image_index = image_pointer - 1
  42. image_offset = image_index * record_bytes
  43. gap = image_offset - consumed
  44. assert gap >= 0
  45. if gap:
  46. inp.read(gap)
  47. # This assumes there is only one OBJECT in the file, and it is the
  48. # IMAGE.
  49. height = int(pdskey(s, ' LINES'))
  50. width = int(pdskey(s, ' LINE_SAMPLES'))
  51. sample_type = pdskey(s, ' SAMPLE_TYPE')
  52. sample_bits = int(pdskey(s, ' SAMPLE_BITS'))
  53. # For Messenger MDIS, SAMPLE_BITS is reported as 16, but only values
  54. # from 0 ot 4095 are used.
  55. bitdepth = 12
  56. if sample_type == 'MSB_UNSIGNED_INTEGER':
  57. fmt = '>H'
  58. else:
  59. raise 'Unknown sample type: %s.' % sample_type
  60. sample_bytes = (1,2)[bitdepth > 8]
  61. row_bytes = sample_bytes * width
  62. fmt = fmt[:1] + str(width) + fmt[1:]
  63. def rowiter():
  64. for y in range(height):
  65. yield struct.unpack(fmt, inp.read(row_bytes))
  66. info = dict(greyscale=True, alpha=False, bitdepth=bitdepth,
  67. size=(width,height), gamma=1.0)
  68. return rowiter(), info
  69. def main(argv=None):
  70. import sys
  71. if argv is None:
  72. argv = sys.argv
  73. argv = argv[1:]
  74. arg = argv
  75. if len(arg) >= 1:
  76. f = open(arg[0], 'rb')
  77. else:
  78. f = sys.stdin
  79. pixels,info = img(f)
  80. w = png.Writer(**info)
  81. w.write(sys.stdout, pixels)
  82. if __name__ == '__main__':
  83. main()