Python use pptx read image files in folder place in ppt slide - python

Need some help.
I'm writing the code to get file name from List and use those file name to look in folder for get the images place on PowerPoint slide. The purpose is I would like to add three image on same slide. So, every slide will have 3 images and so on...
Let say...
Slide1 : place image file name aaaa-1.jpg, aaaa-2.jpg, aaaa-3.jpg
Slide2 : Place image file name bbbb-1.jpg, bbbb-2.jpg, bbbb-3.jpg
... and so on until end of data in list
The file name that keep in list look like this ..list =['aaaa-1.jpg', 'aaaa-2.jpg', 'aaaa-3.jpg', 'bbb-1.jpg, bbbb-2.jpg', 'bbbb-3.jpg' ...]
I use function to send files name to pptx creating module but it doesn't work. After run this code, they build 3 images (with same file) in one slide!
Could you kindly please advise.
Thanks for all answers from your guy.
Here is my code
from pptx import Presentation
from pptx.util import Inches
import os
prs = Presentation()
prs.slide_height=Inches(9)
prs.slide_width=Inches(16)
def buildafm(f1,f2,f3): #pass f1, f2, f3 to function
blank_slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(blank_slide_layout)
os.chdir(r"C:\Python38-32\faprojects\folders\hzt")
left = top = Inches(1)
height = Inches(3.5)
width = Inches(3.5)
pic = slide.shapes.add_picture(f1, left, top, width=width, height=height)
left = Inches(5)
top = Inches(1)
height = Inches(3.5)
width = Inches(3.5)
pic = slide.shapes.add_picture(f2, left, top, width=width, height=height)
left = Inches(9)
top = Inches(1)
height = Inches(3.5)
width = Inches(5.5)
pic = slide.shapes.add_picture(f3, left, top, width=width, height=height)
os.chdir(r"C:\Python38-32\faprojects\folders\hzt")
a = os.listdir(os.getcwd())
# Image files name in folder HZT
#a=['aaaaaaaaaaa.001.jpg','aaaaaaaaaaaa.002.jpg','bbbbbbbbbb.001.jpg','bbbbbbbbbb.002.jpg','cccccccccc.001.jpg','cccccccccc.002.jpg']
newList = [string[:10] for string in a]
print("here is new list",newList)
no_dupes = [x for n, x in enumerate(newList) if x not in newList[:n]]
print("here is new list",no_dupes)
print("Number of heads",len(no_dupes))
hd=no_dupes[0:1]
str1=""
hd=str1.join(hd)
print(hd)
res = list(filter(lambda x: hd in x, a))
print("file is",res)
'''f1 = res[0:1]
f2 = res[1:2]
f3 = res[2:3]'''
for t in res:
print(t)
#showdata(t)
buildafm(t,t,t) #call function to create pptx
prs.save('testbat.pptx')
os.startfile("testbat.pptx")

Related

Setting width of heading image in docx

im trying to define 2 images as header and a image as footer, but cant seem to resize it correctly.
docpath="/Users/ricardosimoes/Desktop/DESKTOP/Jira/my_word_file.docx"
mydoc = docx.Document()
section_h = mydoc.sections[0]
header = section_h.header
styles = mydoc.styles
style = styles.add_style('Tahoma',WD_STYLE_TYPE.PARAGRAPH)
style.font.name = 'Tahoma'
style.font.size = Pt(11)
shd = OxmlElement('w:background')
# Add attributes to the xml element
shd.set(qn('w:color'), '#0000FF')
shd.set(qn('w:themeColor'), 'text1')
shd.set(qn('w:themeTint'), 'F2')
# Add background element at the start of Document.xml using below
mydoc.element.insert(0, shd)
# Add displayBackgroundShape element to setting.xml
shd1 = OxmlElement('w:displayBackgroundShape')
mydoc.settings.element.insert(0, shd1)
paragraph_h = header.paragraphs[0]
runheader = paragraph_h.add_run()
runheader.add_picture("client_report/report_img/titulo.png", width=docx.shared.Inches(5), height=docx.shared.Inches(1))
paragraph_h = header.paragraphs[0]
runheader = paragraph_h.add_run()
runheader.add_picture("client_report/report_img/titulo_logo.png", width=docx.shared.Inches(5), height=docx.shared.Inches(1))
mydoc.add_picture("client_report/report_img/bottom.png", width=docx.shared.Inches(5),
height=docx.shared.Inches(1))
mydoc.save(docpath)
I need to specify that the titulo.png and bottom.png fit width of the page and the titulo_logo.png set in front of the titulo.png on the bottom corner left of the image.
Can this be done?

Openpyxl - Error after convert an image to excel spreadsheet possible problem with styles.xml

I'm trying to use a python script to convert an image (*.jpg) to the background color of an Excel's spreadsheet. According to the following photo:
Full Python script:
import openpyxl
from PIL import Image
def image_to_excel(file, output, percentage):
# Open picture and create a workbook instance
im = Image.open(file)
wb = openpyxl.Workbook()
sheet = wb.active
# Resize image with spreadsheet's columns
width, height = im.size
cols = width * percentage/100
print('Old image size: ' + str(im.size))
imgScale = cols/width
newSize = (int(width*imgScale), int(height*imgScale))
im = im.resize(newSize)
# Get new picture's dimensions
cols, rows = im.size
print('New image size: ' + str(im.size))
# Spreadsheet's cell: height = 6 and width = 1
for i in range(1, rows):
sheet.row_dimensions[i].height = 0.6
for j in range(1, cols):
column_letter = openpyxl.utils.get_column_letter(j)
sheet.column_dimensions[column_letter].width = 0.0625
# Convert image to RGB
rgb_im = im.convert('RGB')
# Formatting cell's color
for i in range(1, rows):
for j in range(1, cols):
c = rgb_im.getpixel((j, i))
rgb2hex = lambda r,g,b: f"ff{r:02x}{g:02x}{b:02x}"
c = rgb2hex(*c)
sheet.cell(row = i, column = j).value = " "
customFill = openpyxl.styles.PatternFill(start_color=c, end_color=c, fill_type='solid')
sheet.cell(row = i, column = j).fill = customFill
# Save workbook
#im.close()
#rgb_im.close()
wb.save(output)
wb.close()
# Export
image_to_excel('jangada.jpg', 'final.xlsx', 100)
The problem is when I tried to change the images, like this one: https://www.planetware.com/wpimages/2019/09/croatia-in-pictures-most-beautiful-places-to-visit-plitvice-lakes.jpg and after run the code I got the error:
The translation is something like that:
Excel was able to open teh file by repairing or removing the unreadable content.
Removed Records: Style from /xl/styles.xml part (Styles)
Repaired Records: Informations about the cell part of /xl/worksheets/sheet1.xml
I'm using excel 2013. Anyone knows how to solve it ?
Your rgb2hex isn't working as you intended, remove the ff from it, I think that's whats breaking your code.
Your func:
>>>rgb2hex = lambda r,g,b: f"ff{r:02x}{g:02x}{b:02x}"
>>>rgb2hex(120,120,120)
ff787878
The output should be 787878.
>>>rgb2hex = lambda r,g,b: f"{r:02x}{g:02x}{b:02x}"
>>>rgb2hex(120,120,120)
787878

Set Author, Title, and Subject for PDF using Reportlab

How can you correctly set the Author, Title and Subject attributes for a PDF File using Reportlab?
I have found the methods in the Reportlab User Guide on page 56, but I am not sure how to implement them correctly.
Below in my PDF cropping and scaling script, I have added the annotations method, but I don't know where to call them from, or if a whole new Canvas object is needed. Please excuse the lengthy code, but only after line 113 is the doc being created, above are mostly auxiliary methods, including the annotations method on line 30.
# All the necessary parameters are accessible after line 92,
# but can of course be changed manually in the Code
# imports for the crop, rename to avoid conflict with reportlab Image import
from PIL import Image as imgPIL
from PIL import ImageChops, ImageOps, ImageFilter
import os.path, sys
# import for the PDF creation
import glob
from reportlab.lib.pagesizes import A4
from reportlab.lib import utils
from reportlab.platypus import Image, SimpleDocTemplate, Spacer
from reportlab.pdfgen import canvas
# get os path for Cropping
path = (os.path.dirname(os.path.abspath("cropPDF.py")))
dirs = os.listdir(path)
def trim(im, border="white"):
bg = imgPIL.new(im.mode, im.size, border)
diff = ImageChops.difference(im, bg)
bbox = diff.getbbox()
if bbox:
return im.crop(bbox)
def annotations(canvas):
canvas.setAuthor("the ReportLab Team")
canvas.setTitle("ReportLab PDF Generation User Guide")
canvas.setSubject("How to Generate PDF files using the ReportLab modules")
def findMaxWidth():
maxWidth = 0
for item in dirs:
try:
fullpath = os.path.join(path, item)
if os.path.isfile(fullpath):
im = imgPIL.open(fullpath)
maxWidth = max(maxWidth, im.size[0])
except:
pass
return maxWidth
def padImages(docHeight):
maxWidth = findMaxWidth()
for item in dirs:
try:
fullpath = os.path.join(path, item)
if os.path.isfile(fullpath):
im = imgPIL.open(fullpath)
f, e = os.path.splitext(fullpath)
width, height = im.size # get the image dimensions, the height is needed for the blank image
if not docHeight <= height: # to prevent oversized images from bein padded, such that they remain centered
image = imgPIL.new('RGB', (maxWidth, height),
(255, 255, 255)) # create a white image with the max width
image.paste(im, (0, 0)) # paste the original image overtop the blank one, flush on the left side
image.save(f + ".png", "PNG", quality=100)
except:
pass
def crop():
for item in dirs:
try:
fullpath = os.path.join(path, item)
if os.path.isfile(fullpath):
im = imgPIL.open(fullpath)
f, e = os.path.splitext(fullpath)
imCrop = trim(im, "white")
imCrop.save(f + ".png", "PNG", quality=100)
except:
pass
def add_page_number(canvas, doc):
canvas.saveState()
canvas.setFont('Times-Roman', numberFontSize)
page_number_text = "%d" % (doc.page)
canvas.drawCentredString(
pageNumberSpacing * mm,
pageNumberSpacing * mm,
page_number_text
)
canvas.restoreState()
#############################
executeCrop = True
executePad = True
outputName = "output.pdf" #The name of the file that will be created
fileAuthor = "Roman Stadler" #these 3 attributes are visible in the file info menu
fileTitle = ""
fileSubject = ""
margin = 0.5
imageWidthDefault = 550
spacerHeight = 7
scalingIfImageTooTall = 0.95 # larger than 95 can result in an empty page after the image
includePagenumbers = True
numberFontSize = 10
pageNumberSpacing = 5
############################
doc = SimpleDocTemplate(
outputName,
topMargin=margin * mm,
leftMargin=margin * mm,
rightMargin=margin * mm,
bottomMargin=margin * mm,
pagesize=A4
)
if executeCrop:
crop()
if executePad:
padImages(doc.height)
filelist = glob.glob("*.png") # Get a list of files in the current directory
filelist.sort()
story = [] # create the list of images for the PDF
for fn in filelist:
img = utils.ImageReader(fn)
img_width, img_height = img.getSize() # necessary for the aspect ratio
aspect = img_height / float(img_width)
documentHeight = doc.height
imageWidth = imageWidthDefault
imageHeight = imageWidth * aspect
if imageHeight > documentHeight:
imageHeight = documentHeight * scalingIfImageTooTall
imageWidth = imageHeight / aspect
img = Image(
fn,
width=imageWidth,
height=imageHeight
)
story.append(img)
space = Spacer(width=0, height=spacerHeight)
story.append(space)
if includePagenumbers and not len(filelist) == 0: # if pagenumbers are desired, or not
doc.build(
story,
onFirstPage=add_page_number,
onLaterPages=add_page_number,
)
elif not len(filelist) == 0:
doc.build(story)
else: # to prevent an empty PDF that can't be opened
print("no files found")
In the meantime, I have found another way, that does not use reportlab, but instead relies on PyPDF2:
The following import is needed:
# PyPDF2 for the metadata modification
from PyPDF2 import PdfFileReader, PdfFileWriter
Then the metadata can be edited like this:
author = "Roman Stadler"
title = "CropPDF"
subject = "Stackoverflow"
#rest of the script
#attemp the metadate edit
try:
file = open('output.pdf', 'rb+')
reader = PdfFileReader(file)
writer = PdfFileWriter()
writer.appendPagesFromReader(reader)
metadata = reader.getDocumentInfo()
writer.addMetadata(metadata)
writer.addMetadata({
'/Author': author,
'/Title': title,
'/Subject' : subject,
'/Producer' : "CropPDF",
'/Creator' : "CropPDF",
})
writer.write(file)
file.close()
except:
print("Error while editing metadata")
You can define attributes like the author when defining the doc as a SimpleDocTemplate
doc = SimpleDocTemplate(
outputName,
topMargin=margin * mm,
leftMargin=margin * mm,
rightMargin=margin * mm,
bottomMargin=margin * mm,
pagesize=A4,
title="This is the title of the document", #exchange with your title
author="John Smith", #exchange with your authors name
subject"Adding metadata to pdf via reportlab" #exchange with your subject
)

Merging and saving images in PIL Python

I have two folders of images and I am trying to build one large image from all the slices in each folder. I need to alternate between folders to build the image. For example the first slice comes from folder 1, the second slice comes from folder 2, the third from folder 1 ect. I have the files ordered by filename in the individual folders so I am trying to iterate through the folders and add a new strip to an image. The code runs BUT it doesn't seem to be saving the composite image. I am new to PIL, so I am sure that it is something simple, but your help is appreciated. Thanks!
def merge_images(file1, file2):
"""Merge two images into one, displayed above and below
:param file1: path to first image file
:param file2: path to second image file
:return: the merged Image object
"""
if file1.startswith('.'):
return None
image1 = Image.open(file1)
image2 = Image.open(file2)
(width1, height1) = image1.size
(width2, height2) = image2.size
result_width = width1 + width2
result_height = max(height1, height2)
result = Image.new('RGB', (result_width, result_height))
result.paste(im=image1, box=(0, 0))
result.paste(im=image2, box=(0, height1))
return result
imageCounter = 0
firstPass = True
compImage = Image.new('RGBA', img.size, (0,0,0,0))
for i in range(len(boundingBoxes)+1):
if firstPass:
compImage = merge_images('./image_processing/'+ os.listdir('./image_processing/')[imageCounter],
'./img_patches/outputs/'+os.listdir('./img_patches/outputs/')[imageCounter])
if compImage is not None:
firstPass = False
compImage.save('./image_processing/compImage.jpg')
else:
compImage = merge_images('./image_processing/compImage.jpg','./image_processing/'+ os.listdir('./image_processing/')[imageCounter])
compImage.save('./image_processing/compImage.jpg')
compImage = merge_images('./image_processing/compImage.jpg','./img_patches/outputs/'+ os.listdir('./img_patches/outputs/')[imageCounter])
compImage.save('./image_processing/compImage.jpg')
imageCounter = imageCounter + 1
You have to tell PIL to save the images:
for i in range(len(boundingBoxes)+1):
if firstPass:
compImage = merge_images('./image_processing/'+ os.listdir('./image_processing/')[imageCounter],
'./img_patches/outputs/'+os.listdir('./img_patches/outputs/')[imageCounter])
compImage.save(open('output/{}.png'.format(imageCounter), 'w'))

Python 3.5.1 - Assign variables to all Files (Filetype: .jpg) inside target folder

I am fairly new to Python and have a difficult Problem to solve:
Here is what I am trying to do -->
I have a Folder (path known) with 1 - x picture files (.jpg) in it, whereas x can be as high as 1000
These picture files should be stiched together (one on top of the other)
To do so I want Python to assign a variable to each Picture file in the known folder and then create a loop which stiches these variable-stored pictures together and outputs it as 1 picture (.jpg)
Here is what I have coded so far:
from PIL import Image
import glob
#The following GLOB part doesn't work, I tried to make a List with all the
#files (.jpg) inside the main directory
#image_list = []
#for filename in glob.glob('*.jpg'):
# test = Image.open(filename)
# image_list.append(test)
img1 = Image.open("img1.jpg")
img2 = Image.open("img2.jpg")
def merge_images(img1, img2):
(width1, height1) = img1.size
(width2, height2) = img2.size
result_width = max(width1, width2)
result_height = height1 + height2
result = Image.new('RGB', (result_width, result_height))
result.paste(im=img2, box=(0,0))
result.paste(im=img1, box=(0,height1-2890))
return result
merged = merge_images(img1, img2)
merged.save("test.jpg")
What this does is to assign img1.jpg and img2.jpg to a variable and then stack them on top of oneanother and save this stacked picture as "test.jpg". Where do I go from here if I want to assign many pictures (.jpg) to variables and stack them on top of each other without typing a line of code for each new picture (see description further up?)
Thanks a lot for your help!
Chris
If you start with a 0x0 image, you can stack further images onto it like this:
stacked_img = Image.new('RGB', (0, 0))
for filename in glob.glob('*.jpg'):
stacked_img = merge_images(stacked_img, Image.open(filename))
stacked_img.save('stacked.jpg')
You might also like to change the height1-2890 to height2 in the merge_images() function if you are trying to stack the second image below the first image, i.e.
result.paste(im=img1, box=(0,height2))
Why not use a container such as a list?
images = [Image.open(img_name) for img_name in os.listdir(my_folder) if img_name.endswith('.jpg')
def merge_images(list_images):
result_width = max(img.size[0] for img in images)
result_height = sum(img.size[1] for img in images)
result = Image.new('RGB', (result_width, result_height))
for idx, img in enumerate(list_images):
result.paste(im=img, box=(0,list_images[0].size[1]-idx*2890))
See Data Structures for more information.
If performance is important, consider using map instead of a loop.
this is my code in which I implemented your approach. As a result, I am getting an image where 2 of the 4 images are displayed and the rest of the image is black. In the source directory I have 4 images (img1.jpg - img4.jpg)
from PIL import Image
import glob
stacked_img = Image.new('RGB', (0,0))
def merge_images(img1, img2):
(width1, height1) = img1.size
(width2, height2) = img2.size
result_width = max(width1, width2)
result_height = height1 + height2
result = Image.new('RGB', (result_width, result_height))
result.paste(im=img2, box=(0,0))
result.paste(im=img1, box=(0,height1))
return result
for filename in glob.glob('*.jpg'):
stacked_img = merge_images(stacked_img, Image.open(filename))
stacked_img.save('stacked.jpg')

Categories

Resources