图像转换 - 无法将RGBA模式写入JPEG

15

我想在项目上传之前调整并降低图像的大小和质量。 这是我尝试过的方法:

def save(self):
    im = Image.open(self.image)
    output = BytesIO()
    im = im.resize(240, 240)
    im.save(output, format='JPEG', quality=95)
    output.seek(0)
    self.image = InMemoryUploadedFile(output, 'ImageField', "%s.jpg" % self.image.name.split('.')[0], 'image/jpeg', sys.getsizeof(output), None)
    super(Model, self).save()

如果我上传jpg图像,它可以正常工作,但如果我上传png或任何其他类型的图像,则无法工作,会出现错误,如cannot write mode RGBA as JPEGcannot write mode P as JPEG等。

我们该如何解决这个问题呢?谢谢!


@Teemu先生,每当我上传jpg图像时,它都可以正常工作,但如果我上传其他类型的图像,则会引发错误。我们如何将图像类型更改为jpg,以便它可以正常工作。我是新来的,所以我不小心添加了JavaScriptPHP,我已经将它们删除 :) - user9203538
我不熟悉Python,但是“无法将RGBA模式写入JPEG”听起来只有在jpg格式下才有道理..? - Teemu
@Teemu 先生,当我上传一个 png 图像时出现了这个错误。 - user9203538
2个回答

32

如果你的图像模式是 "P" 或 "RGBA",并且你想将它转换为jpeg格式,那么你需要先将 image.mode 转换,因为之前的模式不支持jpeg格式。

if im.mode in ("RGBA", "P"):
    im = im.convert("RGB")

https://github.com/python-pillow/Pillow/issues/2609


4

摘要timop2

  • backgroud

    • JPG not support alpha = transparency
    • RGBA, P has alpha = transparency
      • RGBA= Red Green Blue Alpha
  • result

    • cannot write mode RGBA as JPEG
    • cannot write mode P as JPEG
  • solution

    • before save to JPG, discard alpha = transparency
      • such as: convert Image to RGB
    • then save to JPG
  • your code

    if im.mode == "JPEG":
        im.save(output, format='JPEG', quality=95)
    elif im.mode in ["RGBA", "P"]:
        im = im.convert("RGB")
        im.save(output, format='JPEG', quality=95)
    
  • More for you:

关于 调整大小并降低图像质量,我已经实现了一个函数供您(和其他人)参考:

from PIL import Image, ImageDraw
cfgDefaultImageResample = Image.BICUBIC # Image.LANCZOS

def resizeImage(inputImage,
                newSize,
                resample=cfgDefaultImageResample,
                outputFormat=None,
                outputImageFile=None
                ):
    """
        resize input image
        resize normally means become smaller, reduce size
    :param inputImage: image file object(fp) / filename / binary bytes
    :param newSize: (width, height)
    :param resample: PIL.Image.NEAREST, PIL.Image.BILINEAR, PIL.Image.BICUBIC, or PIL.Image.LANCZOS
        https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.thumbnail
    :param outputFormat: PNG/JPEG/BMP/GIF/TIFF/WebP/..., more refer:
        https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
        if input image is filename with suffix, can omit this -> will infer from filename suffix
    :param outputImageFile: output image file filename
    :return:
        input image file filename: output resized image to outputImageFile
        input image binary bytes: resized image binary bytes
    """
    openableImage = None
    if isinstance(inputImage, str):
        openableImage = inputImage
    elif CommonUtils.isFileObject(inputImage):
        openableImage = inputImage
    elif isinstance(inputImage, bytes):
        inputImageLen = len(inputImage)
        openableImage = io.BytesIO(inputImage)

    if openableImage:
        imageFile = Image.open(openableImage)
    elif isinstance(inputImage, Image.Image):
        imageFile = inputImage
    # <PIL.PngImagePlugin.PngImageFile image mode=RGBA size=3543x3543 at 0x1065F7A20>
    imageFile.thumbnail(newSize, resample)
    if outputImageFile:
        # save to file
        imageFile.save(outputImageFile)
        imageFile.close()
    else:
        # save and return binary byte
        imageOutput = io.BytesIO()
        # imageFile.save(imageOutput)
        outputImageFormat = None
        if outputFormat:
            outputImageFormat = outputFormat
        elif imageFile.format:
            outputImageFormat = imageFile.format
        imageFile.save(imageOutput, outputImageFormat)
        imageFile.close()
        compressedImageBytes = imageOutput.getvalue()
        compressedImageLen = len(compressedImageBytes)
        compressRatio = float(compressedImageLen)/float(inputImageLen)
        print("%s -> %s, resize ratio: %d%%" % (inputImageLen, compressedImageLen, int(compressRatio * 100)))
        return compressedImageBytes

最新的代码可以在这里找到:

https://github.com/crifan/crifanLibPython/blob/master/crifanLib/crifanMultimedia.py


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接