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
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
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
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
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
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
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
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
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)
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