drawings.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. # Copyright (c) 2010-2024 openpyxl
  2. from io import BytesIO
  3. from warnings import warn
  4. from openpyxl.xml.functions import fromstring
  5. from openpyxl.xml.constants import IMAGE_NS
  6. from openpyxl.packaging.relationship import (
  7. get_rel,
  8. get_rels_path,
  9. get_dependents,
  10. )
  11. from openpyxl.drawing.spreadsheet_drawing import SpreadsheetDrawing
  12. from openpyxl.drawing.image import Image, PILImage
  13. from openpyxl.chart.chartspace import ChartSpace
  14. from openpyxl.chart.reader import read_chart
  15. def find_images(archive, path):
  16. """
  17. Given the path to a drawing file extract charts and images
  18. Ignore errors due to unsupported parts of DrawingML
  19. """
  20. src = archive.read(path)
  21. tree = fromstring(src)
  22. try:
  23. drawing = SpreadsheetDrawing.from_tree(tree)
  24. except TypeError:
  25. warn("DrawingML support is incomplete and limited to charts and images only. Shapes and drawings will be lost.")
  26. return [], []
  27. rels_path = get_rels_path(path)
  28. deps = []
  29. if rels_path in archive.namelist():
  30. deps = get_dependents(archive, rels_path)
  31. charts = []
  32. for rel in drawing._chart_rels:
  33. try:
  34. cs = get_rel(archive, deps, rel.id, ChartSpace)
  35. except TypeError as e:
  36. warn(f"Unable to read chart {rel.id} from {path} {e}")
  37. continue
  38. chart = read_chart(cs)
  39. chart.anchor = rel.anchor
  40. charts.append(chart)
  41. images = []
  42. if not PILImage: # Pillow not installed, drop images
  43. return charts, images
  44. for rel in drawing._blip_rels:
  45. dep = deps.get(rel.embed)
  46. if dep.Type == IMAGE_NS:
  47. try:
  48. image = Image(BytesIO(archive.read(dep.target)))
  49. except OSError:
  50. msg = "The image {0} will be removed because it cannot be read".format(dep.target)
  51. warn(msg)
  52. continue
  53. if image.format.upper() == "WMF": # cannot save
  54. msg = "{0} image format is not supported so the image is being dropped".format(image.format)
  55. warn(msg)
  56. continue
  57. image.anchor = rel.anchor
  58. images.append(image)
  59. return charts, images