Prevent imagejpeg() from saving EXIF data for images (spec. FileDateTime) - php

Our server is saving EXIF data to every file saved with imagejpeg(). As far as I know, this is not the default behavior (or even possible, from what I've read). But, it is occurring, and due to the FileDateTime information being included (and using the time of save), it is breaking functionality in our upload/approval system (md5_file() returns a different value for the exact same image due to FileDateTime always being different).
Is there a way to prevent imagejpeg() from saving EXIF data for images by default?
Server Information
CentOS 5
Parallels Plesk Panel 10.4.4
GD Version: bundled (2.0.34 compatible)
PHP 5.3
Code
<?php
public function upload_book_cover($book, $cover, $filename = NULL, $approved = NULL){
global $c_consummo, $user;
$approved = bool($approved, true, true);
if(filesize($cover)>5242880){
return false; // Too large;
}
$max_width = 450;
$cover_info = getimagesize($cover);
if(!$this->is_valid_book_cover_type($cover_info['mime'])){
return false; // Invalid image type
}
$width = $cover_info[0];
$height = $cover_info[1];
if($width<200){
return false; // Too small
} elseif($width>1500){
return false; // Too wide
}
$original_cover = false;
switch($cover_info[2]){
case IMAGETYPE_GIF:
$original_cover = imagecreatefromgif($cover);
break;
case IMAGETYPE_JPEG:
$original_cover = imagecreatefromjpeg($cover);
break;
case IMAGETYPE_PNG:
$original_cover = imagecreatefrompng($cover);
break;
case IMAGETYPE_BMP:
$original_cover = imagecreatefrombmp($cover);
break;
}
if(!$original_cover){
return false; // Unsupported type
}
if($width>$max_width){
$new_width = $max_width;
} else {
$new_width = $width;
}
$new_height = round($height*($new_width/$width));
$new_cover = imagecreatetruecolor($new_width, $new_height);
if(!$new_cover){
return false; // Could not create true color image
}
if(!imagecopyresampled($new_cover, $original_cover, 0, 0, 0, 0, $new_width, $new_height, $width, $height)){
return false; // Could not copy image
}
if(!imagejpeg($new_cover, $cover, 100)){
return false; // Image could not be saved to tmp file
// This is adding *new* EXIF data to images by itself
}
$file_hash = md5_file($cover);
$duplicate_book_cover = $this->find_duplicate_book_cover($book, $file_hash);
if($duplicate_book_cover){
return $duplicate_book_cover;
}
$file_id = $c_consummo->upload_file($cover, $filename);
...
}

It looks like you have tried several things here, but lets try one more.
Do you EVER need EXIF information in your application?
If not lets take out support for EXIF and see if that completely removes it.
If it does not remove it, then perhaps the functions are reading it from the existing photos and then just blindly including it in the file that is written.
You can know for sure by printing out the EXIF information at each step of process

No idea why EXIF data is being written - so the following may help you remove it.
One suggestion is to run something as a command on the server - it will need some installation: http://hacktux.com/read/remove/exif - then run throuhg EXEC from PHP.
There's also solution posted here that uses ImageMagick if you also have that installed (or cen get it installed: Remove EXIF data from JPG using PHP (but note warning about colour)
Otherwise, the other suggestion is as above, try turning off the EXIT extension.
Sorry if they don't help, but you did ask for any suggestions.

Apparently, GD doesn't like when the path to the input / output file is the same, but the credit isn't mine. To fix, use a new (tmp) file to save the newly created image to:
<?php
...
if(!imagecopyresampled($new_cover, $original_cover, 0, 0, 0, 0, $new_width, $new_height, $width, $height)){
return false; // Could not copy image
}
// Create a tmp file.
$cover_new = tempnam('/tmp', 'cover-');
// Use $cover_new instead of $cover
if(!imagejpeg($new_cover, $cover_new, 100)){
return false; // Image could not be saved to tmp file
}
// Use $cover_new instead of $cover
$file_hash = md5_file($cover_new);
$duplicate_book_cover = $this->find_duplicate_book_cover($book, $file_hash);
if($duplicate_book_cover){
return $duplicate_book_cover;
}
// Use $cover_new instead of $cover
$file_id = $c_consummo->upload_file($cover_new, $filename);
...

Read this, maybe it will help:
http://www.php.net/manual/en/function.imagecreatefromjpeg.php#65656
and this:
http://www.sentex.net/~mwandel/jhead/usage.html

You could possibly convert the jpeg to a gif first, then convert the gif back to a jpeg. In doing so, my understanding is that you would destroy the EXIF data. It's a hack, but it should work.

The only thing that spring to mind is, that you could ignore the EXIF data and just make your hash from something else? My suggestion would be to try either hashing the raw output without saving to a file (here outputting in gif format -which makes a smaller, 8-bit image for performance- to an output buffer and hashing the buffer content)
if(!imagecopyresampled(...)) {...}
ob_start();
imagegif($new_cover);
$file_hash = md5(ob_get_contents());
ob_end_clean();
if(!imagejpeg($new_cover, $cover, 100)) {...}
Or you could build a string containing only the pixel information and hash that (here done by accessing each pixel and appending its value to a string, in reverse for performance)
$pixels = '';
for($x=$new_width-1; $x>=0; $x--) {
for($y=$new_height-1; $y>=0; $y--) {
$pixels .= imagecolorat($new_cover, $x, $y);
}
}
$file_hash = md5($pixels);
For performance, you could also choose only to take samples from the image, as this should work just as well or maybe even better (here sampling every 5th pixel of every 5th row)
$pixels = '';
for($x=$new_width-1; $x>=0; $x-=5) {
for($y=$new_height-1; $y>=0; $y-=5) {
$pixels .= imagecolorat($new_cover, $x, $y);
}
}
$file_hash = md5($pixels);
I hope some of this will work (as I can't test it right now) or at least will help you find the way that works for you :)

This is a bit of a hack, but it will work, just do this after your switch() statement:
$original_cover = imagerotate($original_cover,360,0);
GD will strip any EXIF data out, as it doesn't support it.

You could try using imagecreatefromjpeg on the image created with imagejpeg and replacing with the newly created one.

$res = imagecreatefromjpeg($filename) to load the image, then imagejpeg($res, $filename, QUALITY)to rerender it.
You can use imagemagick too:
$img = new Imagick($image);
$img->stripImage();
$img->writeImage($image);
$img->clear();
$img->destroy();

Your PHP must be compiled in with --enable-exif.
Try to disable globally EXIF functionality by recompiling PHP without this option.

Related

How to install small PHP scripts for tools into pages of an existing website?

First of all, I'm a physician and not a technical expert whatsoever like you, so please bear with me :D
I want to build a website that offers online tools like "email extracting", "image resizing", etc, and I was wondering how to install tools with small PHP scripts like 1-2 .php files, and have them on different pages in the existing website "internettoolkits.com"?
Other tools I found, have more folders and files and most videos talk about databases and playing with file managers, and for those, I decided to create a subdomain for each, following the advises of creating new database and updating the file manager since they have an admin and user areas. (according to my understanding)
But for the small ones that don't require admin and user areas, like email extracting tool, can I have the php scripts added to a page/post in wordpress like with using HTML scripts? I tried the HTML scripts and they work fine (you can see examples on that website)
Do I insert them in specific files in the file manager and how to do it to make it appear in a designated page called "Thumbnail Generator Tool" for example?
Do I need to create a specific database for each of those small tools or not?
I tried using plugins (code snippet) and (insert PHP code snippet) and both didn't work
Example of tool to have: Thumbnail generator tool that have 2 files below:
first file (image.class.php)
<?php
###############################################################
# Thumbnail Image Class for Thumbnail Generator
###############################################################
# For updates visit http://www.zubrag.com/scripts/
###############################################################
class Zubrag_image {
var $save_to_file = true;
var $image_type = -1;
var $quality = 100;
var $max_x = 100;
var $max_y = 100;
var $cut_x = 0;
var $cut_y = 0;
function SaveImage($im, $filename) {
$res = null;
// ImageGIF is not included into some GD2 releases, so it might not work
// output png if gifs are not supported
if(($this->image_type == 1) && !function_exists('imagegif')) $this->image_type = 3;
switch ($this->image_type) {
case 1:
if ($this->save_to_file) {
$res = ImageGIF($im,$filename);
}
else {
header("Content-type: image/gif");
$res = ImageGIF($im);
}
break;
case 2:
if ($this->save_to_file) {
$res = ImageJPEG($im,$filename,$this->quality);
}
else {
header("Content-type: image/jpeg");
$res = ImageJPEG($im, NULL, $this->quality);
}
break;
case 3:
if (PHP_VERSION >= '5.1.2') {
// Convert to PNG quality.
// PNG quality: 0 (best quality, bigger file) to 9 (worst quality, smaller file)
$quality = 9 - min( round($this->quality / 10), 9 );
if ($this->save_to_file) {
$res = ImagePNG($im, $filename, $quality);
}
else {
header("Content-type: image/png");
$res = ImagePNG($im, NULL, $quality);
}
}
else {
if ($this->save_to_file) {
$res = ImagePNG($im, $filename);
}
else {
header("Content-type: image/png");
$res = ImagePNG($im);
}
}
break;
}
return $res;
}
function ImageCreateFromType($type,$filename) {
$im = null;
switch ($type) {
case 1:
$im = ImageCreateFromGif($filename);
break;
case 2:
$im = ImageCreateFromJpeg($filename);
break;
case 3:
$im = ImageCreateFromPNG($filename);
break;
}
return $im;
}
// generate thumb from image and save it
function GenerateThumbFile($from_name, $to_name) {
// if src is URL then download file first
$temp = false;
if (substr($from_name,0,7) == 'http://') {
$tmpfname = tempnam("tmp/", "TmP-");
$temp = #fopen($tmpfname, "w");
if ($temp) {
#fwrite($temp, #file_get_contents($from_name)) or die("Cannot download image");
#fclose($temp);
$from_name = $tmpfname;
}
else {
die("Cannot create temp file");
}
}
// check if file exists
if (!file_exists($from_name)) die("Source image does not exist!");
// get source image size (width/height/type)
// orig_img_type 1 = GIF, 2 = JPG, 3 = PNG
list($orig_x, $orig_y, $orig_img_type, $img_sizes) = #GetImageSize($from_name);
// cut image if specified by user
if ($this->cut_x > 0) $orig_x = min($this->cut_x, $orig_x);
if ($this->cut_y > 0) $orig_y = min($this->cut_y, $orig_y);
// should we override thumb image type?
$this->image_type = ($this->image_type != -1 ? $this->image_type : $orig_img_type);
// check for allowed image types
if ($orig_img_type < 1 or $orig_img_type > 3) die("Image type not supported");
if ($orig_x > $this->max_x or $orig_y > $this->max_y) {
// resize
$per_x = $orig_x / $this->max_x;
$per_y = $orig_y / $this->max_y;
if ($per_y > $per_x) {
$this->max_x = $orig_x / $per_y;
}
else {
$this->max_y = $orig_y / $per_x;
}
}
else {
// keep original sizes, i.e. just copy
if ($this->save_to_file) {
#copy($from_name, $to_name);
}
else {
switch ($this->image_type) {
case 1:
header("Content-type: image/gif");
readfile($from_name);
break;
case 2:
header("Content-type: image/jpeg");
readfile($from_name);
break;
case 3:
header("Content-type: image/png");
readfile($from_name);
break;
}
}
return;
}
if ($this->image_type == 1) {
// should use this function for gifs (gifs are palette images)
$ni = imagecreate($this->max_x, $this->max_y);
}
else {
// Create a new true color image
$ni = ImageCreateTrueColor($this->max_x,$this->max_y);
}
// Fill image with white background (255,255,255)
$white = imagecolorallocate($ni, 255, 255, 255);
imagefilledrectangle( $ni, 0, 0, $this->max_x, $this->max_y, $white);
// Create a new image from source file
$im = $this->ImageCreateFromType($orig_img_type,$from_name);
// Copy the palette from one image to another
imagepalettecopy($ni,$im);
// Copy and resize part of an image with resampling
imagecopyresampled(
$ni, $im, // destination, source
0, 0, 0, 0, // dstX, dstY, srcX, srcY
$this->max_x, $this->max_y, // dstW, dstH
$orig_x, $orig_y); // srcW, srcH
// save thumb file
$this->SaveImage($ni, $to_name);
if($temp) {
unlink($tmpfname); // this removes the file
}
}
}
?>
Second file named (thumb.php)
<?php
###############################################################
# Thumbnail Image Generator 1.3
###############################################################
# Visit http://www.zubrag.com/scripts/ for updates
###############################################################
// REQUIREMENTS:
// PHP 4.0.6 and GD 2.0.1 or later
// May not work with GIFs if GD2 library installed on your server
// does not support GIF functions in full
// Parameters:
// src - path to source image
// dest - path to thumb (where to save it)
// x - max width
// y - max height
// q - quality (applicable only to JPG, 1 to 100, 100 - best)
// t - thumb type. "-1" - same as source, 1 = GIF, 2 = JPG, 3 = PNG
// f - save to file (1) or output to browser (0).
// Sample usage:
// 1. save thumb on server
// http://www.zubrag.com/thumb.php?src=test.jpg&dest=thumb.jpg&x=100&y=50
// 2. output thumb to browser
// http://www.zubrag.com/thumb.php?src=test.jpg&x=50&y=50&f=0
// Below are default values (if parameter is not passed)
// save to file (true) or output to browser (false)
$save_to_file = true;
// Quality for JPEG and PNG.
// 0 (worst quality, smaller file) to 100 (best quality, bigger file)
// Note: PNG quality is only supported starting PHP 5.1.2
$image_quality = 100;
// resulting image type (1 = GIF, 2 = JPG, 3 = PNG)
// enter code of the image type if you want override it
// or set it to -1 to determine automatically
$image_type = -1;
// maximum thumb side size
$max_x = 100;
$max_y = 100;
// cut image before resizing. Set to 0 to skip this.
$cut_x = 0;
$cut_y = 0;
// Folder where source images are stored (thumbnails will be generated from these images).
// MUST end with slash.
$images_folder = '/www/images/';
// Folder to save thumbnails, full path from the root folder, MUST end with slash.
// Only needed if you save generated thumbnails on the server.
// Sample for windows: c:/wwwroot/thumbs/
// Sample for unix/linux: /home/site.com/htdocs/thumbs/
$thumbs_folder = '/www/thumbs/';
///////////////////////////////////////////////////
/////////////// DO NOT EDIT BELOW
///////////////////////////////////////////////////
$to_name = '';
if (isset($_REQUEST['f'])) {
$save_to_file = intval($_REQUEST['f']) == 1;
}
if (isset($_REQUEST['src'])) {
$from_name = urldecode($_REQUEST['src']);
}
else {
die("Source file name must be specified.");
}
if (isset($_REQUEST['dest'])) {
$to_name = urldecode($_REQUEST['dest']);
}
else if ($save_to_file) {
die("Thumbnail file name must be specified.");
}
if (isset($_REQUEST['q'])) {
$image_quality = intval($_REQUEST['q']);
}
if (isset($_REQUEST['t'])) {
$image_type = intval($_REQUEST['t']);
}
if (isset($_REQUEST['x'])) {
$max_x = intval($_REQUEST['x']);
}
if (isset($_REQUEST['y'])) {
$max_y = intval($_REQUEST['y']);
}
if (!file_exists($images_folder)) die('Images folder does not exist (update $images_folder in the script)');
if ($save_to_file && !file_exists($thumbs_folder)) die('Thumbnails folder does not exist (update $thumbs_folder in the script)');
// Allocate all necessary memory for the image.
// Special thanks to Alecos for providing the code.
ini_set('memory_limit', '-1');
// include image processing code
include('image.class.php');
$img = new Zubrag_image;
// initialize
$img->max_x = $max_x;
$img->max_y = $max_y;
$img->cut_x = $cut_x;
$img->cut_y = $cut_y;
$img->quality = $image_quality;
$img->save_to_file = $save_to_file;
$img->image_type = $image_type;
// generate thumbnail
$img->GenerateThumbFile($images_folder . $from_name, $thumbs_folder . $to_name);
?>
This is not nearly as easy as you may think.
To answer your question:
I want to build a website that offers online tools like "email extracting", "image resizing", etc, and I was wondering how to install tools with small PHP scripts like 1-2 .php files, and have them on different pages in the existing website
For each tool you want to integrate, you will want to create a separate plugin. This plugin can be as simple as a single PHP file but I'm guessing they are going to be more complex.
Some of the plugins you create will need admin pages unless you are planning on running them just on your own website. In these cases, it's safe to use a config file and just set the needed options there. it's not ideal, but it is quicker than creating an admin page.
Yes, some of your plugins will need database access. You wouldn't create a new database just for them though. Whenever possible, work within WordPress' existing DB structure. You have a lot of different tools at your disposal for saving off options both permanently and temporarily. As a last option, you could create your own table in the database just for your plugins but I would not do that unless there is absolutely no way to use the existing structures.
For integrating them into pages, the easy way is to use short codes. The modern way is to use Gutenberg blocks. Blocks take more time to code but if you are planning on selling/distributing these tools, people will expect them. If you are just using these on your own, a short-code would probably suffice.
Sorry I don't have a better answer for you but honestly, what you are asking is a lot of work. (and I've not even touched on auditing the code for security issues before integrating it into your site!)
Cheers! :)
=C=

My php Watermark function is not working for png image

I am using a PHP function to add my logo as the watermark on images uploaded on my website. But I don't know why my watermark function is not working for png files. however, it works for jpeg files perfectly. this is my PHP function.
function watermark($img) {
global $wm_file, $wm_right, $wm_bottom;
// image values pulled from config.inc.php
$logo = './images/' . $wm_file; // path to the watermark.png
$sp = $wm_right; // spacing from right side
$sq = $wm_bottom; // spacing from bottom
$size = getImageSize($img);
$sizel = getImageSize($logo);
$imgA = imageCreateFromJpeg($img);
imageAlphaBlending($imgA, TRUE);
if($sizel[0] > $size[0] || $sizel[1] > $size[1])
{
// logo size > img size
$sizelo[0] = $sizel[0];
$sizelo[1] = $sizel[1];
$sizel[0] = ($sizel[0]/2);
$sizel[1] = ($sizel[1]/2);
}
else
{
$sizelo[0] = $sizel[0];
$sizelo[1] = $sizel[1];
}
$imgBa = imageCreateFromPng($logo);
$imgB = imageCreateTrueColor($sizel[0], $sizel[1]);
imageAlphaBlending($imgB, TRUE);
imageCopyResampled($imgB, $imgBa, 0, 0, 0, 0, $sizel[0], $sizel[1], $sizelo[0], $sizelo[1]);
imageColorTransparent($imgB, ImageColorAllocate($imgB, 0, 0, 0));
$perc = 100;
imageCopymerge($imgA, $imgB, ($size[0]-$sizel[0]-$sp), ($size[1]-$sizel[1]-$sq), 0, 0, $sizel[0], $sizel[1], $perc);
unlink($img);
if(imageJpeg($imgA, $img, 100))
{
imageDestroy($imgB);
imageDestroy($imgA);
return true;
}
chmod($img, 0777);
}
The problem I see is that you are using imageCreateFromJpeg() as the way to generate the resource for your $img that you are passing to the function.
If you pass a jpeg through the function it will work. If you pass a png it will not.
I recommend using imagecreatefromstring() to create all your resources as it is not dependent on the file type. Like so:
$source = imagecreatefromstring(file_get_contents($filePath));
Another benefit of this is that it will return false if the function fails to create a resource from the file path that you supplied meaning that the file is not an image file.
Now that you have a resource to use for the rest of your code, imageJpeg() will save the resource as a jpeg back to the file path.
Hope that helps.
One other side note. If you intend on using bmp images, the GD library does not have a built in function for bmps. However on PHP.net, someone did write a createimagefromBMP() that works really well. Also I think that on the latest version of PHP the GD library does now actually have a createimagefromBMP() function.
I also see that you are using unlink() to delete the image from your directory. This is not necessary for two reasons. The imageJpeg() will just overwrite the original. Also, if for some reason your script fails it may delete the image prematurely and you will loose the image without the new one being written.
Please be careful when using chmod(), always make sure that you set permissions back to the original permissions when you are done.
chmod($img, 777); //Give broad permissions.
//Do something.
chmod($img, 600(or whatever they were)); //Reset permission back to where they were before you changed them.

PHP imagecopyresampled() can't seem to output result

I'm trying to read a directory of .jpg files from a folder ./gallery/, make them a bit smaller, and then save them back to ./gallery/_thumbs/.
Everything seems to work up until I try to use the imagecopyresampled() to actually do the resizing. The PHP man says it should return a bool on success/failure, but I'm able to get anything and hence don't know what I'm doing wrong.
I'm assuming that if I get a valid result from imagecopyresampled() that the imagejpeg() will work okay the way I have it?
for($i=0;$files_in_dir[$i]!=null;$i++)
{
if (!($files_in_dir[$i]=="."||$files_in_dir[$i]==".."||$files_in_dir[$i]=="_thumb"))
{
$my_images['image_name']=$files_in_dir[$i];
$my_images['path_to_current']=$directory.$my_images['image_name'];
$my_images['path_to_finished_thumb']=$directory.$sub_directory.$prefix.$my_images['image_name'];
$my_images['image_handler']=imagecreatefromjpeg($my_images['path_to_current']);
$imagesize = getimagesize($my_images['path_to_current']);
$my_images['width']=$imagesize[0];
$my_images['height']=$imagesize[1];
$my_images['ratio']=$my_images['height']/$my_images['width'];
$my_height = round($my_width / $ratio);
echo "<pre>";
var_dump($my_images);
$newImage = imagecreatetruecolor($my_width,$my_height);
$success = imagecopyresampled($newImage,$my_images['image_handler'],0,0,0,0,$my_width,$my_height,$my_images['width'],$my_images['height']);
echo "my success was: ",$success,"<br />";
imagejpeg($newImage,$my_images['path_to_finished_thumb'],80);
imagedestroy($my_images['image_handler']);
imagedestroy($newImage);
echo "</pre>";
}
}
?>
There are a couple things to come to mind.
First, check to make sure PHP is able to write to the files and directories in question.
Make sure you're seeing all errors/warnings so you know when something fails.
From your report it certainly sounds like your copy of PHP has the GD extension installed, but do make sure before you assume that extension-based functions like imagejpeg() are available. You can use a page containing <?php phpinfo(); to determine this yourself, or you can do it programmatically using function_exists().
I've taken the liberty of streamlining your script to make it easier to catch possible bugs (fewer lines = fewer possible mistakes):
<?php
// Make sure we see processing errors during development/testing.
error_reporting(E_ALL);
ini_set('display_errors', true);
// Set up operating parameters.
$filePattern = 'gallery/*.[jJ][pP][gG]';
$thumbPattern = 'thumbs/%s';
$targetWidth = 200;
$targetQuality = 80;
// Create the output dir, if it doesn't already exist. This will fail
// if PHP does not have write access to the local folder.
$thumbDir = sprintf($thumbPattern, '');
if (!is_dir($thumbDir)) {
mkdir($thumbDir);
}
// Abort if GD is not installed.
if (!function_exists('imagejpeg')) {
die('PHP does not have the GD extension installed. Aborting.');
}
// Abort if the output directory is not writable.
if (!is_writable($thumbDir)) {
die('The output directory is not writable by PHP. Check permissions. Aborting.');
}
// Loop over all found jpg files.
foreach (new GlobIterator($filePattern) as $f) {
// var_dump($f->getRealpath()); // Debugging the path name.
// Skip regenerating cached thumbs for performance.
$thumbPath = sprintf($thumbPattern, $f->getFilename());
if (file_exists($thumbPath)) {
continue;
}
// Determine thumbnail output size.
list($w, $h) = getimagesize($f->getRealpath());
$ratio = $h / $w;
$targetHeight = round($targetWidth * $ratio);
// Generate the thumbnail from the original.
$jpg = imagecreatefromjpeg($f->getRealpath());
$thumb = imagecreatetruecolor($targetWidth, $targetHeight);
$success = imagecopyresampled(
$thumb,
$jpg,
0, 0, 0, 0,
$targetWidth, $targetHeight, $w, $h
);
imagejpeg($thumb, $thumbPath, $targetQuality);
}
(Gist version here.)
One thing I caught during this process was that the logic for determining the thumbnail ratio was reversed. It needs to be $targetWidth * $ratio (instead of $targetWidth / $ratio).
This version of the script doesn't do the same naming manipulation-- it just creates a new thumbs/ folder wherever the script lives and saves the thumbnail versions from gallery/ into it.

Images rotate automatically

I have a iPhone app that uploads pictures to my server. One major issue I am having is a rotating one.
For some reason if I upload a picture from my iPhone, some pictures will automatically rotate. The one's that do get rotated are the ones in portrait mode. I have no code in my script that rotates the images.
How does a server exactly process tall images? Should I modify my php file to check to rotate it ahead after it automatically rotates? Should I code something in my iPhone app that will check this?
Any help is appreciated!
PS: If you need code, feel free to ask!
Some pictures(jpg) have exif data that tells the position the camera was when the picture was shot.
Take a look at http://www.php.net/manual/en/function.exif-read-data.php#76964
You may rotate the pictures server-side like this
Or a better way is to use this library
https://github.com/Intervention/image
And simply use like this-
$img = Image::make('foo.jpg')->orientate();
More can be found here.
When you take a picture your phone saves any rotation metadata in EXIF headers. When you upload the image to your server, that metadata is still sitting there but it's your job to apply it to the image to rotate it (if you want). In PHP you can use a function called exif_read_data:
function correctImageOrientation($filename)
{
$exif = exif_read_data($filename);
if ($exif && isset($exif['Orientation'])) {
$orientation = $exif['Orientation'];
if ($orientation != 1) {
$img = imagecreatefromjpeg($filename);
$deg = 0;
switch ($orientation) {
case 3:
$deg = 180;
break;
case 6:
$deg = 270;
break;
case 8:
$deg = 90;
break;
}
if ($deg) {
$img = imagerotate($img, $deg, 0);
}
imagejpeg($img, $filename, 95);
}
}
}
To use it simply call the function after you save the file. For more info and an additional PHP solution see the original source.

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.

Categories