Avoid adding an image when it does not exist - python, spreadsheet - python

I wonder how can I omit adding the .png image when it doesn't exist in the folder. Just to leave the space in spreadsheet empty. The simplest way to do it?
logo = Image("./logo.png")
element = Image("./element.png")
ws.merge_cells('A1:E3')
logo.width = 500
logo.height = 120
element.width = 140
element.height = 140
element.alignment = Alignment(horizontal="left", vertical="center")
ws.add_image(logo, 'A1')
ws.add_image(element, 'E1')
Thanks for help.

The solution is:
Create the new file using PIL and save it, then open as openpyxl's image to avoid error AttributeError: fp
Code:
from openpyxl.drawing.image import Image as XLImage
from PIL import Image as PILImage
ws.merge_cells('A1:E3')
try:
logo = XLImage("./Bosch_logo.png")
except FileNotFoundError:
logo_pil = PILImage.new("RGB", (500, 120), (255, 255, 255))
logo_pil.save("Bosch_logo_pil.png")
logo = XLImage("Bosch_logo_pil.png")
else:
logo.width = 500
logo.height = 120
try:
element = XLImage("./element.png")
except FileNotFoundError:
element_pil = PILImage.new("RGB", (140, 140), (255, 255, 255))
element_pil.save("element_pil.png")
element = XLImage("element_pil.png")
else:
element.width = 140
element.height = 140
element.alignment = Alignment(horizontal="left", vertical="center")
ws.add_image(logo, 'A1')
ws.add_image(element, 'E1')

Related

convert Image to PDF in Python

I want to convert image to pdf in python.
this is my code:
import docx
from docx.shared import Inches, Mm
import os
from PIL import Image
from PIL import Image, ImageDraw, ImageFont
from docx2pdf import convert
from wand.image import Image as Im
image_dir = os.listdir(os.getcwd()+'\\Images')
print(len(image_dir))
doc = docx.Document()
section = doc.sections[0]
section.page_height = Mm(1000)
section.page_width = Mm(580)
section.left_margin = Mm(25.4)
section.right_margin = Mm(25.4)
section.top_margin = Mm(25.4)
section.bottom_margin = Mm(25.4)
section.header_distance = Mm(12.7)
section.footer_distance = Mm(12.7)
p = doc.add_paragraph()
x = 0
for i in range(0, len(image_dir)):
size = (130, 160)
temp_img = Image.open(os.getcwd()+'\\Images\\'+image_dir[i])
temp_img = temp_img.resize(size)
# temp_img.thumbnail(size, Image.ANTIALIAS)
# temp_img.show()
background = Image.new('RGBA', (500, 220), (255, 255, 255, 0))
for k in range(0, 3):
background.paste(temp_img, (0,0))
background.paste(temp_img, (150,0))
background.paste(temp_img, (300,0))
font = ImageFont.truetype(r'arial.ttf', 25)
d1 = ImageDraw.Draw(background)
d1.text((5, 160), image_dir[i][:-4], fill =(0, 0, 0), font = font)
background.save("temp.png")
with Im(filename ="temp.png") as img:
# generating sharp image using sharpen() function.
img.sharpen(radius = 16, sigma = 8)
img.save(filename ="temp1.png")
r = p.add_run()
r.add_picture("temp1.png")
doc.save('demo1.docx')
convert("demo1.docx")
This code run well. But IMG quality of pdf is poor and process is very slowly.
I want to improve convert speed.
Somebody help me. Thank you.
I think PIL is enough for you to combine an image with text into a PDF.
for example, you can save the combined images with text like this
import os
from PIL import Image, ImageDraw, ImageFont
image_dir = os.listdir(os.getcwd()+'\\Images')
for i in range(0, len(image_dir)):
size = (130, 160)
temp_img = Image.open(os.getcwd()+'\\Images\\'+image_dir[i])
temp_img = temp_img.resize(size)
background = Image.new('RGB', (500, 220), (255, 255, 255))
for k in range(0, 3):
background.paste(temp_img, (0,0))
background.paste(temp_img, (150,0))
background.paste(temp_img, (300,0))
font = ImageFont.truetype('arial.ttf', 25)
d1 = ImageDraw.Draw(background)
d1.text((5, 160), image_dir[i][:-4], fill =(0, 0, 0), font = font)
background.save(f"{image_dir[i][:-4]}.pdf")
This is my try. Just give the directory path and its done; you end up with a subdirectory containing all the PDF files
from pathlib import *
from PIL import Image
# path input #
path = input("Enter The path of you Images directory: \n")
path = Path(f"{path}")
####################################################
# making a subdirectory to contain the PDF version #
(path/"PDF's").mkdir(exist_ok=True)
# iterating over every file in the given directory #
# we use try function to ignore non image files #
for pp in path.glob("*"):
try:
with Image.open(pp) as image:
im = image.convert("RGB")
pth = Path(f"{path}\PDF's\{pp.stem}.pdf")
im.save(pth, save_all=True)
except:
pass
print("Conversion Completed ...")
# if you want to merge PDF's uncomment the next segment
#import PyPDF2
# merger = PyPDF2.PdfFileMerger()
# path = Path(f"{path}\PDF's")
# # (path/"MergedPDF's").touch()
# if (path/"MergedPDF's.pdf").exists():
# (path/"MergedPDF's.pdf").unlink()
# for pdf in path.glob("*.pdf"):
# merger.append(PyPDF2.PdfReader(pdf, "rb"))
# output = open(path/"MergedPDF's.pdf", "wb")
# merger.write(output)
# merger.close()
Pillow solution is pretty good in my opinion. But if u need more control over your pdf I suggest u to use PyMuPDF. Best library for pdf manipulation, hands down.
# copy image files to PDF pages
# each page will have image dimensions
import fitz
doc = fitz.open() # new PDF
imglist = [ ... image file names ...] # e.g. a directory listing
for img in imglist:
imgdoc=fitz.open(img) # open image as a document
pdfbytes=imgdoc.convert_to_pdf() # make a 1-page PDF of it
imgpdf=fitz.open("pdf", pdfbytes)
doc.insert_pdf(imgpdf) # insert the image PDF
doc.save("allmyimages.pdf")
Is pretty handy if u want to add metadata:
import fitz
doc = fitz.open()
metadata = {'producer': 'YourName', 'format': 'PDF 1.4', 'encryption': None, 'author': 'YourName',
'modDate': 'none', 'keywords': 'none', 'title': 'YourPdf', 'creationDate': 'none',
'creator': 'none', 'subject': 'none'} # your metadata needs to be a dictionary
doc.set_metadata(metadata)
table of contents:
import fitz
doc = fitz.open()
# the toc is a basically a list of lists. Each list has 3 elements:
# - first: the layer of the toc link (basically the main category (1), subcategory (2) etc..)
# - second: title of the layer
# - third: page where the title is linked
table_of_content = [[1, 'The PyMuPDF Documentation', 1], [2, 'Introduction', 1], [3, 'Note on the Name fitz', 1], [3, 'License', 1]]
doc.set_toc(table_of_content)
etc... I think that giving a look at the documentation is pretty useful

Get images from folder(s), merging two images and then output variant image(s) into new folder w/ unique file names

So I have two folders, one containing shirts with different colors and the other with logos.
I'm trying to take the images contained in the shirts folder and storing them into an array. I kinda figured how to "store" them using the tkinter module. But kinda confused. I would like to be able to do the same with the logos. Once stored in the array, I want to fetch the images and merge them into every possible image combination for each shirt/logo color OR better yet, specify which colors should have which logos depending on color.
Within the merging process, I want it to resize the shirt image and logo image to a standard size and place the logo image in a specific spot on the shirt image.
Once all that's done, I want to export the new images into a folder with unique names (thinking of a loop that adds shirt_n.jpg, n = 1,2,3 etc.)
I tried looking it all up and I do find pieces of what I want but I can't figure out how to put it together to work.
EDIT: I kinda figured out HOW to get the outcome I want but as you can see below the code below is very simple and not optimized. Which I have no idea how to optimize to compress it into less lines of code.
# python imports
import os
from tkinter import Tk
from tkinter.filedialog import askopenfilename
from PIL import Image
Tk().withdraw()
imFile = askopenfilename()
print("What shade is the shirt? Dark or Light?")
respShade = input()
print("What's the logo location? Right or Left?:")
respLocation = input()
print("Color abriv. name?")
respName = input()
shirt = Image.open(imFile)
shirt_01 = shirt.resize((1200, 1800))
shirt_02 = shirt.resize((1200, 1800))
shirt_03 = shirt.resize((1200, 1800))
# For Dark Apparel
if "ark" in respShade:
logo_hfwl = Image.open("images/logos/randazzo/hfox-wht.png")
logo_hfwl = logo_hfwl.resize((150, 80))
logo_hrtw = Image.open("images/logos/randazzo/htld-wht.png")
logo_hrtw = logo_hrtw.resize((150, 80))
logo3_rzwl = Image.open("images/logos/randazzo/rand-wht.png")
logo3_rzwl = logo3_rzwl.resize((150, 80))
if "lef" in respLocation:
shirt_01.paste(logo_hfwl, (660, 660), logo_hfwl)
shirt_02.paste(logo_hrtw, (660, 660), logo_hrtw)
shirt_03.paste(logo3_rzwl, (660, 660), logo3_rzwl)
elif "rig" in respLocation:
shirt_01.paste(logo_hfwl, (410, 660), logo_hfwl)
shirt_02.paste(logo_hrtw, (410, 660), logo_hrtw)
shirt_03.paste(logo3_rzwl, (410, 660), logo3_rzwl)
shirt_01.save('images/final/' + respName + '-hfwl.jpg')
shirt_02.save('images/final/' + respName + '-hrtw.jpg')
shirt_03.save('images/final/' + respName + '-rwl.jpg')
# For Light Apparel
if "ght" in respShade:
logo_hfwl = Image.open("images/logos/randazzo/hfox.png")
logo_hfwl = logo_hfwl.resize((150, 80))
logo_hrtw = Image.open("images/logos/randazzo/htld.png")
logo_hrtw = logo_hrtw.resize((150, 80))
logo3_rzwl = Image.open("images/logos/randazzo/rand.png")
logo3_rzwl = logo3_rzwl.resize((150, 80))
if "lef" in respLocation:
shirt_01.paste(logo_hfwl, (660, 660), logo_hfwl)
shirt_02.paste(logo_hrtw, (660, 660), logo_hrtw)
shirt_03.paste(logo3_rzwl, (660, 660), logo3_rzwl)
elif "rig" in respLocation:
shirt_01.paste(logo_hfwl, (410, 660), logo_hfwl)
shirt_02.paste(logo_hrtw, (410, 660), logo_hrtw)
shirt_03.paste(logo3_rzwl, (410, 660), logo3_rzwl)
shirt_01.save('images/final/' + respName + '-hfwl.jpg')
shirt_02.save('images/final/' + respName + '-hrtw.jpg')
shirt_03.save('images/final/' + respName + '-rwl.jpg')
# shirt.save('images/final/change_me.jpg')
path = "images/final/"
path = os.path.realpath(path)
os.startfile(path)
Also, I tried looking up how to save them into a folder with unique names. Couldn't really find anything really straight forward. If you could explain the thought process behind your solution, that would help me understand! Thank you so much!
First of all I suggest to organize the images as follows:
├── logos // all logos
├── shirts
│ ├── light // light colored shirts
│ └── dark // dark colored shirts
├── final
│ ├── right // all shirts with each logo on the right
│ └── left // all shirts with each logo on the left
Then we need to define a function to read all images in a directory, without the need to get user input. That is why I think we don't need tkinter at all
def getImages(searchDir):
"""
Returns a list with the paths of all images found in the given path
"""
imagesPaths = []
for root, directories, files in walk(searchDir):
for file in files:
if '.jpg' in file or '.png' in file:
imagesPaths.append(path.join(root, file))
print("Found images in '{}' = {}".format(searchDir, len(imagesPaths)))
return imagesPaths
Now the most important function is the one which merges the logo in ".png" format over a shirt in ".jpeg" format. This function has three parts:
Part 1: Open both images then resize both of them to the desired height and width.
Part 2: Paste the logo over the shirt (we need a trick to do that so we change the color format into RGBA)
Part3: Get the name of both files, then "glue" them together. You are free to name your images as you like, so feel free to change this step as much as you need.
This is the body of such a function:
def addLogo(shirtPath, logoPath, shift=(0,0), outPath="final"):
"""
Takes a background image and a foreground image add merge them.
The foreground image can be scaled and be rotated. It can also
be put at an aribttatry location (x,y).
"""
img1 = Image.open(shirtPath).convert('RGBA')
img2 = Image.open(logoPath).convert('RGBA')
img1 = img1.resize((1200, 1800))
img2 = img2.resize((150, 80))
# paste img2 on top of img1
shift1 = (0, 0)
shift2 = shift
blended = Image.new('RGBA', size=(1200, 1800), color=(0, 0, 0, 0))
blended.paste(img1, shift1)
blended.paste(img2, shift2, img2)
# Save the image with a name combinig both images names
name1 = getNameWithoutExtension(shirtPath)
name2 = getNameWithoutExtension(logoPath)
blended = blended.convert("RGB")
blended.save("{}/{}_{}.jpg".format(outPath, name2, name1))
This is a sample of the result I got inside the "final/left" folder. I had two shirts and three logos, so the result was six pictures.
Finally, this is the whole code
# python imports
from os import walk, path, rename, mkdir
from PIL import Image
# This is a generic function which gets all paths of images
def getImages(searchDir):
"""
Returns a list with the paths of all images found in the given path
"""
imagesPaths = []
for root, directories, files in walk(searchDir):
for file in files:
if '.jpg' in file or '.png' in file:
imagesPaths.append(path.join(root, file))
print("Found images in '{}' = {}".format(searchDir, len(imagesPaths)))
return imagesPaths
def getNameWithoutExtension(imagePath):
name = path.basename(imagePath)
return path.splitext(name)[0]
def addLogo(shirtPath, logoPath, shift=(0,0), outPath="final"):
"""
Takes a background image and a foreground image add merge them.
The foreground image can be scaled and be rotated. It can also
be put at an aribttatry location (x,y).
"""
img1 = Image.open(shirtPath).convert('RGBA')
img2 = Image.open(logoPath).convert('RGBA')
img1 = img1.resize((1200, 1800))
img2 = img2.resize((150, 80))
# paste img2 on top of img1
shift1 = (0, 0)
shift2 = shift
blended = Image.new('RGBA', size=(1200, 1800), color=(0, 0, 0, 0))
blended.paste(img1, shift1)
blended.paste(img2, shift2, img2)
# Save the image with a name combinig both images names
name1 = getNameWithoutExtension(shirtPath)
name2 = getNameWithoutExtension(logoPath)
blended = blended.convert("RGB")
blended.save("{}/{}_{}.jpg".format(outPath, name2, name1))
# Load all logo files
logos_array = getImages("logos")
# Load all light shirts
light_shirts_array = getImages("shirts/light")
#Load all dark shirts
dark_shirts_array = getImages("shirts/dark")
# Loop over light shirts and add each logo to each of them
for shirt in light_shirts_array:
for logo in logos_array:
# Paste on the left
addLogo(shirt, logo, (410, 660), "final/left")
# Paste on the right
addLogo(shirt, logo, (660, 660), "final/right")
You can search through the files in a directory by using the os.listdir() function. Try adding this to your code.
from tkinter import filedialog, Tk
import os
root = Tk()
root.withdraw()
path = filedialog.askdirectory(master=root)
imported_images = []
for file in os.listdir(path):
file_path = os.path.join(path, file)
imported_images.append(file_path)
# An easier, one-liner for doing this is by the use of list comprehension.
# imported_images = [os.path.join(path, file) for file in os.listdir(path)]
# imported_images is now a list of all the file paths in the specified directory.
I believe using the askdirectory function is an easier way than pasting it in.

NotADirectoryError: [Errno 20] Not a directory: 'known_faces/.DS_Store'

How can I fix the following error:
NotADirectoryError: [Errno 20] Not a directory:
'known_faces/.DS_Store'
Code
import face_recognition
import os
import cv2
import numpy as np
KNOWN_FACES = "known_faces"
UNKNOWN_FACES = "unknown_faces"
TOLERANCE = 0.6
THICKNESS = 3
MODEL = "cnn"
known_faces = []
known_names = []
for name in os.listdir(KNOWN_FACES):
for filename in os.listdir(f"{KNOWN_FACES}/{name}"):
image = face_recognition.load_image_file(f"{KNOWN_FACES}/{name}/{filename}")
encoding = face_recognition.face_encodings(image)
known_faces.append(encoding)
known_names.append(name)
print("processing unknown_faces")
for filename in os.listdir(UNKNOWN_FACES):
print(filename)
image = face_recognition.load_image_file(f"{UNKNOWN_FACES}/{filename}")
locations = face_recognition.face_locations(image, model=MODEL)
encodings = face_recognition.face_encodings(image, locations)
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
for face_encoding, face_locations in zip(encodings, locations):
results = face_recognition.compare_faces(face_encoding, known_faces, TOLERANCE)
MATCH = None
if True in results:
match = known_names[results.index(True)]
print(f"Match found: {match}")
top_left = (face_location[3], face_location[0])
bot_right = (face_location[1], face_location[2])
color = [0, 255, 0]
cv2.rectangle(image, top_left, bot_right, color, THICKNESS)
top_left = (face_location[3], face_location[0])
bot_right = (face_location[1], face_location[2] + 22)
cv2.rectangle(image, top_left, bot_right, color, cv2.FILLED)
cv2.putText(image, math, (face_location[3]+10, face_location[2])+15, cv2.FONT_HERSEY_SIMPLEX, 0.5, (200,200,200), THICKNESS)
cv2.imshow(filename, image)
cv2.waitKey(10000)
os.listdir(KNOWN_FACES) returns all the files in the KNOWN_FACES directory. In your specific case also the .DS_Store file.
You can filter the results considering only directories and excluding files such as .DS_Store.
import os
for name in os.listdir(KNOWN_FACES):
dir_path = os.path.join(KNOWN_FACES, name)
# if it's a directory
if os.path.isdir(dir_path):
for filename in os.listdir(dir_path):
# if the file is a valid file (a better way could be to check your specific extension, e.g., png)
if not filename.startswith('.'):
filepath = os.path.join(dir_path, filename)
image = face_recognition.load_image_file(filepath)
There is a file in your "known_faces" directory named .DS_Store. Since you only want to look at directories in the "known_faces" directory, you need to remove that file.
As abc has pointed out, you may just want to check that you are looking in a directory by using os.path.isdir().

Use custom scrapy imagePipeline to download images and overwrite existing images

I am practising using scrapy to crop image with a custom imagePipeline.
I am using this code:
class MyImagesPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
for image_url in item['image_urls']:
yield Request(image_url)
def convert_image(self, image, size=None):
if image.format == 'PNG' and image.mode == 'RGBA':
background = Image.new('RGBA', image.size, (255, 255, 255))
background.paste(image, image)
image = background.convert('RGB')
elif image.mode != 'RGB':
image = image.convert('RGB')
if size:
image = image.copy()
image.thumbnail(size, Image.ANTIALIAS)
else:
# cut water image TODO use defined image replace Not cut
x,y = image.size
if(y>120):
image = image.crop((0,0,x,y-25))
buf = StringIO()
try:
image.save(buf, 'JPEG')
except Exception, ex:
raise ImageException("Cannot process image. Error: %s" % ex)
return image, buf
It works well but have a problem.
If there are original images in the folder,
then run the spider,
the images it download won't replace the original one.
How can I get it to over-write the original images ?
There is an expiration setting, it is by default 90 days.

PIL - Convert GIF Frames to JPG

I tried to convert an gif to single images with Python Image Library,
but it results in weird frames
The Input gif is:
Source Image http://longcat.de/gif_example.gif
In my first try, i tried to convert the image with Image.new to an
RGB image, with 255,255,255 as white background - like in any other
example i've found on the internet:
def processImage( infile ):
try:
im = Image.open( infile )
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
try:
while 1:
background = Image.new("RGB", im.size, (255, 255, 255))
background.paste(im)
background.save('foo'+str(i)+'.jpg', 'JPEG', quality=80)
i += 1
im.seek( im.tell() + 1 )
except EOFError:
pass # end of sequence
but it results in weird output files:
Example #1 http://longcat.de/gif_example1.jpg
My second try was, to convert the gif in an RGBA first, and then use
its transparency mask, to make the transparent pieces white:
def processImage( infile ):
try:
im = Image.open( infile )
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
try:
while 1:
im2 = im.convert('RGBA')
im2.load()
background = Image.new("RGB", im2.size, (255, 255, 255))
background.paste(im2, mask = im2.split()[3] )
background.save('foo'+str(i)+'.jpg', 'JPEG', quality=80)
i += 1
im.seek( im.tell() + 1 )
except EOFError:
pass # end of sequence
which results in an output like this:
Example #2 http://longcat.de/gif_example2.jpg
The advantage over the first try was, that the first frame looks pretty good
But as you can see, the rest is broken
What should i try next?
Edit:
I think i came a lot closer to the solution
Example #3 http://longcat.de/gif_example3.png
I had to use the palette of the first image for the other images,
and merge it with the previous frame (for gif animations which use
diff-images)
def processImage( infile ):
try:
im = Image.open( infile )
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
size = im.size
lastframe = im.convert('RGBA')
mypalette = im.getpalette()
try:
while 1:
im2 = im.copy()
im2.putpalette( mypalette )
background = Image.new("RGB", size, (255,255,255))
background.paste( lastframe )
background.paste( im2 )
background.save('foo'+str(i)+'.png', 'PNG', quality=80)
lastframe = background
i += 1
im.seek( im.tell() + 1 )
except EOFError:
pass # end of sequence
But i actually dont know, why my transparency is black, instead of white
Even if i modify the palette (change the transparency channel to white)
or use the transparency mask, the background is still black
First of all, JPEG doesn't support transparency! But that's not the only problem.. As you move to the next frame of the GIF the palette information is lost (problem witn PIL?) - so PIL is unable to correctly convert to the RGBA framework (Hence the first frame is okish, but all the others are screwy). So the work-around is to add the palette back in for every frame, (which is what you were doing in your last code example, but your trouble was that you were saving as RGB not RGBA so you had no alpha/ transparency channel. Also you were doing a few unnecessary things..). Anyhow, here are the .png's with transparency and the corrected code, hope its of some use :)
import Image
import sys
def processImage(infile):
try:
im = Image.open(infile)
except IOError:
print "Cant load", infile
sys.exit(1)
i = 0
mypalette = im.getpalette()
try:
while 1:
im.putpalette(mypalette)
new_im = Image.new("RGBA", im.size)
new_im.paste(im)
new_im.save('foo'+str(i)+'.png')
i += 1
im.seek(im.tell() + 1)
except EOFError:
pass # end of sequence
processImage('gif_example.gif')
When viewing an image on an image viewer, even when transparency is set to zero, it tends to display the image as black. One way to be sure that your image is truly transparent is to merge it over another. The 'emoticon' should be seen whilst not obstructing the other image.Try:
background = Image.open('someimage.jpg') #an existing image
foreground = Image.open('foo.jpg') #one of the above images
background.paste(foreground, (0,0), foreground)
background.save('trial.jpg') #the composite image
Theoretically, if you open 'trial.jpg' in the image viewer and the content of the initial image is preserved and on top of it lies the foo image then you'll know for sure if it's just the image viewer and your images are fine...
source here
Image.open('image.gif').convert('RGB').save('image.jpg')
This works for me. The following example shows converting image.gif to 8 jpg format images with white background.
from PIL import Image
from PIL import GifImagePlugin
def gif2jpg(file_name: str, num_key_frames: int, trans_color: tuple):
"""
convert gif to `num_key_frames` images with jpg format
:param file_name: gif file name
:param num_key_frames: result images number
:param trans_color: set converted transparent color in jpg image
:return:
"""
with Image.open(file_name) as im:
for i in range(num_key_frames):
im.seek(im.n_frames // num_key_frames * i)
image = im.convert("RGBA")
datas = image.getdata()
newData = []
for item in datas:
if item[3] == 0: # if transparent
newData.append(trans_color) # set transparent color in jpg
else:
newData.append(tuple(item[:3]))
image = Image.new("RGB", im.size)
image.getdata()
image.putdata(newData)
image.save('{}.jpg'.format(i))
gif2jpg("image.gif", 8, (255, 255, 255)) # convert image.gif to 8 jpg images with white background

Categories