据我所知,您可以通过以下方式使用PIL获取图像大小
from PIL import Image
im = Image.open(image_filename)
width, height = im.size
但是,我希望获得图像的宽度和高度,而不必将图像加载到内存中。可能吗?我只做图像大小的统计,不关心图像内容。我只是想让我的处理速度更快。
pypi上有一个名为imagesize
的包,目前对我有效,尽管它看起来不是很活跃。
安装:
pip install imagesize
用法:
import imagesize
width, height = imagesize.get("test.png")
print(width, height)
主页:https://github.com/shibukawa/imagesize_py
PyPi:https://pypi.org/project/imagesize/
正如注释所暗示的,当调用. open
时,PIL不会将图像加载到内存中。查看PIL 1.1.7
的文档,. open
的文档字符串如下:
def open(fp, mode="r"):
"Open an image file, without loading the raster data"
源代码中有一些文件操作,例如:
...
prefix = fp.read(16)
...
fp.seek(0)
...
但是这些很难构成阅读整个文件。事实上. open
只是返回一个文件对象和成功时的文件名。此外,医生说:
打开(文件,mode=“r”)
打开并标识给定的图像文件。
这是一个懒惰的操作;此函数用于标识文件,但在您尝试处理数据(或调用load方法)之前,不会从文件中读取实际图像数据。
深入研究,我们看到. open
调用_open
,这是特定于图像格式的重载。_open
的每个实现都可以在一个新文件中找到,例如。. jpeg文件位于JpegImagePlugin.py
中。让我们深入看看那个。
在这里,事情似乎变得有点棘手,其中有一个无限循环,当找到jpeg标记时会被打破:
while True:
s = s + self.fp.read(1)
i = i16(s)
if i in MARKER:
name, description, handler = MARKER[i]
# print hex(i), name, description
if handler is not None:
handler(self, i)
if i == 0xFFDA: # start of scan
rawmode = self.mode
if self.mode == "CMYK":
rawmode = "CMYK;I" # assume adobe conventions
self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
# self.__offset = self.fp.tell()
break
s = self.fp.read(1)
elif i == 0 or i == 65535:
# padded marker or junk; move on
s = "\xff"
else:
raise SyntaxError("no marker found")
如果文件格式不正确,它可以读取整个文件。但是,如果它读取信息标记OK,那么它应该提前爆发。函数handler
最终设置图像的尺寸self.size
。
如果你不关心图像内容,PIL可能是一种过度使用。
我建议解析python magic模块的输出:
>>> t = magic.from_file('teste.png')
>>> t
'PNG image data, 782 x 602, 8-bit/color RGBA, non-interlaced'
>>> re.search('(\d+) x (\d+)', t).groups()
('782', '602')
这是一个围绕libMagic的包装器,它读取尽可能少的字节,以识别文件类型签名。
脚本相关版本:
https://raw.githubusercontent.com/scardine/image_size/master/get_image_size.py
[更新]
不幸的是,当应用于JPEG时,上面给出了“JPEG图像数据,EXIF标准2.21”。没有图像大小!–亚历克斯·弗林特
似乎JPEG是抗魔法的。:-)
我可以理解为什么:为了获得JPEG文件的图像尺寸,您可能需要读取比libMagic喜欢读取的更多的字节。
卷起袖子,附带了这个非常未经测试的代码片段(从GitHub获得),它不需要第三方模块。
#-------------------------------------------------------------------------------
# Name: get_image_size
# Purpose: extract image dimensions given a file path using just
# core modules
#
# Author: Paulo Scardine (based on code from Emmanuel VAÏSSE)
#
# Created: 26/09/2013
# Copyright: (c) Paulo Scardine 2013
# Licence: MIT
#-------------------------------------------------------------------------------
#!/usr/bin/env html" target="_blank">python
import os
import struct
class UnknownImageFormat(Exception):
pass
def get_image_size(file_path):
"""
Return (width, height) for a given img file content - no external
dependencies except the os and struct modules from core
"""
size = os.path.getsize(file_path)
with open(file_path) as input:
height = -1
width = -1
data = input.read(25)
if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
# GIFs
w, h = struct.unpack("<HH", data[6:10])
width = int(w)
height = int(h)
elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
and (data[12:16] == 'IHDR')):
# PNGs
w, h = struct.unpack(">LL", data[16:24])
width = int(w)
height = int(h)
elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
# older PNGs?
w, h = struct.unpack(">LL", data[8:16])
width = int(w)
height = int(h)
elif (size >= 2) and data.startswith('\377\330'):
# JPEG
msg = " raised while trying to decode as JPEG."
input.seek(0)
input.read(2)
b = input.read(1)
try:
while (b and ord(b) != 0xDA):
while (ord(b) != 0xFF): b = input.read(1)
while (ord(b) == 0xFF): b = input.read(1)
if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
input.read(3)
h, w = struct.unpack(">HH", input.read(4))
break
else:
input.read(int(struct.unpack(">H", input.read(2))[0])-2)
b = input.read(1)
width = int(w)
height = int(h)
except struct.error:
raise UnknownImageFormat("StructError" + msg)
except ValueError:
raise UnknownImageFormat("ValueError" + msg)
except Exception as e:
raise UnknownImageFormat(e.__class__.__name__ + msg)
else:
raise UnknownImageFormat(
"Sorry, don't know how to get information from this file."
)
return width, height
[更新2019]
查看一个Rust实现:https://github.com/scardine/imsz
目前,我正在用下面的代码做一个非常简单的方法。 如果我删除代码的部分,它将图像打印为正常质量+正常大小,因为我希望它的高度限制在250,并返回类似于此图像的内容。 但它返回的内容类似于下面显示的内容。
我制作了一个用于图像和视频共享的社交应用程序。但是,加载图像需要花费太多时间。我正在使用glide图书馆。请告诉我如何在图像质量没有明显变化的情况下(如Instagram)缩小从gallery中拾取的图像的大小,然后将其上载到firebase存储。请帮忙!
问题内容: 每次更新同一张图片时,图像质量都会通过图像压缩方法降低。 我不想一次又一次地压缩图像。请提出一些建议。 问题答案: 首先,使用PNG压缩不会丢失图像质量。 如果仍要获取不压缩的字节,则可以尝试以下操作: 要从字节数组取回:
问题内容: 每次更新同一张图片时,图像质量都会通过图像压缩方法降低。 我不想一次又一次地压缩图像。请提出一些建议。 问题答案: 首先,使用PNG压缩不会丢失图像质量。 如果仍要获取不压缩的字节,则可以尝试以下操作: 要从字节数组取回:
问题内容: 我有一个很长的页面,可在用户滚动浏览时动态加载图像。 但是,如果用户快速滚动离开页面的某个部分,我不希望图像继续加载到页面的该部分视图之外。 除了图像加载外,页面上还同时发生了许多其他请求,因此在scroll事件上触发钝化window.stop()是不可接受的。 我尝试删除并清除不再可见的图像的img src属性,但是,由于请求已经启动,因此图像会继续加载。 请记住,当用户短暂滚动经过
我想在对话框窗口中显示图像(保存在项目文件夹中),但当我运行我的方法showDialogWithImage时,我会得到文件NotFoundException:imgs\pic1。jpg(系统无法找到指定的文件),尽管图像位于那里。 我也尝试过以这种方式加载图像: Image=new Image(getClass(). getResourceAsStream(path));,但遇到了同样的问题。 是