PHP ImageMagick invert color - php

I'm working on a PHP app that converts a self portrait into a pencil drawing and part of the app requires a desaturated/inverted image similar to the example below:
before and after invert:
It's easy creating a desaturated image, but how would I achieve this invert using imagemagick? I tried using negate, but failed miserably.
Here's what I have so far:
<?php
$img = new Imagick();
$img->readImage($image);
$img->modulateImage(100, 0, 100);
$img->writeImage('image.png');
ob_clean();
header('Content-Type: image/png');
echo $img;
$img->destroy();
?>

According this page, you can call imagemagick filter by PHP functions :
function negateImage($imagePath, $grayOnly, $channel) {
$imagick = new Imagick(realpath($imagePath));
$imagick->negateImage($grayOnly, $channel);
header("Content-Type: image/jpg");
echo $imagick->getImageBlob();
}

Related

PHP PDF to image crops some files when generating a thumbnail. setIteratorIndex fails as well

I have written a function in PHP 7.4 that generates a thumbnail of the first page of a PDF document. The function works as intended for most PDF files.
However, some PDFs get cropped when I generate the thumbnail. Additionally, sometimes, I don't get the first page.
This PDF triggers both problems:
http://www.teavigoinfo.com/pdf/study-27.pdf
function PDF2Thumbnail($url) {
$image = #file_get_contents($url);
if($image) {
$im = new Imagick();
$im->readImageBlob($image);
$im->setIteratorIndex(0);
$im->thumbnailImage(300, 0);
$im->setImageFormat('png');
$im = $im->flattenImages();
header('Content-Type: image/png');
echo $im;
}
}
Thank you.

Laravel generate image and add content type header

Hi I'm using php's gd library to generate images. I've decided to integrate this into laravel, and I managed to make it work.
My problem is that if laravel sometimes overwrites my content-type header.
This is my controller:
public function imga($algorythm,$w=false,$h=false){
if (!$w) $w=rand(250,750);
if (!$h) $h=rand(250,750);
$im = imagecreatetruecolor($w, $h);
//Here some fancy function is called
if (method_exists($this,'img_'.$algorythm)){
$this->{'img_'.$algorythm}($im,$w,$h);
}
header("Content-type: image/png");
imagepng($im);
imagedestroy($im);
}
Most of the times if the image is large enough the browser displays it just as expected, but if the image is to small laravel overwrites the content type header with "text/html; charset=UTF-8".
I've read https://laravel.com/docs/5.4/responses but to make it this way I need to have a string.
So I've looked at this: PHP: create image with ImagePng and convert with base64_encode in a single file? but I'm not sure if this is the right way, it looks like a dirty hack to me.
Should I put the imagepng call inside a view and add the headers there, isn't this a bit overkill?
How to use functions that output data instead of returning it in laravel.
Laravel controller actions are usually expected to give a response of some sort, which defaults to text/html.
Your fix could be as easy as:
header("Content-Type: image/png");
imagepng($im);
imagedestroy($im);
exit;
}
Alternatively you can use a package like intervention (http://image.intervention.io). From which you can generate an image response.
One way would be to capture the image output with ob_get_contents and then make a response with that:
public function imga($algorythm,$w=false,$h=false){
if (!$w) $w=rand(250,750);
if (!$h) $h=rand(250,750);
$im = imagecreatetruecolor($w, $h);
//Here some fancy function is called
if (method_exists($this,'img_'.$algorythm)){
$this->{'img_'.$algorythm}($im,$w,$h);
}
ob_start();
$rendered_buffer = imagepng($im);
$buffer = ob_get_contents();
imagedestroy($im);
ob_end_clean();
$response = Response::make($rendered_buffer);
$response->header('Content-Type', 'image/png');
return $response;
}
EDIT: Just saw your link, this is basically just an implementation of that.
If you want a "more laravel" way, you could save the image, return it, then delete it:
public function imga($algorythm,$w=false,$h=false){
if (!$w) $w=rand(250,750);
if (!$h) $h=rand(250,750);
$im = imagecreatetruecolor($w, $h);
//Here some fancy function is called
if (method_exists($this,'img_'.$algorythm)){
$this->{'img_'.$algorythm}($im,$w,$h);
}
// store the image
$filepath = storage_path('tmpimg/' . uniqid() . '.png');
imagepng($im, $filepath);
imagedestroy($im);
$headers = array(
'Content-Type' => 'image/png'
);
// respond with the image then delete it
return response()->file($filepath, $headers)->deleteFileAfterSend(true);
}

Create Thumbnail of ONLINE PDF for first page only using Imagick

I tried to make a thumbnail of a pdf file which is hosted on another server. My current code is:
<?php
$im = new imagick("http://www.d3publisher.us/Walkthroughs/Naruto_NC_3_DS.pdf");
$im->setImageFormat('jpg');
header('Content-Type: image/jpeg');
echo $im;
?>
The problem is that code is only generating thumbnail for LAST PAGE of the pdf file. How can I make a thumbnail for first page only? I tried to add [0] at the imagick line.
$im = new imagick("http://www.d3publisher.us/Walkthroughs/Naruto_NC_3_DS.pdf[0]");
but it didn't work. It only work for local pdf file, i.e:
$im = new imagick("my-pdf-file.pdf[0]");
Please help me solve this problem.. Thanks..
You'll need to reset the active image to the first page. This can be done with Imagick::setIteratorIndex.
<?php
$im = new imagick("http://www.d3publisher.us/Walkthroughs/Naruto_NC_3_DS.pdf");
$im->setIteratorIndex(0);
$im->setImageFormat('jpg');
header('Content-Type: image/jpeg');
echo $im;
?>
Try...
$im->setImageIndex(0); //this will return 1th page of the pdf file
$im->setImageFormat('jpg');
"This can be done with Imagick::setIteratorIndex. .."
..or not. Simply has no effect . Setting it to one crashes something, setting it to 0 gets the last page..
function make_thumbnail($filename)
{
try
{
$imagick= new Imagick($filename);
}
catch(ImagickException $e)
{
// failed to make a thimbynail. what now?
// load up our trusty truetype font png instead?
$imagick->destroy();
return "0"; // shove any rubbish in the db - it will just say no image available when asked.
}
$imagick->setIteratorIndex(0);// rewind to first page or image of a multi series
$imagick->setImageFormat("png"); // turn it into a png
$imagick = $imagick->flattenImages(); // remove any transparency
$imagick->scaleImage(300,0); //resize...to less than 300px wide
$d = $imagick->getImageGeometry();
$h = $d['height'];
if($h > 300)
$imagick->scaleImage(0,300);
$imagick->setImageCompression(\Imagick::COMPRESSION_UNDEFINED);
$imagick->setImageCompressionQuality(0);
$imagick->setIteratorIndex(0);
$a = $imagick->getImageBlob(); // output as bytestream
$imagick->destroy();
return $a;
}

Other non-image related code before and after header no longer work

I am trying to use header('Content-type: image/jpeg') to edit and display jpeg photos as follows.
header('Content-type: image/jpeg')
$filename = 'aaa.jpg';
$im = imagecreatefromjpeg($filename);
imagefilter($im, IMG_FILTER_CONTRAST,50);
imagejpeg($im);
imagedestroy($im);
In the same file,I also have other simple codes like $abc = $_POST['abc'].
After I put the header, code before the header and code after image destroy($im) no longer work. And when I put any code such as $_post['abc'] before the header, both header and code doesn't work. All codes were fine before I included header and code to manipulate and output image. It is my first time using header('Content-type: image/jpeg') and I cannot find the answer after trying for so long. Please help. Thank you.
If you want to output html page, do not send image header. But instead, at first output the transformed image to a file on your server and add the <img> or <a>nchor tag in your html page:
<html><body>
<?php
$output_dir = 'images';
if (!file_exists($output_dir)) {
mkdir($output_dir, 0777);
}
$filename = 'aaa.jpg';
$filename2 = 'aaa2.jpg';
if (!file_exists($filename)) {
echo 'Input image not exists!'; exit;
}
$im = imagecreatefromjpeg($filename);
imagefilter($im, IMG_FILTER_CONTRAST, 50);
imagejpeg($im, $output_dir.'/'.$filename2);
imagedestroy($im);
echo 'Original image:<br/><img src="'.$filename.'" /><br/>';
echo 'Transformed image:<br/><img src="'.$output_dir.'/'.$filename2.'" />';
?>
</body></html>
That image header send in case, you want to output it as standalone image. For more examples have a look at php.net.

PHP-Imagemagick image display

I have php code which create pdf thumbnail as follows;
<?php
$file ="test.pdf";
$im = new imagick(realpath($file).'[0]');
$im->setImageFormat("png");
$im->resizeImage(200,200,1,0);
header("Content-Type: image/jpeg");
$thumbnail = $im->getImageBlob();
echo $thumbnail;
?>
Which is working well. But if I want to display the image in a web page, I have to use <img src=""> tag. Is there any way to remove header("Content-Type: image/jpeg");
from the syntax and echo image using <img src="">..? Or anybody tell me how to use the syntax to display the image inside a web page.
I am running apache with php5 in my Windows Vista PC..
With Imagick, you could use base64 encoding:
echo '<img src="data:image/jpg;base64,'.base64_encode($img->getImageBlob()).'" alt="" />';`
However, this method is kind a slow and therefore I recommend generating and saving the image earlier $img->writeImage($path).
you can try to display the image by this way:
// start buffering
ob_start();
$thumbnail = $im->getImageBlob();
$contents = ob_get_contents();
ob_end_clean();
echo "<img src='data:image/jpg;base64,".base64_encode($contents)."' />";
Embedding an image using base64 is a COMPLETELY wrong way to go about the problem esp. with something stateless like a php web script.
You should instead use http parameters to have a single php file which can perform two tasks - the default will send html , and the parameter will instruct the php file to print the image. Below is the "standard" way to do it -
<?php
if (!array_key_exists('display',$_GET))
{
print('<html><head></head><body><img src="'.$_SERVER['PHP_SELF'].'?display=image"></body></html>');
} else
{
// The display key exists which means we want to display an image
$file ="test.pdf";
$im = new imagick(realpath($file).'[0]');
$im->setImageFormat("png");
$im->resizeImage(200,200,1,0);
header("Content-Type: image/jpeg");
$thumbnail = $im->getImageBlob();
echo $thumbnail;
}
?>
You can embed the raw image in you page, see the blog entry below for an example in page syntax.
http://www.sveinbjorn.org/news/2005-11-28-02-39-23
But i think it would be more productive to save the thumbnail on the filesystem and serve it as normal file. Otherwise you will be generating the thumbnail each time the page is accessed. Someone possibly uploaded this PDF file, so you may as well generate the thumbnail on upload time.
As I can see there are too many answers which are not accurate enough, so here goes mine:
This will print the image as you are doing it now(by the time of asking this question). As alternative to answer by #Vasil Dakov you should modify the snippet i gave you like this:
<?php
// ... Image generation goes here
header("Content-Type: image/jpeg");
ob_start();
print $im->getImageBlob();
$the_outputted_image = ob_get_flush();
?>
// Assuming that you use MVC approach and you are storing $the_outputted_image in a object and passing it to the view(ie. index.html or the HTML below the code).
//... Html code of index.html
<img src="data:image/jpg;base64 <?php print $the_outputted_image; ?>" alt="image" title="IMagick Generated Image" />
As another alternative is creating a script to generate the image, save it in some folder ( assuming img/ is the folder) and return only the path+filename+ extension to the file:
<?php
// ... Image generation goes here
header("Content-Type: image/jpeg");
$filename = 'img/' . md5(microtime()) . '.jpg'// Microtime is just as an example, you should use your own method.
$fp = fopen($filename, "x"); //Creating and opening the file for write-only
$im->writeImageFile($fp); //Writing the image to the file pointer (I would recommend writing it using, fwrite(), because it is binary-safe writing method)
fclose($fp);
?>
// Html
<img src="<?php print $filename; ?>" alt="image" title="IMagick Generated Image" />
documentation for Imagick::writeImageFile
In my case I found out a solution like this:
$im = new Imagick("http://www.yourserver.com/upload/file_name.pdf");
$im->setResolution(300, 300); // if higher image will be good to read
$im->setIteratorIndex(0); // read first page
$im->setImageFormat('jpg');
header('Content-Type: image/jpeg');
ob_start();
print $im->getImageBlob();
$contents = ob_get_contents();
ob_end_clean();
echo "<img src='data:image/jpg;base64,".base64_encode($contents)."' />"; //output as image
good luck.
The only solution would be to convert your image to base64 and include it as an embedded base64 image (data:image/png;base64, ). Further reference.
But this isn't supported in IE 6 and 7.

Categories