折腾:
【未解决】Python中实现二进制数据的图片的压缩
期间,此处已经可以压缩图片:
【已解决】Python的Pillow中如何压缩缩放图片且保持原图宽高比例
了,然后希望拿到压缩后图片的二进制数据。
Image.tobytes(encoder_name=’raw’, *args)[source]
好像这个可以?
”This method returns the raw image data from the internal storage. For compressed image data (e.g. PNG, JPEG) use save(), with a BytesIO parameter for in-memory data.“
去看看save
但是保存参数只支持fp,不支持binary
python pillow get image binary data
python pillow image output to binary data
用这个好像可以?
”The img object needs to be saved again; write it to another BytesIO object:
output = io.BytesIO()
img.save(output, format=’JPEG’)
then get the written data with the .getvalue() method:
hex_data = output.getvalue()”
好像就是
去写代码试试
fileBytes = fileObj.read() log.debug("len(fileBytes)=%s", len(fileBytes)) if fileType == MongoFileType.IMAGE.value: imageFile = Image.open(fileBytes)
结果报错:
imageFile = Image.open(fileBytes) File "/Users/crifan/.local/share/virtualenvs/EvaluationSystemServer-6RbmF4Wj/lib/python3.6/site-packages/PIL/Image.py", line 2609, in open fp = builtins.open(filename, "rb") ValueError: embedded null byte
换成:
imageStream = io.BytesIO(fileBytes) imageFile = Image.open(imageStream)
就可以了:

输出:
len(fileBytes)=427306 imageFile=<PIL.PngImagePlugin.PngImageFile image mode=RGBA size=3543x3543 at 0x10615C5C0>
结果代码:
fileBytes = fileObj.read() log.debug("len(fileBytes)=%s", len(fileBytes)) if fileType == MongoFileType.IMAGE.value: imageStream = io.BytesIO(fileBytes) imageFile = Image.open(imageStream) log.debug("imageFile=%s", imageFile) log.debug("imageFile.size=%s", imageFile.size) imageFile.thumbnail(IMAGE_COMPRESS_SIZE, Image.ANTIALIAS) log.debug("imageFile=%s", imageFile) imageOutput = io.BytesIO() log.debug("imageOutput=%s", imageOutput) imageFile.save(imageOutput) log.debug("imageFile=%s", imageFile) compressedImageBytes = imageOutput.getvalue() log.debug("compressedImageBytes=%s", compressedImageBytes) log.debug("len(compressedImageBytes)=%s", len(compressedImageBytes)) fileBytes = compressedImageBytes
中的
imageFile.save(imageOutput)
还是出错:
imageFile.save(imageOutput) File "/Users/crifan/.local/share/virtualenvs/EvaluationSystemServer-6RbmF4Wj/lib/python3.6/site-packages/PIL/Image.py", line 1951, in save raise ValueError('unknown file extension: {}'.format(ext)) ValueError: unknown file extension:
试试
“For Python3 it is required to use BytesIO:”
搜:
python3-flask-pil-in-memory-image
试试:StringIO()
先去试试:
的BytesIO,好像已经是了
难道是缺少设置后缀?
去加上后缀
以及去看看save参数
好像不支持把JPEG写成JPG?
后续试试
才看到:
“* format – Optional format override. If omitted, the format to use is determined from the filename extension. If a file object was used instead of a filename, this parameter should always be used.”
-》此处是Byte,不是filename,没有suffix,所以必要要传递format参数才对
加了后缀:
imageSuffix = fileObj.filename.split(".")[-1] # png log.debug("imageSuffix=%s", imageSuffix) imageFormat = imageSuffix.upper() # PNG log.debug("imageFormat=%s", imageFormat) # imageFile.save(imageOutput) imageFile.save(imageOutput, imageFormat)
果然可以了。
【总结】
最后用代码:
imageOutput = io.BytesIO() log.debug("imageOutput=%s", imageOutput) imageSuffix = fileObj.filename.split(".")[-1] # png log.debug("imageSuffix=%s", imageSuffix) imageFormat = imageSuffix.upper() # PNG if imageFormat == "JPG": imageFormat = "JPEG" log.debug("imageFormat=%s", imageFormat) # imageFile.save(imageOutput) imageFile.save(imageOutput, imageFormat) log.debug("imageFile=%s", imageFile) log.debug("imageFile.size=%s", imageFile.size) compressedImageBytes = imageOutput.getvalue()
实现了要的效果:
可以把压缩后的图片保存成二进制数据了:

其中二进制数据中可以看到PNG
其中:
- 对于png图片,设置格式为PNG
- 对于JPG图片,设置格式为JPEG
- 对应的说明都在
- Image file formats — Pillow (PIL Fork) 5.3.0 documentation
- https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
【后记】
看到:
的评论中说
image.save(output, format=image.format)
看来是Image有format属性-》那就可以直接用,不需要从文件后缀去得到格式了。
去试试
从官网解释:
“PIL.Image.format
The file format of the source file. For images created by the library itself (via a factory function, or by running a method on an existing image), this attribute is set to None.
Type:
string or None”
很明显:
此处从binary data输入的image,此处format应该是None
resize后的image的info是:

然后format是有的:


即:此处从binary的byte从读入的Image,是可以解析出来format是PNG的:
同时可见解析后的对象已经是:
<PIL.PngImagePlugin.PngImageFile image mode=RGBA size=3543×3543 at 0x1065F7A20>
了,就已经表示是PNG格式了。
所以去优化代码,用format即可。
outputImageFormat = None if outputFormat: outputImageFormat = outputFormat elif imageFile.format: outputImageFormat = imageFile.format imageFile.save(imageOutput, outputImageFormat)
是可以的:

再去看看对于jpeg图片能否检测出format:

也是可以的。
更新后的代码是:
imageFile.thumbnail(newSize, resample) # 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() log.debug("len(compressedImageBytes)=%s", len(compressedImageBytes)) return compressedImageBytes
【后记2】
从:
也可以看到对应的函数的解释了:
“class io.BytesIO([initial_bytes])
A stream implementation using an in-memory bytes buffer. It inherits BufferedIOBase. The buffer is discarded when the close() method is called.
The optional argument initial_bytes is a bytes-like object that contains initial data.
BytesIO provides or overrides these methods in addition to those from BufferedIOBase and IOBase:
getvalue()
Return bytes containing the entire contents of the buffer.”
转载请注明:在路上 » 【已解决】Python的Pillow如何返回图像的二进制数据