Ignore:
Timestamp:
2015-04-21T00:42:50+02:00 (11 years ago)
Author:
Don-vip
Message:

fix #11359 - update to metadata-extractor 2.8.1

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/com/drew/metadata/exif/ExifSubIFDDescriptor.java

    r8132 r8243  
    2121package com.drew.metadata.exif;
    2222
    23 import com.drew.imaging.PhotographicConversions;
    24 import com.drew.lang.Rational;
    2523import com.drew.lang.annotations.NotNull;
    26 import com.drew.lang.annotations.Nullable;
    27 import com.drew.metadata.TagDescriptor;
    28 
    29 import java.io.UnsupportedEncodingException;
    30 import java.text.DecimalFormat;
    31 import java.util.HashMap;
    32 import java.util.Map;
    33 
    34 import static com.drew.metadata.exif.ExifSubIFDDirectory.*;
    3524
    3625/**
     
    3928 * @author Drew Noakes https://drewnoakes.com
    4029 */
    41 public class ExifSubIFDDescriptor extends TagDescriptor<ExifSubIFDDirectory>
     30public class ExifSubIFDDescriptor extends ExifDescriptorBase<ExifSubIFDDirectory>
    4231{
    43     /**
    44      * Dictates whether rational values will be represented in decimal format in instances
    45      * where decimal notation is elegant (such as 1/2 -> 0.5, but not 1/3).
    46      */
    47     private final boolean _allowDecimalRepresentationOfRationals = true;
    48 
    49     @NotNull
    50     private static final java.text.DecimalFormat SimpleDecimalFormatter = new DecimalFormat("0.#");
    51 
    5232    public ExifSubIFDDescriptor(@NotNull ExifSubIFDDirectory directory)
    5333    {
    5434        super(directory);
    5535    }
    56 
    57     // Note for the potential addition of brightness presentation in eV:
    58     // Brightness of taken subject. To calculate Exposure(Ev) from BrightnessValue(Bv),
    59     // you must add SensitivityValue(Sv).
    60     // Ev=BV+Sv   Sv=log2(ISOSpeedRating/3.125)
    61     // ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.
    62 
    63     /**
    64      * Returns a descriptive value of the specified tag for this image.
    65      * Where possible, known values will be substituted here in place of the raw
    66      * tokens actually kept in the Exif segment.  If no substitution is
    67      * available, the value provided by getString(int) will be returned.
    68      *
    69      * @param tagType the tag to find a description for
    70      * @return a description of the image's value for the specified tag, or
    71      *         <code>null</code> if the tag hasn't been defined.
    72      */
    73     @Override
    74     @Nullable
    75     public String getDescription(int tagType)
    76     {
    77         switch (tagType) {
    78             case TAG_NEW_SUBFILE_TYPE:
    79                 return getNewSubfileTypeDescription();
    80             case TAG_SUBFILE_TYPE:
    81                 return getSubfileTypeDescription();
    82             case TAG_THRESHOLDING:
    83                 return getThresholdingDescription();
    84             case TAG_FILL_ORDER:
    85                 return getFillOrderDescription();
    86             case TAG_EXPOSURE_TIME:
    87                 return getExposureTimeDescription();
    88             case TAG_SHUTTER_SPEED:
    89                 return getShutterSpeedDescription();
    90             case TAG_FNUMBER:
    91                 return getFNumberDescription();
    92             case TAG_COMPRESSED_AVERAGE_BITS_PER_PIXEL:
    93                 return getCompressedAverageBitsPerPixelDescription();
    94             case TAG_SUBJECT_DISTANCE:
    95                 return getSubjectDistanceDescription();
    96             case TAG_METERING_MODE:
    97                 return getMeteringModeDescription();
    98             case TAG_WHITE_BALANCE:
    99                 return getWhiteBalanceDescription();
    100             case TAG_FLASH:
    101                 return getFlashDescription();
    102             case TAG_FOCAL_LENGTH:
    103                 return getFocalLengthDescription();
    104             case TAG_COLOR_SPACE:
    105                 return getColorSpaceDescription();
    106             case TAG_EXIF_IMAGE_WIDTH:
    107                 return getExifImageWidthDescription();
    108             case TAG_EXIF_IMAGE_HEIGHT:
    109                 return getExifImageHeightDescription();
    110             case TAG_FOCAL_PLANE_RESOLUTION_UNIT:
    111                 return getFocalPlaneResolutionUnitDescription();
    112             case TAG_FOCAL_PLANE_X_RESOLUTION:
    113                 return getFocalPlaneXResolutionDescription();
    114             case TAG_FOCAL_PLANE_Y_RESOLUTION:
    115                 return getFocalPlaneYResolutionDescription();
    116             case TAG_BITS_PER_SAMPLE:
    117                 return getBitsPerSampleDescription();
    118             case TAG_PHOTOMETRIC_INTERPRETATION:
    119                 return getPhotometricInterpretationDescription();
    120             case TAG_ROWS_PER_STRIP:
    121                 return getRowsPerStripDescription();
    122             case TAG_STRIP_BYTE_COUNTS:
    123                 return getStripByteCountsDescription();
    124             case TAG_SAMPLES_PER_PIXEL:
    125                 return getSamplesPerPixelDescription();
    126             case TAG_PLANAR_CONFIGURATION:
    127                 return getPlanarConfigurationDescription();
    128             case TAG_YCBCR_SUBSAMPLING:
    129                 return getYCbCrSubsamplingDescription();
    130             case TAG_EXPOSURE_PROGRAM:
    131                 return getExposureProgramDescription();
    132             case TAG_APERTURE:
    133                 return getApertureValueDescription();
    134             case TAG_MAX_APERTURE:
    135                 return getMaxApertureValueDescription();
    136             case TAG_SENSING_METHOD:
    137                 return getSensingMethodDescription();
    138             case TAG_EXPOSURE_BIAS:
    139                 return getExposureBiasDescription();
    140             case TAG_FILE_SOURCE:
    141                 return getFileSourceDescription();
    142             case TAG_SCENE_TYPE:
    143                 return getSceneTypeDescription();
    144             case TAG_COMPONENTS_CONFIGURATION:
    145                 return getComponentConfigurationDescription();
    146             case TAG_EXIF_VERSION:
    147                 return getExifVersionDescription();
    148             case TAG_FLASHPIX_VERSION:
    149                 return getFlashPixVersionDescription();
    150             case TAG_ISO_EQUIVALENT:
    151                 return getIsoEquivalentDescription();
    152             case TAG_USER_COMMENT:
    153                 return getUserCommentDescription();
    154             case TAG_CUSTOM_RENDERED:
    155                 return getCustomRenderedDescription();
    156             case TAG_EXPOSURE_MODE:
    157                 return getExposureModeDescription();
    158             case TAG_WHITE_BALANCE_MODE:
    159                 return getWhiteBalanceModeDescription();
    160             case TAG_DIGITAL_ZOOM_RATIO:
    161                 return getDigitalZoomRatioDescription();
    162             case TAG_35MM_FILM_EQUIV_FOCAL_LENGTH:
    163                 return get35mmFilmEquivFocalLengthDescription();
    164             case TAG_SCENE_CAPTURE_TYPE:
    165                 return getSceneCaptureTypeDescription();
    166             case TAG_GAIN_CONTROL:
    167                 return getGainControlDescription();
    168             case TAG_CONTRAST:
    169                 return getContrastDescription();
    170             case TAG_SATURATION:
    171                 return getSaturationDescription();
    172             case TAG_SHARPNESS:
    173                 return getSharpnessDescription();
    174             case TAG_SUBJECT_DISTANCE_RANGE:
    175                 return getSubjectDistanceRangeDescription();
    176             default:
    177                 return super.getDescription(tagType);
    178         }
    179     }
    180 
    181     @Nullable
    182     public String getNewSubfileTypeDescription()
    183     {
    184         return getIndexedDescription(TAG_NEW_SUBFILE_TYPE, 1,
    185             "Full-resolution image",
    186             "Reduced-resolution image",
    187             "Single page of multi-page reduced-resolution image",
    188             "Transparency mask",
    189             "Transparency mask of reduced-resolution image",
    190             "Transparency mask of multi-page image",
    191             "Transparency mask of reduced-resolution multi-page image"
    192         );
    193     }
    194 
    195     @Nullable
    196     public String getSubfileTypeDescription()
    197     {
    198         return getIndexedDescription(TAG_SUBFILE_TYPE, 1,
    199             "Full-resolution image",
    200             "Reduced-resolution image",
    201             "Single page of multi-page image"
    202         );
    203     }
    204 
    205     @Nullable
    206     public String getThresholdingDescription()
    207     {
    208         return getIndexedDescription(TAG_THRESHOLDING, 1,
    209             "No dithering or halftoning",
    210             "Ordered dither or halftone",
    211             "Randomized dither"
    212         );
    213     }
    214 
    215     @Nullable
    216     public String getFillOrderDescription()
    217     {
    218         return getIndexedDescription(TAG_FILL_ORDER, 1,
    219             "Normal",
    220             "Reversed"
    221         );
    222     }
    223 
    224     @Nullable
    225     public String getSubjectDistanceRangeDescription()
    226     {
    227         return getIndexedDescription(TAG_SUBJECT_DISTANCE_RANGE,
    228             "Unknown",
    229             "Macro",
    230             "Close view",
    231             "Distant view"
    232         );
    233     }
    234 
    235     @Nullable
    236     public String getSharpnessDescription()
    237     {
    238         return getIndexedDescription(TAG_SHARPNESS,
    239             "None",
    240             "Low",
    241             "Hard"
    242         );
    243     }
    244 
    245     @Nullable
    246     public String getSaturationDescription()
    247     {
    248         return getIndexedDescription(TAG_SATURATION,
    249             "None",
    250             "Low saturation",
    251             "High saturation"
    252         );
    253     }
    254 
    255     @Nullable
    256     public String getContrastDescription()
    257     {
    258         return getIndexedDescription(TAG_CONTRAST,
    259             "None",
    260             "Soft",
    261             "Hard"
    262         );
    263     }
    264 
    265     @Nullable
    266     public String getGainControlDescription()
    267     {
    268         return getIndexedDescription(TAG_GAIN_CONTROL,
    269             "None",
    270             "Low gain up",
    271             "Low gain down",
    272             "High gain up",
    273             "High gain down"
    274         );
    275     }
    276 
    277     @Nullable
    278     public String getSceneCaptureTypeDescription()
    279     {
    280         return getIndexedDescription(TAG_SCENE_CAPTURE_TYPE,
    281             "Standard",
    282             "Landscape",
    283             "Portrait",
    284             "Night scene"
    285         );
    286     }
    287 
    288     @Nullable
    289     public String get35mmFilmEquivFocalLengthDescription()
    290     {
    291         Integer value = _directory.getInteger(TAG_35MM_FILM_EQUIV_FOCAL_LENGTH);
    292         return value == null
    293             ? null
    294             : value == 0
    295             ? "Unknown"
    296             : SimpleDecimalFormatter.format(value) + "mm";
    297     }
    298 
    299     @Nullable
    300     public String getDigitalZoomRatioDescription()
    301     {
    302         Rational value = _directory.getRational(TAG_DIGITAL_ZOOM_RATIO);
    303         return value == null
    304             ? null
    305             : value.getNumerator() == 0
    306             ? "Digital zoom not used."
    307             : SimpleDecimalFormatter.format(value.doubleValue());
    308     }
    309 
    310     @Nullable
    311     public String getWhiteBalanceModeDescription()
    312     {
    313         return getIndexedDescription(TAG_WHITE_BALANCE_MODE,
    314             "Auto white balance",
    315             "Manual white balance"
    316         );
    317     }
    318 
    319     @Nullable
    320     public String getExposureModeDescription()
    321     {
    322         return getIndexedDescription(TAG_EXPOSURE_MODE,
    323             "Auto exposure",
    324             "Manual exposure",
    325             "Auto bracket"
    326         );
    327     }
    328 
    329     @Nullable
    330     public String getCustomRenderedDescription()
    331     {
    332         return getIndexedDescription(TAG_CUSTOM_RENDERED,
    333             "Normal process",
    334             "Custom process"
    335         );
    336     }
    337 
    338     @Nullable
    339     public String getUserCommentDescription()
    340     {
    341         byte[] commentBytes = _directory.getByteArray(TAG_USER_COMMENT);
    342         if (commentBytes == null)
    343             return null;
    344         if (commentBytes.length == 0)
    345             return "";
    346 
    347         final Map<String, String> encodingMap = new HashMap<String, String>();
    348         encodingMap.put("ASCII", System.getProperty("file.encoding")); // Someone suggested "ISO-8859-1".
    349         encodingMap.put("UNICODE", "UTF-16LE");
    350         encodingMap.put("JIS", "Shift-JIS"); // We assume this charset for now.  Another suggestion is "JIS".
    351 
    352         try {
    353             if (commentBytes.length >= 10) {
    354                 String firstTenBytesString = new String(commentBytes, 0, 10);
    355 
    356                 // try each encoding name
    357                 for (Map.Entry<String, String> pair : encodingMap.entrySet()) {
    358                     String encodingName = pair.getKey();
    359                     String charset = pair.getValue();
    360                     if (firstTenBytesString.startsWith(encodingName)) {
    361                         // skip any null or blank characters commonly present after the encoding name, up to a limit of 10 from the start
    362                         for (int j = encodingName.length(); j < 10; j++) {
    363                             byte b = commentBytes[j];
    364                             if (b != '\0' && b != ' ')
    365                                 return new String(commentBytes, j, commentBytes.length - j, charset).trim();
    366                         }
    367                         return new String(commentBytes, 10, commentBytes.length - 10, charset).trim();
    368                     }
    369                 }
    370             }
    371             // special handling fell through, return a plain string representation
    372             return new String(commentBytes, System.getProperty("file.encoding")).trim();
    373         } catch (UnsupportedEncodingException ex) {
    374             return null;
    375         }
    376     }
    377 
    378     @Nullable
    379     public String getIsoEquivalentDescription()
    380     {
    381         // Have seen an exception here from files produced by ACDSEE that stored an int[] here with two values
    382         Integer isoEquiv = _directory.getInteger(TAG_ISO_EQUIVALENT);
    383         // There used to be a check here that multiplied ISO values < 50 by 200.
    384         // Issue 36 shows a smart-phone image from a Samsung Galaxy S2 with ISO-40.
    385         return isoEquiv != null
    386             ? Integer.toString(isoEquiv)
    387             : null;
    388     }
    389 
    390     @Nullable
    391     public String getExifVersionDescription()
    392     {
    393         return getVersionBytesDescription(TAG_EXIF_VERSION, 2);
    394     }
    395 
    396     @Nullable
    397     public String getFlashPixVersionDescription()
    398     {
    399         return getVersionBytesDescription(TAG_FLASHPIX_VERSION, 2);
    400     }
    401 
    402     @Nullable
    403     public String getSceneTypeDescription()
    404     {
    405         return getIndexedDescription(TAG_SCENE_TYPE,
    406             1,
    407             "Directly photographed image"
    408         );
    409     }
    410 
    411     @Nullable
    412     public String getFileSourceDescription()
    413     {
    414         return getIndexedDescription(TAG_FILE_SOURCE,
    415             1,
    416             "Film Scanner",
    417             "Reflection Print Scanner",
    418             "Digital Still Camera (DSC)"
    419         );
    420     }
    421 
    422     @Nullable
    423     public String getExposureBiasDescription()
    424     {
    425         Rational value = _directory.getRational(TAG_EXPOSURE_BIAS);
    426         if (value == null)
    427             return null;
    428         return value.toSimpleString(true) + " EV";
    429     }
    430 
    431     @Nullable
    432     public String getMaxApertureValueDescription()
    433     {
    434         Double aperture = _directory.getDoubleObject(TAG_MAX_APERTURE);
    435         if (aperture == null)
    436             return null;
    437         double fStop = PhotographicConversions.apertureToFStop(aperture);
    438         return "F" + SimpleDecimalFormatter.format(fStop);
    439     }
    440 
    441     @Nullable
    442     public String getApertureValueDescription()
    443     {
    444         Double aperture = _directory.getDoubleObject(TAG_APERTURE);
    445         if (aperture == null)
    446             return null;
    447         double fStop = PhotographicConversions.apertureToFStop(aperture);
    448         return "F" + SimpleDecimalFormatter.format(fStop);
    449     }
    450 
    451     @Nullable
    452     public String getExposureProgramDescription()
    453     {
    454         return getIndexedDescription(TAG_EXPOSURE_PROGRAM,
    455             1,
    456             "Manual control",
    457             "Program normal",
    458             "Aperture priority",
    459             "Shutter priority",
    460             "Program creative (slow program)",
    461             "Program action (high-speed program)",
    462             "Portrait mode",
    463             "Landscape mode"
    464         );
    465     }
    466 
    467     @Nullable
    468     public String getYCbCrSubsamplingDescription()
    469     {
    470         int[] positions = _directory.getIntArray(TAG_YCBCR_SUBSAMPLING);
    471         if (positions == null)
    472             return null;
    473         if (positions[0] == 2 && positions[1] == 1) {
    474             return "YCbCr4:2:2";
    475         } else if (positions[0] == 2 && positions[1] == 2) {
    476             return "YCbCr4:2:0";
    477         } else {
    478             return "(Unknown)";
    479         }
    480     }
    481 
    482     @Nullable
    483     public String getPlanarConfigurationDescription()
    484     {
    485         // When image format is no compression YCbCr, this value shows byte aligns of YCbCr
    486         // data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for each subsampling
    487         // pixel. If value is '2', Y/Cb/Cr value is separated and stored to Y plane/Cb plane/Cr
    488         // plane format.
    489         return getIndexedDescription(TAG_PLANAR_CONFIGURATION,
    490             1,
    491             "Chunky (contiguous for each subsampling pixel)",
    492             "Separate (Y-plane/Cb-plane/Cr-plane format)"
    493         );
    494     }
    495 
    496     @Nullable
    497     public String getSamplesPerPixelDescription()
    498     {
    499         String value = _directory.getString(TAG_SAMPLES_PER_PIXEL);
    500         return value == null ? null : value + " samples/pixel";
    501     }
    502 
    503     @Nullable
    504     public String getRowsPerStripDescription()
    505     {
    506         final String value = _directory.getString(TAG_ROWS_PER_STRIP);
    507         return value == null ? null : value + " rows/strip";
    508     }
    509 
    510     @Nullable
    511     public String getStripByteCountsDescription()
    512     {
    513         final String value = _directory.getString(TAG_STRIP_BYTE_COUNTS);
    514         return value == null ? null : value + " bytes";
    515     }
    516 
    517     @Nullable
    518     public String getPhotometricInterpretationDescription()
    519     {
    520         // Shows the color space of the image data components
    521         Integer value = _directory.getInteger(TAG_PHOTOMETRIC_INTERPRETATION);
    522         if (value == null)
    523             return null;
    524         switch (value) {
    525             case 0: return "WhiteIsZero";
    526             case 1: return "BlackIsZero";
    527             case 2: return "RGB";
    528             case 3: return "RGB Palette";
    529             case 4: return "Transparency Mask";
    530             case 5: return "CMYK";
    531             case 6: return "YCbCr";
    532             case 8: return "CIELab";
    533             case 9: return "ICCLab";
    534             case 10: return "ITULab";
    535             case 32803: return "Color Filter Array";
    536             case 32844: return "Pixar LogL";
    537             case 32845: return "Pixar LogLuv";
    538             case 32892: return "Linear Raw";
    539             default:
    540                 return "Unknown colour space";
    541         }
    542     }
    543 
    544     @Nullable
    545     public String getBitsPerSampleDescription()
    546     {
    547         String value = _directory.getString(TAG_BITS_PER_SAMPLE);
    548         return value == null ? null : value + " bits/component/pixel";
    549     }
    550 
    551     @Nullable
    552     public String getFocalPlaneXResolutionDescription()
    553     {
    554         Rational rational = _directory.getRational(TAG_FOCAL_PLANE_X_RESOLUTION);
    555         if (rational == null)
    556             return null;
    557         final String unit = getFocalPlaneResolutionUnitDescription();
    558         return rational.getReciprocal().toSimpleString(_allowDecimalRepresentationOfRationals)
    559             + (unit == null ? "" : " " + unit.toLowerCase());
    560     }
    561 
    562     @Nullable
    563     public String getFocalPlaneYResolutionDescription()
    564     {
    565         Rational rational = _directory.getRational(TAG_FOCAL_PLANE_Y_RESOLUTION);
    566         if (rational == null)
    567             return null;
    568         final String unit = getFocalPlaneResolutionUnitDescription();
    569         return rational.getReciprocal().toSimpleString(_allowDecimalRepresentationOfRationals)
    570             + (unit == null ? "" : " " + unit.toLowerCase());
    571     }
    572 
    573     @Nullable
    574     public String getFocalPlaneResolutionUnitDescription()
    575     {
    576         // Unit of FocalPlaneXResolution/FocalPlaneYResolution.
    577         // '1' means no-unit, '2' inch, '3' centimeter.
    578         return getIndexedDescription(TAG_FOCAL_PLANE_RESOLUTION_UNIT,
    579             1,
    580             "(No unit)",
    581             "Inches",
    582             "cm"
    583         );
    584     }
    585 
    586     @Nullable
    587     public String getExifImageWidthDescription()
    588     {
    589         final Integer value = _directory.getInteger(TAG_EXIF_IMAGE_WIDTH);
    590         return value == null ? null : value + " pixels";
    591     }
    592 
    593     @Nullable
    594     public String getExifImageHeightDescription()
    595     {
    596         final Integer value = _directory.getInteger(TAG_EXIF_IMAGE_HEIGHT);
    597         return value == null ? null : value + " pixels";
    598     }
    599 
    600     @Nullable
    601     public String getColorSpaceDescription()
    602     {
    603         final Integer value = _directory.getInteger(TAG_COLOR_SPACE);
    604         if (value == null)
    605             return null;
    606         if (value == 1)
    607             return "sRGB";
    608         if (value == 65535)
    609             return "Undefined";
    610         return "Unknown (" + value + ")";
    611     }
    612 
    613     @Nullable
    614     public String getFocalLengthDescription()
    615     {
    616         Rational value = _directory.getRational(TAG_FOCAL_LENGTH);
    617         if (value == null)
    618             return null;
    619         java.text.DecimalFormat formatter = new DecimalFormat("0.0##");
    620         return formatter.format(value.doubleValue()) + " mm";
    621     }
    622 
    623     @Nullable
    624     public String getFlashDescription()
    625     {
    626         /*
    627          * This is a bit mask.
    628          * 0 = flash fired
    629          * 1 = return detected
    630          * 2 = return able to be detected
    631          * 3 = unknown
    632          * 4 = auto used
    633          * 5 = unknown
    634          * 6 = red eye reduction used
    635          */
    636 
    637         final Integer value = _directory.getInteger(TAG_FLASH);
    638 
    639         if (value == null)
    640             return null;
    641 
    642         StringBuilder sb = new StringBuilder();
    643 
    644         if ((value & 0x1) != 0)
    645             sb.append("Flash fired");
    646         else
    647             sb.append("Flash did not fire");
    648 
    649         // check if we're able to detect a return, before we mention it
    650         if ((value & 0x4) != 0) {
    651             if ((value & 0x2) != 0)
    652                 sb.append(", return detected");
    653             else
    654                 sb.append(", return not detected");
    655         }
    656 
    657         if ((value & 0x10) != 0)
    658             sb.append(", auto");
    659 
    660         if ((value & 0x40) != 0)
    661             sb.append(", red-eye reduction");
    662 
    663         return sb.toString();
    664     }
    665 
    666     @Nullable
    667     public String getWhiteBalanceDescription()
    668     {
    669         // '0' means unknown, '1' daylight, '2' fluorescent, '3' tungsten, '10' flash,
    670         // '17' standard light A, '18' standard light B, '19' standard light C, '20' D55,
    671         // '21' D65, '22' D75, '255' other.
    672         final Integer value = _directory.getInteger(TAG_WHITE_BALANCE);
    673         if (value == null)
    674             return null;
    675         switch (value) {
    676             case 0: return "Unknown";
    677             case 1: return "Daylight";
    678             case 2: return "Florescent";
    679             case 3: return "Tungsten";
    680             case 10: return "Flash";
    681             case 17: return "Standard light";
    682             case 18: return "Standard light (B)";
    683             case 19: return "Standard light (C)";
    684             case 20: return "D55";
    685             case 21: return "D65";
    686             case 22: return "D75";
    687             case 255: return "(Other)";
    688             default:
    689                 return "Unknown (" + value + ")";
    690         }
    691     }
    692 
    693     @Nullable
    694     public String getMeteringModeDescription()
    695     {
    696         // '0' means unknown, '1' average, '2' center weighted average, '3' spot
    697         // '4' multi-spot, '5' multi-segment, '6' partial, '255' other
    698         Integer value = _directory.getInteger(TAG_METERING_MODE);
    699         if (value == null)
    700             return null;
    701         switch (value) {
    702             case 0: return "Unknown";
    703             case 1: return "Average";
    704             case 2: return "Center weighted average";
    705             case 3: return "Spot";
    706             case 4: return "Multi-spot";
    707             case 5: return "Multi-segment";
    708             case 6: return "Partial";
    709             case 255: return "(Other)";
    710             default:
    711                 return "";
    712         }
    713     }
    714 
    715     @Nullable
    716     public String getSubjectDistanceDescription()
    717     {
    718         Rational value = _directory.getRational(TAG_SUBJECT_DISTANCE);
    719         if (value == null)
    720             return null;
    721         java.text.DecimalFormat formatter = new DecimalFormat("0.0##");
    722         return formatter.format(value.doubleValue()) + " metres";
    723     }
    724 
    725     @Nullable
    726     public String getCompressedAverageBitsPerPixelDescription()
    727     {
    728         Rational value = _directory.getRational(TAG_COMPRESSED_AVERAGE_BITS_PER_PIXEL);
    729         if (value == null)
    730             return null;
    731         String ratio = value.toSimpleString(_allowDecimalRepresentationOfRationals);
    732         return value.isInteger() && value.intValue() == 1
    733             ? ratio + " bit/pixel"
    734             : ratio + " bits/pixel";
    735     }
    736 
    737     @Nullable
    738     public String getExposureTimeDescription()
    739     {
    740         String value = _directory.getString(TAG_EXPOSURE_TIME);
    741         return value == null ? null : value + " sec";
    742     }
    743 
    744     @Nullable
    745     public String getShutterSpeedDescription()
    746     {
    747         // I believe this method to now be stable, but am leaving some alternative snippets of
    748         // code in here, to assist anyone who's looking into this (given that I don't have a public CVS).
    749 
    750 //        float apexValue = _directory.getFloat(ExifSubIFDDirectory.TAG_SHUTTER_SPEED);
    751 //        int apexPower = (int)Math.pow(2.0, apexValue);
    752 //        return "1/" + apexPower + " sec";
    753         // TODO test this method
    754         // thanks to Mark Edwards for spotting and patching a bug in the calculation of this
    755         // description (spotted bug using a Canon EOS 300D)
    756         // thanks also to Gli Blr for spotting this bug
    757         Float apexValue = _directory.getFloatObject(TAG_SHUTTER_SPEED);
    758         if (apexValue == null)
    759             return null;
    760         if (apexValue <= 1) {
    761             float apexPower = (float)(1 / (Math.exp(apexValue * Math.log(2))));
    762             long apexPower10 = Math.round((double)apexPower * 10.0);
    763             float fApexPower = (float)apexPower10 / 10.0f;
    764             return fApexPower + " sec";
    765         } else {
    766             int apexPower = (int)((Math.exp(apexValue * Math.log(2))));
    767             return "1/" + apexPower + " sec";
    768         }
    769 
    770 /*
    771         // This alternative implementation offered by Bill Richards
    772         // TODO determine which is the correct / more-correct implementation
    773         double apexValue = _directory.getDouble(ExifSubIFDDirectory.TAG_SHUTTER_SPEED);
    774         double apexPower = Math.pow(2.0, apexValue);
    775 
    776         StringBuffer sb = new StringBuffer();
    777         if (apexPower > 1)
    778             apexPower = Math.floor(apexPower);
    779 
    780         if (apexPower < 1) {
    781             sb.append((int)Math.round(1/apexPower));
    782         } else {
    783             sb.append("1/");
    784             sb.append((int)apexPower);
    785         }
    786         sb.append(" sec");
    787         return sb.toString();
    788 */
    789     }
    790 
    791     @Nullable
    792     public String getFNumberDescription()
    793     {
    794         Rational value = _directory.getRational(TAG_FNUMBER);
    795         if (value == null)
    796             return null;
    797         return "F" + SimpleDecimalFormatter.format(value.doubleValue());
    798     }
    799 
    800     @Nullable
    801     public String getSensingMethodDescription()
    802     {
    803         // '1' Not defined, '2' One-chip color area sensor, '3' Two-chip color area sensor
    804         // '4' Three-chip color area sensor, '5' Color sequential area sensor
    805         // '7' Trilinear sensor '8' Color sequential linear sensor,  'Other' reserved
    806         return getIndexedDescription(TAG_SENSING_METHOD,
    807             1,
    808             "(Not defined)",
    809             "One-chip color area sensor",
    810             "Two-chip color area sensor",
    811             "Three-chip color area sensor",
    812             "Color sequential area sensor",
    813             null,
    814             "Trilinear sensor",
    815             "Color sequential linear sensor"
    816         );
    817     }
    818 
    819     @Nullable
    820     public String getComponentConfigurationDescription()
    821     {
    822         int[] components = _directory.getIntArray(TAG_COMPONENTS_CONFIGURATION);
    823         if (components == null)
    824             return null;
    825         String[] componentStrings = {"", "Y", "Cb", "Cr", "R", "G", "B"};
    826         StringBuilder componentConfig = new StringBuilder();
    827         for (int i = 0; i < Math.min(4, components.length); i++) {
    828             int j = components[i];
    829             if (j > 0 && j < componentStrings.length) {
    830                 componentConfig.append(componentStrings[j]);
    831             }
    832         }
    833         return componentConfig.toString();
    834     }
    83536}
Note: See TracChangeset for help on using the changeset viewer.