Word to Markdown: convert a docx with pandoc, keep images
Bobby Huang ·
Under One pandoc command that keeps the image, you'll find the T3 pandoc line and the image line it wrote into out2.md. The section Why the image link breaks without extract-media sets the T2 image line next to the media check that found no file. Your own output gets its reader checks in Steps before you trust the Markdown.
Key takeaways
- See Why the image link breaks without extract-media for the T2 media check and its rc=1 result.
- Turn to Which Markdown flavor to ask pandoc for, where the T5 table and image from out5.md are quoted.
- Look at the T4 image line under Keep long lines whole with wrap set to none.
- Read What to fix by hand after converting for the parts of out.md that differ from notes.md.
- Work through the numbered steps in Steps before you trust the Markdown before you rely on the file.
How do I convert a Word document to Markdown without losing images? Run pandoc on the .docx with --extract-media, so the picture lands in a folder beside the new .md file. Then open the output and check the image links and the table by eye.
The whole test script ran once on one machine, and each result here comes from that run. The input, report.docx, was written by pandoc from a small file named notes.md, and nobody opened or saved it in Word. New to .md files? This explainer on .md files covers the basics.
One pandoc command that keeps the image
The test began with notes.md, a 32-line file. Inside it sit front matter, four headings, bullets, numbered steps, one table, fenced Python code, a quote, a web link and one image line. Its image line names diagram.png, a 2905-byte picture kept in that same folder. The version line in the log reads pandoc 3.8.3.
T1 turned notes.md into a Word file:
pandoc notes.md -o report.docx
T1 returned rc=0. The listing after it put report.docx at 14910 bytes. From there, T3 ran the line this page is about:
pandoc report.docx -t markdown --extract-media=assets -o out2.md
T3 ended with rc=0. Here is the image line pandoc wrote into out2.md:
{width="4.430555555555555in"
height="2.7777777777777776e-2in"}
After T3, the test listed the files under assets and found one: assets/media/rId12.png. So the link in out2.md points to a file that exists on disk. The alt text, Diagram, is the same as in notes.md. The file name changed: pandoc named the picture rId12.png in place of diagram.png. Pandoc also wrapped two size values, width and height, in curly braces; notes.md had neither.
What if the input name is wrong? T6 ran pandoc on nofile.docx, a name with no file behind it. Pandoc printed an error and ended with rc=1. This line from it names the cause:
nofile.docx: withBinaryFile: does not exist (No such file or directory)
If a script runs your convert step, have it stop on a nonzero exit code before anything reads the output.
Why the image link breaks without extract-media
T2 ran the same conversion with no media flag:
pandoc report.docx -t markdown -o out.md
T2 ended with rc=0. Its out.md matched out2.md line for line, with one exception. The image line came out like this:
{width="4.430555555555555in"
height="2.7777777777777776e-2in"}
Next, the test checked for media/rId12.png in the folder. No such file was there, and that check ended with rc=1. So out.md links to a picture that pandoc never wrote to disk, even though T2 itself returned rc=0. In T2, rc=0 and a missing picture went together.
The T3 line closed that gap. With --extract-media=assets, pandoc wrote the picture to assets/media/rId12.png and pointed the link there. T5 named a different folder, assets5, and its image source pointed into assets5/media. Relative paths and alt text are covered in this Markdown images walkthrough.
Which Markdown flavor to ask pandoc for
T2 and T5 differ in the value after -t. T2 asked for markdown. T5 asked for commonmark_x and named a media folder too:
pandoc report.docx -t commonmark_x --extract-media=assets5 -o out5.md
T5 ended with rc=0. Two parts of out5.md came out in a different shape from out.md.
The table. In out.md, the T2 table has no pipes. Pandoc drew it with runs of dashes, and an empty line splits the Draft row from the Review row:
--------------------------------------------------------------
Item Owner Due
-------------------- -------------------- --------------------
Draft Jane Fri
Review John Mon
--------------------------------------------------------------
In out5.md, the T5 table keeps pipes and alignment colons, with extra spaces inside the cells:
| Item | Owner | Due |
|:-------|:-----:|----:|
| Draft | Jane | Fri |
| Review | John | Mon |
Its words and colons match notes.md. In notes.md, each cell had a single space on each side. How Markdown tables are built explains the pipe syntax.
The image. T5 wrote no Markdown image line at all. It wrote an HTML figure block:
<figure>
<img src="assets5/media/rId12.png" style="width:4.43056in"
alt="Diagram" />
<figcaption aria-hidden="true"><p>Diagram</p></figcaption>
</figure>
Here the width sits in a style value, 4.43056in, and no height appears. The word Diagram shows up twice, once as the alt text and once inside the caption.
So the pick comes down to what reads the file next. If that reader wants pipe tables, the T5 output has them. If it wants a plain Markdown image line, the T2 and T3 output has that. No viewer or site was checked in this test, so open both files and compare them before you choose.
Keep long lines whole with wrap set to none
Look again at the T2 image line. Pandoc broke it in two, with the width ending line one and the height starting line two. T4 added one flag:
pandoc report.docx -t markdown --wrap=none -o out3.md
T4 returned rc=0, and its image line stayed in one piece:
{width="4.430555555555555in" height="2.7777777777777776e-2in"}
The other lines of out3.md match out.md. T4 ran without --extract-media, so its link points to media/rId12.png. The T2 media check found no file at that path. The test never ran both flags in one command, so this page has no output to show for that pairing.
Why care about a split line? Search out.md for rId12 and you land on half of the image syntax. If you plan to search the output or compare versions of it, check that each image line is whole.
What to fix by hand after converting
Compare out.md with notes.md one part at a time. The list below covers T2. The T3, T4 and T5 files match it here, apart from the image and table changes shown above.
- Front matter. out.md has no trace of the
title: Meeting notesblock from the opening of notes.md. Add it back if your file needs it. - Code block. notes.md wraps the code in a fence labeled python. Pandoc returned
print("hello")as one line pushed in by four spaces, fence and label gone. The words of the code matched. Put the fence and the label back by hand. - Numbered list. Pandoc put two spaces after each number, as in
1. Write the summary., where notes.md has one. - The table. In T2, T3 and T4, the table lost its pipes, as quoted under Which Markdown flavor to ask pandoc for. Rewrite it as a pipe table if that is the form you keep, or take the T5 table.
- The image. The link names rId12.png in place of diagram.png, and pandoc added two size values. The height value is 2.7777777777777776e-2in. Rename the picture and edit the line if you want the old name back, and check both values against the picture you expect.
- What matched. The four heading lines, the two bullet lines with
**Friday**and*old*, the quote and the example.com link came back as written in notes.md.
If you convert the .docx again later, check these parts again in the new output. Once the .md file becomes your master copy, fix things there.
Steps before you trust the Markdown
Use this list on your own converted file. The test log speaks for report.docx alone.
- Check the exit code first. T6 in this test returned rc=1 when the input file did not exist.
- Find each image line and confirm that the file it points to exists. In this test, T2 ended with rc=0 while its image link pointed to a missing file.
- Open each extracted picture and check it against the source document.
- Read the width and height values pandoc added to each image line. Keep them, change them or delete them.
- Check each table. Read its header row, cell words, row order and alignment.
- Check each code block for its fence and its language label.
- Check the first lines of the file for the front matter you expect.
- If you asked for
commonmark_x, search the file for<figure>and decide whether you want HTML in your Markdown. - Keep the .docx until the .md file passes these checks.
Going the other way, from a .md file to a .docx? See how to turn Markdown into a Word file with pandoc.
Where Sashmark fits
Sashmark, a Markdown app for the desktop, is still under construction, and no build is out for anyone yet. Once the Word file has become Markdown, the planned app would open that Markdown as a readable page. A mistake spotted in that page could be corrected right there, and the Round-Trip design would write only that correction to disk. Changes View would mark the paragraphs an agent touched between your visits, git or no git.
It is in development and has not been released. The app itself has no AI features. See the planned features, the help pages and the roadmap for where each part stands.
Follow the app's progress at sashmark.com.
Questions
- Can pandoc keep images when a docx becomes Markdown?
- The T3 line under One pandoc command that keeps the image is the command this test ran for that.
- Which Markdown flavor should I pick?
- Weigh the T2 and T5 output quoted under Which Markdown flavor to ask pandoc for.
- Why did one image line turn into two lines?
- See the T4 image line quoted in Keep long lines whole with wrap set to none.
- Pandoc can't find my input file. What then?
- The T6 run and its error text sit in One pandoc command that keeps the image.