Beispiel #1
0
    def _create_freeze_panes(
        self, sheet_name: str, freeze_panes: Tuple[int, int]
    ) -> None:
        """
        Create freeze panes in the sheet.

        Parameters
        ----------
        sheet_name : str
            Name of the spreadsheet
        freeze_panes : tuple of (int, int)
            Freeze pane location x and y
        """
        from odf.config import (
            ConfigItem,
            ConfigItemMapEntry,
            ConfigItemMapIndexed,
            ConfigItemMapNamed,
            ConfigItemSet,
        )

        config_item_set = ConfigItemSet(name="ooo:view-settings")
        self.book.settings.addElement(config_item_set)

        config_item_map_indexed = ConfigItemMapIndexed(name="Views")
        config_item_set.addElement(config_item_map_indexed)

        config_item_map_entry = ConfigItemMapEntry()
        config_item_map_indexed.addElement(config_item_map_entry)

        config_item_map_named = ConfigItemMapNamed(name="Tables")
        config_item_map_entry.addElement(config_item_map_named)

        config_item_map_entry = ConfigItemMapEntry(name=sheet_name)
        config_item_map_named.addElement(config_item_map_entry)

        config_item_map_entry.addElement(
            ConfigItem(name="HorizontalSplitMode", type="short", text="2")
        )
        config_item_map_entry.addElement(
            ConfigItem(name="VerticalSplitMode", type="short", text="2")
        )
        config_item_map_entry.addElement(
            ConfigItem(
                name="HorizontalSplitPosition", type="int", text=str(freeze_panes[0])
            )
        )
        config_item_map_entry.addElement(
            ConfigItem(
                name="VerticalSplitPosition", type="int", text=str(freeze_panes[1])
            )
        )
        config_item_map_entry.addElement(
            ConfigItem(name="PositionRight", type="int", text=str(freeze_panes[0]))
        )
        config_item_map_entry.addElement(
            ConfigItem(name="PositionBottom", type="int", text=str(freeze_panes[1]))
        )
def doit(args):
    logfile = args.logger
    if args.report: logfile.loglevel = args.report

    try:
        root = ET.parse(args.input).getroot()
    except:
        logfile.log("Error parsing FTML input", "S")

    if args.font:  # font(s) specified on command line
        fontlist = getfonts(args.font, logfile)
    else:  # get font spec from FTML fontsrc element
        fontlist = getfonts([root.find("./head/fontsrc").text], logfile, False)
        #fontlist = getfonts( [fs.text for fs in root.findall("./head/fontsrc")], False ) ### would allow multiple fontsrc elements
    numfonts = len(fontlist)
    if numfonts == 0:
        logfile.log("No font(s) specified", "S")
    if numfonts > 1:
        formattedfontnum = ["{0:02d}".format(n) for n in range(numfonts)]
    else:
        formattedfontnum = [""]
    logfile.log("Font(s) specified:", "V")
    for n, (fontname, bold, italic, embeddedfont) in enumerate(fontlist):
        logfile.log(
            " " + formattedfontnum[n] + " " + fontname +
            BoldItalic(bold, italic) + " " + str(embeddedfont), "V")

    # get optional fontscale; compute pointsize as int(12*fontscale/100). If result xx is not 12, then add "fo:font-size=xxpt" in Px styles
    pointsize = 12
    fontscaleel = root.find("./head/fontscale")
    if fontscaleel != None:
        fontscale = fontscaleel.text
        try:
            pointsize = int(int(fontscale) * 12 / 100)
        except ValueError:
            # any problem leaves pointsize 12
            logfile.log("Problem with fontscale value; defaulting to 12 point",
                        "W")

    # Get FTML styles and generate LO writer styles
    # P2 is paragraph style for string element when no features specified
    # each Px (for P3...) corresponds to an FTML style, which specifies lang or feats or both
    # if numfonts > 1, two-digit font number is appended to make an LO writer style for each FTML style + font combo
    # When LO writer style is used with attribute rtl="True", "R" appended to style name
    LOstyles = {}
    ftmlstyles = {}
    Pstylenum = 2
    LOstyles["P2"] = ("", None, None)
    ftmlstyles[0] = "P2"
    for s in root.findall("./head/styles/style"):
        Pstylenum += 1
        Pnum = "P" + str(Pstylenum)
        featstring = ""
        if s.get('feats'):
            featstring = parsefeats(s.get('feats'))
        langname = None
        countryname = None
        lang = s.get('lang')
        if lang != None:
            x = re.match(langcode, lang)
            langname = x.group('langname')
            countryname = x.group('countryname')
        # FTML <test> element @stylename attribute references this <style> element @name attribute
        ftmlstyles[s.get('name')] = Pnum
        LOstyles[Pnum] = (featstring, langname, countryname)

    # create LOwriter file and construct styles for tables, column widths, etc.
    LOdoc = OpenDocumentText()
    init(LOdoc, numfonts)
    # Initialize sequence counters
    sds = SequenceDecls()
    sd = sds.addElement(
        SequenceDecl(displayoutlinelevel='0', name='Illustration'))
    sd = sds.addElement(SequenceDecl(displayoutlinelevel='0', name='Table'))
    sd = sds.addElement(SequenceDecl(displayoutlinelevel='0', name='Text'))
    sd = sds.addElement(SequenceDecl(displayoutlinelevel='0', name='Drawing'))
    LOdoc.text.addElement(sds)

    # Create Px style for each (featstring, langname, countryname) tuple in LOstyles
    # and for each font (if >1 font, append to Px style name a two-digit number corresponding to the font in fontlist)
    # and (if at least one rtl attribute) suffix of nothing or "R"
    # At the same time, collect info for creating FontFace elements (and any embedded fonts)
    suffixlist = ["", "R"
                  ] if root.find(".//test/[@rtl='True']") != None else [""]
    fontfaces = {}
    for p in sorted(LOstyles, key=lambda x: int(x[1:])
                    ):  # key = lambda x : int(x[1:]) corrects sort order
        featstring, langname, countryname = LOstyles[p]
        for n, (fontname, bold, italic, embeddedfont) in enumerate(
                fontlist):  # embeddedfont = None if no embedding needed
            fontnum = formattedfontnum[n]
            # Collect fontface info: need one for each font family + feature combination
            # Put embedded font in list only under fontname with empty featstring
            if (fontname, featstring) not in fontfaces:
                fontfaces[(fontname, featstring)] = []
            if embeddedfont:
                if (fontname, "") not in fontfaces:
                    fontfaces[(fontname, "")] = []
                if embeddedfont not in fontfaces[(fontname, "")]:
                    fontfaces[(fontname, "")].append(embeddedfont)
            # Generate paragraph styles
            for s in suffixlist:
                pstyle = Style(name=p + fontnum + s, family="paragraph")
                if s == "R":
                    pstyle.addElement(
                        ParagraphProperties(textalign="end",
                                            justifysingleword="false",
                                            writingmode="rl-tb"))
                pstyledic = {}
                pstyledic['fontnamecomplex'] = \
                pstyledic['fontnameasian'] =\
                pstyledic['fontname'] = fontname + featstring
                pstyledic['fontsizecomplex'] = \
                pstyledic['fontsizeasian'] = \
                pstyledic['fontsize'] = str(pointsize) + "pt"
                if bold:
                    pstyledic['fontweightcomplex'] = \
                    pstyledic['fontweightasian'] = \
                    pstyledic['fontweight'] = 'bold'
                if italic:
                    pstyledic['fontstylecomplex'] = \
                    pstyledic['fontstyleasian'] = \
                    pstyledic['fontstyle'] = 'italic'
                if langname != None:
                    pstyledic['languagecomplex'] = \
                    pstyledic['languageasian'] = \
                    pstyledic['language'] = langname
                if countryname != None:
                    pstyledic['countrycomplex'] = \
                    pstyledic['countryasian'] = \
                    pstyledic['country'] = countryname
                pstyle.addElement(TextProperties(attributes=pstyledic))
                #                LOdoc.styles.addElement(pstyle)    ### tried this, but when saving the generated odt, LO changed them to automatic styles
                LOdoc.automaticstyles.addElement(pstyle)

    fontstoembed = []
    for fontname, featstring in sorted(
            fontfaces
    ):  ### Or find a way to keep order of <style> elements from original FTML?
        ff = FontFace(name=fontname + featstring,
                      fontfamily=fontname + featstring,
                      fontpitch="variable")
        LOdoc.fontfacedecls.addElement(ff)
        if fontfaces[(fontname,
                      featstring)]:  # embedding needed for this combination
            for fontfile in fontfaces[(fontname, featstring)]:
                fontstoembed.append(fontfile)  # make list for embedding
                ffsrc = FontFaceSrc()
                ffuri = FontFaceUri(
                    **{
                        'href': "Fonts/" + os.path.basename(fontfile),
                        'type': "simple"
                    })
                ffformat = FontFaceFormat(**{'string': 'truetype'})
                ff.addElement(ffsrc)
                ffsrc.addElement(ffuri)
                ffuri.addElement(ffformat)

    basename = "Table1.B"
    colorcount = 0
    colordic = {
    }  # record color #rrggbb as key and "Table1.Bx" as stylename (where x is current color count)
    tablenum = 0

    # get title and comment and use as title and subtitle
    titleel = root.find("./head/title")
    if titleel != None:
        LOdoc.text.addElement(
            H(outlinelevel=1, stylename="Title", text=titleel.text))
    commentel = root.find("./head/comment")
    if commentel != None:
        LOdoc.text.addElement(P(stylename="Subtitle", text=commentel.text))

    # Each testgroup element begins a new table
    for tg in root.findall("./testgroup"):
        # insert label attribute of testgroup element as subtitle
        tglabel = tg.get('label')
        if tglabel != None:
            LOdoc.text.addElement(
                H(outlinelevel=1, stylename="Subtitle", text=tglabel))

        # insert text from comment subelement of testgroup element
        tgcommentel = tg.find("./comment")
        if tgcommentel != None:
            #print("commentel found")
            LOdoc.text.addElement(P(text=tgcommentel.text))

        tgbg = tg.get(
            'background')  # background attribute of testgroup element
        tablenum += 1
        table = Table(name="Table" + str(tablenum), stylename="Table1")
        table.addElement(TableColumn(stylename="Table1.A"))
        for n in range(numfonts):
            table.addElement(TableColumn(stylename="Table1.B"))
        table.addElement(TableColumn(stylename="Table1.A"))
        table.addElement(TableColumn(stylename="Table1.D"))
        for t in tg.findall("./test"):  # Each test element begins a new row
            # stuff to start the row
            labeltext = t.get('label')
            stylename = t.get('stylename')
            stringel = t.find('./string')
            commentel = t.find('./comment')
            rtlsuffix = "R" if t.get('rtl') == 'True' else ""
            comment = commentel.text if commentel != None else None
            colBstyle = "Table1.A1"
            tbg = t.get(
                'background'
            )  # get background attribute of test group (if one exists)
            if tbg == None: tbg = tgbg
            if tbg != None:  # if background attribute for test element (or background attribute for testgroup element)
                if tbg not in colordic:  # if color not found in color dic, create new style
                    colorcount += 1
                    newname = basename + str(colorcount)
                    colordic[tbg] = newname
                    tb1style = Style(name=newname, family="table-cell")
                    tb1style.addElement(
                        TableCellProperties(
                            attributes={
                                'padding': "0.0382in",
                                'border': "0.05pt solid #000000",
                                'backgroundcolor': tbg
                            }))
                    LOdoc.automaticstyles.addElement(tb1style)
                colBstyle = colordic[tbg]

            row = TableRow()
            table.addElement(row)
            # fill cells
            # column A (label)
            cell = TableCell(stylename="Table1.A1", valuetype="string")
            if labeltext:
                cell.addElement(
                    P(stylename="Table_20_Contents", text=labeltext))
            row.addElement(cell)

            # column B (string)
            for n in range(numfonts):
                Pnum = ftmlstyles[stylename] if stylename != None else "P2"
                Pnum = Pnum + formattedfontnum[n] + rtlsuffix
                ### not clear if any of the following can be moved outside loop and reused
                cell = TableCell(stylename=colBstyle, valuetype="string")
                par = P(stylename=Pnum)
                if len(stringel) == 0:  # no <em> subelements
                    par.addText(re.sub(backu, hextounichr, stringel.text))
                else:  # handle <em> subelement(s)
                    if stringel.text != None:
                        par.addElement(
                            Span(stylename="T1",
                                 text=re.sub(backu, hextounichr,
                                             stringel.text)))
                    for e in stringel.findall("em"):
                        if e.text != None:
                            par.addText(re.sub(backu, hextounichr, e.text))
                        if e.tail != None:
                            par.addElement(
                                Span(stylename="T1",
                                     text=re.sub(backu, hextounichr, e.tail)))
                cell.addElement(par)
                row.addElement(cell)

            # column C (comment)
            cell = TableCell(stylename="Table1.A1", valuetype="string")
            if comment:
                cell.addElement(P(stylename="Table_20_Contents", text=comment))
            row.addElement(cell)

            # column D (stylename)
            cell = TableCell(stylename="Table1.A1", valuetype="string")
            if comment:
                cell.addElement(
                    P(stylename="Table_20_Contents", text=stylename))
            row.addElement(cell)
        LOdoc.text.addElement(table)

    LOdoc.text.addElement(P(stylename="Subtitle",
                            text=""))  # Empty paragraph to end ### necessary?

    try:
        if fontstoembed: logfile.log("Embedding fonts in document", "V")
        for f in fontstoembed:
            LOdoc._extra.append(
                OpaqueObject(
                    filename="Fonts/" + os.path.basename(f),
                    mediatype=
                    "application/x-font-ttf",  ### should be "application/font-woff" or "/font-woff2" for WOFF fonts, "/font-opentype" for ttf
                    content=io.open(f, "rb").read()))
        ci = ConfigItem(**{
            'name': 'EmbedFonts',
            'type': 'boolean'
        })  ### (name = 'EmbedFonts', type = 'boolean')
        ci.addText('true')
        cis = ConfigItemSet(**{'name': 'ooo:configuration-settings'
                               })  ### (name = 'ooo:configuration-settings')
        cis.addElement(ci)
        LOdoc.settings.addElement(cis)
    except:
        logfile.log("Error embedding fonts in document", "E")
    logfile.log("Writing output file: " + args.output, "P")
    LOdoc.save(unicode(args.output))
    return
Beispiel #3
0
def doit(args) :
    logfile = args.logger
    if args.report: logfile.loglevel = args.report

    try:
        root = ET.parse(args.input).getroot()
    except:
        logfile.log("Error parsing FTML input", "S")

    if args.font:                   # font(s) specified on command line
        fontlist = getfonts( args.font, logfile )
    else:                           # get font spec from FTML fontsrc element
        fontlist = getfonts( [root.find("./head/fontsrc").text], logfile, False )
        #fontlist = getfonts( [fs.text for fs in root.findall("./head/fontsrc")], False ) ### would allow multiple fontsrc elements
    numfonts = len(fontlist)
    if numfonts == 0:
        logfile.log("No font(s) specified", "S")
    if numfonts > 1:
        formattedfontnum = ["{0:02d}".format(n) for n in range(numfonts)]
    else:
        formattedfontnum = [""]
    logfile.log("Font(s) specified:", "V")
    for n, (fontname, bold, italic, embeddedfont) in enumerate(fontlist):
        logfile.log(" " + formattedfontnum[n] + " " + fontname + BoldItalic(bold, italic) + " " + str(embeddedfont), "V")

    # get optional fontscale; compute pointsize as int(12*fontscale/100). If result xx is not 12, then add "fo:font-size=xxpt" in Px styles
    pointsize = 12
    fontscaleel = root.find("./head/fontscale")
    if fontscaleel != None:
        fontscale = fontscaleel.text
        try:
            pointsize = int(int(fontscale)*12/100)
        except ValueError:
            # any problem leaves pointsize 12
            logfile.log("Problem with fontscale value; defaulting to 12 point", "W")

    # Get FTML styles and generate LO writer styles
    # P2 is paragraph style for string element when no features specified
    # each Px (for P3...) corresponds to an FTML style, which specifies lang or feats or both
    # if numfonts > 1, two-digit font number is appended to make an LO writer style for each FTML style + font combo
    # When LO writer style is used with attribute rtl="True", "R" appended to style name
    LOstyles = {}
    ftmlstyles = {}
    Pstylenum = 2
    LOstyles["P2"] = ("", None, None)
    ftmlstyles[0] = "P2"
    for s in root.findall("./head/styles/style"):
        Pstylenum += 1
        Pnum = "P" + str(Pstylenum)
        featstring = ""
        if s.get('feats'):
            featstring = parsefeats(s.get('feats'))
        langname = None
        countryname = None
        lang = s.get('lang')
        if lang != None:
            x = re.match(langcode, lang)
            langname = x.group('langname')
            countryname = x.group('countryname')
        # FTML <test> element @stylename attribute references this <style> element @name attribute
        ftmlstyles[s.get('name')] = Pnum
        LOstyles[Pnum] = (featstring, langname, countryname)

    # create LOwriter file and construct styles for tables, column widths, etc.
    LOdoc = OpenDocumentText()
    init(LOdoc, numfonts)
    # Initialize sequence counters
    sds = SequenceDecls()
    sd = sds.addElement(SequenceDecl(displayoutlinelevel = '0', name = 'Illustration'))
    sd = sds.addElement(SequenceDecl(displayoutlinelevel = '0', name = 'Table'))
    sd = sds.addElement(SequenceDecl(displayoutlinelevel = '0', name = 'Text'))
    sd = sds.addElement(SequenceDecl(displayoutlinelevel = '0', name = 'Drawing'))
    LOdoc.text.addElement(sds)

    # Create Px style for each (featstring, langname, countryname) tuple in LOstyles
    # and for each font (if >1 font, append to Px style name a two-digit number corresponding to the font in fontlist)
    # and (if at least one rtl attribute) suffix of nothing or "R"
    # At the same time, collect info for creating FontFace elements (and any embedded fonts)
    suffixlist = ["", "R"] if root.find(".//test/[@rtl='True']") != None else [""]
    fontfaces = {}
    for p in sorted(LOstyles, key = lambda x : int(x[1:])):  # key = lambda x : int(x[1:]) corrects sort order
        featstring, langname, countryname = LOstyles[p]
        for n, (fontname, bold, italic, embeddedfont) in enumerate(fontlist): # embeddedfont = None if no embedding needed
            fontnum = formattedfontnum[n]
            # Collect fontface info: need one for each font family + feature combination
            # Put embedded font in list only under fontname with empty featstring
            if (fontname, featstring) not in fontfaces:
                fontfaces[ (fontname, featstring) ] = []
            if embeddedfont:
                if (fontname, "") not in fontfaces:
                    fontfaces[ (fontname, "") ] = []
                if embeddedfont not in fontfaces[ (fontname, "") ]:
                    fontfaces[ (fontname, "") ].append(embeddedfont)
            # Generate paragraph styles
            for s in suffixlist:
                pstyle = Style(name=p+fontnum+s, family="paragraph")
                if s == "R":
                    pstyle.addElement(ParagraphProperties(textalign="end", justifysingleword="false", writingmode="rl-tb"))
                pstyledic = {}
                pstyledic['fontnamecomplex'] = \
                pstyledic['fontnameasian'] =\
                pstyledic['fontname'] = fontname + featstring
                pstyledic['fontsizecomplex'] = \
                pstyledic['fontsizeasian'] = \
                pstyledic['fontsize'] = str(pointsize) + "pt"
                if bold:
                    pstyledic['fontweightcomplex'] = \
                    pstyledic['fontweightasian'] = \
                    pstyledic['fontweight'] = 'bold'
                if italic:
                    pstyledic['fontstylecomplex'] = \
                    pstyledic['fontstyleasian'] = \
                    pstyledic['fontstyle'] = 'italic'
                if langname != None:
                    pstyledic['languagecomplex'] = \
                    pstyledic['languageasian'] = \
                    pstyledic['language'] = langname
                if countryname != None:
                    pstyledic['countrycomplex'] = \
                    pstyledic['countryasian'] = \
                    pstyledic['country'] = countryname
                pstyle.addElement(TextProperties(attributes=pstyledic))
#                LOdoc.styles.addElement(pstyle)    ### tried this, but when saving the generated odt, LO changed them to automatic styles
                LOdoc.automaticstyles.addElement(pstyle)

    fontstoembed = []
    for fontname, featstring in sorted(fontfaces):  ### Or find a way to keep order of <style> elements from original FTML?
        ff = FontFace(name=fontname + featstring, fontfamily=fontname + featstring, fontpitch="variable")
        LOdoc.fontfacedecls.addElement(ff)
        if fontfaces[ (fontname, featstring) ]:     # embedding needed for this combination
            for fontfile in fontfaces[ (fontname, featstring) ]:
                fontstoembed.append(fontfile)       # make list for embedding
                ffsrc = FontFaceSrc()
                ffuri = FontFaceUri( **{'href': "Fonts/" + os.path.basename(fontfile), 'type': "simple"} )
                ffformat = FontFaceFormat( **{'string': 'truetype'} )
                ff.addElement(ffsrc)
                ffsrc.addElement(ffuri)
                ffuri.addElement(ffformat)

    basename = "Table1.B"
    colorcount = 0
    colordic = {} # record color #rrggbb as key and "Table1.Bx" as stylename (where x is current color count)
    tablenum = 0

    # get title and comment and use as title and subtitle
    titleel = root.find("./head/title")
    if titleel != None:
        LOdoc.text.addElement(H(outlinelevel=1, stylename="Title", text=titleel.text))
    commentel = root.find("./head/comment")
    if commentel != None:
        LOdoc.text.addElement(P(stylename="Subtitle", text=commentel.text))

    # Each testgroup element begins a new table
    for tg in root.findall("./testgroup"):
        # insert label attribute of testgroup element as subtitle
        tglabel = tg.get('label')
        if tglabel != None:
            LOdoc.text.addElement(H(outlinelevel=1, stylename="Subtitle", text=tglabel))

        # insert text from comment subelement of testgroup element
        tgcommentel = tg.find("./comment")
        if tgcommentel != None:
            #print("commentel found")
            LOdoc.text.addElement(P(text=tgcommentel.text))

        tgbg = tg.get('background') # background attribute of testgroup element
        tablenum += 1
        table = Table(name="Table" + str(tablenum), stylename="Table1")
        table.addElement(TableColumn(stylename="Table1.A"))
        for n in range(numfonts):
            table.addElement(TableColumn(stylename="Table1.B"))
        table.addElement(TableColumn(stylename="Table1.A"))
        table.addElement(TableColumn(stylename="Table1.D"))
        for t in tg.findall("./test"):                # Each test element begins a new row
            # stuff to start the row
            labeltext = t.get('label')
            stylename = t.get('stylename')
            stringel = t.find('./string')
            commentel = t.find('./comment')
            rtlsuffix = "R" if t.get('rtl') == 'True' else ""
            comment = commentel.text if commentel != None else None
            colBstyle = "Table1.A1"
            tbg = t.get('background')   # get background attribute of test group (if one exists)
            if tbg == None: tbg = tgbg
            if tbg != None:             # if background attribute for test element (or background attribute for testgroup element)
                if tbg not in colordic: # if color not found in color dic, create new style
                    colorcount += 1
                    newname = basename + str(colorcount)
                    colordic[tbg] = newname
                    tb1style = Style(name=newname, family="table-cell")
                    tb1style.addElement(TableCellProperties(attributes={'padding':"0.0382in", 'border':"0.05pt solid #000000", 'backgroundcolor':tbg}))
                    LOdoc.automaticstyles.addElement(tb1style)
                colBstyle = colordic[tbg]

            row = TableRow()
            table.addElement(row)
            # fill cells
            # column A (label)
            cell = TableCell(stylename="Table1.A1", valuetype="string")
            if labeltext:
                cell.addElement(P(stylename="Table_20_Contents", text = labeltext))
            row.addElement(cell)

            # column B (string)
            for n in range(numfonts):
                Pnum = ftmlstyles[stylename] if stylename != None else "P2"
                Pnum = Pnum + formattedfontnum[n] + rtlsuffix
                ### not clear if any of the following can be moved outside loop and reused
                cell = TableCell(stylename=colBstyle, valuetype="string")
                par = P(stylename=Pnum)
                if len(stringel) == 0: # no <em> subelements
                    par.addText(re.sub(backu, hextounichr, stringel.text))
                else:   # handle <em> subelement(s)
                    if stringel.text != None:
                        par.addElement(Span(stylename="T1", text = re.sub(backu, hextounichr, stringel.text)))
                    for e in stringel.findall("em"):
                        if e.text != None:
                            par.addText(re.sub(backu, hextounichr, e.text))
                        if e.tail != None:
                            par.addElement(Span(stylename="T1", text = re.sub(backu, hextounichr, e.tail)))
                cell.addElement(par)
                row.addElement(cell)

            # column C (comment)
            cell = TableCell(stylename="Table1.A1", valuetype="string")
            if comment:
                cell.addElement(P(stylename="Table_20_Contents", text = comment))
            row.addElement(cell)

            # column D (stylename)
            cell = TableCell(stylename="Table1.A1", valuetype="string")
            if comment:
                cell.addElement(P(stylename="Table_20_Contents", text = stylename))
            row.addElement(cell)
        LOdoc.text.addElement(table)

    LOdoc.text.addElement(P(stylename="Subtitle", text="")) # Empty paragraph to end ### necessary?

    try:
        if fontstoembed: logfile.log("Embedding fonts in document", "V")
        for f in fontstoembed:
            LOdoc._extra.append(
                OpaqueObject(filename = "Fonts/" + os.path.basename(f),
                    mediatype = "application/x-font-ttf",      ### should be "application/font-woff" or "/font-woff2" for WOFF fonts, "/font-opentype" for ttf
                    content = io.open(f, "rb").read() ))
        ci = ConfigItem(**{'name':'EmbedFonts', 'type': 'boolean'}) ### (name = 'EmbedFonts', type = 'boolean')
        ci.addText('true')
        cis=ConfigItemSet(**{'name':'ooo:configuration-settings'})  ### (name = 'ooo:configuration-settings')
        cis.addElement(ci)
        LOdoc.settings.addElement(cis)
    except:
        logfile.log("Error embedding fonts in document", "E")
    logfile.log("Writing output file: " + args.output, "P")
    LOdoc.save(unicode(args.output))
    return