예제 #1
0
파일: text.py 프로젝트: frankier/beampy
def render_text(ct, usetex=True):
    """
        Function to render the text using latex

        latex -> dvi -> dvi2svgm -> svg

        Use the svg output for the text in the frame
    """

    args = ct['args']
    textin = ct['content']

    #Check if their is width in args or if we need to use the default width
    if "width" in args:
        w = float(ct['positionner'].width)
    else:
        w = float(document._width)

    if usetex:

        #Check if a color is defined in args
        if 'color' in args:
            textin = color_text(textin, args['color'])

        if 'center' in args['align']:
            texalign = r'\centering'
        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}
        """ % (w * (72.27 / 96.), texalign, args['size'],
               (args['size'] + args['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("Baseline one TeX error 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 'va' in args and args['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
        #args['x'] = convert_unit(args['x'])
        #args['y'] = convert_unit(args['y'])
        #args = ' '.join( [str(arg)+"='"+str(val)+"'" for arg, val in args.iteritems()] )
        print('[WARNING !!!]: Classic text not yet implemented')
        output = "<text>%s</text>" % (textin.decode('utf-8'))
        #TODO: Need to fix the estimation of te width
        #print("[WARNING!!!] Width of classic svg text can't be estimated")
        text_width = 0
        text_height = 0

    #Update positionner with the correct width and height of the final svg
    ct['positionner'].update_size(text_width, text_height)

    return output
예제 #2
0
파일: figure.py 프로젝트: Cgadal/beampy
    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
예제 #3
0
파일: text.py 프로젝트: odevauchelle/beampy
def render_text( textin, args, usetex=True):
    """
        Function to render the text using latex

        latex -> dvi -> dvi2svgm -> svg

        Use the svg output for the text in the frame
    """

    #Check if their is width in args or if we need to use the default width
    if "width" in args:
        w = float(convert_unit(str(args['width'])))
    else:
        w = float(document._width)

    if usetex:

        #Check if a color is defined in args
        if 'fill' in args:
            if "#" in args['fill']:
                textin = r'{\color[HTML]{%s} %s }'%(args['fill'].replace('#','').upper(), textin)
            else:
                textin =r'{\color{%s} %s }'%(args['fill'], textin)

        if 'center' in args['align']:
            texalign = r'\centering'
        else:
            texalign = ''

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

        \end{varwidth}
        \end{document}
        """%(w*(72.27/96.),texalign,args['font-size'],(args['font-size']+args['font-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)



        #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("Baseline one TeX error 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 'va' in args and args['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
        args['x'] = convert_unit(args['x'])
        args['y'] = convert_unit(args['y'])
        args = ' '.join( [str(arg)+"='"+str(val)+"'" for arg, val in args.iteritems()] )
        output = "<text %s>%s</text>"%(args, textin.decode('utf-8'))
        #TODO: Need to fix the estimation of te width
        #print("[WARNING!!!] Width of classic svg text can't be estimated")
        text_width = 0
        text_height = 0

    return output, text_width, text_height
예제 #4
0
파일: figure.py 프로젝트: hchauvet/beampy
    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
예제 #5
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
예제 #6
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
예제 #7
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)
예제 #8
0
파일: text.py 프로젝트: hchauvet/beampy
    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