Index: trunk/phase3/includes/Exif.php |
— | — | @@ -17,7 +17,7 @@ |
18 | 18 | * |
19 | 19 | * @ingroup Media |
20 | 20 | * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> |
21 | | - * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason, 2009 Brent Garber |
| 21 | + * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason |
22 | 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License |
23 | 23 | * @see http://exif.org/Exif2-2.PDF The Exif 2.2 specification |
24 | 24 | * @file |
— | — | @@ -51,6 +51,11 @@ |
52 | 52 | var $mExifTags; |
53 | 53 | |
54 | 54 | /** |
| 55 | + * A one dimentional array of all Exif tags |
| 56 | + */ |
| 57 | + var $mFlatExifTags; |
| 58 | + |
| 59 | + /** |
55 | 60 | * The raw Exif data returned by exif_read_data() |
56 | 61 | */ |
57 | 62 | var $mRawExifData; |
— | — | @@ -104,165 +109,192 @@ |
105 | 110 | */ |
106 | 111 | $this->mExifTags = array( |
107 | 112 | # TIFF Rev. 6.0 Attribute Information (p22) |
108 | | - 'IFD0' => array( |
| 113 | + 'tiff' => array( |
109 | 114 | # Tags relating to image structure |
110 | | - 'ImageWidth' => Exif::SHORT.','.Exif::LONG, # Image width |
111 | | - 'ImageLength' => Exif::SHORT.','.Exif::LONG, # Image height |
112 | | - 'BitsPerSample' => array( Exif::SHORT, 3 ), # Number of bits per component |
113 | | - # "When a primary image is JPEG compressed, this designation is not" |
114 | | - # "necessary and is omitted." (p23) |
115 | | - 'Compression' => Exif::SHORT, # Compression scheme #p23 |
116 | | - 'PhotometricInterpretation' => Exif::SHORT, # Pixel composition #p23 |
117 | | - 'Orientation' => Exif::SHORT, # Orientation of image #p24 |
118 | | - 'SamplesPerPixel' => Exif::SHORT, # Number of components |
119 | | - 'PlanarConfiguration' => Exif::SHORT, # Image data arrangement #p24 |
120 | | - 'YCbCrSubSampling' => array( Exif::SHORT, 2), # Subsampling ratio of Y to C #p24 |
121 | | - 'YCbCrPositioning' => Exif::SHORT, # Y and C positioning #p24-25 |
122 | | - 'XResolution' => Exif::RATIONAL, # Image resolution in width direction |
123 | | - 'YResolution' => Exif::RATIONAL, # Image resolution in height direction |
124 | | - 'ResolutionUnit' => Exif::SHORT, # Unit of X and Y resolution #(p26) |
| 115 | + 'structure' => array( |
| 116 | + 'ImageWidth' => Exif::SHORT.','.Exif::LONG, # Image width |
| 117 | + 'ImageLength' => Exif::SHORT.','.Exif::LONG, # Image height |
| 118 | + 'BitsPerSample' => Exif::SHORT, # Number of bits per component |
| 119 | + # "When a primary image is JPEG compressed, this designation is not" |
| 120 | + # "necessary and is omitted." (p23) |
| 121 | + 'Compression' => Exif::SHORT, # Compression scheme #p23 |
| 122 | + 'PhotometricInterpretation' => Exif::SHORT, # Pixel composition #p23 |
| 123 | + 'Orientation' => Exif::SHORT, # Orientation of image #p24 |
| 124 | + 'SamplesPerPixel' => Exif::SHORT, # Number of components |
| 125 | + 'PlanarConfiguration' => Exif::SHORT, # Image data arrangement #p24 |
| 126 | + 'YCbCrSubSampling' => Exif::SHORT, # Subsampling ratio of Y to C #p24 |
| 127 | + 'YCbCrPositioning' => Exif::SHORT, # Y and C positioning #p24-25 |
| 128 | + 'XResolution' => Exif::RATIONAL, # Image resolution in width direction |
| 129 | + 'YResolution' => Exif::RATIONAL, # Image resolution in height direction |
| 130 | + 'ResolutionUnit' => Exif::SHORT, # Unit of X and Y resolution #(p26) |
| 131 | + ), |
125 | 132 | |
126 | 133 | # Tags relating to recording offset |
127 | | - 'StripOffsets' => Exif::SHORT.','.Exif::LONG, # Image data location |
128 | | - 'RowsPerStrip' => Exif::SHORT.','.Exif::LONG, # Number of rows per strip |
129 | | - 'StripByteCounts' => Exif::SHORT.','.Exif::LONG, # Bytes per compressed strip |
130 | | - 'JPEGInterchangeFormat' => Exif::SHORT.','.Exif::LONG, # Offset to JPEG SOI |
131 | | - 'JPEGInterchangeFormatLength' => Exif::SHORT.','.Exif::LONG, # Bytes of JPEG data |
| 134 | + 'offset' => array( |
| 135 | + 'StripOffsets' => Exif::SHORT.','.Exif::LONG, # Image data location |
| 136 | + 'RowsPerStrip' => Exif::SHORT.','.Exif::LONG, # Number of rows per strip |
| 137 | + 'StripByteCounts' => Exif::SHORT.','.Exif::LONG, # Bytes per compressed strip |
| 138 | + 'JPEGInterchangeFormat' => Exif::SHORT.','.Exif::LONG, # Offset to JPEG SOI |
| 139 | + 'JPEGInterchangeFormatLength' => Exif::SHORT.','.Exif::LONG, # Bytes of JPEG data |
| 140 | + ), |
132 | 141 | |
133 | 142 | # Tags relating to image data characteristics |
134 | | - 'TransferFunction' => Exif::SHORT, # Transfer function |
135 | | - 'WhitePoint' => array( Exif::RATIONAL, 2), # White point chromaticity |
136 | | - 'PrimaryChromaticities' => array( Exif::RATIONAL, 6), # Chromaticities of primarities |
137 | | - 'YCbCrCoefficients' => array( Exif::RATIONAL, 3), # Color space transformation matrix coefficients #p27 |
138 | | - 'ReferenceBlackWhite' => array( Exif::RATIONAL, 6), # Pair of black and white reference values |
| 143 | + 'characteristics' => array( |
| 144 | + 'TransferFunction' => Exif::SHORT, # Transfer function |
| 145 | + 'WhitePoint' => Exif::RATIONAL, # White point chromaticity |
| 146 | + 'PrimaryChromaticities' => Exif::RATIONAL, # Chromaticities of primarities |
| 147 | + 'YCbCrCoefficients' => Exif::RATIONAL, # Color space transformation matrix coefficients #p27 |
| 148 | + 'ReferenceBlackWhite' => Exif::RATIONAL # Pair of black and white reference values |
| 149 | + ), |
139 | 150 | |
140 | 151 | # Other tags |
141 | | - 'DateTime' => Exif::ASCII, # File change date and time |
142 | | - 'ImageDescription' => Exif::ASCII, # Image title |
143 | | - 'Make' => Exif::ASCII, # Image input equipment manufacturer |
144 | | - 'Model' => Exif::ASCII, # Image input equipment model |
145 | | - 'Software' => Exif::ASCII, # Software used |
146 | | - 'Artist' => Exif::ASCII, # Person who created the image |
147 | | - 'Copyright' => Exif::ASCII, # Copyright holder |
| 152 | + 'other' => array( |
| 153 | + 'DateTime' => Exif::ASCII, # File change date and time |
| 154 | + 'ImageDescription' => Exif::ASCII, # Image title |
| 155 | + 'Make' => Exif::ASCII, # Image input equipment manufacturer |
| 156 | + 'Model' => Exif::ASCII, # Image input equipment model |
| 157 | + 'Software' => Exif::ASCII, # Software used |
| 158 | + 'Artist' => Exif::ASCII, # Person who created the image |
| 159 | + 'Copyright' => Exif::ASCII, # Copyright holder |
| 160 | + ), |
148 | 161 | ), |
149 | 162 | |
150 | 163 | # Exif IFD Attribute Information (p30-31) |
151 | | - 'EXIF' => array( |
152 | | - # TODO: NOTE: Nonexistence of this field is taken to mean nonconformance |
153 | | - # to the EXIF 2.1 AND 2.2 standards |
154 | | - 'ExifVersion' => array( Exif::UNDEFINED, 4 ), # Exif version |
155 | | - 'FlashPixVersion' => array( Exif::UNDEFINED, 4 ), # Supported Flashpix version #p32 |
| 164 | + 'exif' => array( |
| 165 | + # Tags relating to version |
| 166 | + 'version' => array( |
| 167 | + # TODO: NOTE: Nonexistence of this field is taken to mean nonconformance |
| 168 | + # to the EXIF 2.1 AND 2.2 standards |
| 169 | + 'ExifVersion' => Exif::UNDEFINED, # Exif version |
| 170 | + 'FlashpixVersion' => Exif::UNDEFINED, # Supported Flashpix version #p32 |
| 171 | + ), |
156 | 172 | |
157 | 173 | # Tags relating to Image Data Characteristics |
158 | | - 'ColorSpace' => Exif::SHORT, # Color space information #p32 |
| 174 | + 'characteristics' => array( |
| 175 | + 'ColorSpace' => Exif::SHORT, # Color space information #p32 |
| 176 | + ), |
159 | 177 | |
160 | 178 | # Tags relating to image configuration |
161 | | - 'ComponentsConfiguration' => array( Exif::UNDEFINED, 1), # Meaning of each component #p33 |
162 | | - 'CompressedBitsPerPixel' => Exif::RATIONAL, # Image compression mode |
163 | | - 'PixelYDimension' => Exif::SHORT.','.Exif::LONG, # Valid image width |
164 | | - 'PixelXDimension' => Exif::SHORT.','.Exif::LONG, # Valid image height |
| 179 | + 'configuration' => array( |
| 180 | + 'ComponentsConfiguration' => Exif::UNDEFINED, # Meaning of each component #p33 |
| 181 | + 'CompressedBitsPerPixel' => Exif::RATIONAL, # Image compression mode |
| 182 | + 'PixelYDimension' => Exif::SHORT.','.Exif::LONG, # Valid image width |
| 183 | + 'PixelXDimension' => Exif::SHORT.','.Exif::LONG, # Valind image height |
| 184 | + ), |
165 | 185 | |
166 | 186 | # Tags relating to related user information |
167 | | - 'MakerNote' => Exif::UNDEFINED, # Manufacturer notes |
168 | | - 'UserComment' => Exif::UNDEFINED, # User comments #p34 |
| 187 | + 'user' => array( |
| 188 | + 'MakerNote' => Exif::UNDEFINED, # Manufacturer notes |
| 189 | + 'UserComment' => Exif::UNDEFINED, # User comments #p34 |
| 190 | + ), |
169 | 191 | |
170 | 192 | # Tags relating to related file information |
171 | | - 'RelatedSoundFile' => Exif::ASCII, # Related audio file |
| 193 | + 'related' => array( |
| 194 | + 'RelatedSoundFile' => Exif::ASCII, # Related audio file |
| 195 | + ), |
172 | 196 | |
173 | 197 | # Tags relating to date and time |
174 | | - 'DateTimeOriginal' => Exif::ASCII, # Date and time of original data generation #p36 |
175 | | - 'DateTimeDigitized' => Exif::ASCII, # Date and time of original data generation |
176 | | - 'SubSecTime' => Exif::ASCII, # DateTime subseconds |
177 | | - 'SubSecTimeOriginal' => Exif::ASCII, # DateTimeOriginal subseconds |
178 | | - 'SubSecTimeDigitized' => Exif::ASCII, # DateTimeDigitized subseconds |
| 198 | + 'dateandtime' => array( |
| 199 | + 'DateTimeOriginal' => Exif::ASCII, # Date and time of original data generation #p36 |
| 200 | + 'DateTimeDigitized' => Exif::ASCII, # Date and time of original data generation |
| 201 | + 'SubSecTime' => Exif::ASCII, # DateTime subseconds |
| 202 | + 'SubSecTimeOriginal' => Exif::ASCII, # DateTimeOriginal subseconds |
| 203 | + 'SubSecTimeDigitized' => Exif::ASCII, # DateTimeDigitized subseconds |
| 204 | + ), |
179 | 205 | |
180 | 206 | # Tags relating to picture-taking conditions (p31) |
181 | | - 'ExposureTime' => Exif::RATIONAL, # Exposure time |
182 | | - 'FNumber' => Exif::RATIONAL, # F Number |
183 | | - 'ExposureProgram' => Exif::SHORT, # Exposure Program #p38 |
184 | | - 'SpectralSensitivity' => Exif::ASCII, # Spectral sensitivity |
185 | | - 'ISOSpeedRatings' => Exif::SHORT, # ISO speed rating |
186 | | - 'OECF' => Exif::UNDEFINED, # Optoelectronic conversion factor |
187 | | - 'ShutterSpeedValue' => Exif::SRATIONAL, # Shutter speed |
188 | | - 'ApertureValue' => Exif::RATIONAL, # Aperture |
189 | | - 'BrightnessValue' => Exif::SRATIONAL, # Brightness |
190 | | - 'ExposureBiasValue' => Exif::SRATIONAL, # Exposure bias |
191 | | - 'MaxApertureValue' => Exif::RATIONAL, # Maximum land aperture |
192 | | - 'SubjectDistance' => Exif::RATIONAL, # Subject distance |
193 | | - 'MeteringMode' => Exif::SHORT, # Metering mode #p40 |
194 | | - 'LightSource' => Exif::SHORT, # Light source #p40-41 |
195 | | - 'Flash' => Exif::SHORT, # Flash #p41-42 |
196 | | - 'FocalLength' => Exif::RATIONAL, # Lens focal length |
197 | | - 'SubjectArea' => array( Exif::SHORT, 4 ), # Subject area |
198 | | - 'FlashEnergy' => Exif::RATIONAL, # Flash energy |
199 | | - 'SpatialFrequencyResponse' => Exif::UNDEFINED, # Spatial frequency response |
200 | | - 'FocalPlaneXResolution' => Exif::RATIONAL, # Focal plane X resolution |
201 | | - 'FocalPlaneYResolution' => Exif::RATIONAL, # Focal plane Y resolution |
202 | | - 'FocalPlaneResolutionUnit' => Exif::SHORT, # Focal plane resolution unit #p46 |
203 | | - 'SubjectLocation' => array( Exif::SHORT, 2), # Subject location |
204 | | - 'ExposureIndex' => Exif::RATIONAL, # Exposure index |
205 | | - 'SensingMethod' => Exif::SHORT, # Sensing method #p46 |
206 | | - 'FileSource' => Exif::UNDEFINED, # File source #p47 |
207 | | - 'SceneType' => Exif::UNDEFINED, # Scene type #p47 |
208 | | - 'CFAPattern' => Exif::UNDEFINED, # CFA pattern |
209 | | - 'CustomRendered' => Exif::SHORT, # Custom image processing #p48 |
210 | | - 'ExposureMode' => Exif::SHORT, # Exposure mode #p48 |
211 | | - 'WhiteBalance' => Exif::SHORT, # White Balance #p49 |
212 | | - 'DigitalZoomRatio' => Exif::RATIONAL, # Digital zoom ration |
213 | | - 'FocalLengthIn35mmFilm' => Exif::SHORT, # Focal length in 35 mm film |
214 | | - 'SceneCaptureType' => Exif::SHORT, # Scene capture type #p49 |
215 | | - 'GainControl' => Exif::RATIONAL, # Scene control #p49-50 |
216 | | - 'Contrast' => Exif::SHORT, # Contrast #p50 |
217 | | - 'Saturation' => Exif::SHORT, # Saturation #p50 |
218 | | - 'Sharpness' => Exif::SHORT, # Sharpness #p50 |
219 | | - 'DeviceSettingDescription' => Exif::UNDEFINED, # Desice settings description |
220 | | - 'SubjectDistanceRange' => Exif::SHORT, # Subject distance range #p51 |
| 207 | + 'conditions' => array( |
| 208 | + 'ExposureTime' => Exif::RATIONAL, # Exposure time |
| 209 | + 'FNumber' => Exif::RATIONAL, # F Number |
| 210 | + 'ExposureProgram' => Exif::SHORT, # Exposure Program #p38 |
| 211 | + 'SpectralSensitivity' => Exif::ASCII, # Spectral sensitivity |
| 212 | + 'ISOSpeedRatings' => Exif::SHORT, # ISO speed rating |
| 213 | + 'OECF' => Exif::UNDEFINED, # Optoelectronic conversion factor |
| 214 | + 'ShutterSpeedValue' => Exif::SRATIONAL, # Shutter speed |
| 215 | + 'ApertureValue' => Exif::RATIONAL, # Aperture |
| 216 | + 'BrightnessValue' => Exif::SRATIONAL, # Brightness |
| 217 | + 'ExposureBiasValue' => Exif::SRATIONAL, # Exposure bias |
| 218 | + 'MaxApertureValue' => Exif::RATIONAL, # Maximum land aperture |
| 219 | + 'SubjectDistance' => Exif::RATIONAL, # Subject distance |
| 220 | + 'MeteringMode' => Exif::SHORT, # Metering mode #p40 |
| 221 | + 'LightSource' => Exif::SHORT, # Light source #p40-41 |
| 222 | + 'Flash' => Exif::SHORT, # Flash #p41-42 |
| 223 | + 'FocalLength' => Exif::RATIONAL, # Lens focal length |
| 224 | + 'SubjectArea' => Exif::SHORT, # Subject area |
| 225 | + 'FlashEnergy' => Exif::RATIONAL, # Flash energy |
| 226 | + 'SpatialFrequencyResponse' => Exif::UNDEFINED, # Spatial frequency response |
| 227 | + 'FocalPlaneXResolution' => Exif::RATIONAL, # Focal plane X resolution |
| 228 | + 'FocalPlaneYResolution' => Exif::RATIONAL, # Focal plane Y resolution |
| 229 | + 'FocalPlaneResolutionUnit' => Exif::SHORT, # Focal plane resolution unit #p46 |
| 230 | + 'SubjectLocation' => Exif::SHORT, # Subject location |
| 231 | + 'ExposureIndex' => Exif::RATIONAL, # Exposure index |
| 232 | + 'SensingMethod' => Exif::SHORT, # Sensing method #p46 |
| 233 | + 'FileSource' => Exif::UNDEFINED, # File source #p47 |
| 234 | + 'SceneType' => Exif::UNDEFINED, # Scene type #p47 |
| 235 | + 'CFAPattern' => Exif::UNDEFINED, # CFA pattern |
| 236 | + 'CustomRendered' => Exif::SHORT, # Custom image processing #p48 |
| 237 | + 'ExposureMode' => Exif::SHORT, # Exposure mode #p48 |
| 238 | + 'WhiteBalance' => Exif::SHORT, # White Balance #p49 |
| 239 | + 'DigitalZoomRatio' => Exif::RATIONAL, # Digital zoom ration |
| 240 | + 'FocalLengthIn35mmFilm' => Exif::SHORT, # Focal length in 35 mm film |
| 241 | + 'SceneCaptureType' => Exif::SHORT, # Scene capture type #p49 |
| 242 | + 'GainControl' => Exif::RATIONAL, # Scene control #p49-50 |
| 243 | + 'Contrast' => Exif::SHORT, # Contrast #p50 |
| 244 | + 'Saturation' => Exif::SHORT, # Saturation #p50 |
| 245 | + 'Sharpness' => Exif::SHORT, # Sharpness #p50 |
| 246 | + 'DeviceSettingDescription' => Exif::UNDEFINED, # Desice settings description |
| 247 | + 'SubjectDistanceRange' => Exif::SHORT, # Subject distance range #p51 |
| 248 | + ), |
221 | 249 | |
222 | | - 'ImageUniqueID' => Exif::ASCII, # Unique image ID |
| 250 | + 'other' => array( |
| 251 | + 'ImageUniqueID' => Exif::ASCII, # Unique image ID |
| 252 | + ), |
223 | 253 | ), |
224 | 254 | |
225 | 255 | # GPS Attribute Information (p52) |
226 | | - 'GPS' => array( |
227 | | - 'GPSVersionID' => array( Exif::BYTE, 4 ), # GPS tag version |
228 | | - 'GPSLatitudeRef' => Exif::ASCII, # North or South Latitude #p52-53 |
229 | | - 'GPSLatitude' => array( Exif::RATIONAL, 3 ), # Latitude |
230 | | - 'GPSLongitudeRef' => Exif::ASCII, # East or West Longitude #p53 |
231 | | - 'GPSLongitude' => array( Exif::RATIONAL, 3), # Longitude |
232 | | - 'GPSAltitudeRef' => Exif::BYTE, # Altitude reference |
233 | | - 'GPSAltitude' => Exif::RATIONAL, # Altitude |
234 | | - 'GPSTimeStamp' => array( Exif::RATIONAL, 3), # GPS time (atomic clock) |
235 | | - 'GPSSatellites' => Exif::ASCII, # Satellites used for measurement |
236 | | - 'GPSStatus' => Exif::ASCII, # Receiver status #p54 |
237 | | - 'GPSMeasureMode' => Exif::ASCII, # Measurement mode #p54-55 |
238 | | - 'GPSDOP' => Exif::RATIONAL, # Measurement precision |
239 | | - 'GPSSpeedRef' => Exif::ASCII, # Speed unit #p55 |
240 | | - 'GPSSpeed' => Exif::RATIONAL, # Speed of GPS receiver |
241 | | - 'GPSTrackRef' => Exif::ASCII, # Reference for direction of movement #p55 |
242 | | - 'GPSTrack' => Exif::RATIONAL, # Direction of movement |
243 | | - 'GPSImgDirectionRef' => Exif::ASCII, # Reference for direction of image #p56 |
244 | | - 'GPSImgDirection' => Exif::RATIONAL, # Direction of image |
245 | | - 'GPSMapDatum' => Exif::ASCII, # Geodetic survey data used |
246 | | - 'GPSDestLatitudeRef' => Exif::ASCII, # Reference for latitude of destination #p56 |
247 | | - 'GPSDestLatitude' => array( Exif::RATIONAL, 3 ), # Latitude destination |
248 | | - 'GPSDestLongitudeRef' => Exif::ASCII, # Reference for longitude of destination #p57 |
249 | | - 'GPSDestLongitude' => array( Exif::RATIONAL, 3 ), # Longitude of destination |
250 | | - 'GPSDestBearingRef' => Exif::ASCII, # Reference for bearing of destination #p57 |
251 | | - 'GPSDestBearing' => Exif::RATIONAL, # Bearing of destination |
252 | | - 'GPSDestDistanceRef' => Exif::ASCII, # Reference for distance to destination #p57-58 |
253 | | - 'GPSDestDistance' => Exif::RATIONAL, # Distance to destination |
254 | | - 'GPSProcessingMethod' => Exif::UNDEFINED, # Name of GPS processing method |
255 | | - 'GPSAreaInformation' => Exif::UNDEFINED, # Name of GPS area |
256 | | - 'GPSDateStamp' => Exif::ASCII, # GPS date |
257 | | - 'GPSDifferential' => Exif::SHORT, # GPS differential correction |
| 256 | + 'gps' => array( |
| 257 | + 'GPSVersionID' => Exif::BYTE, # GPS tag version |
| 258 | + 'GPSLatitudeRef' => Exif::ASCII, # North or South Latitude #p52-53 |
| 259 | + 'GPSLatitude' => Exif::RATIONAL, # Latitude |
| 260 | + 'GPSLongitudeRef' => Exif::ASCII, # East or West Longitude #p53 |
| 261 | + 'GPSLongitude' => Exif::RATIONAL, # Longitude |
| 262 | + 'GPSAltitudeRef' => Exif::BYTE, # Altitude reference |
| 263 | + 'GPSAltitude' => Exif::RATIONAL, # Altitude |
| 264 | + 'GPSTimeStamp' => Exif::RATIONAL, # GPS time (atomic clock) |
| 265 | + 'GPSSatellites' => Exif::ASCII, # Satellites used for measurement |
| 266 | + 'GPSStatus' => Exif::ASCII, # Receiver status #p54 |
| 267 | + 'GPSMeasureMode' => Exif::ASCII, # Measurement mode #p54-55 |
| 268 | + 'GPSDOP' => Exif::RATIONAL, # Measurement precision |
| 269 | + 'GPSSpeedRef' => Exif::ASCII, # Speed unit #p55 |
| 270 | + 'GPSSpeed' => Exif::RATIONAL, # Speed of GPS receiver |
| 271 | + 'GPSTrackRef' => Exif::ASCII, # Reference for direction of movement #p55 |
| 272 | + 'GPSTrack' => Exif::RATIONAL, # Direction of movement |
| 273 | + 'GPSImgDirectionRef' => Exif::ASCII, # Reference for direction of image #p56 |
| 274 | + 'GPSImgDirection' => Exif::RATIONAL, # Direction of image |
| 275 | + 'GPSMapDatum' => Exif::ASCII, # Geodetic survey data used |
| 276 | + 'GPSDestLatitudeRef' => Exif::ASCII, # Reference for latitude of destination #p56 |
| 277 | + 'GPSDestLatitude' => Exif::RATIONAL, # Latitude destination |
| 278 | + 'GPSDestLongitudeRef' => Exif::ASCII, # Reference for longitude of destination #p57 |
| 279 | + 'GPSDestLongitude' => Exif::RATIONAL, # Longitude of destination |
| 280 | + 'GPSDestBearingRef' => Exif::ASCII, # Reference for bearing of destination #p57 |
| 281 | + 'GPSDestBearing' => Exif::RATIONAL, # Bearing of destination |
| 282 | + 'GPSDestDistanceRef' => Exif::ASCII, # Reference for distance to destination #p57-58 |
| 283 | + 'GPSDestDistance' => Exif::RATIONAL, # Distance to destination |
| 284 | + 'GPSProcessingMethod' => Exif::UNDEFINED, # Name of GPS processing method |
| 285 | + 'GPSAreaInformation' => Exif::UNDEFINED, # Name of GPS area |
| 286 | + 'GPSDateStamp' => Exif::ASCII, # GPS date |
| 287 | + 'GPSDifferential' => Exif::SHORT, # GPS differential correction |
258 | 288 | ), |
259 | 289 | ); |
260 | 290 | |
261 | 291 | $this->file = $file; |
262 | 292 | $this->basename = wfBaseName( $this->file ); |
263 | 293 | |
| 294 | + $this->makeFlatExifTags(); |
| 295 | + |
264 | 296 | $this->debugFile( $this->basename, __FUNCTION__, true ); |
265 | 297 | wfSuppressWarnings(); |
266 | | - $data = exif_read_data( $this->file, 0, true ); |
| 298 | + $data = exif_read_data( $this->file ); |
267 | 299 | wfRestoreWarnings(); |
268 | 300 | /** |
269 | 301 | * exif_read_data() will return false on invalid input, such as |
— | — | @@ -270,35 +302,56 @@ |
271 | 303 | * containing random gibberish. |
272 | 304 | */ |
273 | 305 | $this->mRawExifData = $data ? $data : array(); |
| 306 | + |
274 | 307 | $this->makeFilteredData(); |
275 | 308 | $this->makeFormattedData(); |
| 309 | + |
276 | 310 | $this->debugFile( __FUNCTION__, false ); |
277 | 311 | } |
278 | 312 | |
| 313 | + /**#@+ |
| 314 | + * @private |
| 315 | + */ |
279 | 316 | /** |
| 317 | + * Generate a flat list of the exif tags |
| 318 | + */ |
| 319 | + function makeFlatExifTags() { |
| 320 | + $this->extractTags( $this->mExifTags ); |
| 321 | + } |
| 322 | + |
| 323 | + /** |
| 324 | + * A recursing extractor function used by makeFlatExifTags() |
| 325 | + * |
| 326 | + * Note: This used to use an array_walk function, but it made PHP5 |
| 327 | + * segfault, see `cvs diff -u -r 1.4 -r 1.5 Exif.php` |
| 328 | + */ |
| 329 | + function extractTags( &$tagset ) { |
| 330 | + foreach( $tagset as $key => $val ) { |
| 331 | + if( is_array( $val ) ) { |
| 332 | + $this->extractTags( $val ); |
| 333 | + } else { |
| 334 | + $this->mFlatExifTags[$key] = $val; |
| 335 | + } |
| 336 | + } |
| 337 | + } |
| 338 | + |
| 339 | + /** |
280 | 340 | * Make $this->mFilteredExifData |
281 | 341 | */ |
282 | 342 | function makeFilteredData() { |
283 | 343 | $this->mFilteredExifData = $this->mRawExifData; |
284 | 344 | |
285 | | - foreach( array_keys( $this->mFilteredExifData ) as $section ) { |
286 | | - if ( !in_array( $section, array_keys( $this->mExifTags ) ) ) { |
287 | | - $this->debug( $section , __FUNCTION__, "'$section' is not a valid Exif section" ); |
288 | | - unset( $this->mFilteredExifData[$section] ); |
289 | | - continue; |
| 345 | + foreach( $this->mFilteredExifData as $k => $v ) { |
| 346 | + if ( !in_array( $k, array_keys( $this->mFlatExifTags ) ) ) { |
| 347 | + $this->debug( $v, __FUNCTION__, "'$k' is not a valid Exif tag" ); |
| 348 | + unset( $this->mFilteredExifData[$k] ); |
290 | 349 | } |
| 350 | + } |
291 | 351 | |
292 | | - foreach( array_keys( $this->mFilteredExifData[$section] ) as $tag ) { |
293 | | - if ( !in_array( $tag, array_keys( $this->mExifTags[$section] ) ) ) { |
294 | | - $this->debug( $tag, __FUNCTION__, "'$tag' is not a valid tag in '$section'" ); |
295 | | - unset( $this->mFilteredExifData[$section][$tag] ); |
296 | | - continue; |
297 | | - } |
298 | | - $value = $this->mFilteredExifData[$section][$tag]; |
299 | | - if( !$this->validate( $section, $tag, $value ) ) { |
300 | | - $this->debug( $value, __FUNCTION__, "'$tag' contained invalid data" ); |
301 | | - unset( $this->mFilteredExifData[$section][$tag] ); |
302 | | - } |
| 352 | + foreach( $this->mFilteredExifData as $k => $v ) { |
| 353 | + if ( !$this->validate($k, $v) ) { |
| 354 | + $this->debug( $v, __FUNCTION__, "'$k' contained invalid data" ); |
| 355 | + unset( $this->mFilteredExifData[$k] ); |
303 | 356 | } |
304 | 357 | } |
305 | 358 | } |
— | — | @@ -350,7 +403,7 @@ |
351 | 404 | * @return int |
352 | 405 | */ |
353 | 406 | public static function version() { |
354 | | - return 2; // We don't need no bloddy constants! |
| 407 | + return 1; // We don't need no bloddy constants! |
355 | 408 | } |
356 | 409 | |
357 | 410 | /**#@+ |
— | — | @@ -454,36 +507,15 @@ |
455 | 508 | * Validates if a tag has a legal value according to the Exif spec |
456 | 509 | * |
457 | 510 | * @private |
458 | | - * @param $section String: section where tag is located. |
| 511 | + * |
459 | 512 | * @param $tag String: the tag to check. |
460 | 513 | * @param $val Mixed: the value of the tag. |
461 | | - * @param $recursive Boolean: true if called recursively for array types. |
462 | 514 | * @return bool |
463 | 515 | */ |
464 | | - function validate( $section, $tag, $val, $recursive = false ) { |
| 516 | + function validate( $tag, $val ) { |
465 | 517 | $debug = "tag is '$tag'"; |
466 | | - $etype = $this->mExifTags[$section][$tag]; |
467 | | - $ecount = 1; |
468 | | - if( is_array( $etype ) ) { |
469 | | - list( $etype, $ecount ) = $etype; |
470 | | - if ( $recursive ) |
471 | | - $ecount = 1; // checking individual elements |
472 | | - } |
473 | | - $count = count( $val ); |
474 | | - if( $ecount != $count ) { |
475 | | - $this->debug( $val, __FUNCTION__, "Expected $ecount elements for $tag but got $count" ); |
476 | | - return false; |
477 | | - } |
478 | | - if( $count > 1 ) { |
479 | | - foreach( $val as $v ) { |
480 | | - if( !$this->validate( $section, $tag, $v, true ) ) { |
481 | | - return false; |
482 | | - } |
483 | | - } |
484 | | - return true; |
485 | | - } |
486 | 518 | // Does not work if not typecast |
487 | | - switch( (string)$etype ) { |
| 519 | + switch( (string)$this->mFlatExifTags[$tag] ) { |
488 | 520 | case (string)Exif::BYTE: |
489 | 521 | $this->debug( $val, __FUNCTION__, $debug ); |
490 | 522 | return $this->isByte( $val ); |
— | — | @@ -601,12 +633,11 @@ |
602 | 634 | function getFormattedData() { |
603 | 635 | global $wgLang; |
604 | 636 | |
605 | | - $sections =& $this->mExif; |
| 637 | + $tags =& $this->mExif; |
606 | 638 | |
607 | | - $resolutionunit = !isset( $sections['IFD0']['ResolutionUnit'] ) || $sections['IFD0']['ResolutionUnit'] == 2 ? 2 : 3; |
608 | | - unset( $sections['IFD0']['ResolutionUnit'] ); |
| 639 | + $resolutionunit = !isset( $tags['ResolutionUnit'] ) || $tags['ResolutionUnit'] == 2 ? 2 : 3; |
| 640 | + unset( $tags['ResolutionUnit'] ); |
609 | 641 | |
610 | | - foreach( $sections as $section => &$tags ) { |
611 | 642 | foreach( $tags as $tag => $val ) { |
612 | 643 | switch( $tag ) { |
613 | 644 | case 'Compression': |
— | — | @@ -672,7 +703,7 @@ |
673 | 704 | break; |
674 | 705 | |
675 | 706 | // TODO: YCbCrCoefficients #p27 (see annex E) |
676 | | - case 'ExifVersion': case 'FlashPixVersion': |
| 707 | + case 'ExifVersion': case 'FlashpixVersion': |
677 | 708 | $tags[$tag] = "$val"/100; |
678 | 709 | break; |
679 | 710 | |
— | — | @@ -936,24 +967,6 @@ |
937 | 968 | } |
938 | 969 | break; |
939 | 970 | |
940 | | - case 'GPSAltitudeRef': |
941 | | - switch( $val ) { |
942 | | - case 0: case 1: |
943 | | - $tags[$tag] = $this->msg( 'GPSAltitude', $val ); |
944 | | - break; |
945 | | - default: |
946 | | - $tags[$tag] = $val; |
947 | | - break; |
948 | | - } |
949 | | - break; |
950 | | - |
951 | | - case 'GPSLatitude': |
952 | | - case 'GPSDestLatitude': |
953 | | - case 'GPSLongitude': |
954 | | - case 'GPSDestLongitude': |
955 | | - $tags[$tag] = $this->formatCoords( $val ); |
956 | | - break; |
957 | | - |
958 | 971 | case 'GPSStatus': |
959 | 972 | switch( $val ) { |
960 | 973 | case 'A': case 'V': |
— | — | @@ -977,6 +990,7 @@ |
978 | 991 | break; |
979 | 992 | |
980 | 993 | case 'GPSSpeedRef': |
| 994 | + case 'GPSDestDistanceRef': |
981 | 995 | switch( $val ) { |
982 | 996 | case 'K': case 'M': case 'N': |
983 | 997 | $tags[$tag] = $this->msg( 'GPSSpeed', $val ); |
— | — | @@ -987,17 +1001,6 @@ |
988 | 1002 | } |
989 | 1003 | break; |
990 | 1004 | |
991 | | - case 'GPSDestDistanceRef': |
992 | | - switch( $val ) { |
993 | | - case 'K': case 'M': case 'N': |
994 | | - $tags[$tag] = $this->msg( 'GPSDestDistance', $val ); |
995 | | - break; |
996 | | - default: |
997 | | - $tags[$tag] = $val; |
998 | | - break; |
999 | | - } |
1000 | | - break; |
1001 | | - |
1002 | 1005 | case 'GPSTrackRef': |
1003 | 1006 | case 'GPSImgDirectionRef': |
1004 | 1007 | case 'GPSDestBearingRef': |
— | — | @@ -1045,9 +1048,8 @@ |
1046 | 1049 | break; |
1047 | 1050 | } |
1048 | 1051 | } |
1049 | | - } |
1050 | 1052 | |
1051 | | - return $this->mExif; |
| 1053 | + return $tags; |
1052 | 1054 | } |
1053 | 1055 | |
1054 | 1056 | /** |
— | — | @@ -1070,7 +1072,7 @@ |
1071 | 1073 | |
1072 | 1074 | /** |
1073 | 1075 | * Format a number, convert numbers from fractions into floating point |
1074 | | - * numbers, joins arrays of numbers with commas. |
| 1076 | + * numbers |
1075 | 1077 | * |
1076 | 1078 | * @private |
1077 | 1079 | * |
— | — | @@ -1078,15 +1080,7 @@ |
1079 | 1081 | * @return mixed A floating point number or whatever we were fed |
1080 | 1082 | */ |
1081 | 1083 | function formatNum( $num ) { |
1082 | | - global $wgLang; |
1083 | 1084 | $m = array(); |
1084 | | - if( is_array($num) ) { |
1085 | | - $out = array(); |
1086 | | - foreach( $num as $number ) { |
1087 | | - $out[] = $this->formatNum($number); |
1088 | | - } |
1089 | | - return $wgLang->commaList( $out ); |
1090 | | - } |
1091 | 1085 | if ( preg_match( '/^(\d+)\/(\d+)$/', $num, $m ) ) |
1092 | 1086 | return $wgLang->formatNum( $m[2] != 0 ? $m[1] / $m[2] : $num ); |
1093 | 1087 | else |
— | — | @@ -1141,29 +1135,6 @@ |
1142 | 1136 | } |
1143 | 1137 | return $a; |
1144 | 1138 | } |
1145 | | - |
1146 | | - /** |
1147 | | - * Format a coordinate value, convert numbers from fractions |
1148 | | - * into floating point numbers, . |
1149 | | - * |
1150 | | - * @private |
1151 | | - * |
1152 | | - * @param $coords Array: degrees, minutes and seconds |
1153 | | - * @param $ref String: reference direction (N/S/E/W), optional |
1154 | | - * @return mixed A floating point number or whatever we were fed |
1155 | | - */ |
1156 | | - function formatCoords( $coords, $ref = null ) { |
1157 | | - list($deg, $min, $sec) = $coords; |
1158 | | - $deg = $this->formatNum($deg); |
1159 | | - $min = $this->formatNum($min); |
1160 | | - $sec = $this->formatNum($sec); |
1161 | | - $out = $deg . "°"; |
1162 | | - if ($min) $out .= " " . $min . "'"; |
1163 | | - if ($sec) $out .= " " . $sec . '"'; |
1164 | | - if ($ref) $out .= " " . $ref; |
1165 | | - return $out; |
1166 | | - } |
1167 | | - |
1168 | 1139 | } |
1169 | 1140 | |
1170 | 1141 | /** |
Index: trunk/phase3/includes/media/Bitmap.php |
— | — | @@ -320,32 +320,20 @@ |
321 | 321 | if ( !$exif ) { |
322 | 322 | return false; |
323 | 323 | } |
324 | | - if ( !isset( $exif['MEDIAWIKI_EXIF_VERSION'] ) || |
325 | | - $exif['MEDIAWIKI_EXIF_VERSION'] != Exif::version() ) |
326 | | - { |
327 | | - // XXX: This should be caught by isMetadataValid(), but |
328 | | - // some non-local repos might call this function without |
329 | | - // checking validity, causing FormatExif to barf, so we |
330 | | - // check it again just to be sure. |
331 | | - wfDebug( __METHOD__.": wrong version\n" ); |
332 | | - return false; |
333 | | - } |
334 | 324 | unset( $exif['MEDIAWIKI_EXIF_VERSION'] ); |
335 | 325 | $format = new FormatExif( $exif ); |
336 | 326 | |
337 | 327 | $formatted = $format->getFormattedData(); |
338 | 328 | // Sort fields into visible and collapsed |
339 | 329 | $visibleFields = $this->visibleMetadataFields(); |
340 | | - foreach ( $formatted as $section => $tags ) { |
341 | | - foreach ( $tags as $name => $value ) { |
342 | | - $tag = strtolower( $name ); |
343 | | - self::addMeta( $result, |
344 | | - in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed', |
345 | | - 'exif', |
346 | | - $tag, |
347 | | - $value |
348 | | - ); |
349 | | - } |
| 330 | + foreach ( $formatted as $name => $value ) { |
| 331 | + $tag = strtolower( $name ); |
| 332 | + self::addMeta( $result, |
| 333 | + in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed', |
| 334 | + 'exif', |
| 335 | + $tag, |
| 336 | + $value |
| 337 | + ); |
350 | 338 | } |
351 | 339 | return $result; |
352 | 340 | } |
Index: trunk/phase3/languages/messages/MessagesEn.php |
— | — | @@ -3580,26 +3580,17 @@ |
3581 | 3581 | 'exif-gpslongitude-e' => 'East longitude', |
3582 | 3582 | 'exif-gpslongitude-w' => 'West longitude', |
3583 | 3583 | |
3584 | | -# Pseudotags used for GPSAltitudeRef |
3585 | | -'exif-gpsaltitude-0' => 'Meters above sea level', |
3586 | | -'exif-gpsaltitude-1' => 'Meters below sea level', |
3587 | | - |
3588 | 3584 | 'exif-gpsstatus-a' => 'Measurement in progress', |
3589 | 3585 | 'exif-gpsstatus-v' => 'Measurement interoperability', |
3590 | 3586 | |
3591 | 3587 | 'exif-gpsmeasuremode-2' => '2-dimensional measurement', |
3592 | 3588 | 'exif-gpsmeasuremode-3' => '3-dimensional measurement', |
3593 | 3589 | |
3594 | | -# Pseudotags used for GPSSpeedRef |
| 3590 | +# Pseudotags used for GPSSpeedRef and GPSDestDistanceRef |
3595 | 3591 | 'exif-gpsspeed-k' => 'Kilometers per hour', |
3596 | 3592 | 'exif-gpsspeed-m' => 'Miles per hour', |
3597 | 3593 | 'exif-gpsspeed-n' => 'Knots', |
3598 | 3594 | |
3599 | | -# Pseudotags used for GPSDestDistanceRef |
3600 | | -'exif-gpsdestdistance-k' => 'Kilometers', |
3601 | | -'exif-gpsdestdistance-m' => 'Miles', |
3602 | | -'exif-gpsdestdistance-n' => 'Nautical miles', |
3603 | | - |
3604 | 3595 | # Pseudotags used for GPSTrackRef, GPSImgDirectionRef and GPSDestBearingRef |
3605 | 3596 | 'exif-gpsdirection-t' => 'True direction', |
3606 | 3597 | 'exif-gpsdirection-m' => 'Magnetic direction', |