44them in a document.
55"""
66
7+ from __future__ import annotations
8+
79import hashlib
810import io
911import os
12+ from typing import IO , Tuple
13+
14+ from typing_extensions import Self
1015
1116from docx .image .exceptions import UnrecognizedImageError
12- from docx .shared import Emu , Inches , lazyproperty
17+ from docx .shared import Emu , Inches , Length , lazyproperty
1318
1419
15- class Image ( object ) :
20+ class Image :
1621 """Graphical image stream such as JPEG, PNG, or GIF with properties and methods
1722 required by ImagePart."""
1823
19- def __init__ (self , blob , filename , image_header ):
24+ def __init__ (self , blob : bytes , filename : str , image_header : BaseImageHeader ):
2025 super (Image , self ).__init__ ()
2126 self ._blob = blob
2227 self ._filename = filename
2328 self ._image_header = image_header
2429
2530 @classmethod
26- def from_blob (cls , blob ) :
31+ def from_blob (cls , blob : bytes ) -> Self :
2732 """Return a new |Image| subclass instance parsed from the image binary contained
2833 in `blob`."""
2934 stream = io .BytesIO (blob )
@@ -73,60 +78,66 @@ def filename(self):
7378 return self ._filename
7479
7580 @property
76- def px_width (self ):
81+ def px_width (self ) -> int :
7782 """The horizontal pixel dimension of the image."""
7883 return self ._image_header .px_width
7984
8085 @property
81- def px_height (self ):
86+ def px_height (self ) -> int :
8287 """The vertical pixel dimension of the image."""
8388 return self ._image_header .px_height
8489
8590 @property
86- def horz_dpi (self ):
91+ def horz_dpi (self ) -> int :
8792 """Integer dots per inch for the width of this image.
8893
8994 Defaults to 72 when not present in the file, as is often the case.
9095 """
9196 return self ._image_header .horz_dpi
9297
9398 @property
94- def vert_dpi (self ):
99+ def vert_dpi (self ) -> int :
95100 """Integer dots per inch for the height of this image.
96101
97102 Defaults to 72 when not present in the file, as is often the case.
98103 """
99104 return self ._image_header .vert_dpi
100105
101106 @property
102- def width (self ):
107+ def width (self ) -> Inches :
103108 """A |Length| value representing the native width of the image, calculated from
104109 the values of `px_width` and `horz_dpi`."""
105110 return Inches (self .px_width / self .horz_dpi )
106111
107112 @property
108- def height (self ):
113+ def height (self ) -> Inches :
109114 """A |Length| value representing the native height of the image, calculated from
110115 the values of `px_height` and `vert_dpi`."""
111116 return Inches (self .px_height / self .vert_dpi )
112117
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 image 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.
125135 """
126136 if width is None and height is None :
127137 return self .width , self .height
128138
129139 if width is None :
140+ assert height is not None
130141 scaling_factor = float (height ) / float (self .height )
131142 width = round (self .width * scaling_factor )
132143
@@ -142,7 +153,12 @@ def sha1(self):
142153 return hashlib .sha1 (self ._blob ).hexdigest ()
143154
144155 @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 :
146162 """Return an instance of the |Image| subclass corresponding to the format of the
147163 image in `stream`."""
148164 image_header = _ImageHeaderFactory (stream )
0 commit comments