diag.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. """
  2. Blockdiag Tag
  3. ---------
  4. This tag implements a liquid style tag for blockdiag [1]. You can use different
  5. diagram types like blockdiag, seqdiag, packetdiag etc. [1]
  6. [1] http://blockdiag.com/en/blockdiag/
  7. Syntax
  8. ------
  9. {% blockdiag {
  10. <diagramm type> {
  11. <CODE>
  12. }
  13. }
  14. %}
  15. Examples
  16. --------
  17. {% blockdiag {
  18. blockdiag {
  19. A -> B -> C;
  20. B -> D;
  21. }
  22. }
  23. %}
  24. {% blockdiag {
  25. actdiag {
  26. A -> B -> C -> D -> E;
  27. lane {
  28. A; C; E;
  29. }
  30. lane {
  31. B; D;
  32. }
  33. }
  34. }
  35. %}
  36. {% blockdiag {
  37. packetdiag {
  38. 0-7: Source Port
  39. 8-15: Destination Port
  40. 16-31: Sequence Number
  41. 32-47: Acknowledgment Number
  42. }
  43. }
  44. %}
  45. ...
  46. Output
  47. ------
  48. <span class="blockdiag" style="align: center;"><img src="data:image/png;base64,_BASE64_IMAGE DATA_/></span>
  49. """
  50. import io
  51. import os
  52. import sys
  53. import base64
  54. import re
  55. from .mdx_liquid_tags import LiquidTags
  56. SYNTAX = '{% blockdiag [diagram type] [code] %}'
  57. DOT_BLOCK_RE = re.compile(r'^\s*(?P<diagram>\w+).*$', re.MULTILINE | re.DOTALL)
  58. _draw_mode = 'PNG'
  59. _publish_mode = 'PNG'
  60. def get_diag(code, command):
  61. """ Generate diagramm and return data """
  62. import tempfile
  63. import shutil
  64. code = code + u'\n'
  65. try:
  66. tmpdir = tempfile.mkdtemp()
  67. fd, diag_name = tempfile.mkstemp(dir=tmpdir)
  68. f = os.fdopen(fd, "w")
  69. f.write(code.encode('utf-8'))
  70. f.close()
  71. format = _draw_mode.lower()
  72. draw_name = diag_name + '.' + format
  73. saved_argv = sys.argv
  74. argv = [diag_name, '-T', format, '-o', draw_name]
  75. if _draw_mode == 'SVG':
  76. argv += ['--ignore-pil']
  77. # Run command
  78. command.main(argv)
  79. # Read image data from file
  80. file_name = diag_name + '.' + _publish_mode.lower()
  81. with io.open(file_name, 'rb') as f:
  82. data = f.read()
  83. f.close()
  84. finally:
  85. for file in os.listdir(tmpdir):
  86. os.unlink(tmpdir + "/" + file)
  87. # os.rmdir will fail -> use shutil
  88. shutil.rmtree(tmpdir)
  89. return data
  90. def diag(code, command):
  91. if command == "blockdiag": # blockdiag
  92. import blockdiag.command
  93. return get_diag(code, blockdiag.command)
  94. elif command == "diagram": # diagram
  95. import blockdiag.command
  96. return get_diag(code, blockdiag.command)
  97. elif command == "seqdiag": # seqdiag
  98. import seqdiag.command
  99. return get_diag(code, seqdiag.command)
  100. elif command == "actdiag": # actdiag
  101. import actdiag.command
  102. return get_diag(code, actdiag.command)
  103. elif command == "nwdiag": # nwdiag
  104. import nwdiag.command
  105. return get_diag(code, nwdiag.command)
  106. elif command == "packetdiag": # packetdiag
  107. import packetdiag.command
  108. return get_diag(code, packetdiag.command)
  109. elif command == "rackdiag": # racketdiag
  110. import rackdiag.command
  111. return get_diag(code, rackdiag.command)
  112. else: # not found
  113. print("No such command %s" % command)
  114. return None
  115. @LiquidTags.register("blockdiag")
  116. def blockdiag_parser(preprocessor, tag, markup):
  117. """ Blockdiag parser """
  118. m = DOT_BLOCK_RE.search(markup)
  119. if m:
  120. # Get diagram type and code
  121. diagram = m.group('diagram').strip()
  122. code = markup
  123. # Run command
  124. output = diag(code, diagram)
  125. if output:
  126. # Return Base64 encoded image
  127. return '<span class="blockdiag" style="align: center;"><img src="data:image/png;base64,%s"></span>' % base64.b64encode(output)
  128. else:
  129. raise ValueError('Error processing input. '
  130. 'Expected syntax: {0}'.format(SYNTAX))
  131. # This import allows image tag to be a Pelican plugin
  132. from .liquid_tags import register