home *** CD-ROM | disk | FTP | other *** search
/ Freelog 116 / FreelogNo116-JuilletSeptembre2013.iso / GestionFichiers / metamorphose / metamorphose2_0.8.2_setup.exe / metamorphose2.exe / EXIF.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2011-01-12  |  39KB  |  1,514 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4.  
  5. def make_string(seq):
  6.     str = ''
  7.     for c in seq:
  8.         if 32 <= c and c < 256:
  9.             str += chr(c)
  10.             continue
  11.     
  12.     if not str:
  13.         return seq
  14.     return str
  15.  
  16.  
  17. def make_string_uc(seq):
  18.     code = seq[0:8]
  19.     seq = seq[8:]
  20.     return make_string(seq)
  21.  
  22. FIELD_TYPES = ((0, 'X', 'Proprietary'), (1, 'B', 'Byte'), (1, 'A', 'ASCII'), (2, 'S', 'Short'), (4, 'L', 'Long'), (8, 'R', 'Ratio'), (1, 'SB', 'Signed Byte'), (1, 'U', 'Undefined'), (2, 'SS', 'Signed Short'), (4, 'SL', 'Signed Long'), (8, 'SR', 'Signed Ratio'))
  23. EXIF_TAGS = {
  24.     256: ('ImageWidth',),
  25.     257: ('ImageLength',),
  26.     258: ('BitsPerSample',),
  27.     259: ('Compression', {
  28.         1: 'Uncompressed',
  29.         2: 'CCITT 1D',
  30.         3: 'T4/Group 3 Fax',
  31.         4: 'T6/Group 4 Fax',
  32.         5: 'LZW',
  33.         6: 'JPEG (old-style)',
  34.         7: 'JPEG',
  35.         8: 'Adobe Deflate',
  36.         9: 'JBIG B&W',
  37.         10: 'JBIG Color',
  38.         32766: 'Next',
  39.         32769: 'Epson ERF Compressed',
  40.         32771: 'CCIRLEW',
  41.         32773: 'PackBits',
  42.         32809: 'Thunderscan',
  43.         32895: 'IT8CTPAD',
  44.         32896: 'IT8LW',
  45.         32897: 'IT8MP',
  46.         32898: 'IT8BL',
  47.         32908: 'PixarFilm',
  48.         32909: 'PixarLog',
  49.         32946: 'Deflate',
  50.         32947: 'DCS',
  51.         34661: 'JBIG',
  52.         34676: 'SGILog',
  53.         34677: 'SGILog24',
  54.         34712: 'JPEG 2000',
  55.         34713: 'Nikon NEF Compressed',
  56.         65000: 'Kodak DCR Compressed',
  57.         65535: 'Pentax PEF Compressed' }),
  58.     262: ('PhotometricInterpretation',),
  59.     263: ('Thresholding',),
  60.     266: ('FillOrder',),
  61.     269: ('DocumentName',),
  62.     270: ('ImageDescription',),
  63.     271: ('Make',),
  64.     272: ('Model',),
  65.     273: ('StripOffsets',),
  66.     274: ('Orientation', {
  67.         1: 'Horizontal (normal)',
  68.         2: 'Mirrored horizontal',
  69.         3: 'Rotated 180',
  70.         4: 'Mirrored vertical',
  71.         5: 'Mirrored horizontal then rotated 90 CCW',
  72.         6: 'Rotated 90 CW',
  73.         7: 'Mirrored horizontal then rotated 90 CW',
  74.         8: 'Rotated 90 CCW' }),
  75.     277: ('SamplesPerPixel',),
  76.     278: ('RowsPerStrip',),
  77.     279: ('StripByteCounts',),
  78.     282: ('XResolution',),
  79.     283: ('YResolution',),
  80.     284: ('PlanarConfiguration',),
  81.     285: ('PageName', make_string),
  82.     296: ('ResolutionUnit', {
  83.         1: 'Not Absolute',
  84.         2: 'Pixels/Inch',
  85.         3: 'Pixels/Centimeter' }),
  86.     301: ('TransferFunction',),
  87.     305: ('Software',),
  88.     306: ('DateTime',),
  89.     315: ('Artist',),
  90.     318: ('WhitePoint',),
  91.     319: ('PrimaryChromaticities',),
  92.     342: ('TransferRange',),
  93.     512: ('JPEGProc',),
  94.     513: ('JPEGInterchangeFormat',),
  95.     514: ('JPEGInterchangeFormatLength',),
  96.     529: ('YCbCrCoefficients',),
  97.     530: ('YCbCrSubSampling',),
  98.     531: ('YCbCrPositioning', {
  99.         1: 'Centered',
  100.         2: 'Co-sited' }),
  101.     532: ('ReferenceBlackWhite',),
  102.     18246: ('Rating',),
  103.     33421: ('CFARepeatPatternDim',),
  104.     33422: ('CFAPattern',),
  105.     33423: ('BatteryLevel',),
  106.     33432: ('Copyright',),
  107.     33434: ('ExposureTime',),
  108.     33437: ('FNumber',),
  109.     33723: ('IPTC/NAA',),
  110.     34665: ('ExifOffset',),
  111.     34675: ('InterColorProfile',),
  112.     34850: ('ExposureProgram', {
  113.         0: 'Unidentified',
  114.         1: 'Manual',
  115.         2: 'Program Normal',
  116.         3: 'Aperture Priority',
  117.         4: 'Shutter Priority',
  118.         5: 'Program Creative',
  119.         6: 'Program Action',
  120.         7: 'Portrait Mode',
  121.         8: 'Landscape Mode' }),
  122.     34852: ('SpectralSensitivity',),
  123.     34853: ('GPSInfo',),
  124.     34855: ('ISOSpeedRatings',),
  125.     34856: ('OECF',),
  126.     36864: ('ExifVersion', make_string),
  127.     36867: ('DateTimeOriginal',),
  128.     36868: ('DateTimeDigitized',),
  129.     37121: ('ComponentsConfiguration', {
  130.         0: '',
  131.         1: 'Y',
  132.         2: 'Cb',
  133.         3: 'Cr',
  134.         4: 'Red',
  135.         5: 'Green',
  136.         6: 'Blue' }),
  137.     37122: ('CompressedBitsPerPixel',),
  138.     37377: ('ShutterSpeedValue',),
  139.     37378: ('ApertureValue',),
  140.     37379: ('BrightnessValue',),
  141.     37380: ('ExposureBiasValue',),
  142.     37381: ('MaxApertureValue',),
  143.     37382: ('SubjectDistance',),
  144.     37383: ('MeteringMode', {
  145.         0: 'Unidentified',
  146.         1: 'Average',
  147.         2: 'CenterWeightedAverage',
  148.         3: 'Spot',
  149.         4: 'MultiSpot',
  150.         5: 'Pattern' }),
  151.     37384: ('LightSource', {
  152.         0: 'Unknown',
  153.         1: 'Daylight',
  154.         2: 'Fluorescent',
  155.         3: 'Tungsten',
  156.         9: 'Fine Weather',
  157.         10: 'Flash',
  158.         11: 'Shade',
  159.         12: 'Daylight Fluorescent',
  160.         13: 'Day White Fluorescent',
  161.         14: 'Cool White Fluorescent',
  162.         15: 'White Fluorescent',
  163.         17: 'Standard Light A',
  164.         18: 'Standard Light B',
  165.         19: 'Standard Light C',
  166.         20: 'D55',
  167.         21: 'D65',
  168.         22: 'D75',
  169.         255: 'Other' }),
  170.     37385: ('Flash', {
  171.         0: 'No',
  172.         1: 'Fired',
  173.         5: 'Fired (?)',
  174.         7: 'Fired (!)',
  175.         9: 'Fill Fired',
  176.         13: 'Fill Fired (?)',
  177.         15: 'Fill Fired (!)',
  178.         16: 'Off',
  179.         24: 'Auto Off',
  180.         25: 'Auto Fired',
  181.         29: 'Auto Fired (?)',
  182.         31: 'Auto Fired (!)',
  183.         32: 'Not Available' }),
  184.     37386: ('FocalLength',),
  185.     37396: ('SubjectArea',),
  186.     37500: ('MakerNote',),
  187.     37510: ('UserComment', make_string_uc),
  188.     37520: ('SubSecTime',),
  189.     37521: ('SubSecTimeOriginal',),
  190.     37522: ('SubSecTimeDigitized',),
  191.     40091: ('XPTitle',),
  192.     40092: ('XPComment',),
  193.     40093: ('XPAuthor',),
  194.     40094: ('XPKeywords',),
  195.     40095: ('XPSubject',),
  196.     40960: ('FlashPixVersion', make_string),
  197.     40961: ('ColorSpace', {
  198.         1: 'sRGB',
  199.         2: 'Adobe RGB',
  200.         65535: 'Uncalibrated' }),
  201.     40962: ('ExifImageWidth',),
  202.     40963: ('ExifImageLength',),
  203.     40965: ('InteroperabilityOffset',),
  204.     41483: ('FlashEnergy',),
  205.     41484: ('SpatialFrequencyResponse',),
  206.     41486: ('FocalPlaneXResolution',),
  207.     41487: ('FocalPlaneYResolution',),
  208.     41488: ('FocalPlaneResolutionUnit',),
  209.     41492: ('SubjectLocation',),
  210.     41493: ('ExposureIndex',),
  211.     41495: ('SensingMethod', {
  212.         1: 'Not defined',
  213.         2: 'One-chip color area',
  214.         3: 'Two-chip color area',
  215.         4: 'Three-chip color area',
  216.         5: 'Color sequential area',
  217.         7: 'Trilinear',
  218.         8: 'Color sequential linear' }),
  219.     41728: ('FileSource', {
  220.         1: 'Film Scanner',
  221.         2: 'Reflection Print Scanner',
  222.         3: 'Digital Camera' }),
  223.     41729: ('SceneType', {
  224.         1: 'Directly Photographed' }),
  225.     41730: ('CVAPattern',),
  226.     41985: ('CustomRendered', {
  227.         0: 'Normal',
  228.         1: 'Custom' }),
  229.     41986: ('ExposureMode', {
  230.         0: 'Auto Exposure',
  231.         1: 'Manual Exposure',
  232.         2: 'Auto Bracket' }),
  233.     41987: ('WhiteBalance', {
  234.         0: 'Auto',
  235.         1: 'Manual' }),
  236.     41988: ('DigitalZoomRatio',),
  237.     41989: ('FocalLengthIn35mmFilm',),
  238.     41990: ('SceneCaptureType', {
  239.         0: 'Standard',
  240.         1: 'Landscape',
  241.         2: 'Portrait',
  242.         3: 'Night)' }),
  243.     41991: ('GainControl', {
  244.         0: 'None',
  245.         1: 'Low gain up',
  246.         2: 'High gain up',
  247.         3: 'Low gain down',
  248.         4: 'High gain down' }),
  249.     41992: ('Contrast', {
  250.         0: 'Normal',
  251.         1: 'Soft',
  252.         2: 'Hard' }),
  253.     41993: ('Saturation', {
  254.         0: 'Normal',
  255.         1: 'Soft',
  256.         2: 'Hard' }),
  257.     41994: ('Sharpness', {
  258.         0: 'Normal',
  259.         1: 'Soft',
  260.         2: 'Hard' }),
  261.     41995: ('DeviceSettingDescription',),
  262.     41996: ('SubjectDistanceRange',),
  263.     42240: ('Gamma',),
  264.     50341: ('PrintIM',),
  265.     59932: ('Padding',) }
  266. INTR_TAGS = {
  267.     1: ('InteroperabilityIndex',),
  268.     2: ('InteroperabilityVersion',),
  269.     4096: ('RelatedImageFileFormat',),
  270.     4097: ('RelatedImageWidth',),
  271.     4098: ('RelatedImageLength',) }
  272. GPS_TAGS = {
  273.     0: ('GPSVersionID',),
  274.     1: ('GPSLatitudeRef',),
  275.     2: ('GPSLatitude',),
  276.     3: ('GPSLongitudeRef',),
  277.     4: ('GPSLongitude',),
  278.     5: ('GPSAltitudeRef',),
  279.     6: ('GPSAltitude',),
  280.     7: ('GPSTimeStamp',),
  281.     8: ('GPSSatellites',),
  282.     9: ('GPSStatus',),
  283.     10: ('GPSMeasureMode',),
  284.     11: ('GPSDOP',),
  285.     12: ('GPSSpeedRef',),
  286.     13: ('GPSSpeed',),
  287.     14: ('GPSTrackRef',),
  288.     15: ('GPSTrack',),
  289.     16: ('GPSImgDirectionRef',),
  290.     17: ('GPSImgDirection',),
  291.     18: ('GPSMapDatum',),
  292.     19: ('GPSDestLatitudeRef',),
  293.     20: ('GPSDestLatitude',),
  294.     21: ('GPSDestLongitudeRef',),
  295.     22: ('GPSDestLongitude',),
  296.     23: ('GPSDestBearingRef',),
  297.     24: ('GPSDestBearing',),
  298.     25: ('GPSDestDistanceRef',),
  299.     26: ('GPSDestDistance',),
  300.     29: ('GPSDate',) }
  301. IGNORE_TAGS = (37510, 37500)
  302.  
  303. def nikon_ev_bias(seq):
  304.     if len(seq) < 4:
  305.         return ''
  306.     if seq == [
  307.         252,
  308.         1,
  309.         6,
  310.         0]:
  311.         return '-2/3 EV'
  312.     if seq == [
  313.         253,
  314.         1,
  315.         6,
  316.         0]:
  317.         return '-1/2 EV'
  318.     if seq == [
  319.         254,
  320.         1,
  321.         6,
  322.         0]:
  323.         return '-1/3 EV'
  324.     if seq == [
  325.         0,
  326.         1,
  327.         6,
  328.         0]:
  329.         return '0 EV'
  330.     if seq == [
  331.         2,
  332.         1,
  333.         6,
  334.         0]:
  335.         return '+1/3 EV'
  336.     if seq == [
  337.         3,
  338.         1,
  339.         6,
  340.         0]:
  341.         return '+1/2 EV'
  342.     if seq == [
  343.         4,
  344.         1,
  345.         6,
  346.         0]:
  347.         return '+2/3 EV'
  348.     a = seq[0]
  349.     if a == 0:
  350.         return '0 EV'
  351.     b = seq[2]
  352.     whole = a / b
  353.     a = a % b
  354.     return ret_str
  355.  
  356. MAKERNOTE_NIKON_NEWER_TAGS = {
  357.     1: ('MakernoteVersion', make_string),
  358.     2: ('ISOSetting', make_string),
  359.     3: ('ColorMode',),
  360.     4: ('Quality',),
  361.     5: ('Whitebalance',),
  362.     6: ('ImageSharpening',),
  363.     7: ('FocusMode',),
  364.     8: ('FlashSetting',),
  365.     9: ('AutoFlashMode',),
  366.     11: ('WhiteBalanceBias',),
  367.     12: ('WhiteBalanceRBCoeff',),
  368.     13: ('ProgramShift', nikon_ev_bias),
  369.     14: ('ExposureDifference', nikon_ev_bias),
  370.     15: ('ISOSelection',),
  371.     17: ('NikonPreview',),
  372.     18: ('FlashCompensation', nikon_ev_bias),
  373.     19: ('ISOSpeedRequested',),
  374.     22: ('PhotoCornerCoordinates',),
  375.     24: ('FlashBracketCompensationApplied', nikon_ev_bias),
  376.     25: ('AEBracketCompensationApplied',),
  377.     26: ('ImageProcessing',),
  378.     27: ('CropHiSpeed',),
  379.     29: ('SerialNumber',),
  380.     30: ('ColorSpace',),
  381.     31: ('VRInfo',),
  382.     32: ('ImageAuthentication',),
  383.     34: ('ActiveDLighting',),
  384.     35: ('PictureControl',),
  385.     36: ('WorldTime',),
  386.     37: ('ISOInfo',),
  387.     128: ('ImageAdjustment',),
  388.     129: ('ToneCompensation',),
  389.     130: ('AuxiliaryLens',),
  390.     131: ('LensType',),
  391.     132: ('LensMinMaxFocalMaxAperture',),
  392.     133: ('ManualFocusDistance',),
  393.     134: ('DigitalZoomFactor',),
  394.     135: ('FlashMode', {
  395.         0: 'Did Not Fire',
  396.         1: 'Fired, Manual',
  397.         7: 'Fired, External',
  398.         8: 'Fired, Commander Mode ',
  399.         9: 'Fired, TTL Mode' }),
  400.     136: ('AFFocusPosition', {
  401.         0: 'Center',
  402.         256: 'Top',
  403.         512: 'Bottom',
  404.         768: 'Left',
  405.         1024: 'Right' }),
  406.     137: ('BracketingMode', {
  407.         0: 'Single frame, no bracketing',
  408.         1: 'Continuous, no bracketing',
  409.         2: 'Timer, no bracketing',
  410.         16: 'Single frame, exposure bracketing',
  411.         17: 'Continuous, exposure bracketing',
  412.         18: 'Timer, exposure bracketing',
  413.         64: 'Single frame, white balance bracketing',
  414.         65: 'Continuous, white balance bracketing',
  415.         66: 'Timer, white balance bracketing' }),
  416.     138: ('AutoBracketRelease',),
  417.     139: ('LensFStops',),
  418.     140: ('NEFCurve1',),
  419.     141: ('ColorMode',),
  420.     143: ('SceneMode',),
  421.     144: ('LightingType',),
  422.     145: ('ShotInfo',),
  423.     146: ('HueAdjustment',),
  424.     147: ('Compression',),
  425.     148: ('Saturation', {
  426.         -3: 'B&W',
  427.         -2: '-2',
  428.         -1: '-1',
  429.         0: '0',
  430.         1: '1',
  431.         2: '2' }),
  432.     149: ('NoiseReduction',),
  433.     150: ('NEFCurve2',),
  434.     151: ('ColorBalance',),
  435.     152: ('LensData',),
  436.     153: ('RawImageCenter',),
  437.     154: ('SensorPixelSize',),
  438.     156: ('Scene Assist',),
  439.     158: ('RetouchHistory',),
  440.     160: ('SerialNumber',),
  441.     162: ('ImageDataSize',),
  442.     165: ('ImageCount',),
  443.     166: ('DeletedImageCount',),
  444.     167: ('TotalShutterReleases',),
  445.     168: ('FlashInfo',),
  446.     169: ('ImageOptimization',),
  447.     170: ('Saturation',),
  448.     171: ('DigitalVariProgram',),
  449.     172: ('ImageStabilization',),
  450.     173: ('Responsive AF',),
  451.     176: ('MultiExposure',),
  452.     177: ('HighISONoiseReduction',),
  453.     183: ('AFInfo',),
  454.     184: ('FileInfo',),
  455.     256: ('DigitalICE',),
  456.     259: ('PreviewCompression', {
  457.         1: 'Uncompressed',
  458.         2: 'CCITT 1D',
  459.         3: 'T4/Group 3 Fax',
  460.         4: 'T6/Group 4 Fax',
  461.         5: 'LZW',
  462.         6: 'JPEG (old-style)',
  463.         7: 'JPEG',
  464.         8: 'Adobe Deflate',
  465.         9: 'JBIG B&W',
  466.         10: 'JBIG Color',
  467.         32766: 'Next',
  468.         32769: 'Epson ERF Compressed',
  469.         32771: 'CCIRLEW',
  470.         32773: 'PackBits',
  471.         32809: 'Thunderscan',
  472.         32895: 'IT8CTPAD',
  473.         32896: 'IT8LW',
  474.         32897: 'IT8MP',
  475.         32898: 'IT8BL',
  476.         32908: 'PixarFilm',
  477.         32909: 'PixarLog',
  478.         32946: 'Deflate',
  479.         32947: 'DCS',
  480.         34661: 'JBIG',
  481.         34676: 'SGILog',
  482.         34677: 'SGILog24',
  483.         34712: 'JPEG 2000',
  484.         34713: 'Nikon NEF Compressed',
  485.         65000: 'Kodak DCR Compressed',
  486.         65535: 'Pentax PEF Compressed' }),
  487.     513: ('PreviewImageStart',),
  488.     514: ('PreviewImageLength',),
  489.     531: ('PreviewYCbCrPositioning', {
  490.         1: 'Centered',
  491.         2: 'Co-sited' }),
  492.     16: ('DataDump',) }
  493. MAKERNOTE_NIKON_OLDER_TAGS = {
  494.     3: ('Quality', {
  495.         1: 'VGA Basic',
  496.         2: 'VGA Normal',
  497.         3: 'VGA Fine',
  498.         4: 'SXGA Basic',
  499.         5: 'SXGA Normal',
  500.         6: 'SXGA Fine' }),
  501.     4: ('ColorMode', {
  502.         1: 'Color',
  503.         2: 'Monochrome' }),
  504.     5: ('ImageAdjustment', {
  505.         0: 'Normal',
  506.         1: 'Bright+',
  507.         2: 'Bright-',
  508.         3: 'Contrast+',
  509.         4: 'Contrast-' }),
  510.     6: ('CCDSpeed', {
  511.         0: 'ISO 80',
  512.         2: 'ISO 160',
  513.         4: 'ISO 320',
  514.         5: 'ISO 100' }),
  515.     7: ('WhiteBalance', {
  516.         0: 'Auto',
  517.         1: 'Preset',
  518.         2: 'Daylight',
  519.         3: 'Incandescent',
  520.         4: 'Fluorescent',
  521.         5: 'Cloudy',
  522.         6: 'Speed Light' }) }
  523.  
  524. def olympus_special_mode(v):
  525.     a = {
  526.         0: 'Normal',
  527.         1: 'Unknown',
  528.         2: 'Fast',
  529.         3: 'Panorama' }
  530.     b = {
  531.         0: 'Non-panoramic',
  532.         1: 'Left to right',
  533.         2: 'Right to left',
  534.         3: 'Bottom to top',
  535.         4: 'Top to bottom' }
  536.     if v[0] not in a or v[2] not in b:
  537.         return v
  538.     return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
  539.  
  540. MAKERNOTE_OLYMPUS_TAGS = {
  541.     256: ('JPEGThumbnail',),
  542.     512: ('SpecialMode', olympus_special_mode),
  543.     513: ('JPEGQual', {
  544.         1: 'SQ',
  545.         2: 'HQ',
  546.         3: 'SHQ' }),
  547.     514: ('Macro', {
  548.         0: 'Normal',
  549.         1: 'Macro',
  550.         2: 'SuperMacro' }),
  551.     515: ('BWMode', {
  552.         0: 'Off',
  553.         1: 'On' }),
  554.     516: ('DigitalZoom',),
  555.     517: ('FocalPlaneDiagonal',),
  556.     518: ('LensDistortionParams',),
  557.     519: ('SoftwareRelease',),
  558.     520: ('PictureInfo',),
  559.     521: ('CameraID', make_string),
  560.     3840: ('DataDump',),
  561.     768: ('PreCaptureFrames',),
  562.     1028: ('SerialNumber',),
  563.     4096: ('ShutterSpeedValue',),
  564.     4097: ('ISOValue',),
  565.     4098: ('ApertureValue',),
  566.     4099: ('BrightnessValue',),
  567.     4100: ('FlashMode',),
  568.     4100: ('FlashMode', {
  569.         2: 'On',
  570.         3: 'Off' }),
  571.     4101: ('FlashDevice', {
  572.         0: 'None',
  573.         1: 'Internal',
  574.         4: 'External',
  575.         5: 'Internal + External' }),
  576.     4102: ('ExposureCompensation',),
  577.     4103: ('SensorTemperature',),
  578.     4104: ('LensTemperature',),
  579.     4107: ('FocusMode', {
  580.         0: 'Auto',
  581.         1: 'Manual' }),
  582.     4119: ('RedBalance',),
  583.     4120: ('BlueBalance',),
  584.     4122: ('SerialNumber',),
  585.     4131: ('FlashExposureComp',),
  586.     4134: ('ExternalFlashBounce', {
  587.         0: 'No',
  588.         1: 'Yes' }),
  589.     4135: ('ExternalFlashZoom',),
  590.     4136: ('ExternalFlashMode',),
  591.     4137: ('Contrast \tint16u', {
  592.         0: 'High',
  593.         1: 'Normal',
  594.         2: 'Low' }),
  595.     4138: ('SharpnessFactor',),
  596.     4139: ('ColorControl',),
  597.     4140: ('ValidBits',),
  598.     4141: ('CoringFilter',),
  599.     4142: ('OlympusImageWidth',),
  600.     4143: ('OlympusImageHeight',),
  601.     4148: ('CompressionRatio',),
  602.     4149: ('PreviewImageValid', {
  603.         0: 'No',
  604.         1: 'Yes' }),
  605.     4150: ('PreviewImageStart',),
  606.     4151: ('PreviewImageLength',),
  607.     4153: ('CCDScanMode', {
  608.         0: 'Interlaced',
  609.         1: 'Progressive' }),
  610.     4154: ('NoiseReduction', {
  611.         0: 'Off',
  612.         1: 'On' }),
  613.     4155: ('InfinityLensStep',),
  614.     4156: ('NearLensStep',),
  615.     8208: ('Equipment',),
  616.     8224: ('CameraSettings',),
  617.     8240: ('RawDevelopment',),
  618.     8256: ('ImageProcessing',),
  619.     8272: ('FocusInfo',),
  620.     12288: ('RawInfo ',) }
  621. MAKERNOTE_OLYMPUS_TAG_0x2020 = {
  622.     256: ('PreviewImageValid', {
  623.         0: 'No',
  624.         1: 'Yes' }),
  625.     257: ('PreviewImageStart',),
  626.     258: ('PreviewImageLength',),
  627.     512: ('ExposureMode', {
  628.         1: 'Manual',
  629.         2: 'Program',
  630.         3: 'Aperture-priority AE',
  631.         4: 'Shutter speed priority AE',
  632.         5: 'Program-shift' }),
  633.     513: ('AELock', {
  634.         0: 'Off',
  635.         1: 'On' }),
  636.     514: ('MeteringMode', {
  637.         2: 'Center Weighted',
  638.         3: 'Spot',
  639.         5: 'ESP',
  640.         261: 'Pattern+AF',
  641.         515: 'Spot+Highlight control',
  642.         1027: 'Spot+Shadow control' }),
  643.     768: ('MacroMode', {
  644.         0: 'Off',
  645.         1: 'On' }),
  646.     769: ('FocusMode', {
  647.         0: 'Single AF',
  648.         1: 'Sequential shooting AF',
  649.         2: 'Continuous AF',
  650.         3: 'Multi AF',
  651.         10: 'MF' }),
  652.     770: ('FocusProcess', {
  653.         0: 'AF Not Used',
  654.         1: 'AF Used' }),
  655.     771: ('AFSearch', {
  656.         0: 'Not Ready',
  657.         1: 'Ready' }),
  658.     772: ('AFAreas',),
  659.     1025: ('FlashExposureCompensation',),
  660.     1280: ('WhiteBalance2', {
  661.         0: 'Auto',
  662.         16: '7500K (Fine Weather with Shade)',
  663.         17: '6000K (Cloudy)',
  664.         18: '5300K (Fine Weather)',
  665.         20: '3000K (Tungsten light)',
  666.         21: '3600K (Tungsten light-like)',
  667.         33: '6600K (Daylight fluorescent)',
  668.         34: '4500K (Neutral white fluorescent)',
  669.         35: '4000K (Cool white fluorescent)',
  670.         48: '3600K (Tungsten light-like)',
  671.         256: 'Custom WB 1',
  672.         257: 'Custom WB 2',
  673.         258: 'Custom WB 3',
  674.         259: 'Custom WB 4',
  675.         512: 'Custom WB 5400K',
  676.         513: 'Custom WB 2900K',
  677.         514: 'Custom WB 8000K' }),
  678.     1281: ('WhiteBalanceTemperature',),
  679.     1282: ('WhiteBalanceBracket',),
  680.     1283: ('CustomSaturation',),
  681.     1284: ('ModifiedSaturation', {
  682.         0: 'Off',
  683.         1: 'CM1 (Red Enhance)',
  684.         2: 'CM2 (Green Enhance)',
  685.         3: 'CM3 (Blue Enhance)',
  686.         4: 'CM4 (Skin Tones)' }),
  687.     1285: ('ContrastSetting',),
  688.     1286: ('SharpnessSetting',),
  689.     1287: ('ColorSpace', {
  690.         0: 'sRGB',
  691.         1: 'Adobe RGB',
  692.         2: 'Pro Photo RGB' }),
  693.     1289: ('SceneMode', {
  694.         0: 'Standard',
  695.         6: 'Auto',
  696.         7: 'Sport',
  697.         8: 'Portrait',
  698.         9: 'Landscape+Portrait',
  699.         10: 'Landscape',
  700.         11: 'Night scene',
  701.         13: 'Panorama',
  702.         16: 'Landscape+Portrait',
  703.         17: 'Night+Portrait',
  704.         19: 'Fireworks',
  705.         20: 'Sunset',
  706.         22: 'Macro',
  707.         25: 'Documents',
  708.         26: 'Museum',
  709.         28: 'Beach&Snow',
  710.         30: 'Candle',
  711.         35: 'Underwater Wide1',
  712.         36: 'Underwater Macro',
  713.         39: 'High Key',
  714.         40: 'Digital Image Stabilization',
  715.         44: 'Underwater Wide2',
  716.         45: 'Low Key',
  717.         46: 'Children',
  718.         48: 'Nature Macro' }),
  719.     1290: ('NoiseReduction', {
  720.         0: 'Off',
  721.         1: 'Noise Reduction',
  722.         2: 'Noise Filter',
  723.         3: 'Noise Reduction + Noise Filter',
  724.         4: 'Noise Filter (ISO Boost)',
  725.         5: 'Noise Reduction + Noise Filter (ISO Boost)' }),
  726.     1291: ('DistortionCorrection', {
  727.         0: 'Off',
  728.         1: 'On' }),
  729.     1292: ('ShadingCompensation', {
  730.         0: 'Off',
  731.         1: 'On' }),
  732.     1293: ('CompressionFactor',),
  733.     1295: ('Gradation', {
  734.         '-1 -1 1': 'Low Key',
  735.         '0 -1 1': 'Normal',
  736.         '1 -1 1': 'High Key' }),
  737.     1312: ('PictureMode', {
  738.         1: 'Vivid',
  739.         2: 'Natural',
  740.         3: 'Muted',
  741.         256: 'Monotone',
  742.         512: 'Sepia' }),
  743.     1313: ('PictureModeSaturation',),
  744.     1314: ('PictureModeHue?',),
  745.     1315: ('PictureModeContrast',),
  746.     1316: ('PictureModeSharpness',),
  747.     1317: ('PictureModeBWFilter', {
  748.         0: 'n/a',
  749.         1: 'Neutral',
  750.         2: 'Yellow',
  751.         3: 'Orange',
  752.         4: 'Red',
  753.         5: 'Green' }),
  754.     1318: ('PictureModeTone', {
  755.         0: 'n/a',
  756.         1: 'Neutral',
  757.         2: 'Sepia',
  758.         3: 'Blue',
  759.         4: 'Purple',
  760.         5: 'Green' }),
  761.     1536: ('Sequence',),
  762.     1537: ('PanoramaMode',),
  763.     1539: ('ImageQuality2', {
  764.         1: 'SQ',
  765.         2: 'HQ',
  766.         3: 'SHQ',
  767.         4: 'RAW' }),
  768.     2305: ('ManometerReading',) }
  769. MAKERNOTE_CASIO_TAGS = {
  770.     1: ('RecordingMode', {
  771.         1: 'Single Shutter',
  772.         2: 'Panorama',
  773.         3: 'Night Scene',
  774.         4: 'Portrait',
  775.         5: 'Landscape' }),
  776.     2: ('Quality', {
  777.         1: 'Economy',
  778.         2: 'Normal',
  779.         3: 'Fine' }),
  780.     3: ('FocusingMode', {
  781.         2: 'Macro',
  782.         3: 'Auto Focus',
  783.         4: 'Manual Focus',
  784.         5: 'Infinity' }),
  785.     4: ('FlashMode', {
  786.         1: 'Auto',
  787.         2: 'On',
  788.         3: 'Off',
  789.         4: 'Red Eye Reduction' }),
  790.     5: ('FlashIntensity', {
  791.         11: 'Weak',
  792.         13: 'Normal',
  793.         15: 'Strong' }),
  794.     6: ('Object Distance',),
  795.     7: ('WhiteBalance', {
  796.         1: 'Auto',
  797.         2: 'Tungsten',
  798.         3: 'Daylight',
  799.         4: 'Fluorescent',
  800.         5: 'Shade',
  801.         129: 'Manual' }),
  802.     11: ('Sharpness', {
  803.         0: 'Normal',
  804.         1: 'Soft',
  805.         2: 'Hard' }),
  806.     12: ('Contrast', {
  807.         0: 'Normal',
  808.         1: 'Low',
  809.         2: 'High' }),
  810.     13: ('Saturation', {
  811.         0: 'Normal',
  812.         1: 'Low',
  813.         2: 'High' }),
  814.     20: ('CCDSpeed', {
  815.         64: 'Normal',
  816.         80: 'Normal',
  817.         100: 'High',
  818.         125: '+1.0',
  819.         244: '+3.0',
  820.         250: '+2.0' }) }
  821. MAKERNOTE_FUJIFILM_TAGS = {
  822.     0: ('NoteVersion', make_string),
  823.     4096: ('Quality',),
  824.     4097: ('Sharpness', {
  825.         1: 'Soft',
  826.         2: 'Soft',
  827.         3: 'Normal',
  828.         4: 'Hard',
  829.         5: 'Hard' }),
  830.     4098: ('WhiteBalance', {
  831.         0: 'Auto',
  832.         256: 'Daylight',
  833.         512: 'Cloudy',
  834.         768: 'DaylightColor-Fluorescent',
  835.         769: 'DaywhiteColor-Fluorescent',
  836.         770: 'White-Fluorescent',
  837.         1024: 'Incandescent',
  838.         3840: 'Custom' }),
  839.     4099: ('Color', {
  840.         0: 'Normal',
  841.         256: 'High',
  842.         512: 'Low' }),
  843.     4100: ('Tone', {
  844.         0: 'Normal',
  845.         256: 'High',
  846.         512: 'Low' }),
  847.     4112: ('FlashMode', {
  848.         0: 'Auto',
  849.         1: 'On',
  850.         2: 'Off',
  851.         3: 'Red Eye Reduction' }),
  852.     4113: ('FlashStrength',),
  853.     4128: ('Macro', {
  854.         0: 'Off',
  855.         1: 'On' }),
  856.     4129: ('FocusMode', {
  857.         0: 'Auto',
  858.         1: 'Manual' }),
  859.     4144: ('SlowSync', {
  860.         0: 'Off',
  861.         1: 'On' }),
  862.     4145: ('PictureMode', {
  863.         0: 'Auto',
  864.         1: 'Portrait',
  865.         2: 'Landscape',
  866.         4: 'Sports',
  867.         5: 'Night',
  868.         6: 'Program AE',
  869.         256: 'Aperture Priority AE',
  870.         512: 'Shutter Priority AE',
  871.         768: 'Manual Exposure' }),
  872.     4352: ('MotorOrBracket', {
  873.         0: 'Off',
  874.         1: 'On' }),
  875.     4864: ('BlurWarning', {
  876.         0: 'Off',
  877.         1: 'On' }),
  878.     4865: ('FocusWarning', {
  879.         0: 'Off',
  880.         1: 'On' }),
  881.     4866: ('AEWarning', {
  882.         0: 'Off',
  883.         1: 'On' }) }
  884. MAKERNOTE_CANON_TAGS = {
  885.     6: ('ImageType',),
  886.     7: ('FirmwareVersion',),
  887.     8: ('ImageNumber',),
  888.     9: ('OwnerName',) }
  889. MAKERNOTE_CANON_TAG_0x001 = {
  890.     1: ('Macromode', {
  891.         1: 'Macro',
  892.         2: 'Normal' }),
  893.     2: ('SelfTimer',),
  894.     3: ('Quality', {
  895.         2: 'Normal',
  896.         3: 'Fine',
  897.         5: 'Superfine' }),
  898.     4: ('FlashMode', {
  899.         0: 'Flash Not Fired',
  900.         1: 'Auto',
  901.         2: 'On',
  902.         3: 'Red-Eye Reduction',
  903.         4: 'Slow Synchro',
  904.         5: 'Auto + Red-Eye Reduction',
  905.         6: 'On + Red-Eye Reduction',
  906.         16: 'external flash' }),
  907.     5: ('ContinuousDriveMode', {
  908.         0: 'Single Or Timer',
  909.         1: 'Continuous' }),
  910.     7: ('FocusMode', {
  911.         0: 'One-Shot',
  912.         1: 'AI Servo',
  913.         2: 'AI Focus',
  914.         3: 'MF',
  915.         4: 'Single',
  916.         5: 'Continuous',
  917.         6: 'MF' }),
  918.     10: ('ImageSize', {
  919.         0: 'Large',
  920.         1: 'Medium',
  921.         2: 'Small' }),
  922.     11: ('EasyShootingMode', {
  923.         0: 'Full Auto',
  924.         1: 'Manual',
  925.         2: 'Landscape',
  926.         3: 'Fast Shutter',
  927.         4: 'Slow Shutter',
  928.         5: 'Night',
  929.         6: 'B&W',
  930.         7: 'Sepia',
  931.         8: 'Portrait',
  932.         9: 'Sports',
  933.         10: 'Macro/Close-Up',
  934.         11: 'Pan Focus' }),
  935.     12: ('DigitalZoom', {
  936.         0: 'None',
  937.         1: '2x',
  938.         2: '4x' }),
  939.     13: ('Contrast', {
  940.         65535: 'Low',
  941.         0: 'Normal',
  942.         1: 'High' }),
  943.     14: ('Saturation', {
  944.         65535: 'Low',
  945.         0: 'Normal',
  946.         1: 'High' }),
  947.     15: ('Sharpness', {
  948.         65535: 'Low',
  949.         0: 'Normal',
  950.         1: 'High' }),
  951.     16: ('ISO', {
  952.         0: 'See ISOSpeedRatings Tag',
  953.         15: 'Auto',
  954.         16: '50',
  955.         17: '100',
  956.         18: '200',
  957.         19: '400' }),
  958.     17: ('MeteringMode', {
  959.         3: 'Evaluative',
  960.         4: 'Partial',
  961.         5: 'Center-weighted' }),
  962.     18: ('FocusType', {
  963.         0: 'Manual',
  964.         1: 'Auto',
  965.         3: 'Close-Up (Macro)',
  966.         8: 'Locked (Pan Mode)' }),
  967.     19: ('AFPointSelected', {
  968.         12288: 'None (MF)',
  969.         12289: 'Auto-Selected',
  970.         12290: 'Right',
  971.         12291: 'Center',
  972.         12292: 'Left' }),
  973.     20: ('ExposureMode', {
  974.         0: 'Easy Shooting',
  975.         1: 'Program',
  976.         2: 'Tv-priority',
  977.         3: 'Av-priority',
  978.         4: 'Manual',
  979.         5: 'A-DEP' }),
  980.     23: ('LongFocalLengthOfLensInFocalUnits',),
  981.     24: ('ShortFocalLengthOfLensInFocalUnits',),
  982.     25: ('FocalUnitsPerMM',),
  983.     28: ('FlashActivity', {
  984.         0: 'Did Not Fire',
  985.         1: 'Fired' }),
  986.     29: ('FlashDetails', {
  987.         14: 'External E-TTL',
  988.         13: 'Internal Flash',
  989.         11: 'FP Sync Used',
  990.         7: '2nd("Rear")-Curtain Sync Used',
  991.         4: 'FP Sync Enabled' }),
  992.     32: ('FocusMode', {
  993.         0: 'Single',
  994.         1: 'Continuous' }) }
  995. MAKERNOTE_CANON_TAG_0x004 = {
  996.     7: ('WhiteBalance', {
  997.         0: 'Auto',
  998.         1: 'Sunny',
  999.         2: 'Cloudy',
  1000.         3: 'Tungsten',
  1001.         4: 'Fluorescent',
  1002.         5: 'Flash',
  1003.         6: 'Custom' }),
  1004.     9: ('SequenceNumber',),
  1005.     14: ('AFPointUsed',),
  1006.     15: ('FlashBias', {
  1007.         65472: '-2 EV',
  1008.         65484: '-1.67 EV',
  1009.         65488: '-1.50 EV',
  1010.         65492: '-1.33 EV',
  1011.         65504: '-1 EV',
  1012.         65516: '-0.67 EV',
  1013.         65520: '-0.50 EV',
  1014.         65524: '-0.33 EV',
  1015.         0: '0 EV',
  1016.         12: '0.33 EV',
  1017.         16: '0.50 EV',
  1018.         20: '0.67 EV',
  1019.         32: '1 EV',
  1020.         44: '1.33 EV',
  1021.         48: '1.50 EV',
  1022.         52: '1.67 EV',
  1023.         64: '2 EV' }),
  1024.     19: ('SubjectDistance',) }
  1025.  
  1026. def s2n_motorola(str):
  1027.     x = 0
  1028.     for c in str:
  1029.         x = x << 8 | ord(c)
  1030.     
  1031.     return x
  1032.  
  1033.  
  1034. def s2n_intel(str):
  1035.     x = 0
  1036.     y = 0x0L
  1037.     for c in str:
  1038.         x = x | ord(c) << y
  1039.         y = y + 8
  1040.     
  1041.     return x
  1042.  
  1043.  
  1044. def gcd(a, b):
  1045.     if b == 0:
  1046.         return a
  1047.     return gcd(b, a % b)
  1048.  
  1049.  
  1050. class Ratio:
  1051.     
  1052.     def __init__(self, num, den):
  1053.         self.num = num
  1054.         self.den = den
  1055.  
  1056.     
  1057.     def __repr__(self):
  1058.         self.reduce()
  1059.         if self.den == 1:
  1060.             return str(self.num)
  1061.         return '%d/%d' % (self.num, self.den)
  1062.  
  1063.     
  1064.     def reduce(self):
  1065.         div = gcd(self.num, self.den)
  1066.         if div > 1:
  1067.             self.num = self.num / div
  1068.             self.den = self.den / div
  1069.         
  1070.  
  1071.  
  1072.  
  1073. class IFD_Tag:
  1074.     
  1075.     def __init__(self, printable, tag, field_type, values, field_offset, field_length):
  1076.         self.printable = printable
  1077.         self.tag = tag
  1078.         self.field_type = field_type
  1079.         self.field_offset = field_offset
  1080.         self.field_length = field_length
  1081.         self.values = values
  1082.  
  1083.     
  1084.     def __str__(self):
  1085.         return self.printable
  1086.  
  1087.     
  1088.     def __repr__(self):
  1089.         return '(0x%04X) %s=%s @ %d' % (self.tag, FIELD_TYPES[self.field_type][2], self.printable, self.field_offset)
  1090.  
  1091.  
  1092.  
  1093. class EXIF_header:
  1094.     
  1095.     def __init__(self, file, endian, offset, fake_exif, strict, debug = 0):
  1096.         self.file = file
  1097.         self.endian = endian
  1098.         self.offset = offset
  1099.         self.fake_exif = fake_exif
  1100.         self.strict = strict
  1101.         self.debug = debug
  1102.         self.tags = { }
  1103.  
  1104.     
  1105.     def s2n(self, offset, length, signed = 0):
  1106.         self.file.seek(self.offset + offset)
  1107.         slice = self.file.read(length)
  1108.         if self.endian == 'I':
  1109.             val = s2n_intel(slice)
  1110.         else:
  1111.             val = s2n_motorola(slice)
  1112.         if signed:
  1113.             msb = 0x1L << 8 * length - 1
  1114.             if val & msb:
  1115.                 val = val - (msb << 1)
  1116.             
  1117.         
  1118.         return val
  1119.  
  1120.     
  1121.     def n2s(self, offset, length):
  1122.         s = ''
  1123.         for dummy in range(length):
  1124.             if self.endian == 'I':
  1125.                 s = s + chr(offset & 255)
  1126.             else:
  1127.                 s = chr(offset & 255) + s
  1128.             offset = offset >> 8
  1129.         
  1130.         return s
  1131.  
  1132.     
  1133.     def first_IFD(self):
  1134.         return self.s2n(4, 4)
  1135.  
  1136.     
  1137.     def next_IFD(self, ifd):
  1138.         entries = self.s2n(ifd, 2)
  1139.         return self.s2n(ifd + 2 + 12 * entries, 4)
  1140.  
  1141.     
  1142.     def list_IFDs(self):
  1143.         i = self.first_IFD()
  1144.         a = []
  1145.         while i:
  1146.             a.append(i)
  1147.             i = self.next_IFD(i)
  1148.         return a
  1149.  
  1150.     
  1151.     def dump_IFD(self, ifd, ifd_name, dict = EXIF_TAGS, relative = 0, stop_tag = 'UNDEF'):
  1152.         entries = self.s2n(ifd, 2)
  1153.         for i in range(entries):
  1154.             entry = ifd + 2 + 12 * i
  1155.             tag = self.s2n(entry, 2)
  1156.             tag_entry = dict.get(tag)
  1157.             if tag_entry:
  1158.                 tag_name = tag_entry[0]
  1159.             else:
  1160.                 tag_name = 'Tag 0x%04X' % tag
  1161.             if not not detailed and tag in IGNORE_TAGS:
  1162.                 field_type = self.s2n(entry + 2, 2)
  1163.                 None if field_type < field_type else self.strict
  1164.                 typelen = FIELD_TYPES[field_type][0]
  1165.                 count = self.s2n(entry + 4, 4)
  1166.                 offset = entry + 8
  1167.                 if count * typelen > 4:
  1168.                     if relative:
  1169.                         tmp_offset = self.s2n(offset, 4)
  1170.                         offset = tmp_offset + ifd - 8
  1171.                         if self.fake_exif:
  1172.                             offset = offset + 18
  1173.                         
  1174.                     else:
  1175.                         offset = self.s2n(offset, 4)
  1176.                 
  1177.                 field_offset = offset
  1178.                 if field_type == 2:
  1179.                     if count != 0 and count < 0x80000000L:
  1180.                         self.file.seek(self.offset + offset)
  1181.                         values = self.file.read(count)
  1182.                         values = values.split('\x00', 1)[0]
  1183.                     else:
  1184.                         values = ''
  1185.                 else:
  1186.                     values = []
  1187.                     signed = field_type in (6, 8, 9, 10)
  1188.                     if count < 1000:
  1189.                         for dummy in range(count):
  1190.                             if field_type in (5, 10):
  1191.                                 value = Ratio(self.s2n(offset, 4, signed), self.s2n(offset + 4, 4, signed))
  1192.                             else:
  1193.                                 value = self.s2n(offset, typelen, signed)
  1194.                             values.append(value)
  1195.                             offset = offset + typelen
  1196.                         
  1197.                     elif tag_name == 'MakerNote':
  1198.                         for dummy in range(count):
  1199.                             value = self.s2n(offset, typelen, signed)
  1200.                             values.append(value)
  1201.                             offset = offset + typelen
  1202.                         
  1203.                     
  1204.                 if count == 1 and field_type != 2:
  1205.                     printable = str(values[0])
  1206.                 elif count > 50 and len(values) > 20:
  1207.                     printable = str(values[0:20])[0:-1] + ', ... ]'
  1208.                 else:
  1209.                     printable = str(values)
  1210.                 if tag_entry:
  1211.                     if len(tag_entry) != 1:
  1212.                         if callable(tag_entry[1]):
  1213.                             printable = tag_entry[1](values)
  1214.                         else:
  1215.                             printable = ''
  1216.                             for i in values:
  1217.                                 printable += tag_entry[1].get(i, repr(i))
  1218.                             
  1219.                     
  1220.                 
  1221.                 self.tags[ifd_name + ' ' + tag_name] = IFD_Tag(printable, tag, field_type, values, field_offset, count * typelen)
  1222.                 if self.debug:
  1223.                     print ' debug:   %s: %s' % (tag_name, repr(self.tags[ifd_name + ' ' + tag_name]))
  1224.                 
  1225.             
  1226.             if tag_name == stop_tag:
  1227.                 break
  1228.                 continue
  1229.         
  1230.  
  1231.     
  1232.     def extract_TIFF_thumbnail(self, thumb_ifd):
  1233.         entries = self.s2n(thumb_ifd, 2)
  1234.         if self.endian == 'M':
  1235.             tiff = 'MM\x00*\x00\x00\x00\x08'
  1236.         else:
  1237.             tiff = 'II*\x00\x08\x00\x00\x00'
  1238.         self.file.seek(self.offset + thumb_ifd)
  1239.         tiff += self.file.read(entries * 12 + 2) + '\x00\x00\x00\x00'
  1240.         for i in range(entries):
  1241.             entry = thumb_ifd + 2 + 12 * i
  1242.             tag = self.s2n(entry, 2)
  1243.             field_type = self.s2n(entry + 2, 2)
  1244.             typelen = FIELD_TYPES[field_type][0]
  1245.             count = self.s2n(entry + 4, 4)
  1246.             oldoff = self.s2n(entry + 8, 4)
  1247.             ptr = i * 12 + 18
  1248.             if tag == 273:
  1249.                 strip_off = ptr
  1250.                 strip_len = count * typelen
  1251.             
  1252.             if count * typelen > 4:
  1253.                 newoff = len(tiff)
  1254.                 tiff = tiff[:ptr] + self.n2s(newoff, 4) + tiff[ptr + 4:]
  1255.                 if tag == 273:
  1256.                     strip_off = newoff
  1257.                     strip_len = 4
  1258.                 
  1259.                 self.file.seek(self.offset + oldoff)
  1260.                 tiff += self.file.read(count * typelen)
  1261.                 continue
  1262.         
  1263.         old_offsets = self.tags['Thumbnail StripOffsets'].values
  1264.         old_counts = self.tags['Thumbnail StripByteCounts'].values
  1265.         for i in range(len(old_offsets)):
  1266.             offset = self.n2s(len(tiff), strip_len)
  1267.             tiff = tiff[:strip_off] + offset + tiff[strip_off + strip_len:]
  1268.             strip_off += strip_len
  1269.             self.file.seek(self.offset + old_offsets[i])
  1270.             tiff += self.file.read(old_counts[i])
  1271.         
  1272.         self.tags['TIFFThumbnail'] = tiff
  1273.  
  1274.     
  1275.     def decode_maker_note(self):
  1276.         note = self.tags['EXIF MakerNote']
  1277.         make = self.tags['Image Make'].printable
  1278.         if 'NIKON' in make:
  1279.             if note.values[0:7] == [
  1280.                 78,
  1281.                 105,
  1282.                 107,
  1283.                 111,
  1284.                 110,
  1285.                 0,
  1286.                 1]:
  1287.                 if self.debug:
  1288.                     print 'Looks like a type 1 Nikon MakerNote.'
  1289.                 
  1290.                 self.dump_IFD(note.field_offset + 8, 'MakerNote', dict = MAKERNOTE_NIKON_OLDER_TAGS)
  1291.             elif note.values[0:7] == [
  1292.                 78,
  1293.                 105,
  1294.                 107,
  1295.                 111,
  1296.                 110,
  1297.                 0,
  1298.                 2]:
  1299.                 if self.debug:
  1300.                     print 'Looks like a labeled type 2 Nikon MakerNote'
  1301.                 
  1302.                 if note.values[12:14] != [
  1303.                     0,
  1304.                     42] and note.values[12:14] != [
  1305.                     0x2AL,
  1306.                     0x0L]:
  1307.                     raise ValueError("Missing marker tag '42' in MakerNote.")
  1308.                 note.values[12:14] != [
  1309.                     0x2AL,
  1310.                     0x0L]
  1311.                 self.dump_IFD(note.field_offset + 10 + 8, 'MakerNote', dict = MAKERNOTE_NIKON_NEWER_TAGS, relative = 1)
  1312.             elif self.debug:
  1313.                 print 'Looks like an unlabeled type 2 Nikon MakerNote'
  1314.             
  1315.             self.dump_IFD(note.field_offset, 'MakerNote', dict = MAKERNOTE_NIKON_NEWER_TAGS)
  1316.             return None
  1317.         if make.startswith('OLYMPUS'):
  1318.             self.dump_IFD(note.field_offset + 8, 'MakerNote', dict = MAKERNOTE_OLYMPUS_TAGS)
  1319.         
  1320.         if 'CASIO' in make or 'Casio' in make:
  1321.             self.dump_IFD(note.field_offset, 'MakerNote', dict = MAKERNOTE_CASIO_TAGS)
  1322.             return None
  1323.         if make == 'FUJIFILM':
  1324.             endian = self.endian
  1325.             self.endian = 'I'
  1326.             offset = self.offset
  1327.             self.offset += note.field_offset
  1328.             self.dump_IFD(12, 'MakerNote', dict = MAKERNOTE_FUJIFILM_TAGS)
  1329.             self.endian = endian
  1330.             self.offset = offset
  1331.             return None
  1332.         if make == 'Canon':
  1333.             self.dump_IFD(note.field_offset, 'MakerNote', dict = MAKERNOTE_CANON_TAGS)
  1334.             for i in (('MakerNote Tag 0x0001', MAKERNOTE_CANON_TAG_0x001), ('MakerNote Tag 0x0004', MAKERNOTE_CANON_TAG_0x004)):
  1335.                 self.canon_decode_tag(self.tags[i[0]].values, i[1])
  1336.             
  1337.             return None
  1338.  
  1339.     
  1340.     def olympus_decode_tag(self, value, dict):
  1341.         pass
  1342.  
  1343.     
  1344.     def canon_decode_tag(self, value, dict):
  1345.         for i in range(1, len(value)):
  1346.             x = dict.get(i, ('Unknown',))
  1347.             if self.debug:
  1348.                 print i, x
  1349.             
  1350.             name = x[0]
  1351.             if len(x) > 1:
  1352.                 val = x[1].get(value[i], 'Unknown')
  1353.             else:
  1354.                 val = value[i]
  1355.             self.tags['MakerNote ' + name] = IFD_Tag(str(val), None, 0, None, None, None)
  1356.         
  1357.  
  1358.  
  1359.  
  1360. def process_file(f, stop_tag = 'UNDEF', details = True, strict = False, debug = False):
  1361.     global detailed
  1362.     detailed = details
  1363.     fake_exif = 0
  1364.     data = f.read(12)
  1365.     None if data[0:4] in ('II*\x00', 'MM\x00*') else data[6:10] == 'Exif'
  1366.     return { }
  1367.     if debug:
  1368.         print {
  1369.             'I': 'Intel',
  1370.             'M': 'Motorola' }[endian], 'format'
  1371.     
  1372.     hdr = EXIF_header(f, endian, offset, fake_exif, strict, debug)
  1373.     ifd_list = hdr.list_IFDs()
  1374.     ctr = 0
  1375.     for i in ifd_list:
  1376.         if ctr == 0:
  1377.             IFD_name = 'Image'
  1378.         elif ctr == 1:
  1379.             IFD_name = 'Thumbnail'
  1380.             thumb_ifd = i
  1381.         else:
  1382.             IFD_name = 'IFD %d' % ctr
  1383.         if debug:
  1384.             print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i)
  1385.         
  1386.         hdr.dump_IFD(i, IFD_name, stop_tag = stop_tag)
  1387.         exif_off = hdr.tags.get(IFD_name + ' ExifOffset')
  1388.         if exif_off:
  1389.             if debug:
  1390.                 print ' EXIF SubIFD at offset %d:' % exif_off.values[0]
  1391.             
  1392.             hdr.dump_IFD(exif_off.values[0], 'EXIF', stop_tag = stop_tag)
  1393.             intr_off = hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
  1394.             if intr_off:
  1395.                 if debug:
  1396.                     print ' EXIF Interoperability SubSubIFD at offset %d:' % intr_off.values[0]
  1397.                 
  1398.                 hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability', dict = INTR_TAGS, stop_tag = stop_tag)
  1399.             
  1400.         
  1401.         gps_off = hdr.tags.get(IFD_name + ' GPSInfo')
  1402.         if gps_off:
  1403.             if debug:
  1404.                 print ' GPS SubIFD at offset %d:' % gps_off.values[0]
  1405.             
  1406.             hdr.dump_IFD(gps_off.values[0], 'GPS', dict = GPS_TAGS, stop_tag = stop_tag)
  1407.         
  1408.         ctr += 1
  1409.     
  1410.     thumb = hdr.tags.get('Thumbnail Compression')
  1411.     if thumb and thumb.printable == 'Uncompressed TIFF':
  1412.         hdr.extract_TIFF_thumbnail(thumb_ifd)
  1413.     
  1414.     thumb_off = hdr.tags.get('Thumbnail JPEGInterchangeFormat')
  1415.     if thumb_off:
  1416.         f.seek(offset + thumb_off.values[0])
  1417.         size = hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0]
  1418.         hdr.tags['JPEGThumbnail'] = f.read(size)
  1419.     
  1420.     if 'EXIF MakerNote' in hdr.tags and 'Image Make' in hdr.tags and detailed:
  1421.         hdr.decode_maker_note()
  1422.     
  1423.     if 'JPEGThumbnail' not in hdr.tags:
  1424.         thumb_off = hdr.tags.get('MakerNote JPEGThumbnail')
  1425.         if thumb_off:
  1426.             f.seek(offset + thumb_off.values[0])
  1427.             hdr.tags['JPEGThumbnail'] = file.read(thumb_off.field_length)
  1428.         
  1429.     
  1430.     return hdr.tags
  1431.  
  1432.  
  1433. def usage(exit_status):
  1434.     msg = 'Usage: EXIF.py [OPTIONS] file1 [file2 ...]\n'
  1435.     msg += 'Extract EXIF information from digital camera image files.\n\nOptions:\n'
  1436.     msg += '-q --quick   Do not process MakerNotes.\n'
  1437.     msg += '-t TAG --stop-tag TAG   Stop processing when this tag is retrieved.\n'
  1438.     msg += '-s --strict   Run in strict mode (stop on errors).\n'
  1439.     msg += '-d --debug   Run in debug mode (display extra info).\n'
  1440.     print msg
  1441.     sys.exit(exit_status)
  1442.  
  1443. if __name__ == '__main__':
  1444.     import sys
  1445.     import getopt
  1446.     
  1447.     try:
  1448.         (opts, args) = getopt.getopt(sys.argv[1:], 'hqsdt:v', [
  1449.             'help',
  1450.             'quick',
  1451.             'strict',
  1452.             'debug',
  1453.             'stop-tag='])
  1454.     except getopt.GetoptError:
  1455.         usage(2)
  1456.  
  1457.     if args == []:
  1458.         usage(2)
  1459.     
  1460.     detailed = True
  1461.     stop_tag = 'UNDEF'
  1462.     debug = False
  1463.     strict = False
  1464.     for o, a in opts:
  1465.         if o in ('-h', '--help'):
  1466.             usage(0)
  1467.         
  1468.         if o in ('-q', '--quick'):
  1469.             detailed = False
  1470.         
  1471.         if o in ('-t', '--stop-tag'):
  1472.             stop_tag = a
  1473.         
  1474.         if o in ('-s', '--strict'):
  1475.             strict = True
  1476.         
  1477.         if o in ('-d', '--debug'):
  1478.             debug = True
  1479.         
  1480.     
  1481.     for filename in args:
  1482.         
  1483.         try:
  1484.             file = open(filename, 'rb')
  1485.         except:
  1486.             print "'%s' is unreadable\n" % filename
  1487.             continue
  1488.  
  1489.         print filename + ':'
  1490.         data = process_file(file, stop_tag = stop_tag, details = detailed, strict = strict, debug = debug)
  1491.         if not data:
  1492.             print 'No EXIF information found'
  1493.             continue
  1494.         
  1495.         x = data.keys()
  1496.         x.sort()
  1497.         for i in x:
  1498.             if i in ('JPEGThumbnail', 'TIFFThumbnail'):
  1499.                 continue
  1500.             
  1501.             
  1502.             try:
  1503.                 print '   %s (%s): %s' % (i, FIELD_TYPES[data[i].field_type][2], data[i].printable)
  1504.             except:
  1505.                 print 'error', i, '"', data[i], '"'
  1506.  
  1507.         
  1508.         if 'JPEGThumbnail' in data:
  1509.             print 'File has JPEG thumbnail'
  1510.         
  1511.         print 
  1512.     
  1513.  
  1514.