行空板提供了一个完整的而非裁剪的Python运行环境,默认还安装好了PIL库,可以很方便的进行图形的处理。
同时,行空板自身还有屏幕,那么结合PIL,可以很快实现一个电子相册。
要想实现一个电子相册,需要以下几个方面的功能:
- 图片源文件
- 从相册目录获取供显示用的图片列表
- 等比缩放图片
- 显示图片
下面,我们就一项一项的来实现。
1. 图片源文件:
行空板带有16G的eMMC存储空间,系统占用了一部分,甚于空间还很多:
而行空板的自带的WEB管理界面,提供了文件上传的功能:
虽然一次只能上传一张图片,但是使用非常简单方便。
所以,这个电子相册,图片源文件,通过WEB界面,上传到/root/album/目录下。
2. 从相册目录获取供显示用的图片列表
在Python中,进行目录操作,获取目录内的文件列表,是一件非常容易的事情。
代码如下:
```
import os
# 获取图片文件列表
files= os.listdir("/root/album/") #得到文件夹下的所有文件名称
photos = []
for file in files: #遍历文件夹
file_path = "%s/%s" % (album_dir, file)
print([file_path, os.path.isfile(file_path), file.endswith(".jpg")])
if os.path.isfile(file_path) and file.endswith(".jpg"): # 判断是否是文件,且后缀为.jpg才使用
photos.append(file_path) # 将文件路径存到list中
```
在上述代码逻辑如下:
- 通过 os.listdir 获取/root/album/目录内的文件列表
- 遍历获取的文件列表
- 如果是文件,且后缀为.jpg,则添加到图片列表中
其中的关键调用:
- os.listdir() 方法:用于返回指定的文件夹包含的文件或文件夹的名字的列表
- os.path.isfile()方法:用于判断路径是否为文件
- file.endswith(".jpg"):用于判断文件名称后缀是否为.jpg
3. 等比缩放图片
为什么要等比缩放图片呢?直接显示不行吗?
当然可以直接显示,但是需要注意的是,行空板的屏幕分辨率为240x320,如果直接显示,那么小于这个尺寸的图片,就占不满屏幕,大于这个尺寸的图片,则会超出屏幕只显示一部分。
所以,我们需要对图片进行等比缩放,按照宽高比,等比缩放到宽最大240,高最大320大小。
光缩放图片还不行,缩放后,我们还要将图片放在正中央,缩放后的图片如果不是正好240x320大小,那么还要在旁边留黑或者留白。
在Python中,应用PIL的Image模块,可以很方便的进行图片的处理。
等比缩放并留边的代码如下:
```
from PIL import Image
w_max = 240 # 屏幕宽度
h_max = 320 # 屏幕高度
ratio_base = float(w_max) / h_max # 宽高比
img = Image.open(file_path)
w, h = img.size
ratio = float(w) / h
if ratio>ratio_base:
w_s = w_max
h_s = int(w_s * ratio)
elif ratio < ratio_base:
h_s = h_max
w_s = int(h_s * ratio)
else:
w_s = w_max
h_s = h_max
# 等比缩放图片
img = img.resize((w_s, h_s),Image.ANTIALIAS)
# 给图片四周留黑
w_blank = int((w_max - w_s)/2)
h_blank = int((h_max - h_s)/2)
img2 = Image.new("RGB", (w_max, h_max), "black")
img2.paste(img, (w_blank, h_blank))
```
上述代码的逻辑如下:
- 先定义最大尺寸,并计算宽高比
- 使用PIL.Image打开图片
- 计算打开图片的宽高比,与最大尺寸进行对比,然后计算出来等比缩放后的大小;计算后的大小,宽不超过240,高不超过320
- 将图片根据计算后的宽高结果,进行等比缩放
- 新生成一个240x320的图片,且默认为黑色black;如果留白,则用white
- 将等比缩放后的图片,拷贝到新的图片,且根据缩放后的宽高,设置好拷贝后的位置,使得其居中
其中的关键调用:
- Image.open()方法:表示打开一个图片文件
- Image.resize((宽度, 高度),Image.ANTIALIAS):表示调整图片的尺寸
-
Image.new("RGB", (宽度, 高度), "颜色")
-
颜色可以为颜色的名称,也可以使元组表示RGB,例如(0,0,0)为黑色,(255,255,255)为白色,(255,0,0)为红色,其他以此类推
-
Image.paste(img, (x, y)):表示将img图片,拷贝到当前打开的图片的(x, y)坐标位置
4. 显示图片
图片有了,也等比缩放好了,现在就要显示图片了。
在行空板上,自带有GUI库,用于屏幕的操作,可以很方便的显示图片。
```
from unihiker import GUI #导入包
gui=GUI() #实例化GUI类
gui.clear() # 清除屏幕
photo_prev = None
photo_image = gui.draw_image(x=0, y=0, image=img2, origin='top_left')
if not photo_prev == None:
# 移除上一次显示的图片
photo_prev.remove()
photo_prev = photo_image
```
上述代码的逻辑如下:
- 初始化屏幕库,并清屏
- 将上一步调整好的图片,显示到屏幕上
- 并把前一张显示的图片移除
其中的关键调用如下:
- gui=GUI():实例化一个GUi对象
- gui.clear():清屏
- gui.draw_image(x=0, y=0, image=img2, origin='top_left'):在屏幕上左上角为坐标原点显示图片,image可以直接为一个图片的绝对路径,也可以为PIL.Image打开的图片
- photo_prev.remove():表示清除该控件,不限图片,其他控件也可以用
这里为什么每次显示后,要清除原有的呢?
因为,如果提前清除的话,屏幕可能会闪,有显示空挡;
如果不清除的话,那越显示积累越多,屏幕上堆的控件太多,会造成堆积问题,影响性能。
所以,每次显示后,清除老的。
5. 最终代码
整合上述各个部分的代码,最终代码如下:
import os
from unihiker import GUI #导入包
from PIL import Image
from time import sleep
album_dir = "/root/album" #相册图片目录
w_max = 240 # 屏幕宽度
h_max = 320 # 屏幕高度
ratio_base = float(w_max) / h_max # 宽高比
gui=GUI() #实例化GUI类
gui.clear() # 清除屏幕
while True:
photo_prev = None # 上一个显示的图片
# 获取图片文件列表
files= os.listdir(album_dir) #得到文件夹下的所有文件名称
photos = []
for file in files: #遍历文件夹
file_path = "%s/%s" % (album_dir, file)
# print([file_path, os.path.isfile(file_path), file.endswith(".jpg")])
if os.path.isfile(file_path) and file.endswith(".jpg"): # 判断是否是文件,且后缀为.jpg才使用
photos.append(file_path) # 将文件路径存到list中
if len(photos):
# 遍历显示图片
for i in range(0,len(photos)):
file_path = photos[i]
# 打开图片,并计算等比缩放后的宽高
img = Image.open(file_path)
w, h = img.size
ratio = float(w) / h
if ratio>ratio_base:
w_s = w_max
h_s = int(w_s * ratio)
elif ratio < ratio_base:
h_s = h_max
w_s = int(h_s * ratio)
else:
w_s = w_max
h_s = h_max
# 等比缩放图片
img = img.resize((w_s, h_s),Image.ANTIALIAS)
# 给图片四周留黑
w_blank = int((w_max - w_s)/2)
h_blank = int((h_max - h_s)/2)
img2 = Image.new("RGB", (w_max, h_max), "black")
img2.paste(img, (w_blank, h_blank))
# print([img.size, img2.size])
# 绘制图片
photo_image = gui.draw_image(x=0, y=0, image=img2, origin='top_left')
if not photo_prev == None:
# 移除上一次显示的图片
photo_prev.remove()
photo_prev = photo_image
img = None
img2 = None
sleep(3)
sleep(3)
6. 实际效果:
最终实际效果,如视频所示:
362_1667792024
如果再配上音乐,效果就会更完美了,大家试试!