JPG 还是 PNG 和内存结构有关系吗?还是只是保存到硬盘的时候,才有区别?

JPG 还是 PNG 和内存结构有关系吗?还是只是保存到硬盘的时候,才有区别?

我最近在使用 selenium 做一个网页自动截屏的服务, 保存的截图需要保存为 jpg 文件

有两个相关的 api

selenium/webdriver/remote/webdriver.py

    def get_screenshot_as_png(self) -> bytes:

"""

Gets the screenshot of the current window as a binary data.

:Usage:

::

driver.get_screenshot_as_png()

"""

return b64decode(self.get_screenshot_as_base64().encode('ascii'))

def get_screenshot_as_base64(self) -> str:

"""

Gets the screenshot of the current window as a base64 encoded string

which is useful in embedded images in HTML.

:Usage:

::

driver.get_screenshot_as_base64()

"""

return self.execute(Command.SCREENSHOT)['value']

一个是 get_screenshot_as_png,另一个是 get_screenshot_as_base64

get_screenshot_as_png 中也是调用了 get_screenshot_as_base64

我就有问题了,这里的 get_screenshot_as_png 就是对 get_screenshot_as_base64 的结果做了简单的 decodeencode

这样就得到 PNG 了?那我怎么的到 JPG 呢?

难道 get_screenshot_as_base64 返回的 base64 其实就是 PNG 编解码后的 base64?

我本来想的是,图片都是三维矩阵,只有在保存到硬盘的时候,才分 pngjpg这些,是这样的吗?

还是说因为 PNG 是无损的,所以简单的编解码就好了,JPG 要有损压缩,才需要后续特殊处理?


回答:

自己解决了

我的需求:我会获得 png 的 stream (type 为 bytes),我要把 png 上传到 oss,但是 png 太大了,就像转成 jpg 再上传到 oss 中

但是,简中互联网上的教程都是,教你怎么把『内存中的 png』 变成 『硬盘上的 jpg』

这是非常愚蠢的!

我需要的是:『内存中的 png』 变成 『内存中的 jpg』

简单的来讲,就是我希望,使用 python 把 png 转成 jpg 并压缩这个过程全程发生在 RAM 中,而不涉及任何硬盘读写

所以,我写了下面的代码:

import unittest

from loguru import logger

from mark import BASE_DIR

from pathlib import Path

from PIL import Image

from PIL.Image import Image as PIL_Image

import sys

import io

def png_stream_2_png_image(png_stream: bytes) -> PIL_Image:

file_like_obj = io.BytesIO(png_stream)

png_image = Image.open(file_like_obj)

return png_image

def png_image_2_jpg_stream(png_image: PIL_Image, quality=100) -> bytes:

assert png_image.format == 'PNG'

file_like_obj = io.BytesIO()

png_image = png_image.convert('RGB') # PNG 是 RGBA,多了一个透明通道,JPG不支持透明通道

png_image.save(file_like_obj, format='JPEG', quality=quality)

stream = file_like_obj.getvalue()

return stream

def png_stream_2_jpg_stream(png_stream: bytes, quality=100) -> bytes:

"""

png_stream into png_imgae

png_imgae into jpg_stream

"""

png_image = png_stream_2_png_image(png_stream)

jpg_stream = png_image_2_jpg_stream(png_image, quality)

return jpg_stream

def png_image_2_png_stream(png_image: PIL_Image) -> bytes:

assert png_image.format == 'PNG'

file_like_obj = io.BytesIO()

png_image.save(file_like_obj, format='PNG')

stream = file_like_obj.getvalue()

return stream

class TestCompress(unittest.TestCase):

def test_compress_on_memory_2(self):

"""

python -m unittest testing.test_compress.TestCompress.test_compress_on_memory_2

"""

src_file_path = BASE_DIR/'static/img/94dcb906ff774e7ab4d6e8b1abcc147b.jpg'

png_image = Image.open(src_file_path)

png_stream = png_image_2_png_stream(png_image)

jpg_stream = png_image_2_jpg_stream(png_image, quality=50)

# logger.debug(png_stream)

logger.debug(type(png_stream))

logger.debug(len(png_stream))

logger.debug(type(jpg_stream))

logger.debug(len(jpg_stream))

logger.debug(f'压缩比: {round(len(jpg_stream)/len(png_stream)*100)}%')

输出结果如下:

─➤  python -m unittest testing.test_compress.TestCompress.test_compress_on_memory_2

2022-07-15 13:05:31.375 | DEBUG | testing.test_compress:test_compress_on_memory_2:59 - <class 'bytes'>

2022-07-15 13:05:31.375 | DEBUG | testing.test_compress:test_compress_on_memory_2:60 - 1075380

2022-07-15 13:05:31.375 | DEBUG | testing.test_compress:test_compress_on_memory_2:62 - <class 'bytes'>

2022-07-15 13:05:31.375 | DEBUG | testing.test_compress:test_compress_on_memory_2:63 - 172836

2022-07-15 13:05:31.375 | DEBUG | testing.test_compress:test_compress_on_memory_2:65 - 压缩比: 16%


回答:

JPG 和 PNG 是两种编码,需要 JPG 的话自己转换一下。

from PIL import Image

im = Image.open("in.jpg")

rgb_im = im.convert('RGB')

rgb_im.save('out.jpg')


回答:

比如1920×1080的图片,在内存里一般都是一个1920×1080×3的字节数组,也可能是1920×1080×4(包含透明通道的话)。
3代表的是rgb三通道,每个像素由rgb三通道决定,它们取值在0-255之间。 而且一般不用三维矩阵,比如opencv中就使用一维数组去保存图片,类似第一个像素点是a[0] a[1] a[2], 第二个像素点是a[3] a[4] a[5]。

当需要保存到磁盘时,为了解决存储空间,才会以png/jpg等格式编码压缩大小。

b64decode(self.get_screenshot_as_base64().encode('ascii'))

上边这一行,返回值是字节数组,应该和png/jpg格式无关才对。你可以看一下返回的字节数组的长度,如果能被1920 * 1080(屏幕分辨率)整除,应该就是和png/jpg格式无关。


回答:

图片要显示,在内存中为了方便直接显示,一般都是解码开的图形数据啦,这可以认为无压缩的原始数据,只有在保存为图片格式时才进行编码保存。

你想要保存为jpg,可以png转jpg格式,这个有第三方库支持的。

以上是 JPG 还是 PNG 和内存结构有关系吗?还是只是保存到硬盘的时候,才有区别? 的全部内容, 来源链接: utcz.com/p/938508.html

回到顶部