bitdiagram.py :  » Media-Sound-Audio » Python-Audio-Tools » audiotools-2.14 » docs » reference » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Media Sound Audio » Python Audio Tools 
Python Audio Tools » audiotools 2.14 » docs » reference » bitdiagram.py
#!/usr/bin/python

import sys

try:
    from reportlab.pdfgen import canvas
    from reportlab.lib.units import inch
    from reportlab.pdfbase.pdfmetrics import registerFont
    from reportlab.pdfbase.ttfonts import TTFont
except ImportError:
    print "*** ReportLab is required"
    print "Please fetch the open-source version from http://www.reportlab.org"
    sys.exit(1)

(SOLID,DASHED,DOTTED,BLANK) = range(4)
(NE,NW,SE,SW) = range(4)
ROW_HEIGHT = 22

class Chunk:
    #text should be the chunk's text Unicode string, or None
    #width is size of the chunk as a floating point percentage
    #chunk_id is a unique text string, or None
    #style is one of the style enumerations such as SOLID, DASHED, etc.
    def __init__(self, text = None, start_size = None, end_size = None,
                 width = 1.0, chunk_id = None, style = SOLID):
        self.text = text
        self.width = width
        self.id = chunk_id
        self.style = style
        if (start_size is not None):
            self.start_size = unicode(start_size)
        else:
            self.start_size = None
        if (end_size is not None):
            self.end_size = unicode(end_size)
        else:
            self.end_size = None

        #the chunk's location in the PDF, in x,y point pairs
        self.ne = self.nw = self.se = self.sw = (0,0)

    def get_corner(self, corner):
        if (corner == NE):
            return self.ne
        elif (corner == NW):
            return self.nw
        elif (corner == SE):
            return self.se
        elif (corner == SW):
            return self.sw
        else:
            raise ValueError("invalid corner")

    def previous_column(self, row):
        i = row.index(self) - 1
        if (i >= 0):
            return row[i]
        else:
            return None

    def next_column(self, row):
        try:
            return row[row.index(self) + 1]
        except IndexError:
            return None

    def previous_chunk(self, chunks):
        i = chunks.index(self) - 1
        if (i >= 0):
            return chunks[i]
        else:
            return None

    def pt_width(self):
        return abs(self.nw[0] - self.ne[0])

    def pt_height(self):
        return abs(self.nw[1] - self.sw[1])

    def __repr__(self):
        return "Chunk(%s,%s,%s,%s,%s,%s)" % \
            (repr(self.text),self.start_size,self_end_size,
             self.width,self.id,self.style)

    def to_pdf(self, pdf):
        pdf.setStrokeColorRGB(0,0,0)
        pdf.setFillColorRGB(0,0,0)

        if (self.style is not BLANK):
            if (self.style == SOLID):
                pdf.setDash(1,0)
            elif (self.style == DASHED):
                pdf.setDash(6,6)
            elif (self.style == DOTTED):
                pdf.setDash(1,6)
            pdf.rect(self.sw[0],self.sw[1],self.pt_width(),self.pt_height())

        if (self.text is not None):
            pdf.setFont("DejaVu",10)
            pdf.drawCentredString((self.ne[0] + self.nw[0]) / 2,
                                  self.se[1] + 10,
                                  self.text)

            pdf.setFont("DejaVu",6)
            if ((self.start_size == self.end_size) and
                (self.start_size is not None)):
                pdf.drawCentredString((self.ne[0] + self.nw[0]) / 2,
                                  self.se[1] + 3,
                                  self.start_size)
            else:
                if (self.start_size is not None):
                    pdf.drawString(self.sw[0] + 4,
                                   self.se[1] + 3,
                                   self.start_size)
                if (self.end_size is not None):
                    pdf.drawRightString(self.se[0] - 4,
                                        self.se[1] + 3,
                                        self.end_size)

class BlankChunk(Chunk):
    def __init__(self, width = 1.0):
        Chunk.__init__(self,text=None,start_size=None,end_size=None,
                       width=width,chunk_id=None,
                       style=BLANK)

class Row:
    def __init__(self):
        self.chunks = []
        self.height = ROW_HEIGHT

    def add_chunk(self, chunk):
        self.chunks.append(chunk)

    def index(self, chunk):
        return self.chunks.index(chunk)

    def __iter__(self):
        return iter(self.chunks)

    def __len__(self):
        return len(self.chunks)

    def __getitem__(self, i):
        return self.chunks[i]

    def to_pdf(self, pdf, total_width, top, bottom):
        for (col_pos,chunk) in enumerate(self):
            previous_column = chunk.previous_column(self)
            if (previous_column is None):
                left = 0
            else:
                left = previous_column.ne[0]
            right = left + (chunk.width * total_width)

            chunk.nw = (left,top)
            chunk.ne = (right,top)
            chunk.sw = (left,bottom)
            chunk.se = (right,bottom)

            #render the calculated chunk
            chunk.to_pdf(pdf)

class Spacer(Row):
    def __init__(self, height):
        self.chunks = []
        self.height = height

    def add_chunk(self, chunk):
        pass

    def to_pdf(self, pdf, total_width, top, bottom):
        pass


class Line:
    def __init__(self,
                 start_chunk, start_corner,
                 end_chunk, end_corner,
                 style=SOLID):
        self.start_chunk = start_chunk
        self.start_corner = start_corner
        self.end_chunk = end_chunk
        self.end_corner = end_corner
        self.style = style

    def render(self, pdf):
        if (self.style is not BLANK):
            if (self.style == SOLID):
                pdf.setDash(1,0)
            elif (self.style == DASHED):
                pdf.setDash(6,6)
            elif (self.style == DOTTED):
                pdf.setDash(1,6)
            pdf.setStrokeColorRGB(0,0,0)
            (start_x,start_y) = self.start_chunk.get_corner(self.start_corner)
            (end_x,end_y) = self.end_chunk.get_corner(self.end_corner)
            pdf.line(start_x,start_y,end_x,end_y)

class ChunkTable:
    def __init__(self):
        self.rows = []
        self.chunks = []
        self.lines = []
        self.chunk_map = {}

    def add_row(self, *chunks):
        row = Row()
        for chunk in chunks:
            if (chunk.id is not None):
                if (chunk.id in self.chunk_map):
                    raise ValueError("chunk ID %s already taken" % (chunk.id))
                else:
                    self.chunk_map[chunk.id] = chunk

            row.add_chunk(chunk)
            self.chunks.append(chunk)
        self.rows.append(row)

    def add_spacer(self, height):
        self.rows.append(Spacer(height))

    def add_line(self, start_id, start_corner,
                 end_id, end_corner,
                 style=SOLID):
        self.lines.append(Line(self.chunk_map[start_id],start_corner,
                               self.chunk_map[end_id],end_corner,
                               style))

    #given a width value (in points) and filename string,
    #render all the lines and chunks as a PDF file
    def to_pdf(self, total_width, filename):
        total_rows = len(self.rows)
        total_height = sum([row.height for row in self.rows])

        registerFont(TTFont("DejaVu", "DejaVuSans.ttf"))

        pdf = canvas.Canvas(filename)
        pdf.setPageSize((total_width,total_height))

        #calculate the positions of each row
        top = total_height
        for (row_pos,row) in enumerate(self.rows):
            bottom = top - row.height
            row.to_pdf(pdf, total_width, top, bottom)
            top = bottom

        #calculate the positions for each line
        for line in self.lines:
            line.render(pdf)

        pdf.showPage()
        pdf.save()


# def build_pdf():
#     wave = ChunkTable()
#     wave.add_row(Chunk(u"ID (\u2018RIFF\u2019 0x52494646)",0,31,.333333),
#                  Chunk(u"Chunk Size (file size - 8)",32,63,.333333),
#                  Chunk(u"Chunk Data",64,None,.333333,
#                        chunk_id="data"))
#     wave.add_row(BlankChunk(1.0))
#     wave.add_row(Chunk(u"Type (\u2018WAVE\u2019 0x57415645)",0,31,.333333,
#                        chunk_id="type"),
#                  Chunk(u"Chunk\u2081",32,None,.222222,
#                        chunk_id="chunk"),
#                  Chunk(u"Chunk\u2082",None,None,.222222),
#                  Chunk(u"...",None,None,.222222,style=DASHED,
#                        chunk_id="..."))

#     wave.add_line("data",SW,"type",NW,DOTTED)
#     wave.add_line("data",SE,"...",NE,DOTTED)

#     wave.add_row(BlankChunk(1.0))
#     wave.add_row(Chunk(u"Chunk ID (ASCII text)",0,31,.333333,
#                        chunk_id="chunk_id"),
#                  Chunk(u"Chunk Size",32,63,.333333),
#                  Chunk(u"Chunk Data",64,None,.333333,style=DASHED,
#                        chunk_id="chunk_data"))

#     wave.add_line("chunk",SW,"chunk_id",NW,DOTTED)
#     wave.add_line("chunk",SE,"chunk_data",NE,DOTTED)

#     wave.to_pdf(6 * 72,"bits.pdf")

def parse_xml(xml_filename):
    import xml.dom.minidom

    STYLE_MAP = {u"solid":SOLID,
                 u"dashed":DASHED,
                 u"dotted":DOTTED,
                 u"blank":BLANK}

    CORNER_MAP = {u"ne":NE,
                  u"se":SE,
                  u"nw":NW,
                  u"sw":SW}

    dom = xml.dom.minidom.parse(xml_filename)
    diagram = dom.getElementsByTagName(u"diagram")[0]
    table = ChunkTable()

    for part in diagram.childNodes:
        if (part.nodeName == u'row'):
            columns = []
            for col in part.childNodes:
                if (col.nodeName == u'col'):
                    chunk_args = {}
                    if (len(col.childNodes) > 0):
                        chunk_args["text"] = col.childNodes[0].data
                    if (col.hasAttribute("start")):
                        chunk_args["start_size"] = col.getAttribute("start")
                    if (col.hasAttribute("end")):
                        chunk_args["end_size"] = col.getAttribute("end")
                    if (col.hasAttribute("width")):
                        chunk_args["width"] = float(col.getAttribute("width"))
                    if (col.hasAttribute("id")):
                        chunk_args["chunk_id"] = col.getAttribute("id")
                    if (col.hasAttribute("style")):
                        chunk_args["style"] = STYLE_MAP[col.getAttribute("style")]
                    columns.append(Chunk(**chunk_args))
                elif (col.nodeName == u'blank'):
                    chunk_args = {}
                    if (col.hasAttribute("width")):
                        chunk_args["width"] = float(col.getAttribute("width"))
                    columns.append(BlankChunk(**chunk_args))

            table.add_row(*columns)
        elif (part.nodeName == u"spacer"):
            if (part.hasAttribute("height")):
                table.add_spacer(int(
                        round(ROW_HEIGHT *
                              float(part.getAttribute("height")))))
            else:
                table.add_spacer(ROW_HEIGHT)
        elif (part.nodeName == u"line"):
            table.add_line(part.getAttribute("s_id"),
                           CORNER_MAP[part.getAttribute("s_corner")],
                           part.getAttribute("e_id"),
                           CORNER_MAP[part.getAttribute("e_corner")],
                           STYLE_MAP[part.getAttribute("style")])

    return table

if (__name__ == '__main__'):
    import optparse

    parser = optparse.OptionParser()
    parser.add_option('-i','--input',dest='input',help='input XML file')
    parser.add_option('-o','--output',dest='output',help='output PDF file')
    parser.add_option('-w','--width',dest='width',
                      type='int',default=6 * 72,
                      help='digram width, in PostScript points')

    (options,args) = parser.parse_args()

    if (options.input is None):
        print "*** An input file is required"
        sys.exit(1)
    if (options.output is None):
        print "*** An output file is required"
        sys.exit(1)

    parse_xml(options.input).to_pdf(options.width,options.output)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.