Embedding IPTC to Image in PHP with GD - php

I am trying to take a photograph and create a thumbnail without losing the IPTC info that contains copyright info and other information. I am scripting using GD for the resize which of course results in the loss of the IPTC data since it creates an entire new file, not actually resizing the original. So, my solution was to extract the IPTC data from the original image and then embed it in the thumbnail. As of now, everything runs fine and the thumbnail is generated except the IPTC data is not copied over. My code snippet is below. Can anyone see anyhting I am missing? This is based off of the examples in the PHP manual for iptcembed(). Oh yeah, I am working within the Zend Framework but apart from the Registry to handle the config, this is pretty straightforward OOP code. Thanks!
public function resizeImage($image, $size)
{
// Get Registry
$galleryConfig = Zend_Registry::get('gallery_config');
$path = APPLICATION_PATH . $galleryConfig->paths->mediaPath . $image->path . '/';
$file = $image->filename . '.' . $image->extension;
$newFilename = $image->filename . '_' . $size . '.' . $image->extension;
// Get Original Size
list($width, $height) = getimagesize($path . $file);
// Check orientation, create scalar
if($width > $height){
$scale = $width / $size;
}else{
$scale = $height / $size;
}
// Set Quality
switch($size){
case ($size <= 200):
$quality = 60;
break;
case ($size > 200 && $size <= 600):
$quality = 80;
break;
case ($size > 600):
$quality = 100;
break;
}
// Recalculate new sizes with default ratio
$new_width = round($width * (1 / $scale));
$new_height = round($height * (1/ $scale));
// Resize Original Image
$imageResized = imagecreatetruecolor($new_width, $new_height);
$imageTmp = imagecreatefromjpeg ($path.$file);
imagecopyresampled($imageResized, $imageTmp, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
// Save File
$complete = imagejpeg($imageResized, $path . $newFilename, $quality);
// Copy IPTC info into new file
$imagesize = getImageSize($path . $file, $info);
if(isset($info['APP13'])){
$content = iptcembed($info['APP13'], $path . $newFilename);
$fw = fopen($path . $newFilename , 'wb');
fwrite($fw, $content);
fclose($fw);
}
}

I think iptcembed does automatically save the file, which means that the php.net manual example is wrong:
Return Values
If success and spool flag is lower than 2 then the JPEG will not be returned as a string, FALSE on errors.
See http://php.net/iptcembed

Related

How to adjust this script to use Glob instead of 1 file

I have created this script based on reading other posts on StackOverflow. The script creates a thumbnail from the original image and adds it to a folder. The source images are located on my local server so Glob would work however I am not sure how to adjust this script so that it will run this function on all files in a folder (Glob). I realize it may be memory intensive but I only need to do it a few times on several folders and I'll be done with it.
Just in case you are questioning the reason I have included $height2, it is a little hack I came up with where we create the thumbnail while maintaining the aspect ratio then only save the top 250px so that the thumb is 250 x 250 but not distorted (stretched). It works great.
I just need to adjust to do a batch of all images in the source folder.
Any help would be great. Please keep in mind that I am a front end developer (html and css) and not great at PHP. This script alone took me forever to make work lol.
If anyone can help me adjust it for a full folder, that would be great.
foreach(glob('SourceFolder/*.jpg', GLOB_NOSORT) as $url); {
Thumbnail ($url, "DestinationFolder/*.jpg");
function Thumbnail($url, $filename, $width = 250, $height = true, $height2 = 250) {
// download and create gd image
$image = ImageCreateFromString(file_get_contents($url));
// calculate resized ratio
// Note: if $height is set to TRUE then we automatically calculate the height based on the ratio
$height = $height === true ? (ImageSY($image) * $width / ImageSX($image)) : $height;
// create image
$output = ImageCreateTrueColor($width, $height2);
ImageCopyResampled($output, $image, 0, 0, 0, 0, $width, $height, ImageSX($image), ImageSY($image));
// save image
ImageJPEG($output, $filename, 100);
}
}
I was able to adjust the code on my own after reading the online PHP manual.
The final code:
foreach (glob("SourceFolder/*.jpg") as $url) {
$destdir = "Destination/" . basename($url, null);
$width = 250;
$height = true;
// download and create gd image
$image = ImageCreateFromString(file_get_contents($url));
// calculate resized ratio
// Note: if $height is set to TRUE then we automatically calculate the height based on the ratio
$height = $height === true ? (ImageSY($image) * $width / ImageSX($image)) : $height;
// create image
$output = ImageCreateTrueColor($width, $height);
ImageCopyResampled($output, $image, 0, 0, 0, 0, $width, $height, ImageSX($image), ImageSY($image));
// save image
ImageJPEG($output, $destdir, 100);
}
This solution uses opendir and readdir. I have found that this approach can
handle folders with more files.
// Set desired height and width
$desiredWidth = 250;
$desiredHeight = true;
// Set source and destination folders
$srcFolder = "SourceFolder";
$destFolder = "Destination";
// This is more memory efficient than using glob()
$dh = opendir($srcFolder);
if ( ! $dh ) {
die('Unable to open folder ' . $srcFolder);
}
while($filename = readdir($dh) ) {
// only process jpg files.
if ( preg_match('/.jpg$/', $filename) ) {
$inputFile = sprintf('%s/%s', $srcFolder, $filename);
$outputFile = sprintf('%s/%s', $destFolder, $filename);
echo "file: $filename\n";
echo "input: $inputFile\n";
echo "output: $outputFile\n";
$inputImage = #ImageCreateFromJpeg($inputFile);
if ( $inputImage ) {
// calculate resized ratio
// Note: if $height is set to TRUE then we automatically calculate the height based on the ratio
$height = $desiredHeight === true ? (ImageSY($inputImage) * $desiredWidth / ImageSX($inputImage)) : $desiredHeight;
// create image
$outputImage = ImageCreateTrueColor($desiredWidth, $height);
ImageCopyResampled($outputImage, $inputImage, 0, 0, 0, 0, $desiredWidth, $height, ImageSX($inputImage), ImageSY($inputImage));
// save image
ImageJPEG($outputImage, $outputFile, 100);
ImageDestroy($inputImage);
ImageDestroy($outputImage);
} else {
echo "Could not process file\n";
}
}
}
closedir($dh);

There are gray stains on the image after converting to another format after use ImageMagick php

I have the following problem. I use ImageMagick for the reformat PDF to JPG. Everything goes well but on the picture appear the mark in the form of triangles. Here is an example code and images before and after.
$pdf_file = $name[0] . '.pdf';
$im = new imagick($pdf_file);
$i = 0;
foreach ($im as $_img) {
$i++;
$_img->setResolution(300, 300);
$im->setImageColorspace(255);
$im->setCompression(Imagick::COMPRESSION_JPEG);
$im->setCompressionQuality(60);
$_img->setImageFormat('jpg');
$_img->writeImage(__DIR__ .'/'.$main_name[0] . '.jpg');
}
$im->destroy();
$new_name = DIR .'/'. $main_name[0] . '.jpg';
$new_name1 = $main_name[0] . '.jpg';
//$new_name1 = preg_replace('/[^A-Za-z0-9\-]/', '', $new_name1);
$size = getimagesize($new_name1);
$ratio = $size[0]/$size[1]; // width/height
if( $ratio > 1) {
$width = 700;
$height = 700/$ratio;
}
else {
$width = 700*$ratio;
$height = 700;
}
$src = imagecreatefromstring(file_get_contents($new_name1));
$dst = imagecreatetruecolor($width,$height);
imagecopyresampled($dst,$src,0,0,0,0,$width,$height,$size[0],$size[1]);
imagedestroy($src);
imagepng($dst,$new_name1); // adjust format as needed
imagedestroy($dst);
The "stains" are JPEG artifacts. Use a higher "quality" (60 is pretty low; 90 would be better for this type of image), or use PNG instead. The higher-quality JPEG will of course occupy a larger filesize, but that's the tradeoff.

How to resize image without storing it on a folder

So, i have been stuck on this for couple of hours. I have tired to google any solutions for this but didn't find solutions. So any help is greatly appreciated.
My Issue:
I am using form to upload multiple images. Due to data being backup on multiple servers i have to stored them on database. And storing the images on folder is not a solution. I thinks I can save the image onto the database but my I need to create a thumbnail of all the images which are being uploaded. So that's my problem, how do i create a thumbnail from those tmp files. I created to use imagecreate its not working, I am not able to fetch the content of that thumbnail and save it onto the database.
This is a code i used to resize that image which doesn't return the contents.
function resize_image($file, $w, $h, $crop=FALSE) {
list($width, $height) = getimagesize($file);
$r = $width / $height;
if ($crop) {
if ($width > $height) {
$width = abs(ceil($width-($width*abs($r-$w/$h))));
} else {
$height = abs(ceil($height-($height*abs($r-$w/$h))));
}
$newwidth = $w;
$newheight = $h;
} else {
if ($w/$h > $r) {
$newwidth = $h*$r;
$newheight = $h;
} else {
$newheight = $w/$r;
$newwidth = $w;
}
}
$src = imagecreatefromjpeg($file);
$dst = imagecreatetruecolor($newwidth, $newheight);
imagecopyresampled($dst, $src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
return $dst;
}
This is my code which is used after form is posted: Right now it only displays all the files that are uploaded.
for($i=0;$i< count($_FILES['upload_file']['tmp_name']);$i++)
{
$size = getimagesize($_FILES['upload_file']['tmp_name'][$i]);
$name = $_FILES['upload_file']['name'][$i];
$type = $size['mime'];
$file_size_bits = $size['bits'];
$file_size_width = $size[0];
$file_size_height = $size[1];
$name = $_FILES['upload_file']['name'][$i];
$image_size = $size[3];
$uploadedfile = $_FILES['upload_file']['tmp_name'][$i];
$tmpName = base64_encode(file_get_contents($_FILES['upload_file']['tmp_name'][$i]));
$sImage_ = "data:" . $size["mime"] . ";base64," . $tmpName;
echo '<p>Preview from the data stored on to the database</p><img src="' . $sImage_ . '" alt="Your Image" />';
}
I need to create a thumbnail of those files that are being uploaded. How do i achieve that.
Please advise.
Thanks for your help.
Cheers
This is your big problem:
return $dst;
$dst is the image resource, not the image data.
You should use imagejpeg() or imagepng() to send the image data back instead.
Because those functions output the data stream to browser, we use some output buffer functions to capture the outputted image data instead of send it to the browser.
So,
return $dst;
replace with:
ob_start();
imagejpeg( $dst, NULL, 100); // or imagepng( $dst, NULL, 0 );
$final_image = ob_get_contents();
ob_end_clean();
return $final_image;

Check image dimensions before upload

Hi I based this function from the one I've found on web and tried modifying it up for my PHP page for uploading of their icons but I want to limit the user from uploading an image which should only size 100x100px. Well I just call it using this:
uploadImage($id,$_FILES['upload']['name'],$_FILES['upload']['tmp_name']);
This is the function I made:
function uploadImage($new_name,$imagename,$tmp_name){
if($tmp_name!=null||$tmp_name!=""){
list($width, $height, $type, $attr) = getimagesize($tmp_name);
if($width==100&&$height==100){
$image1 = $imagename;
$extension = substr($image1, strrpos($image1, '.') + 1);
$image = "$new_name.$extension";
$folder = "Images/";
if($image) {
$filename = $folder.$image;
$copied = copy($tmp_name, $filename);
}
else echo "image not uploaded.";
}
else
echo "upload only 100x100px image!";
}
}
Now the problem is that even if I uploaded an image which exceeds the 100 x 100px dimensions it still proceeds without returning any errors and now I'm lost with it.
You probably need to re-factor your code a bit; have a function that checks whether the uploaded image is valid, and then one actually does the upload. Alternatively, you could create a class.
<?php
class ImageUpload
{
public $tmpImage;
public $maxWidth = 100;
public $maxHeight = 100;
public $errors = [];
public function __construct($image)
{
$this->tmpImage = $image;
}
public function upload()
{
// Check image is valid; if not throw exception
// Check image is within desired dimensions
list($width, $height) = getimagesize($this->tmpImage);
if ($width > $this->maxWidth || $height > $this->maxHeight) {
throw new Exception(sprintf('Your image exceeded the maximum dimensions (%d×%d)', $this->maxWidth, $this->maxHeight));
}
// Create filename
// Do the upload logic, i.e. move_uploaded_file()
}
}
You can then use this class as follows:
<?php
$imageUpload = new ImageUpload($_FILES['upload']['tmp_name']);
try {
$imageUpload->upload();
} catch (Exception $e) {
echo 'An error occurred: ' . $e->getMessage();
}
This was written off the cuff, so they may be errors. But hopefully it demonstrates a better way to handle file uploads, and errors that may occur during upload.
well, you can also resize the image after upload.
function createFixSizeImage( $pathToImages, $pathToFixSizeImages, $Width )
{
// open the directory
$dir = opendir( $pathToImages );
// loop through it, looking for any/all JPG files:
while (false !== ($fname = readdir( $dir ))) {
$image_info = getimagesize( "path/to/images/".$fname );
$image_width = $image_info[0];
$image_height = $image_info[1];
$image_type = $image_info[2];
switch ( $image_type )
{
case IMAGETYPE_JPEG:
// parse path for the extension
$info = pathinfo($pathToImages . $fname);
// continue only if this is a JPEG image
if ( strtolower($info['extension']) == 'jpeg' )
{
// load image and get image size
$img = imagecreatefromjpeg( "{$pathToImages}{$fname}" );
$width = imagesx( $img );
$height = imagesy( $img );
// give the size,u want
$new_width = 100;
$new_height = 100;
// create a new temporary image
$tmp_img = imagecreatetruecolor( $new_width, $new_height );
// copy and resize old image into new image
imagecopyresized( $tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
// save Fix Size Images into a file
imagejpeg( $tmp_img, "{$pathToFixSizeImages}{$fname}" );
}
break;
case IMAGETYPE_PNG:
// parse path for the extension
$info = pathinfo($pathToImages . $fname);
// continue only if this is a JPEG image
if ( strtolower($info['extension']) == 'png' )
{
// load image and get image size
$img = imagecreatefrompng( "{$pathToImages}{$fname}" );
$width = imagesx( $img );
$height = imagesy( $img );
$new_width = 100;
$new_height = 100;
// create a new temporary image
$tmp_img = imagecreatetruecolor( $new_width, $new_height );
// copy and resize old image into new image
imagecopyresized( $tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
// save Fix Size Images into a file
imagejpeg( $tmp_img, "{$pathToFixSizeImages}{$fname}" );
}
break;
case IMAGETYPE_BMP:
echo "bmp";
break;
default:
break;
}
}
}
// close the directory
closedir( $dir );
}
createFixSizeImage("path","path/to/images/to/be/saved",100);
Extending more or less unknown code and then debugging it, is like you wrote some code weeks ago and you don't understand it any longer.
In your case you are extending some existing code (you have not posted the original code, but your wrote that you did it that way) by adding the feature of checking the image size.
So that you do not need to edit much of the (unknown but) working code, create the new feature as a function of it's own:
/**
* #param string $file
* #param int $with
* #param int $height
* #return bool|null true/false if image has that exact size, null on error.
*/
function image_has_size($file, $width, $height)
{
$result = getimagesize($file);
if ($count($result) < 2) {
return null;
}
list($file_width, $file_height) = $result;
return ($file_width == (int) $width)
&& ($file_height == (int) $height);
}
You now have the new functionality in a single function you can much more easily integrate into the original (hopefully otherwise working) code.
Usage:
$imageHasCorrectSize = image_has_size($tmp_name, 100, 100);
So whenever you change code, do it like a surgeon, keeping the cuts as small as possible.

PHP-GD Image re-size loses the quality of the image

I've made this piece of code, it will re-size images on the fly, if it can't find the requested image, and then stores it.
The only problem with this is that the output jpg image has a low quality.
I was wondering if there is something I need to change to improve the image quality.
if (isset($_GET['size'])) {
$size = $_GET['size'];
}
if (isset($_GET['name'])) {
$filename = $_GET['name'];
}
$filePath = "files/catalog/" . urldecode($filename);
// Content type
header('Content-Type: image/jpeg');
// Get new sizes
list($width, $height) = getimagesize($filePath);
if ($_GET["name"] && !$size) {
$newwidth = $width * $percent;
$newheight = $height * $percent;
} else if ($_GET["name"] && $size) {
switch ($size) {
case "thumbs":
$newwidth = 192;
$newheight = 248;
break;
case "large":
$newwidth = 425;
$newheight = 550;
break;
}
}
$resizedFileName = $filename;
$resizedFileName = str_replace(".jpg", "", $resizedFileName) . ".jpg";
$resizedFilePath = "files/catalog/" . urldecode($resizedFileName);
if (!file_exists($resizedFilePath)) {
// Load
$thumb = imagecreatetruecolor($newwidth, $newheight);
$source = imagecreatefromjpeg($filePath);
// Resize
imagecopyresized($thumb, $source, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
// Output
imagejpeg($thumb, $resizedFilePath);
//file_put_contents($, $binarydata);
$imageContent = file_get_contents($resizedFilePath);
echo $imageContent;
} else {
$imageContent = file_get_contents($resizedFilePath);
echo $imageContent;
}
Instead of imagecopyresized() you must use imagecopyresampled() and imagejpeg() function has third optional parameter and you can specify quality.
Probably because you are using imagejpeg() wrong, the second variable in the functions stands for the quality in percentage!
You want imagecopyresampled(). resize works by throwing away unecessary pixels. resampled() will average things out and produce much smoother results.

Categories