diff --git a/html2docx/image.py b/html2docx/image.py index a8465aa..bedbc32 100644 --- a/html2docx/image.py +++ b/html2docx/image.py @@ -16,6 +16,7 @@ # In LibreOffice, the maximum height for an image is capped to USABLE_HEIGHT. USABLE_HEIGHT = Inches(8.1) USABLE_WIDTH = Inches(5.8) +DEFAULT_DPI = 72 MAX_IMAGE_SIZE = 10 * 1024 * 1024 # 10 MiB @@ -104,11 +105,23 @@ def image_size( """ image = Image.from_blob(image_buffer.getbuffer()) - height = image.px_height if height_px is None else height_px - width = image.px_width if width_px is None else width_px + # Normalize image size to inches. + # - Without a specified pixel size, images are their actual pixel size, so that + # images of the same pixel size appear the same size in the document, regardless + # of their resolution. + # - With a specified pixel size, images should take the specified size, regardless + # of their resolution. + if height_px is None: + height = image.px_height / image.vert_dpi + else: + height = height_px / DEFAULT_DPI + if width_px is None: + width = image.px_width / image.horz_dpi + else: + width = width_px / DEFAULT_DPI - height = Inches(height / image.vert_dpi) - width = Inches(width / image.horz_dpi) + height = Inches(height) + width = Inches(width) size = {} if width > USABLE_WIDTH: diff --git a/tests/data/img_height.json b/tests/data/img_height.json index 182d0c7..631469e 100644 --- a/tests/data/img_height.json +++ b/tests/data/img_height.json @@ -7,8 +7,8 @@ "shapes": [ { "type": 3, - "width": 2857500, - "height": 2857500 + "width": 3810000, + "height": 3810000 } ] } diff --git a/tests/data/img_ratio.json b/tests/data/img_ratio.json index 9f09d34..c901760 100644 --- a/tests/data/img_ratio.json +++ b/tests/data/img_ratio.json @@ -7,8 +7,8 @@ "shapes": [ { "type": 3, - "width": 190500, - "height": 95250 + "width": 254000, + "height": 127000 } ] } diff --git a/tests/data/img_width.json b/tests/data/img_width.json index 182d0c7..631469e 100644 --- a/tests/data/img_width.json +++ b/tests/data/img_width.json @@ -7,8 +7,8 @@ "shapes": [ { "type": 3, - "width": 2857500, - "height": 2857500 + "width": 3810000, + "height": 3810000 } ] } diff --git a/tests/test_image_size.py b/tests/test_image_size.py index 6f663fd..71a936d 100644 --- a/tests/test_image_size.py +++ b/tests/test_image_size.py @@ -2,19 +2,19 @@ from docx.shared import Inches -from html2docx.image import USABLE_HEIGHT, USABLE_WIDTH, image_size +from html2docx.image import DEFAULT_DPI, USABLE_HEIGHT, USABLE_WIDTH, image_size -from .utils import DPI, PROJECT_DIR, generate_image +from .utils import PROJECT_DIR, generate_image broken_image = PROJECT_DIR / "html2docx" / "image-broken.png" broken_image_bytes = broken_image.read_bytes() -def inches_to_px(inches: int, dpi: int = DPI) -> int: +def inches_to_px(inches: int, dpi: int = DEFAULT_DPI) -> int: return ceil(inches / Inches(1) * dpi) -def px_to_inches(px: int, dpi: int = DPI) -> int: +def px_to_inches(px: int, dpi: int = DEFAULT_DPI) -> int: return ceil(px * Inches(1) / dpi) @@ -77,15 +77,29 @@ def test_resize_exceeds_height(): assert size == {"height": USABLE_HEIGHT} -def test_dpi_width(): +def test_no_pixel_size_uses_dpi_width(): width_px = inches_to_px(USABLE_WIDTH, 300) image = generate_image(width=width_px, height=1, dpi=(300, 300)) size = image_size(image) assert size == {} -def test_dpi_height(): +def test_no_pixel_size_uses_dpi_height(): height_px = inches_to_px(USABLE_HEIGHT, 300) image = generate_image(width=1, height=height_px, dpi=(300, 300)) size = image_size(image) assert size == {} + + +def test_pixel_size_specified_ignores_dpi_width(): + width_px = inches_to_px(Inches(1)) + image = generate_image(width=width_px, height=1, dpi=(300, 300)) + size = image_size(image, width_px=width_px) + assert size == {"width": Inches(1)} + + +def test_pixel_size_specified_ignores_dpi_height(): + height_px = inches_to_px(Inches(1)) + image = generate_image(width=1, height=height_px, dpi=(300, 300)) + size = image_size(image, height_px=height_px) + assert size == {"height": Inches(1)} diff --git a/tests/utils.py b/tests/utils.py index 13b9df8..3c22b0d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -3,12 +3,13 @@ from PIL import Image +from html2docx.image import DEFAULT_DPI + TEST_DIR = pathlib.Path(__file__).parent.resolve(strict=True) PROJECT_DIR = TEST_DIR.parent -DPI = 72 -def generate_image(width: int, height: int, dpi=(DPI, DPI)) -> BytesIO: +def generate_image(width: int, height: int, dpi=(DEFAULT_DPI, DEFAULT_DPI)) -> BytesIO: data = BytesIO() with Image.new("L", (width, height)) as image: image.save(data, format="png", dpi=dpi)