Save image on RAM and work on it using ImageMagick - php

I am working on a project where the client can create dynamic image by merging different layers (images) into single image and then show that generated image to client. Currently my code is something like this
$output = uniqid().'.jpg';
exec('convert -size 600x800 xc:white '.$output);
$layers = array(//array of about hundreds of PNG images);
foreach($layers as $key => $singleLayer)
{
$layerIs = $singleLayer['image'];
$positionsXY = explode(',', $singleLayer['xy']);
exec('composite -geometry +'.$positionsXY[0].'+'.$positionsXY[1].' '.$layerIs.' '.$output.' '.$output);
}
$base64 = base64_encode(file_get_contents($output));
unlink($output);
return 'data:image/jpeg;base64,'.$base64;
In my above code, I am generating a white background image and then merging multiple PNG images on it these images are more than 100. While also saving this image every time a single layer is merged and then output the final image to client after deleting the generated image. This all takes about 15 seconds to do.
So, My Question is if ImageMagick has an option which can allow me to save image on ram instead of saving image on harddisk which in turn can speed up my processing?
Although I found this http://www.imagemagick.org/discourse-server/viewtopic.php?t=20295 but could not understand much of it that how can I implement it.

The easiest way to use ImageMagick in php is to use the ImageMagick extension & class. I would not recommend using the exec function for it.
So first off, converting the image and store it in a variable.
You say you are not used to variabled, but by your code it seems like you are, you might just not know it.
For example, your $output is a variabe. The variable contains the image after the output is made (if it succeeds).
Now, I'm not 100% sure what your layers array contains, if its images or paths to images, but I expect that its paths, so I'll go with that assumption.
Your first exec call does a convert, I don't think that is nessesery, cause you have no input, all you need is a "white image" from what I can see.
To do that, create a new image object with and create a new image which is the correct size and bg color:
$image = new Imagick();
$image->newImage(600, 800, "white");
You then loop through the layers as you do, but instead of exec you use the imagemagick image you created above:
foreach($layers as $key => $singleLayer) {
$layerIs = $singleLayer['image'];
$positionsXY = explode(',', $singleLayer['xy']);
// Each loop should load the image into a new imagemagick object, but we release it when the scope is exited.
$layer = new IMagick($layerIs);
$image->compositeImage($layer, Imagick::COMPOSITE_DEFAULT, $positionsXY[0], $positionsXY[1]);
}
When the loop is complete, the $image variable will contain the composited image, which you can return as you wish.
$image->setImageFormat('jpg');
return "data:image/jpeg;base64,{base64_encode($image)}";
Note: Code is not tested and written directly in browser. So it might need to be rewritten!

Related

How To Add An Image Above Another using PHP

I Have A Background Image Now I want PHP to Put Another Image On Top Of It (The Other Image Is Stored in A Variable)
Example variable $x
& My Background Image Is Also A Variable $back
Example ../img/back.jpg
Now i wish to Add The $x On The Left side of The Background
How May I Achieve this?
Like In This Pic There is The Green Part with a Shadow Image
How Can I replace that PART with another Picture using PHP?
(https://i.stack.imgur.com/IjK0o.jpg)
What i Have so Far
<?php
copy("https://graph.facebook.com/FACEBOOKID/picture?width=99&height=99", "picture.jpg");
$x = "picture.jpg";
copy("https://i.stack.imgur.com/IjK0o.jpg","bg.jpg");
$back = "bg.jpg";
?>
Combining images is part of image processing. You can use the gd library directly. However I recommend using an OO image processing library like intervention image, which is easier to write and understand.
// open the background image file
$img = Image::make('bg.jpg');
// Add the facebook image
$img->insert('picture.jpg');
// Save the image as a new file
$img->save('newpicture.jpg');
Read the documentation about the insert method to understand how to position the facebook image.

PHP Imagick PSD thumbs getting strange artifacts

We have a server that accepts PSD files. It will load it into a new Imagick object and create 4 jpg thumbs for it.
Oddly the first thumb, the largest one looks great. Each thumb after that experiences some image distortion where a layer was using a stroke effect.
Code:
$image = new Imagick($fileName);
$image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
foreach ($thumbSizes as $key => $size) { //largest to smallest
if($size>$longestSide){
$size = $longestSide;
}
$this->image->thumbnailImage($size,$size,true);
$this->image->writeImage($nameBase . '-' . $key . ".$extension");
}
$image->destroy();
I'm not sure how Imagick works internally, but my intuition tells me that if the largest thumb is accurate then each one after that should be.
NOTE: I expect some image distortion when resizing an image. But if you look at the example I posted it's different than your normal resizing artifacts. It's changing the color of some text. I assume it's a problem with it resizing the stroke effect. But I would have thought since I flattened the image first, the stroke effect wouldn't exist anymore. I can pass in a jpeg representation of the same file and it resizes them all perfectly.
I think the PSD conversion is just borked by the library/special FX on the PSD. This is the first image output by similar code to yours:
The color of the number is transparent rather than black - but similarly, not correct. If the issue is being caused by the FX on that layer and you can't find a version of the library that processes the PSD that works correctly, I would suggest not using Imagick/ImageMagick to do the processing, but instead install a copy of Photoshop on the server and use the CLI processing capabilities of Photoshop itself to do the processing: https://helpx.adobe.com/photoshop/using/processing-batch-files.html .
btw an observation - you are resizing the same image repeatedly, this is less than optimal. You can avoid this by resizing a clone of the original image:
foreach ($thumbSizes as $key => $size) { //largest to smallest
$temp = clone $image;
if($size>$longestSide){
$size = $longestSide;
}
$temp->thumbnailImage($size,$size,true);
$temp->writeImage($nameBase . '-' . $key . ".$extension");
}
This should give a slightly higher output image quality.

Resize a PHP GD-generated image in PHP and display it

I am making an avatar script from scratch and am having some problems. I got transparency working, and multi-image support for heads, bodies, shirts, etc.
Anyhow, I want to be able to generate specific sizes of the avatar within the PHP script. At this time, I have the variable $baseImage, which is an image generated using the GD script below:
$baseImage = imagecreatefrompng($startAsset);
imagealphablending($baseImage, true);
imagesavealpha($baseImage, true);
... combine all images into $base here
header("Content-type: image/png");
imagepng($baseImage);
The size of the image this generates is 350x550 (pixels) and I want to be able to get a smaller size.
I've done research but cannot find a working solution. What built-in PHP GD functions can resize this, retain transparency, and keep the great quality/colors?
There is no way to change the size of an image resource directly. Instead, you need to create a new image of the desired size and use imagecopyresampled to copy from the fullsize image to the resized one.

imagemagick - downsize/crop/save to jpeg in one go?

I have a php script that will receive a bunch of images uploaded.
What I need to do is create a small thumbnail of each, on the fly using imagemagick.
I can do that easy enough but I also need to crop it so that the thumbnail is always 100x100.
the images supplied won't be the same proportions so simply downsizing won't work.
Can I downsize, crop to 100x100 and save to jpeg all in one step?
I believe this should do what you want:
convert 'just_uploaded/*' -resize 100x100^ -gravity center -extent 100x100 -set filename:f '%t' +adjoin 'just_uploaded_thumbs/%[filename:f].jpg'
resize will downsize, extent (in combination with gravity) will crop, and the rest takes care of saving with a modified name, in JPEG format, in a different directory.
Short answer: no. That'll be 3 steps, no less.
Longer answer: you can do it using the command line interface. In PHP, the only way is to write a function that will do what you ask. Then, for each image, you can just call your function. I'm not sure how this is more beneficial than just using the 3 Imagick functions separately...
I like the sfThumbnailPlugin. It wraps around both ImageMagick or GD
http://www.symfony-project.org/plugins/sfThumbnailPlugin
Example:
public function executeUpload()
{
// Retrieve the name of the uploaded file
$fileName = $this->getRequest()->getFileName('file');
// Create the thumbnail
$thumbnail = new sfThumbnail(150, 150);
$thumbnail->loadFile($this->getRequest()->getFilePath('file'));
$thumbnail->save(sfConfig::get('sf_upload_dir').'/thumbnail/'.$fileName, 'image/png');
// Move the uploaded file to the 'uploads' directory
$this->getRequest()->moveFile('file', sfConfig::get('sf_upload_dir').'/'.$fileName);
// Do whatever is next
$this->redirect('media/show?filename='.$fileName);
}

How to compress images in CodeIgniter, yet do not change their dimensions?

I have a site where users can upload images. I process these images directly and resize them into 5 additional formats using the CodeIgniter Image Manipulation class. I do this quite efficiently as follow:
I always resize from the previous format, instead of from the original
I resize using an image quality of 90% which about halves the file size of jpegs
The above way of doing things I implemented after advise I got from another question I asked. My test case is a 1.6MB JPEG in RGB mode with a high resolution of 3872 x 2592. For that image, which is kind of borderline case, the resize process in total takes about 2 secs, which is acceptable to me.
Now, only one challenge remains. I want the original file to be compressed using that 90% quality but without resizing it. The idea being that that file too will take half the file size. I figured I could simply resize it to its' current dimensions, but that doesn't seem to do anything to the file or its size. Here's my code, somewhat simplified:
$sourceimage = "test.jpg";
$resize_settings['image_library'] = 'gd2';
$resize_settings['source_image'] = $sourceimage;
$resize_settings['maintain_ratio'] = false;
$resize_settings['quality'] = '90%';
$this->load->library('image_lib', $resize_settings);
$resize_settings['width'] = $imagefile['width'];
$resize_settings['height'] = $imagefile['height'];
$resize_settings['new_image'] = $filename;
$this->image_lib->initialize($resize_settings);
$this->image_lib->resize();
The above code works fine for all formats except the original. I tried debugging into the CI class to see why nothing happens and I noticed that the script detects that the dimensions did not change. Next, it simply makes a copy of that file without processing it at all. I commented that piece of code to force it to resize but now still nothing happens.
Does anybody know how to compress an image (any image, not just jpegs) to 90% using the CI class without changing the dimensions?
I guess you could do something like this:
$original_size = getimagesize('/path/to/original.jpg');
And then set the following options like this:
$resize_settings['width'] = $original_size[0];
$resize_settings['height'] = $original_size[1];
Ok, so that doesn't work due to CI trying to be smart, the way I see it you've three possible options:
Rotate the Image by 360ยบ
Watermark the Image (with a 1x1 Transparent Image)
Do It Yourself
The DIY approach is really simple, I know you don't want to use "custom" functions but take a look:
ImageJPEG(ImageCreateFromString(file_get_contents('/path/to/original.jpg')), '/where/to/save/optimized.jpg', 90);
As you can see, it's even more simpler than using CI.
PS: The snippet above can open any type of image (GIF, PNG and JPEG) and it always saves the image as JPEG with 90% of quality, I believe this is what you're trying to archive.

Categories