Index: branches/img_metadata/phase3/includes/Exif.php |
— | — | @@ -37,6 +37,7 @@ |
38 | 38 | const UNDEFINED = 7; //!< An 8-bit byte that can take any value depending on the field definition |
39 | 39 | const SLONG = 9; //!< A 32-bit (4-byte) signed integer (2's complement notation), |
40 | 40 | const SRATIONAL = 10; //!< Two SLONGs. The first SLONG is the numerator and the second SLONG is the denominator. |
| 41 | + const IGNORE = -1; // A fake value for things we don't want or don't support. |
41 | 42 | |
42 | 43 | //@{ |
43 | 44 | /* @var array |
— | — | @@ -96,9 +97,7 @@ |
97 | 98 | * |
98 | 99 | * @param $file String: filename. |
99 | 100 | * @fixme the following are broke: |
100 | | - * SubjectArea, ExifVersion, Flashpix Version (probably any Exif:Undefined with non 1 count) |
101 | | - * SceneType, FileSource, MakerNote (we really don't want makerNote though), |
102 | | - * ComponenentsConfiguration, and possibly others pending better testing. |
| 101 | + * SubjectArea, GPSAltitudeRef, possibly more, need more testing. |
103 | 102 | * |
104 | 103 | * DigitalZoomRatio = 0/0 is rejected. need to determine if thats valid. |
105 | 104 | * possibly should treat 0/0 = 0. need to read exif spec on that. |
— | — | @@ -107,6 +106,9 @@ |
108 | 107 | /** |
109 | 108 | * Page numbers here refer to pages in the EXIF 2.2 standard |
110 | 109 | * |
| 110 | + * Note, Exif::UNDEFINED is treated as a string, not as an array of bytes |
| 111 | + * so don't put a count parameter for any UNDEFINED values. |
| 112 | + * |
111 | 113 | * @link http://exif.org/Exif2-2.PDF The Exif 2.2 specification |
112 | 114 | */ |
113 | 115 | $this->mExifTags = array( |
— | — | @@ -157,20 +159,20 @@ |
158 | 160 | 'EXIF' => array( |
159 | 161 | # TODO: NOTE: Nonexistence of this field is taken to mean nonconformance |
160 | 162 | # to the EXIF 2.1 AND 2.2 standards |
161 | | - 'ExifVersion' => array( Exif::UNDEFINED, 4 ), # Exif version |
162 | | - 'FlashPixVersion' => array( Exif::UNDEFINED, 4 ), # Supported Flashpix version #p32 |
| 163 | + 'ExifVersion' => Exif::UNDEFINED, # Exif version |
| 164 | + 'FlashPixVersion' => Exif::UNDEFINED, # Supported Flashpix version #p32 |
163 | 165 | |
164 | 166 | # Tags relating to Image Data Characteristics |
165 | 167 | 'ColorSpace' => Exif::SHORT, # Color space information #p32 |
166 | 168 | |
167 | 169 | # Tags relating to image configuration |
168 | | - 'ComponentsConfiguration' => array( Exif::UNDEFINED, 1), # Meaning of each component #p33 |
| 170 | + 'ComponentsConfiguration' => Exif::UNDEFINED, # Meaning of each component #p33 |
169 | 171 | 'CompressedBitsPerPixel' => Exif::RATIONAL, # Image compression mode |
170 | 172 | 'PixelYDimension' => Exif::SHORT.','.Exif::LONG, # Valid image width |
171 | 173 | 'PixelXDimension' => Exif::SHORT.','.Exif::LONG, # Valid image height |
172 | 174 | |
173 | 175 | # Tags relating to related user information |
174 | | - 'MakerNote' => Exif::UNDEFINED, # Manufacturer notes |
| 176 | + 'MakerNote' => Exif::IGNORE, # Manufacturer notes |
175 | 177 | 'UserComment' => Exif::UNDEFINED, # User comments #p34 |
176 | 178 | |
177 | 179 | # Tags relating to related file information |
— | — | @@ -189,7 +191,7 @@ |
190 | 192 | 'ExposureProgram' => Exif::SHORT, # Exposure Program #p38 |
191 | 193 | 'SpectralSensitivity' => Exif::ASCII, # Spectral sensitivity |
192 | 194 | 'ISOSpeedRatings' => Exif::SHORT, # ISO speed rating |
193 | | - 'OECF' => Exif::UNDEFINED, # Optoelectronic conversion factor |
| 195 | + 'OECF' => Exif::IGNORE, # Optoelectronic conversion factor. Note: We don't have support for this atm. |
194 | 196 | 'ShutterSpeedValue' => Exif::SRATIONAL, # Shutter speed |
195 | 197 | 'ApertureValue' => Exif::RATIONAL, # Aperture |
196 | 198 | 'BrightnessValue' => Exif::SRATIONAL, # Brightness |
— | — | @@ -202,7 +204,7 @@ |
203 | 205 | 'FocalLength' => Exif::RATIONAL, # Lens focal length |
204 | 206 | 'SubjectArea' => array( Exif::SHORT, 4 ), # Subject area |
205 | 207 | 'FlashEnergy' => Exif::RATIONAL, # Flash energy |
206 | | - 'SpatialFrequencyResponse' => Exif::UNDEFINED, # Spatial frequency response |
| 208 | + 'SpatialFrequencyResponse' => Exif::IGNORE, # Spatial frequency response. Not supported atm. |
207 | 209 | 'FocalPlaneXResolution' => Exif::RATIONAL, # Focal plane X resolution |
208 | 210 | 'FocalPlaneYResolution' => Exif::RATIONAL, # Focal plane Y resolution |
209 | 211 | 'FocalPlaneResolutionUnit' => Exif::SHORT, # Focal plane resolution unit #p46 |
— | — | @@ -211,7 +213,7 @@ |
212 | 214 | 'SensingMethod' => Exif::SHORT, # Sensing method #p46 |
213 | 215 | 'FileSource' => Exif::UNDEFINED, # File source #p47 |
214 | 216 | 'SceneType' => Exif::UNDEFINED, # Scene type #p47 |
215 | | - 'CFAPattern' => Exif::UNDEFINED, # CFA pattern |
| 217 | + 'CFAPattern' => Exif::IGNORE, # CFA pattern. not supported atm. |
216 | 218 | 'CustomRendered' => Exif::SHORT, # Custom image processing #p48 |
217 | 219 | 'ExposureMode' => Exif::SHORT, # Exposure mode #p48 |
218 | 220 | 'WhiteBalance' => Exif::SHORT, # White Balance #p49 |
— | — | @@ -222,7 +224,7 @@ |
223 | 225 | 'Contrast' => Exif::SHORT, # Contrast #p50 |
224 | 226 | 'Saturation' => Exif::SHORT, # Saturation #p50 |
225 | 227 | 'Sharpness' => Exif::SHORT, # Sharpness #p50 |
226 | | - 'DeviceSettingDescription' => Exif::UNDEFINED, # Desice settings description |
| 228 | + 'DeviceSettingDescription' => Exif::IGNORE, # Desice settings description. FIXME: this could maybe be supported. |
227 | 229 | 'SubjectDistanceRange' => Exif::SHORT, # Subject distance range #p51 |
228 | 230 | |
229 | 231 | 'ImageUniqueID' => Exif::ASCII, # Unique image ID |
— | — | @@ -346,8 +348,90 @@ |
347 | 349 | unset( $this->mFilteredExifData ); |
348 | 350 | } |
349 | 351 | |
| 352 | + $this->toHex( 'FileSource', true ); |
| 353 | + $this->toHex( 'SceneType', true ); |
| 354 | + |
| 355 | + $this->charCodeString( 'UserComment' ); |
| 356 | + $this->charCodeString( 'GPSProcessingMethod'); |
| 357 | + $this->charCodeString( 'GPSAreaInformation' ); |
| 358 | + |
| 359 | + //ComponentsConfiguration should really be an array instead of a string... |
| 360 | + if ( isset ( $this->mFilteredExifData['ComponentsConfiguration'] ) ) { |
| 361 | + $val = $this->mFilteredExifData['ComponentsConfiguration']; |
| 362 | + $ccVals = array(); |
| 363 | + for ($i = 0; $i < strlen($val); $i++) { |
| 364 | + $ccVals[$i] = ord( substr($val, $i, 1) ); |
| 365 | + } |
| 366 | + $ccVals['_type'] = 'ol'; //this is for formatting later. |
| 367 | + $this->mFilteredExifData['ComponentsConfiguration'] = $ccVals; |
| 368 | + } |
| 369 | + |
350 | 370 | } |
351 | 371 | /** |
| 372 | + * do userComment and similar. pg. 34 of exif standard. |
| 373 | + * basically first 8 bytes is charset, rest is value. |
| 374 | + * Needs more testing, as its unclear from exif standard if they mean |
| 375 | + * utf-8, utf-16, or something else by 'unicode'. |
| 376 | + * @param $prop String prop name. |
| 377 | + * @todo this is in need of testing. |
| 378 | + */ |
| 379 | + function charCodeString ( $prop ) { |
| 380 | + if ( isset( $this->mFilteredExifData[$prop] ) ) { |
| 381 | + |
| 382 | + if ( strlen($this->mFilteredExifData[$prop]) <= 8 ) { |
| 383 | + //invalid. Must be at least 9 bytes long. |
| 384 | + |
| 385 | + $this->debug( $this->mFilteredExifData[$prop] , __FUNCTION__, false ); |
| 386 | + unset($this->mFilteredExifData[$prop]); |
| 387 | + return; |
| 388 | + } |
| 389 | + |
| 390 | + $charCode = substr( $this->mFilteredExifData[$prop], 0, 8); |
| 391 | + $val = substr( $this->mFilteredExifData[$prop], 8); |
| 392 | + |
| 393 | + |
| 394 | + switch ($charCode) { |
| 395 | + case "\x4A\x49\x53\x00\x00\x00\x00\x00": |
| 396 | + //JIS |
| 397 | + $val = iconv("Shift-JIS", "UTF-8//IGNORE", $val); |
| 398 | + break; |
| 399 | + default: //unicode or undefined. leave as is. |
| 400 | + break; |
| 401 | + } |
| 402 | + |
| 403 | + //trim and check to make sure not only whitespace. |
| 404 | + $val = trim($val); |
| 405 | + if ( strlen( $val ) === 0 ) { |
| 406 | + //only whitespace. |
| 407 | + $this->debug( $this->mFilteredExifData[$prop] , __FUNCTION__, "$prop: Is only whitespace" ); |
| 408 | + unset($this->mFilteredExifData[$prop]); |
| 409 | + return; |
| 410 | + } |
| 411 | + |
| 412 | + //all's good. |
| 413 | + $this->mFilteredData[$prop] = $val; |
| 414 | + } |
| 415 | + } |
| 416 | + /** |
| 417 | + * Convert an Exif::UNDEFINED from a raw binary string |
| 418 | + * to a hex string. This is sometimes needed depending on |
| 419 | + * the type of UNDEFINED field |
| 420 | + * @param $prop String name of property |
| 421 | + * @param $stripLeadingZero boolean should it strip first leading zero |
| 422 | + * if present on result (bit of a hack). |
| 423 | + */ |
| 424 | + function toHex ( $prop, $stripLeadingZero = false ) { |
| 425 | + if ( isset( $this->mFilteredExifData[$prop] ) ) { |
| 426 | + $val = bin2hex( $this->mFilteredExifData[$prop] ); |
| 427 | + if ( $stripLeadingZero ) { |
| 428 | + if (substr( $val, 0, 1) === '0') { |
| 429 | + $val = substr( $val, 1); |
| 430 | + } |
| 431 | + } |
| 432 | + $this->mFilteredExifData[$prop] = $val; |
| 433 | + } |
| 434 | + } |
| 435 | + /** |
352 | 436 | * Convert gps in exif form to a single floating point number |
353 | 437 | * for example 10 degress 20`40`` S -> -10.34444 |
354 | 438 | * @param String $prop a gps coordinate exif tag name (like GPSLongitude) |
— | — | @@ -498,6 +582,13 @@ |
499 | 583 | } |
500 | 584 | |
501 | 585 | function isUndefined( $in ) { |
| 586 | + |
| 587 | + $this->debug( $in, __FUNCTION__, true ); |
| 588 | + return true; |
| 589 | + |
| 590 | + /* Exif::UNDEFINED means string of bytes |
| 591 | + so this validation does not make sense. |
| 592 | + comment out for now. |
502 | 593 | if ( !is_array( $in ) && preg_match( '/^\d{4}$/', $in ) ) { // Allow ExifVersion and FlashpixVersion |
503 | 594 | $this->debug( $in, __FUNCTION__, true ); |
504 | 595 | return true; |
— | — | @@ -505,6 +596,7 @@ |
506 | 597 | $this->debug( $in, __FUNCTION__, false ); |
507 | 598 | return false; |
508 | 599 | } |
| 600 | + */ |
509 | 601 | } |
510 | 602 | |
511 | 603 | function isSlong( $in ) { |
— | — | @@ -589,6 +681,9 @@ |
590 | 682 | case (string)Exif::SHORT.','.Exif::LONG: |
591 | 683 | $this->debug( $val, __FUNCTION__, $debug ); |
592 | 684 | return $this->isShort( $val ) || $this->isLong( $val ); |
| 685 | + case (string)Exif::IGNORE: |
| 686 | + $this->debug( $val, __FUNCTION__, $debug ); |
| 687 | + return false; |
593 | 688 | default: |
594 | 689 | $this->debug( $val, __FUNCTION__, "The tag '$tag' is unknown" ); |
595 | 690 | return false; |