tobento/service-picture

为PHP应用程序提供图片支持。

1.0.0 2024-09-29 11:01 UTC

This package is auto-updated.

Last update: 2024-09-29 11:03:59 UTC


README

图片服务为PHP应用程序提供创建和渲染图片的接口。它包含默认实现,但您可以根据需要创建特定实现。

目录

入门

使用以下命令运行项目以添加图片服务项目的最新版本。

composer require tobento/service-picture

要求

  • PHP 8.0或更高版本

亮点

  • 框架无关,与任何项目兼容
  • 解耦设计

文档

图片创建器

图片创建器根据给定的定义创建图像,并返回一个包含图像的已创建图片,您可以将图像存储在任何您喜欢的地方。

创建图片创建器

图片创建器使用Imager Service创建图像。

use Tobento\Service\Imager\InterventionImage\ImagerFactory;
use Tobento\Service\Picture\PictureCreator;

$pictureCreator = new PictureCreator(
    imager: (new ImagerFactory())->createImager(),
);

详细说明

use Psr\Log\LoggerInterface;
use Tobento\Service\Imager\Action;
use Tobento\Service\Imager\InterventionImage\ImagerFactory;
use Tobento\Service\Picture\Exception\ResourceSizeException;
use Tobento\Service\Picture\PictureCreator;
use Tobento\Service\Picture\PictureCreatorInterface;

$pictureCreator = new PictureCreator(
    imager: (new ImagerFactory())->createImager(),
    
    // You may define imager actions which are not allowed and will be skipped:
    disallowedActions: [
        Action\Colorize::class,
    ],
    
    // You may adjust the supported mime types:
    supportedMimeTypes: [
        'image/png', 'image/jpeg', 'image/gif', 'image/webp',
    ],
    
    // You may set an upsize limit for resizing images:
    upsize: 1.2, // default is null (unlimited)
    
    // You may skip smaller sized images (except img src)
    // from generating at all to prevent unsharp images.
    skipSmallerSizedSrc: true, // false is default
    
    // You may verify sizes. If one of the defined image size
    // is too small, a ResourceSizeException will be thrown.
    verifySizes: true, // false is default
    
    // You may pass a logger for debugging:
    logger: null, // LoggerInterface
);

var_dump($pictureCreator instanceof PictureCreatorInterface);
// bool(true)

图片创建

从流创建图片

使用createFromStream方法从PSR-7流创建图片

use Psr\Http\Message\StreamInterface;
use Tobento\Service\Picture\CreatedPictureInterface;
use Tobento\Service\Picture\DefinitionInterface;
use Tobento\Service\Picture\PictureInterface;

$createdPicture = $pictureCreator->createFromStream(
    stream: $stream, // StreamInterface
    definition: $definition, // DefinitionInterface
);

var_dump($createdPicture instanceof CreatedPictureInterface);
// bool(true)

var_dump($createdPicture instanceof PictureInterface);
// bool(true)

查看定义部分以了解有关定义的更多信息。

查看图片部分以了解有关默认的PictureInterface::class实现的更多信息。

从资源创建图片

使用createFromResource方法从实现ResourceInterface接口的任何资源创建图片

use Tobento\Service\Imager\ResourceInterface;
use Tobento\Service\Picture\CreatedPictureInterface;
use Tobento\Service\Picture\DefinitionInterface;
use Tobento\Service\Picture\PictureInterface;

$createdPicture = $pictureCreator->createFromResource(
    resource: $resource, // ResourceInterface
    definition: $definition, // DefinitionInterface
);

var_dump($createdPicture instanceof CreatedPictureInterface);
// bool(true)

var_dump($createdPicture instanceof PictureInterface);
// bool(true)

查看Imager Service - Resource部分以了解有关它的更多信息。

查看定义部分以了解有关定义的更多信息。

查看图片部分以了解有关默认的PictureInterface::class实现的更多信息。

支持的资源

已创建图片

已创建的图片包含所有创建的图像,您可以使用它以您所需的方式存储图像。

use Tobento\Service\Imager\Response\Encoded;
use Tobento\Service\Picture\CreatedPictureInterface;
use Tobento\Service\Picture\PictureInterface;

var_dump($createdPicture instanceof CreatedPictureInterface);
// bool(true)

var_dump($createdPicture instanceof PictureInterface);
// bool(true)

foreach($createdPicture->srces() as $src) {
    var_dump($src instanceof SrcInterface);
    // bool(true)
    
    // The encoded image which was created:
    var_dump($src->encoded() instanceof Encoded);
    // bool(true)
}

查看Encoded Response以了解有关它的更多信息。

定义

数组定义

数组定义是默认的图片定义。

use Tobento\Service\Picture\Definition\ArrayDefinition;
use Tobento\Service\Picture\DefinitionInterface;
use Tobento\Service\Picture\PictureInterface;
use Tobento\Service\Picture\Src;

$definition = new ArrayDefinition(name: 'product:main', definition: [
    'img' => [
        'src' => [600, 600], // [width, height]
        // or width only, height will be resized keeping ratio
        'src' => [600],
        // or height only, width will be resized keeping ratio
        'src' => [null, 600],
        // or
        'src' => [null, null], // keeps resource dimensions.
        // or using Src class
        'src' => new Src(
            width: 600, // or null
            height: 600, // or null
            // you may set a mime type to convert to:
            mimeType: 'image/webp',
            // you may define quality and actions:
            options: ['quality' => 90, 'actions' => ['crop' => [300, 200, 10, 15]]]
        ),
        // img attributes:
        'alt' => 'Alternative Text',
        'class' => 'foo',
        'data-foo' => 'foo',
        'sizes' => '(max-width: 600px) 480px, 800px',
        'loading' => 'lazy',
        'srcset' => [
            '480w' => [480], // same definition as img src
            '800w' => [800],
        ],
    ],
    // You may define any sources:
    'sources' => [
        [
            'media' => '(min-width: 800px)',
            'srcset' => [
                '' => [1200, 600],
            ],
            'type' => 'image/webp',
        ],
        [
            'media' => '(max-width: 600px)',
            'srcset' => [
                '' => [600, 600],
            ],
            'type' => 'image/webp',
            'width' => '600',
            'height' => '600',
        ],
    ],
    // Attributes for the picture tag:
    'attributes' => [
        'class' => 'foo',
    ],
    // Options:
    'options' => [
        // You may define a global quality if not specified individually with the Src class:
        'quality' => [
            'image/jpeg' => 70,
            'image/webp' => 70,
        ],
        // You may convert all png to jpeg types if not defined individually:
        'convert' => ['image/png' => 'image/jpeg'],
        // You may define imager actions used if not specified individually with the Src class:
        'actions' => [
            'greyscale' => [],
            'gamma' => ['gamma' => 5.5],
        ],
    ],
]);

var_dump($definition instanceof DefinitionInterface);
// bool(true)

// Definition to picture:
var_dump($definition->toPicture() instanceof PictureInterface);
// bool(true)

带有像素密度描述符的示例

use Tobento\Service\Picture\Definition\ArrayDefinition;

$definition = new ArrayDefinition(name: 'logo', definition: [
    'img' => [
        'src' => [250],
        'srcset' => [
            '' => [250],
            '2x' => [500],
        ],
    ],
]);

图片定义

use Tobento\Service\Picture\Img;
use Tobento\Service\Picture\Definition\PictureDefinition;
use Tobento\Service\Picture\DefinitionInterface;
use Tobento\Service\Picture\Picture;
use Tobento\Service\Picture\PictureInterface;
use Tobento\Service\Picture\Source;
use Tobento\Service\Picture\Sources;
use Tobento\Service\Picture\Src;
use Tobento\Service\Picture\Srcset;

$definition = new PictureDefinition(
    name: 'product',
    picture: new Picture(
        img: new Img(
            src: new Src(
                width: 600, // or null
                height: 600, // or null
                // you may set a mime type to convert to:
                mimeType: 'image/webp',
                // you may define quality and actions:
                options: ['quality' => 90, 'actions' => ['crop' => [300, 200, 10, 15]]],
            ),
            // you may define a srcset:
            srcset: new Srcset(
                new Src(width: 480, descriptor: '480w'),
                new Src(width: 800, descriptor: '800w'),
            ),
            attributes: [
                'sizes' => '(max-width: 600px) 480px, 800px',
                'loading' => 'lazy',
                'class' => 'foo',
            ],
        ),
        sources: new Sources(
            new Source(
                srcset: new Srcset(
                    new Src(width: 1200, height: 600),
                ),
                attributes: [
                    'media' => '(min-width: 800px)',
                    'type' => 'image/webp',
                ],
            ),
            new Source(
                srcset: new Srcset(
                    new Src(width: 600, height: 600),
                ),
                attributes: [
                    'media' => '(max-width: 600px)',
                    'type' => 'image/webp',
                ],
            ),
        ),
        attributes: [
            'class' => 'foo',
        ],
        options: [
            // You may define a global quality if not specified individually with the Src class:
            'quality' => [
                'image/jpeg' => 70,
                'image/webp' => 70,
            ],
            // You may convert all png to jpeg types if not defined individually:
            'convert' => ['image/png' => 'image/jpeg'],
            // You may define imager actions used if not specified individually with the Src class:
            'actions' => [
                'greyscale' => [],
                'gamma' => ['gamma' => 5.5],
            ],
        ],
    )
);

var_dump($definition instanceof DefinitionInterface);
// bool(true)

// Definition to picture:
var_dump($definition->toPicture() instanceof PictureInterface);
// bool(true)

定义

您可以使用以下定义类来添加、过滤和获取定义。

默认定义

use Tobento\Service\Picture\Definition\ArrayDefinition;
use Tobento\Service\Picture\DefinitionInterface;
use Tobento\Service\Picture\Definitions\Definitions;
use Tobento\Service\Picture\DefinitionsInterface;

$definitions = new Definitions(
    'product', // a definitions name
    new ArrayDefinition('product-main', ['img' => ['src' => [50]]]),
    // ... DefinitionInterface
);

var_dump($definitions instanceof DefinitionsInterface);
// bool(true)

JSON文件定义

JsonFilesDefinitions类从给定目录中的JSON文件加载定义。

use Tobento\Service\Dir\Dir;
use Tobento\Service\Dir\Dirs;
use Tobento\Service\Picture\Definition\ArrayDefinition;
use Tobento\Service\Picture\DefinitionInterface;
use Tobento\Service\Picture\Definitions\JsonFilesDefinitions;
use Tobento\Service\Picture\DefinitionsInterface;

$definitions = new JsonFilesDefinitions(
    name: 'product', // a definitions name
    dirs: new Dirs(new Dir('dir/private/picture-definitions/'))
);

var_dump($definitions instanceof DefinitionsInterface);
// bool(true)

示例目录

private/
    picture-definitions/
        product.json
        ...

示例JSON定义

{
    "img": {
        "src": {
            "width": 300,
            "height": null,
            "descriptor": null,
            "mimeType": "image/png",
            "url": null,
            "path": null,
            "options": []
        },
        "srcset": [
            {
                "width": 200
            }
        ],
        "attributes": {
            "key": "value"
        }
    },
    "sources": [
        {
            "srcset": [
                {
                    "width": 200,
                    "height": null,
                    "descriptor": null,
                    "url": null,
                    "path": null,
                    "options": []
                }
            ],
            "attributes": {
                "key": "value"
            }
        }
    ],
    "attributes": {
        "key": "value"
    },
    "options": {
        "key": "value"
    }
}

栈定义

use Tobento\Service\Picture\Definition\ArrayDefinition;
use Tobento\Service\Picture\Definitions\Definitions;
use Tobento\Service\Picture\Definitions\StackDefinitions;
use Tobento\Service\Picture\DefinitionsInterface;

$definitions = new StackDefinitions(
    'name', // a definitions name
    new Definitions('product', new ArrayDefinition('product-main', ['img' => ['src' => [50]]])),
    // ... DefinitionsInterface
);

var_dump($definitions instanceof DefinitionsInterface);
// bool(true)

图片

图片类可用于创建、存储或渲染图片。

use Tobento\Service\Picture\Img;
use Tobento\Service\Picture\ImgInterface;
use Tobento\Service\Picture\Picture;
use Tobento\Service\Picture\PictureInterface;
use Tobento\Service\Picture\Sources;
use Tobento\Service\Picture\SourcesInterface;
use Tobento\Service\Picture\Src;

$picture = new Picture(
    img: new Img(
        src: new Src(),
    ),
    sources: new Sources(),
    attributes: [],
    options: [],
);

var_dump($picture instanceof PictureInterface);
// bool(true)

// returns the img:
var_dump($picture->img() instanceof ImgInterface);
// bool(true)

// returns a new instance with the given img:
$picture = $picture->withImg(new Img(new Src()));

// returns the sources:
var_dump($picture->sources() instanceof SourcesInterface);
// bool(true)

// returns a new instance with the given sources:
$picture = $picture->withSources(new Sources());

// returns the attributes:
$attributes = $picture->attributes();

// returns a new instance with the given attributes:
$picture = $picture->withAttributes([]);

// returns the options:
$options = $picture->options();

// returns a new instance with the given options:
$picture = $picture->withOptions([]);

Srces

srces方法返回一个包含所有收集的Src类的生成器

use Tobento\Service\Picture\Img;
use Tobento\Service\Picture\Picture;
use Tobento\Service\Picture\Sources;
use Tobento\Service\Picture\Src;
use Tobento\Service\Picture\SrcInterface;

$picture = new Picture(
    img: new Img(
        src: new Src(),
    ),
    sources: new Sources(),
);

foreach($picture->srces() as $src) {
    var_dump($src instanceof SrcInterface);
    // bool(true)
}

toTag

toTag方法返回一个新的创建的图片标签。

use Tobento\Service\Picture\Img;
use Tobento\Service\Picture\Picture;
use Tobento\Service\Picture\PictureTagInterface;
use Tobento\Service\Picture\Sources;
use Tobento\Service\Picture\Src;

$picture = new Picture(
    img: new Img(
        src: new Src(),
    ),
    sources: new Sources(),
);

var_dump($picture->toTag() instanceof PictureTagInterface);
// bool(true)

查看图片标签部分以了解有关默认的PictureTagInterface::class的更多信息。

jsonSerialize

jsonSerialize 方法将对象序列化为可以由 json_encode() 原生序列化的值。

use Tobento\Service\Picture\Img;
use Tobento\Service\Picture\Picture;
use Tobento\Service\Picture\Sources;
use Tobento\Service\Picture\Src;

$picture = new Picture(
    img: new Img(
        src: new Src(),
    ),
    sources: new Sources(),
);

$jsonSerialized = $picture->jsonSerialize();

Img

use Tobento\Service\Picture\Img;
use Tobento\Service\Picture\ImgInterface;
use Tobento\Service\Picture\Src;
use Tobento\Service\Picture\SrcInterface;
use Tobento\Service\Picture\Srcset;
use Tobento\Service\Picture\SrcsetInterface;

$img = new Img(
    src: new Src(), // SrcInterface
    srcset: new Srcset(), // null|SrcsetInterface
    attributes: [],
);

var_dump($img instanceof ImgInterface);
// bool(true)

// returns the src:
var_dump($img->src() instanceof SrcInterface);
// bool(true)

// returns a new instance with the given src:
$img = $img->withSrc(new Src());

// returns the srcset or null if none:
var_dump($img->srcset() instanceof SrcsetInterface);
// bool(true)

// returns a new instance with the given srcset:
$img = $img->withSrcset(new Srcset());

// returns the attributes:
$attributes = $img->attributes();

// returns a new instance with the given attributes:
$img = $img->withAttributes([]);

// json serialize:
$jsonSerialized = $img->jsonSerialize();

来源

use Tobento\Service\Picture\Source;
use Tobento\Service\Picture\SourceInterface;
use Tobento\Service\Picture\Sources;
use Tobento\Service\Picture\SourcesInterface;
use Tobento\Service\Picture\Srcset;
use Tobento\Service\Picture\SrcInterface;

$sources = new Sources(
    new Source(new Srcset()),
    new Source(new Srcset()),
);

var_dump($sources instanceof SourcesInterface);
// bool(true)

// iterate sources:
foreach($sources as $source) {
    var_dump($source instanceof SourceInterface);
    // bool(true)
}
// or
foreach($sources->all() as $source) {}

// count sources:
var_dump($sources->count());
// int(2)

// returns all collected Src classes:
foreach($sources->srces() as $src) {
    var_dump($src instanceof SrcInterface);
    // bool(true)
}

// json serialize:
$jsonSerialized = $sources->jsonSerialize();

源代码

use Tobento\Service\Picture\Source;
use Tobento\Service\Picture\SourceInterface;
use Tobento\Service\Picture\Srcset;
use Tobento\Service\Picture\SrcsetInterface;

$source = new Source(
    srcset: new Srcset(),
    attributes: []
);

var_dump($source instanceof SourceInterface);
// bool(true)

// returns the srcset or null if none:
var_dump($source->srcset() instanceof SrcsetInterface);
// bool(true)

// returns a new instance with the given srcset:
$source = $source->withSrcset(new Srcset());

// returns the attributes:
$attributes = $source->attributes();

// returns a new instance with the given attributes:
$source = $source->withAttributes([]);

// json serialize:
$jsonSerialized = $source->jsonSerialize();

Srcset

use Tobento\Service\Picture\Src;
use Tobento\Service\Picture\SrcInterface;
use Tobento\Service\Picture\Srcset;
use Tobento\Service\Picture\SrcsetInterface;

$srcset = new Srcset(
    new Src(width: 200, descriptor: '1x'),
    new Src(width: 400, descriptor: '2x'),
);

var_dump($srcset instanceof SrcsetInterface);
// bool(true)

// iterate srces:
foreach($srcset as $src) {
    var_dump($src instanceof SrcInterface);
    // bool(true)
}
// or
foreach($srcset->all() as $src) {}

// count srces:
var_dump($srcset->count());
// int(2)

// json serialize:
$jsonSerialized = $srcset->jsonSerialize();

Src

use Tobento\Service\Imager\Response\Encoded;
use Tobento\Service\Picture\Src;
use Tobento\Service\Picture\SrcInterface;

$src = new Src(
    width: 200, // null|int
    height: 200, // null|int
    descriptor: '200w', // null|string, may be used for srcset
    mimeType: 'image/jpeg', // null|string
    url: null, // null|string
    path: null, // null|string
    encoded: null, // null|Encoded
    options: [],
);

var_dump($src instanceof SrcInterface);
// bool(true)

// returns the width or null if none:
var_dump($src->width());
// int(200)

// returns a new instance with the given width:
$src = $src->withWidth(300); // or null

// returns the height or null if none:
var_dump($src->height());
// int(200)

// returns a new instance with the given height:
$src = $src->withHeight(300); // or null

// returns the descriptor or null if none:
var_dump($src->descriptor());
// string(4) "200w"

// returns a new instance with the given descriptor:
$src = $src->withDescriptor('1x'); // or null

// returns the mimeType or null if none:
var_dump($src->mimeType());
// string(10) "image/jpeg"

// returns a new instance with the given mimeType:
$src = $src->withMimeType('image/gif'); // or null

// returns the url or null if none:
var_dump($src->url());
// NULL or string

// returns a new instance with the given url:
$src = $src->withUrl('https://example.com/image.jpg'); // or null

// returns the path or null if none:
var_dump($src->path());
// NULL or string

// returns a new instance with the given path:
$src = $src->withPath('path/image.jpg'); // or null

// returns the encoded or null if none:
var_dump($src->encoded());
// NULL or Encoded

// returns a new instance with the given encoded:
$src = $src->withEncoded(null); // or Encoded

// returns the options:
var_dump($src->options());
// array(0) { }

// returns a new instance with the given options:
$src = $src->withOptions([]);

// json serialize:
$jsonSerialized = $src->jsonSerialize();

图片工厂

可以使用图片工厂来创建图片。

use Tobento\Service\Picture\PictureFactory;
use Tobento\Service\Picture\PictureFactoryInterface;

$factory = new PictureFactory(
    // you may throw exceptions if an error occurs:
    throwOnError: true, // false is default
);

var_dump($factory instanceof PictureFactoryInterface);
// bool(true)

从数组创建

使用 createFromArray 方法从给定的数组创建图片

use Tobento\Service\Picture\PictureFactory;
use Tobento\Service\Picture\PictureInterface;

$picture = (new PictureFactory())->createFromArray([
    'img' => [
        'src' => [
            'width' => 300,
            'height' => null,
            'descriptor' => '2x', // or null
            'mimeType' => 'image/jpeg', // or null
            'url' => null,
            'path' => null,
            'options' => [],
        ],
        'srcset' => [
            ['width' => 200],
        ],
        'attributes' => ['key' => 'value'],
    ],
    'sources' => [
        [
            'srcset' => [
                [
                    'width' => 200,
                    'height' => null,
                    'descriptor' => null,
                    'url' => null,
                    'path' => null,
                    'options' => [],
                ],
            ],
            'attributes' => ['key' => 'value']
        ],
    ],
    'attributes' => ['key' => 'value'],
    'options' => ['key' => 'value'],
]);

var_dump($picture instanceof PictureInterface);
// bool(true)

图片标签工厂

可以使用图片标签工厂来创建图片标签。

use Tobento\Service\Picture\PictureTagFactory;
use Tobento\Service\Picture\PictureTagFactoryInterface;

$factory = new PictureTagFactory();

var_dump($factory instanceof PictureTagFactoryInterface);
// bool(true)

从图片创建

使用 createFromPicture 方法从给定的图片创建图片标签

use Tobento\Service\Picture\Img;
use Tobento\Service\Picture\Picture;
use Tobento\Service\Picture\PictureTagFactory;
use Tobento\Service\Picture\PictureTagInterface;
use Tobento\Service\Picture\Sources;
use Tobento\Service\Picture\Src;

$picture = new Picture(
    img: new Img(
        src: new Src(url: 'https://example.com/image.jpg'),
    ),
    sources: new Sources(),
);

$pictureTag = (new PictureTagFactory())->createFromPicture($picture);

var_dump($pictureTag instanceof PictureTagInterface);
// bool(true)

图片标签

图片标签渲染图片 HTML 标签。

use Tobento\Service\Picture\PictureTag;
use Tobento\Service\Picture\PictureTagInterface;
use Tobento\Service\Tag\Attributes;
use Tobento\Service\Tag\Tag;
use Tobento\Service\Tag\TagInterface;

$picture = new PictureTag(
    new Tag(name: 'picture'),
    new Tag(name: 'img', attributes: new Attributes(['src' => 'image.jpg'])),
    new Tag(name: 'source', attributes: new Attributes(['srcset' => 'image.webp', 'type' => 'image/webp'])),
    new Tag(name: 'source', attributes: new Attributes(['srcset' => 'image.avif', 'type' => 'image/avif'])),
);

var_dump($picture instanceof PictureTagInterface);
// bool(true)

var_dump($picture instanceof \Stringable);
// bool(true)

// returns the "picture" tag:
var_dump($picture->tag() instanceof TagInterface);
// bool(true)

// returns a new instance with the given "picture" tag:
$picture = $picture->withTag(new Tag('picture'));

// returns the "img" tag:
var_dump($picture->img() instanceof TagInterface);
// bool(true)

// returns a new instance with the given "img" tag:
$picture = $picture->withImg(new Tag('img'));

// returns the "source" tags:
foreach($picture->sources() as $source) {
    var_dump($source instanceof TagInterface);
    // bool(true)
}

// returns a new instance with the given "source" tags:
$picture = $picture->withSources(
    new Tag(name: 'source', attributes: new Attributes(['srcset' => 'image.webp', 'type' => 'image/webp'])),
    new Tag(name: 'source', attributes: new Attributes(['srcset' => 'image.avif', 'type' => 'image/avif'])),
);

// returns a new instance with the given "picture" attribute:
$picture = $picture->attr(name: 'data-foo', value: 'Foo');

// returns a new instance with the given "img" attribute:
$picture = $picture->imgAttr(name: 'data-bar', value: 'Bar');

您可以查看 标签服务 - 标签接口 部分以了解关于 TagInterface::class 的更多信息。

渲染图片

<?= $picture->render() ?>

// or just
<?= $picture ?>

空图片标签

空图片标签根本不渲染任何内容,在某些情况下可能很有用。

use Tobento\Service\Picture\PictureTagInterface;
use Tobento\Service\Picture\NullPictureTag;

$picture = new NullPictureTag();

var_dump($picture instanceof PictureTagInterface);
// bool(true)

var_dump((string)$picture);
// string(0) ""

鸣谢