mainul12501/drag-drop-crop-image-upload

Laravel drag, drop, and crop image upload widget.

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

Language:JavaScript

pkg:composer/mainul12501/drag-drop-crop-image-upload

v1.0.3 2026-01-04 12:29 UTC

This package is auto-updated.

Last update: 2026-01-04 12:30:37 UTC


README

A Laravel package that provides an elegant drag-and-drop image upload widget with built-in cropping functionality. Perfect for profile pictures, avatars, and any image upload that requires user-controlled cropping.

Latest Version on Packagist License

Features

  • Drag & drop image upload
  • Interactive image cropping with Cropper.js
  • Image rotation (90° left/right)
  • Configurable aspect ratio, dimensions, and quality
  • Base64 to file conversion with automatic format detection
  • Bootstrap modal integration support
  • Customizable labels and UI text
  • Auto-cleanup of old images on re-upload

Requirements

Requirement Version
PHP 8.1 - 8.5
Laravel 11.x, 12.x

Installation

Via Composer (Packagist)

composer require mainul12501/drag-drop-crop-image-upload

Publish the assets and configuration:

php artisan vendor:publish --tag=drag-drop-crop-assets
php artisan vendor:publish --tag=drag-drop-crop-config

Local Development

Add to your main app's composer.json:

{
    "repositories": [
        {
            "type": "path",
            "url": "packages/drag-drop-crop-image-upload"
        }
    ],
    "require": {
        "mainul/drag-drop-crop-image-upload": "*"
    }
}

Then run:

composer update
php artisan vendor:publish --tag=drag-drop-crop-assets
php artisan vendor:publish --tag=drag-drop-crop-config

Quick Start

1. Render the Widget in Your Blade View

{!! DragDropCrop::generateUpload('profile_image') !!}

2. Handle the Upload in Your Controller

use DragDropCropImageUpload\Facades\DragDropCrop;

public function store(Request $request)
{
    $imagePath = DragDropCrop::uploadFromBase64(
        $request->input('profile_image'),
        'uploads/avatars'
    );

    // Save $imagePath to your database
    User::create([
        'avatar' => $imagePath,
        // ... other fields
    ]);
}

Usage

Basic Usage

{!! DragDropCrop::generateUpload('field_name') !!}

With Custom Options

{!! DragDropCrop::generateUpload('profile_image', [
    'aspect_ratio' => 1,          // 1:1 square (use 16/9 for widescreen)
    'crop_width' => 300,          // Output width in pixels
    'crop_height' => 300,         // Output height in pixels
    'max_size_mb' => 5,           // Maximum file size in MB
    'quality' => 0.8,             // JPEG quality (0.1 to 1.0)
]) !!}

Inside Bootstrap Modal

{!! DragDropCrop::generateUpload('avatar', [
    'modal_id' => 'profileModal',  // Resets widget when modal closes
]) !!}

Custom Labels

{!! DragDropCrop::generateUpload('photo', [
    'labels' => [
        'title' => 'Upload Your Photo',
        'browse' => 'Click to select',
        'supports' => 'JPG, PNG (Max 10MB)',
        'cropped_title' => 'Preview:',
        'change' => 'Choose Different',
        'reset' => 'Start Over',
        'rotate_left' => 'Rotate Left',
        'rotate_right' => 'Rotate Right',
        'crop' => 'Crop & Save',
    ],
]) !!}

API Reference

DragDropCrop::generateUpload(string $inputName, array $options = [])

Renders the drag-drop-crop widget.

Parameters:

Parameter Type Description
$inputName string Name attribute for the hidden input containing cropped base64 data
$options array Configuration options (see below)

Options:

Option Type Default Description
id string auto-generated Unique widget identifier
file_input_name string {inputName}_file Name for the file input element
aspect_ratio float 1 Width/height ratio (1 = square, 16/9 = widescreen)
crop_width int 300 Output image width in pixels
crop_height int 300 Output image height in pixels
max_size_mb int 5 Maximum allowed file size in MB
quality float 0.8 JPEG compression quality (0.1 - 1.0)
modal_id string null Bootstrap modal ID for auto-reset on close
labels array [] Custom UI text labels

Returns: Illuminate\Support\HtmlString

DragDropCrop::uploadFromBase64(?string $base64String, ?string $directory, ?string $namePrefix, ?string $existingPath)

Converts base64 image data to a file and saves it.

Parameters:

Parameter Type Default Description
$base64String string|null - Base64-encoded image data from the widget
$directory string|null config value Upload directory relative to public/
$namePrefix string|null null Prefix for the generated filename
$existingPath string|null null Path to existing image (will be deleted)

Returns: string|null - Relative path to the uploaded file, or $existingPath if no new upload

Example with all parameters:

$path = DragDropCrop::uploadFromBase64(
    $request->input('profile_image'),  // Base64 from form
    'uploads/users',                    // Save to public/uploads/users/
    'user_' . $user->id,               // Prefix: user_123_...
    $user->current_avatar              // Delete old avatar
);

Generated filename format: {prefix}_{timestamp}_{random}.{ext}

Example: user_123_1704067200_a1b2c3d4e5.jpg

Configuration

After publishing, edit config/drag-drop-crop.php:

return [
    // Default upload directory (relative to public/)
    'upload_directory' => 'frontend/auth',

    // Default aspect ratio (1 = square)
    'aspect_ratio' => 1,

    // Default crop dimensions
    'crop_width' => 300,
    'crop_height' => 300,

    // Maximum file size in MB
    'max_size_mb' => 5,

    // JPEG compression quality (0.1 - 1.0)
    'quality' => 0.8,

    // Published assets path
    'asset_path' => 'vendor/drag-drop-crop',
];

Complete Example

Blade View (create-profile.blade.php)

<form action="{{ route('profile.store') }}" method="POST">
    @csrf

    <div class="mb-3">
        <label class="form-label">Profile Picture</label>
        {!! DragDropCrop::generateUpload('avatar', [
            'aspect_ratio' => 1,
            'crop_width' => 400,
            'crop_height' => 400,
            'max_size_mb' => 10,
            'quality' => 0.9,
            'labels' => [
                'title' => 'Drop your photo here',
                'supports' => 'JPG, PNG, GIF (Max 10MB)',
            ],
        ]) !!}
    </div>

    <div class="mb-3">
        <label class="form-label">Name</label>
        <input type="text" name="name" class="form-control">
    </div>

    <button type="submit" class="btn btn-primary">Save Profile</button>
</form>

Controller (ProfileController.php)

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use DragDropCropImageUpload\Facades\DragDropCrop;

class ProfileController extends Controller
{
    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'avatar' => 'nullable|string', // Base64 string
        ]);

        $avatarPath = null;

        if ($request->filled('avatar')) {
            $avatarPath = DragDropCrop::uploadFromBase64(
                $request->input('avatar'),
                'uploads/avatars',
                'avatar'
            );
        }

        $user = User::create([
            'name' => $request->input('name'),
            'avatar' => $avatarPath,
        ]);

        return redirect()->route('profile.show', $user)
            ->with('success', 'Profile created!');
    }

    public function update(Request $request, User $user)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'avatar' => 'nullable|string',
        ]);

        // This will delete the old avatar and upload the new one
        $avatarPath = DragDropCrop::uploadFromBase64(
            $request->input('avatar'),
            'uploads/avatars',
            'avatar_' . $user->id,
            $user->avatar  // Existing path to delete
        );

        $user->update([
            'name' => $request->input('name'),
            'avatar' => $avatarPath,
        ]);

        return redirect()->route('profile.show', $user)
            ->with('success', 'Profile updated!');
    }
}

Display the Image

@if($user->avatar)
    <img src="{{ asset($user->avatar) }}" alt="Avatar" class="rounded-circle">
@endif

Supported Image Formats

Format Extension MIME Type
JPEG .jpg image/jpeg
PNG .png image/png
GIF .gif image/gif
WebP .webp image/webp

User Interaction Flow

  1. User drags an image onto the widget (or clicks to browse)
  2. Selected image appears in the cropping interface
  3. User adjusts the crop area (drag, resize, rotate)
  4. User clicks "Crop Image" to confirm
  5. Cropped preview is shown with option to change
  6. On form submit, base64 data is sent to the server
  7. Server converts base64 to file and returns the path

License

MIT License. See LICENSE for details.

Credits

  • Cropper.js - Image cropping library
  • Built for Laravel 11 & 12

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Links