Uploaded image: converting format - php

I want to convert a uploaded image to its original format, (jpg, jpeg rpng, etc.) but I need to re-size these images to be 150px width and 210px height. Is it possible to change the size while copying, or do I have to convert it?
This was unsucessful:
$uploaddir1 = "/home/myweb/public_html/temp/sfds454.png";
$uploaddir2 = "/home/myweb/public_html/images/sfds454.png";
$cmd = "/usr/bin/ffmpeg -i $uploaddir1 -vframes 1 -s 150x210 -r 1 -f mjpeg $uploaddir2";
#exec($cmd);

You can use gd instead of ffmpeg. To convert or resize an image, see this example: http://ryanfait.com/resources/php-image-resize/resize.txt
Php lib for gd:
http://php.net/manual/en/function.imagecopyresampled.php
There is also some samples of resizing scripts in that page.

I recently had to solve just this problem, and implemented this simple caching solution:
<?php
function send($name, $ext) {
$fp = fopen($name, 'rb');
// send the right headers
header("Content-Type: image/$ext");
header("Content-Length: " . filesize($name));
// dump the picture and stop the script
fpassthru($fp);
exit;
}
error_reporting(E_ALL);
ini_set('display_errors', 'On');
if (isset($_REQUEST['fp'])) {
$ext = pathinfo($_REQUEST['fp'], PATHINFO_EXTENSION);
$allowedExt = array('png', 'jpg', 'jpeg');
if (!in_array($ext, $allowedExt)) {
echo 'fail';
}
if (!isset($_REQUEST['w']) && !isset($_REQUEST['h'])) {
send($_REQUEST['fp']);
}
else {
$w = $_REQUEST['w'];
$h = $_REQUEST['h'];
//use height, width, modification time and path to generate a hash
//that will become the file name
$filePath = realpath($_REQUEST['fp']);
$cachePath = md5($filePath.filemtime($filePath).$h.$w);
if (!file_exists("tmp/$cachePath")) {
exec("gm convert -quality 80% -colorspace RGB -resize " .$w .'x' . $h . " $filePath tmp/$cachePath");
}
send("tmp/$cachePath", $ext);
}
}
?>
Some things that I noticed:
Graphicsmagick converted much faster than imagemagick, although I did not test conversion with cuda processing.
For the final product I re-implemented this code in ASP using the language's native graphics library. This was much faster again but would break if out-of-memory errors occurred (worked fine on my workstation, but wouldn't work on 4GB RAM server).

Related

Create PDF thumbnail with Imagick and write to file

I'm trying to create a pdf thumbnail with Imagick and save it on the server in the same location as the pdf. The code below works fine as is. The problem is that I don't want to echo the image. But if I remove the echo statement, the resulting jpg file contains errors and is unreadable. How can I create the thumbnail and write to a file without sending it to the browser?
$pdfThumb = new \imagick();
$pdfThumb->setResolution(10, 10);
$pdfThumb->readImage($filePath . $fileName . $fileExt . '[0]');
$pdfThumb->setImageFormat('jpg');
header("Content-Type: image/jpeg");
echo $pdfThumb;
$fp = fopen($filePath . $fileName . '.jpg', "x");
$pdfThumb->writeImageFile($fp);
fclose($fp);
DaGhostman Dimitrov provided some helpful code on #16606642, but it doesn't work for me for some reason.
I would try:
$pdfThumb = new imagick();
$pdfThumb->setResolution(10, 10);
$pdfThumb->readImage($filePath . $fileName . $fileExt . '[0]');
$pdfThumb->setImageFormat('jpg');
$fp = $filePath . $fileName . '.jpg';
$pdfThumb->writeImage($fp);
Bonzo's answer requires imagick on the webserver. If imagick is not on the webserver you can try to execute imagemagick from the commandline by php command exec():
exec('convert -thumbnail "178^>" -background white -alpha remove -crop 178x178+0+0 my_pdf.pdf[0] my_pdf.png')
And if you like to convert all pdfs in one step from same folder where your script is located try this:
exec('for f in *.pdf; do convert -thumbnail "178^>" -background white -alpha remove -crop 178x178+0+0 "$f"[0] "${f%.pdf}.png"; done');
In this examples I create a png thumbnail 178x178 pixel from the first page (my_pdf.pdf[0] the 0 means first pdf page).

Php imagick anti aliasing

I have a problem with my php: when I make conversion PDF to JPG not shown correctly.
This is the original pictures of pdf - > http://s16.postimg.org/ma0jizgt1/text_problem2_fw.png
This is the jpg after converting with imagick - > http://s14.postimg.org/ilhs9tt3l/text_problem_fw.png
Please can you help me ?
Thank you
PHP:
if (move_uploaded_file( $_FILES["files"]["tmp_name"], $uploadUrlPdf . $_FILES["files"]["name"]))
{
$_FILES['files']['name'];
$nr_pag = $_POST['nr_pagini'];
for($i = 0; $i < $nr_pag; $i++)
{
$fn = $uploadUrlSwf.sprintf("%02d", "$i").".jpg";
if (!file_exists($fn))
{
$im = new imagick();
$im->setResolution($dpi,$dpi);
$pdf = $uploadUrlPdf.$_FILES['files']['name']."[$i]";
$im->readimage($pdf);
$im->setImageFormat('jpg');
$im->writeImage($fn);
file_put_contents( $fn, (string)$im );
$im->clear();
$im->destroy();
}
}
}
else
{
echo "error!";
}
Try setting your dpi value higher. If that does not work, try another export format (other than jpg). SVG would be your best bet, because you can scale that while the text and other shapes are still perfect quality. JPG wil not be sharp at a high zoom level if the resolution (dpi) is too low.
This forum entry might help: anti-aliased text when exporting PDF to image

resize width and compress images on upload php mysql

I have a client that sends me text messages from his iPhone with images for me to upload into his gallery. I'm trying to create a admin system so I can simply take the images from the texts, go to the admin page on my iPhone and upload the images straight to the gallery.
This would save me tons of time in my day to day work schedule.
Using the provided code. How can I add the following functions:
I would like to compress the file size down to a smaller size if possible, similar to the save to web jpg function in Photoshop. (Most images I get are around 1-3 MB. I would like to get them down to around 150-500kb max)
I would like to automatically change the width to 760px, but keep the aspect ratio so the images are not squished. He sends me landscape and portrait images.
Beings they are iPhone images. They have an extension .JPG (all caps) I would like this to change to .jpg (all lower case.) This is not a deal breaker I would just like to know how to do this for future use.
Either one of these functions would be very helpful, but all 3 would be ideal for my situation.
Here is the code I'm working with?
THIS IS THE FINAL CORRECT CODE FOR UPLOADING AND RESIZING IMAGES PROVIDED By #tman
Make sure you have imagick installed in your php.ini file. Check with your hosting provider to install it.
<?php
include($_SERVER['DOCUMENT_ROOT'] . "/connections/dbconnect.php");
for($i=0;$i<count($_FILES["image"]["name"]);$i++){
if($_FILES["image"]["name"][$i] != ''){ // don't insert if file name empty
$dataType = mysql_real_escape_string($_POST["dataType"][$i]);
$title = mysql_real_escape_string($_POST["title"][$i]);
$fileData = pathinfo($_FILES["image"]["name"][$i]);
$fileName = uniqid() . '.' . $fileData['extension'];
$target_path = $_SERVER['DOCUMENT_ROOT'] . "/images/gallery/" . $fileName;
if (move_uploaded_file($_FILES["image"]["tmp_name"][$i], $target_path)){ // The file is in the images/gallery folder.
// Insert record into database by executing the following query:
$sql="INSERT INTO images (data_type, title, file_name) "."VALUES('$dataType','$title','$fileName')";
$retval = mysql_query($sql);
///NEW
$size = getimagesize($target_path);
$width=$size[0];
$height=$size[1];
$newwidth = 760;
$newheight = $height*($newwidth/$width);
$pic = new Imagick($target_path);//specify name
$pic->resizeImage($newwidth,$newhight,Imagick::FILTER_LANCZOS,1);
unlink($target_path);
$pic->writeImage($target_path);
$pic->destroy();
///NEW
echo "The image {$_FILES['image']['name'][$i]} was successfully uploaded and added to the gallery<br />
<a href='index.php'>Add another image</a><br />";
}
else
{
echo "There was an error uploading the file {$_FILES['image']['name'][$i]}, please try again!<br />";
}
}
} // close your foreach
?>
uploader.php Original code. Allows me to upload 4 images at once. WORKS!!!
<?php
include($_SERVER['DOCUMENT_ROOT'] . "/connections/dbconnect.php");
for($i=0;$i<count($_FILES["image"]["name"]);$i++){
if($_FILES["image"]["name"][$i] != ''){ // don't insert if file name empty
$dataType = mysql_real_escape_string($_POST["dataType"][$i]);
$title = mysql_real_escape_string($_POST["title"][$i]);
$fileData = pathinfo($_FILES["image"]["name"][$i]);
$fileName = uniqid() . '.' . $fileData['extension'];
$target_path = $_SERVER['DOCUMENT_ROOT'] . "/images/gallery/" . $fileName;
if (move_uploaded_file($_FILES["image"]["tmp_name"][$i], $target_path)){ // The file is in the images/gallery folder.
// Insert record into database by executing the following query:
$sql="INSERT INTO images (data_type, title, file_name) "."VALUES('$dataType','$title','$fileName')";
$retval = mysql_query($sql);
echo "The image {$_FILES['image']['name'][$i]} was successfully uploaded and added to the gallery<br />
<a href='index.php'>Add another image</a><br />";
}
else
{
echo "There was an error uploading the file {$_FILES['image']['name'][$i]}, please try again!<br />";
}
}
} // close your foreach
?>
FYI, This will allow you to give a unique names to your images, resize the width, but keep the correct aspect ratio and upload multiple file at the same time.
Awesome Stuff!
Like this:
$filelocation='http://help.com/images/help.jpg';
$newfilelocation='http://help.com/images/help1.jpg';
$size = getimagesize($filelocation);
$width=$size[0];//might need to be ['1'] im tired .. :)
$height=$size[1];
// Plz note im not sure of units pixles? & i could have the width and height confused
//just had some knee surgery so im kinda loopy :)
$newwidth = 760;
$newheight = $height*($newwidth/$width)
$pic = new Imagick( $filelocation);//specify name
$pic->resizeImage($newwidth,$newhight,Imagick::FILTER_LANCZOS,1);
//again might have width and heing confused
$pic->writeImage($newfilelocation);//output name
$pic->destroy();
unlink($filelocation);//deletes image
Here is something kind of similar, lets check the size and compress if the image seems that it is too big. I didn't resize it which just requires that you get the dimensions and resize based on desire.
All this is doing is if the file is greater than 250KB compress it to 85% ..
$bytes = filesize($inventory_path.DIRECTORY_SEPARATOR.$this->uploadName);
//$maxSizeInBytes = 26400; //is 250KB? No? compress it.
if ($bytes > 26400) {
$img = new Imagick($inventory_path.DIRECTORY_SEPARATOR.$this->uploadName);
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->stripImage();
$img->setImageCompressionQuality(85);
$img->writeImage($inventory_path.DIRECTORY_SEPARATOR.$this->uploadName);
}
OR:
// resize with imagejpeg ($image, $destination, $quality); if greater than byte size KB
// Assume only supported file formats on website are jpg,jpeg,png, and gif. (any others will not be compressed)
$bytes = filesize($inventory_path.DIRECTORY_SEPARATOR.$this->uploadName);
//$maxSizeInBytes = 26400; //is gtr than 250KB? No? compress it.
if ($bytes > 26400) {
$info = getimagesize($inventory_path.DIRECTORY_SEPARATOR.$this->uploadName);
$quality = 85; //(1-100), 85-92 produces 75% quality
if ($info['mime'] == 'image/jpeg') {
$image = imagecreatefromjpeg($inventory_path.DIRECTORY_SEPARATOR.$this->uploadName);
imagejpeg($image,$inventory_path.DIRECTORY_SEPARATOR.$this->uploadName,$quality);
} elseif ($info['mime'] == 'image/gif') {
$image = imagecreatefromgif($inventory_path.DIRECTORY_SEPARATOR.$this->uploadName);
imagejpeg($image,$inventory_path.DIRECTORY_SEPARATOR.$this->uploadName,$quality);
} elseif ($info['mime'] == 'image/png') {
$image = imagecreatefrompng($inventory_path.DIRECTORY_SEPARATOR.$this->uploadName
imagejpeg($image,$inventory_path.DIRECTORY_SEPARATOR.$this->uploadName,$quality);
}
}

Remove EXIF data from JPG using PHP

Is there any way to remove the EXIF data from a JPG using PHP? I have heard of PEL, but I'm hoping there's a simpler way. I am uploading images that will be displayed online and would like the EXIF data removed.
Thanks!
EDIT: I don't/can't install ImageMagick.
Use gd to recreate the graphical part of the image in a new one, that you save with another name.
See PHP gd
edit 2017
Use the new Imagick feature.
Open Image:
<?php
$incoming_file = '/Users/John/Desktop/file_loco.jpg';
$img = new Imagick(realpath($incoming_file));
Be sure to keep any ICC profile in the image
$profiles = $img->getImageProfiles("icc", true);
then strip image, and put the profile back if any
$img->stripImage();
if(!empty($profiles)) {
$img->profileImage("icc", $profiles['icc']);
}
Comes from this PHP page, see comment from Max Eremin down the page.
A fast way to do it in PHP using ImageMagick (Assuming you have it installed and enabled).
<?php
$images = glob('*.jpg');
foreach($images as $image)
{
try
{
$img = new Imagick($image);
$img->stripImage();
$img->writeImage($image);
$img->clear();
$img->destroy();
echo "Removed EXIF data from $image. \n";
} catch(Exception $e) {
echo 'Exception caught: ', $e->getMessage(), "\n";
}
}
?>
I was looking for a solution to this as well. In the end I used PHP to rewrite the JPEG with ALL Exif data removed. I didn't need any of it for my purposes.
This option has several advantages...
The file is smaller because the EXIF data is gone.
There is no loss of image quality (because the image data is unchanged).
Also a note on using imagecreatefromjpeg: I tried this and my files got bigger. If you set quality to 100, your file will be LARGER, because the image has been resampled, and then stored in a lossless way. And if you don't use quality 100, you lose image quality. The ONLY way to avoid resampling is to not use imagecreatefromjpeg.
Here is my function...
/**
* Remove EXIF from a JPEG file.
* #param string $old Path to original jpeg file (input).
* #param string $new Path to new jpeg file (output).
*/
function removeExif($old, $new)
{
// Open the input file for binary reading
$f1 = fopen($old, 'rb');
// Open the output file for binary writing
$f2 = fopen($new, 'wb');
// Find EXIF marker
while (($s = fread($f1, 2))) {
$word = unpack('ni', $s)['i'];
if ($word == 0xFFE1) {
// Read length (includes the word used for the length)
$s = fread($f1, 2);
$len = unpack('ni', $s)['i'];
// Skip the EXIF info
fread($f1, $len - 2);
break;
} else {
fwrite($f2, $s, 2);
}
}
// Write the rest of the file
while (($s = fread($f1, 4096))) {
fwrite($f2, $s, strlen($s));
}
fclose($f1);
fclose($f2);
}
The code is pretty simple. It opens the input file for reading and the output file for writing, and then starts reading the input file. It data from one to the other. Once it reaches the EXIF marker, it reads the length of the EXIF record and skips over that number of bytes. It then continues by reading and writing the remaining data.
The following will remove all EXIF data of a jpeg file. This will make a copy of original file without EXIF and remove the old file. Use 100 quality not to loose any quality details of picture.
$path = "/image.jpg";
$img = imagecreatefromjpeg ($path);
imagejpeg ($img, $path, 100);
imagedestroy ($img);
(simple approximation to the graph can be found here)
function remove_exif($in, $out)
{
$buffer_len = 4096;
$fd_in = fopen($in, 'rb');
$fd_out = fopen($out, 'wb');
while (($buffer = fread($fd_in, $buffer_len)))
{
// \xFF\xE1\xHH\xLLExif\x00\x00 - Exif
// \xFF\xE1\xHH\xLLhttp:// - XMP
// \xFF\xE2\xHH\xLLICC_PROFILE - ICC
// \xFF\xED\xHH\xLLPhotoshop - PH
while (preg_match('/\xFF[\xE1\xE2\xED\xEE](.)(.)(exif|photoshop|http:|icc_profile|adobe)/si', $buffer, $match, PREG_OFFSET_CAPTURE))
{
echo "found: '{$match[3][0]}' marker\n";
$len = ord($match[1][0]) * 256 + ord($match[2][0]);
echo "length: {$len} bytes\n";
echo "write: {$match[0][1]} bytes to output file\n";
fwrite($fd_out, substr($buffer, 0, $match[0][1]));
$filepos = $match[0][1] + 2 + $len - strlen($buffer);
fseek($fd_in, $filepos, SEEK_CUR);
echo "seek to: ".ftell($fd_in)."\n";
$buffer = fread($fd_in, $buffer_len);
}
echo "write: ".strlen($buffer)." bytes to output file\n";
fwrite($fd_out, $buffer, strlen($buffer));
}
fclose($fd_out);
fclose($fd_in);
}
It is a prototype for a call from a command line.
this is the simplest way:
$images = glob($location.'/*.jpg');
foreach($images as $image) {
$img = imagecreatefromjpeg($image);
imagejpeg($img,$image,100);
}
I completely misunderstood your question.
You could use some command line tool to do this job. or write your own php extension to do it. have a look at this lib that would be useful: http://www.sno.phy.queensu.ca/~phil/exiftool/
Cheers,
vfn
I'm not pretty sure about it, but if its possible using GD o ImageMagick, the first thing that come to my mind is to create a new Image and add the old image to the new one.

Downscale/resize?

How do I resize/downscale the images that gets uploaded with my upload script down to 350x100 if they are over 350x100?
My script:
$allowed_filetypes = array('.png','.PNG');
$filename = $_FILES['strUpload']['name'];
$ext = substr($filename, strpos($filename,'.'), strlen($filename)-1);
if(in_array($ext,$allowed_filetypes))
{
list($width, $height, $type, $attr) = getimagesize($_FILES['strUpload']['tmp_name']);
if ($width > 350 || $height > 100)
{
echo "That file dimensions are not allowed. Only 350x100 is allowed";
exit();
}
if ($_FILES['strUpload']['size'] > 2097152 )
{
echo "ERROR: Large File Size. Only less than 2mb accepted";
exit();
}
$imagename = uniqid('ff') . ".png";
move_uploaded_file ( $_FILES['strUpload']['tmp_name'], $imagename );
print ( "<script type=\"text/javascript\">" );
if(file_exists($imagename) && $_FILES['strUpload']['name'] != '')
{
print ( "self.opener.SetImageFile(\"" . $imagename . "\");" );
echo "\n";
print ( "self.opener.setInputFile(\"" . $imagename . "\");" );
}
echo "\n";
print ( "window.close();" );
echo "\n";
print ( "</script>" );
$open = new dbconnect();
$open->callDB("localhost","pema2201_william","lindberg","pema2201_siggen");
$ip = $_SERVER['REMOTE_ADDR'];
$dattum = date('Y-m-d H:i:s', time());
mysql_query("INSERT INTO piclist (ip,pic,datum) VALUES('$ip','$imagename','$dattum')") or die(mysql_error());
}
else
{
echo "WRONG FILE TYPE ONLY PNG ALLOWED"
}
PHP has several image handling libraries. The GD library has shipped since PHP 4.3 so I suggest using that. Just read the docs to find what you need.
Use imagecopyresized - there's a good example of how to use it on the PHP manual page.
Have a look at this question someone else asked a few days ago.
That not only explains how it's done, but also how it's done in an efficient way. (ImageMagick should be used over the GD library)
Hope that helps.
The general gist is to create a new "canvas" of the desired dimensions for the image to go in.
Take your uploaded image and copy it onto the new canvas giving setting a source width x height (take all of the source image) and destination width x height (use all of the destination canvas), offsets are available to shift the image around a bit if you need to.
Then finally save it where you need it to go, or insert it into a database field, (this will replace your move_uploaded_file call).

Categories