Image not displayed in excell cell (python and openpyxl) - python

i am tring to create a script using python and openpyxl`s function called add_image which will add resized photos into cells, for this i am using the
following code:
from PIL import Image
from openpyxl import load_workbook
from openpyxl import Workbook
wb = load_workbook('file.xlsx')
ws = wb.active
max_row = ws.max_row
########## SET DIMENSIONS FOR 'F' cells#######
ws.column_dimensions['F'].width=200
for x in range (2,max_row+1):
ws.row_dimensions[x].height=200
##############################################
img = Image.open(file)
bound_width_height = (195, 150)
img.thumbnail(bound_width_height, Image.ANTIALIAS)
nimg = openpyxl.drawing.image.Image(img)
ws.add_image(nimg,'F3')
wb.save('test.xlsx')
print('done!')
but when i am watching into test.xlsx file i see This image cannot curently be displayed.
Result:
https://imgur.com/a/mjgL4hn
Any ideeas why?

Related

Using `wb.save` results in "UnboundLocalError: local variable 'rel' referenced before assignment"

I am trying to learn how to place an image in an Excel worksheet but I am having a problem with wb.save. My program ends with the following error:
"C:\Users\Don\PycharmProjects\Test 2\venv\Scripts\python.exe" "C:/Users/Don/PycharmProjects/Test 2/Test 2.py"
Traceback (most recent call last):
File "C:/Users/Don/PycharmProjects/Test 2/Test 2.py", line 20, in <module>
wb.save('POKENO Cards new.xlsx')
File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\workbook\workbook.py", line 392, in save
save_workbook(self, filename)
File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 293, in save_workbook
writer.save()
File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 275, in save
self.write_data()
File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 75, in write_data
self._write_worksheets()
File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 218, in _write_worksheets
self._write_drawing(ws._drawing)
File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\writer\excel.py", line 141, in _write_drawing
self._archive.writestr(drawing.path[1:], tostring(drawing._write()))
File "C:\Users\Don\PycharmProjects\Test 2\venv\lib\site-packages\openpyxl\drawing\spreadsheet_drawing.py", line 295, in _write
self._rels.append(rel)
UnboundLocalError: local variable 'rel' referenced before assignment
Process finished with exit code 1
This is my code. It works until the last statement.
import openpyxl as xl
from PIL import Image
#im = Image.open(r"Playing Cards/2C.jpg")
im = Image.open(r"C:/Users/Don/Pictures/resized Nyle.jpg")
wb = xl.load_workbook(filename="C:/Users/Don/PycharmProjects/Test 2/POKENO Cards.xlsx")
ws1 = wb.worksheets[0]
im.show()
img = im.resize((78, 100))
img.show()
wb2 = xl.load_workbook(filename="C:/Users/Don/PycharmProjects/Test 2/POKENO Cards new.xlsx")
ws2 = wb2.active
ws2.add_image(im, 'A4')
wb2.save(filename="C:/Users/Don/PycharmProjects/Test 2/POKENO Cards new.xlsx")
The error is a bit cryptic, but the Traceback is quite clear enough to trace the cause of the problem: that openpyxl's add_image method expects a openpyxl.drawing.image.Image object, and not a PIL Image.
If you check the lines in openpyxl / drawing / spreadsheet_drawing.py that raised the error, there's a check there for the image type:
for idx, obj in enumerate(self.charts + self.images, 1):
anchor = _check_anchor(obj)
if isinstance(obj, ChartBase):
rel = Relationship(type="chart", Target=obj.path)
...
elif isinstance(obj, Image):
rel = Relationship(type="image", Target=obj.path)
...
anchors.append(anchor)
self._rels.append(rel)
The problem is that your code
im = Image.open(r"C:/Users/Don/Pictures/resized Nyle.jpg")
...
ws2.add_image(im, 'A4')
passed in a 'PIL.PngImagePlugin.PngImageFile' type. It is not a ChartBase type or openpyxl's own Image type. So rel will never be initialized leading to the error that rel was used before being assigned something, leading to "local variable 'rel' referenced before assignment...".
If you check openpyxl / drawing / image, you might notice that openpyxl's Image is just a wrapper for PIL's Image. It needs a PIL.Image.Image object and internally calls PILImage.open(img) on the passed image object if it isn't one.
So you might think that converting img to openpyxl's Image might work.
import openpyxl as xl
from openpyxl import Workbook
from openpyxl.drawing.image import Image as XLImage
from PIL import Image as PILImage
im = PILImage.open("my_input_image.png")
pil_img = im.resize((78, 100))
xl_img = XLImage(pil_img)
wb2 = Workbook()
ws2 = wb2.active
ws2.add_image(xl_img, 'A1')
wb2.save(filename="output.xlsx")
That would solve the original error, but then you'll get a new error, "'Image' object has no attribute 'fp'", because openpyxl's Image module expects that the image object has a fp attribute, which is only available if the Image was created from a file (i.e. open(filename)).
So, the solution I can come up with is to:
Create the image object as PIL Image
Do image pre-processing (ex. resize)
Save the pre-processed image back to a file
Create the image object as openpyxl's image
Add that image to the workbook
from openpyxl import Workbook
from openpyxl.drawing.image import Image as XLImage
from PIL import Image as PILImage
im = PILImage.open("my_input_image.png")
pil_img = im.resize((78, 100))
pil_img.save("my_resized_image.png")
xl_img = XLImage("my_resized_image.png")
wb2 = Workbook()
ws2 = wb2.active
ws2.add_image(xl_img, 'A1')
wb2.save(filename="output.xlsx")
If you don't need to do any image processing before adding the image, just open the file directly using openpyxl's Image class:
from openpyxl import Workbook
from openpyxl.drawing.image import Image as XLImage
xl_img = XLImage("my_input_image.png")
wb2 = Workbook()
ws2 = wb2.active
ws2.add_image(xl_img, 'A1')
wb2.save(filename="output.xlsx")

Not able to export matplotlib plot to excel sheet --- Plotted graph in Jupyter notebook using matplotlib to Excel

From Stackoverflow, i got following code for the task
import matplotlib.pyplot as plt
Import openpyxl
#Graph Command
plt.scatter('Month','Balance',data=test)
#Saving
plt.savefig("myplot.png", dpi = 150)
wb = load_workbook('input.xlsx')
ws = wb.active
img = image('myplot.png')
img.anchor(ws.cell('A1'))
ws.add_image(img)
wb.save('output.xlsx')
But i was getting error
"TypeError: 'module' object is not callable"
I change the code
import matplotlib.pyplot as plt
from openpyxl import load_workbook
from openpyxl.drawing import image
plt.scatter('Month','Balance',data=test)
plt.savefig("myplot.png", dpi = 150)
wb = load_workbook('input.xlsx')
ws = wb.active
img = image('myplot.png')
img.anchor(ws.cell('A1'))
ws.add_image(img)
wb.save('output.xlsx')
But still same error.
Please help me in exporting multiple charts/plots to excel sheet from Jupyter notebook.
Got the answer after some changes in the code:-
import openpyxl
import matplotlib.pyplot as plt
fig = plt.figure()
#plotting Graph
plt.scatter('Month','Balance',data=test)
fig.savefig('temp.png', dpi=fig.dpi)
#Saving Graph in the excel Sheet
wb = openpyxl.Workbook()
ws = wb.worksheets[0]
img = openpyxl.drawing.image.Image('temp.png')
img.anchor = 'A1'
ws.add_image(img)
wb.save('out.xlsx')

Export Images From Excel using Python with specific name

I am trying to read an excel using python, Excel has two columns name as Product_Name and second is LOGO. product Name as the name suggests contains the Product Name Like Fish ,Laptop whereas Second columns contain the logo of that Product Name.I am trying to save images from the LOGO column with image name as Product Name .Below Code is working fine but Product Name and saved Images are mismatching
import win32com.client # Need pywin32 from pip
from PIL import ImageGrab # Need PIL as well
import os
excel = win32com.client.Dispatch("Excel.Application")
workbook = excel.ActiveWorkbook
wb_folder = workbook.Path
wb_name = workbook.Name
wb_path = os.path.join(wb_folder, wb_name)
print(wb_path)
print("Extracting images from %s" % wb_path)
image_no = 0
for sheet in workbook.Worksheets:
if(sheet.Name == "Ch"):
for shape,r in zip(sheet.Shapes,range(4,200)):
if shape.Name.startswith("Picture"):
image_no += 1
print("---- Image No. %07i ----" % image_no)
print(r)
imagen = sheet.Cells(r,'E').value
filename = sheet.Cells(r,'E').value + ".jpg"
file_path = os.path.join (wb_folder, filename)
print("Saving as %s" % file_path) # Debug output
shape.Copy() # Copies from Excel to Windows clipboard
# Use PIL (python imaging library) to save from Windows clipboard
# to a file
image = ImageGrab.grabclipboard()
print(image)
try:
image.save(file_path,'jpeg')
except AttributeError:
F = open('error.txt','w')
F.write(imagen)
F.close()
Following script extracts all images from Excel file and name them with "Channel name" value:
import re
from PIL import ImageGrab
import win32com.client as win32
FILE = r'C:\Users\user\Desktop\so\53994108\logo.xlsx'
CELLS = [(4, 5, 'F'), (3, 3, 'D')]
excel = win32.gencache.EnsureDispatch('Excel.Application')
workbook = excel.Workbooks.Open(FILE)
for i, worksheet in enumerate(workbook.Sheets):
row = CELLS[i][0]
while True:
name = worksheet.Cells(row, CELLS[i][1]).Value
if not name:
break
name = re.sub(r'\W+ *', ' ', name)
rng = worksheet.Range('{}{}'.format(CELLS[i][2], row))
rng.CopyPicture(1, 2)
im = ImageGrab.grabclipboard()
im.save('{}.jpg'.format(name))
row += 1
So I've got following images on the end:

Python Export Excel Sheet Range as Image

So it seems there's something weird going on with PIL ImageGrab.grabclipboard()
import win32com.client
from PIL import ImageGrab
o = win32com.client.Dispatch('Excel.Application')
o.visible = False
wb = o.Workbooks.Open(path)
ws = wb.Worksheets['Global Dash']
ws.Range(ws.Cells(1,1),ws.Cells(66,16)).CopyPicture()
img = ImageGrab.grabclipboard()
imgFile = os.path.join(path_to_img,'test.jpg')
img.save(imgFile)
When I run this, I notice that if I ctrl-V , the image is actually correctly saved on the clipboard, but my img variable returns None, meaning ImageGrab.grabclipboard() is somehow not working. Any ideas?
Here I have a solution which might help you.
import excel2img
excel2img.export_img("example.xlsx/example.csv","image.png/image.bmp","sheet!B2:H22")
This is working perfectly for me.
To clarify those comments of Florent B. and David Yang
Add optional parameter Format into .CopyPicture() will make ImageGrab.getclipboard() work as expected.
The following code will be
ws.Range(ws.Cells(1,1),ws.Cells(66,16)).CopyPicture(Format = 2)
Number 2 is xlBitmap, refer to https://learn.microsoft.com/en-us/office/vba/api/excel.range.copypicture
I just replaced ws.Range(ws.Cells(1,1),ws.Cells(66,16)).CopyPicture() by ws.Range(ws.Cells(1,1),ws.Cells(66,16)).Copy() and it
worked perfectly.
So this is the entire code.
import win32com.client
from PIL import ImageGrab
o = win32com.client.Dispatch('Excel.Application')
o.visible = False
wb = o.Workbooks.Open(path)
ws = wb.Worksheets['Global Dash']
ws.Range(ws.Cells(1,1),ws.Cells(66,16)).Copy()
img = ImageGrab.grabclipboard()
imgFile = os.path.join(path_to_img,'test.jpg')
img.save(imgFile)
I just tried the method posted in the comments under the question and it actually works!
Pay attention to use win32com.client.constants to get the xlBitmap.
In addition, my environment is Python 3.6 and I haven't tried it again in Python 2.7.
win32c = win32com.client.constants
ws.Range(ws.Cells(1,1),ws.Cells(66,16)).CopyPicture(Format= win32c.xlBitmap)
img = ImageGrab.grabclipboard()
imgFile = os.path.join(path_to_img,'test.jpg')
img.save(imgFile)
This solution worked for me.
Try to start Excel with:
o = win32com.client.gencache.EnsureDispatch("Excel.Application")
Then use win32com.client.constants to get the xlBitmap
wb = o.Workbooks.Open(workbook_file_name)
ws = wb.Worksheets("Vs. Disk or Retrofit Chart View")
ws.Range(ws.Cells(22,1),ws.Cells(62,8)).CopyPicture(Format= win32com.client.constants.xlBitmap)
img = ImageGrab.grabclipboard()
imgFile = os.path.join(os.getcwd(),'test.jpg')
img.save(imgFile)
The best way to do it is:
import win32com.client
from PIL import ImageGrab
wb_file_name = 'Input.xlsx'
outputPNGImage = 'Output.png'
xls_file = win32com.client.gencache.EnsureDispatch("Excel.Application")
wb = xls_file.Workbooks.Open(Filename=wb_file_name)
xls_file.DisplayAlerts = False
ws = wb.Worksheets("Desired_Tab")
ws.Range(ws.Cells(1,1),ws.Cells(15,3)).CopyPicture(Format= win32com.client.constants.xlBitmap) # example from cell (1,1) to cell (15,3)
img = ImageGrab.grabclipboard()
img.save(outputPNGImage)
wb.Close(SaveChanges=False, Filename=wb_file_name)

Insert image in openpyxl

Is it possible to insert an image (jpeg, png, etc) using openpyxl?
Basically I want to place a generated image with a chart below it.
I don't see anything in the documentation, which seems to be a little lacking compared to the maturity of the code.
The following inserts an image in cell A1. Adjust the image location to your needs or handle the creation of the PIL image yourself and hand that to Image()
import openpyxl
wb = openpyxl.Workbook()
ws = wb.worksheets[0]
img = openpyxl.drawing.image.Image('test.jpg')
img.anchor = 'A1'
ws.add_image(img)
wb.save('out.xlsx')
In older versions of openpyxl the following works:
import openpyxl
wb = openpyxl.Workbook()
ws = wb.worksheets[0]
img = openpyxl.drawing.Image('test.jpg')
img.anchor(ws.cell('A1'))
ws.add_image(img)
wb.save('out.xlsx')
Providing a full update on how to do this. This solution uses openpyxl version 2.4.5.
I downloaded an image to my local directory, opened an existing workbook and saved with the image inserted.
import openpyxl
from openpyxl import load_workbook
from openpyxl import Workbook
from openpyxl.drawing.image import Image
from openpyxl.utils import coordinate_from_string
openpyxl_version = openpyxl.__version__
print(openpyxl_version) #to see what version I'm running
# downloaded a .png to local directory manually from
# "https://www.python.org/static/opengraph-icon-200x200.png"
#change to the location and name of your image
png_loc = r'c:\users\me\opengraph-icon-200x200.png'
# test.xlsx already exists in my current directory
wb = load_workbook('test.xlsx')
ws = wb.active
my_png = openpyxl.drawing.image.Image(png_loc)
ws.add_image(my_png, 'B3')
wb.save('test.xlsx')
Results:
This code worked for me:
import openpyxl
wb = openpyxl.Workbook()
ws = wb.worksheets[0]
ws.merge_cells('A1:A3')
img = openpyxl.drawing.image.Image('image.jpg')
row_number = 1
col_idx = 1
cell = ws.cell(row=row_number, column=col_idx)
ws.add_image(img)
wb.save('output.xlsx')
Just to add, I have been using openpyxl==2.5.6 (with Python3.65), and I had to use img.anchor('A1') instead of img.anchor(ws.cell('A1')).
import openpyxl
wb = openpyxl.Workbook()
ws = wb.worksheets[0]
img = openpyxl.drawing.Image('test.jpg')
img.anchor('A1')
ws.add_image(img)
wb.save('out.xlsx')

Categories

Resources