@@ -791,15 +791,20 @@ def decode_stream_data(stream: Any) -> bytes:
791791 return data
792792
793793
794- def _xobj_to_image (x_object : dict [str , Any ]) -> tuple [Optional [str ], bytes , Any ]:
794+ def _xobj_to_image (
795+ x_object : dict [str , Any ],
796+ pillow_parameters : Union [dict [str , Any ], None ] = None
797+ ) -> tuple [Optional [str ], bytes , Any ]:
795798 """
796799 Users need to have the pillow package installed.
797800
798801 It's unclear if pypdf will keep this function here, hence it's private.
799802 It might get removed at any point.
800803
801804 Args:
802- x_object:
805+ x_object:
806+ pillow_parameters: parameters provided to Pillow Image.save() method,
807+ cf. <https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.save>
803808
804809 Returns:
805810 Tuple[file extension, bytes, PIL.Image.Image]
@@ -846,6 +851,9 @@ def _apply_alpha(
846851 extension = ".png"
847852 return img , extension , image_format
848853
854+ if pillow_parameters is None :
855+ pillow_parameters = {}
856+
849857 # For error reporting
850858 obj_as_text = (
851859 x_object .indirect_reference .__repr__ ()
@@ -947,10 +955,14 @@ def _apply_alpha(
947955 img , x_object , obj_as_text , image_format , extension
948956 )
949957
958+ # Preserver JPEG image quality - cf. https://github.com/py-pdf/pypdf/issues/3515
959+ if image_format == "JPEG" and "quality" not in pillow_parameters :
960+ pillow_parameters ["quality" ] = "keep"
961+
950962 # Save image to bytes
951963 img_byte_arr = BytesIO ()
952964 try :
953- img .save (img_byte_arr , format = image_format )
965+ img .save (img_byte_arr , format = image_format , ** pillow_parameters )
954966 except OSError : # pragma: no cover # covered with pillow 10.3
955967 # in case of we convert to RGBA and then to PNG
956968 img1 = img .convert ("RGBA" )
0 commit comments