Example #1
0
    def render(self):
        """
            The render of an svg part 
        """

        #TODO: Parse the svg to get height and width
        #Need to get the height and width of the svg command
        tmpsvg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" xmlns:xlink="http://www.w3.org/1999/xlink">%s</svg>' % self.content

        #Need to create a temp file
        tmpfile, tmpname = tempfile.mkstemp(prefix='beampytmp')
        with open(tmpname + '.svg', 'w') as f:
            f.write(tmpsvg)

        svg_width = getsvgwidth(tmpname + '.svg')
        svg_height = getsvgheight(tmpname + '.svg')

        #remove the svg
        os.remove(tmpname + '.svg')

        #Update the final svg size
        self.update_size(svg_width, svg_height)
        #Add the final svg output of the figure
        self.svgout = self.content

        #Set rendered flag to true (needed for the cache)
        self.rendered = True
Example #2
0
    def render(self):
        """
            The render of an svg part
        """

        #Need to create a temp file
        if self.inkscape_size:
            logging.debug('Run inkscape to get svg size')
            # Need to get the height and width of the svg command
            tmpsvg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" xmlns:xlink="http://www.w3.org/1999/xlink">'
            if self.out_svgdefs is not None:
                tmpsvg += '<defs>%s</defs>' % (' '.join(self.out_svgdefs))

            tmpsvg += ' %s</svg>' % (self.content)

            # Use NamedTemporaryFile, that automatically remove the file on close by default
            with tempfile.NamedTemporaryFile(mode='w',
                                             prefix='beampytmp',
                                             suffix='.svg') as f:
                f.write(tmpsvg)

                # Need to flush the file to make it's content updated on disk
                f.file.flush()

                # Get the dimension of the svg using inkscape
                svg_width = getsvgwidth(f.name)
                svg_height = getsvgheight(f.name)

        else:
            svg_width = convert_unit(self.width.value)
            svg_height = convert_unit(self.height.value)

        #Update the final svg size
        self.update_size(svg_width, svg_height)
        #Add the final svg output of the figure
        self.svgout = self.content

        #Set rendered flag to true (needed for the cache)
        self.rendered = True
Example #3
0
    def render(self):
        """
            Text is rendered using latex if self.usetex = True if not use simple svg
        """

        if self.usetex:
            #print(self.svgtext)
            if self.svgtext == '':
                # Run the local render
                self.local_render()

                # If it's still empty their is an error
                if self.svgtext == '':
                    print("Latex Compilation Error")
                    print("Beampy Input:")
                    print(self.content)
                    sys.exit(0)

            #Parse the ouput with beautifullsoup
            soup = BeautifulSoup(self.svgtext, 'xml')
            svgsoup = soup.find('svg')
            #print(soup)

            #Find the width and height
            xinit, yinit, text_width, text_height = svgsoup.get(
                'viewBox').split()
            text_width = float(text_width)
            text_height = float(text_height)

            #Get id of paths element to make a global counter over the entire document
            if 'path' not in document._global_counter:
                document._global_counter['path'] = 0

            #New method with a global glyph store
            svgsoup = self.parse_dvisvgm_svg(svgsoup)

            #Change id in svg defs to use the global id system
            #soup = make_global_svg_defs(soup)

            #svgsoup = soup.find('svg')

            #Find all links to apply the style defined in theme['link']
            links = svgsoup.find_all('a')
            style = ' '.join([
                '%s:%s;' % (str(key), str(value))
                for key, value in list(document._theme['link'].items())
            ])
            for link in links:
                link['style'] = style

            #Use the first <use> in svg to get the y of the first letter
            try:
                uses = svgsoup.find_all('use')
            except:
                print(soup)

            if len(uses) > 0:
                #TODO: need to make a more fine definition of baseline
                baseline = 0
                for use in uses:
                    if use.has_attr('y'):
                        baseline = float(use.get('y'))
                        break

                if baseline == 0:
                    print("No Baseline found in TeX and is put to 0")
                    #print baseline

                #Get the group tag to get the transform matrix to add yoffset
                g = svgsoup.find('g')
                transform_matrix = g.get('transform')

                if getattr(self, 'va', False) and self.va == 'baseline':
                    yoffset = -float(baseline)
                    xoffset = -float(xinit)
                    #for the box plot (see boxed below)
                    oldyinit = yinit
                    yinit = -float(baseline) + float(yinit)
                    baseline = -float(oldyinit) + float(baseline)

                else:
                    yoffset = -float(yinit)
                    xoffset = -float(xinit)
                    #For the box plot
                    baseline = -float(yinit) + float(baseline)
                    yinit = 0

                #print baseline, float(yinit), yoffset
                #newmatrix = 'translate(%s,%0.4f)'%(-float(xoffset),-float(yoffset) )
                tex_pt_to_px = 96 / 72.27
                newmatrix = 'scale(%0.3f) translate(%0.1f,%0.1f)' % (
                    tex_pt_to_px, xoffset, yoffset)
                g['transform'] = newmatrix
                text_width = text_width * tex_pt_to_px
                text_height = text_height * tex_pt_to_px
                baseline = baseline * tex_pt_to_px
                yinit = yinit * tex_pt_to_px
                g['opacity'] = self.opacity
                #g['viewBox'] = svgsoup.get('viewBox')

            output = svgsoup.renderContents().decode('utf8', errors='replace')

            #Add red box around the text
            if document._text_box:
                boxed = '''<g transform="translate(%0.1f,%0.1f)">
                <line x1="0" y1="0" x2="%i" y2="0" style="stroke: red"/>
                <line x1="%i" y1="0" x2="%i" y2="%i" style="stroke: red"/>
                <line x1="%i" y1="%i" x2="0" y2="%i" style="stroke: red"/>
                <line x1="0" y1="%i" x2="0" y2="0" style="stroke: red"/>
                <line x1="0" y1="%i" x2="%i" y2="%i" style="stroke: green"/>
                </g>'''
                output += boxed % (0, float(yinit), text_width, text_width,
                                   text_width, text_height, text_width,
                                   text_height, text_height, text_height,
                                   baseline, text_width, baseline)

            #print output
        else:
            #Render as svg text
            #print('[WARNING !!!]: Classic text not yet implemented')
            textin = self.content
            style = ''
            if hasattr(self, 'color'):
                style += 'color:%s' % (self.color)

            output = '<text style="%s">%s</text>' % (style,
                                                     textin.decode('utf-8'))
            tmpsvg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" xmlns:xlink="http://www.w3.org/1999/xlink">%s</svg>' % output

            #Need to create a temp file
            with tempfile.NamedTemporaryFile(mode='w',
                                             suffix='.svt',
                                             prefix='beampytmp') as f:

                f.write(tmpsvg)
                # update file content to disk

                f.file.flush()
                # Get width and height
                text_width = getsvgwidth(f.name)
                text_height = getsvgheight(f.name)

            # print(text_width, text_height)

        #Update positionner with the correct width and height of the final svg
        self.update_size(text_width, text_height)
        #Store the output svg
        logging.debug(type(output))
        self.svgout = output
        #Update the rendered state of the module
        self.rendered = True
Example #4
0
    def render(self):
        """
            function to render figures
        """

        # Svg // pdf render
        if self.ext in ('svg', 'pdf', 'eps', 'matplotlib'):
            #Convert pdf to svg
            if self.ext == 'pdf':
                figurein = convert_pdf_to_svg(self.content)
            elif self.ext == 'eps':
                figurein = convert_eps_to_svg(self.content)

            #Convert matplotlib figure to svg
            elif self.ext == 'matplotlib':

                #Store mpl svg to a stringIO object
                with StringIO() as tmpf:
                    self.content.savefig(tmpf,
                                         bbox_inches='tight',
                                         format='svg')
                    tmpf.seek(0)  #go to the biginig of the file

                    #store tmpf content as string in figurein variable
                    figurein = tmpf.read().encode('utf-8')

            #General case for svg format
            else:
                #Check if a filename is given for a svg file or directly read the content value
                if os.path.isfile(self.content):
                    with open(self.content, 'r') as f:
                        figurein = f.read()

                else:
                    figurein = self.content

            #test if we need to optimise the svg
            if document._optimize_svg:
                figurein = optimize_svg(figurein)

            soup = BeautifulSoup(figurein, 'xml')

            #Change id in svg defs to use the global id system
            soup = make_global_svg_defs(soup)

            #Optimize the size of embeded svg images !
            if document._resize_raster:
                imgs = soup.findAll('image')
                if imgs:
                    for img in imgs:

                        #True width and height of embed svg image
                        width, height = int(float(img['width'])), int(
                            float(img['height']))
                        img_ratio = height / float(width)
                        b64content = img['xlink:href']

                        try:
                            in_img = BytesIO(
                                base64.b64decode(
                                    b64content.split(';base64,')[1]))
                            tmp_img = Image.open(in_img)
                            #print(tmp_img)
                            out_img = resize_raster_image(
                                tmp_img,
                                max_width=self.positionner.width.value)
                            out_b64 = base64.b64encode(
                                out_img.read()).decode('utf8')

                            #replace the resized image into the svg
                            img['xlink:href'] = 'data:image/%s;base64, %s' % (
                                tmp_img.format.lower(), out_b64)
                        except:
                            print('Unable to reduce the image size')
                            pass

            svgtag = soup.find('svg')

            svg_viewbox = svgtag.get("viewBox")

            tmph = svgtag.get("height")
            tmpw = svgtag.get("width")
            if tmph is None or tmpw is None:
                with tempfile.NamedTemporaryFile(mode='w',
                                                 prefix='beampytmp',
                                                 suffix='.svg') as f:
                    try:
                        f.write(figurein)
                    except Exception as e:
                        #python 2
                        f.write(figurein.encode('utf8'))

                    # force to write file content to disk
                    f.file.flush()

                    # get svg size using inkscape
                    tmph = getsvgheight(f.name)
                    tmpw = getsvgwidth(f.name)

            svgheight = convert_unit(tmph)
            svgwidth = convert_unit(tmpw)

            if svg_viewbox is not None:
                svgheight = svg_viewbox.split(' ')[3]
                svgwidth = svg_viewbox.split(' ')[2]

            # BS4 get the svg tag content without <svg> and </svg>
            tmpfig = svgtag.renderContents().decode('utf8')

            # Scale the figure according to the given width
            if self.width.value is not None and self.height.value is None:
                # SCALE OK need to keep the original viewBox !!!
                scale = (self.positionner.width / float(svgwidth)).value
                figure_height = float(svgheight) * scale
                figure_width = self.positionner.width.value

            # Scale the figure according to the given height
            if self.height.value is not None and self.width.value is None:
                figure_height = self.positionner.height.value
                scale = (self.positionner.height / float(svgheight)).value
                figure_width = float(svgwidth) * scale

            # Dont scale the figure let the user fix the width height
            if self.height.value is not None and self.width.value is not None:
                output = tmpfig
                figure_height = self.positionner.height.value
                figure_width = self.positionner.width.value
            else:
                # Apply the scaling to the figure
                tmphead = '\n<g transform="scale(%0.5f)">' % (scale)
                output = tmphead + tmpfig + '</g>\n'

            #Update the final svg size
            self.update_size(figure_width, figure_height)
            #Add the final svg output of the figure
            self.svgout = output

        #Bokeh images
        if self.ext == 'bokeh':

            # Change the sizing mode (need scale_both) to adapt size of the figure
            self.content.sizing_mode = 'scale_both'
            # Run the bokeh components function to separate figure html div and js script
            figscript, figdiv = components(self.content, wrap_script=False)

            # Transform figscript to givea function name load_bokehjs
            tmp = figscript.splitlines()
            goodscript = '\n'.join(['["load_bokeh"] = function() {'] +
                                   tmp[1:-1] + ['};\n'])

            #Add the htmldiv to htmlout
            self.htmlout = "<div id='bk_resizer' width='{width}px' height='{height}px' style='width: {width}px; height: {height}px; transform-origin: left top 0px;'> {html} </div>"
            self.htmlout = self.htmlout.format(width=self.positionner.width,
                                               height=self.positionner.height,
                                               html=figdiv)

            #Add the script to scriptout
            self.jsout = goodscript

        #For the other format
        if self.ext in ('png', 'jpeg', 'gif'):
            #Open image with PIL to compute size
            tmp_img = Image.open(self.content)
            _, _, tmpwidth, tmpheight = tmp_img.getbbox()

            # Scale the figure according to the given width
            if self.width.value is not None and self.height.value is None:
                # SCALE OK need to keep the original viewBox !!!
                scale = (self.positionner.width / float(tmpwidth)).value
                figure_height = float(tmpheight) * scale
                figure_width = self.positionner.width.value

            # Scale the figure according to the given height
            if self.height.value is not None and self.width.value is None:
                figure_height = self.positionner.height.value
                scale = (self.positionner.height / float(tmpheight)).value
                figure_width = float(tmpwidth) * scale

            # Dont scale the figure let the user fix the width height
            if self.height.value is not None and self.width.value is not None:
                figure_height = self.positionner.height.value
                figure_width = self.positionner.width.value

            if document._resize_raster:
                #Rescale figure to the good size (to improve size and display speed)
                if self.ext == 'gif':
                    print('Gif are not resized, the original size is taken!')
                    with open(self.content, "rb") as f:
                        figurein = base64.b64encode(f.read()).decode('utf8')

                else:
                    out_img = resize_raster_image(tmp_img,
                                                  max_width=figure_width)
                    figurein = base64.b64encode(out_img.read()).decode('utf8')
                    out_img.close()
            else:
                with open(self.content, "rb") as f:
                    figurein = base64.b64encode(f.read()).decode('utf8')

            tmp_img.close()

            if self.ext == 'png':
                output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/png;base64, %s" />' % (
                    figure_width, figure_height, figurein)

            if self.ext == 'jpeg':
                output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/jpg;base64, %s" />' % (
                    figure_width, figure_height, figurein)

            if self.ext == 'gif':
                output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/gif;base64, %s" />' % (
                    figure_width, figure_height, figurein)

            # Update the final size of the figure
            self.update_size(figure_width, figure_height)
            # Add the final svg to svgout
            self.svgout = output

        #print self.width, self.height
        #Update the rendered state of the module
        self.rendered = True
Example #5
0
    def render(self):
        """
            Text is rendered using latex if self.usetex = True if not use simple svg
        """

        if self.usetex:

            #Check if a color is defined in args
            if hasattr(self, 'color'):
                textin = color_text(self.content, self.color)
            else:
                textin = self.content

            if 'center' in self.align:
                texalign = r'\centering'
            elif 'right' in self.align:
                texalign = r'\flushright'
            else:
                texalign = ''

            #fontsize{size}{interlinear_size}
            pretex = r"""
            \documentclass[crop=True]{standalone}
            \usepackage[utf8x]{inputenc}
            \usepackage{fix-cm}
            \usepackage[hypertex]{hyperref}
            \usepackage[svgnames]{xcolor}
            \renewcommand{\familydefault}{\sfdefault}
            \usepackage{varwidth}
            \usepackage{amsmath}
            \usepackage{amsfonts}
            \usepackage{amssymb}
            \begin{document}
            \begin{varwidth}{%ipt}
            %s
            \fontsize{%i}{%i}\selectfont %s

            \end{varwidth}
            \end{document}
            """ % (self.width * (72.27 / 96.), texalign, self.size,
                   (self.size + self.size * 0.1), textin)
            #96/72.27 pt_to_px for latex

            #latex2svg
            testsvg = latex2svg(pretex)

            if testsvg == '':
                print("Latex Compilation Error")
                print("Beampy Input")
                print(pretex)
                sys.exit(0)

            #Parse the ouput with beautifullsoup
            soup = BeautifulSoup(testsvg, 'xml')
            svgsoup = soup.find('svg')
            #print(soup)

            #Find the width and height
            xinit, yinit, text_width, text_height = svgsoup.get(
                'viewBox').split()
            text_width = float(text_width)
            text_height = float(text_height)

            #TODO: REPLACE BeautifulSoup by lxml (which is faster)
            #from lxml import etree
            #doc = etree.fromstring(testsvg)
            #dtest = doc.xpath('//path/id')
            #print(dtest)

            #Get id of paths element to make a global counter over the entire document
            if 'path' not in document._global_counter:
                document._global_counter['path'] = 0

            #Create unique_id_ with time
            #text_id =  ("%0.2f"%time.time()).split('.')[-1]
            """
            for path in soup.find_all('path'):
                pid = path.get('id')
                new_pid = '%s_%i'%(text_id, document._global_counter['path'])

                #Check genereta an hash of the glyphs svg path and check if it's
                #already define in the global store
                md5print = hashlib.md5(path.get('d')).hexdigest()

                new_svg_path = "<path d='%s', id='%s'> "%(path.get('d'), new_pid)
                print(new_svg_path)
               
                print(md5print, 'for ', pid, 'nid', new_pid)

                #Old way on the global svg
                testsvg = re.sub(pid, new_pid, testsvg)
                document._global_counter['path'] += 1

            #Reparse the svg
            soup = BeautifulSoup(testsvg, 'xml')
            """

            #New method with a global glyph store
            svgsoup = parse_dvisvgm_svg(svgsoup)

            #Change id in svg defs to use the global id system
            #soup = make_global_svg_defs(soup)

            #svgsoup = soup.find('svg')

            #Find all links to apply the style defined in theme['link']
            links = svgsoup.find_all('a')
            style = ' '.join([
                '%s:%s;' % (str(key), str(value))
                for key, value in document._theme['link'].items()
            ])
            for link in links:
                link['style'] = style

            #Use the first <use> in svg to get the y of the first letter
            try:
                uses = svgsoup.find_all('use')
            except:
                print(soup)

            if len(uses) > 0:
                #TODO: need to make a more fine definition of baseline
                baseline = 0
                for use in uses:
                    if use.has_attr('y'):
                        baseline = float(use.get('y'))
                        break

                if baseline == 0:
                    print("No Baseline found in TeX and is put to 0")
                    #print baseline

                #Get the group tag to get the transform matrix to add yoffset
                g = svgsoup.find('g')
                transform_matrix = g.get('transform')

                if getattr(self, 'va', False) and self.va == 'baseline':
                    yoffset = -float(baseline)
                    xoffset = -float(xinit)
                    #for the box plot (see boxed below)
                    oldyinit = yinit
                    yinit = -float(baseline) + float(yinit)
                    baseline = -float(oldyinit) + float(baseline)

                else:
                    yoffset = -float(yinit)
                    xoffset = -float(xinit)
                    #For the box plot
                    baseline = -float(yinit) + float(baseline)
                    yinit = 0

                #print baseline, float(yinit), yoffset
                #newmatrix = 'translate(%s,%0.4f)'%(-float(xoffset),-float(yoffset) )
                tex_pt_to_px = 96 / 72.27
                newmatrix = 'scale(%0.3f) translate(%0.1f,%0.1f)' % (
                    tex_pt_to_px, xoffset, yoffset)
                g['transform'] = newmatrix
                text_width = text_width * tex_pt_to_px
                text_height = text_height * tex_pt_to_px
                baseline = baseline * tex_pt_to_px
                yinit = yinit * tex_pt_to_px
                #g['viewBox'] = svgsoup.get('viewBox')

            output = svgsoup.renderContents()

            #Add red box around the text
            if document._text_box:
                boxed = '''<g transform="translate(%0.1f,%0.1f)">
                <line x1="0" y1="0" x2="%i" y2="0" style="stroke: red"/>
                <line x1="%i" y1="0" x2="%i" y2="%i" style="stroke: red"/>
                <line x1="%i" y1="%i" x2="0" y2="%i" style="stroke: red"/>
                <line x1="0" y1="%i" x2="0" y2="0" style="stroke: red"/>
                <line x1="0" y1="%i" x2="%i" y2="%i" style="stroke: green"/>
                </g>'''
                output += boxed % (0, float(yinit), text_width, text_width,
                                   text_width, text_height, text_width,
                                   text_height, text_height, text_height,
                                   baseline, text_width, baseline)

            #print output
        else:
            #Render as svg text
            #print('[WARNING !!!]: Classic text not yet implemented')
            textin = self.content
            style = ''
            if hasattr(self, 'color'):
                style += 'color:%s' % (self.color)

            output = '<text style="%s">%s</text>' % (style,
                                                     textin.decode('utf-8'))
            tmpsvg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" xmlns:xlink="http://www.w3.org/1999/xlink">%s</svg>' % output

            #Need to create a temp file
            tmpfile, tmpnam = tempfile.mkstemp(prefix='beampytmp')
            with open(tmpnam + '.svg', 'w') as f:
                f.write(tmpsvg)

            text_width = getsvgwidth(tmpnam + '.svg')
            text_height = getsvgheight(tmpnam + '.svg')

            os.remove(tmpnam + '.svg')

            print(text_width, text_height)

        #Update positionner with the correct width and height of the final svg
        self.update_size(text_width, text_height)

        #Store the output svg
        self.svgout = output
        #Update the rendered state of the module
        self.rendered = True
Example #6
0
    def render(self):
        """
            function to render figures
        """


        #Svg // pdf render
        if self.ext in ('svg', 'pdf') :
            #Convert pdf to svg
            if self.ext == 'pdf' :
                figurein = convert_pdf_to_svg( self.content )
            else:
                #Check if a filename is given for a svg file or directly read the content value
                if os.path.isfile(self.content):
                    with open(self.content) as f:
                        figurein = f.read()
                else:
                    figurein = self.content

            #test if we need to optimise the svg
            if document._optimize_svg:
                figurein = optimize_svg(figurein)

            soup = BeautifulSoup(figurein, 'xml')

            #Change id in svg defs to use the global id system
            soup = make_global_svg_defs(soup)

            #Optimize the size of embeded svg images !
            if document._resize_raster:
                imgs = soup.findAll('image')
                if imgs:
                    for img in imgs:

                        #True width and height of embed svg image
                        width, height = int( float(img['width']) ) , int( float(img['height']) )
                        img_ratio = height/float(width)
                        b64content = img['xlink:href']

                        try:
                            in_img =  BytesIO( base64.b64decode(b64content.split(';base64,')[1]) )
                            tmp_img = Image.open(in_img)
                            #print(tmp_img)
                            out_img = resize_raster_image( tmp_img )
                            out_b64 = base64.b64encode( out_img.read() )

                            #replace the resized image into the svg
                            img['xlink:href'] = 'data:image/%s;base64, %s'%(tmp_img.format.lower(), out_b64)
                        except:
                            print('Unable to reduce the image size')
                            pass

            svgtag = soup.find('svg')

            svg_viewbox = svgtag.get("viewBox")

            tmph = svgtag.get("height")
            tmpw = svgtag.get("width")
            if tmph == None or tmpw == None:
                fmpf, tmpname = tempfile.mkstemp(prefix="beampytmp")
                with open( tmpname+'.svg', 'w' ) as f:
                    f.write(figurein)
                    #print figurein
                tmph = getsvgheight( tmpname+'.svg' )
                tmpw = getsvgwidth( tmpname+'.svg' )
                #print tmpw, tmph
                os.remove(tmpname+'.svg')


            svgheight = convert_unit( tmph )
            svgwidth = convert_unit( tmpw )

            if svg_viewbox != None:
                svgheight = svg_viewbox.split(' ')[3]
                svgwidth = svg_viewbox.split(' ')[2]

            #SCALE OK need to keep the original viewBox !!!
            scale_x = self.positionner.width/float(svgwidth)
            #print svgwidth, svgheight, scale_x
            #scale_y = float(convert_unit(args['height']))/float(svgheight)
            good_scale = scale_x

            #BS4 get the svg tag content without <svg> and </svg>
            tmpfig = svgtag.renderContents()

            #Add the correct first line and last
            tmphead = '\n<g transform="scale(%0.5f)">'%(good_scale)
            output = tmphead + tmpfig + '</g>\n'

            figure_height = float(svgheight)*good_scale
            figure_width = self.width

            #Update the final svg size
            self.update_size(figure_width, figure_height)
            #Add the final svg output of the figure
            self.svgout = output

        #Bokeh images
        if self.ext == 'bokeh':

            #Run the bokeh components function to separate figure html div and js script
            figscript, figdiv = components(self.content, wrap_script=False)

            #Transform figscript to givea function name load_bokehjs
            tmp = figscript.splitlines()
            goodscript = '\n'.join( ['["load_bokeh"] = function() {'] + tmp[1:-1] + ['};\n'] )

            #Add the htmldiv to htmlout
            self.htmlout = figdiv
            #Add the script to scriptout
            self.jsout = goodscript

        #For the other format
        if self.ext in ('png', 'jpeg'):
            #Open image with PIL to compute size
            tmp_img = Image.open(self.content)
            _,_,tmpwidth,tmpheight = tmp_img.getbbox()
            scale_x = self.positionner.width/float(tmpwidth)
            figure_height = float(tmpheight) * scale_x
            figure_width = self.positionner.width

            if document._resize_raster:
                #Rescale figure to the good size (to improve size and display speed)
                out_img = resize_raster_image(tmp_img)
                figurein = base64.b64encode(out_img.read())
                out_img.close()
            else:
                with open( self.content, "r") as f:
                    figurein = base64.b64encode(f.read())

            tmp_img.close()

            if self.ext == 'png':
                output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/png;base64, %s" />'%(figure_width, figure_height, figurein)

            if self.ext == 'jpeg':
                output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/jpg;base64, %s" />'%(figure_width, figure_height, figurein)

            #Update the final size of the figure
            self.update_size(figure_width, figure_height)
            #Add the final svg to svgout
            self.svgout = output

        #print self.width, self.height
        #Update the rendered state of the module
        self.rendered = True
Example #7
0
    def render(self):
        """
            function to render figures
        """


        #Svg // pdf render
        if self.ext in ('svg', 'pdf', 'matplotlib') :
            #Convert pdf to svg
            if self.ext == 'pdf' :
                figurein = convert_pdf_to_svg( self.content )

            #Convert matplotlib figure to svg
            elif self.ext == 'matplotlib':

                #Store mpl svg to a stringIO object
                with StringIO() as tmpf:
                    self.content.savefig(tmpf, bbox_inches='tight', format='svg')
                    tmpf.seek(0) #go to the biginig of the file

                    #store tmpf content as string in figurein variable
                    figurein = tmpf.read().encode('utf-8')

            #General case for svg format
            else:
                #Check if a filename is given for a svg file or directly read the content value
                if os.path.isfile(self.content):
                    with open(self.content) as f:
                        figurein = f.read()
                else:
                    figurein = self.content

            #test if we need to optimise the svg
            if document._optimize_svg:
                figurein = optimize_svg(figurein)

            soup = BeautifulSoup(figurein, 'xml')

            #Change id in svg defs to use the global id system
            soup = make_global_svg_defs(soup)

            #Optimize the size of embeded svg images !
            if document._resize_raster:
                imgs = soup.findAll('image')
                if imgs:
                    for img in imgs:

                        #True width and height of embed svg image
                        width, height = int( float(img['width']) ) , int( float(img['height']) )
                        img_ratio = height/float(width)
                        b64content = img['xlink:href']

                        try:
                            in_img =  BytesIO( base64.b64decode(b64content.split(';base64,')[1]) )
                            tmp_img = Image.open(in_img)
                            #print(tmp_img)
                            out_img = resize_raster_image( tmp_img )
                            out_b64 = base64.b64encode( out_img.read() )

                            #replace the resized image into the svg
                            img['xlink:href'] = 'data:image/%s;base64, %s'%(tmp_img.format.lower(), out_b64)
                        except:
                            print('Unable to reduce the image size')
                            pass

            svgtag = soup.find('svg')

            svg_viewbox = svgtag.get("viewBox")

            tmph = svgtag.get("height")
            tmpw = svgtag.get("width")
            if tmph == None or tmpw == None:
                fmpf, tmpname = tempfile.mkstemp(prefix="beampytmp")
                with open( tmpname+'.svg', 'w' ) as f:
                    f.write(figurein)
                    #print figurein
                tmph = getsvgheight( tmpname+'.svg' )
                tmpw = getsvgwidth( tmpname+'.svg' )
                #print tmpw, tmph
                os.remove(tmpname+'.svg')


            svgheight = convert_unit( tmph )
            svgwidth = convert_unit( tmpw )

            if svg_viewbox != None:
                svgheight = svg_viewbox.split(' ')[3]
                svgwidth = svg_viewbox.split(' ')[2]

            #SCALE OK need to keep the original viewBox !!!
            scale_x = self.positionner.width/float(svgwidth)
            #print svgwidth, svgheight, scale_x
            #scale_y = float(convert_unit(args['height']))/float(svgheight)
            good_scale = scale_x

            #BS4 get the svg tag content without <svg> and </svg>
            tmpfig = svgtag.renderContents()

            #Add the correct first line and last
            tmphead = '\n<g transform="scale(%0.5f)">'%(good_scale)
            output = tmphead + tmpfig + '</g>\n'

            figure_height = float(svgheight)*good_scale
            figure_width = self.width

            #Update the final svg size
            self.update_size(figure_width, figure_height)
            #Add the final svg output of the figure
            self.svgout = output

        #Bokeh images
        if self.ext == 'bokeh':

            # Run the bokeh components function to separate figure html div and js script
            figscript, figdiv = components(self.content, wrap_script=False)

            # Transform figscript to givea function name load_bokehjs
            tmp = figscript.splitlines()
            goodscript = '\n'.join( ['["load_bokeh"] = function() {'] + tmp[1:-1] + ['};\n'] )

            #Add the htmldiv to htmlout
            self.htmlout = figdiv
            #Add the script to scriptout
            self.jsout = goodscript

        #For the other format
        if self.ext in ('png', 'jpeg'):
            #Open image with PIL to compute size
            tmp_img = Image.open(self.content)
            _,_,tmpwidth,tmpheight = tmp_img.getbbox()
            scale_x = self.positionner.width/float(tmpwidth)
            figure_height = float(tmpheight) * scale_x
            figure_width = self.positionner.width

            if document._resize_raster:
                #Rescale figure to the good size (to improve size and display speed)
                out_img = resize_raster_image(tmp_img)
                figurein = base64.b64encode(out_img.read())
                out_img.close()
            else:
                with open( self.content, "r") as f:
                    figurein = base64.b64encode(f.read())

            tmp_img.close()

            if self.ext == 'png':
                output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/png;base64, %s" />'%(figure_width, figure_height, figurein)

            if self.ext == 'jpeg':
                output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/jpg;base64, %s" />'%(figure_width, figure_height, figurein)

            #Update the final size of the figure
            self.update_size(figure_width, figure_height)
            #Add the final svg to svgout
            self.svgout = output

        #print self.width, self.height
        #Update the rendered state of the module
        self.rendered = True
Example #8
0
def render_figure( ct ):

    """
        function to render figures
    """

    #read args in the dict
    args = ct['args']

    #Svg // pdf render
    if args['ext'] in ('svg', 'pdf') :

        #Convert pdf to svg
        if args['ext'] == 'pdf' :
            figurein = convert_pdf_to_svg( args['filename'] )
        else:
            #Check if a filename is given for a svg file or directly read the content value
            if 'filename' in args:
                with open(args['filename']) as f:
                    figurein = f.read()
            else:
                figurein = ct['content']

        #test if we need to optimise the svg
        if document._optimize_svg:
            figurein = optimize_svg(figurein)

        soup = BeautifulSoup(figurein, 'xml')

        #Change id in svg defs to use the global id system
        soup = make_global_svg_defs(soup)

        #Optimize the size of embeded svg images !
        if document._resize_raster:
            imgs = soup.findAll('image')
            if imgs:
                for img in imgs:
                    #True width and height of embed svg image
                    width, height = int( float(img['width']) ) , int( float(img['height']) )
                    img_ratio = height/float(width)
                    b64content = img['xlink:href']

                    try:
                        in_img =  BytesIO( base64.b64decode(b64content.split(';base64,')[1]) )
                        tmp_img = Image.open(in_img)
                        #print(tmp_img)
                        out_img = resize_raster_image( tmp_img )
                        out_b64 = base64.b64encode( out_img.read() )

                        #replace the resized image into the svg
                        img['xlink:href'] = 'data:image/%s;base64, %s'%(tmp_img.format.lower(), out_b64)
                    except:
                        print('Unable to reduce the image size')
                        pass

        svgtag = soup.find('svg')

        svg_viewbox = svgtag.get("viewBox")

        tmph = svgtag.get("height")
        tmpw = svgtag.get("width")
        if tmph == None or tmpw == None:
            fmpf, tmpname = tempfile.mkstemp(prefix="beampytmp")
            with open( tmpname+'.svg', 'w' ) as f:
                f.write(figurein)
                #print figurein
            tmph = getsvgheight( tmpname+'.svg' )
            tmpw = getsvgwidth( tmpname+'.svg' )
            #print tmpw, tmph
            os.remove(tmpname+'.svg')


        svgheight = convert_unit( tmph )
        svgwidth = convert_unit( tmpw )

        if svg_viewbox != None:
            svgheight = svg_viewbox.split(' ')[3]
            svgwidth = svg_viewbox.split(' ')[2]

        #SCALE OK need to keep the original viewBox !!!
        scale_x = ct['positionner'].width/float(svgwidth)
        #print svgwidth, svgheight, scale_x
        #scale_y = float(convert_unit(args['height']))/float(svgheight)
        good_scale = scale_x

        #BS4 get the svg tag content without <svg> and </svg>
        tmpfig = svgtag.renderContents()

        #print tmpfig[:100]

        #Add the correct first line and last
        #tmphead = '<g  transform="matrix(%s,0,0,%s,%s,%s)" viewBox="%s">'%(str(good_scale), str(good_scale), convert_unit(args['x']), convert_unit(args['y']), svg_viewbox))
        tmphead = '\n<g transform="scale(%0.5f)">'%(good_scale)
        output = tmphead + tmpfig + '</g>\n'

        figure_height = float(svgheight)*good_scale
        figure_width = ct['positionner'].width

    #Bokeh images
    if args['ext'] == 'bokeh':
        figurein = ct['content']
        figure_height = ct['positionner'].height
        figure_width =  ct['positionner'].width
        output = """%s"""%figurein


    #For the other format
    if args['ext'] in ['png', 'jpeg']:
        #Open image with PIL to compute size
        tmp_img = Image.open(args['filename'])
        _,_,tmpwidth,tmpheight = tmp_img.getbbox()
        scale_x = ct['positionner'].width/float(tmpwidth)
        figure_height = float(tmpheight) * scale_x
        figure_width = ct['positionner'].width

        if document._resize_raster:
            #Rescale figure to the good size (to improve size and display speed)
            out_img = resize_raster_image(tmp_img)
            figurein = base64.b64encode(out_img.read())
            out_img.close()
        else:
            with open( args['filename'], "r") as f:
                figurein = base64.b64encode(f.read())

        tmp_img.close()

    if args['ext'] == 'png':
        output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/png;base64, %s" />'%(figure_width, figure_height, figurein)

    if args['ext'] == 'jpeg':
        output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/jpg;base64, %s" />'%(figure_width, figure_height, figurein)

    ct['positionner'].update_size(figure_width, figure_height)

    return output
Example #9
0
def render_figure( figurein, args ):
    
    """
        function to render figures
    """

    #For svg figure
    
    if args['ext'] in ('svg', 'pdf') :

        #test if we need to optimise the svg
        
        if document._optimize_svg:
            figurein = optimize_svg(figurein)

        soup = BeautifulSoup(figurein, 'xml')

        #Change id in svg defs to use the global id system
        soup = make_global_svg_defs(soup)

        svgtag = soup.find('svg')

        svg_viewbox = svgtag.get("viewBox")

        tmph = svgtag.get("height")
        tmpw = svgtag.get("width")
        if tmph == None or tmpw == None:
            fmpf, tmpname = tempfile.mkstemp(prefix="beampytmp")
            with open( tmpname+'.svg', 'w' ) as f:
                f.write(figurein)
                #print figurein
            tmph = getsvgheight( tmpname+'.svg' )
            tmpw = getsvgwidth( tmpname+'.svg' )
            #print tmpw, tmph
            os.remove(tmpname+'.svg')

        
        svgheight = convert_unit( tmph )
        svgwidth = convert_unit( tmpw )

        if svg_viewbox != None:
            svgheight = svg_viewbox.split(' ')[3]
            svgwidth = svg_viewbox.split(' ')[2]

        #SCALE OK need to keep the original viewBox !!!
        scale_x = float(convert_unit(args['width']))/float(svgwidth)
        #print svgwidth, svgheight, scale_x
        #scale_y = float(convert_unit(args['height']))/float(svgheight)
        good_scale = scale_x

        #BS4 get the svg tag content without <svg> and </svg>
        tmpfig = svgtag.renderContents()

        #print tmpfig[:100]

        #Add the correct first line and last
        #tmphead = '<g  transform="matrix(%s,0,0,%s,%s,%s)" viewBox="%s">'%(str(good_scale), str(good_scale), convert_unit(args['x']), convert_unit(args['y']), svg_viewbox))
        tmphead = '\n<g transform="scale(%0.5f)">'%(good_scale)
        output = tmphead + tmpfig + '</g>\n'

        figure_height = float(svgheight)*good_scale
        figure_width = convert_unit(args['width'])
        
    #Bokeh images
    if args['ext'] == 'bokeh':
        figure_height = float(convert_unit(args['height']))
        figure_width = convert_unit(args['width'])
        output = """%s"""%figurein


    #For the other format
    if args['ext'] in ['png', 'jpeg']:
        #Open image with PIL to compute size
        tmp_img = Image.open(args['filename'])
        _,_,tmpwidth,tmpheight = tmp_img.getbbox()
        tmp_img.close()
        scale_x = float(convert_unit(args['width']))/float(tmpwidth)
        figure_height = float(tmpheight) * scale_x
        figure_width = convert_unit(args['width'])
        
    if args['ext'] == 'png':
        output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/png;base64, %s" />'%(figure_width, figure_height, figurein)

    if args['ext'] == 'jpeg':
        output = '<image x="0" y="0" width="%s" height="%s" xlink:href="data:image/jpg;base64, %s" />'%(figure_width, figure_height, figurein)
    
    #Save the heigt
    #args['height'] = figure_height
    
    return output, float(figure_width), float(figure_height)
Example #10
0
    def render(self):
        """
            Text is rendered using latex if self.usetex = True if not use simple svg
        """

        if self.usetex:

            #Check if a color is defined in args
            if hasattr(self, 'color'):
                textin = color_text( self.content, self.color )
            else:
                textin = self.content

            if 'center' in self.align:
                texalign = r'\centering'
            elif 'right' in self.align:
                texalign = r'\flushright'
            else:
                texalign = ''

            #fontsize{size}{interlinear_size}
            pretex = r"""
            \documentclass[crop=True]{standalone}
            \usepackage[utf8x]{inputenc}
            \usepackage{fix-cm}
            \usepackage[hypertex]{hyperref}
            \usepackage[svgnames]{xcolor}
            \renewcommand{\familydefault}{\sfdefault}
            \usepackage{varwidth}
            \usepackage{amsmath}
            \usepackage{amsfonts}
            \usepackage{amssymb}
            \begin{document}
            \begin{varwidth}{%ipt}
            %s
            \fontsize{%i}{%i}\selectfont %s

            \end{varwidth}
            \end{document}
            """%( self.width*(72.27/96.), texalign,
                self.size, (self.size+self.size*0.1),
                textin )
            #96/72.27 pt_to_px for latex

            #latex2svg
            testsvg = latex2svg( pretex )

            if testsvg == '':
                print("Latex Compilation Error")
                print("Beampy Input")
                print(pretex)
                sys.exit(0)

            #Parse the ouput with beautifullsoup
            soup = BeautifulSoup(testsvg, 'xml')
            svgsoup = soup.find('svg')

            #Get id of paths element to make a global counter over the entire document
            if 'path' not in document._global_counter:
                document._global_counter['path'] = 0

            #Create unique_id_ with time
            text_id =  ("%0.2f"%time.time()).split('.')[-1]
            for path in soup.find_all('path'):
                pid = path.get('id')
                new_pid = '%s_%i'%(text_id, document._global_counter['path'])
                testsvg = re.sub(pid,new_pid, testsvg)
                #path['id'] = new_pid //Need to change also the id ine each use elements ... replace (above) is simpler
                document._global_counter['path'] += 1

            #Reparse the svg
            soup = BeautifulSoup(testsvg, 'xml')

            #Change id in svg defs to use the global id system
            soup = make_global_svg_defs(soup)

            svgsoup = soup.find('svg')

            xinit, yinit, text_width, text_height = svgsoup.get('viewBox').split()
            text_width = float(text_width)
            text_height = float(text_height)

            #Find all links to apply the style defined in theme['link']
            links = soup.find_all('a')
            style = ' '.join(['%s:%s;'%(str(key), str(value)) for key, value in document._theme['link'].items()])
            for link in links:
                link['style'] = style

            #Use the first <use> in svg to get the y of the first letter
            try:
                uses = soup.find_all('use')
            except:
                print soup

            if len(uses) > 0:
                #TODO: need to make a more fine definition of baseline
                baseline = 0
                for use in uses:
                    if use.has_attr('y'):
                        baseline = float(use.get('y'))
                        break

                if baseline == 0:
                    print("No Baseline found in TeX and is put to 0")
                    #print baseline

                #Get the group tag to get the transform matrix to add yoffset
                g = soup.find('g')
                transform_matrix = g.get('transform')


                if getattr(self, 'va', False) and self.va == 'baseline':
                    yoffset = - float(baseline)
                    xoffset = - float(xinit)
                    #for the box plot (see boxed below)
                    oldyinit = yinit
                    yinit = - float(baseline) + float(yinit)
                    baseline = -float(oldyinit) + float(baseline)

                else:
                    yoffset = -float(yinit)
                    xoffset = -float(xinit)
                    #For the box plot
                    baseline = -float(yinit) + float(baseline)
                    yinit = 0



                #print baseline, float(yinit), yoffset
                #newmatrix = 'translate(%s,%0.4f)'%(-float(xoffset),-float(yoffset) )
                tex_pt_to_px = 96/72.27
                newmatrix = 'scale(%0.3f) translate(%0.1f,%0.1f)'%(tex_pt_to_px, xoffset, yoffset)
                g['transform'] = newmatrix
                text_width = text_width * tex_pt_to_px
                text_height = text_height * tex_pt_to_px
                baseline = baseline * tex_pt_to_px
                yinit = yinit * tex_pt_to_px
                #g['viewBox'] = svgsoup.get('viewBox')

            output = svgsoup.renderContents()

            #Add red box around the text
            if document._text_box:
                boxed = '''<g transform="translate(%0.1f,%0.1f)">
                <line x1="0" y1="0" x2="%i" y2="0" style="stroke: red"/>
                <line x1="%i" y1="0" x2="%i" y2="%i" style="stroke: red"/>
                <line x1="%i" y1="%i" x2="0" y2="%i" style="stroke: red"/>
                <line x1="0" y1="%i" x2="0" y2="0" style="stroke: red"/>
                <line x1="0" y1="%i" x2="%i" y2="%i" style="stroke: green"/>
                </g>'''
                output += boxed%( 0, float(yinit),
                                 text_width,
                                 text_width,text_width,text_height,
                                 text_width,text_height,text_height,
                                 text_height,
                                 baseline,text_width,baseline)

            #print output
        else:
            #Render as svg text
            #print('[WARNING !!!]: Classic text not yet implemented')
            textin = self.content
            style = ''
            if hasattr(self, 'color'):
                style += 'color:%s'%(self.color)

            output = '<text style="%s">%s</text>'%(style, textin.decode('utf-8'))
            tmpsvg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" xmlns:xlink="http://www.w3.org/1999/xlink">%s</svg>'%output

            #Need to create a temp file
            tmpfile, tmpnam = tempfile.mkstemp(prefix='beampytmp')
            with open( tmpnam + '.svg', 'w' ) as f:
                f.write( tmpsvg )

            text_width =  getsvgwidth(tmpnam + '.svg')
            text_height = getsvgheight(tmpnam + '.svg')

            os.remove(tmpnam + '.svg')

            print(text_width, text_height)

        #Update positionner with the correct width and height of the final svg
        self.update_size(text_width, text_height)

        #Store the output svg
        self.svgout = output
        #Update the rendered state of the module
        self.rendered = True