yilanboy/preview
Composer 安装命令:
composer require yilanboy/preview
包简介
Generate the preview image
README 文档
README
A simple package to generate a preview image.
Installation
Install the package with composer.
composer require yilanboy/preview
Then create an image generator.
use Yilanboy\Preview\Canvas\Solid; use Yilanboy\Preview\Canvas\Enums\Margin; use Yilanboy\Preview\Canvas\Enums\Format; use Yilanboy\Preview\Canvas\Enums\Size; use Yilanboy\Preview\Generator; use Yilanboy\Preview\Text\Enums\Font; use Yilanboy\Preview\Text\Enums\FontSize; use Yilanboy\Preview\Text\TextBlock; new Generator() ->size(Size::OpenGraph) ->margin(Margin::Medium) ->format(Format::PNG) ->background(new Solid('#777bb3')) ->title(new TextBlock( text: 'Preview', color: 'white', fontSize: FontSize::Large, font: Font::Inter, )) ->description(new TextBlock( text: 'A simple PHP package to create preview image', color: 'white', fontSize: FontSize::Small, font: Font::Inter, )) ->output();
This code will display the following image on the web page.
Examples
The most common use for this package is generating an Open Graph image — the
preview card shown when a link is shared on social media. Instead of designing one by hand for every
blog post, generate it from the post's own title and description. (Generator defaults to
Size::OpenGraph, so the dimensions are already right.)
Laravel
Serve it on the fly. Point a route at each post and render the image straight to the response:
use App\Models\Post; use Yilanboy\Preview\Canvas\Enums\Format; use Yilanboy\Preview\Canvas\Gradient; use Yilanboy\Preview\Generator; use Yilanboy\Preview\Text\Enums\FontSize; use Yilanboy\Preview\Text\TextBlock; Route::get('/posts/{post}/og.png', function (Post $post) { $format = Format::PNG; $image = new Generator() ->format($format) ->background(new Gradient(from: '#1e3a8a', to: '#9333ea')) ->title(new TextBlock(text: $post->title, color: 'white', fontSize: FontSize::Medium)) ->bytes(); return response($image, 200, [ 'Content-Type' => $format->mimeType(), ]); })->name('posts.og');
Then reference the route in your page's <head> so social platforms pick it up:
<meta property="og:image" content="{{ route('posts.og', $post) }}">
Or generate it once, ahead of time. If you'd rather not render on every request, build the image when a post is published and save it to disk, then serve the static file:
$image = new Generator() ->background(new Gradient(from: '#1e3a8a', to: '#9333ea')) ->title(new TextBlock(text: $post->title, color: 'white', fontSize: FontSize::Medium)) ->bytes(); Storage::put("images/posts/{$post->id}/og.png", $image);
Canvas
Size
Pick a preset that matches where the image will be embedded. Generator defaults to Size::OpenGraph.
use Yilanboy\Preview\Canvas\Enums\Size; $generator->size(Size::Square);
| Preset | Dimensions | Where it's used |
|---|---|---|
OpenGraph |
1200 × 630 | Facebook, generic Open Graph previews |
Square |
1080 × 1080 | Instagram, LinkedIn square posts |
Landscape |
1920 × 1080 | 16:9 landscape, slide / hero images |
Portrait |
1080 × 1920 | 9:16 vertical, stories and reels |
YouTube |
1280 × 720 | YouTube video thumbnails |
If no preset fits, set the width and height yourself. Both must be at least 1, otherwise an
InvalidInput exception is thrown. size() and dimensions() set the same canvas size, so the last call wins.
$generator->dimensions(width: 800, height: 418);
Margin
Text is inset from the canvas edges by a fixed pixel margin. Generator defaults to Margin::Medium (60px).
use Yilanboy\Preview\Canvas\Enums\Margin; $generator->margin(Margin::Large);
| Preset | Pixels |
|---|---|
None |
0 |
Small |
30 |
Medium |
60 |
Large |
90 |
ExtraLarge |
120 |
Backgrounds
Generator::background() accepts anything implementing the Background interface. Three implementations ship with the
package.
Solid — a flat color.
use Yilanboy\Preview\Canvas\Solid; $generator->background(new Solid('#777bb3'));
Gradient — two colors interpolated across the canvas.
use Yilanboy\Preview\Canvas\Gradient; use Yilanboy\Preview\Canvas\Enums\GradientDirection; $generator->background(new Gradient( from: '#1e3a8a', to: '#9333ea', direction: GradientDirection::Diagonal, ));
GradientDirection cases: Vertical (default) · Horizontal · Diagonal.
Image — render a bitmap behind your text.
use Yilanboy\Preview\Canvas\Image; use Yilanboy\Preview\Canvas\Enums\ImageFit; $generator->background(new Image( path: __DIR__.'/cover.jpg', fit: ImageFit::Cover, opacity: 0.6, tint: '#000000', ));
ImageFit cases: Cover (default) · Contain · Stretch · Tile.
opacity is a float between 0.0 and 1.0 (default 1.0). When opacity < 1.0, the canvas is filled with tint
first so the tint color shows through the partially transparent image — use it to darken or wash the background. tint
defaults to #000000.
See all three modes interactively in the playground (next section).
Text
TextBlock
TextBlock is a final readonly class, so it's immutable. Every constructor
argument is named and defaulted — to vary a field, construct a new instance:
$base = new TextBlock(text: 'Hello'); $red = new TextBlock(text: 'Hello', color: 'red'); $big = new TextBlock(text: 'Hello', fontSize: FontSize::Huge);
If no FontSize preset fits, pass a custom size in pixels instead. It must be at least 1, otherwise an
InvalidInput exception is thrown.
$custom = new TextBlock(text: 'Hello', fontSize: 42);
Available customization enums live under Yilanboy\Preview\Text\Enums:
| Enum | Cases |
|---|---|
Font |
Inter · InterMedium · Roboto · RobotoMedium · JetBrainsMono · JetBrainsMonoMedium · NotoSans · NotoSansMedium · NotoSansSC · NotoSansSCMedium · NotoSansTC · NotoSansTCMedium · NotoSansJP · NotoSansJPMedium |
FontSize |
ExtraSmall (24) · Small (32) · Medium (50) · Large (64) · ExtraLarge (80) · Huge (100) |
Alignment |
Left · Center · Right |
LineHeight |
Snug (1.15) · Normal (1.3) · Relaxed (1.5) · Loose (1.75) |
All 14 bundled fonts are static TrueType instances shipped under SIL OFL, with separate files per weight because GD
cannot select a weight from a variable font: each family ships a Regular (400) and a Medium (500) variant (the *Medium
cases). Inter is the 24pt optical cut. NotoSansTC covers Latin + Traditional Chinese, NotoSansSC covers Latin +
Simplified Chinese, and NotoSansJP covers Latin + Japanese; NotoSans, Inter, Roboto, and JetBrainsMono (a
monospaced family) are Latin-only.
Currently, the text supports English, Chinese (Traditional and Simplified), and Japanese.
Alignment controls how each line is positioned horizontally within the margins. TextBlock defaults to
Alignment::Left.
use Yilanboy\Preview\Text\Enums\Alignment; use Yilanboy\Preview\Text\TextBlock; $generator->title(new TextBlock( text: 'Preview', alignment: Alignment::Center, ));
Line Height
When text wraps to multiple lines, LineHeight controls the spacing between them. The value is a unit-less multiplier
of the text's font size (CSS line-height semantics). TextBlock defaults to LineHeight::Normal (1.3×).
use Yilanboy\Preview\Text\Enums\LineHeight; use Yilanboy\Preview\Text\TextBlock; $generator->description(new TextBlock( text: 'A longer description that wraps to multiple lines for demonstration purposes.', lineHeight: LineHeight::Loose, ));
| Preset | Multiplier |
|---|---|
Snug |
1.15× |
Normal |
1.3× |
Relaxed |
1.5× |
Loose |
1.75× |
Custom Fonts
The font argument also accepts a filesystem path to your own font file, instead of a bundled Font case.
use Yilanboy\Preview\Text\TextBlock; new TextBlock( text: 'Hello', font: __DIR__.'/fonts/MyFont.ttf', );
Only TrueType (.ttf) files are supported. OpenType (.otf) is rejected. A path is accepted only when all of
the following hold:
- the file exists and is readable;
- the extension is
.ttf(case-insensitive); - the file's first 4 bytes are the TrueType
sfntheader (0x00010000) — this is what rejects an.otfrenamed to.ttf, whose header isOTTO.
If the path is not a valid TrueType font, the constructor throws an InvalidInput exception with the message
The font path is not a valid TrueType font file. Validation runs in the constructor, so an invalid TextBlock can
never exist — construction fails fast.
Security: the font path is read straight off disk and is treated as trusted input. It must come from you, the developer — never from unsanitised end-user input, which would enable arbitrary file reads and file-existence probing.
Output
There are three ways to produce the final image:
output()renders it, sets the HTTPContent-Typeheader from the format's MIME type, and writes the bytes straight to the response. This is convenient for plain PHP scripts; in frameworks like Laravel or Symfony, preferbytes()and return a framework response instead.save($path)renders it and writes the bytes to a file.bytes()renders it and returns the encoded bytes as a string, which is useful for framework responses or object storage.
$generator->output(); // serve in the HTTP response $generator->save('preview.png'); // write to a file $image = $generator->bytes(); // return encoded image bytes
format() selects the encoding. Format has three cases — PNG (default), JPEG, and WEBP.
use Yilanboy\Preview\Canvas\Enums\Format; $generator->format(Format::JPEG);
quality() changes the output quality for lossy formats (JPEG and WEBP). It accepts values from 0 to 100.
$generator ->format(Format::WEBP) ->quality(85);
Note:
quality()does not apply toPNG. PNG compression is lossless, so changing compression affects encoding speed and file size, not visual image quality.
Note: the format set via
format()always wins —save()does not look at the file extension. The configured format is the single source of truth, soformat(Format::JPEG)->save('preview.png')writes JPEG bytes into a file namedpreview.png. Keep the extension and format in sync yourself.
Exceptions
Everything the library throws lives under Yilanboy\Preview\Exceptions. Invalid input (bad colors, font paths,
dimensions, etc.) throws InvalidInput, and render-time GD failures throw RenderFailure. Both implement the
PreviewException marker interface and still extend their SPL parents (InvalidArgumentException /
RuntimeException), so existing catch blocks keep working.
use Yilanboy\Preview\Exceptions\PreviewException; try { $generator->save($path); } catch (PreviewException $e) { // anything this library threw }
Start a Local Server to Show the Image
There is a playground.php file in examples folder. Start a local server to open an interactive form where you can
edit the title, description, font, and font size, switch between Solid / Gradient / Image backgrounds, preview
gradients live via CSS, and tweak image opacity and tint with sliders.
php -S localhost:8000 examples/playground.php
Then open your browser and visit localhost:8000.
Development
Run tests:
composer tests
Format code with Pint (only dirty files):
composer fmt
Run all checks (Pint + PHPStan):
composer check
Snapshot Testing
The image tests use snapshot testing: each test generates a PNG and compares it against a stored reference image in
tests/Fixtures/. The comparison is tolerant rather than pixel-exact — it ignores anti-aliasing noise that differs
between macOS and Linux FreeType builds, while still catching real rendering changes (different text, color, or layout).
When you make an intentional change to rendering output, regenerate the fixtures by setting the UPDATE_SNAPSHOTS
environment variable (any non-empty value other than 0 works):
UPDATE_SNAPSHOTS=1 composer tests
Each snapshot test detects the variable and overwrites its fixture in tests/Fixtures/ with the freshly generated
image. Always open the regenerated PNGs and confirm they look correct before committing — once a fixture is updated,
it becomes the new source of truth.
yilanboy/preview 适用场景与选型建议
yilanboy/preview 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 88 次下载、GitHub Stars 达 3, 最近一次更新时间为 2024 年 11 月 28 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「image」 「preview」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 yilanboy/preview 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 yilanboy/preview 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 yilanboy/preview 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Enable api support and preview module
Yii2 LightBox image galary widget uses Lightbox v2.10.0 by Lokesh Dhakar
The Yii2 extension uses jQuery jquery.carousel-1.1.min.js and makes image carousel from php array of structure defined.
Preview of settings in footer of tt_content element in page module.
A tool for scraping URL resources (oEmbed, OpenGraph, Twitter cards, JSON-LD)
The Yii2 extension uses jQuery PrettyPhoto and OwlCarousel js and makes image galary from php array of structure defined.
统计信息
- 总下载量: 88
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 4
- 点击次数: 4
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2024-11-28
