How to remove exif from a JPG without losing image quality? - php

I have a PHP photo sharing application in which user-uploaded images are resized into various thumb formats using ImageMagick.
As a seemingly "smart" way to save on file size, I am stripping exif info from these thumbs as follow:
$imagick = new Imagick($image);
$imagick->stripImage();
$imagick->writeImage($image);
This works. It does remove the EXIF info, where a thumbs of 30KB saves 12KB and becomes 18KB. A significant saving when showing many of such thumbs on a single page.
The problem however is that it works a little too well. The resulting images seem to lose a lot of color information and look "flat" compared to their non-stripped versions.
Based on my research so far, my theory is that one or both of the following is true:
Imagick throws away essential color profile information as part of the stripping process
Imagick recompresses the image upon saving it, losing quality
Regardless of the cause of the problem, I'm looking for a way to remove EXIF information in such a way that it does not affect the image quality or color itself.
Is this even possible?
Update:
Based on Gerald Schneider's answer, I tried enforcing the quality setting to 100% prior to "stripping" the image:
$imagick = new Imagick($image);
$imagick->setCompression(imagick::COMPRESSION_JPEG);
$imagick->setCompressionQuality(100);
$imagick->stripImage();
$imagick->writeImage($image);
Unfortunately, the problem remains. Below is example output where despite setting the quality to 100%, images are still flattened.

Consider keeping the ICC profile (which causes richer colors) while removing all other EXIF data:
Extract the ICC profile
Strip EXIF data and image profile
Add the ICC profile back
In PHP + imagick:
$profiles = $img->getImageProfiles("icc", true);
$img->stripImage();
if(!empty($profiles))
$img->profileImage("icc", $profiles['icc']);
(Important note: using the ImageMagick 3.1.0 beta, the result I got from getImageProfiles() was slightly different from the documentation. I'd advise playing around with the parameters until you get an associative array with the actual profile(s).)
For command line ImageMagick:
convert image.jpg profile.icm
convert image.jpg -strip -profile profile.icm output.jpg
Images will get recompressed of course if you use ImageMagick, but at least colors stay intact.
Hope this helps.

Having made similar changes to MIME types in file headers that were incorrectly stored, I'd suggest you verify the length of the EXIF data via the standard tools, and then "Zero" the data manually using multibyte string functions.
EXIF can only be a maximum of 64KB in a JPEG file, however I'm not positive if it's exacly 64KB, so I would begin with this.

GIMP (another opensource image editor) also allows to remove EXIF, IPTC, XMP, thumbnail, ICC (color profile), etc meta data without loosing image/picture quality.
After opening the image in GIMP, Choose "Export" / "Export As" etc option, then select/unselect what meta data you want to remove/keep.
To keep original image quality you must select (tick mark) the option "Use quality settings from original image", which is shown under the "Quality" sliding-bar in top.
I usually like to keep ICC (save color profile meta data) option selected, to keep good color quality, with a colored photo.
Other options (Save EXIF, Save IPTC, Save XMP, Save thumbnail, etc) i usually unselect.
More info: here.

Related

How can I resize an image then centralize it with a white background? Can it be done using php-Imagine library?

The effect I would like to generate is exactly like the example in
this StackOverflow thread: (Related Question)
1.Resize image
2.Keep proportion
3.Add or Fill none-image areas with white background
Here are three examples of this process below:
1. If original is square no matter 640*640 or 1024*1024, just resize it to target dimension e.g. 480*480 will work.
If the original input is vertical rectangular,the output should not be cropped
and still be centerlized as below (the red dash edge marker is just make it easier to see the background is white and the proportion is kept after image resized to 480*480 px)
if the original input is horizontal rectangular, output like below, white background, keeps proportion and image uncroped , thus without losing anything after the image processing.
So after I've clarified such a question,
I would like to know:
Is there a general name of such Custom Image Resize mentioned above?
would like to know how to achieve it using php image library Imagine?
is it doable using php-imagine, or have to switch to another library, e.g imagemagick?
P.S. If you would like to achieve the effect either in image-resizing or video resizing, you can use below FFMPEG single-line command.
(thanks to #Mulvya, yes below code applies both to videos and image formats)
[run below built-in code in ffmpeg console to achieve the mentioned resize effect]
[video resize]
ffmpeg -i "[raw video url or videofile location.mp4]" -vf "scale=iw*min(480/iw\,480/ih):ih*min(480/iw\,480/ih),pad=480:480:(480-iw)/2:(480-ih)/2:color=white" [save_path_and_filename].mp4
[image resize]
ffmpeg -i "[raw image url or imagefile location.jpg]" -vf "scale=iw*min(480/iw\,480/ih):ih*min(480/iw\,480/ih),pad=480:480:(480-iw)/2:(480-ih)/2:color=white" [save_path_and_filename].jpg
Sorry i don'T have full answer for you and it's too long for a comment, but this can be done natively using some maths and php's http://php.net/manual/en/ref.image.php
Check in the area of imagecopyresize() imageecreate() imagescale and so on. It a pretty complex lib so you will have to do some try and mistake to get where you want to go.
From experience you can:
create an empty image, imagecreatetruecolor()
change background color to white
take a scetion of an image and paste it in the new created image using imagecopyresample() imagecopyresize()
export this image ans gif, png, jpg. imagepng(), imagejpg().
add watermark
and ALOT more.
Sorry i don'T have a more complete answer but depending on your need it can take a few mitues/hours to make it perfect. have fun.
On top of it, if you know ffmpeg, you can make both work together and make awesome media outputs. Cheers to you

Jquery mobile orientation uploaded photo

I'm trying to upload some photo from a mobile using jquery mobile and php but after uploading my photo it's always in landscape format even if my photo is in portrait format on my iphone !
So i can't know which one must be rotated or no .
Thanks
I had this same problem. My solution was a little quick and dirty but here you go:
Write a function to be called when the image loads, check to see if the image is going to rendered in landscape.
$(".imgTile").load(function(){
if(this.width>this.height){
$(this).css("transform","rotate(90deg)");
$(this).css("top",".7em");
$(this).css("left","-.5em");
}
}
A couple notes: I found I had to do some repositioning to get the rotated image to fit properly into the listview (hence the setting of top and left properties) so you may need to tweak this for your needs. Second, there are different css "transform" properties for different browsers, so you may need to set each to have cross browser support. Here's a guide on those properties http://www.w3schools.com/cssref/css3_pr_transform.asp
EDIT: I took some time and came up with a much more solid solution.
First, use php to read the exif tags:
$exif=exif_read_data("uploads/$fileExtension.jpg",0,true);
$orient=$exif["IFD0"]["Orientation"];
Some research into the EXIF standard reveals that the three cases that the iPhone will generate are:
1-- requires no rotation
3-- requires 180 deg. rotation
6-- required 90 deg. rotation
Then use php's shell_exec to run the following shell script, which uses imagemagick to destroy the EXIF headers, and physically rotates the image the specified amount:
#!/bin/bash
for i in $[filename]
do convert -rotate $[number of degrees] $i $i
done
mogrify -strip $[filename]
Now, the image will be correctly oriented everywhere, and browsers that do read EXIF headers won't show it any differently.
The only thing left to do is execute the script with the correct arguments based on the tag value.
Hope this helps!

php watermarking causes much bigger files

I used a 3rdparty image merging watermarking script to watermark some images, though it did the job as it should the result was the kind of disastrous the folder/dir size went from 3GB to 9GB.
So I was thinking that regular watermarking would be a better option rather then image overlaying, but I can't seem to find anything about wm backgrounds only text, what I want is a white section overlay at the bottom of each image and text inside that section, basically like 9gag.com but on top of image rather then below.
example:
The problem is likely the output settings. Watermarking itself should not add to the process, however when generating a "new" image, there's a good chance the optimization/compression settings weren't the same as the original image (setting it as anything lower than the original image won't gain any quality since the information is already lost, so keep it the same or set it higher).

php: Storing images in database

Currently i am using gd to converting the image uploaded in jpg with
imagjpeg($data,NULL,85)
and storing it in a blob mysql field. Problem is the quality. Yes the quality is just awful. A screenshot of a window with some text inside becomes pretty hugly. (While with a game screenshot the quality is passable)
Should I use other lib than GD?
Should I use other gd format? (imagepng?)
ps. please note: this is not a duplicate.. i am not asking how to save an img to db
ps2. note that if i should change my currently format/method I have to convert something like 5000-6000 images already stored as jpg in my db
ps3. i use 85 for imagejpeg, can't use a higher value because the image size would grow more than the original version
ps4. I need to store image in db, please stay in topic
Thanks all
================================
REFORMULATING THE QUESTION
I save image (mostly software screenshots, sometime games screenshots) in BLOB field after doing an imagejpeg($resourceFromImageCreateFromString,NULL,85);
Problem I am experiencing is the image uploaded looks pretty bad in confront of the original even if it's the same size. (sometime it gets bigger because of 85)
Is the imagejpeg implementations that sucks?
ps. my simple upload script does the follow calls:
upload file
open it with "rb" (binary)
pass the data to imagecreatefromstring
pass the result to imagejpeg
Thanks again
Is there a special reason you want to store your image inside a BLOB?
What quality argument did you pass to imagejpeg()?
You can set the quality of your output with the 3rd parameter to imagejpeg(). The problem is that JPEG is not the best format for images with a lot of text - you have to choose between turning down the quality and getting a lot of artifacts in your image, or turning up the quality and having a large file size. You might consider using PNG instead.
my first recommendation would be to try saving it as a png as the quality is better.
my second recommendation is to try the quality parameter in imagejpeg($image, $filename, $quality).
recommendation #3 - I worked on a site that I had to rewrite the image storage system because they implemented just what you are doing, storing images as BLOBs in the database. Their system only had about 20K images in it and it was crashing weekly because the database could not handle the load.
The conversion process for 5-6K images should not take more than a couple hours no matter how large the images. When I converted my images to disk storage from db storage, I ran 1K images at a time and each run took 5-10 minutes.
Why do you re-code anyway if it already IS a jpeg? To save space? Well, but then you already have your answer, in part - to save space from jpg to jpg you have to save in lower quality.
You cannot specify quality with imagecopyresampled, with imagejpeg you can. Use a high(er) value for the quality parameter.
Please note that JPEG is a format optimized for storing FOTOS. Images with large areas of the same color, straight lines etc. are much better stored in a lossless format like PNG. Of course, if you have a screenshot taken from a screen with fotos as desk background you have elements of both - so choose your format according to what you want. If the foto-part is more important and you don't care as much about fonts and lines, go with jpeg. Of course JPEG can be just as good quality as PNG for screenshots as well, but then you miss out on most of its compression capabilities, you have to use a 90+% quality setting. At 100% JPEG too is lossless, but by then a PNG might actually be of smaller (file)size.

Using PEL (PHP EXIF Library), is there a way to remove the embedded thumbnail from an image's EXIF data?

I am working on a project that resizes images using PHP. This project utilizes PEL to copy EXIF data from the source image to the resized image. However, when resizing images to be really small, the embedded EXIF data contains a thumbnail that is actually much larger than the resized image itself. I would love to use PEL to remove this thumbnail from the EXIF data while keeping all of the other goodies. Any ideas?
I'm sure there are other ways but the simplest way I can see from here is to read the file in using GD, output a new image and copy the EXIF across. This is by no means a simple process but if you're already doing resizing, it would make some sense.
PEL is a bit stale. If you're doing this on any real scale, you might want to look at playing around with some simple Python scripting. You have access to much better graphics and EXIF libraries and you can cron the script to run on a set period... Though I admit this might not suit your website's image processing flow.
You would need to use an image processing library, imagemagik (imagik) or gmagik would work.
Basically you would grab all of the info you wanted via exif then use $image -> stripimage() to remove ALL the meta-data, including the thumbnail, then use gmagic again to take the data you pulled out via exif to add it back in. ($image -> commentimage for example).
The only catch is that none of the documentation specifies whether the image will be re-added as exif, or some other meta-data type.

Categories