I am trying to use ImageMagick for some photo manipulation (crop for the moment). I succeed previously the desired outcome by using GD library for PHP (on my localhost) but now the hosting doesn't support it and they suggest me to use ImageMagick instead. The issue is that I can crop an image that it is stored locally :
<?php
$four = '4fingers1.jpg';
exec("convert $four -crop 100x100+100+100 test.jpg");
?>
<img src="test.jpg">
with no problem but when it comes from http sources (the actual purpose of my script) I receive no image. The code is the following (I post with a form the actual src of the image):
$src = $_POST['src'];
exec("convert $src -resize 720x720 resized.jpg"); // this is specified in the documentation
exec("convert resized.jpg -crop 100x100+100+100 final.jpg");
?>
<img src="final.jpg"> <!-- no image -->
<img src="resized.jpg"> <!-- no image -->
<img src="<?php echo $src; ?>"> <!-- alright -->
The documentation specify the following:
IM can also download an image that is published on the 'world wide
web' by specifying that images URL. This basically provides a 'http:'
image coder, which is why it works.
Link: http://www.imagemagick.org/Usage/files/#read
I've tried a lots of code snippets founded online and can't figure it out why is not working? I can use maybe something else to reach my purpose?
First of all, as Prisoner comments this code is vulnerable to shell argument injection. Basically anyone can manipulate the post parameters and cause you to execute any command line they want; this is potentially disastrous and should be addressed immediately!
One way to fix the security issue is use escapeshellarg; this should also fix your "original" problem since there is no apparent reason for the command to fail. If the URL is valid and the argument is properly escaped it should just work.
Alternatively, you can solve both the security headache and your original problem by downloading the image yourself and saving it to a temporary file before calling IM:
$temp = tempnam(sys_get_temp_dir());
file_put_contents($temp, file_get_contents($url));
exec("convert ".escapeshellarg($temp)." -crop 100x100+100+100 test.jpg");
First I'm with the answer of Jon and the comment of Prisoner. You'll have to escape the $src POST var to prevent from shell command injection using escapeshellarg():
$src = escapeshellarg($_POST);
Further you should use the second param (output of command) and the third param (return value of command) and respect it.
Call exec() like this:
exec("convert $src -resize 720x720 resized.jpg 2>&1", $output, $returnval);
if($returnval !== 0) {
die('imagemagick error: ' . join("<br/>", $output));
}
Now you are able to react on errors and you can see what's going wrong. Note that I've redirected stderr of imagemagick to stdout using shell redirection ( 2>&1 )
The problem was that IM have a problem with the https protocol in my case. I've tested with a http image and everything was working fine so I made the following:
<?php
$src = $_POST['src'];
$src = preg_replace('/^https\:\/\//', 'http://', $src);
$src = escapeshellarg($src);
exec('convert ' . $src . ' resized.jpg 2>&1', $output, $returnval);
if($returnval !== 0) {
die('imagemagick error: ' . join("<br/>", $output));
}
?>
<img src="resized.jpg">
I have the image now displayed and I can start crop it and so on.
Related
Suppose a user uploads a .txt or .php file, and I want to generate a .png thumbnail for it. Is there a simple way of doing it, that doesn't require me to open the file and write its contents into a new .png? I have ImageMagick and FFmpeg available, there must be a way to take advantage of that, but I've been looking a lot and no luck yet.
Thanks in advance.
You can use ffmpeg:
ffmpeg -video_size 640x480 -chars_per_frame 60000 -i in.txt -frames:v 1 out.png
However, it has some caveats:
By default it renders 6000 characters per frame, so it may not draw all of your text. You can change this with the -chars_per_frame and/or -framerate input options. Default frame rate is 25.
The text will not be automatically word wrapped so you will have to add line breaks for the text to fit your output video size.
You could always use php's imagettftext function.
It would give you a representation of what is in the text file.
http://php.net/manual/en/function.imagettftext.php
You can use PHP's class imagick to convert the file to image.
It will work for a txt file nicely.
try
{
$im = new imagick("inputfile.txt[0]");
if ($im)
{
$im->setImageAlphaChannel(imagick::ALPHACHANNEL_DEACTIVATE);
$im->setImageFormat('jpg');
$im->setImageCompressionQuality(85);
file_put_contents("outfile.jpg",$im->getImageBlob());
}
} catch(Exception $e)
{
echo "cannot process";
}
// When imagick is unable to read the file, it may wrongly
// set internal server error 500 status code.
// I do not understand why that happens, because the script
// continues normally. Anyway, lets overwrite it here for all cases.
header("HTTP/1.1 200 OK");
$image = new Imagick();
$image->readImage("text:" . $filename . "[0]");
$image->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
$image->setImageFormat('png');
$image->writeImage($linkImage);
I want to be able to generate image thumbnails without saving them to the server. So far, I've come up with this code, but I'm not sure what to do with $code.
$code = system("convert galleries/13_0.jpg -resize 400x270 /dev/stdout");
How would I go about plugging $code into the PHP/HTML to get the raw image code to display as a jpg?
I would advise you not to do this from the system as you have described.
PHP has libraries for doing this sort of thing.
http://www.php.net/manual/en/ref.image.php.
http://php.net/manual/en/book.imagick.php.
And there are libraries the wrap these native functions for manipulating images. https://imagine.readthedocs.org/en/latest/
That way all your code is in PHP and you are not relying on the system to do anything (providing PHP has been compiled with the libraries as described. They are standard libraries available in most PHP builds and you can enable them if they are not included).
Edit: I'm advocating that you.
Open the source image.
Convert the source image
Return the source image
with imagine you would do it thus:
$imagine = new Imagine\Gd\Imagine();
$size = new Imagine\Image\Box(400, 270);
$imagine->open('/path/to/large_image.jpg')
->resize($size)
->show('jpg');
If the $code is the raw data, could you have another file getimage.php which would write the data out but set the header content type to image/JPEG? So your img src would be getimage.php?image=13_0.jpg for example?
I would save it to memory, then read it, then delete it. /dev/shm is a ramdrive on most Linux systems.
$tmp = '/dev/shm/'.uniqid('',true).'.jpg';
system("convert galleries/13_0.jpg -resize 400x270 $tmp");
header("Content-Type: image/jpeg");
header('Content-Length: '.filesize($tmp));
readfile($tmp);
unlink($tmp);
This question has already been asked (see link below) but none of the answers work. So I have this ImageMagick script that I am using to tint PNGs and it works great but the problem is that it actually generates files on the server. What I want instead is exactly what GD does where it does the image manipulation and then displays it without actually saving an image.
Here is my ImageMagick code that I use to tint the image. This code does the converting and generates an extra file on the server which is the final image.
<?php
$source = "src.png";
$final = "FINAL.png";
$color = "#00FF00";
exec("convert $source -threshold 100% +level-colors '$color', $final");
?>
Here is a GD example code which does an image manipulation and displays the final image directly without saving extra images to the server:
<?php
header('Content-Type: image/png');
$source = "src.png";
$im = imagecreatefrompng($source);
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagepng($im);
imagedestroy($im);
?>
So essentially I want the image manipulation that is done in the first example, but without saving extra images and displaying the output in the browser.
Links searched:
None of the solutions worked:
Generate images with ImageMagick without saving to file but still display them on website
How can I convert my ImageMagick code to iMagick? PHP-Imagemagick image display
A direct example using your code for others to learn from.
I use this same method on my shared Linux server on Godaddy.
<?php
$source = "src.png";
$color = "#00FF00";
$cmd = "convert $source -threshold 100% +level-colors '$color',".
" -unsharp 0.2x0.6+1.0 -quality 50 JPG:-";
header("Content-type: image/jpeg");
passthru($cmd, $retval);
exit();
?>
Note: - Are you sure you are using "-threshold 100% +level-colors '$color'," correctly? Threshold 100% will push an image to black. Which then +level-colors '#00FF00', will just make a solid green image. I am assuming you have simplified the code for this demonstration.
Note: - "+level-colors '$color'", does not work on Godaddy's servers. It works fine on my home server though. Possibly an outdated ImageMagick version installed on Godaddy's server.
I'm using a generic PHP based CMS, i wanted to create a script which read the pdf created a thumbnail and cached it. There were lots of different answers, and i did have a fair few problems with different versions of imagick, but this is script which worked for me.
some people might find it useful and maybe someone could advice me if it is optimised?
<?php
$loc = *the file location*;
$pdf = *the file name*;
$format = "jpg";
$dest = "$loc$pdf.$format";
if (file_exists($dest))
{
$im = new imagick();
$im->readImage($dest);
header( "Content-Type: image/jpg" );
echo $im;
exit;
}
else
{
$im = new imagick($loc.$pdf.'[0]');
$im->setImageFormat($format);
$width = $im->getImageheight();
$im->cropImage($width, $width, 0, 0);
$im->scaleImage(110, 167, true);
$im->writeImage($dest);
header( "Content-Type: image/jpg" );
echo $im;
exit;
}
?>
Leverage PHP and ImageMagick to create PDF thumbnails
http://stormwarestudios.com/articles/leverage-php-imagemagick-create-pdf-thumbnails/
In this article, we discuss using PHP and ImageMagick to generate thumbnails from a given PDF, storing them in a temporary (or “cache”) directory, and serving them up to the web.
One of our more recent clients made a request to display PDF thumbnails published through the Joomla CMS that we’d deployed for them.
The requirement was fairly simple, but the execution was a little more involved. After installing ImageMagick, ImageMagick PHP bindings (which incidentally aren’t working, and a workaround was devised), and sleuthing some code, the following solution was determined:
<?php
function thumbPdf($pdf, $width)
{
try
{
$tmp = 'tmp';
$format = "png";
$source = $pdf.'[0]';
$dest = "$tmp/$pdf.$format";
if (!file_exists($dest))
{
$exec = "convert -scale $width $source $dest";
exec($exec);
}
$im = new Imagick($dest);
header("Content-Type:".$im->getFormat());
echo $im;
}
catch(Exception $e)
{
echo $e->getMessage();
}
}
$file = $_GET['pdf'];
$size = $_GET['size'];
if ($file && $size)
{
thumbPdf($file, $size);
}
?>
The above code assumes that you’ve provided appropriate permissions to the temporary directory (usually chmod 755 or chmod 777, depending on your level of courage), that you’ve saved the above code snippet in a file called thumbPdf.php, and placed this somewhere visible on your web server.
After obtaining parameters from GET, the code checks the destination temporary directory, and if the desired image is not present, it uses ImageMagick’s convert program to generate the PDF thumbnail, sized down to the appropriate proportion, and saves the image in the temporary directory. Finally, it reloads the thumbnail into an ImageMagick PHP object, and outputs the content to the browser.
Invoking the above code is done fairly easily; simply call the PHP script from inside an image tag, like so:
<img src="/path/to/thumbPdf.php?pdf=your.pdf&size=200" />
The above code would generate a thumbnail from the first page of “your.pdf”, sized 200 pixels wide by an appropriately-proportioned height.
Good luck, and happy webmastering!
I know it's been discussed here:
Should I use a PHP extension for ImageMagick or just use PHP's Exec() function to run the terminal commands?
And to quote drew101:
You would benefit a lot using the PHP extensions instead of using exec
or similar functions. Built in extensions will be faster and use less
memory as you will not have to spawn new processes and read the output
back. The image objects will be directly available in PHP instead of
having to read file output, which should make the images easier to
work with.
If you have a busy site, creating lots of processes to edit images may
start to slow things down and consume additional memory.
If you have not installed the Imagick php library for some reason you may use the ghost script and generate thumbnail of an pdf using the below example :
exec('gs -dSAFER -dBATCH -sDEVICE=jpeg -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -r300 -sOutputFile=xyz.jpg xyz.pdf');
i need display modyfied image , i have 2 option as i see it
to create temp image that is modified and then delete it
or to create the image on the fly and display it with passthru
for example :
$photo="foo.jpg";
$THUMB_SZ = 125;
$THUMB_PRESZ = $THUMB_SZ * 2;
$QUALITY = 87;
$convert = "/usr/bin/convert";
$command = "$convert -size $THUMB_PRESZ".'x'."$THUMB_PRESZ \"$photo\"" .
" -thumbnail $THUMB_SZ".'x'."$THUMB_SZ" .
" -unsharp 0.2x0.6+1.0" .
" -quality $QUALITY JPG:-";
header("Content-type: image/jpeg");
passthru($command, $retval);
and then in the html part <img src="foo.php">
If you need to create the image more than once, then I would suggest you create the file on disk, for two reasons
It saves creating it more than once.
With the correct caching headers, you can save transferring the data to the same client more than once as well.
If you really only need to show it once, ever, then you can do it using passthrough (or, if you're interested in performance, use the PHP Imagick bindings, it's faster, cleaner and safer than using imagick via the command line).
If you don't need to keep the modified image then using passthru saves a disk write and a delete. Your app is probably not that speed sensitive though.
If I really concern for performance, I would avoid the passthru choice. It would needlessly execute external command each time a user requested the image. If you use temp image, and changed the img src reference to the temp image, only the web server will retrieve the image and send it to the user, no PHP nor convert will be involved. Of course, I was assuming the image is changed not very often.