0

I am working on a Laravel application and at some point, when I allow users to upload their own images for different purposes, I want to generate resized previews for these images.

I am uploading all user content to Amazon S3 and the first thing I did about resizing image is uploading the original image, then went through a foreach, resized the image and re-uploaded it to S3.

As you can image, having 4 sizes for each image dramatically increases the upload time and is a performance concern for me.

Here is a code snippet that I use in my upload function:

$storageDriver = Storage::disk('cloud-storage')->getDriver();
$parentSuccess = $storageDriver->put("/$parentId", file_get_contents($file), [
    'visibility' => 'public',
    'ACL' => 'public-read',
    'ContentType' => $contentType,
]);

$ratio = $imageSize[0] / $imageSize[1];
foreach (self::IMAGE_SIZES as $size) {
    if ($size > $imageSize[0] || ($size / $ratio) > $imageSize[1]) {
        continue;
    }

    $id = DB::table('storage')->insertGetId([
        'content_type' => $contentType,
        'parent_id' => $parentId,
        'image_width' => $size,
        'image_height' => intval($size / $ratio),
    ]);

    $image = Image::make($file)->encode('jpg');
    $image->resize($size, null, function ($constraint) {
        $constraint->aspectRatio();
        $constraint->upsize();
    });
    $image->save();

    $success = $storageDriver->put("/$id", (string)$image, [
        'visibility' => 'public',
        'ACL' => 'public-read',
        'ContentType' => 'image/jpeg',
    ]);

    if (!$success) {
        return null;
    }
}

(I know there is a lot of code not included, but it's not relevant).

What method would you choose for handling this in a more efficient way?

Victor
  • 13,914
  • 19
  • 78
  • 147
  • Hey Victor, you can generate resized images in real time using a service like [ImageKit.io](https://imagekit.io), Cloudinary, Imgix etc. I am the co-founder of ImageKit. – manu4543 Feb 09 '18 at 09:01
  • @manu4543 Hi, thank you! I am looking forward to using a homegrown solution instead of adding extra costs for the application. – Victor Feb 09 '18 at 14:34

1 Answers1

0

Had to implement something like this in my last project, I used Lazy loading. Upload the parent image to s3 and generate the thumbnails only when needed.

You can have the function getThumbnails() attached to the model that has image. The function checks if thumbnails have been generated for that model and returns it, else it generates them.

public function getThumbnails(){
    $thumbDir = "path/to/model/thumbnail/dir";

    //Check if the folder exists.
    //You can also double check if the directory actually has the thumbnails in it
    if(!file_exists($thumbDir)){
       $this->generateThumbnails($thumbDir);
    }

    //Return something
}

For more fun, you can be more specific and have a function handle each thumbnail.

public function getThumbnailX(){
    $thumb = "path/to/specific/model/thumbnail";
    if(!file_exists($thumb)){
       $this->generateThumbnailX($thumb);
    }
    return $thumb;
}

public function getThumbnailX2(){
    ...
}

Super fun, add it as an attribute of the model.

public function getThumbXAttribute(){
    return getThumbnailX();
}

so you can go ahead and call $model->thumbX whenever you need thumbX.

This reduces processing time and also the size of storage required as not all images may have their thumbnail generated.

Victor Anuebunwa
  • 2,553
  • 2
  • 24
  • 34
  • I think you missed the point however. If I do this, the `GET` requests will take long because that's when the image is generated. The huge latency comes from the fact the we do not store any user-uploaded content on our own servers but on Amazon S3. – Victor Feb 09 '18 at 14:35