@@ -954,38 +954,92 @@ class ImageTests(object):
954954 IMAGE_RELATIONSHIP_ID = "rId5"
955955
956956 def _read_embedded_image (self , element ):
957+ return self ._read_embedded_images (element )[0 ]
958+
959+ def _read_embedded_images (self , element ):
957960 relationships = Relationships ([
958961 _image_relationship (self .IMAGE_RELATIONSHIP_ID , "media/hat.png" ),
959962 ])
960-
961963 mocks = funk .Mocks ()
962964 docx_file = mocks .mock ()
963965 funk .allows (docx_file ).open ("word/media/hat.png" ).returns (io .BytesIO (self .IMAGE_BYTES ))
964-
965966 content_types = mocks .mock ()
966967 funk .allows (content_types ).find_content_type ("word/media/hat.png" ).returns ("image/png" )
967-
968- return _read_and_get_document_xml_element (
968+ return _read_and_get_document_xml_elements (
969969 element ,
970970 content_types = content_types ,
971971 relationships = relationships ,
972972 docx_file = docx_file ,
973973 )
974974
975- def test_can_read_imagedata_elements_with_rid_attribute (self ):
976- imagedata_element = xml_element ("v:imagedata" , {
977- "r:id" : self .IMAGE_RELATIONSHIP_ID ,
978- "o:title" : "It's a hat"
979- })
975+ def can_read_shape_elements_with_rid_and_size_attributes (self ):
976+ shape_element = xml_element ("v:shape" , {"style" : "width:31.5pt;height:38.25pt" }, [
977+ xml_element ("v:imagedata" , {
978+ "r:id" : self .IMAGE_RELATIONSHIP_ID ,
979+ "o:title" : "It's a hat"
980+ })
981+ ])
980982
981983 image = self ._read_embedded_image (imagedata_element )
984+ image = self ._read_embedded_image (shape_element )
982985
983986 assert_equal (documents .Image , type (image ))
984987 assert_equal ("It's a hat" , image .alt_text )
985988 assert_equal ("image/png" , image .content_type )
989+ assert_equal (documents .Size (width = "31.5pt" , height = "38.25pt" ), image .size )
986990 with image .open () as image_file :
987991 assert_equal (self .IMAGE_BYTES , image_file .read ())
988992
993+
994+ def cannot_resize_shape_with_multiple_nodes (self ):
995+ shape_element = xml_element ("v:shape" , {"style" : "width:31.5pt;height:38.25pt" }, [
996+ xml_element ("v:imagedata" , {
997+ "r:id" : self .IMAGE_RELATIONSHIP_ID ,
998+ "o:title" : "It's a hat"
999+ }),
1000+ xml_element ("v:textbox" , {}, [
1001+ xml_element ("w:txbxContent" , {}, [
1002+ _paragraph_with_style_id ("textbox-content" )
1003+ ])
1004+ ])
1005+ ])
1006+
1007+ nodes = self ._read_embedded_images (shape_element )
1008+
1009+ assert_equal (2 , len (nodes ))
1010+ image_node = nodes [0 ]
1011+ assert_equal (documents .Image , type (image_node ))
1012+ assert_equal ("It's a hat" , image_node .alt_text )
1013+ assert_equal (None , image_node .size )
1014+
1015+
1016+ def can_read_shape_elements_with_unused_style_elements (self ):
1017+ shape_element = xml_element ("v:shape" , {"style" : "width:31.5pt;position:absolute;height:38.25pt" }, [
1018+ xml_element ("v:imagedata" , {
1019+ "r:id" : self .IMAGE_RELATIONSHIP_ID ,
1020+ "o:title" : "It's a hat"
1021+ })
1022+ ])
1023+
1024+ image = self ._read_embedded_image (shape_element )
1025+
1026+ assert_equal (documents .Image , type (image ))
1027+ assert_equal (documents .Size (width = "31.5pt" , height = "38.25pt" ), image .size )
1028+
1029+
1030+ def can_read_shape_elements_with_inch_size_attributes (self ):
1031+ shape_element = xml_element ("v:shape" , {"style" : "width:0.58in;height:0.708in" }, [
1032+ xml_element ("v:imagedata" , {
1033+ "r:id" : self .IMAGE_RELATIONSHIP_ID ,
1034+ "o:title" : "It's a hat"
1035+ })
1036+ ])
1037+
1038+ image = self ._read_embedded_image (shape_element )
1039+
1040+ assert_equal (documents .Image , type (image ))
1041+ assert_equal (documents .Size (width = "0.58in" , height = "0.708in" ), image .size )
1042+
9891043 def test_when_imagedata_element_has_no_relationship_id_then_it_is_ignored_with_warning (self ):
9901044 imagedata_element = xml_element ("v:imagedata" )
9911045
@@ -999,6 +1053,7 @@ def test_can_read_inline_pictures(self):
9991053 drawing_element = _create_inline_image (
10001054 blip = _embedded_blip (self .IMAGE_RELATIONSHIP_ID ),
10011055 description = "It's a hat" ,
1056+ extent = (9525 , 19000 )
10021057 )
10031058
10041059 image = self ._read_embedded_image (drawing_element )
@@ -1021,6 +1076,7 @@ def test_alt_text_title_is_used_if_alt_text_description_is_missing(self):
10211076 assert_equal (documents .Image , type (image ))
10221077 assert_equal ("It's a hat" , image .alt_text )
10231078 assert_equal ("image/png" , image .content_type )
1079+ assert_equal (documents .Size (width = "1" , height = "2" ), image .size )
10241080 with image .open () as image_file :
10251081 assert_equal (self .IMAGE_BYTES , image_file .read ())
10261082
@@ -1294,9 +1350,9 @@ def _text_element(value):
12941350 return xml_element ("w:t" , {}, [xml_text (value )])
12951351
12961352
1297- def _create_inline_image (blip , description = None , title = None ):
1353+ def _create_inline_image (blip , description = None , title = None , extent = None ):
12981354 return xml_element ("w:drawing" , {}, [
1299- xml_element ("wp:inline" , {}, _create_image_elements (blip , description = description , title = title ))
1355+ xml_element ("wp:inline" , {}, _create_image_elements (blip , description = description , title = title , extent = extent ))
13001356 ])
13011357
13021358
@@ -1306,15 +1362,19 @@ def _create_anchored_image(description, blip):
13061362 ])
13071363
13081364
1309- def _create_image_elements (blip , description = None , title = None ):
1365+ def _create_image_elements (blip , description = None , title = None , extent = None ):
13101366 properties = {}
13111367 if description is not None :
13121368 properties ["descr" ] = description
13131369 if title is not None :
13141370 properties ["title" ] = title
1315-
1371+ extent = {
1372+ "cx" : extent [0 ] if extent else "0" ,
1373+ "cy" : extent [1 ] if extent else "0"
1374+ }
13161375 return [
13171376 xml_element ("wp:docPr" , properties ),
1377+ xml_element ("wp:extent" , extent ),
13181378 xml_element ("a:graphic" , {}, [
13191379 xml_element ("a:graphicData" , {}, [
13201380 xml_element ("pic:pic" , {}, [
0 commit comments