"Fossies" - the Fresh Open Source Software Archive

Member "xhtml2pdf-0.2.5/xhtml2pdf/tags.py" (8 Oct 2020, 20902 Bytes) of package /linux/www/xhtml2pdf-0.2.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "tags.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.2.4_vs_0.2.5.

    1 # -*- coding: utf-8 -*-
    2 from __future__ import print_function, unicode_literals
    3 from reportlab.graphics.barcode import createBarcodeDrawing
    4 from reportlab.lib.pagesizes import A4
    5 from reportlab.lib.units import inch, mm
    6 from reportlab.platypus.doctemplate import NextPageTemplate, FrameBreak
    7 from reportlab.platypus.flowables import Spacer, HRFlowable, PageBreak, Flowable
    8 from reportlab.platypus.frames import Frame
    9 from reportlab.platypus.paraparser import tt2ps, ABag
   10 from xhtml2pdf import xhtml2pdf_reportlab
   11 from xhtml2pdf.util import getColor, getSize, getAlign, dpi96
   12 from xhtml2pdf.xhtml2pdf_reportlab import PmlImage, PmlPageTemplate
   13 import copy
   14 import logging
   15 import re
   16 import warnings
   17 import six
   18 import string
   19 
   20 # Copyright 2010 Dirk Holtwick, holtwick.it
   21 #
   22 # Licensed under the Apache License, Version 2.0 (the "License");
   23 # you may not use this file except in compliance with the License.
   24 # You may obtain a copy of the License at
   25 #
   26 #     http://www.apache.org/licenses/LICENSE-2.0
   27 #
   28 # Unless required by applicable law or agreed to in writing, software
   29 # distributed under the License is distributed on an "AS IS" BASIS,
   30 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   31 # See the License for the specific language governing permissions and
   32 # limitations under the License.
   33 
   34 log = logging.getLogger("xhtml2pdf")
   35 
   36 
   37 def deprecation(message):
   38     warnings.warn("<" + message + "> is deprecated!", DeprecationWarning, stacklevel=2)
   39 
   40 
   41 class pisaTag:
   42     """
   43     The default class for a tag definition
   44     """
   45 
   46     def __init__(self, node, attr):
   47         self.node = node
   48         self.tag = node.tagName
   49         self.attr = attr
   50 
   51     def start(self, c):
   52         pass
   53 
   54     def end(self, c):
   55         pass
   56 
   57 
   58 class pisaTagBODY(pisaTag):
   59     """
   60     We can also asume that there is a BODY tag because html5lib
   61     adds it for us. Here we take the base font size for later calculations
   62     in the FONT tag.
   63     """
   64 
   65     def start(self, c):
   66         c.baseFontSize = c.frag.fontSize
   67         # print("base font size", c.baseFontSize)
   68 
   69 
   70 class pisaTagTITLE(pisaTag):
   71     def end(self, c):
   72         c.meta["title"] = c.text
   73         c.clearFrag()
   74 
   75 
   76 class pisaTagSTYLE(pisaTag):
   77     def start(self, c):
   78         c.addPara()
   79 
   80 
   81     def end(self, c):
   82         c.clearFrag()
   83 
   84 
   85 class pisaTagMETA(pisaTag):
   86     def start(self, c):
   87         name = self.attr.name.lower()
   88         if name in ("author", "subject", "keywords"):
   89             c.meta[name] = self.attr.content
   90 
   91 
   92 class pisaTagSUP(pisaTag):
   93     def start(self, c):
   94         c.frag.super = 1
   95 
   96 
   97 class pisaTagSUB(pisaTag):
   98     def start(self, c):
   99         c.frag.sub = 1
  100 
  101 
  102 class pisaTagA(pisaTag):
  103     rxLink = re.compile("^(#|[a-z]+\:).*")
  104 
  105 
  106     def start(self, c):
  107         attr = self.attr
  108         # XXX Also support attr.id ?
  109         if attr.name:
  110             # Important! Make sure that cbDefn is not inherited by other
  111             # fragments because of a bug in Reportlab!
  112             afrag = c.frag.clone()
  113             # These 3 lines are needed to fix an error with non internal fonts
  114             afrag.fontName = "Helvetica"
  115             afrag.bold = 0
  116             afrag.italic = 0
  117             afrag.cbDefn = ABag(
  118                 kind="anchor",
  119                 name=attr.name,
  120                 label="anchor")
  121             c.fragAnchor.append(afrag)
  122             c.anchorName.append(attr.name)
  123         if attr.href and self.rxLink.match(attr.href):
  124             c.frag.link = attr.href
  125 
  126     def end(self, c):
  127         pass
  128 
  129 
  130 class pisaTagFONT(pisaTag):
  131     # Source: http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size
  132 
  133     def start(self, c):
  134         if self.attr["color"] is not None:
  135             c.frag.textColor = getColor(self.attr["color"])
  136         if self.attr["face"] is not None:
  137             c.frag.fontName = c.getFontName(self.attr["face"])
  138         if self.attr["size"] is not None:
  139             size = getSize(self.attr["size"], c.frag.fontSize, c.baseFontSize)
  140             c.frag.fontSize = max(size, 1.0)
  141 
  142     def end(self, c):
  143         pass
  144 
  145 
  146 class pisaTagP(pisaTag):
  147     def start(self, c):
  148         # save the type of tag; it's used in PmlBaseDoc.afterFlowable()
  149         # to check if we need to add an outline-entry
  150         # c.frag.tag = self.tag
  151         if self.attr.align is not None:
  152             c.frag.alignment = getAlign(self.attr.align)
  153 
  154 
  155 class pisaTagDIV(pisaTagP):
  156     pass
  157 
  158 
  159 class pisaTagH1(pisaTagP):
  160     pass
  161 
  162 
  163 class pisaTagH2(pisaTagP):
  164     pass
  165 
  166 
  167 class pisaTagH3(pisaTagP):
  168     pass
  169 
  170 
  171 class pisaTagH4(pisaTagP):
  172     pass
  173 
  174 
  175 class pisaTagH5(pisaTagP):
  176     pass
  177 
  178 
  179 class pisaTagH6(pisaTagP):
  180     pass
  181 
  182 
  183 def listDecimal(c):
  184     c.listCounter += 1
  185     return six.text_type("%d." % c.listCounter)
  186 
  187 
  188 roman_numeral_map = (
  189     (1000, 'M'),
  190     (900, 'CM'),
  191     (500, 'D'),
  192     (400, 'CD'),
  193     (100, 'C'),
  194     (90, 'XC'),
  195     (50, 'L'),
  196     (40, 'XL'),
  197     (10, 'X'),
  198     (9, 'IX'),
  199     (5, 'V'),
  200     (4, 'IV'),
  201     (1, 'I'),
  202 )
  203 
  204 
  205 def int_to_roman(i):
  206     result = []
  207     for integer, numeral in roman_numeral_map:
  208         count = int(i / integer)
  209         result.append(numeral * count)
  210         i -= integer * count
  211     return ''.join(result)
  212 
  213 
  214 def listUpperRoman(c):
  215     c.listCounter += 1
  216     roman = int_to_roman(c.listCounter)
  217     return six.text_type("%s." % roman)
  218 
  219 
  220 def listLowerRoman(c):
  221     return listUpperRoman(c).lower()
  222 
  223 
  224 def listUpperAlpha(c):
  225     c.listCounter += 1
  226     index = c.listCounter - 1
  227     try:
  228         alpha = string.ascii_uppercase[index]
  229     except IndexError:
  230         # needs to start over and double the character
  231         # this will probably fail for anything past the 2nd time
  232         alpha = string.ascii_uppercase[index - 26]
  233         alpha *= 2
  234     return six.text_type("%s." % alpha)
  235 
  236 
  237 def listLowerAlpha(c):
  238     return listUpperAlpha(c).lower()
  239 
  240 
  241 _bullet = u"\u2022"
  242 _list_style_type = {
  243     "none": u"",
  244     "disc": _bullet,
  245     "circle": _bullet,  # XXX PDF has no equivalent
  246     "square": _bullet,  # XXX PDF has no equivalent
  247     "decimal": listDecimal,
  248     "decimal-leading-zero": listDecimal,
  249     "lower-roman": listLowerRoman,
  250     "upper-roman": listUpperRoman,
  251     "hebrew": listDecimal,
  252     "georgian": listDecimal,
  253     "armenian": listDecimal,
  254     "cjk-ideographic": listDecimal,
  255     "hiragana": listDecimal,
  256     "katakana": listDecimal,
  257     "hiragana-iroha": listDecimal,
  258     "katakana-iroha": listDecimal,
  259     "lower-latin": listDecimal,
  260     "lower-alpha": listLowerAlpha,
  261     "upper-latin": listDecimal,
  262     "upper-alpha": listUpperAlpha,
  263     "lower-greek": listDecimal,
  264 }
  265 
  266 
  267 class pisaTagUL(pisaTagP):
  268     def start(self, c):
  269         self.counter, c.listCounter = c.listCounter, 0
  270 
  271     def end(self, c):
  272         c.addPara()
  273         # XXX Simulate margin for the moment
  274         c.addStory(Spacer(width=1, height=c.fragBlock.spaceAfter))
  275         c.listCounter = self.counter
  276 
  277 
  278 class pisaTagOL(pisaTagUL):
  279     pass
  280 
  281 
  282 class pisaTagLI(pisaTag):
  283     def start(self, c):
  284         lst = _list_style_type.get(c.frag.listStyleType or "disc", _bullet)
  285         frag = copy.copy(c.frag)
  286 
  287         self.offset = 0
  288         if frag.listStyleImage is not None:
  289             frag.text = u""
  290             f = frag.listStyleImage
  291             if f and (not f.notFound()):
  292                 img = PmlImage(
  293                     f.getData(),
  294                     width=None,
  295                     height=None)
  296                 img.drawHeight *= dpi96
  297                 img.drawWidth *= dpi96
  298                 img.pisaZoom = frag.zoom
  299                 img.drawWidth *= img.pisaZoom
  300                 img.drawHeight *= img.pisaZoom
  301                 frag.image = img
  302                 self.offset = max(0, img.drawHeight - c.frag.fontSize)
  303         else:
  304             if type(lst) == type(u""):
  305                 frag.text = lst
  306             else:
  307                 # XXX This should be the recent font, but it throws errors in Reportlab!
  308                 frag.text = lst(c)
  309 
  310         # XXX This should usually be done in the context!!!
  311         frag.fontName = frag.bulletFontName = tt2ps(frag.fontName, frag.bold, frag.italic)
  312         c.frag.bulletText = [frag]
  313 
  314     def end(self, c):
  315         c.fragBlock.spaceBefore += self.offset
  316 
  317 
  318 class pisaTagBR(pisaTag):
  319     def start(self, c):
  320         c.frag.lineBreak = 1
  321         c.addFrag()
  322         c.fragStrip = True
  323         del c.frag.lineBreak
  324         c.force = True
  325 
  326 
  327 class pisaTagIMG(pisaTag):
  328     def start(self, c):
  329         attr = self.attr
  330         log.debug("Parsing img tag, src: {}".format(attr.src))
  331         log.debug("Attrs: {}".format(attr))
  332         if attr.src and (not attr.src.notFound()):
  333 
  334             try:
  335                 align = attr.align or c.frag.vAlign or "baseline"
  336                 width = c.frag.width
  337                 height = c.frag.height
  338 
  339                 if attr.width:
  340                     width = attr.width * dpi96
  341                 if attr.height:
  342                     height = attr.height * dpi96
  343 
  344                 img = PmlImage(
  345                     attr.src.getData(),
  346                     width=None,
  347                     height=None)
  348 
  349                 img.pisaZoom = c.frag.zoom
  350 
  351                 img.drawHeight *= dpi96
  352                 img.drawWidth *= dpi96
  353 
  354                 if (width is None) and (height is not None):
  355                     factor = getSize(height, default=img.drawHeight) / img.drawHeight
  356                     img.drawWidth *= factor
  357                     img.drawHeight = getSize(height, default=img.drawHeight)
  358                 elif (height is None) and (width is not None):
  359                     factor = getSize(width, default=img.drawWidth) / img.drawWidth
  360                     img.drawHeight *= factor
  361                     img.drawWidth = getSize(width, default=img.drawWidth)
  362                 elif (width is not None) and (height is not None):
  363                     img.drawWidth = getSize(width, default=img.drawWidth)
  364                     img.drawHeight = getSize(height, default=img.drawHeight)
  365 
  366                 img.drawWidth *= img.pisaZoom
  367                 img.drawHeight *= img.pisaZoom
  368 
  369                 img.spaceBefore = c.frag.spaceBefore
  370                 img.spaceAfter = c.frag.spaceAfter
  371 
  372                 # print "image", id(img), img.drawWidth, img.drawHeight
  373 
  374                 '''
  375                 TODO:
  376 
  377                 - Apply styles
  378                 - vspace etc.
  379                 - Borders
  380                 - Test inside tables
  381                 '''
  382 
  383                 c.force = True
  384                 if align in ["left", "right"]:
  385 
  386                     c.image = img
  387                     c.imageData = dict(
  388                         align=align
  389                     )
  390 
  391                 else:
  392 
  393                     # Important! Make sure that cbDefn is not inherited by other
  394                     # fragments because of a bug in Reportlab!
  395                     # afrag = c.frag.clone()
  396 
  397                     valign = align
  398                     if valign in ["texttop"]:
  399                         valign = "top"
  400                     elif valign in ["absmiddle"]:
  401                         valign = "middle"
  402                     elif valign in ["absbottom", "baseline"]:
  403                         valign = "bottom"
  404 
  405                     afrag = c.frag.clone()
  406                     afrag.text = ""
  407                     afrag.fontName = "Helvetica" # Fix for a nasty bug!!!
  408                     afrag.cbDefn = ABag(
  409                         kind="img",
  410                         image=img, # .getImage(), # XXX Inline?
  411                         valign=valign,
  412                         fontName="Helvetica",
  413                         fontSize=img.drawHeight,
  414                         width=img.drawWidth,
  415                         height=img.drawHeight)
  416 
  417                     c.fragList.append(afrag)
  418                     c.fontSize = img.drawHeight
  419 
  420             except Exception:  # TODO: Kill catch-all
  421                 log.warning(c.warning("Error in handling image"), exc_info=1)
  422         else:
  423             log.warning(c.warning("Need a valid file name!"))
  424 
  425 
  426 class pisaTagHR(pisaTag):
  427     def start(self, c):
  428         c.addPara()
  429         c.addStory(HRFlowable(
  430             color=self.attr.color,
  431             thickness=self.attr.size,
  432             width=self.attr.get('width', "100%") or "100%",
  433             spaceBefore=c.frag.spaceBefore,
  434             spaceAfter=c.frag.spaceAfter
  435         ))
  436 
  437 # --- Forms
  438 
  439 
  440 if 0:
  441 
  442     class pisaTagINPUT(pisaTag):
  443 
  444         def _render(self, c, attr):
  445             width = 10
  446             height = 10
  447             if attr.type == "text":
  448                 width = 100
  449                 height = 12
  450             c.addStory(xhtml2pdf_reportlab.PmlInput(attr.name,
  451                                                     type=attr.type,
  452                                                     default=attr.value,
  453                                                     width=width,
  454                                                     height=height,
  455             ))
  456 
  457         def end(self, c):
  458             c.addPara()
  459             attr = self.attr
  460             if attr.name:
  461                 self._render(c, attr)
  462             c.addPara()
  463 
  464     class pisaTagTEXTAREA(pisaTagINPUT):
  465 
  466         def _render(self, c, attr):
  467             c.addStory(xhtml2pdf_reportlab.PmlInput(attr.name,
  468                                                     default="",
  469                                                     width=100,
  470                                                     height=100))
  471 
  472     class pisaTagSELECT(pisaTagINPUT):
  473 
  474         def start(self, c):
  475             c.select_options = ["One", "Two", "Three"]
  476 
  477         def _render(self, c, attr):
  478             c.addStory(xhtml2pdf_reportlab.PmlInput(attr.name,
  479                                                     type="select",
  480                                                     default=c.select_options[0],
  481                                                     options=c.select_options,
  482                                                     width=100,
  483                                                     height=40))
  484             c.select_options = None
  485 
  486     class pisaTagOPTION(pisaTag):
  487 
  488         pass
  489 
  490 
  491 class pisaTagPDFNEXTPAGE(pisaTag):
  492     """
  493     <pdf:nextpage name="" />
  494     """
  495 
  496     def start(self, c):
  497         c.addPara()
  498         if self.attr.name:
  499             c.addStory(NextPageTemplate(self.attr.name))
  500         c.addStory(PageBreak())
  501 
  502 
  503 class pisaTagPDFNEXTTEMPLATE(pisaTag):
  504     """
  505     <pdf:nexttemplate name="" />
  506     """
  507 
  508     def start(self, c):
  509         c.addStory(NextPageTemplate(self.attr["name"]))
  510 
  511 
  512 class pisaTagPDFNEXTFRAME(pisaTag):
  513     """
  514     <pdf:nextframe name="" />
  515     """
  516 
  517     def start(self, c):
  518         c.addPara()
  519         c.addStory(FrameBreak())
  520 
  521 
  522 class pisaTagPDFSPACER(pisaTag):
  523     """
  524     <pdf:spacer height="" />
  525     """
  526 
  527     def start(self, c):
  528         c.addPara()
  529         c.addStory(Spacer(1, self.attr.height))
  530 
  531 
  532 class pisaTagPDFPAGENUMBER(pisaTag):
  533     """
  534     <pdf:pagenumber example="" />
  535     """
  536 
  537     def start(self, c):
  538         c.frag.pageNumber = True
  539         c.addFrag(self.attr.example)
  540         c.frag.pageNumber = False
  541 
  542 
  543 class pisaTagPDFPAGECOUNT(pisaTag):
  544     """
  545     <pdf:pagecount />
  546     """
  547 
  548     def start(self, c):
  549         c.frag.pageCount = True
  550         c.addFrag()
  551         c.frag.pageCount = False
  552 
  553     def end(self, c):
  554         c.addPageCount()
  555 
  556 
  557 class pisaTagPDFTOC(pisaTag):
  558     """
  559     <pdf:toc />
  560     """
  561 
  562     def end(self, c):
  563         c.multiBuild = True
  564         c.addTOC()
  565 
  566 
  567 class pisaTagPDFFRAME(pisaTag):
  568     """
  569     <pdf:frame name="" static box="" />
  570     """
  571 
  572     def start(self, c):
  573         deprecation("pdf:frame")
  574         attrs = self.attr
  575 
  576         name = attrs["name"]
  577         if name is None:
  578             name = "frame%d" % c.UID()
  579 
  580         x, y, w, h = attrs.box
  581         self.frame = Frame(
  582             x, y, w, h,
  583             id=name,
  584             leftPadding=0,
  585             rightPadding=0,
  586             bottomPadding=0,
  587             topPadding=0,
  588             showBoundary=attrs.border)
  589 
  590         self.static = False
  591         if self.attr.static:
  592             self.static = True
  593             c.addPara()
  594             self.story = c.swapStory()
  595         else:
  596             c.frameList.append(self.frame)
  597 
  598     def end(self, c):
  599         if self.static:
  600             c.addPara()
  601             self.frame.pisaStaticStory = c.story
  602             c.frameStaticList.append(self.frame)
  603             c.swapStory(self.story)
  604 
  605 
  606 class pisaTagPDFTEMPLATE(pisaTag):
  607     """
  608     <pdf:template name="" static box="" >
  609         <pdf:frame...>
  610     </pdf:template>
  611     """
  612 
  613     def start(self, c):
  614         deprecation("pdf:template")
  615         attrs = self.attr
  616         name = attrs["name"]
  617         c.frameList = []
  618         c.frameStaticList = []
  619         if name in c.templateList:
  620             log.warning(c.warning("template '%s' has already been defined", name))
  621 
  622     def end(self, c):
  623         attrs = self.attr
  624         name = attrs["name"]
  625         if len(c.frameList) <= 0:
  626             log.warning(c.warning("missing frame definitions for template"))
  627 
  628         pt = PmlPageTemplate(
  629             id=name,
  630             frames=c.frameList,
  631             pagesize=A4,
  632         )
  633         pt.pisaStaticList = c.frameStaticList
  634         pt.pisaBackgroundList = c.pisaBackgroundList
  635         pt.pisaBackground = self.attr.background
  636 
  637         c.templateList[name] = pt
  638         c.template = None
  639         c.frameList = []
  640         c.frameStaticList = []
  641 
  642 class pisaTagPDFLANGUAGE(pisaTag):
  643     """
  644     <pdf:language name=""/>
  645     """
  646     def start(self, c):
  647         setattr(c,'language',self.attr.name)
  648 
  649 class pisaTagPDFFONT(pisaTag):
  650     """
  651     <pdf:fontembed name="" src="" />
  652     """
  653     def start(self, c):
  654         deprecation("pdf:font")
  655         c.loadFont(self.attr.name, self.attr.src, self.attr.encoding)
  656 
  657 
  658 class pisaTagPDFBARCODE(pisaTag):
  659     _codeName = {
  660         "I2OF5": "I2of5",
  661         "ITF": "I2of5",
  662         "CODE39": "Standard39",
  663         "EXTENDEDCODE39": "Extended39",
  664         "CODE93": "Standard93",
  665         "EXTENDEDCODE93": "Extended93",
  666         "MSI": "MSI",
  667         "CODABAR": "Codabar",
  668         "NW7": "Codabar",
  669         "CODE11": "Code11",
  670         "FIM": "FIM",
  671         "POSTNET": "POSTNET",
  672         "USPS4S": "USPS_4State",
  673         "CODE128": "Code128",
  674         "EAN13": "EAN13",
  675         "EAN8": "EAN8",
  676         "QR": "QR",
  677     }
  678 
  679     class _barcodeWrapper(Flowable):
  680         """
  681         Wrapper for barcode widget
  682         """
  683         def __init__(self, codeName="Code128", value="", **kw):
  684             self.vertical = kw.get('vertical', 0)
  685             self.widget = createBarcodeDrawing(codeName, value=value, **kw)
  686 
  687         def draw(self, canvas, xoffset=0, **kw):
  688             # NOTE: 'canvas' is mutable, so canvas.restoreState() is a MUST.
  689             canvas.saveState()
  690             # NOTE: checking vertical value to rotate the barcode
  691             if self.vertical:
  692                 width, height = self.wrap(0, 0)
  693                 # Note: moving our canvas to the new origin
  694                 canvas.translate(height, -width)
  695                 canvas.rotate(90)
  696             else:
  697                 canvas.translate(xoffset, 0)
  698             self.widget.canv = canvas
  699             self.widget.draw()
  700             canvas.restoreState()
  701 
  702         def wrap(self, aW, aH):
  703             return self.widget.wrap(aW, aH)
  704 
  705     def start(self, c):
  706         attr = self.attr
  707         codeName = attr.type or "Code128"
  708         codeName = pisaTagPDFBARCODE._codeName[codeName.upper().replace("-", "")]
  709         humanReadable = int(attr.humanreadable)
  710         vertical = int(attr.vertical)
  711         checksum = int(attr.checksum)
  712         barWidth = attr.barwidth or 0.01 * inch
  713         barHeight = attr.barheight or 0.5 * inch
  714         fontName = c.getFontName("OCRB10,OCR-B,OCR B,OCRB")  # or "Helvetica"
  715         fontSize = attr.fontsize or 2.75 * mm
  716 
  717         # Assure minimal size.
  718         if codeName in ("EAN13", "EAN8"):
  719             barWidth = max(barWidth, 0.264 * mm)
  720             fontSize = max(fontSize, 2.75 * mm)
  721         else:  # Code39 etc.
  722             barWidth = max(barWidth, 0.0075 * inch)
  723 
  724         barcode = pisaTagPDFBARCODE._barcodeWrapper(
  725             codeName=codeName,
  726             value=attr.value,
  727             barWidth=barWidth,
  728             barHeight=barHeight,
  729             humanReadable=humanReadable,
  730             vertical=vertical,
  731             checksum=checksum,
  732             fontName=fontName,
  733             fontSize=fontSize,
  734         )
  735 
  736         width, height = barcode.wrap(c.frag.width, c.frag.height)
  737         c.force = True
  738 
  739         valign = attr.align or c.frag.vAlign or "baseline"
  740         if valign in ["texttop"]:
  741             valign = "top"
  742         elif valign in ["absmiddle"]:
  743             valign = "middle"
  744         elif valign in ["absbottom", "baseline"]:
  745             valign = "bottom"
  746 
  747         afrag = c.frag.clone()
  748         afrag.text = ""
  749         afrag.fontName = fontName
  750         afrag.cbDefn = ABag(
  751             kind="barcode",
  752             barcode=barcode,
  753             width=width,
  754             height=height,
  755             valign=valign,
  756         )
  757         c.fragList.append(afrag)