4
4
them in a document.
5
5
"""
6
6
7
+ from __future__ import annotations
8
+
7
9
import hashlib
8
10
import io
9
11
import os
12
+ from typing import IO , Tuple
13
+
14
+ from typing_extensions import Self
10
15
11
16
from docx .image .exceptions import UnrecognizedImageError
12
- from docx .shared import Emu , Inches , lazyproperty
17
+ from docx .shared import Emu , Inches , Length , lazyproperty
13
18
14
19
15
- class Image ( object ) :
20
+ class Image :
16
21
"""Graphical image stream such as JPEG, PNG, or GIF with properties and methods
17
22
required by ImagePart."""
18
23
19
- def __init__ (self , blob , filename , image_header ):
24
+ def __init__ (self , blob : bytes , filename : str , image_header : BaseImageHeader ):
20
25
super (Image , self ).__init__ ()
21
26
self ._blob = blob
22
27
self ._filename = filename
23
28
self ._image_header = image_header
24
29
25
30
@classmethod
26
- def from_blob (cls , blob ) :
31
+ def from_blob (cls , blob : bytes ) -> Self :
27
32
"""Return a new |Image| subclass instance parsed from the image binary contained
28
33
in `blob`."""
29
34
stream = io .BytesIO (blob )
@@ -73,60 +78,66 @@ def filename(self):
73
78
return self ._filename
74
79
75
80
@property
76
- def px_width (self ):
81
+ def px_width (self ) -> int :
77
82
"""The horizontal pixel dimension of the image."""
78
83
return self ._image_header .px_width
79
84
80
85
@property
81
- def px_height (self ):
86
+ def px_height (self ) -> int :
82
87
"""The vertical pixel dimension of the image."""
83
88
return self ._image_header .px_height
84
89
85
90
@property
86
- def horz_dpi (self ):
91
+ def horz_dpi (self ) -> int :
87
92
"""Integer dots per inch for the width of this image.
88
93
89
94
Defaults to 72 when not present in the file, as is often the case.
90
95
"""
91
96
return self ._image_header .horz_dpi
92
97
93
98
@property
94
- def vert_dpi (self ):
99
+ def vert_dpi (self ) -> int :
95
100
"""Integer dots per inch for the height of this image.
96
101
97
102
Defaults to 72 when not present in the file, as is often the case.
98
103
"""
99
104
return self ._image_header .vert_dpi
100
105
101
106
@property
102
- def width (self ):
107
+ def width (self ) -> Inches :
103
108
"""A |Length| value representing the native width of the image, calculated from
104
109
the values of `px_width` and `horz_dpi`."""
105
110
return Inches (self .px_width / self .horz_dpi )
106
111
107
112
@property
108
- def height (self ):
113
+ def height (self ) -> Inches :
109
114
"""A |Length| value representing the native height of the image, calculated from
110
115
the values of `px_height` and `vert_dpi`."""
111
116
return Inches (self .px_height / self .vert_dpi )
112
117
113
- def scaled_dimensions (self , width = None , height = None ):
114
- """Return a (cx, cy) 2-tuple representing the native dimensions of this image
115
- scaled by applying the following rules to `width` and `height`.
116
-
117
- If both `width` and `height` are specified, the return value is (`width`,
118
- `height`); no scaling is performed. If only one is specified, it is used to
119
- compute a scaling factor that is then applied to the unspecified dimension,
120
- preserving the aspect ratio of the image. If both `width` and `height` are
121
- |None|, the native dimensions are returned. The native dimensions are calculated
122
- using the dots-per-inch (dpi) value embedded in the image, defaulting to 72 dpi
123
- if no value is specified, as is often the case. The returned values are both
124
- |Length| objects.
118
+ def scaled_dimensions (
119
+ self , width : int | None = None , height : int | None = None
120
+ ) -> Tuple [Length , Length ]:
121
+ """(cx, cy) pair representing scaled dimensions of this image.
122
+
123
+ The native dimensions of the i
10000
mage are scaled by applying the following rules to
124
+ the `width` and `height` arguments.
125
+
126
+ * If both `width` and `height` are specified, the return value is (`width`,
127
+ `height`); no scaling is performed.
128
+ * If only one is specified, it is used to compute a scaling factor that is then
129
+ applied to the unspecified dimension, preserving the aspect ratio of the image.
130
+ * If both `width` and `height` are |None|, the native dimensions are returned.
131
+
132
+ The native dimensions are calculated using the dots-per-inch (dpi) value
133
+ embedded in the image, defaulting to 72 dpi if no value is specified, as is
134
+ often the case. The returned values are both |Length| objects.
125
135
"""
126
136
if width is None and height is None :
127
137
return self .width , self .height
128
138
129
139
if width is None :
140
+ assert height is not None
130
141
scaling_factor = float (height ) / float (self .height )
131
142
width = round (self .width * scaling_factor )
132
143
@@ -142,7 +153,12 @@ def sha1(self):
142
153
return hashlib .sha1 (self ._blob ).hexdigest ()
143
154
144
155
@classmethod
145
- def _from_stream (cls , stream , blob , filename = None ):
156
+ def _from_stream (
157
+ cls ,
158
+ stream : IO [bytes ],
159
+ blob : bytes ,
160
+ filename : str | None = None ,
161
+ ) -> Image :
146
162
"""Return an instance of the |Image| subclass corresponding to the format of the
147
163
image in `stream`."""
148
164
image_header = _ImageHeaderFactory (stream )
0 commit comments