def replace_image(self, slide, imgpath): for shape in slide.shapes: if hasattr(shape, "image"): img = shape if img.width > 2000000: imgPic = img._pic imgRID = imgPic.xpath('./p:blipFill/a:blip/@r:embed')[0] imgPart = slide.part.related_parts[imgRID] with open(imgpath, 'rb') as f: rImgBlob = f.read() rImgWidth, rImgHeight = Image.open(imgpath).size rImgWidth, rImgHeight = Cm(rImgWidth), Cm( rImgHeight) # change from Px # replace imgPart._blob = rImgBlob widthScale = float(rImgWidth) / img.width heightScale = float(rImgHeight) / img.height maxScale = max(widthScale, heightScale) scaledImgWidth, scaledImgHeight = int( rImgWidth / maxScale), int(rImgHeight / maxScale) # center the image if it's different size to the original scaledImgLeft = int(img.left + (img.width - scaledImgWidth) / 2) scaledImgTop = int(img.top + (img.height - scaledImgHeight) / 2) # now update img.left, img.top, img.width, img.height = scaledImgLeft, scaledImgTop, scaledImgWidth, scaledImgHeight break
def batchInsertPngInSlide(self, path_to_tmpl_presentation, imgsPath): left, top, width, height = Cm(4.28), Cm(2.79), Cm(25.58), Cm(16.59) files = os.listdir(imgsPath) pngfiles = [f for f in files if f.endswith((".png"))] # 生成电子发票pptx页 for index, pngfile in enumerate(pngfiles): fullpath = os.path.join(imgsPath, pngfile) prs = Presentation(path_to_tmpl_presentation) slide = prs.slides[0] pic = slide.shapes.add_picture(fullpath, left, top, height=height, width=width) # 填入文字内容 curAmount = float(pngfile[:-4]) self.fillTextInSlide(slide, index + 1, self.totalPage, self.totalAmount, curAmount, self.totalPaper) pptxPath = os.path.join(self.tempPptxPath, os.path.splitext(pngfile)[0] + '.pptx') prs.save(pptxPath)
def reformat_slide_4(prs, df_fdict): slide = prs.slides[3] heading = "QoQ Attrition Overview" add_text_box(slide, [Cm(1.3), Inches(0.2), Inches(9), Inches(1)], heading, 20, True, align_center=False) x_axis, y_axis, values, label_flags = reformat_dict_attr_for_attrition_chart( df_fdict) create_bar_chart(slide, x_axis, y_axis, values, [Cm(1), Inches(1), Inches(4.8), Inches(4.8)], XL_CHART_TYPE.COLUMN_STACKED, format_chart_1_properties, label_flag=label_flags) chart_table = get_json_data_for_table_2(df_fdict) create_table_box( slide, [Inches(5.1), Inches(1), Inches(3.8), Inches(3.5)], 9, chart_table, 1.2) return prs
def set_slide_size(prs: Presentation, width: float = 26, height: float = 15) -> Presentation: """set the size of all slides in cm""" prs.slide_width = Cm(width) prs.slide_height = Cm(height) return prs
def gen_pptx(template, dir, zemi_name, zemi_date, presenters): if os.path.isfile(template): prs = Presentation(template) else: prs = Presentation() slide = prs.slides.add_slide(prs.slide_layouts[1]) slide.shapes.add_textbox(Cm(2.29), Cm(17.94), Cm(5.15), Cm(1.01)) page = prs.slides[0] zemi_title = page.shapes[0] contents = page.placeholders[1] footer = page.shapes[2] zemi_title.text = zemi_name footer.text = zemi_date date = dt.strptime(zemi_date, '%Y/%m/%d').strftime('%y%m%d') new_dir = dir + "_" + date os.makedirs(new_dir, exist_ok=True) os.chdir(new_dir) for i, (person, file) in enumerate(presenters): run = contents.text_frame.paragraphs[0].add_run() if len(presenters) == i + 1: run.text = person else: run.text = person + "\n" run.hyperlink.address = file prs.save("{}.pptx".format(date)) os.chdir("../") print("PPTX file is successfully generated.")
def prt_slide_graph_p2_1(): global slide slide = prs.slides.add_slide(prs.slide_layouts[6]) title_para('prt_slide_graph_p2_1', '년 월 시스템 ') text_para_1st('월 평균(영업일기준) CPU/MEM 사용율%') # 가로 그래프 1개 좌표 x1, y1, cx1, cy1 = Cm(1.0), Cm(2.5), Cm(11.5), Cm(7.8) # x2, y2, cx2, cy2 = Cm(13.0), Cm(2.5), Cm(11.5), Cm(7.8) # x3, y3, cx3, cy3 = Cm(1.0), Cm(10.5), Cm(11.5), Cm(7.8) # x4, y4, cx4, cy4 = Cm(13.0), Cm(10.5), Cm(11.5), Cm(7.8) # 그래프 on_label = 0;on_mark = 1 chart_data1 = ChartData() # chart_data2 = ChartData() # chart_data3 = ChartData() # chart_data4 = ChartData() # chart_data1.categories = deco_data(data1['data']) chart_data1.categories = ['A', 'B', 'C', 'D'] # chart_data1.categories = chart_data2.categories = chart_data3.categories = chart_data4.categories = ['A', 'B', 'C', 'D'] chart_data1.add_series("CH01", (5,3,7), 2) # chart_data2.add_series("CH02", (5,3,7), 2) # chart_data3.add_series("CH03", (5,3,7), 2) # chart_data4.add_series("CH04", (5,3,7), 2) add_chart_in_ppt(x1, y1, cx1, cy1, chart_data1)
def create_table(slide, data, left, top, width, height, header = True): if header: data.loc[-1] = list(data.columns) # adding a row data.index = data.index + 1 # shifting index data.sort_index(inplace=True) left = Cm(left) top = Cm(top) width = Cm(width) height = Cm(height) n_rows = len(data) n_cols = len(data.columns) table = slide.shapes.add_table(n_rows, n_cols, left, top, width, height).table for i, column in enumerate(data.columns): for j in range(len(data[column])): table.cell(j, i).text = str(data[column][j]) table.cell(j, i).vertical_anchor = pptx.enum.text.MSO_ANCHOR.MIDDLE return table
def reformat_slide_2(prs): slide = prs.slides[1] title = "Culture & Talent" font = add_text_box( slide, [Cm(1.3), Cm(6.5), Inches(9), Inches(1)], title, 36, True) fill_text_color(font, [255, 255, 255]) return prs
def add_img(slide): export_path = "export/" file_name = "気象データ.png" png_path = export_path + file_name left = slide.shapes[1].left top = slide.shapes[1].top height = Inches(4.9) pic = slide.shapes.add_picture(png_path, left,top,Cm(30), Cm(12)) return pic
def addName(slide_name, name): left = Inches(2.05) top = Inches(3.55) width = Cm(15) height = Cm(1) txBox = slide_name.shapes.add_textbox(left, top, width, height) tf = txBox.text_frame tf.text = name txBox.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
def text_para_1st(text1): # 상단 text box left = Cm(1.2); top = Cm(2.0); width = Cm(24); heigh = Cm(0.8) txBox = slide.shapes.add_textbox(left, top, width, heigh) tf = txBox.text_frame tf.clear() p = tf.paragraphs[0] p.text = text1 p.font.size = Pt(12)
def _get_cm( left: float, top: float, width: Optional[float], height: Optional[float]) -> Tuple[Cm, Cm, Optional[Cm], Optional[Cm]]: """convert floats to pptx centimeter objects""" left = Cm(left) top = Cm(top) width = Cm(width) if width else None height = Cm(height) if height else None return left, top, width, height
def get_size(self): width = Cm(0) for col_width in self._column_widths: width += col_width height = Cm(0) for row in self._rows: height = height + row.height self._width = width self._height = height
def print_memo_page(): global slide slide = prs.slides.add_slide(prs.slide_layouts[6]) # 슬라이드 추가 title_para(u'참 고', '') # 텍스트 left = Cm(1.2) top = Cm(2.2) height = Cm(15.0) pic = slide.shapes.add_picture('image\\memo.gif',left, top, height=height) # 텍스트 박스 위치 지정
def addtext(slide, text, x, y, w, h, **kwargs): """Add text (box) to given slide.""" # https://python-pptx.readthedocs.io/en/latest/api/enum/MsoAutoShapeType.html#msoautoshapetype # https://python-pptx.readthedocs.io/en/latest/user/autoshapes.html#adjusting-an-autoshape # https://stackoverflow.com/questions/40149992/python-pptx-align-image-to-center-of-slide verb = kwargs.get('verb', 0) tsize = kwargs.get('lsize', 12) # legend font size tcolor = kwargs.get('lcolor', None) # legend font color fcolor = kwargs.get('fill', (6, 46, 162)) # box fill color lcolor = kwargs.get('line', (1, 23, 81)) # box line color thick = kwargs.get('thick', 1.5) # box line thickness (0 = no line) bold = kwargs.get('bold', True) shadow = kwargs.get('shadow', False) boxtype = kwargs.get('box', 'round') print(">>> Add text at (x,y,w,h)=(%.2f cm,%.2f cm,%.2f cm,%.2f cm): %r" % (x, y, w, h, text)) const = MSO_SHAPE.ROUNDED_RECTANGLE if 'round' in boxtype else MSO_SHAPE.RECTANGLE box = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, Cm(x), Cm(y), Cm(w), Cm(h)) box.text = text paragraph = box.text_frame.paragraphs[0] paragraph.alignment = PP_ALIGN.CENTER box.text_frame.vertical_anchor = MSO_ANCHOR.MIDDLE box.text_frame.margin_top = 0 #Pt(0.5) box.text_frame.margin_bottom = 0 #Pt(0.5) if 'round' in boxtype: box.adjustments[0] = 0.15 # rounded corner ###if not tsize or tsize=='auto': ### #box.text_frame.auto_size = MSO_AUTO_SIZE.SHAPE_TO_FIT_TEXT ### box.text_frame.auto_size = MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE ### #paragraph.font.size = Pt(12) ### box.text_frame.fit_text(font_family='Arial') #autofit_text ###else: if tsize: paragraph.font.size = Pt(tsize) if tcolor: paragraph.font.color.rgb = RGBColor(*tcolor) if bold: paragraph.font.bold = True box.shadow.inherit = shadow # turn on/off shadow fill = box.fill if fcolor: fill.solid() fill.fore_color.rgb = RGBColor(*fcolor) else: fill.background() # no fill / transparant line = box.line if thick: line.width = Pt(thick) if lcolor: # user color line.color.rgb = RGBColor(*lcolor) #line.color.brightness = 0.5 # 50% lighter else: line.fill.background() # no line / transparant return box
def generate_uniqueness_table(slide, uniqueness_information, num_rows=10): # Setup table row_height = Cm(0.78) num_cols = 4 col_widths = [Cm(4)] * 4 top, left = Cm(2.5), Cm(1) tablewidth = sum(col_widths) tableheight = (num_rows + 1) * row_height tableshape = slide.shapes.add_table(num_rows + 1, num_cols, left, top, tablewidth, tableheight) table = tableshape.table # Insert table content column_names = { 'Run Name': 'name', 'SSE Difference': 'SSE_difference', 'Fit Difference': 'fit_difference', 'FMS': 'fms', } column_names = ['Run Name', 'SSE Difference', 'Fit Difference', 'FMS'] data_names = ['name', 'SSE_difference', 'fit_difference', 'fms'] format_options = ['', '.2e', '.2e', '.2f'] for cell_title, cell in zip(column_names, table.rows[0].cells): frame = cell.text_frame frame.clear() run = frame.paragraphs[0].add_run() run.text = cell_title font = run.font font.name = FONT_NAME font.size = FONT_SIZE font.bold = True for i in range(num_rows): cellrow = table.rows[i + 1] for data_name, format_option, cell in zip(data_names, format_options, cellrow.cells): cell_data = uniqueness_information[data_name][i] frame = cell.text_frame frame.clear() run = frame.paragraphs[0].add_run() run.text = f"{cell_data:{format_option}}" font = run.font font.name = FONT_NAME font.size = FONT_SIZE # Format table for col_width, column in zip(col_widths, table.columns): column.width = col_width
def reformat_slide_1(prs, df_fdict): slide = prs.slides[0] title = get_title(df_fdict) subtitle = "May 4, 2020" add_text_box( slide, [Cm(1.3), Cm(10), Inches(9), Inches(1)], title, 32, True) add_text_box( slide, [Cm(1.3), Cm(11.5), Inches(9), Inches(1)], subtitle, 28) return prs, title
def insertPngInSlide(path_to_presentation, img_path): prs = Presentation(path_to_presentation) slide = prs.slides[0] left, top, width, height = Cm(4.28), Cm(2.79), Cm(25.58), Cm(16.59) pic = slide.shapes.add_picture(img_path, left, top, height=height, width=width) prs.save('test.pptx')
def addarrow(slide): """Add arrow (in progress).""" # ARROW connector = slide.shapes.add_shape(MSO_CONNECTOR_TYPE.STRAIGHT, Cm(10.), Cm(5.), Cm(0.), Cm(8.)) line = connector.line._get_or_add_ln() line.append( parse_xml(""" <a:tailEnd type="arrow" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/> """)) return line
def process_position_parameter(param): """Process positioning parameters (left, top, width, height) given to df_to_table. If an integer, returns the right instance of the Cm class to allow it to be treated as cm. If missing, then default to 4cm. Otherwise, pass through whatever it gets. """ if param is None: return Cm(4) elif type(param) is int: return Cm(param) else: return param
def write_title(slide, title): # 在指定位置添加文本框 textbox = slide.shapes.add_textbox(left=Cm(0.2), top=Cm(0), width=Cm(20), height=Cm(1)) tf = textbox.text_frame # 在文本框中写入文字,文字内容为每页PPT第一行最后一列的数据 textbox.text = title tf.paragraphs[0].font.size = Pt(15) tf.paragraphs[0].font.name = '微软雅黑' tf.paragraphs[0].font.bold = True
def __init__(self, slide, slide_height, slide_width, top = Cm(0.5), left = Cm(0.5), rows = 8, cols = 5): height = int(slide_height - 2*top) width = int(slide_width/2 - 2*left) # There is only one placeholder currently idx = slide.shapes[0].placeholder_format.idx placeholder = slide.placeholders[idx] task_frame = placeholder.insert_table(rows,cols) table = task_frame.table table.first_row = False table.first_col = False table.last_row = True table.last_col = False """ Set the width of the columns """ percents = [0.55, 0.1, 0.1, 0.1, 0.15] for col, percent in zip(table.columns, percents): col.width = int(percent*width) for row in table.rows: row.height = int(height/rows) default_text = ["<task{:d}>", "0", "0", "0", "<dev>"] for rkey, row in enumerate(table.rows): for ckey, (cell, text) in enumerate(zip(row.cells, default_text)): t = cell.text_frame if ckey == 0: t.word_wrap = True t.auto_size = MSO_AUTO_SIZE.NONE t.vertical_anchor = MSO_ANCHOR.TOP else: t.word_wrap = False t.auto_size = MSO_AUTO_SIZE.NONE t.vertical_anchor = MSO_ANCHOR.MIDDLE p = t.paragraphs[0] if ckey == 0: p.alignment = PP_ALIGN.LEFT else: p.alignment = PP_ALIGN.CENTER r = p.add_run() r.text = default_text[ckey].format(rkey+1) r.font.size = Pt(10) r.font.name = 'Consolas' self.table = table
def get_arguments(self): super().get_arguments() width = self._extractor.get_value("width") if width is not None: self._width = Cm(width) size = self._extractor.get_value("size") if size is not None: self._width = Cm(size[0]) self._height = Cm(size[1]) self._fill_color_input = self._extractor.get_value("fill_color") self._vertical_anchor_input = self._extractor.get_value( "vertical_anchor") self._rotated = self._extractor.get_value("rotated")
def make_ppt_page(prs, blank_slide, title, data, header, type="north"): slide = prs.slides.add_slide(blank_slide) write_title(slide, title) # 添加表格:rows行数,cols列数,left和top是在PPT中的位置,width是表的列宽,height是表的行高 table = slide.shapes.add_table(rows=11, cols=len(header), left=Cm(3), top=Cm(2), width=Cm(19), height=Cm(15) ) table = table.table write_header(table, header) write_data(table, data, type)
def add_gender_pie_chart(self): """ Gender breakdown pie chart :return: """ chart_data = ChartData() chart_data.categories = ['Male', 'Female'] male_percent = self.data_row['twitter_audience_male_percent'] female_percent = self.data_row['twitter_audience_female_percent'] total = male_percent+female_percent m_percent = male_percent/total f_percent = female_percent/total chart_data.add_series('Series 1', (m_percent, f_percent))#sort out the % values x_coord, y_coord, cx_width, cy_height = Cm(10.46), Cm(0.44), Cm(7), Cm(6) chart = self.slide.shapes.add_chart( XL_CHART_TYPE.PIE, x_coord, y_coord, cx_width, cy_height, chart_data).chart chart.has_legend = True chart.legend.position = XL_LEGEND_POSITION.BOTTOM chart.legend.include_in_layout = False chart.plots[0].has_data_labels = True data_labels = chart.plots[0].data_labels data_labels.number_format = '0%' top = Cm(0.01) left = Cm(10.46) width = Cm(3) height = Cm(1) tx_box = self.shapes.add_textbox(left, top, width, height) t_frame = tx_box.text_frame t_frame.text = "Gender Breakdown"
def add_account_type_chart(self): """ Gender breakdown pie chart :return: """ chart_data = ChartData() chart_data.categories = ['Organisation', 'Individual'] organisation_percent = self.data_row['twitter_audience_organisational'] individual_percent = self.data_row['twitter_audience_individuals'] total = organisation_percent+individual_percent i_percent = individual_percent/total o_percent = organisation_percent/total chart_data.add_series('Series 1', (i_percent, o_percent)) x_coord, y_coord, cx_width, cy_height = Cm(18), Cm(0.44), Cm(7.9), Cm(6.9) chart = self.slide.shapes.add_chart( XL_CHART_TYPE.PIE, x_coord, y_coord, cx_width, cy_height, chart_data).chart chart.has_legend = True chart.legend.position = XL_LEGEND_POSITION.BOTTOM chart.legend.include_in_layout = False chart.plots[0].has_data_labels = True data_labels = chart.plots[0].data_labels data_labels.number_format = '0%' top = Cm(0.01) left = Cm(18) width = Cm(3) height = Cm(1) t_box = self.shapes.add_textbox(left, top, width, height) t_frame = t_box.text_frame t_frame.text = "Account Type Distribution"
def __add_text(self, txt, x_coord, y_coord, cx_width, cy_height): """ add text box :param txt: Text to add :param x_coord: x-coordinate :param y_coord: y-coordinate :param cx_width: x-width :param cy_height: y-height :return: """ tx_box = self.shapes.add_textbox(Cm(x_coord), Cm(y_coord), Cm(cx_width), height=cy_height) t_frame = tx_box.text_frame t_frame.text = txt
def add_twitter_profile(self): """ Add twitter profile information e.g. followers, handle etc :return: """ rows = 2 cols = 2 left = Cm(0.81) top = Cm(2) width = Cm(11) height = Cm(2.73) table = self.shapes.add_table(rows, cols, left, top, width, height).table table.columns[0].width = Cm(5) table.columns[1].width = Cm(3) try: image_data = requests.get(self.data_row['twitter_profile_image']).content with open('image.jpg', 'wb') as test: test.write(image_data) self.shapes.add_picture('image.jpg', Cm(0.81), Cm(0.05)) except requests.HTTPError: LOGGER.warn("failed to extract image!") table.cell(0, 0).text = 'Handle' table.cell(0, 1).text = str(self.data_row['twitter_name']) table.cell(1, 0).text = 'Followers' table.cell(1, 1).text = str(self.data_row['twitter_followers_count']) self.__resize_table_font(table, 12)
def reformat_slide_5(prs, ehi_db): slide = prs.slides[4] heading = "EHI Trend" add_text_box(slide, [Cm(1.3), Inches(0.2), Inches(9), Inches(1)], heading, 20, True, align_center=False) x_axis, y_axis_1, values_1, y_axis_2, values_2, data_labels = get_dict_attr_from_dataframe_for_ehi( ehi_db) create_bar_chart( slide, x_axis, y_axis_1, values_1, [Cm(3.3), Inches(0.7), Inches(7.2), Inches(4)], XL_CHART_TYPE.COLUMN_CLUSTERED, format_chart_2_properties, "Average EHI and Category Distribution over EDAP Cycles") create_line_chart( slide, x_axis, y_axis_2, values_2, [Cm(3.6), Inches(1.36), Inches(7.4), Inches(3.15)], format_chart_3_properties) create_custom_legends( slide, [Inches(1.3), Inches(5), Inches(2), Inches(0.4)], legend_dict) add_text_box(slide, [Cm(2.8), Inches(2.5), Inches(1), Inches(1)], "Average EHI", 11, False, align_center=False, rotation=-90, rgb=(123, 123, 123)) add_text_box(slide, [Inches(8.7), Inches(2.9), Inches(1), Inches(1)], "Number of Employees", 11, False, align_center=False, rotation=-90, rgb=(123, 123, 123)) add_text_box( slide, [Inches(4.5), Inches(4.6), Inches(1), Inches(0.2)], "EHI Cycle", 11, False, align_center=False, rgb=(123, 123, 123)) return prs
def add_stanza(slide, text): left = Cm(1.20) top = Cm(5.80) width = Cm(23.00) height = Cm(12.00) stanza = slide.shapes.add_textbox(left, top, width, height) stanza.text = text.upper() # stanza.text = text stanza.text_frame.auto_size = MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE stanza.text_frame.word_wrap = True for paragraph in stanza.text_frame.paragraphs: paragraph.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER paragraph.font.size = Pt(30) paragraph.font.name = 'Comic Sans MS' paragraph.font.color.rgb = RGBColor(0, 176, 240)