class FigureService:
    """
    Service layer for Figure entities.
    """
    _TYPE_PNG = "png"
    _TYPE_SVG = "svg"

    _BRANDING_BAR_PNG = os.path.join(os.path.dirname(__file__), "resources", "branding_bar.png")
    _BRANDING_BAR_SVG = os.path.join(os.path.dirname(__file__), "resources", "branding_bar.svg")

    _DEFAULT_SESSION_NAME = "Default"
    _DEFAULT_IMAGE_FILE_NAME = "snapshot."


    def __init__(self):
        self.logger = get_logger(self.__class__.__module__)
        self.file_helper = FilesHelper()


    def _write_png(self, store_path, export_data):
        img_data = base64.b64decode(export_data)                        # decode the image
        final_image = Image.open(StringIO(img_data))                    # place it in a PIL stream

        branding_bar = Image.open(FigureService._BRANDING_BAR_PNG)      # place the branding bar over
        final_image.paste(branding_bar, (0, final_image.size[1] - branding_bar.size[1]), branding_bar)

        final_image.save(store_path)                                    # store to disk as PNG


    def _write_svg(self, store_path, export_data):
        dom = xml.dom.minidom.parseString(export_data)
        figureSvg = dom.getElementsByTagName('svg')[0]                          # get the original image

        dom = xml.dom.minidom.parse(FigureService._BRANDING_BAR_SVG)

        try:
            width = float(figureSvg.getAttribute('width').replace('px', ''))
            height = float(figureSvg.getAttribute('height').replace('px', ''))
        except ValueError:                                                      # defaults when dimensions are not given
            width = 1024
            height = 768
            figureSvg.setAttribute("width", str(width))
            figureSvg.setAttribute("height", str(height))

        finalSvg = dom.createElement('svg')                                     # prepare the final svg
        brandingSvg = dom.getElementsByTagName('svg')[0]                        # get the branding bar
        brandingSvg.setAttribute("y", str(height))                              # position it below the figure
        height += float(brandingSvg.getAttribute('height').replace('px', ''))   # increase original height with branding bar's height
        finalSvg.setAttribute("width", str(width))                              # same width as original figure
        finalSvg.setAttribute("height", str(height))

        finalSvg.appendChild(figureSvg)                                         # add the image
        finalSvg.appendChild(brandingSvg)                                       # and the branding bar

        # Generate path where to store image
        with open(store_path, 'w') as dest:
            finalSvg.writexml(dest)                                                 # store to disk


    def _image_path(self, project_name, img_type):
        "Generate path where to store image"
        images_folder = self.file_helper.get_images_folder(project_name)
        file_name = FigureService._DEFAULT_IMAGE_FILE_NAME + img_type
        return utils.get_unique_file_name(images_folder, file_name)


    @staticmethod
    def _generate_image_name(project, user, operation, image_name):
        if not image_name:
            if operation is not None:
                # create a name based on the operation that created the image
                # e.g. TVB-Algo-Name-354
                image_name = operation.algorithm.name.replace(' ', '-')
            else:
                # default to a generic name
                image_name = "figure"
        figure_count = dao.get_figure_count(project.id, user.id) + 1
        return 'TVB-%s-%s' % (image_name, figure_count)


    def store_result_figure(self, project, user, img_type, export_data, image_name=None, operation_id=None):
        """
        Store into a file, Result Image and reference in DB.
        """
        store_path, file_name = self._image_path(project.name, img_type)

        if img_type == FigureService._TYPE_PNG:            # PNG file from canvas
            self._write_png(store_path, export_data)
        elif img_type == FigureService._TYPE_SVG:          # SVG file from svg viewer
            self._write_svg(store_path, export_data)

        if operation_id:
            operation = dao.get_operation_by_id(operation_id)
        else:
            operation = None
            operation_id = None

        image_name = self._generate_image_name(project, user, operation, image_name)

        # Store entity into DB
        entity = model.ResultFigure(operation_id, user.id, project.id, FigureService._DEFAULT_SESSION_NAME,
                                    image_name, file_name, img_type)
        entity = dao.store_entity(entity)

        # Load instance from DB to have lazy fields loaded
        figure = dao.load_figure(entity.id)
        # Write image meta data to disk  
        self.file_helper.write_image_metadata(figure)

        if operation:
            # Force writing operation meta data on disk.
            # This is important later for operation import
            self.file_helper.write_operation_metadata(operation)


    def retrieve_result_figures(self, project, user, selected_session_name='all_sessions'):
        """
        Retrieve from DB all the stored Displayer previews that belongs to the specified session. The
        previews are for current user and project; grouped by session.
        """
        result, previews_info = dao.get_previews(project.id, user.id, selected_session_name)
        for name in result:
            for figure in result[name]:
                figures_folder = self.file_helper.get_images_folder(project.name)
                figure_full_path = os.path.join(figures_folder, figure.file_path)
                # Compute the path 
                figure.file_path = utils.path2url_part(figure_full_path)
        return result, previews_info


    @staticmethod
    def load_figure(figure_id):
        """
        Loads a stored figure by its id.
        """
        return dao.load_figure(figure_id)


    def edit_result_figure(self, figure_id, **data):
        """
        Retrieve and edit a previously stored figure.
        """
        figure = dao.load_figure(figure_id)
        figure.session_name = data['session_name']
        figure.name = data['name']
        dao.store_entity(figure)

        # Load instance from DB to have lazy fields loaded.
        figure = dao.load_figure(figure_id)
        # Store figure meta data in an XML attached to the image.
        self.file_helper.write_image_metadata(figure)


    def remove_result_figure(self, figure_id):
        """
        Remove figure from DB and file storage.
        """
        figure = dao.load_figure(figure_id)

        # Delete all figure related files from disk.
        figures_folder = self.file_helper.get_images_folder(figure.project.name)
        path2figure = os.path.join(figures_folder, figure.file_path)
        if os.path.exists(path2figure):
            os.remove(path2figure)
            self.file_helper.remove_image_metadata(figure)

        # Remove figure reference from DB.
        result = dao.remove_entity(model.ResultFigure, figure_id)
        return result
        
        
        
Beispiel #2
0
class FigureService:
    """
    Service layer for Figure entities.
    """
    _TYPE_PNG = "png"
    _TYPE_SVG = "svg"

    _BRANDING_BAR_PNG = os.path.join(os.path.dirname(__file__), "resources",
                                     "branding_bar.png")
    _BRANDING_BAR_SVG = os.path.join(os.path.dirname(__file__), "resources",
                                     "branding_bar.svg")

    _DEFAULT_SESSION_NAME = "Default"
    _DEFAULT_IMAGE_FILE_NAME = "snapshot."

    def __init__(self):
        self.logger = get_logger(self.__class__.__module__)
        self.file_helper = FilesHelper()

    def _write_png(self, store_path, export_data):
        img_data = base64.b64decode(export_data)  # decode the image
        final_image = Image.open(
            StringIO(img_data))  # place it in a PIL stream

        branding_bar = Image.open(
            FigureService._BRANDING_BAR_PNG)  # place the branding bar over
        final_image.paste(branding_bar,
                          (0, final_image.size[1] - branding_bar.size[1]),
                          branding_bar)

        final_image.save(store_path)  # store to disk as PNG

    def _write_svg(self, store_path, export_data):
        dom = xml.dom.minidom.parseString(export_data)
        figureSvg = dom.getElementsByTagName('svg')[
            0]  # get the original image

        dom = xml.dom.minidom.parse(FigureService._BRANDING_BAR_SVG)

        try:
            width = float(figureSvg.getAttribute('width').replace('px', ''))
            height = float(figureSvg.getAttribute('height').replace('px', ''))
        except ValueError:  # defaults when dimensions are not given
            width = 1024
            height = 768
            figureSvg.setAttribute("width", str(width))
            figureSvg.setAttribute("height", str(height))

        finalSvg = dom.createElement('svg')  # prepare the final svg
        brandingSvg = dom.getElementsByTagName('svg')[
            0]  # get the branding bar
        brandingSvg.setAttribute("y",
                                 str(height))  # position it below the figure
        height += float(brandingSvg.getAttribute('height').replace(
            'px', ''))  # increase original height with branding bar's height
        finalSvg.setAttribute("width",
                              str(width))  # same width as original figure
        finalSvg.setAttribute("height", str(height))

        finalSvg.appendChild(figureSvg)  # add the image
        finalSvg.appendChild(brandingSvg)  # and the branding bar

        # Generate path where to store image
        with open(store_path, 'w') as dest:
            finalSvg.writexml(dest)  # store to disk

    def _image_path(self, project_name, img_type):
        "Generate path where to store image"
        images_folder = self.file_helper.get_images_folder(project_name)
        file_name = FigureService._DEFAULT_IMAGE_FILE_NAME + img_type
        return utils.get_unique_file_name(images_folder, file_name)

    @staticmethod
    def _generate_image_name(project, user, operation, image_name):
        if not image_name:
            if operation is not None:
                # create a name based on the operation that created the image
                # e.g. TVB-Algo-Name-354
                image_name = operation.algorithm.displayname.replace(' ', '-')
            else:
                # default to a generic name
                image_name = "figure"
        figure_count = dao.get_figure_count(project.id, user.id) + 1
        return 'TVB-%s-%s' % (image_name, figure_count)

    def store_result_figure(self,
                            project,
                            user,
                            img_type,
                            export_data,
                            image_name=None,
                            operation_id=None):
        """
        Store into a file, Result Image and reference in DB.
        """
        store_path, file_name = self._image_path(project.name, img_type)

        if img_type == FigureService._TYPE_PNG:  # PNG file from canvas
            self._write_png(store_path, export_data)
        elif img_type == FigureService._TYPE_SVG:  # SVG file from svg viewer
            self._write_svg(store_path, export_data)

        if operation_id:
            operation = dao.get_operation_by_id(operation_id)
        else:
            operation = None
            operation_id = None

        image_name = self._generate_image_name(project, user, operation,
                                               image_name)

        # Store entity into DB
        entity = model.ResultFigure(operation_id, user.id, project.id,
                                    FigureService._DEFAULT_SESSION_NAME,
                                    image_name, file_name, img_type)
        entity = dao.store_entity(entity)

        # Load instance from DB to have lazy fields loaded
        figure = dao.load_figure(entity.id)
        # Write image meta data to disk
        self.file_helper.write_image_metadata(figure)

        if operation:
            # Force writing operation meta data on disk.
            # This is important later for operation import
            self.file_helper.write_operation_metadata(operation)

    def retrieve_result_figures(self,
                                project,
                                user,
                                selected_session_name='all_sessions'):
        """
        Retrieve from DB all the stored Displayer previews that belongs to the specified session. The
        previews are for current user and project; grouped by session.
        """
        result, previews_info = dao.get_previews(project.id, user.id,
                                                 selected_session_name)
        for name in result:
            for figure in result[name]:
                figures_folder = self.file_helper.get_images_folder(
                    project.name)
                figure_full_path = os.path.join(figures_folder,
                                                figure.file_path)
                # Compute the path
                figure.file_path = utils.path2url_part(figure_full_path)
        return result, previews_info

    @staticmethod
    def load_figure(figure_id):
        """
        Loads a stored figure by its id.
        """
        return dao.load_figure(figure_id)

    def edit_result_figure(self, figure_id, **data):
        """
        Retrieve and edit a previously stored figure.
        """
        figure = dao.load_figure(figure_id)
        figure.session_name = data['session_name']
        figure.name = data['name']
        dao.store_entity(figure)

        # Load instance from DB to have lazy fields loaded.
        figure = dao.load_figure(figure_id)
        # Store figure meta data in an XML attached to the image.
        self.file_helper.write_image_metadata(figure)

    def remove_result_figure(self, figure_id):
        """
        Remove figure from DB and file storage.
        """
        figure = dao.load_figure(figure_id)

        # Delete all figure related files from disk.
        figures_folder = self.file_helper.get_images_folder(
            figure.project.name)
        path2figure = os.path.join(figures_folder, figure.file_path)
        if os.path.exists(path2figure):
            os.remove(path2figure)
            self.file_helper.remove_image_metadata(figure)

        # Remove figure reference from DB.
        result = dao.remove_entity(model.ResultFigure, figure_id)
        return result
class FigureService:
    """
    Service layer for Figure entities.
    """
    _TYPE_PNG = "png"
    _TYPE_SVG = "svg"

    _BRANDING_BAR_PNG = os.path.join(os.path.dirname(__file__), "resources", "branding_bar.png")
    _BRANDING_BAR_SVG = os.path.join(os.path.dirname(__file__), "resources", "branding_bar.svg")

    _DEFAULT_SESSION_NAME = "Default"
    _DEFAULT_IMAGE_FILE_NAME = "snapshot."


    def __init__(self):
        self.logger = get_logger(self.__class__.__module__)
        self.file_helper = FilesHelper()


    def store_result_figure(self, project, user, img_type, operation_id, export_data):
        """
        Store into a file, Result Image and reference in DB.
        """
        # Generate path where to store image
        store_path = self.file_helper.get_images_folder(project.name, operation_id)
        store_path = utils.get_unique_file_name(store_path, FigureService._DEFAULT_IMAGE_FILE_NAME + img_type)[0]
        file_path = os.path.split(store_path)[1]

        if img_type == FigureService._TYPE_PNG:                         # PNG file from canvas
            imgData = base64.b64decode(export_data)                     # decode the image
            fakeImgFile = StringIO(imgData)                             # PIL.Image only opens from file, so fake one
            origImg = Image.open(fakeImgFile)
            brandingBar = Image.open(FigureService._BRANDING_BAR_PNG)

            finalSize = (origImg.size[0],                               # original width
                         origImg.size[1] + brandingBar.size[1])         # original height + brandingBar height
            finalImg = Image.new("RGBA", finalSize)

            finalImg.paste(origImg, (0, 0))                             # add the original image
            finalImg.paste(brandingBar, (0, origImg.size[1]))           # add the branding bar, below the original
                                                                        # the extra width will be discarded

            finalImg.save(store_path)                                   # store to disk

        elif img_type == FigureService._TYPE_SVG:                                   # SVG file from svg viewer
            dom = xml.dom.minidom.parseString(export_data)
            figureSvg = dom.getElementsByTagName('svg')[0]                          # get the original image

            dom = xml.dom.minidom.parse(FigureService._BRANDING_BAR_SVG)
            brandingSvg = dom.getElementsByTagName('svg')[0]                        # get the branding bar
            brandingSvg.setAttribute("y", figureSvg.getAttribute("height"))         # position it below the figure

            finalSvg = dom.createElement('svg')                                     # prepare the final svg
            width = figureSvg.getAttribute('width').replace('px', '')               # same width as original figure
            finalSvg.setAttribute("width", width)
            height = float(figureSvg.getAttribute('height').replace('px', ''))      # increase original height with
            height += float(brandingSvg.getAttribute('height').replace('px', ''))   # branding bar's height
            finalSvg.setAttribute("height", str(height))

            finalSvg.appendChild(figureSvg)                                         # add the image
            finalSvg.appendChild(brandingSvg)                                       # and the branding bar

            # Generate path where to store image
            dest = open(store_path, 'w')
            finalSvg.writexml(dest)                                                 # store to disk
            dest.close()

        operation = dao.get_operation_by_id(operation_id)
        file_name = 'TVB-%s-%s' % (operation.algorithm.name.replace(' ', '-'), operation_id)    # e.g. TVB-Algo-Name-352

        # Store entity into DB
        entity = model.ResultFigure(operation_id, user.id, project.id, FigureService._DEFAULT_SESSION_NAME,
                                    file_name, file_path, img_type)
        entity = dao.store_entity(entity)

        # Load instance from DB to have lazy fields loaded
        figure = dao.load_figure(entity.id)
        # Write image meta data to disk  
        self.file_helper.write_image_metadata(figure)

        # Force writing operation meta data on disk. 
        # This is important later for operation import
        self.file_helper.write_operation_metadata(operation)


    def retrieve_result_figures(self, project, user, selected_session_name='all_sessions'):
        """
        Retrieve from DB all the stored Displayer previews that belongs to the specified session. The
        previews are for current user and project; grouped by session.
        """
        result, previews_info = dao.get_previews(project.id, user.id, selected_session_name)
        for name in result:
            for figure in result[name]:
                figures_folder = self.file_helper.get_images_folder(project.name, figure.operation.id)
                figure_full_path = os.path.join(figures_folder, figure.file_path)
                # Compute the path 
                figure.file_path = utils.path2url_part(figure_full_path)
        return result, previews_info


    @staticmethod
    def load_figure(figure_id):
        """
        Loads a stored figure by its id.
        """
        return dao.load_figure(figure_id)


    def edit_result_figure(self, figure_id, **data):
        """
        Retrieve and edit a previously stored figure.
        """
        figure = dao.load_figure(figure_id)
        figure.session_name = data['session_name']
        figure.name = data['name']
        dao.store_entity(figure)

        # Load instance from DB to have lazy fields loaded.
        figure = dao.load_figure(figure_id)
        # Store figure meta data in an XML attached to the image.
        self.file_helper.write_image_metadata(figure)


    def remove_result_figure(self, figure_id):
        """
        Remove figure from DB and file storage.
        """
        figure = dao.load_figure(figure_id)

        # Delete all figure related files from disk.
        figures_folder = self.file_helper.get_images_folder(figure.project.name, figure.operation.id)
        path2figure = os.path.join(figures_folder, figure.file_path)
        if os.path.exists(path2figure):
            os.remove(path2figure)
            self.file_helper.remove_image_metadata(figure)

        # Remove figure reference from DB.
        result = dao.remove_entity(model.ResultFigure, figure_id)
        return result