Docx reader: Recognize media inside textboxes (#11515)

Closes #11053.
This commit is contained in:
Raymond Berger
2026-03-12 14:26:17 -07:00
committed by GitHub
parent d39ca219e7
commit f0d05eb438
6 changed files with 94 additions and 9 deletions
+20 -9
View File
@@ -160,21 +160,32 @@ unwrapElement ns element
| isElem ns "w" "smartTag" element
= concatMap (unwrapElement ns) (elChildren element)
| isElem ns "w" "p" element
, textboxes@(_:_) <- findChildrenByName ns "w" "r" element >>=
findChildrenByName ns "mc" "AlternateContent" >>=
findChildrenByName ns "mc" "Fallback" >>=
findChildrenByName ns "w" "pict" >>=
(\e -> findChildrenByName ns "v" "shape" e <>
findChildrenByName ns "v" "rect" e) >>=
findChildrenByName ns "v" "textbox" >>=
findChildrenByName ns "w" "txbxContent"
= concatMap (unwrapElement ns) (concatMap elChildren textboxes) -- handle #9214
, textboxes@(_:_) <- findChildrenByName ns "w" "r" element >>= findTextboxes
= concatMap (unwrapElement ns) (concatMap elChildren textboxes) -- handle #9214, #11053
| isElem ns "w" "r" element
, Just fallback <- findChildByName ns "mc" "AlternateContent" element >>=
findChildByName ns "mc" "Fallback"
= [element{ elContent = concatMap (unwrapContent ns) (elContent fallback) }]
| otherwise
= [element{ elContent = concatMap (unwrapContent ns) (elContent element) }]
where
-- Search textbox content in the run's effective children.
-- If AlternateContent is present, use only the fallback branch,
-- matching the w:r unwrapping logic and avoiding duplicate textbox
-- extraction when both direct and fallback encodings are present.
findRunFallback run =
findChildByName ns "mc" "AlternateContent" run >>=
findChildByName ns "mc" "Fallback"
findTextboxes run =
findTextboxContent =<<
case findRunFallback run of
Just fallback -> findChildrenByName ns "w" "pict" fallback
Nothing -> findChildrenByName ns "w" "pict" run
findTextboxContent pict =
(findChildrenByName ns "v" "shape" pict <>
findChildrenByName ns "v" "rect" pict) >>=
findChildrenByName ns "v" "textbox" >>=
findChildrenByName ns "w" "txbxContent"
unwrapContent :: NameSpaces -> Content -> [Content]
unwrapContent ns (Elem element) = map Elem $ unwrapElement ns element
+14
View File
@@ -215,6 +215,14 @@ tests = [ testGroup "document"
"text in shape format"
"docx/text_in_shape_format.docx"
"docx/text_in_shape_format.native"
, testCompare
"image inside textbox content"
"docx/textbox_image.docx"
"docx/textbox_image.native"
, testCompare
"image inside textbox content with duplicate encoding"
"docx/textbox_image_duplicate_encoding.docx"
"docx/textbox_image_duplicate_encoding.native"
]
, testGroup "blocks"
[ testCompare
@@ -473,6 +481,12 @@ tests = [ testGroup "document"
[ testMediaBag
"image extraction"
"docx/image.docx"
, testMediaBag
"image inside textbox content populates media bag"
"docx/textbox_image.docx"
, testMediaBag
"image inside textbox content with duplicate encoding populates media bag"
"docx/textbox_image_duplicate_encoding.docx"
]
, testGroup "custom styles"
[ testCompare
Binary file not shown.
+30
View File
@@ -0,0 +1,30 @@
[ Para
[ Str "The"
, Space
, Str "image"
, Space
, Str "is"
, Space
, Str "below."
]
, Para
[ Image
( ""
, []
, [ ( "width" , "4.543038057742782in" )
, ( "height" , "2.9166666666666665in" )
]
)
[]
( "media/image1.png" , "" )
]
, Para
[ Str "The"
, Space
, Str "image"
, Space
, Str "is"
, Space
, Str "above."
]
]
Binary file not shown.
@@ -0,0 +1,30 @@
[ Para
[ Str "The"
, Space
, Str "image"
, Space
, Str "is"
, Space
, Str "below."
]
, Para
[ Image
( ""
, []
, [ ( "width" , "4.543038057742782in" )
, ( "height" , "2.9166666666666665in" )
]
)
[]
( "media/image1.png" , "" )
]
, Para
[ Str "The"
, Space
, Str "image"
, Space
, Str "is"
, Space
, Str "above."
]
]