哈Ha!
我正在为我的项目建立一个网站。 在网站上,您需要同时显示很多GIF,每个GIF都很好。 如果一次显示所有内容,则页面加载时间很长。 同时,提供没有GIF的页面(以便可以在此处下载)也是不可能的。
任何对我如何处理此问题感兴趣的人,我都会要求猫。
其实问题是
就像我说的,网站上有非常多的gif,不同而不同。 您可以自己查看其中的多少个:
reface.tech
看到该着陆程序的Beta版后,我立即遇到了加载问题:对于某些用户,页面已加载了很长时间。 对于一个严肃的企业,当然不是这样。
有必要以某种方式解决这个问题。 简单的无损压缩是不可能实现的,因为那时所有媒体内容都已经通过
compressor.io驱动了。 因此,有必要压缩损失并赋予GIF较差的质量。
但是向拥有良好互联网的用户提供不良媒体内容是一种牺牲。 因此,决定以某种方式确定Internet的速度,并根据速度来确定适当的质量。
我们做一个粗略的草图
我们将有一个数组,其中包含要加载的媒体内容的描述。
一个例子:
[ { "large": { "size": 0.6211118698120117, "url": "gifs/control/large/control_1.gif" }, "middle": { "size": 0.5330495834350586, "url": "gifs/control/middle/control_1.gif" }, "small": { "size": 0.4901447296142578, "url": "gifs/control/small/control_1.gif" } } ]
在适当质量的基本要素中,这里是url和文件大小。
我们将简单地:
- 遍历数组(加载页面时)
- 阅读每种质量等级加载的总大小
- 确定是否会在4秒内加载所有内容(这是个人困扰我的时间)
因此,有必要:
- 看到了某种东西,它将组成这样一个数组,以便一切都不会用笔计算(在python中)
- 看到互联网速度
锯速表
这将相对简单。 我们在浏览器的地址栏中输入
eu.httpbin.org/stream-bytes/51200 。 下载长度为51200字节的文件。 我们在公共场合将其推向自己(以衡量托管的速度)。
现在我们需要检查文件摆动了多少。 我们将为此提供一个简单的函数,它将以兆字节每秒的速度返回给我们。
async checkDownloadSpeed(baseUrl, fileSizeInBytes) { return new Promise((resolve, _) => { let startTime = new Date().getTime(); return axios.get(baseUrl).then( response => { const endTime = new Date().getTime(); const duration = (endTime - startTime) / 1000; const bytesPerSecond = (fileSizeInBytes / duration); const megabytesPerSecond = (bytesPerSecond / 1000 / 1000); resolve(megabytesPerSecond); }); }).catch(error => { throw new Error(error); }); }
也就是说,我们记录了下载的开始时间,结束时间,并测量了差异,并且,由于我们知道文件的大小,因此只需对其进行划分即可。
现在,我们将编写一个将以特定速度执行操作的函数:
async getNetworkDownloadSpeed() { const baseUrl = process.env.PUBLIC_URL + '/51200'; const fileSize = 51200; const speed = await this.checkDownloadSpeed(baseUrl, fileSize); console.log("Network speed: " + speed); if (speed.mbps === "Infinity") { SpeedMeasure.speed = 1; } else { SpeedMeasure.speed = speed * 5; } }
通常,此代码存在一个问题:由于文件较小,因此无法确定确切的连接速度。 但是下载更多内容对我们来说太昂贵了,因此我们只需将结果速度乘以5。即使有余地,我们也可以接受,因为实际上速度会更高。
现在,我们将提交一个函数,该函数将根据速度来确定相应的质量:
static getResolution(gifsArray) { let totalSizeLevel1 = 0; let totalSizeLevel2 = 0; let totalSizeLevel3 = 0; for (let i = 0; i < gifsArray.length; i++) { for (let a = 0; a < gifsArray[i].length; a++) { let element = gifsArray[i][a]; totalSizeLevel1 += element.small.size; totalSizeLevel2 += element.middle.size; totalSizeLevel3 += element.large.size; } } if (isNaN(SpeedMeasure.speed)) { SpeedMeasure.speed = 1; } let timeLevel1 = totalSizeLevel1 / SpeedMeasure.speed; let timeLevel2 = totalSizeLevel2 / SpeedMeasure.speed; let timeLevel3 = totalSizeLevel3 / SpeedMeasure.speed; if (timeLevel3 < APPROPRIATE_TIME_LIMIT) { return "large"; } else if (timeLevel2 < APPROPRIATE_TIME_LIMIT) { return "middle"; } else { return "small"; } }
由于计算速度的函数与我们异步,因此SpeedMeasure.speed可能为零。 默认情况下,我们认为连接速度为每秒1 MB。 当函数计算速度时,我们只是重新渲染容器。
我们将数组的数组传递给getResolution函数。 怎么了 因为如果页面上有多个容器,将数组中的相应内容传输到每个容器中比较方便,但是我们需要一次考虑所有下载速度。
使用范例
这是一个用法示例(在React上):
async runFunction() { let speedMeasure = new SpeedMeasure(); await speedMeasure.getNetworkDownloadSpeed(); this.forceUpdate() } componentDidMount() { this.runFunction(); } render() { let quality = SpeedMeasure.getResolution([ Control.getControlArray(), Health.getHealthArray() ]); return ( <div className="app"> <Presentation /> <Control quality={quality} /> <Health quality={quality} /> </div> ); }
因此,当我们确定速度后,将再次渲染容器。
在容器内部(例如,在Control内部),您只需从数组中获取相应的GIF(按索引),然后按质量获取对象,并按url获取链接。 一切都很简单。
编写Python脚本
现在,我们需要以某种方式自动压缩gif并输出包含内容描述的数组。
首先,让我们编写一个压缩脚本。 我们将使用gifsicle。 对于中等压缩的内容,压缩级别将为80(200个压缩级别),对于非常强大的功能,压缩级别将为160。
import os GIFS_DIR = "/home/mixeden//Landingv2/" COMPRESSOR_DIR = "/home/mixeden//gifsicle-static" NOT_OPTIMIZED_DIR = "not_optimized" OPTIMIZED_DIR = "optimized" GIF_RESIZED_DIR = "gif_not_optimized_resized" GIF_COMPRESSED_DIR = "gif_compressed" COMPRESSION_TYPE = ["middle", "small"] for (root, dirs, files) in os.walk(GIFS_DIR, topdown=True): if len(files) > 0 and GIF_RESIZED_DIR in root: for file in files: path = root + "/" + file for compression in COMPRESSION_TYPE: final_path = path.replace(GIF_RESIZED_DIR, GIF_COMPRESSED_DIR + "/" + compression + "/" + OPTIMIZED_DIR) print(path, final_path) if compression == COMPRESSION_TYPE[0]: rate = 80 else: rate = 160 os.system("echo 0 > " + final_path) os.system(COMPRESSOR_DIR + " -O3 --lossy={} -o {} {}".format(rate, final_path, path))
为了使文件路径易于理解,以下是带有gif的文件目录说明:
- NOT_OPTIMIZED_DIR-未优化的GIF
- GIF_RESIZED_DIR-未优化的GIF,但会根据容器的大小进行调整
- GIF_COMPRESSED_DIR-压缩的GIF
文件夹内有带有GIF类别名称的文件夹。 在具有特定文件夹的文件夹内,包含“大”,“中”和“小”(在压缩文件的类型下)。
在脚本中,我们浏览带有gif的目录,对于每个文件,我们执行两种类型的压缩,调用相应的命令行命令。
现在,让我们继续执行脚本以创建一个包含信息的数组。
import json import os GIFS_DIR = "/home/mixeden//Landingv2/" COMPRESSOR_DIR = "/home/mixeden//gifsicle-static" NOT_OPTIMIZED_DIR = "not_optimized" OPTIMIZED_DIR = "optimized" GIF_RESIZED_DIR = "gif_not_optimized_resized" GIF_COMPRESSED_DIR = "gif_compressed" COMPRESSION_TYPE = ["large", "middle", "small"] OUTPUT = {} for (root, dirs, files) in os.walk(GIFS_DIR, topdown=True): if len(files) > 0 and GIF_COMPRESSED_DIR in root and NOT_OPTIMIZED_DIR not in root: files.sort() type = root.split(GIFS_DIR)[1].split(GIF_COMPRESSED_DIR)[0].replace("/", "") print(type) if type not in OUTPUT: OUTPUT[type] = [] if len(OUTPUT[type]) == 0: for file in files: OUTPUT[type].append( { "large": { "url": "", "size": 0 }, "middle": { "url": "", "size": 0 }, "small": { "url": "", "size": 0 } }) for file in files: full_path = root + "/" + file bytes_size = os.path.getsize(full_path) kilobytes_size = bytes_size / 1000 megabytes_size = kilobytes_size / 1000 index = int(file.split("_")[1].replace(".gif", "")) - 1 for typer in COMPRESSION_TYPE: if typer in root: local_type = typer new_url = "gifs/" + full_path.replace(GIFS_DIR, "").replace("/" + GIF_COMPRESSED_DIR, "").replace("/" + OPTIMIZED_DIR, "") OUTPUT[type][index][local_type]['url'] = new_url OUTPUT[type][index][local_type]['size'] = megabytes_size print(OUTPUT) print(json.dumps(OUTPUT, indent=4, sort_keys=True))
在这里,我们浏览包含文件的文件夹,确定文件大小,找出压缩类型,然后将常规信息放入OUTPUT数组。 然后,我们将这个数组输出到控制台以进行复制。
结论
希望本文对您有所帮助。 伙计们,编码不错。