123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- """
- Blockdiag Tag
- ---------
- This tag implements a liquid style tag for blockdiag [1]. You can use different
- diagram types like blockdiag, seqdiag, packetdiag etc. [1]
- [1] http://blockdiag.com/en/blockdiag/
- Syntax
- ------
- {% blockdiag {
- <diagramm type> {
- <CODE>
- }
- }
- %}
- Examples
- --------
- {% blockdiag {
- blockdiag {
- A -> B -> C;
- B -> D;
- }
- }
- %}
- {% blockdiag {
- actdiag {
- A -> B -> C -> D -> E;
- lane {
- A; C; E;
- }
- lane {
- B; D;
- }
- }
- }
- %}
- {% blockdiag {
- packetdiag {
- 0-7: Source Port
- 8-15: Destination Port
- 16-31: Sequence Number
- 32-47: Acknowledgment Number
- }
- }
- %}
- ...
- Output
- ------
- <span class="blockdiag" style="align: center;"><img src="data:image/png;base64,_BASE64_IMAGE DATA_/></span>
- """
- import io
- import os
- import sys
- import base64
- import re
- from .mdx_liquid_tags import LiquidTags
- SYNTAX = '{% blockdiag [diagram type] [code] %}'
- DOT_BLOCK_RE = re.compile(r'^\s*(?P<diagram>\w+).*$', re.MULTILINE | re.DOTALL)
- _draw_mode = 'PNG'
- _publish_mode = 'PNG'
- def get_diag(code, command):
- """ Generate diagramm and return data """
- import tempfile
- import shutil
- code = code + u'\n'
- try:
- tmpdir = tempfile.mkdtemp()
- fd, diag_name = tempfile.mkstemp(dir=tmpdir)
- f = os.fdopen(fd, "w")
- f.write(code.encode('utf-8'))
- f.close()
- format = _draw_mode.lower()
- draw_name = diag_name + '.' + format
- saved_argv = sys.argv
- argv = [diag_name, '-T', format, '-o', draw_name]
- if _draw_mode == 'SVG':
- argv += ['--ignore-pil']
- # Run command
- command.main(argv)
- # Read image data from file
- file_name = diag_name + '.' + _publish_mode.lower()
- with io.open(file_name, 'rb') as f:
- data = f.read()
- f.close()
- finally:
- for file in os.listdir(tmpdir):
- os.unlink(tmpdir + "/" + file)
- # os.rmdir will fail -> use shutil
- shutil.rmtree(tmpdir)
- return data
- def diag(code, command):
- if command == "blockdiag": # blockdiag
- import blockdiag.command
- return get_diag(code, blockdiag.command)
- elif command == "diagram": # diagram
- import blockdiag.command
- return get_diag(code, blockdiag.command)
- elif command == "seqdiag": # seqdiag
- import seqdiag.command
- return get_diag(code, seqdiag.command)
- elif command == "actdiag": # actdiag
- import actdiag.command
- return get_diag(code, actdiag.command)
- elif command == "nwdiag": # nwdiag
- import nwdiag.command
- return get_diag(code, nwdiag.command)
- elif command == "packetdiag": # packetdiag
- import packetdiag.command
- return get_diag(code, packetdiag.command)
- elif command == "rackdiag": # racketdiag
- import rackdiag.command
- return get_diag(code, rackdiag.command)
- else: # not found
- print("No such command %s" % command)
- return None
- @LiquidTags.register("blockdiag")
- def blockdiag_parser(preprocessor, tag, markup):
- """ Blockdiag parser """
- m = DOT_BLOCK_RE.search(markup)
- if m:
- # Get diagram type and code
- diagram = m.group('diagram').strip()
- code = markup
- # Run command
- output = diag(code, diagram)
- if output:
- # Return Base64 encoded image
- return '<span class="blockdiag" style="align: center;"><img src="data:image/png;base64,%s"></span>' % base64.b64encode(output)
- else:
- raise ValueError('Error processing input. '
- 'Expected syntax: {0}'.format(SYNTAX))
- # This import allows image tag to be a Pelican plugin
- from .liquid_tags import register
|