I am trying to write an android app that takes a picture and saves it to a server. The problem is that every picture I take is rotated with -90 degrees when saved on the server. Any idea how I can rotate the picture in php or why it ends up being rotated?
This is how my php file looks like:
<?php
$file_path = "photos/";
$img = $_REQUEST['base64'];
$name=$_REQUEST['ImageName'];
// Decode Image
$binary=base64_decode($img);
$success = file_put_contents($file_path.$name, $binary);
if($success === false) {
echo "Couldn't write file";
} else {
echo "Wrote $success bytes";
}
echo $name;
?>
It isn't a server side issue, every smartphone can apply a different orientation to the camera images.
When you receive the image you have to access to its metadata (exif data si the exact name) to verify its rotation and other properties. Then you should apply to the picture the transformations you need.
This should be a good startpoint to read exif data with PHP: http://php.net/manual/en/function.exif-read-data.php
Maybe it has something to do with image orientation.
Try this
$exif = exif_read_data($file_path.$name);
$ort = $exif['IFD0']['Orientation'];
switch($ort)
{
case 3: // 180 rotate left
$image->imagerotate($file_path.$name, 180, -1);
break;
case 6: // 90 rotate right
$image->imagerotate($file_path.$name, -90, -1);
break;
case 8: // 90 rotate left
$image->imagerotate($file_path.$name, 90, -1);
break;
}
Related
We have a feature that lets users upload images on a website, which can be from a desktop or taken from any cellphone. But from some phones like Iphone images taken vertically end up rotated the wrong way. We need them to be displayed correctly on any device when uploaded from any device.
I found some similar questions but their solution didn't seem to work completely. I need to either rotate them correctly in php as soon as they are uploaded:
if(isset($_FILES["submit_image"])) {
$target_dir = "uploads/images/";
$name = $_FILES['submit_image']['name'];
$size = $_FILES['submit_image']['size'];
$tmp_name = $_FILES['submit_image']['tmp_name'];
//make sure the image is roated correctly? I tried this code that I found in other SO questions but then it doesn't seem to be saving it
// START ORIENTATION FIX
$info = getimagesize($tmp_name);
$image = imagecreatefrompng($tmp_name);
if($info['mime'] == 'image/jpeg') {
$exif = exif_read_data($tmp_name);
if(isset($exif['Orientation'])) {
$orientation = $exif['Orientation'];
}
}
if(isset($orientation)) { //rotate to match the orientation
switch($orientation) {
case 3:
$image = imagerotate($image, 180, 0);
break;
case 6:
$image = imagerotate($image, -90, 0);
break;
case 8:
$image = imagerotate($image, 90, 0);
break;
}
}
if(isset($image)) { //get the variables of the rotated image
$tmp_name = $image["tmp_name"];
$name = $image['name'];
$size = $image['size'];
}
// END ORIENTATION FIX
/*doing some other checks here for image name, size, and mime type
...
*/
$path = calculate_file_path($target_dir, $name);
if (move_uploaded_file($tmp_name, $path) == true) {
$query = "UPDATE {$table} SET {$column} = '{$path}' WHERE id = {$new_pro_id}";
$result = mysqli_query($db, $query);
if ($result) {
//saved
}
else{
//failed
}
}
}
Or maybe fix them later with css whenever the site needs to display them:
.profile_img
{
image-orientation: from-image;
}
But neither seemed to work. the php option broke them completely, and the css option didn't fix the orientation.
EDIT
I get a warning/error message:
exif_read_data() expects parameter 1 to be a valid path, array given in...
But there is no file path anywhere at that point. All I have is $_FILES['submit_image'] which comes from a type="file" field in an html form. I'm sure this variable has all the information which would be in the file path because I use it later to save to the server.
Any ideas?
Thanks :)
I have a very strange problem.
On my website there is a file field that will allow the users to upload their profile picture.
It gets uploaded using JQuery and it gets saved using PHP.
If I upload from a PC / MAC / iPhone then there is no problem whatsoever, however if I upload using an Android device the image gets rotated.
The rotation is not even consistent, it could be 90% 180% or 270%, this happens when taking a image or selecting from the Gallery.
Why would this happen? and is there a possible fix?
This solved the issue
From the PHPDocs
<?php
$image = imagecreatefromstring(file_get_contents($_FILES['image_upload']['tmp_name']));
$exif = exif_read_data($_FILES['image_upload']['tmp_name']);
if(!empty($exif['Orientation'])) {
switch($exif['Orientation']) {
case 8:
$image = imagerotate($image,90,0);
break;
case 3:
$image = imagerotate($image,180,0);
break;
case 6:
$image = imagerotate($image,-90,0);
break;
}
}
// $image now contains a resource with the image oriented correctly
?>
thanks for taking the time to read this. I have a form with 35 file input boxes as part of a CMS for my customer to upload 35 pictures of each his products. The breakdown of that is 7 pictures of the black version, 7 pictures of the blue, 7 pictures of the grey, 7 pictures of the red, and 7 pictures of the white version of each product. So that's 35 total pictures he needs to upload. Additionally, for each of those files that he uploads, a smaller "thumbnail" sized picture needs to be made. I have a file upload script that I always use that works beautifully - when there's one file to upload. I'm not sure how to apply it in this case for 35 files. Each input box has a unique name (black1, black2...black7, blue1, blue2...blue7, etc) so, technically I could repeat the upload code 35 times with the unique name of each file input box to do this, but that is obvoiusly extremely inefficient. I'm hoping someone here can help me out with a better solution.
An additional requirement is that the names of the files be stored in a database. All of the filenames of the black pictures should be put into a string, separated by commas, and stored in the blackpics column of the database. All of the filenames of the blue pictures should be put into a string, separated by commas, and stored in the bluepics columns of the database. And so on for the grey, red, and white pictures.
Here is the code that I have now to upload one file. It gets the file from input box "file", checks that it's of the right extension (an image file), checks the filesize, creates a random file name with a random number and timestamp, creates a thumbnail (448px x 298px - big thumbnail, I know), checks that the original image uploaded was of the right dimensions (873px x 581px), and if everything is okay, I end up with the big file saved in ../images/store/big/ and the thumb saved in ../images/store/small/. They both have the same filename, they're just stored in different directories. Temporary files are deleted and all that, and if there are any errors, the files are deleted. As I said, this works great for one file.
So what I need to do is modify the code so that it does all of this for input box "black1", "black2"..."black7", then saves all the filenames into a string (black1.jpg,black2.jpg,black3.jpg,black4.jpg,black5.jpg,black6.jpg,black7.jpg) which I can then store in the 'blackpics' column of the database. Same for the blue, grey, red, and white. I don't need any help with the database part. I'm thinking that I need to create a function containing the file upload script that returns the filename. Then call that function 35 times, one for each of the input boxes. But I could be wrong.
If anyone could offer me any assistance, I would greatly appreciate it. Here is the code for the upload script:
<?php
$filename = $_FILES["file"]["name"];
$file_basename = substr($filename, 0, strripos($filename, '.')); // get file extention
$file_ext = substr($filename, strripos($filename, '.')); // get file name
$filesize = $_FILES["file"]["size"];
$allowed_file_types = array('.jpg','.gif','.png', '.JPG');
if (in_array($file_ext,$allowed_file_types) && ($filesize < 1024000)) {
// rename file
$rand = rand(1,100000000);
$time = time();
$newfilename = $rand . $time . $file_ext;
if (file_exists("../images/store/big/" . $newfilename)) {
// file already exists error
$err[] = "You have already uploaded this file.";
} else {
move_uploaded_file($_FILES["file"]["tmp_name"], "../images/store/big/" . $newfilename);
$pathToImage = '../images/store/big/' . $newfilename;
$pathToThumb = '../images/store/small/' . $newfilename;
$last4 = substr($pathToImage, -4);
switch(strtolower($last4)) {
case '.jpeg':
$img = imagecreatefromjpeg($pathToImage);
break;
case '.jpg':
$img = imagecreatefromjpeg($pathToImage);
break;
case '.png':
$img = imagecreatefrompng($pathToImage);
break;
case '.gif':
$img = imagecreatefromgif($pathToImage);
break;
default:
exit('Unsupported type: '. $pathToImage);
}
$max_width = 448;
$max_height = 298;
// Get current dimensions
$old_width = imagesx($img);
$old_height = imagesy($img);
// Calculate the scaling we need to do to fit the image inside our frame
$scale = min($max_width/$old_width, $max_height/$old_height);
// Get the new dimensions
$new_width = ceil($scale*$old_width);
$new_height = ceil($scale*$old_height);
$tmp_img = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $old_width, $old_height);
switch(strtolower($last4)) {
case '.jpeg':
imagejpeg($tmp_img, $pathToThumb);
break;
case '.jpg':
imagejpeg($tmp_img, $pathToThumb);
break;
case '.png':
imagepng($tmp_img, $pathToThumb);
break;
case '.gif':
imagegif($tmp_img, $pathToThumb);
break;
default:
exit('Unsupported type: '. $pathToImage);
}
imagedestroy($tmp_img);
imagedestroy($img);
}
} elseif (empty($file_basename)) {
$err[] = "Select a file to upload";
} elseif ($filesize > 1024000) {
$err[] = "File size limit exceeded";
} else {
$err[] = "File type not allowed";
unlink($_FILES["file"]["tmp_name"]);
}
list($width, $height) = getimagesize("../images/store/big/$newfilename");
if ($width != "873" || $height != "581") {
$err[] = "File dimensions error";
unlink("../images/store/big/$newfilename");
unlink("../images/store/small/$newfilename");
}
?>
And in the body I have the file upload fields as so...
<input type="file" name="black1" disabled="1">
<input type="file" name="black2" disabled="1">
...
<input type="file" name="black7" disabled="1">
<input type="file" name="blue1" disabled="1">
<input type="file" name="blue2" disabled="1">
...
<input type="file" name="blue7" disabled="1">
and so on for grey, red, and white.
Like I said, if anyone can help me out, I would greatly appreciate it. And if you made it all the way down here, thanks again for taking the time to read all of this.
First don't use dimensions for images. Dimensions do not say much about the size of the image. And the size matters for displaying the image on a website, not the dimensions.
Second why not use a multipart uploading form? See here. And then your client could select the images colourwise and upload them with one selection, which would reduce the clicks from 35 to seven. Or if you trust your client to be more tech-savvy: Use only one input field and instruct him to name his files in a specific way. Like "b_[name of file].[extension]" for a black image. Then use your favourite string searching method - for example RegEx - to identify the images classes.
I have a page while is used only for print, and some of the images on there are uploaded through a script I have. It seems to always reduce the image to 72 dpi, reguardless of what I set imagejpeg() and imagepng() to for quality.
I've used my own personal script and this one on git hub
https://github.com/maxim/smart_resize_image
I was hoping for a little guidance on preserving the dpi at the original 300dpi.
Here is my own personal script
if (!empty($_FILES['image']['name'])) //checking if file upload box contains a value
{
$saveDirectory = 'pics/'; //name of folder to upload to
$tempName = $_FILES['image']['tmp_name']; //getting the temp name on server
$fileName1 = $_FILES['image']['name']; //getting file name on users computer
$count = 1;
do{
$location = $saveDirectory . $_GET['section'] . $count . $fileName1;
$count++;
}while(is_file($location));
if (move_uploaded_file($tempName, $location)) //Moves the temp file on server
{ //to directory with real name
$image = $location;
// Get new sizes
list($width, $height, $type) = getimagesize($image); //gets information about new server image
$framewidth = 932;
$frameheight = 354;
$realwidth = $width; //setting original width and height
$realheight = $height;
// Load
$file1new = imagecreatetruecolor($framewidth, $frameheight); //creates all black image with target w/h
if($type == 2){
$source = imagecreatefromjpeg($image);
imagecopyresampled($file1new, $source , 0, 0, 0, 0, $framewidth, $frameheight, $realwidth, $realheight);
}
elseif($type == 3){
$source = imagecreatefrompng($image);
imagecopyresampled($file1new, $source , 0, 0, 0, 0, $framewidth, $frameheight, $realwidth, $realheight);
}
else{
echo "Wrong file type";
}
if($type == 2){
//creates jpeg image from file1new for file1 (also retains quality)
imagejpeg($file1new, $image,100);
//frees space
imagedestroy($file1new);
}
elseif($type == 3){
//creates png image from file1new for file1 (also retains quality)
imagepng($file1new, $image,10);
//frees space
imagedestroy($file1new);
}
else{
echo "Wrong file type";
}
}
else
{
echo '<h1> There was an error while uploading the file.</h1>';
}
}
}
Edit: Even if dpi isn't the answer, as I see jpgs in specific don't retain that information. I need some way of keeping these images very clear and crisp.
If you generate image and open with a browser, the browser will reduce it to 72dpi before rendering.
If you open with gimp/phptoshop/whatever image editor , it should preserve the same dpi quality.
Though on a screen, there is no difference since your screen is 72 dpi.
Not tested on new browsers, but it was like this in netscape and first firefox versions, I assume it has not changed since.
The function posted by lorezyra (at) lorezyra (dot) com here: http://www.php.net/manual/es/function.imagejpeg.php#85712 might do the trick.
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.