Я искал документацию для python-docx
и других пакетов, а также переполнение стека, но не смог найти, как удалить все изображения из файлов docx
с помощью python.
Мой конкретный прецедент: мне нужно преобразовать сотни текстовых документов в формат "черновик" для просмотра клиентами. Эти черновики должны быть идентичны исходным документам, но все изображения должны быть удалены/отредактированы от них.
Извините за то, что вы не включили пример того, что я пробовал, что я пробовал - это часы исследований, которые не дали никакой информации. Я нашел этот вопрос о том, как извлекать изображения из текстовых файлов, но это не удаляет их из фактического документа: Извлеките изображения из Word и Excel с помощью Python
Оттуда и из других источников я обнаружил, что файлы docx
могут быть прочитаны как простые zip файлы, я не знаю, означает ли это, что это возможно "повторно застегнуть" без изображений, не затрагивая целостность файла docx
( edit: просто удаление изображений работает, но не позволяет python-docx
продолжать работать с этим файлом из-за отсутствия ссылок на изображения), но подумал, что это может быть путь к решению.
Есть идеи?
Если ваша цель состоит в том, чтобы редактировать изображения, возможно, этот код, который я использовал для аналогичного использования, может быть полезен:
import sys
import zipfile
from PIL import Image, ImageFilter
import io
blur = ImageFilter.GaussianBlur(40)
def redact_images(filename):
outfile = filename.replace(".docx", "_redacted.docx")
with zipfile.ZipFile(filename) as inzip:
with zipfile.ZipFile(outfile, "w") as outzip:
for info in inzip.infolist():
name = info.filename
print(info)
content = inzip.read(info)
if name.endswith((".png", ".jpeg", ".gif")):
fmt = name.split(".")[-1]
img = Image.open(io.BytesIO(content))
img = img.convert().filter(blur)
outb = io.BytesIO()
img.save(outb, fmt)
content = outb.getvalue()
info.file_size = len(content)
info.CRC = zipfile.crc32(content)
outzip.writestr(info, content)
Здесь я использовал PIL для размытия изображений в некоторых файлах, но вместо фильтра размытия можно было использовать любую другую подходящую операцию. Это очень хорошо работало для моего использования.
Я не думаю, что в настоящее время он реализован в python-docx.
Картинки в объектной модели Word определяются как плавающие формы или встроенные фигуры. Документация docx утверждает, что она поддерживает только встроенные формы.
Объектная модель Word для встроенных фигур поддерживает метод Delete()
, который должен быть доступен. Однако он не указан в примерах InlineShapes и существует аналогичный метод для абзацев. Для абзацев есть открытый запрос функции, чтобы добавить эту функциональность, которая датируется 2014 годом! Если он не добавлен в абзацы, он не будет доступен для InlineShapes, поскольку они реализованы как отдельные абзацы.
Вы можете сделать это с помощью win32com, если у вас установлена машина с установленными Word и Python. Это позволит вам напрямую вызвать объектную модель Word, предоставляя вам доступ к методу Delete()
. На самом деле вы, вероятно, можете обмануть - вместо прокрутки документа, чтобы получить каждое изображение, вы можете вызвать Find and Replace, чтобы очистить изображение. Этот вопрос SO говорит о том, что win32com находит и заменяет:
import win32com.client
from os import getcwd, listdir
docs = [i for i in listdir('.') if i[-3:]=='doc' or i[-4:]=='docx'] #All Word file
FromTo = {"First Name":"John",
"Last Name":"Smith"} #You can insert as many as you want
word = win32com.client.DispatchEx("Word.Application")
word.Visible = True #Keep comment after tests
word.DisplayAlerts = False
for doc in docs:
word.Documents.Open('{}\\{}'.format(getcwd(), doc))
for From in FromTo.keys():
word.Selection.Find.Text = From
word.Selection.Find.Replacement.Text = FromTo[From]
word.Selection.Find.Execute(Replace=2, Forward=True) #You made the mistake here=> Replace must be 2
name = doc.rsplit('.',1)[0]
ext = doc.rsplit('.',1)[1]
word.ActiveDocument.SaveAs('{}\\{}_2.{}'.format(getcwd(), name, ext))
word.Quit() # releases Word object from memory
В этом случае, поскольку нам нужны изображения, нам нужно будет использовать короткий код ^ g как find.Text и blank как замену.
word.Selection.Find
find.Text = "^g"
find.Replacement.Text = ""
find.Execute(Replace=1, Forward=True)
Я не знаю об этой библиотеке, но просматривая документацию, я нашел этот раздел об изображениях. В нем упоминается, что в настоящее время невозможно вставить изображения, отличные от встроенных. Если это то, что у вас есть в ваших документах, я предполагаю, что вы также можете получить их, просмотрев объект Document и затем удалить их?
Документ объясняется здесь.
Хотя это и не дубликат, вы также можете посмотреть на этот вопрос ответ, где пользователь "scanny" объясняет, как он находит образы с помощью библиотеки.
docx
которое удалит изображения (из xml?), Но ваше решение креативно и работает для меня, поэтому я выберу его сейчас (если не появится другое «родное» решение)