When I use the GD image library the orientation EXIF data is missing, is it possible to get the data straight from the raw data string before I use imagecreatefromstring() to make the jpg file? The orientation data is there because when I look at the email in gmail in chrome it shows the proper orientation, but as soon as I download the image that data is lost. I also tried using exif_thumbnail to see if I could figure out the orientation from that but the thumbnail is missing too.
If I download the attachment through chrome, windows image viewer displays it as landscape, but if I upload it to flickr it is displayed portrait, what is flickr using to determine orientation?
EDIT: solved it
createimagefromstring strips out a ton of meta data from the image file, but using fwrite creates the file verbatim from the data string, so I did this
$filename = 'pic.jpg';
$r = fopen($filename,'x');
fwrite($r,$raw_data); //$raw_data is the data string of the image
fclose($r);
and voila all the exif data was there! Stupid GD library! >:(
If you're really using the GD library like you say you are, you can leverage getimagesize() to check for the image's dimensions. If the width is greater than the height of the image, you can safely assume that it was taken in landscape mode.
$params = getimagesize($image);
$width = $params[0];
$height = $params[1];
if ($width > $height) {
$mode = "landscape";
} else if ($width < $height) {
$mode = "portrait";
}
Related
I use a PHP script that uploads an image, then gets the dimensions with PHP's getImageSize() and then does things to the image according to the pictures orientation (portrait or landscape).
However (PHP version 5.4.12) on some .jpg files it gets the height and width as they are, and in some (taken with an iPhone) it swaps them, thinking the portrait pictures are actually landscape.
It does not only happen on my local Wampserver, but also on a remote server (with a different PHP version).
Has anyone a clue how
1) to repair this or
2) find a way around the problem?
Some cameras include an orientation tag within the metadata section of the file itself. This is so the device itself can show it in the correct orientation every time regardless of the picture's orientation in its raw data.
It seems like Windows doesn't support reading this orientation tag and instead just reads the pixel data and displays it as-is.
A solution would be to either change the orientation tag in afflicted pictures' metadata on a per-image basis, OR
Use PHP's exif_read_data() function to read the orientation and orient your image accordingly like so:
<?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
?>
References:
https://stackoverflow.com/a/10601175/1124793 (research as to why this is happening)
http://php.net/manual/en/function.exif-read-data.php#110894 (PHP Code)
Function getimagesize() changes width and height in photos that are landscape orientation (horizontal) .
You can use this code:
<?php
$img = "test.jpg";
$exif = exif_read_data($img);
if(empty($exif['Orientation'])) {
list($width, $height, $type, $attr) = getimagesize($img);
}else{
list($height, $width, $type, $attr) = getimagesize($img);
}
?>
But it was fixed automatically in PHP7 and above.
been trying to detect the image orientation of uploaded images from iPhones and then adjust their orientation from that.
I am trying to fix the issue where images taken in potrait, are uploaded with a -90 degree rotate. I tried numerous switch statements which were not working, so decided to return the exif data in my JSON return.
The issue i see is that their is no orientation in the exif data.
I am doing so:
$imagefile = $fileToUpload["tmp_name"];
$destinationImage = imagecreatefromstring(file_get_contents($imagefile));
$exif = exif_read_data($imagefile);
$moveUploadedFile = imagejpeg($destinationImage, $this->uploadDir . "/" . $newFileName, 100);
imagedestroy($destinationImage);
if ($moveUploadedFile) {
$return['ort'] = $exif;
echo json_encode($return);
}
What i am seeing in my return (using firebug) is:
FileName:"phpUQZFHh"
FileDateTime:1410465904
FileSize:473421
FileType:2
MimeType:"image/jpeg"
SectionsFound:"COMMENT"
Computed: OBJECT:
Height:700
Width:933
IsColor:1
Comment: ARRAY:
0:"CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 100"
I want to be able use the exif data like so:
if (!empty($exif['Orientation'])){
//get the orientation
$ort = $exif['Orientation'];
//determine what oreientation the image was taken at
switch($ort){
case 2: // horizontal flip
break;
case 3: // 180 rotate left
$destinationImage = imagerotate($destinationImage, 180, -1);
break;
}
}
Any help?
EDIT: After downloaded an image that had been uploaded and checking its properties it appears that all exif data was removed in the upload process.
This still baffles me as to why it is rotated before / during upload / how to fix this.
I guess the "Orientation" value presents in the returned data of exif_read_data function in case when you upload the picture from your iOS device only. It won't work in desktop browser. I might be wrong.
I ran into the same problem. Turns out some images really did not have any exif data on Orientation at all -- usually ones with the "correct" orientation do not have it. I tried one landscape image taken with an iPhone and there was.
In your case, the photos may have had no exif data in the first place. I had some photos like that as well (rotated -90 degrees but no Orientation info). I could be wrong but without exif data, there's no programmatic way to know if an image is incorrectly oriented.
For incorrectly oriented photos without Orientation info, I suggest you just make sure the user sees (gets a preview) of what about to be uploaded. IME, most users are more than willing to get out of their way to fire up paint/photoshop/etc. just to ensure they have good looking photos.
You can get Orientation value before move the file to the server directory (Worked with iPhone as well)
$image = $_FILES["image"]["tmp_name"];
$orientation = '';
if (function_exists('exif_read_data'))
{
$exif = exif_read_data(image);
if($exif && isset($exif['Orientation']))
$orientation = $exif['Orientation'];
}
Short version
When I try to run file_get_contents() with this link, 'http://s1.reutersmedia.net/resources/r/?m=02&d=20131205&t=2&i=817503382&w=&fh=&fw=&ll=700&pl=378&r=CBRE9B401AG00', it returns: "illegal: d - msg". Why is it that file_get_contents() works on most image link but not this one, and how can I make it work?
Details
Part of my webapp's functionality is to parse external html files for images, then allow the user to select a desired image, and automatically save a reduced-size version of the image to my server. My code works for 99% of cases, but for the remaining 1% I am unable to successfully get the image file onto my server in order to re-size it. The cases that don't work seem to all involve html elements with 'src' attributes that look like this:
http://s1.reutersmedia.net/resources/r/?m=02&d=20131205&t=2&i=817503382&w=&fh=&fw=&ll=580&pl=378&r=CBRE9B401AG00
as opposed to a more standard image path such as this:
http://www.wired.com/images_blogs/wiredscience/2013/12/keyes-wd.jpg
Below is the code that I use in order to get and save the external image once the user has selected it, where the variable $newFileName is equal to an img path string such as the ones pasted above:
$contentOrFalseOnFailure = file_get_contents($newFileName);
$byteCountOrFalseOnFailure = file_put_contents($filenameOut, $contentOrFalseOnFailure);
$fileName = basename($newFileName);
$fileTmpLoc = $filenameOut;
$fileSize = $byteCountOrFalseOnFailure;
$fileExt = pathinfo($fileTmpLoc, PATHINFO_EXTENSION);
list($width, $height) = getimagesize($fileTmpLoc);
if($width < 10 || $height < 10){
header("location: ../message.php?msg=ERROR: That image has no dimensions");
exit();
}
When the src is non-standard, the script doesn't make it beyond this point, ie i get the "That image has no dimestions" error. What can I do to save save these non-standard images?
If you're interested in JUST the image dimensions and nothing else about it, you could go with GD's imagecreatefromstring() without needing a temp on-disk file:
$img = file_get_contents($url);
$gd = imagecreatefromstring($img);
$width = imagesx($gd);
$height = imagesy($gd);
This has the downside of having to decompress the image into memory, however. You'd have to hope that the remote server doesn't sent over a ludicriously dimensioned image that doesn't exceed the PHP memory_limit upon decompression.
Ignore the URL, look at the Content-Type header in the response.
While resizing an image, I have noticed that Imagick and Gmagick produce images with different filesize on HDD with the same options:
$image = new Imagick("c.jpg");
$image->thumbnailImage(260,195);
$image->writeImage("c_imagick.jpg");
outputs an Image with 88kb
$image = new Gmagick("c.jpg");
$image->thumbnailImage(260,195);
$image->writeImage("c_gmagick.jpg");
outputs an Image with 15kb
Does someone have any idea, why the difference is so huge?
Try setting the image compression settings prior to resizing.
$image->setImageCompression(Imagick::COMPRESSION_JPEG);
$image->setImageCompressionQuality(80);
Additionally, check the size of the resulting image. Comments in the PHP documentation lead me to believe that the automatic fit portion of thumbnailImage does not work as you would expect in IMagick.
From PHP Docs:
The fit functionality of thumbnailImage doesn't work as one would anticipate. Instead, use >this to make a thumbnail that has max of 200x82:
// Create thumbnail max of 200x82
$width=$im->getImageWidth();
if ($width > 200) { $im->thumbnailImage(200,null,0); }
$height=$im->getImageHeight();
if ($height > 82) { $im->thumbnailImage(null,82,0); }
I am trying to build a class that does many photo operations, one method will upload images from a user but I am also needing to build a method to grab a photo from a URL and run other methods on it just like if it were being uploaded with a POST form from user.
Below is my start of the function for getting image from URL, it works but needs work still. Below the code you can see a image that is the result of this function being ran. Also is the original image to see what it should look like. You can see that this function makes the image have a black background on this transparent image. How can I make it look better like it should look?
$url = 'http://a0.twimg.com/a/1262802780/images/twitter_logo_header.png';
//run our function
savePhotofromURL($url, 'no');
// photo function should grab an photo from a URL
function savePhotofromURL($photo_url, $saveimage = 'yes'){
if(isset($photo_url) && $photo_url != '') {
//get info about photo
$photo_info = getimagesize($photo_url);
$source_width = $photo_info['0'];
$source_height = $photo_info['1'];
$source_type = $photo_info['mime'];
//grab the Photo from URL
$photo = imagecreatefromstring(file_get_contents($photo_url));
if (is_resource($photo) === true){
if($saveimage === 'yes'){
// TO DO: resize image and make the thumbs code would go here if we are saving image:
// TO DO: resize source image if it is wider then 800 pixels
// TO DO: make 1 thumbnail that is 150 pixels wide
}else{
// We are not saving the image show it in the user's browser
// TO DO: we will add in correct photo type soon
header('Content-Type: image/gif');
imagejpeg($photo, null, 100);
imagedestroy($photo);
}
}else{
// not a valid resource, show error
echo 'error getting URL photo from ' .$photo_url;
}
}else{
// url of image was empty
echo 'The URL was not passed into our function';
}
}
The result looks like this
alt text http://img2.pict.com/52/05/1f/2429493/0/screenshot2b181.png
Instead of like this
The following two calls will tell php to use the alpha blending present in the png image:
ImageAlphaBlending($photo, false);
ImageSaveAlpha($photo, true);
Edit:
I see you're outputting the image as a JPEG also. JPEGs don't support transparency, so no matter what you do you will end up with an incorrect background color. Also see this related question: PHP/GD ImageSaveAlpha and ImageAlphaBlending
You need to add better support for image types and by extension their transparency.
Since the image is transparent we can know that its either a GIF or a PNG yet your sending the GIF header while using imagejpeg() - jpegs dont support any kind of transparency. But if its a png you may also have to account for if its alpha trans or index transparency.