Looking to hire Laravel developers? Try LaraJobs

laravel-mediaforge maintained by webcimes

Description
Laravel file & image upload service with multi-format processing (resize, convert, watermark, text overlay).
Author
Last update
2026/03/31 11:00 (dev-main)
License
Links
Downloads
27

Comments
comments powered by Disqus

webcimes/laravel-mediaforge

Store images and files directly in your existing model columns — no separate media library table required.

Powered by Intervention Image, this Laravel package lets you upload a file once and automatically generate multiple formats (thumbnail, WebP, watermark, etc.), each saved as a structured entry you can store in any JSON/text column of your choosing.

Why this package?

Most media libraries (like Spatie Media Library) introduce a dedicated media table that links files to models through a polymorphic relationship. This works great for complex scenarios, but adds overhead when you just want to attach one or a few images to a model.

With this package:

  • Image data (path, dimensions, format config) is stored directly in whichever column you choose — a JSON column, a text column, even inside a JSON API response.
  • No extra table, no polymorphic join, no extra migration.
  • The upload result is a plain PHP array — store it anywhere, serialize it however you like.
  • Regenerate derivative formats at any time from the stored original.

Features

  • Fluent ImageFormat builder — chain transforms in a readable, IDE-friendly way
  • Multi-format processing in one upload (default + thumb + WebP, all at once)
  • All formats of the same upload grouped in a single folder for easy management
  • ULID-based unique naming (collision-proof, chronologically sortable, URL-safe)
  • Plain PHP array output — no model binding required
  • Regenerate derivative formats from the stored original at any time
  • Works with any Laravel filesystem disk (local, S3, SFTP, …)

Requirements

  • PHP 8.2+
  • Laravel 11, 12, or 13
  • Intervention Image 3.x — requires either the GD or Imagick PHP extension

Installation

composer require webcimes/laravel-mediaforge

Publish the config file:

php artisan vendor:publish --tag="mediaforge-config"

Basic usage

use Webcimes\LaravelMediaforge\ImageFormat;
use Webcimes\LaravelMediaforge\Facades\MediaForge;

// Upload and generate two formats in one call:
$imageData = MediaForge::upload(
    $request->file('cover'),
    'public', // disk
    'products', // base path inside the disk
    [
        ImageFormat::make('default')->scaleDown(1920, 1080)->quality(80)->extension('webp'),
        ImageFormat::make('thumb')->cover(400, 300)->quality(65)->extension('webp'),
    ],
);

// Store $imageData directly in your model column (cast it to 'array' or 'json'):
$product->update(['cover' => $imageData]);

$imageData is a plain array — store it in any JSON column:

// $imageData:
[
    'default' => [
        'disk'     => 'public',
        'path'     => 'products/my-cover_01jq8z.../default.webp',
        'width'    => 1920,
        'height'   => 1080,
        'alt'      => 'my-cover',
        '_config'  => [...], // stored for regeneration
    ],
    'thumb' => [
        'disk'  => 'public',
        'path'  => 'products/my-cover_01jq8z.../thumb.webp',
        'width' => 400,
        'height'=> 300,
        'alt'   => 'my-cover',
        '_config' => [...],
    ],
]

ImageFormat reference

Method Description
->disk('s3') Override the storage disk for this format
->path('media/thumbs') Override the storage directory
->extension('webp') Convert to a specific format
->quality(75) Encoding quality 1–100 (JPEG, WebP, AVIF, HEIC, TIFF)
->filename('hero') Override the file name (without extension)
->suffix('_2x') Append a suffix before the extension
->resize(w, h) Exact dimensions — no ratio preservation
->resizeDown(w, h) Same — only shrinks
->scale(w, h?) Proportional fit — preserves ratio
->scaleDown(w, h?) Same — only shrinks
->cover(w, h) Center-crop to exact dimensions
->coverDown(w, h) Same — only shrinks
->text('Draft', [...]) Text overlay (requires a TTF font — see config)
->watermark('/path/logo.png', [...]) Image watermark overlay
->customAttributes([...]) Custom metadata stored alongside this format entry

Regenerate a format

Re-process derivatives from the stored original at any time — useful when you change the design:

$updated = MediaForge::regenerate($product->cover, [
    ImageFormat::make('thumb')->cover(200, 200)->extension('avif'),
]);

$product->update(['cover' => $updated]);

Delete files

// Deletes all files referenced in the stored entry:
MediaForge::delete($product->cover, 'public');

Custom base name

The upload folder name is {slug}_{ulid} by default. Override it:

// Auto (default): slug + ULID  → my-photo_01jq8z...
MediaForge::upload($file, 'public', 'uploads', $formats);

// ULID only (no slug)          → 01jq8z...
MediaForge::upload($file, 'public', 'uploads', $formats, '');

// Custom prefix + ULID         → product-hero_01jq8z...
MediaForge::upload($file, 'public', 'uploads', $formats, 'product-hero');

Configuration

After publishing (php artisan vendor:publish --tag="mediaforge-config"):

return [
    // Image processing driver:
    //   'gd'      — Built into PHP, works on every host. Default.
    //   'imagick' — Requires ext-imagick. Better quality, native AVIF/HEIC. Recommended if available.
    //   'vips'    — Requires: composer require intervention/image-driver-vips + libvips.
    //               Fastest and lowest memory, but rarely available on shared hosting.
    'driver' => 'gd', // switch to 'imagick' if available on your server

    // Text overlay defaults. Any key passed to ImageFormat::text([...]) overrides these.
    // The default font is Montserrat Regular (TTF) bundled in the package — no setup needed.
    // To use a custom font, set an absolute path to a TTF or OTF file:
    'text' => [
        'font' => null, // defaults to Montserrat TTF bundled in vendor; override: resource_path('fonts/my-font.ttf')
        'size' => 48,
        'color' => 'rgba(255, 255, 255, .75)',
        'align' => 'center',
        'valign' => 'middle',
        'angle' => 0,
        'wrap' => 0, // max line width in px before wrapping; 0 = no wrap
    ],

    // Watermark overlay defaults.
    'watermark' => [
        'position' => 'center',
        'x' => 0,
        'y' => 0,
        'opacity' => 75,
    ],
];

License

MIT