@@ -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]
@@ -947,10 +952,18 @@ def _apply_alpha(
947952 img , x_object , obj_as_text , image_format , extension
948953 )
949954
955+ if pillow_parameters is None :
956+ pillow_parameters = {}
957+ # Preserve JPEG image quality - see issue #3515.
958+ if image_format == "JPEG" and "quality" not in pillow_parameters :
959+ pillow_parameters ["quality" ] = "keep"
960+ # This prevent: Cannot use 'keep' when original image is not a JPEG:
961+ img .format = image_format # type: ignore
962+
950963 # Save image to bytes
951964 img_byte_arr = BytesIO ()
952965 try :
953- img .save (img_byte_arr , format = image_format )
966+ img .save (img_byte_arr , format = image_format , ** pillow_parameters )
954967 except OSError : # pragma: no cover # covered with pillow 10.3
955968 # in case of we convert to RGBA and then to PNG
956969 img1 = img .convert ("RGBA" )
0 commit comments