Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
#!/usr/bin/env python
glob_dictionary = {}
glob_files = []
glob_pictures = []
glob_structure = []
glob_layoutdict = {}
glob_slide_counter = 0
glob_width = 0
glob_height = 0
glob_multipic = False
def sorted_nicely( l ):
convert = lambda text: int(text) if text.isdigit() else text
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
return sorted(l, key = alphanum_key)
def create_layoutdict( presentationx ):
print(" -- scnanning existing layouts --")
global glob_layoutdict
layouts = presentationx.slide_layouts
max_layouts = len(layouts)
counter = 0
for x in range(0,max_layouts):
glob_layoutdict[layouts[x].name] = counter
print(" -+ "+ str(counter) +": "+ layouts[x].name + " -")
counter = counter + 1
print("")
def hex_cutter(font_color):
font_color = font_color.lstrip('#')
rgb_color = struct.unpack('BBB',font_color.decode('hex'))
return(rgb_color)
def format_text( run , part ):
font = run.font
try:
pt_size = part["font_size"]
font.size = Pt(pt_size)
except:
pass
try:
font_name = part["font_name"]
font.name = font_name
except:
pass
try:
font_color = part["font_color"]
rgb_color = hex_cutter(font_color)
val1 = rgb_color[0]; val2 = rgb_color[1]; val3 = rgb_color[2]
run.font.color.rgb = RGBColor(val1, val2, val3)
except:
pass
def format_shape( tx_box , part ):
try:
line_color = part["line_color"]
rgb_color = hex_cutter(line_color)
val1 = rgb_color[0]; val2 = rgb_color[1]; val3 = rgb_color[2]
tx_box.line.color.rgb = RGBColor(val1, val2, val3)
except:
pass
try:
fill_color = part["fill_color"]
rgb_color = hex_cutter(fill_color)
tx_box.fill.solid()
val1 = rgb_color[0]; val2 = rgb_color[1]; val3 = rgb_color[2]
tx_box.fill.fore_color.rgb = RGBColor(val1, val2, val3)
except:
pass
def add_text( tx_box , part , pic_count ):
tf = tx_box.text_frame
tf.word_wrap = True
input = part["input"]
if type(part["input"]) == int:
print(" -- connecting textbox with image name")
number = part["input"]
p = tf.paragraphs[0]
try:
if part["align"] == "c" or part["align"] == "center":
p.alignment = PP_ALIGN.CENTER
except:
pass
run = p.add_run()
try:
run.text = glob_pictures[number][pic_count]
except:
print(" >> Not able to connect textbox to a picture.")
try:
format_text(run, part)
except:
print(" >> Was not able to read the textbox format.")
p = tf.add_paragraph()
else:
text_list = part["input"]
for x in range(0,len(text_list)):
p = tf.paragraphs[x]
try:
if part["align"] == "c" or part["align"] == "center":
p.alignment = PP_ALIGN.CENTER
except:
pass
run = p.add_run()
run.text = text_list[x]
format_text(run, part)
p = tf.add_paragraph()
def get_value( string , entry ):
value = entry[string]
return(value)
def adjust_picheight( pic , necessary_height ):
store_height_1 = pic.height
pic.height = necessary_height
store_height_2 = pic.height
factor = float(store_height_2)/float(store_height_1)
pic.width = int(pic.width*factor)
return(pic.width)
def multipic_list_check( file_list ):
length = 0
picamount = len(file_list[0])
picsperslide = glob_structure[0]*glob_structure[1] # in multipic-mode, parts amount is equal on every layer
complete_slides = picamount / picsperslide
broken_slides = float(picamount) % picsperslide
if broken_slides != 0:
complete_slides = complete_slides + 1
length = complete_slides
print("multipic:")
return(length)
def list_check( file_list ):
### file list = multi list of all pictures and textboxes.
### Check the longest of all part entries.
length = 0
for entry in file_list:
if len(entry) > length:
length = len(entry)
print(" -- " + str(length) + " slides will be created")
return(length)
def path_and_file( part_input ):
split_list = part_input.split('/')
last_element = len(split_list)
regex = split_list[-1]
path = ""
for x in range(0,last_element-1):
path = path + split_list[x] + "/"
basic_tuple = (path, regex)
print(basic_tuple)
return(basic_tuple)
def get_files( entry, entrycount, args ):
print(" -- Working with JSON file entry no. " + str(entrycount+1))
global glob_files
global glob_pictures
global glob_structure
global glob_multipic
part_count = 0
### Check if layers are activated and existing.
layer_control = False
multipic_layer_control = False
try:
layers = entry["layers"]
layer_control = True
except:
pass
try:
multipic_layers = entry["multipic_layers"]
multipic_parts = entry["multipic_parts"]
multipic_input = entry["multipic_input"]
multipic_layer_control = True
except:
pass
if layer_control == True and multipic_layer_control == False:
### Filling the structure list (for example: [3, 4, 4, 4], 3 layers, 4 parts each layer)
glob_structure.append(len(layers))
for layer in layers:
parts = layer["parts"]
glob_structure.append(len(parts))
for part in parts:
if part["type"] == "picture":
basic_tuple = path_and_file(part["input"])
temp_list = []; temp_pic_list = []; path = basic_tuple[0]; regex = basic_tuple[1]; sorting_list = []
### Catching common path errors:
if path == "/" or path == "" or path == " ":
path_search = "."
else:
path_search = path
pattern = re.compile(regex)
try:
for file in os.listdir(path_search):
if pattern.search(file):
sorting_list.append(file)
####### Sorting the files after searching.
sorting_list = sorted_nicely(sorting_list)
##########
for e in sorting_list:
file_tuple = (path, e,)
temp_list.append(file_tuple)
temp_pic_list.append(e)
except:
print(" >> path or files not existing.")
if len(temp_list) == 0:
print(" >> Found 0 picture files for " + basic_tuple[1])
else:
print(" -- Found " + str(len(temp_list)) + " picture files for " + basic_tuple[1])
glob_files.append(temp_list)
glob_pictures.append(temp_pic_list)
if part["type"] == "textbox":
temp_list = []
temp_list.append(part["input"])
glob_files.append(temp_list)
### A layer amount is needed. If no layer is existing, glob_structure needs a zero.############# TODO: lfiles
elif multipic_layer_control == True:
glob_multipic = True
glob_structure.append(multipic_layers)
for layer in range(0,multipic_layers):
glob_structure.append(multipic_parts)
### Filling the structure list (for example: [3, 4, 4, 4], 3 layers, 4 pictures each layer)
basic_tuple = path_and_file(multipic_input)
temp_list = []; temp_pic_list = []; path = basic_tuple[0]; regex = basic_tuple[1]; sorting_list = []
### Catching common path errors:
if args.flist is None:
if path == "/" or path == "" or path == " ":
path_search = "."
else:
path_search = path
pattern = re.compile(regex)
try:
for file in os.listdir(path_search):
if pattern.search(file):
sorting_list.append(file)
####### Sorting the files after searching.
sorting_list = sorted_nicely(sorting_list)
##########
for e in sorting_list:
file_tuple = (path, e,)
temp_list.append(file_tuple)
temp_pic_list.append(e)
print(temp_pic_list)
print(temp_list)
except:
print(" >> path or files not existing.")
else:
absPathList = args.flist.split(",")
absPathList = absPathList
for p in absPathList:
dname = os.path.dirname(p) +"/"
bname = os.path.basename(p)
file_tuple = (dname, bname,)
temp_list.append(file_tuple)
temp_pic_list.append(bname)
print(temp_pic_list)
print(temp_list)
###############################################################################################
if len(temp_list) == 0:
print(" >> Found 0 picture files for " + basic_tuple[1])
else:
print(" -- Found " + str(len(temp_list)) + " picture files for " + basic_tuple[1])
glob_files.append(temp_list)
glob_pictures.append(temp_pic_list)
else:
### 1 list with 1 item must be added: Entry amount should be >0, to create content free slides (like title slides) too.
glob_files.append(['None'])
glob_structure.append(0)
def write_slides( presentation , entry , entrycount ):
global glob_slide_counter
file_list = glob_files
layeramount = glob_structure[0]
layout_number = 1
try:
layout_number = entry["layout"]
except:
pass
try:
layout_number = glob_layoutdict[layout_number]
except:
pass
head_height = 0.15
try:
head_height = entry["head_height"]
except:
pass
if layeramount != 0:
layer_max_height_factor_list = []
layer_max_height_list = []
for layer in range(0,layeramount):
try:
factor = entry["layers"][layer]["size"]
layer_max_height_factor_list.append(factor)
layer_max_height_list.append(int((glob_height-glob_height*head_height)*factor))
except:
factor = 1/float(layeramount)
layer_max_height_factor_list.append(factor)
layer_max_height_list.append(int((glob_height-glob_height*head_height)*factor))
if glob_multipic == False:
max_fileamount = list_check(file_list)
else:
max_fileamount = multipic_list_check(file_list)
print(" -- " + str(layeramount) + " layers for slide found.")
text_count = 0 #outside of for x in range, because needs to be stored over slides away. Stays 0, text always the same
pic_count = 0 #outside of for x in range, because needs to be stored over slides away.
for x in range(0,max_fileamount):
slidex = presentation.slides.add_slide(presentation.slide_layouts[layout_number])
placeholders = slidex.placeholders
glob_slide_counter = glob_slide_counter + 1
print(" ++ Adding slide no. " + str(glob_slide_counter))
try:
note_text_list = entry["notes"]
notes_slide = slidex.notes_slide
text_note = notes_slide.notes_text_frame
for x in range(0,len(note_text_list)):
p = text_note.paragraphs[x]
run = p.add_run()
run.text = note_text_list[x]
p = text_note.add_paragraph()
except:
pass
try:
title_text = entry["title"]
for ph in placeholders:
if "Title" in ph.name:
tf = ph.text_frame
tf.vertical_anchor = MSO_ANCHOR.MIDDLE
p = tf.paragraphs[0]
run = p.add_run()
run.text = title_text
except:
pass
control = False
try:
texts_lists = entry["texts"]
control = True
except:
pass
if control == True:
text_lists = entry["texts"]
ph_counter = 0
for ph in placeholders:
if "Text Placeholder" in ph.name:
try:
add_text(ph, text_lists[ph_counter], 0) #number must be given because of class
format_shape(ph, text_lists[ph_counter])
except:
pass
finally:
ph_counter = ph_counter + 1
file_count = 0
if layeramount != 0:
factor_layer = 0
for layer in range(0,layeramount):
factor_part = 0
partsamount = glob_structure[layer+1] #layer amount at 0, part amounts in glob_structure start at position 1
for y in range(0,partsamount):
if glob_multipic == False:
parts = entry["layers"][layer]["parts"]
try:
frame_value = get_value("frame", parts[y])
frame = frame_value * glob_width
except:
frame = 0
try:
size_part = parts[y]["size"]
except:
size_part = 1/float(partsamount)
left = factor_part*glob_width + frame
top = glob_height*head_height + factor_layer*(glob_height-glob_height*head_height) + frame #headline protection + 0 probably + frame distance
width = glob_width*size_part - (2*frame)
if width < 0:
width = glob_width*size_part
print(" >> width became negative. Deactivated (some) frames")
height = layer_max_height_list[layer] - (2*frame)
if height < 0:
height = glob_width*size_part
print(" >> height became negative. Deactivated (some) frames")
# print("left: " + str(left)); print("top: " + str(top)); print("width: " + str(width)); print("height: " + str(height)); print("(frame*2: " + str(frame*2) + ")"); print(" ")
if parts[y]["type"] == "picture":
try:
img_path = file_list[file_count][pic_count][0] + file_list[file_count][pic_count][1]
pic = slidex.shapes.add_picture(img_path, left, top, width = width)
necessary_height = int(layer_max_height_list[layer] -(frame*2))
if pic.height > necessary_height:
pic.width = adjust_picheight(pic, necessary_height)
pic.height = necessary_height
if pic.width < (glob_width*size_part - (2*frame)):
half_space_width = (glob_width*size_part - (2*frame))/2
half_pic_width = pic.width/2
pic.left = int((half_space_width - half_pic_width) + factor_part*glob_width)
except:
print(" >> Failed to place the picture!")
if parts[y]["type"] == "textbox":
tx_box = slidex.shapes.add_textbox(left, top, width, height)
format_shape(tx_box, parts[y])
add_text(tx_box, parts[y], pic_count)
file_count = file_count + 1
factor_part = factor_part + size_part
else: # if multipic is enabled:
try:
frame_value = entry["multipic_frame"]
frame = frame_value * glob_width
except:
frame = 0
size_part = 1/float(partsamount)
left = factor_part*glob_width + frame
top = glob_height*head_height + factor_layer*(glob_height-glob_height*head_height) + frame #headline protection + 0 probably + frame distance
width = glob_width*size_part - (2*frame)
if width < 0:
width = glob_width*size_part
print(" >> width became negative. Deactivated (some) frames")
height = layer_max_height_list[layer] - (2*frame)
if height < 0:
height = glob_width*size_part
print(" >> height became negative. Deactivated (some) frames")
try:
img_path = file_list[file_count][pic_count][0] + file_list[file_count][pic_count][1]
pic = slidex.shapes.add_picture(img_path, left, top, width = width)
necessary_height = int(layer_max_height_list[layer] -(frame*2))
if pic.height > necessary_height:
pic.width = adjust_picheight(pic, necessary_height)
pic.height = necessary_height
if pic.width < (glob_width*size_part - (2*frame)):
half_space_width = (glob_width*size_part - (2*frame))/2
half_pic_width = pic.width/2
pic.left = int((half_space_width - half_pic_width) + factor_part*glob_width)
except:
print(" >> Failed to place the picture!")
pic_count = pic_count + 1
factor_part = factor_part + size_part
factor_layer = factor_layer + layer_max_height_factor_list[layer]
if glob_multipic == False:
pic_count = pic_count + 1
else:
pass
def argparsefunc():
parser = argparse.ArgumentParser()
parser.add_argument("jfile", type=str, help="Give the JSON file name.")
parser.add_argument("--pptx", type=str, help="Give a pptx file template (check for layout names).")
parser.add_argument("--output", type=str, help="Give a file output name.")
parser.add_argument("--flist", type=str, help="list of file paths")
try:
args = parser.parse_args()
return(args)
except SystemError:
parser.print_help()
exit()
def main():
global glob_dictionary; global glob_width; global glob_height; global glob_structure; global glob_files; global glob_pictures
args = argparsefunc()
try:
output = args.output + ".pptx"
except:
output = args.pptxfile + "_generated.pptx"
starttime = datetime.datetime.now()
print(starttime.strftime("\n >> %Y-%m-%d %H:%M:%S\n"))
with open(args.jfile, 'r+') as json_data:
glob_dictionary = json.load(json_data)
### Core functions.
presentation = Presentation(args.pptx)
create_layoutdict(presentation)
layouts = presentation.slide_layouts
glob_width = presentation.slide_width
glob_height = presentation.slide_height
entrycount = 0
for entry in glob_dictionary["slides"]:
get_files(entry, entrycount, args)
write_slides(presentation, entry, entrycount)
glob_structure = []
glob_files = []
glob_pictures = []
entrycount = entrycount + 1
presentation.save(output)
#####
endtime = datetime.datetime.now()
print(endtime.strftime("\n >> %Y-%m-%d %H:%M:%S\n"))
print(" -- FINISHED --")
print(" (" + output + ")")
if __name__ == "__main__":
from pptx.enum.text import MSO_ANCHOR
from pptx.enum.text import PP_ALIGN
from pptx.dml.color import RGBColor
from pptx import Presentation
from pptx.util import Inches
from pptx.util import Pt
import datetime
import argparse
import numbers
import struct
import json
import re
import os
main()