Creating an image without storing it as a local file

17,392

Solution 1

Most people using PHP choose either ImageMagick or Gd2

I've never used Imagemagick; the Gd2 method:

<?php

// assuming your uploaded file was 'userFileName'

if ( ! is_uploaded_file(validateFilePath($_FILES[$userFileName]['tmp_name'])) ) {
    trigger_error('not an uploaded file', E_USER_ERROR);
}
$srcImage = imagecreatefromjpeg( $_FILES[$userFileName]['tmp_name'] );

// Resize your image (copy from srcImage to dstImage)
imagecopyresampled($dstImage, $srcImage, 0, 0, 0, 0, RESIZED_IMAGE_WIDTH, RESIZED_IMAGE_HEIGHT, imagesx($srcImage), imagesy($srcImage));

// Storing your resized image in a variable
ob_start(); // start a new output buffer
  imagejpeg( $dstImage, NULL, JPEG_QUALITY);
  $resizedJpegData = ob_get_contents();
ob_end_clean(); // stop this output buffer

// free up unused memmory (if images are expected to be large)
unset($srcImage);
unset($dstImage);

// your resized jpeg data is now in $resizedJpegData
// Use your Undesigned method calls to store the data.

// (Many people want to send it as a Hex stream to the DB:)
$dbHandle->storeResizedImage( $resizedJpegData );
?>

Hope this helps.

Solution 2

This can be done using the GD library and output buffering. I don't know how efficient this is compared with other methods, but it doesn't require explicit creation of files.

//$image contains the GD image resource you want to store

ob_start();
imagejpeg($image);
$jpeg_file_contents = ob_get_contents();
ob_end_clean();

//now send $jpeg_file_contents to S3

Solution 3

Once you've got the JPEG in memory (using ImageMagick, GD, or your graphic library of choice), you'll need to upload the object from memory to S3.

Many PHP S3 classes seem to only support file uploads, but the one at Undesigned seems to do what we're after here -

// Manipulate image - assume ImageMagick, so $im is image object
$im = new Imagick();
// Get image source data
$im->readimageblob($image_source);

// Upload an object from a resource (requires size):
$s3->putObject($s3->inputResource($im->getimageblob(), $im->getSize()), 
                  $bucketName, $uploadName, S3::ACL_PUBLIC_READ);

If you're using GD instead, you can use imagecreatefromstring to read an image in from a stream, but I'm not sure whether you can get the size of the resulting object, as required by s3->inputResource above - getimagesize returns the height, width, etc, but not the size of the image resource.

Solution 4

Realize this is an old thread, but I spent some time banging my head against the wall on this today, and thought I would capture my solution here for the next guy.

This method uses AWS SDK for PHP 2 and GD for the image resize (Imagick could also be easily used).

require_once('vendor/aws/aws-autoloader.php');

use Aws\Common\Aws;

define('AWS_BUCKET', 'your-bucket-name-here');

// Configure AWS factory 
$aws = Aws::factory(array(
    'key' => 'your-key-here',
    'secret' => 'your-secret-here',
    'region' => 'your-region-here'
));

// Create reference to S3
$s3 = $aws->get('S3');
$s3->createBucket(array('Bucket' => AWS_BUCKET));
$s3->waitUntilBucketExists(array('Bucket' => AWS_BUCKET));
$s3->registerStreamWrapper();

// Do your GD resizing here (omitted for brevity)

// Capture image stream in output buffer
ob_start();
imagejpeg($imageRes);
$imageFileContents = ob_get_contents();
ob_end_clean();

// Send stream to S3
$context = stream_context_create(
  array(
    's3' => array(
      'ContentType'=> 'image/jpeg'
    )
  )
);
$s3Stream = fopen('s3://'.AWS_BUCKET.'/'.$filename, 'w', false, $context);
fwrite($s3Stream, $imageFileContents);
fclose($s3Stream);

unset($context, $imageFileContents, $s3Stream);

Solution 5

Pretty late to the game on this one, but if you are using the the S3 library mentioned by ConroyP and Imagick you should use the putObjectString() method instead of putObject() due the fact getImageBlob returns a string. Example that finally worked for me:

$headers = array(
    'Content-Type' => 'image/jpeg'
);
$s3->putObjectString($im->getImageBlob(), $bucket, $file_name, S3::ACL_PUBLIC_READ, array(), $headers);

I struggled with this one a bit, hopefully it helps someone else!

Share:
17,392
MPX
Author by

MPX

Updated on June 05, 2022

Comments

  • MPX
    MPX almost 2 years

    Here's my situation - I want to create a resized jpeg image from a user uploaded image, and then send it to S3 for storage, but am looking to avoid writing the resized jpeg to the disk and then reloading it for the S3 request.

    Is there a way to do this completely in memory, with the image data JPEG formatted, saved in a variable?

  • MPX
    MPX over 15 years
    I should have clarified - I am using Undesigned's S3 class. Do you know a GD way of doing what you posted above? Before I jump to installing imagemagick, would be nice to know if I absolutely need to.
  • ConroyP
    ConroyP over 15 years
    My GD is a bit sketchy - I know you can read the image in similarly to ImageMagick, not sure about getting the object size though - been a while since I went through the docs and couldn't see anything there. ImageMagick is well worth the install though IMO!
  • Joe Scylla
    Joe Scylla over 15 years
    imagesx and imagesy returns the width/height of an image ressource.
  • John
    John over 11 years
    I have been struggling with this for over 3 months and saw some light when I read this. However, this does not work for me. getImageBlob appears to return an empty string whereas writeImage to disk works. Any idea?
  • Matt
    Matt over 10 years
    This works perfectly, thanks Bart. Is there some response object that I can use to find out if the transaction failed?
  • Matt
    Matt over 10 years
    I like this s3 library, it's small and simple. However it didn't support s3 folders as far as I could see.
  • shrooma
    shrooma over 10 years
    Per the PHP Docs (us2.php.net/manual/en/function.fwrite.php), fwrite will return false on error.