ibrand/laravel-miniprogram-poster
ibrand/laravel-miniprogram-poster is a Laravel package for generating WeChat mini program sharing posters. It composes QR codes, images, and text into downloadable poster images through a simple, configurable API, streamlining referral and share-card workflows for PHP applications.
Install and wire up
composer require ibrand/laravel-miniprogram-poster
php artisan vendor:publish --provider="iBrand\MiniProgramPoster\ServiceProvider"
Laravel 5.5+ auto-discovers the provider and registers a facade alias. Confirm the config lands in config/ (the package predates the config/ibrand-*.php naming convention, so check the provider's mergeConfigFrom call rather than guessing the filename).
Check your runtime before you write a line of code. This package is a thin wrapper over intervention/image 2.x, which means GD (or Imagick). Verify:
php -r "var_dump(extension_loaded('gd'), function_exists('imagecreatefrompng'), function_exists('imagettftext'));"
Missing FreeType is the classic failure — the poster renders but any text layer is blank or fatal.
Where to look first. The package is small — read src/ end to end (it's a handful of classes) before integrating. There is no docs site, the README is minimal, and the facade is the real API surface. src/ServiceProvider.php → facade → the single poster/composition class tells you everything: constructor signature, how the background is loaded, how layer coordinates are passed, and what save() returns.
First use case — share poster for a mini-program page. The canonical job: take a background template, composite a mini-program QR code (obtained from WeChat's wxacode.getUnlimited API) into a fixed slot, save, return a URL the front-end renders in a share sheet.
use iBrand\MiniProgramPoster\Facades\MiniProgramPoster;
// QR PNG already fetched and cached from wxacode.getUnlimited
$path = MiniProgramPoster::make(public_path('posters/base-750x1334.png'))
->qrcode($qrPng, 275, 940, 200, 200) // x, y, w, h
->save(storage_path("app/public/posters/{$hash}.png"));
Method names vary by release — treat the above as the shape, and open the facade to get the exact ones. The important part is that you supply the QR as an image file; this package does not call WeChat for you.
Two-stage pipeline: fetch QR, then compose. Keep these separate. Fetching the QR involves an access token, HTTP, and rate limits; composition is local CPU. A QrCodeService (cache keyed by scene, backed by Cache::remember with a TTL shorter than the token) feeding a PosterService that owns the facade call keeps failures diagnosable — when a poster is blank you know instantly whether the QR or the composite broke.
Never generate on the share path. onShareAppMessage fires on tap and users expect an instant sheet. Generate on a write event (user "creates" a card, completes an order) or push it to a queue. A 2000×3000 PNG composite is 50–150 ms of pure CPU and will happily block a php-fpm worker.
Cache by content hash, not by user. The poster identity is f(template_id, page, scene, template_version). Store hash as a column or the filename and skip regeneration when it matches. Bump template_version when marketing swaps the background so old posters invalidate cleanly.
Config-driven layout. Put layer geometry (x/y/w/h per template) in config or a DB table, not in code. Marketing adds templates far more often than you'd like, and the whole package is "composite N layers" — layer positions are data.
Always write through the filesystem abstraction. Wrap the package's save() in Storage::disk('public') (or COS/OSS). Poster URLs get shared into WeChat group chats and live for years; you will migrate off local disk.
Confine the facade to one class. A PosterService that calls MiniProgramPoster and nothing else makes the eventual replacement (see gotchas) a one-file change instead of a grep across the app.
Testing. Freeze a fixture background and QR, assert output dimensions and that a few pixels inside the QR slot differ from the background. Do not snapshot-compare image bytes — GD/Imagick version drift makes those flaky.
illuminate/* constraints almost certainly cap out around Laravel 5.7/5.8. On Laravel 9+ you'll be fighting composer or forking. Given the code is a few hundred lines, copying it into app/Support/ and dropping the dependency is usually cheaper than patching the constraint — and you gain the ability to fix the remaining items below.imagecopyresampled into a non-square slot, or cropping into the white border, produces a poster that looks perfect and won't scan. Crop/letterbox the background slot, never the QR. Most "WeChat can't scan it" tickets are this..ttf with read permission. imagettftext fails noisily on some builds and silently draws nothing on others. Ship the font inside your repo and reference it via resource_path().->destroy() on intermediates and keep memory_limit at 256M+.false or a PHP warning, not an exception. Wrap composition in try/finally and during development dump each intermediate layer to a temp dir so you can see which one is missing.rename() into place (atomic on the same filesystem), or gate with a cache lock.getUnlimited codes are permanent per scene, but if you're using a short-lived code variant the cached poster goes stale — include expiry in the hash.Intervention\Image calls on the result yourself, or subclass the poster class and add your own layer methods.How can I help you explore Laravel packages today?