Creating an image without storing it as a local file

时间:2022-02-22 16:57:47

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.

这是我的情况 - 我想从用户上传的图像创建一个调整大小的jpeg图像,然后将其发送到S3进行存储,但我希望避免将调整大小的jpeg写入磁盘,然后为S3请求重新加载它。

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

有没有办法在内存中完全执行此操作,图像数据JPEG格式化,保存在变量中?

8 个解决方案

#1


12  

Most people using PHP choose either ImageMagick or Gd2

大多数使用PHP的人选择ImageMagick或Gd2

I've never used Imagemagick; the Gd2 method:

我从未使用过Imagemagick; Gd2方法:

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

希望这可以帮助。

#2


6  

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.

一旦你在内存中使用了JPEG(使用ImageMagick,GD或你选择的图形库),你就需要将对象从内存上传到S3。

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

许多PHP S3类似乎只支持文件上传,但Undesigned的那个似乎做了我们在这里的事情 -

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

如果您正在使用GD,您可以使用imagecreatefromstring从流中读取图像,但我不确定您是否可以获得结果对象的大小,如上面的s3-> inputResource所要求的那样 - getimagesize返回高度,宽度等,但不是图像资源的大小。

#3


6  

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.

这可以使用GD库和输出缓冲来完成。我不知道这与其他方法相比有多高效,但它不需要显式创建文件。

//$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

#4


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:

这个游戏相当晚,但是如果你使用的是ConroyP和Imagick提到的S3库,你应该使用putObjectString()方法而不是putObject(),因为getImageBlob会返回一个字符串。最终为我工作的例子:

$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!

我有点挣扎这个,希望它可以帮助别人!

#5


5  

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

此方法使用AWS SDK for PHP 2和GD进行图像调整大小(Imagick也可以轻松使用)。

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

#6


4  

The Imagemagick library will let you do that. There are plenty of PHP wrappers like this one around for it (there's even example code for what you want to do on that page ;) )

Imagemagick库可以让你这样做。有很多像这样的PHP包装器(甚至还有用于在该页面上执行的操作的示例代码;))

#7


0  

I encounter the same problem, using openstack object store and php-opencloud library.

我遇到了同样的问题,使用openstack对象存储和php-opencloud库。

Here is my solution, which does not use the ob_start and ob_end_clean function, but store the image in memory and in temp file. The size of the memory and the temp file may be adapted at runtime.

这是我的解决方案,它不使用ob_start和ob_end_clean函数,而是将图像存储在内存和临时文件中。可以在运行时调整存储器和临时文件的大小。

// $image is a resource created by gd2
var_dump($image); // resource(2) of type (gd)

// we create a resource in memory + temp file 
$tmp = fopen('php://temp', '$r+');

// we write the image into our resource
\imagejpeg($image, $tmp);

// the image is now in $tmp, and you can handle it as a stream
// you can, then, upload it as a stream (not tested but mentioned in doc http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-s3.html#uploading-from-a-stream)
$s3->putObject(array(
   'Bucket' => $bucket,
   'Key'    => 'data_from_stream.txt',
   'Body'   => $tmp
));

// or, for the ones who prefers php-opencloud :
$container->createObject([
    'name'  => 'data_from_stream.txt',
    'stream' => \Guzzle\Psr7\stream_for($tmp),
    'contentType' => 'image/jpeg'
]);

About php://temp (from the official documentation of php):

关于php:// temp(来自php的官方文档):

php://memory and php://temp are read-write streams that allow temporary data to be stored in a file-like wrapper. The only difference between the two is that php://memory will always store its data in memory, whereas php://temp will use a temporary file once the amount of data stored hits a predefined limit (the default is 2 MB). The location of this temporary file is determined in the same way as the sys_get_temp_dir() function.

php:// memory和php:// temp是读写流,允许临时数据存储在类似文件的包装器中。两者之间的唯一区别是php://内存将始终将其数据存储在内存中,而一旦存储的数据量达到预定义的限制(默认值为2 MB),php:// temp将使用临时文件。此临时文件的位置以与sys_get_temp_dir()函数相同的方式确定。

The memory limit of php://temp can be controlled by appending /maxmemory:NN, where NN is the maximum amount of data to keep in memory before using a temporary file, in bytes.

可以通过附加/ maxmemory:NN来控制php:// temp的内存限制,其中NN是在使用临时文件之前要保留在内存中的最大数据量(以字节为单位)。

#8


-1  

Maye by using the GD library.

Maye使用GD库。

There is a function to copy out a part of an image and resize it. Of course the part could be the whole image, that way you would only resize it.

有一个功能可以复制图像的一部分并调整其大小。当然,部分可能是整个图像,这样你只会调整它的大小。

see imagecopyresampled

#1


12  

Most people using PHP choose either ImageMagick or Gd2

大多数使用PHP的人选择ImageMagick或Gd2

I've never used Imagemagick; the Gd2 method:

我从未使用过Imagemagick; Gd2方法:

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

希望这可以帮助。

#2


6  

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.

一旦你在内存中使用了JPEG(使用ImageMagick,GD或你选择的图形库),你就需要将对象从内存上传到S3。

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

许多PHP S3类似乎只支持文件上传,但Undesigned的那个似乎做了我们在这里的事情 -

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

如果您正在使用GD,您可以使用imagecreatefromstring从流中读取图像,但我不确定您是否可以获得结果对象的大小,如上面的s3-> inputResource所要求的那样 - getimagesize返回高度,宽度等,但不是图像资源的大小。

#3


6  

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.

这可以使用GD库和输出缓冲来完成。我不知道这与其他方法相比有多高效,但它不需要显式创建文件。

//$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

#4


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:

这个游戏相当晚,但是如果你使用的是ConroyP和Imagick提到的S3库,你应该使用putObjectString()方法而不是putObject(),因为getImageBlob会返回一个字符串。最终为我工作的例子:

$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!

我有点挣扎这个,希望它可以帮助别人!

#5


5  

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

此方法使用AWS SDK for PHP 2和GD进行图像调整大小(Imagick也可以轻松使用)。

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

#6


4  

The Imagemagick library will let you do that. There are plenty of PHP wrappers like this one around for it (there's even example code for what you want to do on that page ;) )

Imagemagick库可以让你这样做。有很多像这样的PHP包装器(甚至还有用于在该页面上执行的操作的示例代码;))

#7


0  

I encounter the same problem, using openstack object store and php-opencloud library.

我遇到了同样的问题,使用openstack对象存储和php-opencloud库。

Here is my solution, which does not use the ob_start and ob_end_clean function, but store the image in memory and in temp file. The size of the memory and the temp file may be adapted at runtime.

这是我的解决方案,它不使用ob_start和ob_end_clean函数,而是将图像存储在内存和临时文件中。可以在运行时调整存储器和临时文件的大小。

// $image is a resource created by gd2
var_dump($image); // resource(2) of type (gd)

// we create a resource in memory + temp file 
$tmp = fopen('php://temp', '$r+');

// we write the image into our resource
\imagejpeg($image, $tmp);

// the image is now in $tmp, and you can handle it as a stream
// you can, then, upload it as a stream (not tested but mentioned in doc http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-s3.html#uploading-from-a-stream)
$s3->putObject(array(
   'Bucket' => $bucket,
   'Key'    => 'data_from_stream.txt',
   'Body'   => $tmp
));

// or, for the ones who prefers php-opencloud :
$container->createObject([
    'name'  => 'data_from_stream.txt',
    'stream' => \Guzzle\Psr7\stream_for($tmp),
    'contentType' => 'image/jpeg'
]);

About php://temp (from the official documentation of php):

关于php:// temp(来自php的官方文档):

php://memory and php://temp are read-write streams that allow temporary data to be stored in a file-like wrapper. The only difference between the two is that php://memory will always store its data in memory, whereas php://temp will use a temporary file once the amount of data stored hits a predefined limit (the default is 2 MB). The location of this temporary file is determined in the same way as the sys_get_temp_dir() function.

php:// memory和php:// temp是读写流,允许临时数据存储在类似文件的包装器中。两者之间的唯一区别是php://内存将始终将其数据存储在内存中,而一旦存储的数据量达到预定义的限制(默认值为2 MB),php:// temp将使用临时文件。此临时文件的位置以与sys_get_temp_dir()函数相同的方式确定。

The memory limit of php://temp can be controlled by appending /maxmemory:NN, where NN is the maximum amount of data to keep in memory before using a temporary file, in bytes.

可以通过附加/ maxmemory:NN来控制php:// temp的内存限制,其中NN是在使用临时文件之前要保留在内存中的最大数据量(以字节为单位)。

#8


-1  

Maye by using the GD library.

Maye使用GD库。

There is a function to copy out a part of an image and resize it. Of course the part could be the whole image, that way you would only resize it.

有一个功能可以复制图像的一部分并调整其大小。当然,部分可能是整个图像,这样你只会调整它的大小。

see imagecopyresampled