Beispiel #1
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)
Beispiel #2
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)
Beispiel #3
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()