Image Intervention w/ Laravel 5.4 Storage

2020-05-24 20:54发布

问题:

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).

回答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());


回答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.



回答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



回答4:

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);


回答5:

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);


回答6:

I've done it with following way, its simple and without any path confusion :

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

// Resize and encode to required type
$img = Image::make($file)->fit(300)->encode('jpg');

//Provide own name
$name = time() . '.jpg';

//Put file with own name
Storage::put($name, $img);

//Move file to your location 
Storage::move($name, 'public/image/' . $name);


回答7:

Make sure to add use Illuminate\Http\File; to top of your file for this to work, and read through the documentation section Automatic Streaming.

This assumes you want all jpegs

$path   = $request->file('createcommunityavatar');
$resize = Image::make($path)->fit(300)->encode('jpg');
$filePath = $resize->getRealPath() . '.jpg';
$resize->save($filePath);
$store  = Storage::putFile('public/image', new File($resize));
$url    = Storage::url($store);

This is how I am doing it in my application with comments to help

// Get the file from the request
$requestImage = request()->file('image');

// Get the filepath of the request file (.tmp) and append .jpg
$requestImagePath = $requestImage->getRealPath() . '.jpg';

// Modify the image using intervention
$interventionImage = Image::make($requestImage)->resize(125, 125)->encode('jpg');

// Save the intervention image over the request image
$interventionImage->save($requestImagePath);

// Send the image to file storage
$url = Storage::putFileAs('photos', new File($requestImagePath), 'thumbnail.jpg');

return response()->json(['url' => $url]);


回答8:

Try updating the GD extension for the current php version.

If that doesn't help, try saving the resized image on local disk and using Storage::putFile.

You may delete the file once it has been uploaded to your storage path.

The second parameter to your putFile method is an instance of the Image Intervention class. You need to pass this as the second parameter to the putFile method.

$resize->save($absolutePath . 'small/' . $imageName);


回答9:

You can't store an \Intervention\Image\Image object directly with the Laravel 5 filesystem. What you can do is resize the image from your request, and save it under the same tmp path. Then just store the uploaded (overwritten) file to the filesystem.

Code:

$image  = $request->file('createcommunityavatar');
//resize and save under same tmp path
$resize = Image::make($image)->fit(300)->save();
// store in the filesystem with a generated filename
$store  = $image->store('image', 'public');
// get url from storage
$url    = Storage::url($store);