img2pdf AlphaChannelError: what is the best way to remove alphachannel
img2pdf AlphaChannelError: what is the best way to remove alphachannel
我有一组图像,我通过以下代码从中创建 pdf
with io.BytesIO() as tmp_io:
tmp_io.write(img2pdf.convert(img_file_paths))
result_bytes = tmp_io.getvalue()
其中一个文件包含 alpha 通道,我得到了
raise AlphaChannelError("Refusing to work on images with alpha channel")
删除 alpha 通道并保存为 pdf rgb 通道的最简单方法是什么?
这是我自己的有点难看的解决方案
def remove_alpha_from_image(image_path):
im = Image.open(image_path)
im.load()
try:
background = Image.new("RGB", im.size, (255, 255, 255))
background.paste(im, mask=im.split()[3]) # 3 is the alpha channel
im = background
except IndexError: # img is not RGBA
pass
name_hash_md5 = md5(bytes(image_path, encoding="utf-8")) # noqa: S303
name = name_hash_md5.hexdigest()
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
path = f"{TMP_DIR}{name}.pdf"
im.save(path, "PNG", resolution=100.0)
return path
with io.BytesIO() as tmp_io:
try:
tmp_io.write(img2pdf.convert(file_paths))
except img2pdf.AlphaChannelError:
tmp_io.write(img2pdf.convert([remove_alpha_from_image(path) for path in file_paths]))
result_bytes = tmp_io.getvalue()
这是我组装的一个实用程序 - 只在一个应用程序中测试过,所以不确定它的通用性如何,但应该是交钥匙的。在 python 3.9
中测试
def image2pdf(image: bytes or str, allow_lossy=True, **rgba_to_kwds) -> bytes:
"""
Converts an image to PDF, optionally allowing for lossy conversion.
:param image: if non RGBA image, this can be any valid input to img2pdf. If RGBA, then must be str (ie. path to image)
or bytes representation of image.
:param allow_lossy: if img2pdf.convert fails with AlphaChannelError, tries to downsample
:param rgba_to_kwds: kwds to _rgba_to
:return: bytes representation of PDF image. To save to disk
pdfBytes=image2pdf(someImage)
with open('converted.pdf', 'w') as f:
f.write(pdfBytes)
"""
try:
pdf_bytes = img2pdf.convert(image)
except img2pdf.AlphaChannelError as alphaError:
if allow_lossy:
rgbBytes = _rgba_to(image)
pdf_bytes = img2pdf.convert(rgbBytes, **rgba_to_kwds)
else:
raise alphaError
return pdf_bytes
def _rgba_to(image: bytes or str, to='RGB', intermediate='PNG') -> bytes:
logging.warning(f"Image has alpha channel... downsampling (newtype={to}, intermediate={intermediate}) and converting")
# Image is a filepath
if isinstance(image, str):
img = Image.open(image)
converted: Image = img.convert(to)
# Image is a bytestream
elif isinstance(image, bytes):
buffered = io.BytesIO(image)
img = Image.open(buffered)
converted: Image = img.convert(to)
else:
raise Exception(f"rgba downsampling only supported for images of type str (ie. filepath) or bytes - got {type(image)}")
buf = io.BytesIO()
converted.save(buf, format=intermediate)
byte_im = buf.getvalue()
return byte_im
def test_convert_png_image_with_alphachannel_to_pdf():
img_path = "some-rgba-image.png"
pdf_bytes = image2pdf(img_path)
# Uncomment if want to view the pdf
with open('converted.pdf', "wb") as f:
f.write(pdf_bytes)
我有一组图像,我通过以下代码从中创建 pdf
with io.BytesIO() as tmp_io:
tmp_io.write(img2pdf.convert(img_file_paths))
result_bytes = tmp_io.getvalue()
其中一个文件包含 alpha 通道,我得到了
raise AlphaChannelError("Refusing to work on images with alpha channel")
删除 alpha 通道并保存为 pdf rgb 通道的最简单方法是什么?
这是我自己的有点难看的解决方案
def remove_alpha_from_image(image_path):
im = Image.open(image_path)
im.load()
try:
background = Image.new("RGB", im.size, (255, 255, 255))
background.paste(im, mask=im.split()[3]) # 3 is the alpha channel
im = background
except IndexError: # img is not RGBA
pass
name_hash_md5 = md5(bytes(image_path, encoding="utf-8")) # noqa: S303
name = name_hash_md5.hexdigest()
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
path = f"{TMP_DIR}{name}.pdf"
im.save(path, "PNG", resolution=100.0)
return path
with io.BytesIO() as tmp_io:
try:
tmp_io.write(img2pdf.convert(file_paths))
except img2pdf.AlphaChannelError:
tmp_io.write(img2pdf.convert([remove_alpha_from_image(path) for path in file_paths]))
result_bytes = tmp_io.getvalue()
这是我组装的一个实用程序 - 只在一个应用程序中测试过,所以不确定它的通用性如何,但应该是交钥匙的。在 python 3.9
中测试def image2pdf(image: bytes or str, allow_lossy=True, **rgba_to_kwds) -> bytes:
"""
Converts an image to PDF, optionally allowing for lossy conversion.
:param image: if non RGBA image, this can be any valid input to img2pdf. If RGBA, then must be str (ie. path to image)
or bytes representation of image.
:param allow_lossy: if img2pdf.convert fails with AlphaChannelError, tries to downsample
:param rgba_to_kwds: kwds to _rgba_to
:return: bytes representation of PDF image. To save to disk
pdfBytes=image2pdf(someImage)
with open('converted.pdf', 'w') as f:
f.write(pdfBytes)
"""
try:
pdf_bytes = img2pdf.convert(image)
except img2pdf.AlphaChannelError as alphaError:
if allow_lossy:
rgbBytes = _rgba_to(image)
pdf_bytes = img2pdf.convert(rgbBytes, **rgba_to_kwds)
else:
raise alphaError
return pdf_bytes
def _rgba_to(image: bytes or str, to='RGB', intermediate='PNG') -> bytes:
logging.warning(f"Image has alpha channel... downsampling (newtype={to}, intermediate={intermediate}) and converting")
# Image is a filepath
if isinstance(image, str):
img = Image.open(image)
converted: Image = img.convert(to)
# Image is a bytestream
elif isinstance(image, bytes):
buffered = io.BytesIO(image)
img = Image.open(buffered)
converted: Image = img.convert(to)
else:
raise Exception(f"rgba downsampling only supported for images of type str (ie. filepath) or bytes - got {type(image)}")
buf = io.BytesIO()
converted.save(buf, format=intermediate)
byte_im = buf.getvalue()
return byte_im
def test_convert_png_image_with_alphachannel_to_pdf(): img_path = "some-rgba-image.png" pdf_bytes = image2pdf(img_path)
# Uncomment if want to view the pdf
with open('converted.pdf', "wb") as f:
f.write(pdf_bytes)