@@ -954,38 +954,91 @@ 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
981- image = self ._read_embedded_image (imagedata_element )
983+ image = self ._read_embedded_image (shape_element )
982984
983985 assert_equal (documents .Image , type (image ))
984986 assert_equal ("It's a hat" , image .alt_text )
985987 assert_equal ("image/png" , image .content_type )
988+ assert_equal (documents .Size (width = "31.5pt" , height = "38.25pt" ), image .size )
986989 with image .open () as image_file :
987990 assert_equal (self .IMAGE_BYTES , image_file .read ())
988991
992+
993+ def cannot_resize_shape_with_multiple_nodes (self ):
994+ shape_element = xml_element ("v:shape" , {"style" : "width:31.5pt;height:38.25pt" }, [
995+ xml_element ("v:imagedata" , {
996+ "r:id" : self .IMAGE_RELATIONSHIP_ID ,
997+ "o:title" : "It's a hat"
998+ }),
999+ xml_element ("v:textbox" , {}, [
1000+ xml_element ("w:txbxContent" , {}, [
1001+ _paragraph_with_style_id ("textbox-content" )
1002+ ])
1003+ ])
1004+ ])
1005+
1006+ nodes = self ._read_embedded_images (shape_element )
1007+
1008+ assert_equal (2 , len (nodes ))
1009+ image_node = nodes [0 ]
1010+ assert_equal (documents .Image , type (image_node ))
1011+ assert_equal ("It's a hat" , image_node .alt_text )
1012+ assert_equal (None , image_node .size )
1013+
1014+
1015+ def can_read_shape_elements_with_unused_style_elements (self ):
1016+ shape_element = xml_element ("v:shape" , {"style" : "width:31.5pt;position:absolute;height:38.25pt" }, [
1017+ xml_element ("v:imagedata" , {
1018+ "r:id" : self .IMAGE_RELATIONSHIP_ID ,
1019+ "o:title" : "It's a hat"
1020+ })
1021+ ])
1022+
1023+ image = self ._read_embedded_image (shape_element )
1024+
1025+ assert_equal (documents .Image , type (image ))
1026+ assert_equal (documents .Size (width = "31.5pt" , height = "38.25pt" ), image .size )
1027+
1028+
1029+ def can_read_shape_elements_with_inch_size_attributes (self ):
1030+ shape_element = xml_element ("v:shape" , {"style" : "width:0.58in;height:0.708in" }, [
1031+ xml_element ("v:imagedata" , {
1032+ "r:id" : self .IMAGE_RELATIONSHIP_ID ,
1033+ "o:title" : "It's a hat"
1034+ })
1035+ ])
1036+
1037+ image = self ._read_embedded_image (shape_element )
1038+
1039+ assert_equal (documents .Image , type (image ))
1040+ assert_equal (documents .Size (width = "0.58in" , height = "0.708in" ), image .size )
1041+
9891042 def test_when_imagedata_element_has_no_relationship_id_then_it_is_ignored_with_warning (self ):
9901043 imagedata_element = xml_element ("v:imagedata" )
9911044
@@ -999,13 +1052,15 @@ def test_can_read_inline_pictures(self):
9991052 drawing_element = _create_inline_image (
10001053 blip = _embedded_blip (self .IMAGE_RELATIONSHIP_ID ),
10011054 description = "It's a hat" ,
1055+ extent = (9525 , 19000 )
10021056 )
10031057
10041058 image = self ._read_embedded_image (drawing_element )
10051059
10061060 assert_equal (documents .Image , type (image ))
10071061 assert_equal ("It's a hat" , image .alt_text )
10081062 assert_equal ("image/png" , image .content_type )
1063+ assert_equal (documents .Size (width = "1" , height = "2" ), image .size )
10091064 with image .open () as image_file :
10101065 assert_equal (self .IMAGE_BYTES , image_file .read ())
10111066
@@ -1294,9 +1349,9 @@ def _text_element(value):
12941349 return xml_element ("w:t" , {}, [xml_text (value )])
12951350
12961351
1297- def _create_inline_image (blip , description = None , title = None ):
1352+ def _create_inline_image (blip , description = None , title = None , extent = None ):
12981353 return xml_element ("w:drawing" , {}, [
1299- xml_element ("wp:inline" , {}, _create_image_elements (blip , description = description , title = title ))
1354+ xml_element ("wp:inline" , {}, _create_image_elements (blip , description = description , title = title , extent = extent ))
13001355 ])
13011356
13021357
@@ -1306,15 +1361,19 @@ def _create_anchored_image(description, blip):
13061361 ])
13071362
13081363
1309- def _create_image_elements (blip , description = None , title = None ):
1364+ def _create_image_elements (blip , description = None , title = None , extent = None ):
13101365 properties = {}
13111366 if description is not None :
13121367 properties ["descr" ] = description
13131368 if title is not None :
13141369 properties ["title" ] = title
1315-
1370+ extent = {
1371+ "cx" : extent [0 ] if extent else "0" ,
1372+ "cy" : extent [1 ] if extent else "0"
1373+ }
13161374 return [
13171375 xml_element ("wp:docPr" , properties ),
1376+ xml_element ("wp:extent" , extent ),
13181377 xml_element ("a:graphic" , {}, [
13191378 xml_element ("a:graphicData" , {}, [
13201379 xml_element ("pic:pic" , {}, [
0 commit comments