/*
* Copyright 2002-2012 Drew Noakes
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* More information about this project is available at:
*
* http://drewnoakes.com/code/exif/
* http://code.google.com/p/metadata-extractor/
*/
package com.drew.metadata.exif;
import com.drew.lang.Rational;
import com.drew.lang.StringUtil;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.TagDescriptor;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
/**
* Provides human-readable string representations of tag values stored in a <code>NikonType2MakernoteDirectory</code>.
*
* Type-2 applies to the E990 and D-series cameras such as the D1, D70 and D100.
*
* @author Drew Noakes http://drewnoakes.com
*/
public class NikonType2MakernoteDescriptor extends TagDescriptor<NikonType2MakernoteDirectory>
{
public NikonType2MakernoteDescriptor(@NotNull NikonType2MakernoteDirectory directory)
{
super(directory);
}
@Nullable
public String getDescription(int tagType)
{
switch (tagType)
{
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_PROGRAM_SHIFT:
return getProgramShiftDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_EXPOSURE_DIFFERENCE:
return getExposureDifferenceDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS:
return getLensDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT:
return getHueAdjustmentDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE:
return getColorModeDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION:
return getAutoFlashCompensationDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_EXPOSURE_COMPENSATION:
return getFlashExposureCompensationDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_BRACKET_COMPENSATION:
return getFlashBracketCompensationDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_EXPOSURE_TUNING:
return getExposureTuningDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS_STOPS:
return getLensStopsDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_COLOR_SPACE:
return getColorSpaceDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ACTIVE_D_LIGHTING:
return getActiveDLightingDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_VIGNETTE_CONTROL:
return getVignetteControlDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1:
return getIsoSettingDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM:
return getDigitalZoomDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_USED:
return getFlashUsedDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION:
return getAutoFocusPositionDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION:
return getFirmwareVersionDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS_TYPE:
return getLensTypeDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_SHOOTING_MODE:
return getShootingModeDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_NEF_COMPRESSION:
return getNEFCompressionDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_HIGH_ISO_NOISE_REDUCTION:
return getHighISONoiseReductionDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_POWER_UP_TIME:
return getPowerUpTimeDescription();
default:
return super.getDescription(tagType);
}
}
@Nullable
public String getPowerUpTimeDescription()
{
Long value = _directory.getLongObject(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_POWER_UP_TIME);
if (value==null)
return null; // TODO have observed a byte[8] here which is likely some kind of date (ticks as long?)
return new Date(value).toString();
}
@Nullable
public String getHighISONoiseReductionDescription()
{
Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_HIGH_ISO_NOISE_REDUCTION);
if (value==null)
return null;
switch (value) {
case 0: return "Off";
case 1: return "Minimal";
case 2: return "Low";
case 4: return "Normal";
case 6: return "High";
default: return "Unknown (" + value + ")";
}
}
@Nullable
public String getFlashUsedDescription()
{
Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_USED);
if (value==null)
return null;
switch (value) {
case 0: return "Flash Not Used";
case 1: return "Manual Flash";
case 3: return "Flash Not Ready";
case 7: return "External Flash";
case 8: return "Fired, Commander Mode";
case 9: return "Fired, TTL Mode";
default: return "Unknown (" + value + ")";
}
}
@Nullable
public String getNEFCompressionDescription()
{
Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_NEF_COMPRESSION);
if (value==null)
return null;
switch (value) {
case 1: return "Lossy (Type 1)";
case 3: return "Uncompressed";
case 7: return "Lossless";
case 8: return "Lossy (Type 2)";
default: return "Unknown (" + value + ")";
}
}
@Nullable
public String getShootingModeDescription()
{
Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_SHOOTING_MODE);
if (value==null)
return null;
Collection<String> bits = new ArrayList<String>();
if ((value&1)==1)
bits.add("Continuous");
else
bits.add("Single Frame");
if ((value&2)==2)
bits.add("Delay");
// Don't know about 3
if ((value&8)==8)
bits.add("PC Control");
if ((value&16)==16)
bits.add("Exposure Bracketing");
if ((value&32)==32)
bits.add("Auto ISO");
if ((value&64)==64)
bits.add("White-Balance Bracketing");
if ((value&128)==128)
bits.add("IR Control");
return StringUtil.join(bits, ", ");
}
@Nullable
public String getLensTypeDescription()
{
Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS_TYPE);
if (value==null)
return null;
Collection<String> bits = new ArrayList<String>();
// TODO validate these values, as 14 is labelled as AF-C elsewhere but appears here as AF-D-G-VR
if ((value&1)==1)
bits.add("MF");
else
bits.add("AF");
if ((value&2)==2)
bits.add("D");
if ((value&4)==4)
bits.add("G");
if ((value&8)==8)
bits.add("VR");
return StringUtil.join(bits, ", ");
}
@Nullable
public String getColorSpaceDescription()
{
Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_COLOR_SPACE);
if (value==null)
return null;
switch (value) {
case 1: return "sRGB";
case 2: return "Adobe RGB";
default: return "Unknown (" + value + ")";
}
}
@Nullable
public String getActiveDLightingDescription()
{
Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ACTIVE_D_LIGHTING);
if (value==null)
return null;
switch (value) {
case 0: return "Off";
case 1: return "Light";
case 3: return "Normal";
case 5: return "High";
case 7: return "Extra High";
case 65535: return "Auto";
default: return "Unknown (" + value + ")";
}
}
@Nullable
public String getVignetteControlDescription()
{
Integer value = _directory.getInteger(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_VIGNETTE_CONTROL);
if (value==null)
return null;
switch (value) {
case 0: return "Off";
case 1: return "Low";
case 3: return "Normal";
case 5: return "High";
default: return "Unknown (" + value + ")";
}
}
@Nullable
public String getAutoFocusPositionDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION);
if (values==null)
return null;
if (values.length != 4 || values[0] != 0 || values[2] != 0 || values[3] != 0) {
return "Unknown (" + _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION) + ")";
}
switch (values[1]) {
case 0:
return "Centre";
case 1:
return "Top";
case 2:
return "Bottom";
case 3:
return "Left";
case 4:
return "Right";
default:
return "Unknown (" + values[1] + ")";
}
}
@Nullable
public String getDigitalZoomDescription()
{
Rational value = _directory.getRational(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM);
if (value==null)
return null;
return value.intValue() == 1
? "No digital zoom"
: value.toSimpleString(true) + "x digital zoom";
}
@Nullable
public String getProgramShiftDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_PROGRAM_SHIFT);
return getEVDescription(values);
}
@Nullable
public String getExposureDifferenceDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_EXPOSURE_DIFFERENCE);
return getEVDescription(values);
}
@NotNull
public String getAutoFlashCompensationDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION);
return getEVDescription(values);
}
@NotNull
public String getFlashExposureCompensationDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_EXPOSURE_COMPENSATION);
return getEVDescription(values);
}
@NotNull
public String getFlashBracketCompensationDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_BRACKET_COMPENSATION);
return getEVDescription(values);
}
@NotNull
public String getExposureTuningDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_EXPOSURE_TUNING);
return getEVDescription(values);
}
@NotNull
public String getLensStopsDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS_STOPS);
return getEVDescription(values);
}
@Nullable
private static String getEVDescription(@Nullable int[] values)
{
if (values==null)
return null;
if (values.length<3 || values[2]==0)
return null;
final DecimalFormat decimalFormat = new DecimalFormat("0.##");
double ev = values[0] * values[1] / (double)values[2];
return decimalFormat.format(ev) + " EV";
}
@Nullable
public String getIsoSettingDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1);
if (values==null)
return null;
if (values[0] != 0 || values[1] == 0)
return "Unknown (" + _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1) + ")";
return "ISO " + values[1];
}
@Nullable
public String getLensDescription()
{
Rational[] values = _directory.getRationalArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS);
if (values==null)
return null;
if (values.length<4)
return _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS);
StringBuilder description = new StringBuilder();
description.append(values[0].intValue());
description.append('-');
description.append(values[1].intValue());
description.append("mm f/");
description.append(values[2].floatValue());
description.append('-');
description.append(values[3].floatValue());
return description.toString();
}
@Nullable
public String getHueAdjustmentDescription()
{
final String value = _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT);
if (value==null)
return null;
return value + " degrees";
}
@Nullable
public String getColorModeDescription()
{
String value = _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE);
if (value==null)
return null;
if (value.startsWith("MODE1"))
return "Mode I (sRGB)";
return value;
}
@Nullable
public String getFirmwareVersionDescription()
{
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION);
if (values==null)
return null;
return ExifSubIFDDescriptor.convertBytesToVersionString(values, 2);
}
}