PHPackages                             tekkenking/tinypeexi - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. tekkenking/tinypeexi

ActiveLibrary[API Development](/categories/api)

tekkenking/tinypeexi
====================

A fluent Laravel package for integrating with the Lossless Media Service (aipeexi).

v1.0.1(2mo ago)021—0%MITPHPPHP ^8.1

Since Mar 5Pushed 2mo agoCompare

[ Source](https://github.com/tekkenking/laravel_tiny_peexi)[ Packagist](https://packagist.org/packages/tekkenking/tinypeexi)[ RSS](/packages/tekkenking-tinypeexi/feed)WikiDiscussions dev Synced 1mo ago

READMEChangelog (2)Dependencies (5)Versions (4)Used By (0)

🖼️ TinyPeexi — Laravel Plugin for Lossless Media Service
========================================================

[](#️-tinypeexi--laravel-plugin-for-lossless-media-service)

> **Upload, transform, and deliver images from your Laravel app in minutes.**

TinyPeexi is a Laravel package that gives you a clean, fluent PHP API to interact with a self-hosted [aipeexi / Lossless Media Service](https://github.com/tekkenking/aipeexi) instance. Upload images, generate optimized variants, apply effects, create e-commerce product shots, and get CDN-ready delivery URLs — all without leaving your Laravel codebase.

---

📦 Installation
--------------

[](#-installation)

### 1. Require via Composer

[](#1-require-via-composer)

```
composer require tekkenking/tinypeexi
```

### 2. Publish the Config File

[](#2-publish-the-config-file)

```
php artisan vendor:publish --provider="Tekkenking\TinyPeexi\TinyPeexiServiceProvider"
```

This creates `config/tinypeexi.php` in your Laravel project.

### 3. Add Your Credentials to `.env`

[](#3-add-your-credentials-to-env)

```
TINYPEEXI_API_URL=http://localhost:8080
TINYPEEXI_TENANT_SLUG=dev
TINYPEEXI_API_KEY=sk_live_your_api_key_here
```

**That's it.** You're ready to use TinyPeexi.

---

🚀 Quick Start
-------------

[](#-quick-start)

```
use Tekkenking\TinyPeexi\Facades\TinyPeexi;

// Upload an image
$asset = TinyPeexi::upload($request->file('photo'));

// Generate a 400px wide WebP variant
$variant = TinyPeexi::variant($asset->sha)
    ->resize(400)
    ->format('webp')
    ->quality(80)
    ->generate();

// Get the public URL
echo $variant->url();
// => http://localhost:8080/a/dev/abc123.../w400.webp
```

---

📖 Full API Reference
--------------------

[](#-full-api-reference)

### Uploading Assets

[](#uploading-assets)

#### Upload from a Form Request

[](#upload-from-a-form-request)

```
$asset = TinyPeexi::upload($request->file('image'));

echo $asset->sha; // "a1b2c3d4e5f6..."
```

#### Upload from a File Path

[](#upload-from-a-file-path)

```
$asset = TinyPeexi::upload('/path/to/local/image.png');

echo $asset->sha;
```

The `upload()` method returns an `AssetDto` with the asset's `sha` (SHA-256 hash), which you'll use as the identifier for all future operations on this image.

#### Uploading Multiple Files at Once

[](#uploading-multiple-files-at-once)

TinyPeexi supports uploading multiple files in a single HTTP request (the backend defaults to a max of 10 files per request).

```
$files = $request->file('gallery_images'); // Array of UploadedFile

$assets = TinyPeexi::uploadMany($files);

foreach ($assets as $asset) {
    echo $asset->sha . "\n";
}
```

The `uploadMany()` method returns an array of `AssetDto` objects.

---

### 🎨 Blade &amp; View Helpers

[](#-blade--view-helpers)

TinyPeexi includes a global helper function `tinypeexi()` to natively integrate into your views. Furthermore, the Variant builder automatically converts directly into a URL string when echoed, keeping your Blade templates incredibly clean.

#### 1. The Fluent Way (Cleanest)

[](#1-the-fluent-way-cleanest)

You don't need to call `->url()`. Just echo the builder directly!

```

```

#### 2. The Array Shorthand (Shortest)

[](#2-the-array-shorthand-shortest)

Pass parameters dynamically if you prefer:

```

```

#### 3. Using Config Presets

[](#3-using-config-presets)

Instantly apply predefined transformations from your `tinypeexi.php` config:

```

```

---

### Bulk Asset Migration

[](#bulk-asset-migration)

TinyPeexi includes a powerful Artisan command to migrate your existing local files into the Lossless Media Service. It is memory-safe, supports batching, queue-based variant generation, and uses a CSV file (`storage/app/tinypeexi_migration_results.csv`) for idempotency, meaning if the process dies, you can run the exact same command again and it will pick up right where it left off!

```
php artisan tinypeexi:migrate \
    --path="/var/www/uploads/2023|/var/www/uploads/2024" \
    --ext="jpg|png|webp" \
    --starts-with="product_|user_" \
    --variants="w800,h800|w200" \
    --batch=50
```

- `--path`: Pipe-separated list of directories to scan.
- `--ext`: Pipe-separated list of extensions to include.
- `--starts-with`: Optional pipe-separated list of filename prefixes to include.
- `--variants`: Optional pipe-separated list of variant dimensions to generate in the background (dispatches `GenerateTinyPeexiVariantJob`).
- `--batch`: Number of originals to upload per HTTP request (default: 50).

---

### Deleting Assets

[](#deleting-assets)

```
TinyPeexi::delete($sha);
```

Returns `true` on success, throws `TinyPeexiException` on failure.

---

### Generating Variants

[](#generating-variants)

The heart of TinyPeexi is the **fluent Variant Builder**. You start with `TinyPeexi::variant($sha)` and chain methods to describe the transformation you want.

#### Basic Resize

[](#basic-resize)

```
$variant = TinyPeexi::variant($sha)
    ->resize(800)
    ->format('jpeg')
    ->quality(85)
    ->generate();

echo $variant->url();
```

#### Resize with Exact Dimensions

[](#resize-with-exact-dimensions)

```
$variant = TinyPeexi::variant($sha)
    ->resize(800, 600)    // width, height
    ->fit('cover')        // crop to fill
    ->generate();
```

#### Available Fit Modes

[](#available-fit-modes)

ModeBehavior`cover`Crop to fill exact dimensions`contain`Fit within dimensions, letterbox if needed`fill`Stretch to exact dimensions (may distort)`inside`Fit inside, never upscale **(default)**`outside`Fit outside, may upscale to cover#### Retina / HiDPI Support

[](#retina--hidpi-support)

```
$variant = TinyPeexi::variant($sha)
    ->resize(400)
    ->dpr(2.0)    // Outputs 800px wide for retina displays
    ->generate();
```

---

### Cropping

[](#cropping)

#### Smart Crop

[](#smart-crop)

```
$variant = TinyPeexi::variant($sha)
    ->resize(400, 400)
    ->fit('cover')
    ->crop('face')        // AI-powered face detection crop
    ->generate();
```

#### Available Crop Positions

[](#available-crop-positions)

PositionDescription`center`Center of image **(default)**`top`Top edge`bottom`Bottom edge`left`Left edge`right`Right edge`topleft`Top-left corner`topright`Top-right corner`bottomleft`Bottom-left corner`bottomright`Bottom-right corner`face`AI face detection (Pro tier)`entropy`Smart crop using entropy analysis`attention`Smart crop using saliency/attention#### Manual Crop Rectangle

[](#manual-crop-rectangle)

```
$variant = TinyPeexi::variant($sha)
    ->cropRect(100, 50, 600, 400) // x, y, width, height
    ->generate();
```

#### Auto-Trim Whitespace

[](#auto-trim-whitespace)

```
$variant = TinyPeexi::variant($sha)
    ->trim(25) // threshold 0-255
    ->generate();
```

---

### Orientation

[](#orientation)

```
// Rotate 90 degrees clockwise
$variant = TinyPeexi::variant($sha)
    ->rotate(90)
    ->generate();

// Flip horizontally (mirror)
$variant = TinyPeexi::variant($sha)
    ->flip('h')
    ->generate();

// Auto-fix EXIF orientation
$variant = TinyPeexi::variant($sha)
    ->autoOrient()
    ->generate();
```

Rotate ValuesFlip Values`0`, `90`, `180`, `270`, `-90``h` (horizontal), `v` (vertical), `both`---

### Effects

[](#effects)

```
$variant = TinyPeexi::variant($sha)
    ->resize(800)
    ->blur(5.0)           // Gaussian blur (0.3 - 1000.0)
    ->sharpen(1.5)        // Sharpen (0.5 - 10.0)
    ->brightness(1.2)     // Brightness (0.1 - 10.0)
    ->contrast(1.1)       // Contrast (0.1 - 10.0)
    ->saturation(1.5)     // Saturation (0.0 - 2.0)
    ->generate();
```

#### Grayscale

[](#grayscale)

```
$variant = TinyPeexi::variant($sha)
    ->grayscale()
    ->format('jpeg')
    ->generate();
```

---

### E-Commerce Product Images

[](#e-commerce-product-images)

This is where TinyPeexi really shines. Creating uniform, professional product images is a single method call.

#### Using the Fluent Builder

[](#using-the-fluent-builder)

```
$variant = TinyPeexi::variant($sha)
    ->format('jpeg')
    ->ecommerce()          // Flag as e-commerce operation
    ->canvas(1024)         // 1024×1024 square canvas
    ->resize(800)          // Product fits within 800px
    ->pad(40)              // 40px breathing room
    ->background('white')  // Clean white background
    ->quality(90)
    ->generate();

echo $variant->url();
// => http://localhost:8080/a/dev/abc123.../w800.jpg
```

#### Using the Shorthand Helper

[](#using-the-shorthand-helper)

If you use the same e-commerce settings repeatedly, use the shorthand:

```
$variant = TinyPeexi::variant($sha)->ecommerceVariant();
// Uses defaults from config: canvas=1024, pad=40, bg=white, jpeg, q=85
```

#### Custom E-Commerce Settings

[](#custom-e-commerce-settings)

```
$variant = TinyPeexi::variant($sha)->ecommerceVariant(
    canvasSize: 800,
    padding: 20,
    background: 'transparent',
    format: 'png',
    quality: 100,
);
```

#### With AI Background Removal

[](#with-ai-background-removal)

```
$variant = TinyPeexi::variant($sha)
    ->removeBg()           // Remove background via AI
    ->canvas(1024)
    ->pad(40)
    ->background('white')
    ->format('jpeg')
    ->quality(90)
    ->generate();
```

---

### Watermarks

[](#watermarks)

#### Image Watermark

[](#image-watermark)

```
// First, upload your watermark image (do this once)
$watermark = TinyPeexi::upload('/path/to/watermark.png');

// Then apply it to any variant
$variant = TinyPeexi::variant($sha)
    ->resize(1200)
    ->watermark(
        assetSha: $watermark->sha,
        position: 'bottomright',
        opacity: 0.5,
        scale: 0.15,
    )
    ->generate();
```

#### Available Watermark Positions

[](#available-watermark-positions)

PositionDescription`center`Center of image`topleft`Top-left corner`topright`Top-right corner`bottomleft`Bottom-left corner`bottomright`Bottom-right corner **(default)**`tile`Tile across entire image---

### Using Presets

[](#using-presets)

Define reusable transformation presets in `config/tinypeexi.php`:

```
// In config/tinypeexi.php
'defaults' => [
    'thumbnail' => [
        'width' => 200,
        'height' => 200,
        'fit' => 'cover',
        'crop' => 'center',
        'format' => 'webp',
        'quality' => 80,
    ],
]
```

Then use them in your code:

```
$variant = TinyPeexi::variant($sha)
    ->preset('thumbnail')
    ->generate();
```

You can define as many presets as you need (e.g., `hero_banner`, `avatar`, `og_image`, etc.).

---

### Batch Variant Generation

[](#batch-variant-generation)

Generate multiple sizes at once:

```
TinyPeexi::variant($sha)->batch(
    sizes: [400, 800, 1200],
    format: 'webp',
);
// Queues: w400.webp, w800.webp, w1200.webp
```

---

### Output Formats

[](#output-formats)

FormatExtensionNotes`jpeg``.jpg`Best for photos`png``.png`Lossless, supports transparency`webp``.webp`Modern, smaller files **(default)**`avif``.avif`Newest, smallest files`gif``.gif`Animated images`tiff``.tiff`Print-quality`ico``.ico`Favicons`svg``.svg`Vector graphics---

⚙️ Configuration Reference
--------------------------

[](#️-configuration-reference)

After publishing, edit `config/tinypeexi.php`:

```
return [
    // === REQUIRED ===
    'api_url'      => env('TINYPEEXI_API_URL', 'http://localhost:8080'),
    'delivery_url' => env('TINYPEEXI_DELIVERY_URL', env('TINYPEEXI_API_URL', 'http://localhost:8080')),
    'tenant_slug'  => env('TINYPEEXI_TENANT_SLUG', 'dev'),
    'api_key'      => env('TINYPEEXI_API_KEY', ''),

    // === ADVANCED (optional) ===
    'advanced' => [
        'timeout'     => env('TINYPEEXI_TIMEOUT', 10),      // seconds
        'retries'     => env('TINYPEEXI_RETRIES', 3),
        'retry_delay' => env('TINYPEEXI_RETRY_DELAY', 500), // ms

        'upload' => [
            'max_filesize_bytes' => env('TINYPEEXI_MAX_UPLOAD_SIZE', 26214400), // 25MB
            'allowed_mimes'      => ['image/jpeg', 'image/png', 'image/webp', 'image/avif', 'image/gif'],
            'strip_metadata'     => env('TINYPEEXI_STRIP_METADATA', true),
            'auto_optimize'      => env('TINYPEEXI_AUTO_OPTIMIZE', false),
        ],
    ],

    // === PRESETS (optional) ===
    'defaults' => [
        'ecommerce' => [
            'canvas' => 1024, 'pad' => 40, 'background' => 'white',
            'format' => 'jpeg', 'quality' => 85,
        ],
        'thumbnail' => [
            'width' => 200, 'height' => 200, 'fit' => 'cover',
            'crop' => 'center', 'format' => 'webp', 'quality' => 80,
        ],
    ],
];
```

### Environment Variables

[](#environment-variables)

VariableDefaultDescription`TINYPEEXI_API_URL``http://localhost:8080`Base URL of aipeexi instance`TINYPEEXI_DELIVERY_URL`Same as API URLCDN/delivery URL`TINYPEEXI_TENANT_SLUG``dev`Your tenant slug`TINYPEEXI_API_KEY`*(empty)*Your API key`TINYPEEXI_TIMEOUT``10`HTTP timeout (seconds)`TINYPEEXI_RETRIES``3`Retry count for failed requests`TINYPEEXI_RETRY_DELAY``500`Delay between retries (ms)`TINYPEEXI_MAX_UPLOAD_SIZE``26214400`Max upload size (bytes)`TINYPEEXI_STRIP_METADATA``true`Strip EXIF on upload`TINYPEEXI_AUTO_OPTIMIZE``false`Auto-optimize on upload---

🧑‍💻 Real-World Examples
-----------------------

[](#‍-real-world-examples)

### Profile Avatar Upload

[](#profile-avatar-upload)

```
// In a Controller
public function updateAvatar(Request $request)
{
    $request->validate(['avatar' => 'required|image|max:5120']);

    $asset = TinyPeexi::upload($request->file('avatar'));

    // Generate a small square avatar
    $variant = TinyPeexi::variant($asset->sha)
        ->resize(200, 200)
        ->fit('cover')
        ->crop('face')
        ->format('webp')
        ->quality(80)
        ->generate();

    auth()->user()->update(['avatar_url' => $variant->url()]);

    return back()->with('success', 'Avatar updated!');
}
```

### Product Image Upload (E-Commerce)

[](#product-image-upload-e-commerce)

```
public function storeProduct(Request $request)
{
    $request->validate(['photo' => 'required|image|max:25600']);

    $asset = TinyPeexi::upload($request->file('photo'));

    // Professional product shot with white background
    $main = TinyPeexi::variant($asset->sha)->ecommerceVariant();

    // Also create a thumbnail
    $thumb = TinyPeexi::variant($asset->sha)
        ->preset('thumbnail')
        ->generate();

    Product::create([
        'name'          => $request->name,
        'image_sha'     => $asset->sha,
        'image_url'     => $main->url(),
        'thumbnail_url' => $thumb->url(),
    ]);

    return redirect()->route('products.index');
}
```

### Responsive Image Set

[](#responsive-image-set)

```
$asset = TinyPeexi::upload($request->file('hero'));

// Generate multiple sizes for responsive  element
TinyPeexi::variant($asset->sha)->batch(
    sizes: [400, 800, 1200, 1600],
    format: 'webp',
);

// In your Blade template:
//
//
//
```

### Blog Post with Watermarked Images

[](#blog-post-with-watermarked-images)

```
$watermarkAsset = TinyPeexi::upload('/path/to/blog-watermark.png');

$asset = TinyPeexi::upload($request->file('blog_image'));

$variant = TinyPeexi::variant($asset->sha)
    ->resize(1200)
    ->format('jpeg')
    ->quality(85)
    ->watermark(
        assetSha: $watermarkAsset->sha,
        position: 'bottomright',
        opacity: 0.3,
        scale: 0.1,
    )
    ->generate();
```

---

🔧 Error Handling
----------------

[](#-error-handling)

All errors throw `TinyPeexiException`:

```
use Tekkenking\TinyPeexi\Exceptions\TinyPeexiException;

try {
    $asset = TinyPeexi::upload($request->file('image'));
} catch (TinyPeexiException $e) {
    Log::error('TinyPeexi upload failed', [
        'message' => $e->getMessage(),
        'code'    => $e->getCode(),
    ]);

    return back()->withErrors(['image' => 'Image upload failed. Please try again.']);
}
```

---

🧪 Testing
---------

[](#-testing)

When writing tests, you can mock the TinyPeexi facade:

```
use Tekkenking\TinyPeexi\Facades\TinyPeexi;
use Tekkenking\TinyPeexi\DTOs\AssetDto;

TinyPeexi::shouldReceive('upload')
    ->once()
    ->andReturn(new AssetDto('fake_sha_256_hash'));
```

---

📋 Method Cheat Sheet
--------------------

[](#-method-cheat-sheet)

MethodDescription`TinyPeexi::upload($file)`Upload an image, returns `AssetDto``TinyPeexi::uploadMany(array $files)`Upload multiple images, returns `AssetDto[]``TinyPeexi::delete($sha)`Delete an asset`TinyPeexi::variant($sha)`Start building a variant`->resize($w, $h?)`Set target dimensions`->fit($mode)`Set fit mode`->dpr($ratio)`Set device pixel ratio`->format($fmt)`Set output format`->quality($q)`Set compression quality`->progressive()`Enable progressive JPEG`->stripMetadata()`Strip EXIF metadata`->crop($position)`Set crop anchor`->cropRect($x,$y,$w,$h)`Manual crop rectangle`->trim($threshold?)`Auto-trim whitespace`->rotate($degrees)`Rotate image`->flip($direction)`Flip image`->autoOrient()`Auto-fix EXIF orientation`->blur($sigma)`Apply Gaussian blur`->sharpen($amount)`Apply sharpening`->brightness($value)`Adjust brightness`->contrast($value)`Adjust contrast`->saturation($value)`Adjust saturation`->grayscale()`Convert to grayscale`->canvas($size)`Set square canvas size`->pad($px)`Set canvas padding`->background($color)`Set background color`->removeBg()`AI background removal`->ecommerce()`Flag as e-commerce operation`->ecommerceVariant(...)`Shorthand for e-commerce variant`->watermark(...)`Add image watermark`->preset($name)`Apply a config preset`->batch($sizes, $fmt?)`Generate multiple sizes`->generate()`Execute and return `VariantDto``->toArray()`Debug: get params as array---

📄 License
---------

[](#-license)

MIT License. See [LICENSE](LICENSE) for details.

---

🤝 Contributing
--------------

[](#-contributing)

Pull requests are welcome! Please open an issue first to discuss what you'd like to change.

---

**Built with ❤️ for Laravel developers by [tekkenking](https://github.com/tekkenking).**

###  Health Score

40

—

FairBetter than 87% of packages

Maintenance94

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

63d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6a921b3fb117a6576493236ef9dcd2754091baa974465c4e1f1e4fb3597680dd?d=identicon)[tekkenking](/maintainers/tekkenking)

---

Top Contributors

[![tekkenking](https://avatars.githubusercontent.com/u/1980114?v=4)](https://github.com/tekkenking "tekkenking (19 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/tekkenking-tinypeexi/health.svg)

```
[![Health](https://phpackages.com/badges/tekkenking-tinypeexi/health.svg)](https://phpackages.com/packages/tekkenking-tinypeexi)
```

###  Alternatives

[simplestats-io/laravel-client

Client for SimpleStats!

4515.5k](/packages/simplestats-io-laravel-client)[jasara/php-amzn-selling-partner-api

A fluent interface for Amazon's Selling Partner API in PHP

1344.8k1](/packages/jasara-php-amzn-selling-partner-api)[surface/laravel-webfinger

A Laravel package to create an ActivityPub webfinger.

113.8k](/packages/surface-laravel-webfinger)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
