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