Branch: Tag:

2002-10-08

2002-10-08 14:04:10 by Martin Nilsson <mani@lysator.liu.se>

Better EXIF support. Some API changes: get_properties only accepts Stdio.File objects. MN_Multi1 is renamed to MN_Multi3.

Rev: lib/modules/Standards.pmod/EXIF.pmod:1.12

3:   //! This module implements EXIF (Exchangeable image file format for Digital Still Cameras) 2.1   //! parsing.    - // $Id: EXIF.pmod,v 1.11 2002/09/24 20:22:56 nilsson Exp $ + // $Id: EXIF.pmod,v 1.12 2002/10/08 14:04:10 nilsson Exp $   // Johan Schön <js@roxen.com>, July 2001.   // Based on Exiftool by Robert F. Tobler <rft@cg.tuwien.ac.at>.   //
11:   // http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html   // http://www.pima.net/standards/it10/PIMA15740/exif.htm    - void add_field(mapping m, string field, mapping alts, mixed index) + void add_field(mapping m, string field, +  mapping|array alts, +  array(int) from, int index)   { -  +  if(index>sizeof(from)) +  return; +  index = from[index]; +  if(mappingp(alts)) {    if(alts[index])    m[field]=alts[index]; -  +  else +  m["failed "+field]=index;    } -  +  else { +  if(index<sizeof(alts)) +  m[field]=alts[index]; +  else +  m["failed "+field]=index; +  } + }    - mapping canon_d30_multi0(array(int) data) + #define SIZETEST(X) if(sizeof(data)<(X)+1) return res + mapping canon_multi0(array(int) data)   {    mapping res=([]); -  +     add_field(res, "CanonMacroMode",    ([1: "Macro", 2: "Normal"]), -  data[1]); +  data, 1);    -  +  SIZETEST(2);    if(data[2])    res->CanonSelfTimerLength = sprintf("%.1f s", data[2]/10.0);       add_field(res, "CanonQuality", -  ([2: "Normal", 3: "Fine", 4: "Superfine"]), -  data[3]); +  ([2: "Normal", 3: "Fine", 4: "Superfine", 5: "Superfine"]), +  data, 3);       add_field(res, "CanonFlashMode",    ([0: "Flash not fired",
40:    5: "Auto + red-eye reduction",    6: "On + red-eye reduction",    16: "External flash", ]), -  data[4]); +  data, 4);       add_field(res, "CanonDriveMode", -  ([0:"Single", 1:"Continuous"]), -  data[5]); +  ({"Single", "Continuous"}), +  data, 5);       add_field(res, "CanonFocusMode", -  ([ 0: "One-Shot", -  1: "AI Servo", -  2: "AI Focus", -  3: "MF", -  4: "Single", -  5: "Continuous", -  6: "MF", ]), -  data[7]); +  ({ "One-Shot", "AI Servo", +  "AI Focus", "MF", "Single", +  "Continuous", "MF" }), +  data, 7);       add_field(res, "CanonImageSize", -  ([0: "Large", 1: "Medium", 2: "Small"]), -  data[10]); +  ({ "Large", "Medium", "Small" }), +  data, 10);       add_field(res, "CanonShootingMode", -  ([ 0: "Full Auto", -  1: "Manual", -  2: "Landscape", -  3: "Fast Shutter", -  4: "Slow Shutter", -  5: "Night", -  6: "B&W", -  7: "Sepia", -  8: "Portrait", -  9: "Sports", -  10: "Macro / Close-Up", -  11: "Pan Focus"]), -  data[11]); +  ({ "Full Auto", "Manual", +  "Landscape", "Fast Shutter", +  "Slow Shutter", "Night", +  "B&W", "Sepia", "Portrait", +  "Sports", "Macro / Close-Up", +  "Pan Focus" }), +  data, 11);       add_field(res, "CanonDigitalZoom", -  ([0: "None", 1: "2X", 2: "4X"]), -  data[12]); +  ({ "None", "2X", "4X" }), +  data, 12);       add_field(res, "CanonContrast",    ([0xffff:"Low", 0x0000:"Normal", 0x0001: "High"]), -  data[13]); +  data, 13); +     add_field(res, "CanonSaturation",    ([0xffff:"Low", 0x0000:"Normal", 0x0001: "High"]), -  data[14]); +  data, 14); +     add_field(res, "CanonSharpness",    ([0xffff:"Low", 0x0000:"Normal", 0x0001: "High"]), -  data[15]); +  data, 15);       add_field(res, "CanonISO", -  ([15: "Auto", 16: "50", 17: "100", 18: "200", 19: "400"]), -  data[16]); +  ([ 0:"100", 1:"200", 2:"400", +  15:"Auto", 16:"50", 17:"100", 18:"200", 19:"400"]), +  data, 16);       add_field(res, "CanonMeteringMode", -  ([3: "Evaluative", 4: "Partial", 5: "Center-weighted"]), -  data[17]); +  ([ 0:"Central importance", 1:"Spot", +  3:"Evaluative", 4:"Partial", 5:"Center-weighted" ]), +  data, 17);       add_field(res, "CanonFocusType",    ([0: "Manual", 1: "Auto", 3: "Close-up (macro)",    8: "Locked (pan mode)"]), -  data[18]); +  data, 18);       add_field(res, "CanonAutoFocusPointSelected",    ([0x3000: "None (MF)",
108:    0x3002: "Right",    0x3003: "Center",    0x3004: "Left"]), -  data[19]); +  data, 19);       add_field(res, "CanonExposureMode", -  ([0: "Easy shooting", -  1: "Program", -  2: "Tv-priority", -  3: "Av-priority", -  4: "Manual", -  5: "A-DEP"]), -  data[20]); +  ({ "Easy shooting", "Program", +  "Tv-priority", "Av-priority", +  "Manual", "A-DEP" }), +  data, 20);    -  +  SIZETEST(25);    float unit=(float)data[25];    res->CanonLensFocalLengthRange=sprintf("%.0f-%.0f mm", data[24]/unit, data[23]/unit);       add_field(res, "CanonFlashActivity", -  ([0: "Did not fire", 1: "Fired"]), data[28]); +  ({ "Did not fire", "Fired" }), data, 28);    -  +  SIZETEST(29);    array flashdetails=({});    if(data[29] & 1<<14)    flashdetails+=({"External E-TTL"});
141:    res->CanonFlashDetails=flashdetails*", ";    else    res->CanonFlashDetails="No flash"; +  +  add_field(res, "CanonFocusMode", +  ({ "Single", "Continuous" }), data, 32); +     return res;   }    - mapping canon_d30_multi1(array(int) data) + mapping canon_multi1(array(int) data) { +  mapping res = ([]); +  +  SIZETEST(1); +  if(data[1]) res->CanonFocalLength = data[1]/32.0; +  return res; + } +  + mapping canon_multi3(array(int) data)   {    mapping res=([]);    -  +  SIZETEST(6); +  if(data[6]) { +  float v = 0.0; +  if(data[6]<65) +  v = v/32.0; +  else +  v = (0x10000-data[6])/32.0; +  res->CanonFlashBias = sprintf("%s%1.2f EV", (v>0?"+":""), v); +  } +     add_field(res, "CanonWhiteBalance", -  ([ 0:"Auto", -  1:"Sunny", -  2:"Cloudy", -  3:"Tungsten", -  4:"Flourescent", -  5:"Flash", -  6:"Custom"]), data[7]); +  ({ "Auto", "Sunny", "Cloudy", +  "Tungsten", "Flourescent", "Flash", +  "Custom" }), data, 7);    -  +  SIZETEST(9);    res->CanonBurstSequenceNumber=(string)data[9]; - // res->CanonAutoFocusPoint=sprintf("%b",data[14]); -  mapping flashbias= +  +  SIZETEST(10); +  res->CanonOpticalZoon=(string)data[10]; +  +  SIZETEST(14); +  if(data[14]) { +  res->CanonAutoFocusPoint = ([ +  0:"Right", +  1:"Center", +  2:"Left" ])[ data[14]&3 ]; +  res->CanonAutoFocusPoints = (string)( data[14]>>11 ); +  } +  +  add_field(res, "CanonFlashBias",    ([ 0xffc0: "-2 EV",    0xffcc: "-1.67 EV",    0xffd0: "-1.50 EV",
176:    0x002c: "+1.33 EV",    0x0030: "+1.50 EV",    0x0034: "+1.67 EV", -  0x0040: "+2 EV" ]); -  if(flashbias[data[15]]) -  res->CanonFlashBias=flashbias[data[15]]; +  0x0040: "+2 EV" ]), +  data, 15); +  +  SIZETEST(19);    res->CanonSubjectDistance=sprintf("%.2f",data[19]/100.0);    return res;   }    -  + mapping canon_multi4(array(int) data) { +  mapping res = ([]); +  add_field(res, "CanonStichDirection", +  ({ "Left to right", "Right to left", "Bottom to top", "Top to bottom" }), +  data, 5); +  return res; + } +  + mapping CANON_D30_MAKERNOTE = ([ +  0x0001: ({"MN_Multi0", "CUSTOM", canon_multi0 }), +  0x0002: ({"MN_Multi1", "CUSTOM", canon_multi1 }), +  0x0004: ({"MN_Multi3", "CUSTOM", canon_multi3 }), +  0x0005: ({"MN_Multi4", "CUSTOM", canon_multi4 }), +  0x0006: ({"MN_ImageType", 0, ([]) }), +  0x0007: ({"MN_FirmwareVersion", 0, ([]) }), +  0x0008: ({"MN_ImageNumber", 0, ([]) }), +  0x0009: ({"MN_OwnerName", 0, ([]) }), +  0x000C: ({"MN_CameraSerialNumber", 0, ([]) }), +  // 0x000F: ({"MN_CustomFunctions", "CUSTOM", canon_custom }), + ]); +  + mapping nikon_iso(array(int) data) { +  mapping res=([]); +  +  SIZETEST(1); +  if(data[1]) res->NikonISOSetting = "ISO"+data[1]; +  return res; + } +  + // NIKON 990, D1 (more?)   mapping NIKON_990_MAKERNOTE = ([    0x0001: ({"MN_0x0001", 0, ([]) }), -  0x0002: ({"MN_ISOSetting", 0, ([]) }), +  0x0002: ({"MN_ISOSetting", "CUSTOM", nikon_iso }),    0x0003: ({"MN_ColorMode", 0, ([]) }),    0x0004: ({"MN_Quality", 0, ([]) }),    0x0005: ({"MN_Whitebalance", 0, ([]) }),    0x0006: ({"MN_ImageSharpening", 0, ([]) }),    0x0007: ({"MN_FocusMode", 0, ([]) }),    0x0008: ({"MN_FlashSetting", 0, ([]) }), -  0x000A: ({"MN_0x0008", 0, ([]) }), +  0x000A: ({"MN_0x000A", 0, ([]) }),    0x000F: ({"MN_ISOSelection", 0, ([]) }),    0x0080: ({"MN_ImageAdjustment", 0, ([]) }),    0x0082: ({"MN_AuxiliaryLens", 0, ([]) }),
208:    0x0010: ({"MN_DataDump", 0, ([]) }),   ]);    - mapping CANON_D30_MAKERNOTE = ([ -  0x0001: ({"MN_Multi0", "CUSTOM", canon_d30_multi0 }), -  0x0004: ({"MN_Multi1", "CUSTOM", canon_d30_multi1 }), -  0x0006: ({"MN_ImageType", 0, ([]) }), -  0x0007: ({"MN_FirmwareVersion", 0, ([]) }), -  0x0008: ({"MN_ImageNumber", 0, ([]) }), -  0x0009: ({"MN_OwnerName", 0, ([]) }), -  0x000C: ({"MN_CameraSerialNumber", 0, ([]) }), + mapping sanyo_specialmode(array(int) data) { +  mapping res = ([]); +  +  add_field(res, "SanyoSpecialMode", +  ([ 0:"Normal", +  2:"Fast", +  3:"Panorama" ]), data, 0); +  +  SIZETEST(1); +  if(data[1]) res->SanyoSpecialModeSequence = (string)data[1]; +  +  add_field(res, "SanyoSpecialModeDirection", +  ([ 1:"Left to right", +  2:"Right to left", +  3:"Bottom to top", +  4:"Top to bottom" ]), data, 2); +  return res; + } +  + mapping sanyo_jpegquality(array(int) data) { +  mapping res=([]); +  +  int r = data[0]&0xff; +  add_field(res, "SanyoJPEGQualityResolution", +  ({ "Very low", "Low", "Medium low", "Medium", "Medium high", +  "High", "Very High", "Super high" }), ({ r }), 0); +  +  r = (data[0]&0xff00)>>8; +  add_field(res, "SanyoJPEGQualityDetail", +  ({ "Normal", "Fine", "Super Fine" }), ({ r }), 0); +  return res; + } +  + mapping SANYO_MAKERNOTE = ([ +  0x00ff: ({"MN_StartOffset", 0, ([]) }), +  0x0100: ({"MN_JPEGThumbnail", 0, ([]) }), +  0x0200: ({"MN_SpecialMode", "CUSTOM", sanyo_specialmode }), +  0x0201: ({"MN_JPEGQuality", "CUTSOM", sanyo_jpegquality }), +  0x0202: ({"MN_Macro", "MAP", +  ([ 0:"Normal", +  1:"Macro", +  2:"View", +  3:"Manual" ]) }), +  0x0204: ({"MN_DigitalZoom", 0, ([]) }), +  0x0207: ({"MN_SoftwareRelease", 0, ([]) }), +  0x0208: ({"MN_PictInfo", 0, ([]) }), +  0x0209: ({"MN_CameraID", 0, ([]) }), +  0x020e: ({"MN_SequentialShotMethod", "MAP", +  ([ 0:"None", +  1:"Standard", +  2:"Best", +  3:"Adjust exposure" ]) }), +  0x020f: ({"MN_WideRange", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x0210: ({"MN_ColourAdjustmentMode", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x0213: ({"MN_QuickShot", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x0214: ({"MN_SelfTimer", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x0216: ({"MN_VoiceMemo", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x0217: ({"MN_RecordShutterRelease", "MAP", +  ([ 0:"Record whilst held", +  1:"Press to start. Press to stop." ]) }), +  0x0218: ({"MN_FlickerReduce", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x0219: ({"MN_OpticalZoom", "MAP", ([ 0:"Disabled", 1:"Enabled" ]) }), +  0x021b: ({"MN_DigitalZoom", "MAP", ([ 0:"Disabled", 1:"Enabled" ]) }), +  0x021d: ({"MN_LightSourceSpecial", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x021e: ({"MN_Resaved", "MAP", ([ 0:"No", 1:"Yes" ]) }), +  0x021f: ({"MN_SceneSelect", "MAP", +  ([ 0:"Off", +  1:"Sport", +  2:"TV", +  3:"Night", +  4:"User 1", +  5:"User 2" ]) }), +  0x0223: ({"MN_ManualFocalDistance", 0, ([]) }), +  0x0224: ({"MN_SequentialShotInterval", "MAP", +  ([ 0:"5 frames/s", +  1:"10 frames/s", +  2:"15 frames/s", +  3:"20 frames/s" ]) }), +  0x0225: ({"MN_FlashMode", "MAP", +  ([ 0:"Auto", +  1:"Force", +  2:"Disabled", +  3:"Red eye" ]) }), +  0x0e00: ({"MN_PrintIMFlags", 0, ([]) }), +  0x0f00: ({"MN_DataDump", 0, ([]) }),   ]);    -  + mapping OLYMPUS_MAKERNOTE = ([ +  0x0200: ({"MN_SpecialMode", "CUSTOM", sanyo_specialmode }), +  0x0201: ({"MN_JPEGQuality", "MAP", +  ([ 0:"SQ", +  1:"HQ", +  2:"SHQ" ]) }), +  0x0202: ({"MN_Macro", "MAP", ([ 0:"No", 1:"Yes" ]) }), +  0x0204: ({"MN_DigitalZoom", "MAP", ([ 0:"1x", 1:"2x" ]) }), +  0x0207: ({"MN_SoftwareRelease", 0, ([]) }), +  0x0208: ({"MN_PictInfo", 0, ([]) }), +  0x0209: ({"MN_CameraID", 0, ([]) }), +  0x0f00: ({"MN_DataDump", 0, ([]) }), + ]); +  + // Nikon E700/E800/E900/E900S/E910/E950 + mapping NIKON_MAKERNOTE = ([ +  0x0002: ({"MN_0x0002", 0, ([]), }), +  0x0003: ({"MN_Quality", "MAP", +  ([ 1:"VGA Basic", +  2:"VGA Normal", +  3:"VGA Fine", +  4:"SXGA Basic", +  5:"SXGA Normal", +  6:"SXGA Fine" ]) }), +  0x0004: ({"MN_ColorMode", "MAP", ([ 1:"Color", 2:"Monochrome" ]) }), +  0x0005: ({"MN_ImageAdjustment", "MAP", +  ([ 0:"Normal", +  1:"Bright+", +  2:"Bright-", +  3:"Contrast+", +  4:"Contrast-" ]) }), +  0x0006: ({"MN_CCDSensitivity", "MAP", +  ([ 0:"ISO80", +  1:"ISO160", +  4:"ISO320", +  5:"ISO100" ]) }), +  0x0007: ({"MN_WhiteBalance", "MAP", +  ([ 0:"Auto", +  1:"Preset", +  2:"Daylight", +  3:"Incandescense", +  4:"Flourescense", +  5:"Cloudy", +  6:"SpeedLight" ]) }), +  0x0008: ({"MN_Focus", 0, ([]) }), +  0x0009: ({"MN_0x0009", 0, ([]) }), +  0x000a: ({"MN_DigitalZoom", 0, ([]) }), +  0x000b: ({"MN_Converter", "MAP", ([ 1:"Fisheye converter" ]) }), +  0x0f00: ({"MN_0x0f00", 0, ([]) }), + ]); +  + mapping CASIO_MAKERNOTE = ([ +  0x0001: ({"MN_RecordingMode", "MAP", +  ([ 1:"Single Shutter", +  2:"Panorama", +  3:"Night Scene", +  4:"Portrait", +  5:"Landscape" ]) }), +  0x0002: ({"MN_Quality", "MAP", +  ([ 1:"Economy", +  2:"Normal", +  3:"Fine" ]) }), +  0x0003: ({"MN_FocusingMode", "MAP", +  ([ 2:"Macro", +  3:"Auto Focus", +  4:"Manual Focus", +  5:"Infinity" ]) }), +  0x0004: ({"MN_FlashMode", "MAP", +  ([ 1:"Auto", +  2:"On", +  3:"Off", +  4:"Red Eye Reduction" ]) }), +  0x0005: ({"MN_FlashIntensity", "MAP", +  ([ 11:"Weak", +  13:"Normal", +  15:"Strong" ]) }), +  0x0006: ({"MN_ObjectDistance", 0, ([]) }), +  0x0007: ({"MN_WhiteBalance", "MAP", +  ([ 1:"Auto", +  2:"Tungsten", +  3:"Daylight", +  4:"Flourescent", +  5:"Shade", +  129:"Manual" ]) }), +  0x000a: ({"MN_DigitalZoom", "MAP", +  ([ 0x10000:"Off", +  0x10001:"2X Digital Zoom" ]) }), +  0x000b: ({"MN_Sharpness", "MAP", +  ([ 0:"Normal", +  1:"Soft", +  2:"Hard" ]) }), +  0x000c: ({"MN_Contrast", "MAP", +  ([ 0:"Normal", +  1:"Low", +  2:"High" ]) }), +  0x000d: ({"MN_Saturation", "MAP", +  ([ 0:"Normal", +  1:"Low", +  2:"High" ]) }), +  0x0014: ({"MN_CCDSensitivity", "MAP", +  ([ 64:"Normal", +  125:"+1.0", +  250:"+2.0", +  244:"+3.0", +  80:"Normal", +  100:"High", ]) }), + ]); +  + mapping FUJIFILM_MAKERNOTE = ([ +  0x0000: ({"MN_Version", 0, ([]) }), +  0x1000: ({"MN_Quality", 0, ([]) }), +  0x1001: ({"MN_Sharpness", "MAP", +  ([ 1:"Soft", +  2:"Soft", +  3:"Normal", +  4:"Hard", +  5:"Hard" ]) }), +  0x1002: ({"MN_WhiteBalance", "MAP", +  ([ 0:"Auto", +  256:"Daylight", +  512:"Cloudy", +  768:"DaylightColor-fluorescence", +  769:"DaywhiteColor-fluorescence", +  770:"White-fluorescence", +  1024:"Incandenscence", +  3840:"Custom white balance" ]) }), +  0x1003: ({"MN_Saturation", "MAP", +  ([ 0:"Normal", +  256:"High", +  512:"Low" ]) }), +  0x1004: ({"MN_Contrast", "MAP", +  ([ 0:"Normal", +  256:"High", +  512:"Low" ]) }), +  0x1010: ({"MN_FlashMode", "MAP", +  ([ 0:"Auto", +  1:"On", +  2:"Off", +  3:"Red-eye reduction" ]) }), +  0x1011: ({"MN_FlashStrength", 0, ([]) }), +  0x1020: ({"MN_Macro", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x1021: ({"MN_FocusMode", "MAP", ([ 0:"Auto focus", 1:"Manual focus" ]) }), +  0x1030: ({"MN_SlowSync", "MAP", ([ 0:"Off", 1:"On" ]) }), +  0x1031: ({"MN_PictureMode", "MAP", +  ([ 0:"Auto", +  1:"Portrait scene", +  2:"Landscape scene", +  4:"Sports scene", +  5:"Night scene", +  6:"Program AE", +  256:"Aperture prior AE", +  512:"Shutter prior AE", +  768:"Manual exposure" ]) }), +  0x1300: ({"MN_BlurWarning", "MAP", ([ 0:"No", 1:"Yes" ]) }), +  0x1301: ({"MN_FocusWarning", "MAP", ([ 0:"No", 1:"Yes" ]) }), +  0x1302: ({"MN_AEWarning", "MAP", ([ 0:"No", 1:"Yes" ]) }), + ]); +    mapping TAG_INFO = ([ -  +  0x0001: ({"InteroperabilityIndex", 0, ([]) }), +  0x0002: ({"InteroperabilityVersion", 0, ([]) }),    0x00fe: ({"NewSubFileType", 0, ([]) }),    0x0100: ({"ImageWidth", 0, ([]) }),    0x0101: ({"ImageLength", 0, ([]) }),    0x0102: ({"BitsPerSample", 0, ([]) }),    0x0103: ({"Compression", 0, ([]) }),    0x0106: ({"PhotometricInterpretation", 0, ([]) }), -  +  0x010a: ({"FillOrder", 0, ([]) }), +  0x010d: ({"DocumentName", 0, ([]) }),    0x010e: ({"ImageDescription", 0, ([]) }),    0x010f: ({"Make", 0, ([]) }),    0x0110: ({"Model", 0, ([]) }),
240:    ([ 1: "Not Absolute",    2: "Inch",    3: "Centimeter", ]) }), +  0x012d: ({"TransferFunction", 0, ([]) }),    0x0131: ({"Software", 0, ([]) }),    0x0132: ({"DateTime", 0, ([]) }),    0x013b: ({"Artist", 0, ([]) }), -  +  0x013e: ({"WhitePoint", 0, ([]) }), +  0x013f: ({"PrimaryChromaticities", 0, ([]) }),    0x0142: ({"TileWidth", 0, ([]) }),    0x0143: ({"TileLength", 0, ([]) }),    0x0144: ({"TileOffsets", 0, ([]) }),    0x0145: ({"TileByteCounts", 0, ([]) }),    0x014a: ({"SubIFDs", 0, ([]) }), -  +  0x0156: ({"TransferRange", 0, ([]) }),    0x015b: ({"JPEGTables", 0, ([]) }), -  +  0x0200: ({"JPEGProc", 0, ([]) }),    0x0201: ({"JPEGInterchangeFormat", 0, ([]) }), // from EXIFread    0x0202: ({"JPEGInterchangeFormatLength", 0, ([]) }), // from EXIFread    0x0211: ({"YCbCrCoefficients", 0, ([]) }),    0x0212: ({"YCbCrSubSampling", 0, ([]) }),    0x0213: ({"YCbCrPositioning", 0, ([]) }),    0x0214: ({"ReferenceBlackWhite", 0, ([]) }), -  +  0x1000: ({"RelatedImageFileFormat", 0, ([]) }), +  0x1001: ({"RelatedImageWidth", 0, ([]) }), +  0x1002: ({"RelatedImageLength", 0, ([]) }), +  0x828d: ({"CFARepeatPatternDim", 0, ([]) }),    0x828f: ({"BatteryLevel", 0, ([]) }),    0x8298: ({"Copyright", 0, ([]) }),    0x829a: ({"ExposureTime", "EXPOSURE", ([]) }),    0x829d: ({"FNumber", "FLOAT", ([]) }),    0x83bb: ({"IPTC_NAA", 0, ([]) }), -  +  0x8769: ({"ExifOffset", 0, ([]) }),    0x8773: ({"InterColorProfile", 0, ([]) }),    0x8822: ({"ExposureProgram", "MAP",    ([ 0: "Unidentified",
278:    0x8829: ({"Interlace", 0, ([]) }),    0x882a: ({"TimeZoneOffset", 0, ([]) }),    0x882b: ({"SelfTimerMode", 0, ([]) }), -  0x8769: ({"ExifOffset", 0, ([]) }), // from EXIFread +     0x9000: ({"ExifVersion", 0, ([]) }), // from EXIFread    0x9003: ({"DateTimeOriginal", 0, ([]) }),    0x9004: ({"DateTimeDigitized", 0, ([]) }), // from EXIFread
333:    "Canon": ({"TAGS", CANON_D30_MAKERNOTE}),    "": ({ 0,([]) }) ]) }),    0x9286: ({"UserComment", 0, ([]) }), +  0x9290: ({"SubSecTime", 0, ([]) }), +  0x9291: ({"SubSecTimeOriginal", 0, ([]) }), +  0x9292: ({"SubSecTimeDigitized", 0, ([]) }),    0xa000: ({"FlashPixVersion", 0, ([]) }),    0xa001: ({"ColorSpace", 0, ([]) }), -  0xa002: ({"ImageWidth", 0, ([]) }), // guess by rft -  0xa003: ({"ImageHeight", 0, ([]) }), // guess by rft +  0xa002: ({"PixelXDimension", 0, ([]) }), +  0xa003: ({"PixelYDimension", 0, ([]) }), +  0xa004: ({"RelatedSoundFile", 0, ([]) }), +  0xa005: ({"ExifInterabilityOffset", 0, ([]) }), +  0xa20b: ({"FlashEnergy", 0, ([]) }), +  0xa20c: ({"SpatialFrequencyResponse", 0, ([]) }), +  0xa20e: ({"FocalPlaneXResolution", 0, ([]) }), +  0xa20f: ({"FocalPlaneYResolution", 0, ([]) }), +  0xa210: ({"FocalPlaneResolutionUnit", 0, ([]) }), +  0xa214: ({"SubjectLocation", 0, ([]) }), +  0xa215: ({"ExposureIndex", 0, ([]) }), +  0xa217: ({"SensingMethod", 0, ([]) }), +  0xa300: ({"FileSource", 0, ([]) }), +  0xa301: ({"SceneType", 0, ([]) }), +  0xa302: ({"CFAPattern", 0, ([]) }),   ]);      mapping TAG_TYPE_INFO =
520:      //! Retrieve the EXIF properties of the given file.   //! @param file - //! The file containing wanted EXIF properties. Either a filename or a - //! Stdio.File object. + //! The Stdio.File object containing wanted EXIF properties.   //! @returns   //! A mapping with all found EXIF properties. - mapping get_properties(Stdio.File|string file) + mapping get_properties(Stdio.File file)   {    int exif_offset=12; -  if(!objectp(file)) -  file=Stdio.File(file, "rb"); +        string skip=file->read(12); // skip the jpeg header   
565:    }    }    } -  else -  tags=([]); +        return tags;   }