class PdfDocument(object):

    CENTER = 'center'
    RIGHT = 'right'
    LEFT = 'left'
    ALIGN = { CENTER: 'Centred', RIGHT: 'Right' }

    def __init__(self, instream, outstream, font=("Takao", 9)):
        self.base = PdfFileReader(instream)

        self.s = BytesIO()
        self.c = Canvas(self.s, pagesize=A4)

        self.font = font
        self.c.setFont(*self.font)

        self.output = outstream

    def string(self, pos, t, align=LEFT):
        getattr(self.c, 'draw%sString' % self.ALIGN.get(align, ''))(*pos, t)

    def circle(self, pos):
        self.c.circle(*pos, r=10, stroke=1, fill=0)

    def text(self, pos, txt, **kwargs):
        t = self.c.beginText()
        t.setTextOrigin(*pos)
        t.textLines(txt)
        self.c.drawText(t)

    def nextpage(self):
        self.c.showPage()
        self.c.setFont(*self.font)

    def write(self):
        self.c.save()
        self.s.seek(0)

        inp = PdfFileReader(self.s)
        out = PdfFileWriter()

        for i in range(min(inp.getNumPages(), self.base.getNumPages())):
            p = self.base.getPage(i)
            p.mergePage(inp.getPage(i))
            out.addPage(p)

        out.write(self.output)
Example #2
0
def save_design_cards(seqs: typing.List[Seq], savedir: str, symbols_dir: str,
                      file_basename: str, title: str):
    pg_w = pagesizes.A7[1]
    pg_h = pagesizes.A7[0] / 2
    lr_pad = 5 * units.mm
    dot_r = .5 * units.mm
    dot_hpad = 2 * units.mm
    dot_vpad = .5 * units.mm

    fn = os.path.join(savedir, f'{file_basename}.pdf')
    canvas = Canvas(fn, pagesize=(pg_w, pg_h))
    canvas.setTitle(title)
    for i, s in enumerate(seqs):
        i = i + 1
        sl = len(s)

        row = -1
        col = 0
        for k in range(i):
            if k % 5 == 0:
                row += 1
                col = 0

            rl = min(5, i - 5 * row)
            c = (rl - 1) * (2 * dot_r + dot_hpad) / 2
            x = pg_w / 2 - c + col * (2 * dot_r + dot_hpad)
            y = pg_h - dot_vpad - dot_r - row * (dot_vpad + 2 * dot_r)
            canvas.circle(x, y, dot_r, stroke=0, fill=1)
            col += 1

        size = (pg_w - 2 * lr_pad) / sl

        canvas.grid([lr_pad + k * size for k in range(sl + 1)],
                    [(pg_h - size) / 2, (pg_h + size) / 2])

        for j, e in enumerate(s):
            if e is None:
                continue
            symbol_fn = os.path.join(symbols_dir, f'SSL{e + 1:02d}.svg')
            symbol = fit_size(svglib.svg2rlg(symbol_fn), size, size)
            x = lr_pad + j * size
            y = (pg_h - size) / 2
            renderPDF.draw(symbol, canvas, x, y)
        canvas.showPage()
    canvas.save()
Example #3
0
 def test_05_coordinates(self):
     from reportlab.lib.pagesizes import A4
     from reportlab.pdfgen.canvas import Canvas
     from reportlab.lib.units import inch
     from reportlab.lib.colors import pink, black, red, blue, green
     c = Canvas('demo.pdf', pagesize=A4)
     c.translate(inch,inch)
     c.setStrokeColor(pink)
     c.grid([1*inch,2*inch,3*inch,4*inch],[0.5*inch, 1*inch, .5*inch, 2*inch, 2.5*inch])
     c.setFont("Times-Roman", 20)
     c.drawString(0,0, "(0,0) the Origin")
     c.drawString(2.5*inch, 1*inch, "(2.5,1) in inches")
     c.drawString(4*inch, 2.5*inch, "(4,2.5)")
     c.setFillColor(red)
     c.rect(0,2*inch,0.2*inch, 0.3*inch, fill=1)
     c.setFillColor(green)
     c.circle(4.5*inch, 0.4*inch, 0.2*inch, fill=1)
     c.showPage()
     c.save()
Example #4
0
    def test(self):
        outPDF = "test_compare.pdf"
        pageSize = pagesizes.portrait(pagesizes.A4)
        canv = Canvas(outPDF, pagesize=pageSize)

        # common variables
        W, H = 5 * cm, 20 * cm
        kifMode = "shrink"  # overflow/truncate/shrink/error

        # hyphenated column
        p = HyParagraph(testdata, sth)
        story = [p]
        frame = KeepInFrame(W, H, story, mode=kifMode)
        w, h = frame.wrapOn(canv, W, H)
        x, y = 100, 100
        frame.drawOn(canv, x, y + (H - h))
        canv.setLineWidth(2)
        canv.setStrokeColor(black)
        canv.circle(x, y, 10)
        canv.setStrokeColor(red)
        canv.rect(x, y, W, H)
        canv.setLineWidth(1)
        canv.setStrokeColor(blue)
        canv.rect(x, y + (H - h), w, h)

        # non-hyphenated column
        p = Paragraph(testdata, st)
        story = [p]
        frame = KeepInFrame(W, H, story, mode=kifMode)
        w, h = frame.wrapOn(canv, W, H)
        x, y = 300, 100
        frame.drawOn(canv, x, y + (H - h))
        canv.setLineWidth(2)
        canv.setStrokeColor(black)
        canv.circle(x, y, 10)
        canv.setStrokeColor(red)
        canv.rect(x, y, W, H)
        canv.setLineWidth(1)
        canv.setStrokeColor(blue)
        canv.rect(x, y + (H - h), w, h)

        canv.showPage()
        canv.save()
 def test_05_coordinates(self):
   from reportlab.lib.pagesizes import A4
   from reportlab.pdfgen.canvas import Canvas
   from reportlab.lib.units import inch
   from reportlab.lib.colors import pink, black, red, blue, green
   c = Canvas('demo.pdf', pagesize=A4)
   c.translate(inch,inch)
   c.setStrokeColor(pink)
   c.grid([1*inch,2*inch,3*inch,4*inch],[0.5*inch, 1*inch, .5*inch, 2*inch, 2.5*inch])
   c.setFont("Times-Roman", 20)
   c.drawString(0,0, "(0,0) the Origin")
   c.drawString(2.5*inch, 1*inch, "(2.5,1) in inches")
   c.drawString(4*inch, 2.5*inch, "(4,2.5)")
   c.setFillColor(red)
   c.rect(0,2*inch,0.2*inch, 0.3*inch, fill=1)
   c.setFillColor(green)
   c.circle(4.5*inch, 0.4*inch, 0.2*inch, fill=1)
   c.showPage()
   c.save()
Example #6
0
 def drawNode(self, pos, col):
     Canvas.setFillColor(self, col)
     Canvas.circle(self, pos[0], pos[1], 0.3, fill=1)
Example #7
0
def main():
    pdfmetrics.registerFont(TTFont('Dosis', 'Dosis-Medium.ttf'))

    stars = []
    with open('bsc5.dat', 'rb') as f:
        for line in f:
            line = '.' + line  # switch to 1-based indexing
            if not line[62].strip():
                continue  # skip coordinate-less novas
            letter = intern(line[8:11])
            if letter == '   ':
                letter = None
            h, m, s = float(line[61:63]), float(line[63:65]), float(line[65:69])
            ra = (h + (m + s / 60.0) / 60.0) * tau / 24.0
            d, m, s = float(line[69:72]), float(line[72:74]), float(line[76:78])
            dec = (d + (m + s / 60.0) / 60.0) * tau / 360.0
            mag = float(line[103:108])
            stars.append((letter, ra, dec, mag))

    h, w = 48, 96
    c = Canvas('logo.pdf', pagesize=(w, h))

    c.setFillColor('white')
    c.rect(0, 0, w, h, stroke=0, fill=1)

    c.setFillColor(bright_star_color)

    rotation = 10.0 * tau / 360.0
    # magscale = 0.1
    # For 10 degrees:
    x_offset = 96 -33.5
    y_offset = h  +37.5
    # For 15 degrees:
    # x_offset = 96 -28.5
    # y_offset = 96 +0.5
    # for 45 degrees:
    # x_offset = 96 -13.5
    # y_offset = 96 -10

    small_glyphs = []
    c.setFont('Helvetica', 2)

    for letter, ra, dec, mag in stars:
        # if mag > 4.0:
        #     continue
        d = - (dec - quarter_tau) * 100
        ra += rotation
        x = d * sin(ra)
        y = d * cos(ra)

        if y < -63.0 or y > -39.0:
            continue
        if x < -43.0 or x > 19.0:
            continue

        x += x_offset
        y += y_offset

        r = ((13.0 - mag) / 10.0) ** 4.0 #* magscale
        r = min(r, 1.0)

        if r < 0.5:
            small_glyphs.append((x, y, r))
        else:
            if letter is not None:
                c.saveState()
                greek_letter, offset = greeks[letter]
                c.setFillColor(greek_color)
                c.drawString(x+offset, y+0.5, greek_letter)
                if letter == 'Alp':
                    c.setFillColor(alpha_star_color)
                    c.circle(x, y, r, stroke=0, fill=1)
                c.restoreState()
                if letter != 'Alp':
                    c.circle(x, y, r, stroke=0, fill=1)
            else:
                c.circle(x, y, r, stroke=0, fill=1)


    c.setFillColor(dim_star_color)
    for x, y, r in small_glyphs:
        c.circle(x, y, r, stroke=0, fill=1)

    c.setFillColor(text_color) #, alpha=0.5)
    c.setFont('Dosis', 24)
    sw = c.stringWidth('Skyfield')
    c.drawString(w // 2 - sw // 2, h - 40, 'Skyfield')

    c.showPage()
    with open('logo.pdf', 'wb') as f:
        f.write(c.getpdfdata())
Example #8
0
    def render(self, outfile, font_name, font_size):
        """
        Render the binary heat map as a PDF to the file-like object or filename
        ``outfile``.  All text will be typeset in the font named ``font_name``
        at size ``font_size``.
        """
        c = Canvas(outfile)
        c.setFont(font_name, font_size)
        leftlen = max(map(c.stringWidth, self.row_labels)) + LABEL_PAD * 2
        toplen  = max(map(c.stringWidth, self.column_labels)) + LABEL_PAD * 2
        miny = self.rows * font_size * 1.2
        maxx = self.columns * font_size * 1.2
        c.setPageSize((leftlen + maxx + PADDING*2, miny + toplen + PADDING*2))
        # Set coordinates so that LL corner has coord (-leftlen-PADDING,
        # -miny-PADDING) and the origin is at the point where the borders of the
        # row & column labels meet:
        c.translate(leftlen+PADDING, miny+PADDING)

        lineheight = font_size * 1.2
        radius = lineheight / 3

        c.setFillColorRGB(*COL_BG_COLOR)
        for i in range(0, self.columns, 2):
            c.rect(
                i * lineheight,
                -miny,
                lineheight,
                miny + toplen,
                stroke=0,
                fill=1,
            )

        c.setFillColorRGB(*ROW_BG_COLOR)
        for i in range(2, self.rows+1, 2):
            # Yes, it starts at 2, so that the positive rectangle height will
            # make it fill row 1.
            c.rect(
                -leftlen,
                -i * lineheight,
                leftlen + maxx,
                lineheight,
                stroke=0,
                fill=1,
            )

        c.setFillColorRGB(0, 0, 0)
        c.line(0, toplen, 0, -miny)
        c.line(-leftlen, 0, maxx, 0)

        for i, label in enumerate(self.row_labels):
            c.drawRightString(
                -LABEL_PAD,
                -(i+1) * lineheight + font_size / 3,
                label,
            )

        for i, label in enumerate(self.column_labels):
            c.saveState()
            c.translate((i+1) * lineheight, 0)
            c.rotate(90)
            c.drawString(LABEL_PAD, font_size / 3, label)
            c.restoreState()

        for row, col in self.get_indexed_pairs():
            c.circle(
                (col+0.5) * lineheight,
                -(row+0.5) * lineheight,
                radius,
                stroke=0,
                fill=1,
            )

        c.showPage()
        c.save()
Example #9
0
def overlay(exam_images, max_scores, exam_seats, output_file, code=None, paper_type=letter):
    can = Canvas(output_file, pagesize=paper_type)
    paper_width, paper_height = paper_type

    exam_images = [[ImageReader(image) for image in exam] for exam in exam_images]

    for xxx, exam_seat in enumerate(exam_seats):
        sys.stdout.write('\rCompiling: %d / %d' % (xxx+1, len(exam_seats)))
        sys.stdout.flush()
        for index, max_score in enumerate(max_scores):
            page_code = 0 if code is None else code[xxx * len(max_scores) + index]
            bg = exam_images[page_code][index]
            can.drawImage(bg, 0*cm, 0*cm, width=paper_width, height=paper_height)

            # Draw QR codes.
            qr = ImageReader(qrcode.make('%d, %d, %d' % (exam_seat.exam_num, index+1, max_score), box_size=1).get_image())

            can.drawImage(qr, 0.75*cm, 0.75*cm, width=1.5*cm, height=1.5*cm)
            can.drawImage(qr, 19.34*cm, 0.75*cm, width=1.5*cm, height=1.5*cm)

            can.setFont('Times-Roman', 10)
            can.drawCentredString(1.5*cm, 0.6*cm, 'Ex %d' % exam_seat.exam_num)
            can.drawCentredString(20.09*cm, 0.6*cm, 'Ex %d' % exam_seat.exam_num)
            can.drawCentredString(3.4*cm, 0.6*cm, 'Page score')

            if index == 0:
                # Write seat name.
                if exam_seat.name:
                    can.setFont('Times-Bold', 22)
                    can.drawString(11.4*cm, 26.60*cm, 'Seat:')

                    can.setFont('Times-Roman', 22)
                    can.drawString(13.3*cm, 26.60*cm, exam_seat.name)

                # Draw UIN box.
                # US letter is 21.58cm x 27.93cm
                box_l, box_t = 11.79*cm, 23.825*cm
                box_w, box_h = 8*cm, 10*cm
                num_digits = 9

                can.rect(box_l, box_t - box_h, box_w, box_h)
                can.line(box_l, box_t - 1.4*cm, box_l + box_w, box_t - 1.4*cm)
                xstep = box_w / (num_digits + 1)
                ystep = box_h / (10 + 1)
                for i in range(num_digits-1):
                    can.line(box_l + 1.5*xstep + i*xstep, box_t - 1.4*cm, box_l + 1.5*xstep + i*xstep, box_t - 1.4*cm + 0.32*cm)
                can.setFont('Times-Bold', 12)
                can.drawString(box_l+0.2*cm, box_t - 0.52*cm, 'Write and bubble in your UIN:')
                can.setFont('Times-Roman', 10)
                for i in range(num_digits):
                    for j in range(10):
                        can.circle(box_l + 1.0*xstep + i*xstep, box_t - 1.4*cm - 0.6*cm - 0.8*j*cm, 0.3*cm)
                        can.drawCentredString(box_l + 1.0*xstep + i*xstep, box_t - 1.4*cm - 0.12*cm - 0.6*cm - 0.8*j*cm, str(j))

            # Draw score box.
            can.setLineWidth(1.5)
            can.line(0*cm, 2.3*cm, 21.59*cm, 2.3*cm)
            can.line(2.3*cm, 0*cm, 2.3*cm, 2.3*cm)
            can.line(4.5*cm, 0*cm, 4.5*cm, 2.3*cm)
            can.line(19.0*cm, 0*cm, 19.0*cm, 2.3*cm)
            can.line(4.5*cm, 0.7*cm, 19.0*cm, 0.7*cm)

            if max_score > 0:
                can.setLineWidth(0.5)
                for x in range(max_score+1):
                    can.rect(5.05*cm + 1.3*x*cm, 1.3*cm, 0.4*cm, 0.4*cm)
                can.setFont('Times-Roman', 10)
                for x in range(max_score+1):
                    can.drawCentredString(5.25*cm + 1.3*x*cm, 1.375*cm, str(x))

                can.setDash(2, 3)
                for x in range(max_score+1):
                    can.rect(4.85*cm + 1.3*x*cm, 1.1*cm, 0.8*cm,0.8*cm)

            can.showPage()

    can.save()
    sys.stdout.write('\n')
    sys.stdout.flush()
Example #10
0
    def render(self, outfile, font_name, font_size):
        """
        Render the binary heat map as a PDF to the file-like object or filename
        ``outfile``.  All text will be typeset in the font named ``font_name``
        at size ``font_size``.
        """
        c = Canvas(outfile)
        c.setFont(font_name, font_size)
        leftlen = max(map(c.stringWidth, self.row_labels)) + LABEL_PAD * 2
        toplen = max(map(c.stringWidth, self.column_labels)) + LABEL_PAD * 2
        miny = self.rows * font_size * 1.2
        maxx = self.columns * font_size * 1.2
        c.setPageSize(
            (leftlen + maxx + PADDING * 2, miny + toplen + PADDING * 2))
        # Set coordinates so that LL corner has coord (-leftlen-PADDING,
        # -miny-PADDING) and the origin is at the point where the borders of the
        # row & column labels meet:
        c.translate(leftlen + PADDING, miny + PADDING)

        lineheight = font_size * 1.2
        radius = lineheight / 3

        c.setFillColorRGB(*COL_BG_COLOR)
        for i in range(0, self.columns, 2):
            c.rect(
                i * lineheight,
                -miny,
                lineheight,
                miny + toplen,
                stroke=0,
                fill=1,
            )

        c.setFillColorRGB(*ROW_BG_COLOR)
        for i in range(2, self.rows + 1, 2):
            # Yes, it starts at 2, so that the positive rectangle height will
            # make it fill row 1.
            c.rect(
                -leftlen,
                -i * lineheight,
                leftlen + maxx,
                lineheight,
                stroke=0,
                fill=1,
            )

        c.setFillColorRGB(0, 0, 0)
        c.line(0, toplen, 0, -miny)
        c.line(-leftlen, 0, maxx, 0)

        for i, label in enumerate(self.row_labels):
            c.drawRightString(
                -LABEL_PAD,
                -(i + 1) * lineheight + font_size / 3,
                label,
            )

        for i, label in enumerate(self.column_labels):
            c.saveState()
            c.translate((i + 1) * lineheight, 0)
            c.rotate(90)
            c.drawString(LABEL_PAD, font_size / 3, label)
            c.restoreState()

        for row, col in self.get_indexed_pairs():
            c.circle(
                (col + 0.5) * lineheight,
                -(row + 0.5) * lineheight,
                radius,
                stroke=0,
                fill=1,
            )

        c.showPage()
        c.save()
Example #11
0
 def drawNode(self, pos, col):
     Canvas.setFillColor(self, col)
     Canvas.circle(self, pos[0], pos[1], 0.3, fill=1)
Example #12
0
def createCalendar(start, end, filename=None, size=SIZE, color=colors.red):
    """
    Create an academic calendar for a quarter.
    Counts academic weeks + 1 week for finals.

    start: an Arrow date
    end: an Arrow date
    filename: String containing the file to write the calendar to
    size: size, in points of the canvas to write on
    color: color for accents
    """

    # initializations
    canvas = Canvas(filename, size)
    weekHeader = calendar.weekheader(1).split()
    weekHeader.insert(0, 0)
    width, height = size

    # dictionary for each month in quarter
    months = 1
    monthInfo = {}

    for dt in arrow.Arrow.range('month', start.replace(day=1),
                                end.replace(day=2)):
        name = dt.format('MMM')
        cal = calendar.monthcalendar(dt.year, dt.month)
        monthInfo[months] = mo(name, cal)
        months += 1

    # arrange array for printing
    fullCal = []
    fullCal.append(weekHeader)
    weekNum = 1

    for m in monthInfo:
        weekNum -= 1
        fullCal.append(monthInfo[m].name)
        for w in monthInfo[m].cal:
            # add academic week numbers
            if (m == 1 and max(w) >= start.day) or weekNum > 0:
                weekNum += 1
            if weekNum > NUMWEEKS + 1:
                weekNum = 0

            w.insert(0, weekNum)
            fullCal.append(w)

    # draw everything out
    cellWidth = .3 * inch
    cellHeight = .3 * inch
    x = 1.5 * inch
    y = height - inch
    canvas.setStrokeAlpha(.25)

    for week in fullCal:
        # found a month
        if type(week) is str:
            canvas.setFont('Helvetica-Bold', 11)
            canvas.setFillColor(color)
            canvas.drawString(inch, y, week)
            canvas.setFillColor(colors.black)
            canvas.setFont('Helvetica', 11)
        else:  # found an array for weekdays
            for d, day in enumerate(week):
                if day != 0:
                    # weekday abbreviations
                    if type(day) is str:
                        canvas.setFont('Helvetica-Bold', 11)
                    else:
                        canvas.setFont('Helvetica', 11)

                    # draw circles around all the week numbers
                    if d == 0:
                        canvas.circle(x, y + .05 * inch, .1 * inch)

                    # weekends
                    if d in (6, 7):
                        canvas.setFillColor(color)
                    else:
                        canvas.setFillColor(colors.black)

                    canvas.drawCentredString(x, y, str(day))
                x += cellWidth
            x = 1.5 * inch
            y -= cellHeight

    # finish this page
    canvas.showPage()
    return canvas
Example #13
0
class PDFGenerator(ReportGenerator):
    """This is a generator to output a PDF using ReportLab library with
    preference by its Platypus API"""
    filename = None

    _is_first_page = True
    _is_latest_page = True
    _current_top_position = 0
    _current_page_number = 0
    _current_object = None

    def __init__(self, report, filename):
        super(PDFGenerator, self).__init__(report)

        self.filename = filename

    def execute(self):
        """Generate a PDF file using ReportLab pdfgen package."""

        # Initializes the PDF canvas
        self.start_pdf(self.filename)

        self.generate_pages()

        # Finalizes the canvas
        self.canvas.save()

    def start_pdf(self, filename):
        """Initializes the PDF document with some properties and methods"""
        # Sets the PDF canvas
        self.canvas = Canvas(filename=filename, pagesize=self.report.page_size)

        # Set PDF properties
        self.canvas.setTitle(self.report.title)
        self.canvas.setAuthor(self.report.author)

        self._is_first_page = True

    def generate_band(self, band, top_position=None):
        """Generate a band having the current top position or informed as its
        top coordinate"""

        # Coordinates and dimensions
        temp_top = top_position = top_position or self.get_top_pos()
        band_rect = {
                'left': self.report.margin_left,
                'top': top_position,
                'right': self.report.page_size[0] - self.report.margin_right,
                'bottom': top_position - band.height,
                }
        # This should be done by a metaclass in Report domain TODO
        band.width = self.report.page_size[0] - self.report.margin_left - self.report.margin_right

        # Loop at band widgets
        for element in band.elements:
            # Widget element
            if isinstance(element, Widget):
                widget = element

                # Set element colors
                self.set_fill_color(self.report.default_font_color)

                # Set widget basic attributes
                widget.instance = self._current_object
                widget.generator = self
                widget.report = self.report # This should be done by a metaclass in Band domain TODO
                widget.band = band # This should be done by a metaclass in Band domain TODO

                if isinstance(widget, Label):
                    para = Paragraph(widget.text, ParagraphStyle(name='Normal', **widget.style))
                    para.wrapOn(self.canvas, widget.width, widget.height)
                    para.drawOn(self.canvas, self.report.margin_left + widget.left, temp_top - widget.top - para.height)

            # Graphic element
            elif isinstance(element, Graphic):
                graphic = element

                # Set element colors
                self.set_fill_color(graphic.fill_color or self.report.default_fill_color)
                self.set_stroke_color(graphic.stroke_color or self.report.default_stroke_color)
                self.set_stroke_width(graphic.stroke_width)

                if isinstance(element, RoundRect):
                    self.canvas.roundRect(
                            self.report.margin_left + graphic.left,
                            top_position - graphic.top - graphic.height,
                            graphic.width,
                            graphic.height,
                            graphic.radius,
                            graphic.stroke,
                            graphic.fill,
                            )
                elif isinstance(element, Rect):
                    self.canvas.rect(
                            self.report.margin_left + graphic.left,
                            top_position - graphic.top - graphic.height,
                            graphic.width,
                            graphic.height,
                            graphic.stroke,
                            graphic.fill,
                            )
                elif isinstance(element, Line):
                    self.canvas.line(
                            self.report.margin_left + graphic.left,
                            top_position - graphic.top,
                            self.report.margin_left + graphic.right,
                            top_position - graphic.bottom,
                            )
                elif isinstance(element, Circle):
                    self.canvas.circle(
                            self.report.margin_left + graphic.left_center,
                            top_position - graphic.top_center,
                            graphic.radius,
                            graphic.stroke,
                            graphic.fill,
                            )
                elif isinstance(element, Arc):
                    self.canvas.arc(
                            self.report.margin_left + graphic.left,
                            top_position - graphic.top,
                            self.report.margin_left + graphic.right,
                            top_position - graphic.bottom,
                            graphic.start_angle,
                            graphic.extent,
                            )
                elif isinstance(element, Ellipse):
                    self.canvas.ellipse(
                            self.report.margin_left + graphic.left,
                            top_position - graphic.top,
                            self.report.margin_left + graphic.right,
                            top_position - graphic.bottom,
                            graphic.stroke,
                            graphic.fill,
                            )
                elif isinstance(element, Image):
                    self.canvas.drawInlineImage(
                            graphic.image,
                            self.report.margin_left + graphic.left,
                            top_position - graphic.top - graphic.height,
                            graphic.width,
                            graphic.height,
                            )

        # Band borders
        if band.borders.get('all', None):
            self.canvas.rect(
                    band_rect['left'],
                    band_rect['top'] - band.height,
                    band_rect['right'] - band_rect['left'],
                    band.height,
                    )

        if band.borders.get('top', None):
            self.canvas.line(band_rect['left'], band_rect['top'], band_rect['right'],
                    band_rect['top'])

        if band.borders.get('right', None):
            self.canvas.line(band_rect['right'], band_rect['top'], band_rect['right'],
                    band_rect['bottom'])

        if band.borders.get('bottom', None):
            self.canvas.line(band_rect['left'], band_rect['bottom'], band_rect['right'],
                    band_rect['bottom'])

        if band.borders.get('left', None):
            self.canvas.line(band_rect['left'], band_rect['top'], band_rect['left'],
                    band_rect['bottom'])

    def generate_begin(self):
        """Generate the report begin band if it exists"""
        if not self.report.band_begin:
            return

        # Call method that print the band area and its widgets
        self.generate_band(self.report.band_begin)
        
        # Update top position after this band
        self.update_top_pos(self.report.band_begin.height)

    def generate_summary(self):
        """Generate the report summary band if it exists"""
        if not self.report.band_summary:
            return

        # Check to force new page if there is no available space
        force_new_page = self.get_available_height() < self.report.band_summary.height

        if force_new_page:
            # Ends the current page
            self._current_top_position = 0
            self.canvas.showPage()

            # Starts a new one
            self.start_new_page()

        # Call method that print the band area and its widgets
        self.generate_band(self.report.band_summary)

        if force_new_page:
            self.generate_page_footer()

    def generate_page_header(self):
        """Generate the report page header band if it exists"""
        if not self.report.band_page_header:
            return

        # Call method that print the band area and its widgets
        self.generate_band(
                self.report.band_page_header,
                self.report.page_size[1] - self.report.margin_top
                )

    def generate_page_footer(self):
        """Generate the report page footer band if it exists"""
        if not self.report.band_page_footer:
            return

        # Call method that print the band area and its widgets
        self.generate_band(
                self.report.band_page_footer,
                self.report.margin_bottom + self.report.band_page_footer.height,
                )

    def generate_pages(self):
        """Loops into the queryset to create the report pages until the end"""
        # Preparing local auxiliar variables
        self._current_page_number = 0
        self._current_object_index = 0
        objects = self.report.queryset and \
                  [object for object in self.report.queryset] or\
                  []

        # Empty report
        if self.report.print_if_empty and not objects:
            self.start_new_page()
            self.generate_begin()
            self.end_current_page()

        # Loop for pages
        while self._current_object_index < len(objects):
            # Starts a new page and generates the page header band
            self.start_new_page()

            # Generate the report begin band
            if self._current_page_number == 0:
                self.generate_begin()

            # Does generate objects if there is no details band
            if not self.report.band_detail:
                self._current_object_index = len(objects)

            # Loop for objects to go into grid on current page
            while self._current_object_index < len(objects):
                # Get current object from list
                self._current_object = objects[self._current_object_index]

                # Generates the detail band
                self.generate_band(self.report.band_detail)

                # Updates top position
                self.update_top_pos(self.report.band_detail.height)

                # Next object
                self._current_object_index += 1

                # Break is this is the end of this page
                if self.get_available_height() < self.report.band_detail.height:
                    break

            # Sets this is the latest page or not
            self._is_latest_page = self._current_object_index >= len(objects)

            # Ends the current page, printing footer and summary and necessary
            self.end_current_page()

            # Breaks if this is the latest item
            if self._is_latest_page:
                break

            # Increment page number
            self._current_page_number += 1

    def start_new_page(self, with_header=True):
        """Do everything necessary to be done to start a new page"""
        if with_header:
            self.generate_page_header()

    def end_current_page(self):
        """Closes the current page, using showPage method. Everything done after
        this will draw into a new page. Before this, using the generate_page_footer
        method to draw the footer"""
        self.generate_page_footer()

        if self._is_latest_page:
            self.generate_summary()

        self.canvas.showPage()

        self._current_page_number += 1
        self._is_first_page = False
        self.update_top_pos(set=0) # <---- update top position

    def get_top_pos(self):
        """Since the coordinates are bottom-left on PDF, we have to use this to get
        the current top position, considering also the top margin."""
        ret = self.report.page_size[1] - self.report.margin_top - self._current_top_position

        if self.report.band_page_header:
            ret -= self.report.band_page_header.height

        return ret

    def get_available_height(self):
        """Returns the available client height area from the current top position
        until the end of page, considering the bottom margin."""
        ret = self.report.page_size[1] - self.report.margin_bottom -\
                self.report.margin_top - self._current_top_position

        if self.report.band_page_header:
            ret -= self.report.band_page_header.height

        if self.report.band_page_footer:
            ret -= self.report.band_page_footer.height

        return ret

    def update_top_pos(self, increase=0, decrease=0, set=None):
        """Updates the current top position controller, increasing (by default),
        decreasing or setting it with a new value."""
        if set is not None:
            self._current_top_position = set
        else:        
            self._current_top_position += increase
            self._current_top_position -= decrease

        return self._current_top_position

    def get_page_count(self): # TODO
        """Calculate and returns the page count for this report. The challenge
        here is do this calculate before to generate the pages."""
        pass

    def set_fill_color(self, color):
        """Sets the current fill on canvas. Used for fonts and shape fills"""
        self.canvas.setFillColor(color)
    
    def set_stroke_color(self, color):
        """Sets the current stroke on canvas"""
        self.canvas.setStrokeColor(color)

    def set_stroke_width(self, width):
        """Sets the stroke/line width for shapes"""
        self.canvas.setLineWidth(width)
Example #14
0
def create_pdf(hocr, filename, font="Courier", author=None, keywords=None, subject=None, title=None, image_path=None, draft=False):
    """ transform hOCR information into a searchable PDF.
    @param hocr the hocr structure as coming from extract_hocr.
    @param filename the name of the PDF generated in output.
    @param font the default font (e.g. Courier, Times-Roman).
    @param author the author name.
    @param subject the subject of the document.
    @param title the title of the document.
    @param image_path the default path where images are stored. If not specified
           relative image paths will be resolved to the current directory.
    @param draft whether to enable debug information in the output.

    """
    def adjust_image_size(width, height):
        return max(width / A4[0], height / A4[1])

    canvas = Canvas(filename)

    if author:
        canvas.setAuthor(author)

    if keywords:
        canvas.setKeywords(keywords)

    if title:
        canvas.setTitle(title)

    if subject:
        canvas.setSubject(subject)

    for bbox, image, lines in hocr:
        if not image.startswith('/') and image_path:
            image = os.path.abspath(os.path.join(image_path, image))
        img_width, img_height = bbox[2:]
        ratio = adjust_image_size(img_width, img_height)
        if draft:
            canvas.drawImage(image, 0, A4[1] - img_height / ratio , img_width / ratio, img_height / ratio)
        canvas.setFont(font, 12)
        for bbox, line in lines:
            if draft:
                canvas.setFillColor(red)
            x0, y0, x1, y1 = bbox
            width = (x1 - x0) / ratio
            height = ((y1 - y0) / ratio)
            x0 = x0 / ratio
            #for ch in 'gjpqy,(){}[];$@':
                #if ch in line:
                    #y0 = A4[1] - (y0 / ratio) - height
                    #break
            #else:
            y0 = A4[1] - (y0 / ratio) - height / 1.3
            #canvas.setFontSize(height * 1.5)
            canvas.setFontSize(height)
            text_width = canvas.stringWidth(line)
            if text_width:
                ## If text_width != 0
                text_object = canvas.beginText(x0, y0)
                text_object.setHorizScale(1.0 * width / text_width * 100)
                text_object.textOut(line)
                canvas.drawText(text_object)
            else:
                info('%s, %s has width 0' % (bbox, line))
            if draft:
                canvas.setStrokeColor(green)
                canvas.rect(x0, y0, width, height)
        if draft:
            canvas.circle(0, 0, 10, fill=1)
            canvas.circle(0, A4[1], 10, fill=1)
            canvas.circle(A4[0], 0, 10, fill=1)
            canvas.circle(A4[0], A4[1], 10, fill=1)
            canvas.setFillColor(green)
            canvas.setStrokeColor(green)
            canvas.circle(0, A4[1] - img_height / ratio, 5, fill=1)
            canvas.circle(img_width / ratio, img_height /ratio, 5, fill=1)
        else:
            canvas.drawImage(image, 0, A4[1] - img_height / ratio , img_width / ratio, img_height / ratio)

        canvas.save()
Example #15
0
def create_pdf(hocr,
               filename,
               font="Courier",
               author=None,
               keywords=None,
               subject=None,
               title=None,
               image_path=None,
               draft=False):
    """ transform hOCR information into a searchable PDF.
    @param hocr the hocr structure as coming from extract_hocr.
    @param filename the name of the PDF generated in output.
    @param font the default font (e.g. Courier, Times-Roman).
    @param author the author name.
    @param subject the subject of the document.
    @param title the title of the document.
    @param image_path the default path where images are stored. If not specified
           relative image paths will be resolved to the current directory.
    @param draft whether to enable debug information in the output.

    """
    def adjust_image_size(width, height):
        return max(width / A4[0], height / A4[1])

    canvas = Canvas(filename)

    if author:
        canvas.setAuthor(author)

    if keywords:
        canvas.setKeywords(keywords)

    if title:
        canvas.setTitle(title)

    if subject:
        canvas.setSubject(subject)

    for bbox, image, lines in hocr:
        if not image.startswith('/') and image_path:
            image = os.path.abspath(os.path.join(image_path, image))
        img_width, img_height = bbox[2:]
        ratio = adjust_image_size(img_width, img_height)
        if draft:
            canvas.drawImage(image, 0, A4[1] - img_height / ratio,
                             img_width / ratio, img_height / ratio)
        canvas.setFont(font, 12)
        for bbox, line in lines:
            if draft:
                canvas.setFillColor(red)
            x0, y0, x1, y1 = bbox
            width = (x1 - x0) / ratio
            height = ((y1 - y0) / ratio)
            x0 = x0 / ratio
            #for ch in 'gjpqy,(){}[];$@':
            #if ch in line:
            #y0 = A4[1] - (y0 / ratio) - height
            #break
            #else:
            y0 = A4[1] - (y0 / ratio) - height / 1.3
            #canvas.setFontSize(height * 1.5)
            canvas.setFontSize(height)
            text_width = canvas.stringWidth(line)
            if text_width:
                ## If text_width != 0
                text_object = canvas.beginText(x0, y0)
                text_object.setHorizScale(1.0 * width / text_width * 100)
                text_object.textOut(line)
                canvas.drawText(text_object)
            else:
                info('%s, %s has width 0' % (bbox, line))
            if draft:
                canvas.setStrokeColor(green)
                canvas.rect(x0, y0, width, height)
        if draft:
            canvas.circle(0, 0, 10, fill=1)
            canvas.circle(0, A4[1], 10, fill=1)
            canvas.circle(A4[0], 0, 10, fill=1)
            canvas.circle(A4[0], A4[1], 10, fill=1)
            canvas.setFillColor(green)
            canvas.setStrokeColor(green)
            canvas.circle(0, A4[1] - img_height / ratio, 5, fill=1)
            canvas.circle(img_width / ratio, img_height / ratio, 5, fill=1)
        else:
            canvas.drawImage(image, 0, A4[1] - img_height / ratio,
                             img_width / ratio, img_height / ratio)

        canvas.save()
Example #16
0
class PDFGenerator(ReportGenerator):
    """This is a generator to output a PDF using ReportLab library with
    preference by its Platypus API"""
    filename = None

    _is_first_page = True
    _is_latest_page = True
    _current_top_position = 0
    _current_page_number = 0
    _current_object = None

    def __init__(self, report, filename):
        super(PDFGenerator, self).__init__(report)

        self.filename = filename

    def execute(self):
        """Generate a PDF file using ReportLab pdfgen package."""

        # Initializes the PDF canvas
        self.start_pdf(self.filename)

        self.generate_pages()

        # Finalizes the canvas
        self.canvas.save()

    def start_pdf(self, filename):
        """Initializes the PDF document with some properties and methods"""
        # Sets the PDF canvas
        self.canvas = Canvas(filename=filename, pagesize=self.report.page_size)

        # Set PDF properties
        self.canvas.setTitle(self.report.title)
        self.canvas.setAuthor(self.report.author)

        self._is_first_page = True

    def generate_band(self, band, top_position=None):
        """Generate a band having the current top position or informed as its
        top coordinate"""

        # Coordinates and dimensions
        temp_top = top_position = top_position or self.get_top_pos()
        band_rect = {
            'left': self.report.margin_left,
            'top': top_position,
            'right': self.report.page_size[0] - self.report.margin_right,
            'bottom': top_position - band.height,
        }
        # This should be done by a metaclass in Report domain TODO
        band.width = self.report.page_size[
            0] - self.report.margin_left - self.report.margin_right

        # Loop at band widgets
        for element in band.elements:
            # Widget element
            if isinstance(element, Widget):
                widget = element

                # Set element colors
                self.set_fill_color(self.report.default_font_color)

                # Set widget basic attributes
                widget.instance = self._current_object
                widget.generator = self
                widget.report = self.report  # This should be done by a metaclass in Band domain TODO
                widget.band = band  # This should be done by a metaclass in Band domain TODO

                if isinstance(widget, Label):
                    para = Paragraph(
                        widget.text,
                        ParagraphStyle(name='Normal', **widget.style))
                    para.wrapOn(self.canvas, widget.width, widget.height)
                    para.drawOn(self.canvas,
                                self.report.margin_left + widget.left,
                                temp_top - widget.top - para.height)

            # Graphic element
            elif isinstance(element, Graphic):
                graphic = element

                # Set element colors
                self.set_fill_color(graphic.fill_color
                                    or self.report.default_fill_color)
                self.set_stroke_color(graphic.stroke_color
                                      or self.report.default_stroke_color)
                self.set_stroke_width(graphic.stroke_width)

                if isinstance(element, RoundRect):
                    self.canvas.roundRect(
                        self.report.margin_left + graphic.left,
                        top_position - graphic.top - graphic.height,
                        graphic.width,
                        graphic.height,
                        graphic.radius,
                        graphic.stroke,
                        graphic.fill,
                    )
                elif isinstance(element, Rect):
                    self.canvas.rect(
                        self.report.margin_left + graphic.left,
                        top_position - graphic.top - graphic.height,
                        graphic.width,
                        graphic.height,
                        graphic.stroke,
                        graphic.fill,
                    )
                elif isinstance(element, Line):
                    self.canvas.line(
                        self.report.margin_left + graphic.left,
                        top_position - graphic.top,
                        self.report.margin_left + graphic.right,
                        top_position - graphic.bottom,
                    )
                elif isinstance(element, Circle):
                    self.canvas.circle(
                        self.report.margin_left + graphic.left_center,
                        top_position - graphic.top_center,
                        graphic.radius,
                        graphic.stroke,
                        graphic.fill,
                    )
                elif isinstance(element, Arc):
                    self.canvas.arc(
                        self.report.margin_left + graphic.left,
                        top_position - graphic.top,
                        self.report.margin_left + graphic.right,
                        top_position - graphic.bottom,
                        graphic.start_angle,
                        graphic.extent,
                    )
                elif isinstance(element, Ellipse):
                    self.canvas.ellipse(
                        self.report.margin_left + graphic.left,
                        top_position - graphic.top,
                        self.report.margin_left + graphic.right,
                        top_position - graphic.bottom,
                        graphic.stroke,
                        graphic.fill,
                    )
                elif isinstance(element, Image):
                    self.canvas.drawInlineImage(
                        graphic.image,
                        self.report.margin_left + graphic.left,
                        top_position - graphic.top - graphic.height,
                        graphic.width,
                        graphic.height,
                    )

        # Band borders
        if band.borders.get('all', None):
            self.canvas.rect(
                band_rect['left'],
                band_rect['top'] - band.height,
                band_rect['right'] - band_rect['left'],
                band.height,
            )

        if band.borders.get('top', None):
            self.canvas.line(band_rect['left'], band_rect['top'],
                             band_rect['right'], band_rect['top'])

        if band.borders.get('right', None):
            self.canvas.line(band_rect['right'], band_rect['top'],
                             band_rect['right'], band_rect['bottom'])

        if band.borders.get('bottom', None):
            self.canvas.line(band_rect['left'], band_rect['bottom'],
                             band_rect['right'], band_rect['bottom'])

        if band.borders.get('left', None):
            self.canvas.line(band_rect['left'], band_rect['top'],
                             band_rect['left'], band_rect['bottom'])

    def generate_begin(self):
        """Generate the report begin band if it exists"""
        if not self.report.band_begin:
            return

        # Call method that print the band area and its widgets
        self.generate_band(self.report.band_begin)

        # Update top position after this band
        self.update_top_pos(self.report.band_begin.height)

    def generate_summary(self):
        """Generate the report summary band if it exists"""
        if not self.report.band_summary:
            return

        # Check to force new page if there is no available space
        force_new_page = self.get_available_height(
        ) < self.report.band_summary.height

        if force_new_page:
            # Ends the current page
            self._current_top_position = 0
            self.canvas.showPage()

            # Starts a new one
            self.start_new_page()

        # Call method that print the band area and its widgets
        self.generate_band(self.report.band_summary)

        if force_new_page:
            self.generate_page_footer()

    def generate_page_header(self):
        """Generate the report page header band if it exists"""
        if not self.report.band_page_header:
            return

        # Call method that print the band area and its widgets
        self.generate_band(self.report.band_page_header,
                           self.report.page_size[1] - self.report.margin_top)

    def generate_page_footer(self):
        """Generate the report page footer band if it exists"""
        if not self.report.band_page_footer:
            return

        # Call method that print the band area and its widgets
        self.generate_band(
            self.report.band_page_footer,
            self.report.margin_bottom + self.report.band_page_footer.height,
        )

    def generate_pages(self):
        """Loops into the queryset to create the report pages until the end"""
        # Preparing local auxiliar variables
        self._current_page_number = 0
        self._current_object_index = 0
        objects = self.report.queryset and \
                  [object for object in self.report.queryset] or\
                  []

        # Empty report
        if self.report.print_if_empty and not objects:
            self.start_new_page()
            self.generate_begin()
            self.end_current_page()

        # Loop for pages
        while self._current_object_index < len(objects):
            # Starts a new page and generates the page header band
            self.start_new_page()

            # Generate the report begin band
            if self._current_page_number == 0:
                self.generate_begin()

            # Does generate objects if there is no details band
            if not self.report.band_detail:
                self._current_object_index = len(objects)

            # Loop for objects to go into grid on current page
            while self._current_object_index < len(objects):
                # Get current object from list
                self._current_object = objects[self._current_object_index]

                # Generates the detail band
                self.generate_band(self.report.band_detail)

                # Updates top position
                self.update_top_pos(self.report.band_detail.height)

                # Next object
                self._current_object_index += 1

                # Break is this is the end of this page
                if self.get_available_height(
                ) < self.report.band_detail.height:
                    break

            # Sets this is the latest page or not
            self._is_latest_page = self._current_object_index >= len(objects)

            # Ends the current page, printing footer and summary and necessary
            self.end_current_page()

            # Breaks if this is the latest item
            if self._is_latest_page:
                break

            # Increment page number
            self._current_page_number += 1

    def start_new_page(self, with_header=True):
        """Do everything necessary to be done to start a new page"""
        if with_header:
            self.generate_page_header()

    def end_current_page(self):
        """Closes the current page, using showPage method. Everything done after
        this will draw into a new page. Before this, using the generate_page_footer
        method to draw the footer"""
        self.generate_page_footer()

        if self._is_latest_page:
            self.generate_summary()

        self.canvas.showPage()

        self._current_page_number += 1
        self._is_first_page = False
        self.update_top_pos(set=0)  # <---- update top position

    def get_top_pos(self):
        """Since the coordinates are bottom-left on PDF, we have to use this to get
        the current top position, considering also the top margin."""
        ret = self.report.page_size[
            1] - self.report.margin_top - self._current_top_position

        if self.report.band_page_header:
            ret -= self.report.band_page_header.height

        return ret

    def get_available_height(self):
        """Returns the available client height area from the current top position
        until the end of page, considering the bottom margin."""
        ret = self.report.page_size[1] - self.report.margin_bottom -\
                self.report.margin_top - self._current_top_position

        if self.report.band_page_header:
            ret -= self.report.band_page_header.height

        if self.report.band_page_footer:
            ret -= self.report.band_page_footer.height

        return ret

    def update_top_pos(self, increase=0, decrease=0, set=None):
        """Updates the current top position controller, increasing (by default),
        decreasing or setting it with a new value."""
        if set is not None:
            self._current_top_position = set
        else:
            self._current_top_position += increase
            self._current_top_position -= decrease

        return self._current_top_position

    def get_page_count(self):  # TODO
        """Calculate and returns the page count for this report. The challenge
        here is do this calculate before to generate the pages."""
        pass

    def set_fill_color(self, color):
        """Sets the current fill on canvas. Used for fonts and shape fills"""
        self.canvas.setFillColor(color)

    def set_stroke_color(self, color):
        """Sets the current stroke on canvas"""
        self.canvas.setStrokeColor(color)

    def set_stroke_width(self, width):
        """Sets the stroke/line width for shapes"""
        self.canvas.setLineWidth(width)
Example #17
0
class pdf:
    def __init__(self, path: str, name: str = 'generated'):
        """
        Create a pdf-file object\n
        :param path: path to create file
        :param name: name of file
        """
        self.file = Canvas(self._get_path(path, name))
        self.set_font(12)
        self.page = 1

    def _get_path(self, path: str, name: str = 'generated') -> str:
        """
        This function cleans path\n
        :param path: path to create file
        :param name: name of file
        :return: clean path to file
        """
        path = ''.join(symbol for symbol in path.lower()
                       if symbol not in ' <>?"\*')
        while path.count(':') > 1:
            path = path[:path.rfind(':')] + path[path.rfind(':') + 1:]
        while path[len(path) - 1] == ' ':
            path = path[:len(path) - 1]
        if ".pdf" in path:
            path = path[0:path.rfind('/') + 1:1]
        if path[len(path) - 1] != '/':
            path += '/'
        if '.pdf' in name:
            name = name[:name.rfind('.')]
        return path + name + '.pdf'

    def _format_data(self, data: dict) -> list:
        """
        This function processing data and return list of data for create table\n
        :param data: dict of data
        :return: list of data
        """
        new_data = [[data['title']]]
        add_list = []
        value_list = []
        for column_elem in data['columns']:
            add_list.append(column_elem['name'])
            value_list.append(column_elem['value'])
        new_data.append(add_list.copy())
        add_list.clear()
        for row_elem in data['rows']:
            for value in value_list:
                add_list.append(row_elem[value])
            new_data.append(add_list.copy())
            add_list.clear()
        return new_data

    def _normal_color(self):
        self.file.setFillColor('black')
        self.file.setStrokeColor('black')

    def set_font(self, font_size: int):
        """
        This function set up font and his size in file\n
        :param font_size: size of font
        """
        self.font_size = font_size
        using_font = ttfonts.TTFont("Calibri", "Calibri.ttf")
        pdfmetrics.registerFont(using_font)
        self.file.setFont("Calibri", self.font_size)

    def write_text(self,
                   text: str,
                   position: str = "mid",
                   x: int = 297,
                   y: int = 815):
        """"
        This function write text on defined position\n
        size of page is 595,841\n
        :param text: string of text to writing
        :param position: left/mid/right position of string of text
        :param x, y: coordinates of string
        """
        self._normal_color()
        if position == "left":
            self.file.drawString(x, y, text)
        elif position == "mid":
            self.file.drawCentredString(x, y, text)
        elif position == "right":
            self.file.drawRightString(x, y, text)

    def random_drawing(self, fg_count: int):
        """
        This function draws random picture\n
        :param fg_count: count of figures, drawn on page
        """
        for figure in range(fg_count):
            methods = [
                self.file.bezier(randint(150, 495), randint(150, 741),
                                 randint(150, 495), randint(150, 741),
                                 randint(150, 495), randint(150, 741),
                                 randint(150, 495), randint(150, 741)),
                self.file.arc(randint(100, 495), randint(100, 741),
                              randint(100, 495), randint(100, 741)),
                self.file.rect(randint(100, 395),
                               randint(100, 641),
                               randint(1, 100),
                               randint(1, 100),
                               fill=randint(0, 1)),
                self.file.ellipse(randint(100, 495),
                                  randint(100, 741),
                                  randint(100, 495),
                                  randint(100, 741),
                                  fill=randint(0, 1)),
                self.file.circle(randint(100, 395),
                                 randint(100, 641),
                                 randint(1, 100),
                                 fill=randint(0, 1)),
                self.file.roundRect(randint(100, 395),
                                    randint(100, 641),
                                    randint(1, 100),
                                    randint(1, 100),
                                    randint(1, 100),
                                    fill=randint(0, 1))
            ]
            self.file.setFillColorRGB(uniform(0, 1),
                                      uniform(0, 1),
                                      uniform(0, 1),
                                      alpha=uniform(0, 1))
            self.file.setStrokeColorRGB(uniform(0, 1),
                                        uniform(0, 1),
                                        uniform(0, 1),
                                        alpha=uniform(0, 1))
            choice(methods)

    def draw_table(self, data: dict, x: int = 10, y: int = 10):
        """
        This function draws table from your dictionary of data\n
        size of page is 595.27,841.89\n
        :param data: dictionary with data, e.g.
        :param x, y: coordinates of left-bottom corner of table
        {
            'title': 'Table title',
            'columns': [
                {'name': 'Name', 'value': 'name'},
                {'name': 'Age', 'value': 'age'}
            ],
            'rows': [
                {'name': 'string1', 'age': 23},
                {'name': 'string2', 'age': 43}
            ]
        }
        """
        self._normal_color()
        data = self._format_data(data)
        table = Table(data=data,
                      style=[("GRID", (0, 1), (-1, -1), 1, "Black"),
                             ("FONT", (0, 0), (-1, -1), "Calibri",
                              self.font_size),
                             ("BOX", (0, 0), (-1, -1), 1, "Black")])
        table.wrapOn(self.file, 10, 10)
        table.drawOn(self.file, x, y)

    def insert_image(self,
                     path: str,
                     x: int = 100,
                     y: int = 200,
                     width: int = None,
                     height: int = None):
        """
        This function inserts image in pdf-file\n
        size of page is 595.27,841.89\n
        :param path: path to image
        :param x, y: coordinates of left-bottom corner of image
        :param width, height: sizes of image
        """
        image = Image(path, width, height)
        image.drawOn(self.file, x, y)

    def next_page(self):
        """
        This function turns the page\n
        """
        self._normal_color()
        self.file.drawString(565, 30, str(self.page))
        self.page += 1
        self.file.showPage()

    def save(self, author: str = 'pdf_gen', title: str = 'GENERATED'):
        """
        This function saves our file\n
        :param author: author of file
        :param title: title of file
        """
        self._normal_color()
        self.file.drawString(565, 30, str(self.page))
        self.file.setAuthor(author)
        self.file.setTitle(title)
        self.file.save()