Where exactly is the DPI information of an image stored (other than Exif)? - python-imaging-library

We have been using a program called Onyx RIPCenter to manage poster printing for few years now. The images were generated using Photoshop and loaded onto the Onyx application on Windows.
Recently we dedcied to automate the workflow by eliminating Photoshop and automatically processing the images through a custom application built in python (using pillow python - https://pillow.readthedocs.io/en/latest/)
Now the problem I have is that when I open the images created through the custom application in RIPCenter, I get wrong sizes in millimetre.
The actual size of the image is,
924mm x 2108mm
instead I get,
2309.99mm x 5269.79mm
The reason for this is the wrong DPI read by the application, instead of 180, it reads 72 (actual size in pixels - 6548 x 14938).
The custom application does set all relevant information to the Exif data including DPI. This can be verified by checking the property of the image file in Windows. But somehow when opening the image in RIPCenter, it shows the wrong DPI value.
Here is the code that saves the image.
def save_image(modified_image, image_file, source_image):
"""
Store the processed image into a file
:param modified_image: <Obj> modified image object
:param image_file: <String> output filename
:param source_image: <Obj> original image object
:return: <Boolean> True if saved
"""
# fix Onyx printer error
# https://media.readthedocs.org/pdf/piexif/latest/piexif.pdf
exif_dict = piexif.load(source_image.info["exif"])
exif_dict["0th"][piexif.ImageIFD.XResolution] = (180.0, 1)
exif_dict["0th"][piexif.ImageIFD.YResolution] = (180.0, 1)
exif_bytes = piexif.dump(exif_dict)
# if this is not set, then the save option will throw an error for setting subsampling='keep'
modified_image.format = source_image.format
try:
modified_image.save(
image_file,
icc_profile=source_image.info.get('icc_profile'),
dpi=source_image.info.get('dpi'),
exif=exif_bytes,
format=source_image.format,
subsampling='keep',
quality=95
)
del source_image
del modified_image
return True
except IOError as e:
print(e)
return None
If the same image is opened and saved in Photoshop, then it shows the correct DPI. I have also tried Gimp and I get the same result. The image with the wrong DPI suddenly gets the right DPI when opened and saved in Gimp.
My understanding is that the pixels (height and width) and the DPI values read from the Exif data across different platforms and applications. But could it be possible that the Onyx RIPCenter application is looking for DPI in a different place?
Below is the exif data of the images.
Exif data of the image that's saved in Photoshop,
[ExifTool] ExifTool Version Number : 11.10
[System] File Name : A3-VictoriaGlenManor-RH-Copper-92.4x210.8-R.jpg
[System] Directory : /Users/vinodsudharshan/Downloads
[System] File Size : 34 MB
[System] File Modification Date/Time : 2018:08:24 14:37:25+02:00
[System] File Access Date/Time : 2018:08:27 23:27:08+02:00
[System] File Inode Change Date/Time : 2018:08:27 22:56:37+02:00
[System] File Permissions : rw-r--r--
[File] File Type : JPEG
[File] File Type Extension : jpg
[File] MIME Type : image/jpeg
[File] Exif Byte Order : Big-endian (Motorola, MM)
[File] Current IPTC Digest : cdcffa7da8c7be09057076aeaf05c34e
[File] Image Width : 6550
[File] Image Height : 14940
[File] Encoding Process : Baseline DCT, Huffman coding
[File] Bits Per Sample : 8
[File] Color Components : 4
[IFD0] Image Width : 6130
[IFD0] Image Height : 8400
[IFD0] Bits Per Sample : 8 8 8
[IFD0] Photometric Interpretation : RGB
[IFD0] Orientation : Horizontal (normal)
[IFD0] Samples Per Pixel : 3
[IFD0] X Resolution : 180
[IFD0] Y Resolution : 180
[IFD0] Resolution Unit : inches
[IFD0] Software : Adobe Photoshop CS5.1 Macintosh
[IFD0] Modify Date : 2018:08:23 17:32:21
[ExifIFD] Exif Version : 0221
[ExifIFD] Color Space : Uncalibrated
[ExifIFD] Exif Image Width : 6550
[ExifIFD] Exif Image Height : 14940
[IFD1] Compression : JPEG (old-style)
[IFD1] X Resolution : 72
[IFD1] Y Resolution : 72
[IFD1] Resolution Unit : inches
[IFD1] Thumbnail Offset : 394
[IFD1] Thumbnail Length : 2261
[IFD1] Thumbnail Image : (Binary data 2261 bytes, use -b option to extract)
[IPTC] Coded Character Set : UTF8
[IPTC] Application Record Version : 0
[Photoshop] IPTC Digest : cdcffa7da8c7be09057076aeaf05c34e
[Photoshop] X Resolution : 180
[Photoshop] Displayed Units X : inches
[Photoshop] Y Resolution : 180
[Photoshop] Displayed Units Y : inches
[Photoshop] Print Style : Centered
[Photoshop] Print Position : 0 0
[Photoshop] Print Scale : 1
[Photoshop] Global Angle : 30
[Photoshop] Global Altitude : 30
[Photoshop] URL List :
[Photoshop] Slices Group Name : A3-VictoriaGlenManor-RH-Copper-92.4x210.8-R
[Photoshop] Num Slices : 1
[Photoshop] Pixel Aspect Ratio : 1
[Photoshop] Photoshop Thumbnail : (Binary data 2261 bytes, use -b option to extract)
[Photoshop] Has Real Merged Data : Yes
[Photoshop] Writer Name : Adobe Photoshop
[Photoshop] Reader Name : Adobe Photoshop CS5.1
[Photoshop] Photoshop Quality : 12
[Photoshop] Photoshop Format : Standard
[Photoshop] Progressive Scans : 3 Scans
[XMP-x] XMP Toolkit : Adobe XMP Core 5.0-c061 64.140949, 2010/12/07-10:57:01
[XMP-xmp] Modify Date : 2018:08:23 17:32:21+02:00
[XMP-xmp] Creator Tool : Adobe Photoshop CS5.1 Macintosh
[XMP-xmp] Create Date : 2018:08:21 15:12:04+02:00
[XMP-xmp] Metadata Date : 2018:08:23 17:32:21+02:00
[XMP-crs] Already Applied : True
[XMP-photoshop] Color Mode : CMYK
[XMP-photoshop] ICC Profile Name : U.S. Web Coated (SWOP) v2
[XMP-dc] Format : image/jpeg
[XMP-xmpMM] Instance ID : xmp.iid:9F9A62F1B5206811BF6AFA75AB99E0BD
[XMP-xmpMM] Document ID : xmp.did:9E9A62F1B5206811BF6AFA75AB99E0BD
[XMP-xmpMM] Original Document ID : xmp.did:9E9A62F1B5206811BF6AFA75AB99E0BD
[XMP-xmpMM] History Action : saved, saved
[XMP-xmpMM] History Instance ID : xmp.iid:9E9A62F1B5206811BF6AFA75AB99E0BD, xmp.iid:9F9A62F1B5206811BF6AFA75AB99E0BD
[XMP-xmpMM] History When : 2018:08:23 17:32:21+02:00, 2018:08:23 17:32:21+02:00
[XMP-xmpMM] History Software Agent : Adobe Photoshop CS5.1 Macintosh, Adobe Photoshop CS5.1 Macintosh
[XMP-xmpMM] History Changed : /, /
[ICC-header] Profile CMM Type : Adobe Systems Inc.
[ICC-header] Profile Version : 2.1.0
[ICC-header] Profile Class : Output Device Profile
[ICC-header] Color Space Data : CMYK
[ICC-header] Profile Connection Space : Lab
[ICC-header] Profile Date Time : 2000:07:26 05:41:53
[ICC-header] Profile File Signature : acsp
[ICC-header] Primary Platform : Apple Computer Inc.
[ICC-header] CMM Flags : Not Embedded, Independent
[ICC-header] Device Manufacturer : Adobe Systems Inc.
[ICC-header] Device Model :
[ICC-header] Device Attributes : Reflective, Glossy, Positive, Color
[ICC-header] Rendering Intent : Media-Relative Colorimetric
[ICC-header] Connection Space Illuminant : 0.9642 1 0.82491
[ICC-header] Profile Creator : Adobe Systems Inc.
[ICC-header] Profile ID : 0
[ICC_Profile] Profile Description : U.S. Web Coated (SWOP) v2
[ICC_Profile] Profile Copyright : Copyright 2000 Adobe Systems, Inc.
[ICC_Profile] Media White Point : 0.7084 0.73595 0.57104
[ICC_Profile] A To B0 : (Binary data 41478 bytes, use -b option to extract)
[ICC_Profile] A To B2 : (Binary data 41478 bytes, use -b option to extract)
[ICC_Profile] A To B1 : (Binary data 41478 bytes, use -b option to extract)
[ICC_Profile] B To A0 : (Binary data 145588 bytes, use -b option to extract)
[ICC_Profile] B To A1 : (Binary data 145588 bytes, use -b option to extract)
[ICC_Profile] B To A2 : (Binary data 145588 bytes, use -b option to extract)
[ICC_Profile] Gamut : (Binary data 37009 bytes, use -b option to extract)
[Adobe] DCT Encode Version : 100
[Adobe] APP14 Flags 0 : [14]
[Adobe] APP14 Flags 1 : (none)
[Adobe] Color Transform : YCCK
[Composite] Image Size : 6550x14940
[Composite] Megapixels : 97.9
Exif data of the image that's saved in the Python Application,
[ExifTool] ExifTool Version Number : 11.10
[System] File Name : A3-TEST_2_EXIF-RH-Copper-92.4x210.8-R.jpg
[System] Directory : /Users/vinodsudharshan/Desktop
[System] File Size : 36 MB
[System] File Modification Date/Time : 2018:08:27 21:55:25+02:00
[System] File Access Date/Time : 2018:08:31 16:59:05+02:00
[System] File Inode Change Date/Time : 2018:08:27 22:56:37+02:00
[System] File Permissions : rw-r--r--
[File] File Type : JPEG
[File] File Type Extension : jpg
[File] MIME Type : image/jpeg
[File] Exif Byte Order : Big-endian (Motorola, MM)
[File] Image Width : 6548
[File] Image Height : 14938
[File] Encoding Process : Baseline DCT, Huffman coding
[File] Bits Per Sample : 8
[File] Color Components : 4
[Adobe] DCT Encode Version : 100
[Adobe] APP14 Flags 0 : (none)
[Adobe] APP14 Flags 1 : (none)
[Adobe] Color Transform : Unknown (RGB or CMYK)
[IFD0] Image Width : 6130
[IFD0] Image Height : 8400
[IFD0] Bits Per Sample : 8 8 8
[IFD0] Photometric Interpretation : RGB
[IFD0] Orientation : Horizontal (normal)
[IFD0] Samples Per Pixel : 3
[IFD0] X Resolution : 180
[IFD0] Y Resolution : 180
[IFD0] Resolution Unit : inches
[IFD0] Software : Adobe Photoshop CS5.1 Macintosh
[IFD0] Modify Date : 2018:07:11 17:42:24
[ExifIFD] Exif Version : 0221
[ExifIFD] Color Space : Uncalibrated
[ExifIFD] Exif Image Width : 5669
[ExifIFD] Exif Image Height : 14173
[IFD1] Compression : JPEG (old-style)
[IFD1] X Resolution : 180
[IFD1] Y Resolution : 180
[IFD1] Resolution Unit : inches
[IFD1] Thumbnail Offset : 404
[IFD1] Thumbnail Length : 2076
[IFD1] Thumbnail Image : (Binary data 2076 bytes, use -b option to extract)
[ICC-header] Profile CMM Type : Adobe Systems Inc.
[ICC-header] Profile Version : 2.1.0
[ICC-header] Profile Class : Output Device Profile
[ICC-header] Color Space Data : CMYK
[ICC-header] Profile Connection Space : Lab
[ICC-header] Profile Date Time : 2000:07:26 05:41:53
[ICC-header] Profile File Signature : acsp
[ICC-header] Primary Platform : Apple Computer Inc.
[ICC-header] CMM Flags : Not Embedded, Independent
[ICC-header] Device Manufacturer : Adobe Systems Inc.
[ICC-header] Device Model :
[ICC-header] Device Attributes : Reflective, Glossy, Positive, Color
[ICC-header] Rendering Intent : Media-Relative Colorimetric
[ICC-header] Connection Space Illuminant : 0.9642 1 0.82491
[ICC-header] Profile Creator : Adobe Systems Inc.
[ICC-header] Profile ID : 0
[ICC_Profile] Profile Description : U.S. Web Coated (SWOP) v2
[ICC_Profile] Profile Copyright : Copyright 2000 Adobe Systems, Inc.
[ICC_Profile] Media White Point : 0.7084 0.73595 0.57104
[ICC_Profile] A To B0 : (Binary data 41478 bytes, use -b option to extract)
[ICC_Profile] A To B2 : (Binary data 41478 bytes, use -b option to extract)
[ICC_Profile] A To B1 : (Binary data 41478 bytes, use -b option to extract)
[ICC_Profile] B To A0 : (Binary data 145588 bytes, use -b option to extract)
[ICC_Profile] B To A1 : (Binary data 145588 bytes, use -b option to extract)
[ICC_Profile] B To A2 : (Binary data 145588 bytes, use -b option to extract)
[ICC_Profile] Gamut : (Binary data 37009 bytes, use -b option to extract)
[Composite] Image Size : 6548x14938
[Composite] Megapixels : 97.8

I would suspect that Onyx RIPCenter is using 72 as a default (which is a common default) and that it normally reads Photoshop:X/YResolution to get the DPI. Try copying the IFD0:X/YResolution to Photoshop:X/YResolution or simply setting the Photoshop:X/YResolution to 180.
In exiftool, you could use
exiftool -Photoshop:*Resolution=180 FILEorDIR
The asterisk is a wildcard which will allow both XResolution and YResolution to be set at the same time. Replace FILEorDIR with the files/directories to be processed. This command creates backup files. Add -overwrite_original to suppress the creation of backup files. Add -r to recurse into subdirectories.

Related

Dimensions change when Ghostscript converts PS to PNG

I use the following minimal PostScript file:
%!PS-Adobe-2.0
%%BoundingBox: 0 0 100 100
0 0 moveto 100 100 rlineto stroke
showpage
This draws a line from (0,0) to (100,100) in a 100x100 box.
I then convert this file minimal.ps to a PNG with this command line, borrowed from GhostScript's documentation:
gs -sDEVICE=pngmono -o minimal.png minimal.ps
With GPL Ghostscript 9.53.3 (current Debian stable) and 9.27 (oldstable) the resulting PNG file has the following dimensions:
> identify minimal.png
minimal.png PNG 612x792 612x792+0+0 8-bit Gray 2c 2994B 0.000u 0:00.000
Both width and height extend far beyond the original BoundingBox, and they are not even equal.
The PNG's dimensions are the same if the output device is pnggray, pngalpha, etc.
The dimensions are also the same if, in the PostScript code, 100 is replaced by 10 or by 10000.
How can I tell GhostScript to create a PNG file whose dimensions automatically fit the PostScript file's BoundingBox?

Saving an Image stored in BytesIO in pillow

I have an image stored as BytesIO of Pillow and I need to save it to a file with some header information (containing textual attributes) that I need to add specific to my problem. I need the bytes to be represented according to some image compression format. Would that be possible? If yes, how it can be done?
I also need to store more than one image in the file.
Storing more than one image in a file is problematic for PNG, JPEG and the most of the common formats. One option for that is TIFF - not sure if that works for you?
Here's how you can store some additional text in a PNG at least:
#!/usr/bin/env python3
from PIL.PngImagePlugin import Image, PngInfo
# Create empty metadata and add a couple of text strings
metadata = PngInfo()
metadata.add_text("Key1:","Value1")
metadata.add_text("Key2:","Value2")
# Create red image and save with metadata embedded
im = Image.new('RGB',(64,64),'red')
im.save("result.png", pnginfo=metadata)
If you check that with pngcheck you will see:
pngcheck -7v result.png
Sample Output
File: result.png (200 bytes)
chunk IHDR at offset 0x0000c, length 13
64 x 64 image, 24-bit RGB, non-interlaced
chunk tEXt at offset 0x00025, length 12, keyword: Key1:
Value1
chunk tEXt at offset 0x0003d, length 12, keyword: Key2:
Value2
chunk IDAT at offset 0x00055, length 95
zlib: deflated, 32K window, default compression
chunk IEND at offset 0x000c0, length 0
No errors detected in result.png (5 chunks, 98.4% compression).
Here's how to save 3 images and a comment in a single TIFF file:
from PIL import Image
from PIL.TiffImagePlugin import ImageFileDirectory_v2, TiffTags
# Create a structure to hold meta-data
ifd = ImageFileDirectory_v2()
ifd[270] = 'Some Funky Comment'
ifd.tagtype[270] = TiffTags.ASCII
# Create red image and save with metadata embedded
im1 = Image.new('RGB',(50,50),'red')
im2 = Image.new('RGB',(64,64),'green')
im3 = Image.new('RGB',(80,80),'blue')
im1.save("result.tif", append_images[im2,im3], save_all=True, tiffinfo=ifd)
And check that with:
tiffinfo -v result.tif
Sample Output
TIFF Directory at offset 0x8 (8)
Image Width: 50 Image Length: 50
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: RGB color
Samples/Pixel: 3
Rows/Strip: 50
Planar Configuration: single image plane
ImageDescription: Some Funky Comment
TIFF Directory at offset 0x1e08 (7688)
Image Width: 64 Image Length: 64
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: RGB color
Samples/Pixel: 3
Rows/Strip: 64
Planar Configuration: single image plane
ImageDescription: Some Funky Comment
TIFF Directory at offset 0x4eb8 (20152)
Image Width: 80 Image Length: 80
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: RGB color
Samples/Pixel: 3
Rows/Strip: 80
Planar Configuration: single image plane
ImageDescription: Some Funky Comment
You can then extract the images on the command-line with ImageMagick like this.
To extract first image:
magick result.tif[0] first.png
To extract last image:
magick result.tif[-1] last.png
To extract all three images:
magick result.tif image-%d.png
Result
-rw-r--r-- 1 mark staff 457 21 Jan 08:11 image-0.png
-rw-r--r-- 1 mark staff 458 21 Jan 08:11 image-1.png
-rw-r--r-- 1 mark staff 460 21 Jan 08:11 image-2.png
Note: Use convert in place of magick above if you are running v6 ImageMagick.
Keywords: Python, PIL, image processing, multiple images, TIF, comment, tiffinfo, IFD, PNG tEXt.

Resize image preserving exif data: focal length etc

What converter(like imagemagick) can be used to convert images with exif data preserving it?
What if I downscale images 4 times? Should I also change the focal length?
Data I have extracted from my JPG photo with exiftool
Focal Length : 50.0 mm (35 mm equivalent: 50.0 mm)
EDIT:
Seems imagemagick preserve exif data:
mogrify -resize 25% -path output_foler/ *.JPG
I believe newer versions of Imagemagick should preserve the metadata. A fall back would be to use Exiftool to copy the data with a command like exiftool -tagsfromfile OldFile -all:all NewFile.
Both of those are platform independent. To be more precise with other programs, you will need specify your OS. For example, with Windows, you can use Irfanview to convert images and it will retain most metadata as long as you enable those options.

How to extract orientation information from videos?

After surfing through tons of documentation on the web it seems that the iPhone always shoots the video at a 480x360 aspect ratio and applies a transformation matrix on the video track. (480x360 may change but its always the same for a given device)
Here is a way of modifying the ffmpeg source within a iOS project and accessing the matrix http://www.seqoy.com/correct-orientation-for-iphone-recorded-movies-with-ffmpeg/
Here is a cleaner way of finding the transformation matrix in iOS-4
How to detect (iPhone SDK) if a video file was recorded in portrait orientation, or landscape.
How can the orientation of the video be extracted in either of the options below -
- iOS 3.2
- ffmpeg (through the command line server side)
- ruby
Any help will be appreciated.
Since most Cameras store their rotation/orientation within the exif-metadata, i would suggest using exifttool and the a ruby wrapper gem called mini_exiftool which is actively maintained.
Install exiftool:
apt-get exiftool || brew install exiftool || port install exiftool
or use what ever package manager is available
Install mini_exiftool:
gem install mini_exiftool
Try it:
irb>
require 'mini_exiftool'
movie = MiniExiftool.new('test_movie.mov')
movie.orientation #=> 90
cheers
You can use ffprobe. No need for any grep, or any other additional processes, or any regex operations to parse the output as shown in other answers.
If you want the rotate metadata:
Command:
ffprobe -loglevel error -select_streams v:0 -show_entries stream_tags=rotate -of default=nw=1:nk=1 input.mp4
Example output:
90
If you want the display matrix rotation side data:
Command:
ffprobe -loglevel error -select_streams v:0 -show_entries side_data=rotation -of default=nw=1:nk=1 input.mp4
Example output:
-90
If you want the display matrix:
Command:
ffprobe -loglevel error -select_streams v:0 -show_entries side_data=displaymatrix -of default=nw=1:nk=1 input.mp4
Example output:
00000000: 0 65536 0
00000001: -65536 0 0
00000002: 15728640 0 1073741824
What the options mean
-loglevel error Omit the header and other info from output.
-select_streams v:0 Only process the first video stream and ignore everything else. Useful if your input contains multiple video streams and you only want info from one.
-show_entries stream_tags=rotate Chooses to output the rotate tag from the video stream.
-of default=nw=1:nk=1 Use default output format, but omit including the section header/footer wrappers and each field key.
Output format
The output from ffprobe can be formatted in several ways. For example, JSON:
ffprobe -loglevel error -show_entries stream_tags=rotate -of json input.mp4
{
"streams": [
{
"tags": {
"rotate": "90"
},
"side_data_list": [
{
}
]
}
]
From what I've found thus far, ffmpeg doesn't have the ability to detect iPhone's orientation. But, the open source library, mediainfo can. A command line example:
$ mediainfo test.mp4 | grep Rotation
Rotation : 90°
More example output from the same iphone video:
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : Baseline#L3.0
Format settings, CABAC : No
Format settings, ReFrames : 1 frame
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 7s 941ms
Bit rate mode : Variable
Bit rate : 724 Kbps
Width : 480 pixels
Height : 360 pixels
Display aspect ratio : 4:3
Rotation : 90°
Frame rate mode : Variable
Frame rate : 29.970 fps
Minimum frame rate : 28.571 fps
Maximum frame rate : 31.579 fps
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.140
Stream size : 702 KiB (91%)
Title : Core Media Video
Encoded date : UTC 2011-06-22 15:58:25
Tagged date : UTC 2011-06-22 15:58:34
Color primaries : BT.601-6 525, BT.1358 525, BT.1700 NTSC, SMPTE 170M
Transfer characteristics : BT.709-5, BT.1361
Matrix coefficients : BT.601-6 525, BT.1358 525, BT.1700 NTSC, SMPTE 170M
ffmpeg reports the metadata with the rotation value for .mov files:
ffmpeg -i myrotatedMOV.mov
....
Duration: 00:00:14.31, start: 0.000000, bitrate: 778 kb/s
Stream #0:0(und): Video: h264 (Baseline) (avc1 / 0x31637661), yuv420p, 480x360, 702 kb/s, 29.98 fps, 30 tbr, 600 tbn, 1200 tbc
Metadata:
rotate : 180
creation_time : 2013-01-09 12:47:36
handler_name : Core Media Data Handler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, mono, s16, 62 kb/s
Metadata:
creation_time : 2013-01-09 12:47:36
handler_name : Core Media Data Handler
In my application I pull it out with regex, ie in python:
import subprocess, re
cmd = 'ffmpeg -i %s' % pathtofile
p = subprocess.Popen(
cmd.split(" "),
stderr = subprocess.PIPE,
close_fds=True
)
stdout, stderr = p.communicate()
reo_rotation = re.compile('rotate\s+:\s(?P<rotation>.*)')
match_rotation = reo_rotation.search(stderr)
rotation = match_rotation.groups()[0]
I havent tried this with a wide range of videos, only a couple .movs recorded from an iphone5, using ffmpeg version 1.0. But so far so good.
Similar to #HdN8's answer, but without the python regex:
$ ffprobe -show_streams any.MOV 2>/dev/null | grep rotate
TAG:rotate=180
Or JSON:
$ ffprobe -of json -show_streams IMG_8738.MOV 2>/dev/null | grep rotate
"rotate": "180",
Or you could parse the JSON (or other output format).
I have extracted on iOS using an AVAssetExportSession, AVMutableComposition and the input AVAssetTrack's preferredTransform. I concatenate the preferred transform with a transformation to fill the target size.
After exporting to a file, I upload using ASIHTTPRequest to my rails server and send the data to Amazon S3 using paperclip.

To geo-tag a photo, what attributes are required? More than lat/lon?

I am trying to geo-tag photos taken with the iPhone camera. Since I'm not saving the photos to the camera roll, the photos do not have any EXIF data.
So, what elements are required in valid EXIF data? I think I have written the latitude, longitude, and altitude to the EXIF data, but when I export the photo, there doesn't seem to be any EXIF data.
I suspect that for a service like Flickr to display the EXIF data, I need to add more than just the latitude and longitude or some such foolishness.
Anyone have any experience with writing EXIF data?
EDIT #3: Aha, got it now! Thanks for your help. What I had to do to address EDIT #2 was add the make, model, and software.
EDIT #2: Thanks to the first respondent (who I will give the correct answer two regardless), my photo is now being geo-tagged, but now I have a related question.
The photo gets automatically located when I upload it to Flickr (when I go to map it it suggests the location), but it doesn't show the nice chart of EXIF data.
This photo is geo-tagged. but no nice chart of EXIF data on this page:http://www.flickr.com/photos/33766454#N02/3980488205/.
This one exported from the camera roll shows a More Properties link to show the EXIF data in full: http://www.flickr.com/photos/33766454#N02/3978868900/
Now I'm wondering what I have to do get Flickr (and also Picasa on my desktop) to display the link to see the EXIF data. When I look at the photos properties on my Mac too, I don't see any EXIF data, but I know it's there.
EDIT: Based on the advice in the first two answers, I set the suggested EXIF tags and inspected them in EXIFTool. Unfortunately, though the EXIF data shows up in EXIFTool, it doesn't show up when I upload to Picasa or Flickr. Here is the output from EXIFTool. Any idea what I still might be missing?
~/Downloads: exiftool My_Photo_-_10-4-09_5_22_20AM.jpg
ExifTool Version Number : 7.96
File Name : My_Photo_-_10-4-09_5_22_20AM.jpg
Directory : .
File Size : 287 kB
File Modification Date/Time : 2009:10:04 05:22:51-07:00
File Type : JPEG
MIME Type : image/jpeg
JFIF Version : 1.01
Resolution Unit : None
X Resolution : 1
Y Resolution : 1
Exif Byte Order : Big-endian (Motorola, MM)
Orientation : Horizontal (normal)
Color Space : sRGB
Exif Image Width : 319
Exif Image Height : 480
GPS Version ID : 2.2.0.0
GPS Latitude Ref : North
GPS Longitude Ref : West
GPS Altitude Ref : Above Sea Level
Image Width : 319
Image Height : 480
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:4:4 (1 1)
GPS Altitude : 0 m Above Sea Level
GPS Latitude : 37 deg 19' 54.08" N
GPS Longitude : 122 deg 1' 50.63" W
GPS Position : 37 deg 19' 54.08" N, 122 deg 1' 50.63" W
Image Size : 319x480
I've done this to geo-tag photos which Picasa will recognise, for Picasa you need to add the following tags:
GPSVersionID ("0 0 2 2 "), GPSlongituderef ("W" or "E"), GPSlatituderef ("N" or "S") and also GPSAltitudeRef ("Above Sea Level")
Values in brackets are the ones I used. These are in addition to the lat, long and altitude tags. As Brian mentions exiftool is excellent for examining and modifying EXIF tags.
EDIT
Output from exiftool:
ExifTool Version Number : 7.01
File Name : bleatarn.jpg
Directory : .
File Size : 3 MB
File Modification Date/Time : 2008:03:01 12:43:44
File Type : JPEG
MIME Type : image/jpeg
JFIF Version : 1.1
Resolution Unit : None
X Resolution : 1
Y Resolution : 1
Exif Byte Order : Little-endian (Intel)
Software : Picasa 3.0
Exif Version : 0210
Interoperability Index : Unknown ( )
Interoperability Version : 0100
Image Unique ID : 6fda6fa9628b8615d99abc81663c9b01
GPS Version ID : 0.0.2.2
GPS Latitude Ref : North
GPS Longitude Ref : West
GPS Altitude Ref : Above Sea Level
GPS Altitude : 0 m
Caption-Abstract : Blea Tarn
Image Width : 3151
Image Height : 1375
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2)
GPS Latitude : 54 deg 25' 44.33" N
GPS Longitude : 3 deg 5' 27.44" W
GPS Position : 54 deg 25' 44.33" N, 3 deg 5' 27.44" W
Image Size : 3151x1375
Only difference I can see is that GPS Version ID is different, and you're Big-endian rather than little-endian (that shouldn't matter, should it?)
This may help. It details how to copy the geotagging data to a photo without geotagged data, and details the EXIF fields used by exiftool.
I would also set GPSMapDatum, as the EXIF standard strongly recommends including this tag. The value would be "WGS-84", assuming your coordinates come from a GPS unit or are based on common web maps or any other current source of location data. (If you're using a different datum, it'd be better to convert it to WGS-84 anyway, since I suspect most viewers just assume that to be the datum.)
If you're not familar, a map datum tells how to interpret the latitude and longitude values. Since the earth is not a perfect sphere, there are many ways the coordinates can be interpreted. Using the wrong interpretation can sometimes have a significant effect on where the marker will end up on a map.