diff --git a/README.md b/README.md index be53728..7b279b0 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,11 @@ __Note:__ To use this feature, you'll also need to have two additional pieces of ### Creating a `PageImage` with `.to_image()` -To turn any page (including cropped pages) into an `PageImage` object, call `my_page.to_image()`. You can optionally pass a `resolution={integer}` keyword argument, which defaults to 72. E.g.: +To turn any page (including cropped pages) into an `PageImage` object, call `my_page.to_image()`. You can optionally pass *one* of the following keyword arguments: + +- `resolution`: The desired number pixels per inch. Defaults to 72. +- `width`: The desired image width in pixels. +- `height`: The desired image width in pixels. ```python im = my_pdf.pages[0].to_image(resolution=150) diff --git a/pdfplumber/display.py b/pdfplumber/display.py index d8ba249..18f0ee5 100644 --- a/pdfplumber/display.py +++ b/pdfplumber/display.py @@ -34,7 +34,7 @@ T_contains_points = Union[Tuple[T_point, ...], List[T_point], T_obj] def get_page_image( - stream: Union[BufferedReader, BytesIO], page_no: int, resolution: int + stream: Union[BufferedReader, BytesIO], page_no: int, resolution: Union[int, float] ) -> WandImage: # If we are working with a file object saved to disk if hasattr(stream, "name"): @@ -88,7 +88,7 @@ class PageImage: self, page: "Page", original: Optional[WandImage] = None, - resolution: int = DEFAULT_RESOLUTION, + resolution: Union[int, float] = DEFAULT_RESOLUTION, ): self.page = page if original is None: diff --git a/pdfplumber/page.py b/pdfplumber/page.py index 2233af6..6b2f495 100644 --- a/pdfplumber/page.py +++ b/pdfplumber/page.py @@ -362,13 +362,30 @@ class Page(Container): p._objects["char"] = utils.dedupe_chars(self.chars, **kwargs) return p - def to_image(self, resolution: Optional[int] = None) -> "PageImage": + def to_image( + self, + resolution: Optional[Union[int, float]] = None, + width: Optional[Union[int, float]] = None, + height: Optional[Union[int, float]] = None, + ) -> "PageImage": """ - For conversion_kwargs, see: - http://docs.wand-py.org/en/latest/wand/image.html#wand.image.Image + You can pass a maximum of 1 of the following: + - resolution: The desired number pixels per inch. Defaults to 72. + - width: The desired image width in pixels. + - height: The desired image width in pixels. """ from .display import DEFAULT_RESOLUTION, PageImage + num_specs = sum(x is not None for x in [resolution, width, height]) + if num_specs > 1: + raise ValueError( + f"Only one of these arguments can be provided: resolution, width, height. You provided {num_specs}" # noqa: E501 + ) + elif width is not None: + resolution = 72 * width / self.width + elif height is not None: + resolution = 72 * height / self.height + return PageImage(self, resolution=resolution or DEFAULT_RESOLUTION) def to_dict(self, object_types: Optional[List[str]] = None) -> Dict[str, Any]: diff --git a/tests/test_display.py b/tests/test_display.py index 84d2072..52b53a1 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -34,6 +34,17 @@ class Test(unittest.TestCase): self.im.draw_vlines([10]) self.im.draw_hlines([10]) + def test_width_height(self): + p = self.pdf.pages[0] + with pytest.raises(ValueError): + p.to_image(resolution=72, height=100) + + im = p.to_image(width=503) + assert im.original.width == 503 + + im = p.to_image(height=805) + assert im.original.height == 805 + def test_debug_tablefinder(self): self.im.reset() settings = {"horizontal_strategy": "text", "intersection_tolerance": 5}