68publishers / image-storage
68publishers/file-storage 扩展,可以即时生成图片等更多功能!
Requires
- php: ^8.1
- ext-json: *
- 68publishers/file-storage: ^1.1.1
- intervention/image: ^2.7.2
Requires (Dev)
- ext-imagick: *
- friendsofphp/php-cs-fixer: ^3.13
- kubawerlos/php-cs-fixer-custom-fixers: ^3.21
- latte/latte: ^3.0
- league/flysystem-aws-s3-v3: ^3.0
- league/flysystem-memory: ^3.10
- mockery/mockery: ^1.5
- nette/application: ^3.1.8
- nette/bootstrap: ^3.1
- nette/di: ^3.0.10
- nette/http: ^3.2.1
- nette/tester: ^2.4.3
- phpstan/phpstan: ^1.9
- phpstan/phpstan-nette: ^1.1
- roave/security-advisories: dev-latest
- symfony/console: ^5.0 | ^6.0
- yosymfony/toml: ^1.0.4
Suggests
- latte/latte: For usage with Latte templates.
- league/flysystem-aws-s3-v3: For generation of SAM configuration files when you're using AWS S3 and 68publishers/image-storage-lambda.
- nette/di: For an integration with Nette Framework.
- symfony/console: If you want to use a console commands.
- yosymfony/toml: For generation of SAM configuration files when you're using AWS S3 and 68publishers/image-storage-lambda.
Conflicts
- 68publishers/doctrine-bridge: <1.0.0
- latte/latte: <3.0
- nette/di: <3.0.10
- nette/http: <3.2.1
- nette/schema: <1.1
- symfony/console: <5.0
- yosymfony/toml: <1.0.4
- dev-master
- v1.3.0
- v1.2.1
- v1.2.0
- v1.1.0
- v1.0.2
- v1.0.1
- v1.0.0
- v0.5.8
- v0.5.7
- v0.5.6
- v0.5.5
- v0.5.4
- v0.5.3
- v0.5.2
- v0.5.1
- v0.5
- v0.4.10
- v0.4.9
- v0.4.8
- v0.4.7
- v0.4.6
- v0.4.5
- v0.4.4
- v0.4.3
- v0.4.2
- v0.4.1
- v0.4
- v0.3.1
- v0.3
- v0.2.3
- v0.2.2
- v0.2.1
- v0.2
- v0.1.2
- v0.1.1
- v0.1
- dev-dependabot/composer/intervention/image-tw-3.4.0
- dev-feature/no-image-latte-function
This package is auto-updated.
Last update: 2024-08-27 03:26:16 UTC
README
🌆 68publishers/file-storage 扩展,可以即时生成图片等更多功能!
基于 thephpleague/flysystem 和 intervention/image
安装
安装 68publishers/image-storage 的最佳方式是使用 Composer
$ composer require 68publishers/image-storage
Nette 框架集成
首先,请阅读 68publishers/file-storage 的文档。
文件存储配置示例
每个 image-storage 都基于文件存储。因此,我们首先需要在文件存储扩展下注册我们的存储。以下是一个示例配置
68publishers.file_storage: storages: local: config: base_path: /images signature_key: my-arbitrary-private-key allowed_pixel_density: [ 1, 2, 3 ] allowed_resolutions: [ 50x50, 200x200, 300x300, 200x, x200 ] allowed_qualities: [ 50, 80, 100 ] encode_quality: 90 cache_max_age: 31536000 filesystem: adapter: League\Flysystem\Local\LocalFilesystemAdapter(%wwwDir%/images) assets: assets/image/noimage.png: noimage/default.png # copy the default no-image assets/image/noimage_user.png: noimage/user.png # copy the default no-image for users
存储配置选项
图像存储配置示例
现在我们可以注册 ImageStorageExtension
并定义 local
图像存储
extensions: 68publishers.image_storage: SixtyEightPublishers\ImageStorage\Bridge\Nette\DI\ImageStorageExtension 68publishers.image_storage: driver: gd # "gd" or "imagick" or "68publishers.imagick", the default is "gd" storages: local: source_filesystem: adapter: League\Flysystem\Local\LocalFilesystemAdapter(%appDir%/../private-data/images) config: [] # an optional config for source filesystem adapter server: local # "local" or "external", the default is "local" route: yes # registers automatically ImageServer presenter into your Router. The option can be applied only if the "server" option is set to "local" and the option "base_path" is set in the FileStorage config no_image: default: noimage/default.png user: noimage/user.png no_image_patterns: user: '^user_avatar\/' # the noimage "user" will be used for missing files with paths that matches this regex presets: my_preset: w: 150 ar: '2x1.5'
动画 GIF
Intervention/image 不支持动画 GIF,但此包附带一个自定义的 imagick
驱动程序,支持它。当您将值 68publishers.imagick
传递给 driver
选项时,将使用该驱动程序。
基本用法
基本用法与 file-storage
的用法类似。
持久化文件
文件持久化几乎与 file-storage
中的持久化相同,但源图像存储时不带文件扩展名。
use SixtyEightPublishers\ImageStorage\ImageStorageInterface; /** @var ImageStorageInterface $storage */ # Create resource from local file or url: $resource = $storage->createResourceFromFile( $storage->createPathInfo('test/my-image.jpeg'), __DIR__ . '/path/to/my-image.jpeg' ); $storage->save($resource); # Create resource from a file that is stored in storage: $resource = $storage->createResource( $storage->createPathInfo('test/my-image') ); # Copy to the new location $storage->save($resource->withPathInfo( $storage->createPathInfo('test/my-image-2') ));
检查文件是否存在
use SixtyEightPublishers\ImageStorage\ImageStorageInterface; /** @var ImageStorageInterface $storage */ $pathInfo = $storage->createPathInfo('test/my-image'); if ($storage->exists($pathInfo)) { echo 'source image exists!'; } if ($storage->exists($pathInfo->withModifiers(['w' => 150]))) { echo 'cached image with width 150 in JPEG (default) format exists!'; } if ($storage->exists($pathInfo->withModifiers(['w' => 150])->withExtension('webp'))) { echo 'cached image with width 150 in WEBP format exists!'; }
删除文件
use SixtyEightPublishers\ImageStorage\ImageStorageInterface; use SixtyEightPublishers\ImageStorage\Persistence\ImagePersisterInterface; /** @var ImageStorageInterface $storage */ # delete all cached images only: $storage->delete($storage->createPathInfo('test/my-image'), [ ImagePersisterInterface::OPTION_DELETE_CACHE_ONLY => TRUE, ]); # delete cached images and source image: $storage->delete($storage->createPathInfo('test/my-image')); # delete only cached image with 200px width in PNG format $storage->delete($storage->createPathInfo('test/my-image.png')->withModifiers(['w' => 200]));
创建指向图像的链接
原始图像不可访问。如果您想访问原始图像,您必须使用修饰符 ['original' => TRUE]
请求它。
use SixtyEightPublishers\ImageStorage\ImageStorageInterface; /** @var ImageStorageInterface $storage */ $pathInfo = $storage->createPathInfo('test/my-image.png') ->withModifiers(['original' => TRUE]) ->withVersion(time()); # /images/test/original/my-image.png?_v=1611837352 echo $storage->link($pathInfo); # /images/test/original/my-image.webp?_v=1611837352 echo $storage->link($pathInfo->withExtension('webp')); # /images/test/ar:2x1,w:200/my-image.webp?_v=1611837352&_s={GENERATED_SIGNATURE_TOKEN} echo $storage->link($pathInfo->withExtension('webp')->withModifiers(['w' => 200, 'ar' => '2x1'])); # you can also wrap PathInfo to FileInfo object: $fileInfo = $storage->createFileInfo($pathInfo); # /images/test/original/my-image.png?_v=1611837352 echo $fileInfo->link(); # /images/test/original/my-image.webp?_v=1611837352 echo $fileInfo->withExtension('webp')->link(); # /images/test/ar:2x1,w:200/my-image.webp?_v=1611837352&_s={GENERATED_SIGNATURE_TOKEN} echo $fileInfo->withExtension('webp')->withModifiers(['w' => 200, 'ar' => '2x1'])->link();
还可以生成 srcset
HTML 属性
use SixtyEightPublishers\ImageStorage\ImageStorageInterface; use SixtyEightPublishers\ImageStorage\Responsive\Descriptor\XDescriptor; use SixtyEightPublishers\ImageStorage\Responsive\Descriptor\WDescriptor; /** @var ImageStorageInterface $storage */ $pathInfo = $storage->createPathInfo('test/my-image.png') ->withModifiers(['w' => 200, 'ar' => '2x1']) ->withVersion(time()); /* /images/test/ar:2x1,pd:1,w:200/my-image.png?_v=1611837352&_s={TOKEN} , /images/test/ar:2x1,pd:2,w:200/my-image.png?_v=1611837352&_s={TOKEN} 2.0x, /images/test/ar:2x1,pd:3,w:200/my-image.png?_v=1611837352&_s={TOKEN} 3.0x */ echo $storage->srcSet($pathInfo, new XDescriptor(1, 2, 3)); /* /images/test/ar:2x1,w:200/my-image.png?_v=1611837352&_s={TOKEN} 200w, /images/test/ar:2x1,w:400/my-image.png?_v=1611837352&_s={TOKEN} 400w, /images/test/ar:2x1,w:600/my-image.png?_v=1611837352&_s={TOKEN} 600w, /images/test/ar:2x1,w:800/my-image.png?_v=1611837352&_s={TOKEN} 800w */ echo $storage->srcSet($pathInfo, new WDescriptor(200, 400, 600, 800)); # you can also wrap PathInfo to FileInfo object: $fileInfo = $storage->createFileInfo($pathInfo); echo $fileInfo->srcSet(new XDescriptor(1, 2, 3)); echo $fileInfo->srcSet(new WDescriptor(200, 400, 600, 800));
与 Latte 的用法
extensions: 68publishers.image_storage.latte: SixtyEightPublishers\ImageStorage\Bridge\Nette\DI\ImageStorageLatteExtension
该扩展向 Latte 添加了这些功能
w_descriptor(...)
-new SixtyEightPublishers\ImageStorage\Responsive\Descriptor\XDescriptor(...)
的快捷方式x_descriptor(...)
-new SixtyEightPublishers\ImageStorage\Responsive\Descriptor\WDescriptor(...)
的快捷方式w_descriptor_range(int $min, int $max, int $step)
-SixtyEightPublishers\ImageStorage\Responsive\Descriptor\WDescriptor::fromRange($min, $max, $step)
的快捷方式no_image(?string $noImageName = NULL, ?string $storageName = NULL)
- 创建一个包含无图像文件路径的 FilInfo 对象
基本用法
{varType SixtyEightPublishers\ImageStorage\FileInfoInterface $fileInfo} {* Note: method FileInfo::__toString() calls ::link() internally *} <img src="{$fileInfo->link()}" alt=""> <img srcset="{$fileInfo->srcSet(x_descriptor(1, 2, 3))}" src="{$fileInfo}" alt=""> {* Create FileInfo from string *} {var $fileInfo = file_info('test/my-image.png')->withModifiers(['o' => 90, 'ar' => '2x1'])} <img srcset="{$fileInfo->srcSet(w_descriptor(400, 800, 1200))}" src="{$fileInfo}" alt=""> {* Create default NoImage if the variable doesn't exists *} {var $fileInfo = ($fileInfo ?? no_image())->withModifiers(['o' => 90, 'ar' => '2x1'])} <img srcset="{$fileInfo->srcSet(w_descriptor(400, 800, 1200))}" src="{$fileInfo}" alt="">
使用 <picture>
标签的高级示例
{var $large = file_info('test/my-image.jpeg')->withModifiers([w => 1172, ar => '1x0.29'])} {var $medium = $large->withModifiers([w => 768, ar => '1x0.59'])} <picture> <source srcset="{$large->withExt('webp')->srcSet(w_descriptor_range(768, 1172 * 3, 200))}" media="(min-width: 768px)" sizes="(min-width: 1188px) calc(1188px - 2 * 0.5rem), (min-width: 992px) calc(100vw - 2 * 0.5rem), calc(100vw - 2 * 1.5rem)" type="image/webp"> <source srcset="{$large->srcSet(w_descriptor_range(768, 1172 * 3, 200))}" media="(min-width: 768px)" sizes="(min-width: 1188px) calc(1188px - 2 * 0.5rem), (min-width: 992px) calc(100vw - 2 * 0.5rem), calc(100vw - 2 * 1.5rem)"> <source srcset="{$medium->withExt('webp')->srcSet(w_descriptor_range(320, 768 * 3, 200))}" sizes="(min-width: 576px) calc(100vw - 2 * 1.5rem), calc(100vw - 2 * 0.5rem)" type="image/webp"> <source srcset="{$medium->srcSet(w_descriptor_range(320, 768 * 3, 200))}" sizes="(min-width: 576px) calc(100vw - 2 * 1.5rem), calc(100vw - 2 * 0.5rem)"> <img src="{$large}" alt=""> </picture>
Symfony 控制台命令
image-storage 扩展了命令 file-storage:clean
并添加了 cache-only
选项,因此命令现在看起来像这样
$ bin/console file-storage:clean [<storage>] [--namespace <value>] [--cache-only]
支持的图像格式和修饰符
图像格式
- JPEG -
.jpeg
或.jpg
- 渐进式 JPEG -
.pjpg
- PNG -
.png
- GIF -
.gif
- WEBP -
.webp
- AVIF -
.avif
修饰符
支持的 fits
contain
- 保持宽高比,将图像调整到尽可能大,同时确保其尺寸小于或等于指定的尺寸。stretch
- 忽略输入的宽高比,拉伸至提供的两个维度。fill
- 保留宽高比,使用“信封”方式在必要时包含在提供的两个维度内。crop-*
- 保留宽高比,通过裁剪确保图片覆盖提供的两个维度。crop-center
crop-left
crop-right
crop-top
crop-top-left
crop-top-right
crop-bottom
crop-bottom-left
crop-bottom-right
图像服务器
本地图像服务器
每个存储的默认图像服务器为 local
。这意味着您的应用程序将处理请求,生成、存储和提供修改后的图像。如果为存储设置了 route: true
选项,则扩展会自动注册 ImageStoragePresenter 和路由。如果您禁用了此设置,则必须自己注册该演示者。
现在您必须修改Web服务器的配置。例如,如果Web服务器是Apache,则修改位于您www目录中的 .htaccess
文件。
# locale images RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(images\/)(.+) index.php [L]
只有在尚未生成静态文件时,应用程序才会被调用。否则,服务器将提供静态文件。
外部图像服务器:与AWS S3和image-storage-lambda的集成
图像存储可以与Amazon S3对象存储和包 68publishers/image-storage-lambda 集成。因此,您的图像存储可以完全无服务器!当然,您可以手动部署 image-storage-lambda
应用程序,并且还可以手动从 image-storage
同步选项到 image-storage-lambda
。
至少,您可以根据以下简单步骤进行部分集成
- 在S3上创建一个部署存储桶
在引导模式下部署AWS SAM应用程序(sam deploy --guided
),将自动创建部署存储桶。但是应用程序将以非引导模式构建,因此我们必须手动创建存储桶。如果您不知道如何创建S3存储桶,请按照 Amazon文档 进行操作。我们建议在此存储桶上启用版本控制。
- 在您的应用程序中需要以下包
league/flysystem-aws-s3-v3
(Flysystem的S3适配器)和yosymfony/toml
(由该包建议)
$ composer require league/flysystem-aws-s3-v3 yosymfony/toml
- 使用S3文件系统配置图像存储(示例:使用最小配置)
services: s3_client: class: Aws\S3\S3Client([... your S3 config ...]) autowired: no 68publishers.file_storage: storages: s3_images: config: # configure what you want but omit the `host` option for now filesystem: adapter: League\Flysystem\AwsS3V3\AwsS3V3Adapter(@s3_client, my-awesome-cache-bucket) # the bucket doesn't exists at this point # if you have your own no-images: assets: %assetsDir%/noimage: noimage 68publishers.image_storage: storages: s3_images: source_filesystem: adapter: League\Flysystem\AwsS3V3\AwsS3V3Adapter(@s3_client, my-awesome-source-bucket) # the bucket doesn't exists at this point server: external # if you have your own no-images: no_image: default: noimage/default.png user: noimage/user.png no_image_patterns: user: '^user_avatar\/'
- 注册和配置编译扩展
ImageStorageLambdaExtension
extensions: 68publishers.image_storage.lambda: SixtyEightPublishers\ImageStorage\Bridge\Nette\DI\ImageStorageLambdaExtension 68publishers.image_storage.lambda: output_dir: %appDir%/config/image-storage-lambda # the default path stacks: s3_images: s3_bucket: {NAME OF YOUR DEPLOYMENT BUCKET FROM THE STEP 1} region: eu-central-1 # optional settings: stack_name: my-awesome-image-storage # the storage name is used by default version: 2.0 # default is 1.0 s3_prefix: custom-prefix # the stack_name is used by default confirm_changeset: yes # must be changeset manually confirmed during deploy? the default value is false capabilities: CAPABILITY_IAM # default, CAPABILITY_IAM or CAPABILITY_NAMED_IAM # optional, automatically detected from AwsS3V3Adapter by default source_bucket_name: source-bucket-name cache_bucket_name: cache-bucket-name
- 为
image-storage-lambda
生成配置
$ php bin/console image-storage:lambda:dump-config
默认情况下,配置文件将放置在目录 app/config/image-storage-lambda/my-awesome-image-storage/samconfig.toml
中。请使用Git进行版本控制。
- 下载
image-storage-lambda
,构建并部署!
首先根据此处定义的要求设置您的本地环境。然后在外部项目之外下载该包。
$ git clone https://github.com/68publishers/image-storage-lambda.git image-storage-lambda
$ cd ./image-storage-lambda
遗憾的是,SAM CLI目前不允许您定义指向 samconfig.toml
文件的路径(相关问题 aws/aws-sam-cli#1615)。因此,您必须将配置复制到 image-storage-lambda
应用程序的根目录。然后您可以构建并部署应用程序!
$ cp ../my-project/app/config/image-storage-lambda/my-awesome-image-storage/samconfig.toml samconfig.toml $ sam build $ sam deploy
- 在图像存储配置中将CloudFront URL设置为主机
在成功部署后,您的CloudFront分发URL将列在输出中。更多信息请在此处。
# ... 68publishers.image_storage: storages: s3_images: config: host: {CLOUDFRONT URL} # ...
贡献
在打开拉取请求之前,请使用以下命令检查您的更改
$ make init # to pull and start all docker images
$ make cs.check
$ make stan
$ make tests.all