Image Intervention w/ Laravel 5.4 Storage

48,111

Solution 1

You're trying to pass into putFile wrong object. That method expects File object (not Image).

$path   = $request->file('createcommunityavatar');

// returns \Intervention\Image\Image - OK
$resize = Image::make($path)->fit(300);

// expects 2nd arg - \Illuminate\Http\UploadedFile - ERROR, because Image does not have hashName method
$store  = Storage::putFile('public/image', $resize);

$url    = Storage::url($store);

Ok, now when we understand the main reason, let's fix the code

// returns Intervention\Image\Image
$resize = Image::make($path)->fit(300)->encode('jpg');

// calculate md5 hash of encoded image
$hash = md5($resize->__toString());

// use hash as a name
$path = "images/{$hash}.jpg";

// save it locally to ~/public/images/{$hash}.jpg
$resize->save(public_path($path));

// $url = "/images/{$hash}.jpg"
$url = "/" . $path;

Let's imagine that you want to use Storage facade:

// does not work - Storage::putFile('public/image', $resize);

// Storage::put($path, $contents, $visibility = null)
Storage::put('public/image/myUniqueFileNameHere.jpg', $resize->__toString());

Solution 2

The put method works with the Image intervention output. The putFile method accepts either an Illuminate\Http\File or Illuminate\Http\UploadedFile instance.

$photo = Image::make($request->file('photo'))
  ->resize(400, null, function ($constraint) { $constraint->aspectRatio(); } )
  ->encode('jpg',80);

Storage::disk('public')->put( 'photo.jpg', $photo);

The above code resizes the uploaded file to 400px width while holding the aspect ratio. Then encodes to jpg at 80% quality. The file is then stored to the public disc. Note you must provide a filename, not just the directory.

Solution 3

Using Laravel 5.8

I had a similar issue when trying to read an image file with Image when this one was saved and loaded with Storage.
Beside all the answers I wasn't sure why it wasn't working.


Exception when Image was trying to read the file

Intervention\Image\Exception\NotReadableException : Unable to init from given binary data.

Short answer

Adding ->encode()solved the issue

http://image.intervention.io/api/encode

Scenario

Basically I had a test like this

Storage::fake();

$photo = factory(Photo::class)->create();    
$file = \Image::make(
    UploadedFile::fake()->image($photo->file_name, 300, 300)
);

Storage::disk($photo->disk)
    ->put(
        $photo->fullPath(),
        $file
    );

And in the controller I had something like this

return \Image::make(
    Storage::disk($photo->disk)
        ->get(
            $photo->fullPath()
        )
)->response();

Solution

After investigation I realized that any file created by Image and saved by the Storage had a size of 0 octets. After looking at all the solutions from this post and few hours after, I noticed everyone was using encode() but no one did mention it was that. So I tried and it worked.

Investigating a bit more, Image does, in fact, encode under the hood before saving. https://github.com/Intervention/image/blob/master/src/Intervention/Image/Image.php#L146

So, my solution was to simple doing this

$file = \Image::make(
    \Illuminate\Http\UploadedFile::fake()->image('filename.jpg', 300, 300)
)->encode();

\Storage::put('photos/test.jpg', $file);

testable in Tinker, It will create a black image

Solution 4

The cleanest solution I could find—using the native Storage facade—is the following. I can confirm that this works in Laravel 5.7, using intervention/image version 2.4.2.

$file = $request->file('avatar');
$path = $file->hashName('public/avatars');
$image = Image::make($file)->fit(300);
Storage::put($path, (string) $image->encode());

$url = Storage::url($path);

Solution 5

I do it this way:

  1. Resize and save image somewhere (such as in the public folder).
  2. Create a new File and pass it to Laravel filesystem functions (such as putFileAs).
  3. Delete temporary intervention file

Note: Of course you can modify it according to your needs.

$file = $request->file('portfolio_thumb_image');

$image = Image::make($file);

$image->resize(570, 326, function ($constraint) {
    $constraint->aspectRatio();
});

$thumbnail_image_name = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME).'.'.$file->getClientOriginalExtension();

$image->save(public_path('images/'.$thumbnail_image_name));

$saved_image_uri = $image->dirname.'/'.$image->basename;

//Now use laravel filesystem.
$uploaded_thumbnail_image = Storage::putFileAs('public/thumbnails/'.$portfolio_returned->id, new File($saved_image_uri), $thumbnail_image_name);

//Now delete temporary intervention image as we have moved it to Storage folder with Laravel filesystem.
$image->destroy();
unlink($saved_image_uri);
Share:
48,111
wizardzeb
Author by

wizardzeb

I love web development and I try to push browsers to their limits. When I'm not on the web, I like to build command-line tools using various technologies. Currently, I have a Laravel project that has been in production for a few years.

Updated on October 27, 2020

Comments

  • wizardzeb
    wizardzeb over 3 years

    I'm using the storage facade to store a avatar which works fine, but I want to resize my image like I did in previous versions of laravel. How can I go about doing this? Here is what I have so far (doesn't work)

      $path   = $request->file('createcommunityavatar');
      $resize = Image::make($path)->fit(300);
      $store  = Storage::putFile('public/image', $resize);
      $url    = Storage::url($store);
    

    Error Message:

      Command (hashName) is not available for driver (Gd).