escolalms/images

Escola 无头 LMS 图像处理

0.1.24 2024-02-14 13:58 UTC

README

swagger codecov phpunit downloads downloads downloads Maintainability Test Coverage

它做什么

该包通过给定参数从源创建调整大小的图像。这是一个无头方法,因此后端在前端请求之前不知道请求的大小。

输入图像由Laravel存储在任何可用的磁盘上(本地存储/s3/任何桶)。一旦请求调整大小的版本,就会创建并返回缓存的版本。以下是一些示例,以展示整体思路。

初始调整大小是通过Intervention/image使用GD驱动程序完成的。这可以配置

在初始调整大小之后,所有图像都使用image-optimizer进行优化。

为了获得最佳结果,必须安装二进制文件。EscolaLMS已准备好的Docker镜像可用于开发(标记work)和生产(标记prod)。

安装

  • composer require escolalms/images
  • php artisan migrate

数据库

  • image_caches - 用于保存原始和调整大小图像路径的表

示例

默认。一个图像作为302重定向结果。

基本的调整大小是通过URL API调用实现的,该调用重定向到新创建的文件。

示例 GET 调用

  • https:///api/images/img?path=test.jpg&w=100 调用应返回宽度为100px的调整大小图像
  • 检查文件是否存在
  • 如果不存在,则使用可用库创建一个
  • 返回302重定向
  • 示例 https:///storage/imgcache/891ee133a8bb111497d494d4c91fe292d9d16bb3.jpg(假设您正在使用本地磁盘存储,在s3位置的情况下,原始位置会有所不同)

一次性调整多个图像。结果为JSON数组。

示例 POST 调用如下

POST /api/images/img HTTP/1.1
Host: localhost:1000
Content-Type: application/json
Content-Length: 212

{
  "paths": [{
    "path": "tutor_avatar.jpg",
    "params": {
      "w": 100
    }
  }, {
    "path": "tutor_avatar.jpg",
    "params": {
      "w": 200
    }
  }, {
    "path": "tutor_avatar.jpg",
    "params": {
      "w": 300
    }
  }]
} 

生成以下结果

[
  {
    "url": "https:///storage/imgcache/3421584c40d270d0fa7ef0c31445a1565db07cb4.jpg",
    "path": "imgcache/3421584c40d270d0fa7ef0c31445a1565db07cb4.jpg",
    "hash": "3421584c40d270d0fa7ef0c31445a1565db07cb4"
  },
  {
    "url": "https:///storage/imgcache/7efc528c2cc7b57d79a42f80d2c1891b517cabfe.jpg",
    "path": "imgcache/7efc528c2cc7b57d79a42f80d2c1891b517cabfe.jpg",
    "hash": "7efc528c2cc7b57d79a42f80d2c1891b517cabfe"
  },
  {
    "url": "https:///storage/imgcache/5db4f572d8c8b1cb6ad97a3bffc9fd6c18b56cc3.jpg",
    "path": "imgcache/5db4f572d8c8b1cb6ad97a3bffc9fd6c18b56cc3.jpg",
    "hash": "5db4f572d8c8b1cb6ad97a3bffc9fd6c18b56cc3"
  }
] 

哈希算法

存在一个简单的算法来猜测结果图像URL。这允许前端应用程序知道处理后的URL,而无需调用API。如下所示

$path = 'test.jpg';
$params = ['w'=>100];

$hash = sha1($path.json_encode($params));

则结果URL将是

$output_file = $url_prefix.$hash.$extension;

端点

存在API端点文档 swagger

测试

运行 ./vendor/bin/phpunit 来运行测试。

测试详细信息 codecov phpunit

事件

此包扩展了filesystem

$this->app->extend('filesystem', function ($service, $app) {
    return new CustomFilesystemManager($app);
});
  1. FileDeleted - 当您在Storage外观中使用delete方法时,将触发此事件。
  2. FileStored - 当您使用putputFileputFileAs方法时,将触发此事件。

监听器

此包监听FileDeletedFileStored事件,并从给定路径删除调整大小的图像。

如何在前端使用此功能

以下是我们生成图像的完全无头方法

以下示例旨在实现两个目的

  • 动态生成图片,前端决定需要什么尺寸
  • 图片不是通过API提供

思路是,因为我们知道缓存的图片的哈希算法,我们可以猜测URL的格式。如果这个URL返回404错误,我们就调用API端点生成一张图片。幸运的是,这个端点创建所需的图片,将其缓存并返回重定向,这对于图片源来说是个好事情。

这种方法的重大缺点是,第一次用户在网络上可能会遇到404错误,并且在找不到图片后需要等待几秒钟才能渲染图片。

<script type="text/javascript" src="sha1.js"></script>
<script>
  // Initial variables 
  const imgPath = "tutor_avatar.jpg";
  const imgPrefix = "https:///storage/imgcache";
  const apiUrl = "https:///api/images/img";
  const rndWith = Math.round(Math.random() * 1000);
  const params = { w: rndWith.toString() }; // random width params
  // super important that all param values are strings 
  // hash from { w: 100 } is different then { w: "100" }
			
  // stright forward helper to convert obejct to URL query params 
  const paramsToUrl = (params) =>
    Object.entries(params)
      .map((e) => e.join("="))
      .join("&");

  /** 
   * @param string path, example "tutor_avatar.jpg"
   * @param array params, example { w: "100" } or { w: "100", h: "10" }
   * @return Image 
   */ 
  const getImage = (path, params) => {
    const hash = SHA1(path + JSON.stringify(params));
    const url = `${imgPrefix}/${hash}.${path.split(".").pop()}`;
    const imgApiUrl = `${apiUrl}/?path=${imgPath}&${paramsToUrl(params)}`;
    const image = new Image();
    image.src = url;
    image.onerror = () => {
      if (image.src != imgApiUrl) {
        // the cached version does not exists yet, lets call API to create one and redirect.
        image.src = imgApiUrl;
      }
    };

    return image;
  };

  document.body.appendChild(getImage(imgPath, params));
</script> 

工作示例可以在doc文件夹中找到。