com.drew.metadata.exif.makernotes.PanasonicMakernoteDescriptor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of metadata-extractor Show documentation
Show all versions of metadata-extractor Show documentation
This is a fork of com.drewnoakes' metadata-extractor that relocates com.adobe.internal to com.adobe.
Java library for extracting EXIF, IPTC, XMP, ICC and other metadata from image and video files.
/*
* Copyright 2002-2019 Drew Noakes and contributors
*
* 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:
*
* https://drewnoakes.com/code/exif/
* https://github.com/drewnoakes/metadata-extractor
*/
package com.drew.metadata.exif.makernotes;
import com.drew.lang.ByteArrayReader;
import com.drew.lang.Charsets;
import com.drew.lang.RandomAccessReader;
import com.drew.lang.annotations.NotNull;
import com.drew.lang.annotations.Nullable;
import com.drew.metadata.Age;
import com.drew.metadata.Face;
import com.drew.metadata.TagDescriptor;
import java.text.DecimalFormat;
import java.io.IOException;
import static com.drew.metadata.exif.makernotes.PanasonicMakernoteDirectory.*;
/**
* Provides human-readable string representations of tag values stored in a {@link PanasonicMakernoteDirectory}.
*
* Some information about this makernote taken from here:
*
* - http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html
* - http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Panasonic.html
*
*
* @author Drew Noakes https://drewnoakes.com
* @author Philipp Sandhaus
*/
@SuppressWarnings("WeakerAccess")
public class PanasonicMakernoteDescriptor extends TagDescriptor
{
public PanasonicMakernoteDescriptor(@NotNull PanasonicMakernoteDirectory directory)
{
super(directory);
}
@Override
@Nullable
public String getDescription(int tagType)
{
switch (tagType) {
case TAG_QUALITY_MODE:
return getQualityModeDescription();
case TAG_FIRMWARE_VERSION:
return getVersionDescription();
case TAG_WHITE_BALANCE:
return getWhiteBalanceDescription();
case TAG_FOCUS_MODE:
return getFocusModeDescription();
case TAG_AF_AREA_MODE:
return getAfAreaModeDescription();
case TAG_IMAGE_STABILIZATION:
return getImageStabilizationDescription();
case TAG_MACRO_MODE:
return getMacroModeDescription();
case TAG_RECORD_MODE:
return getRecordModeDescription();
case TAG_AUDIO:
return getAudioDescription();
case TAG_UNKNOWN_DATA_DUMP:
return getUnknownDataDumpDescription();
case TAG_COLOR_EFFECT:
return getColorEffectDescription();
case TAG_UPTIME:
return getUptimeDescription();
case TAG_BURST_MODE:
return getBurstModeDescription();
case TAG_CONTRAST_MODE:
return getContrastModeDescription();
case TAG_NOISE_REDUCTION:
return getNoiseReductionDescription();
case TAG_SELF_TIMER:
return getSelfTimerDescription();
case TAG_ROTATION:
return getRotationDescription();
case TAG_AF_ASSIST_LAMP:
return getAfAssistLampDescription();
case TAG_COLOR_MODE:
return getColorModeDescription();
case TAG_OPTICAL_ZOOM_MODE:
return getOpticalZoomModeDescription();
case TAG_CONVERSION_LENS:
return getConversionLensDescription();
case TAG_CONTRAST:
return getContrastDescription();
case TAG_WORLD_TIME_LOCATION:
return getWorldTimeLocationDescription();
case TAG_ADVANCED_SCENE_MODE:
return getAdvancedSceneModeDescription();
case TAG_FACE_DETECTION_INFO:
return getDetectedFacesDescription();
case TAG_TRANSFORM:
return getTransformDescription();
case TAG_TRANSFORM_1:
return getTransform1Description();
case TAG_INTELLIGENT_EXPOSURE:
return getIntelligentExposureDescription();
case TAG_FLASH_WARNING:
return getFlashWarningDescription();
case TAG_COUNTRY:
return getCountryDescription();
case TAG_STATE:
return getStateDescription();
case TAG_CITY:
return getCityDescription();
case TAG_LANDMARK:
return getLandmarkDescription();
case TAG_INTELLIGENT_RESOLUTION:
return getIntelligentResolutionDescription();
case TAG_FACE_RECOGNITION_INFO:
return getRecognizedFacesDescription();
case TAG_SCENE_MODE:
return getSceneModeDescription();
case TAG_FLASH_FIRED:
return getFlashFiredDescription();
case TAG_TEXT_STAMP:
return getTextStampDescription();
case TAG_TEXT_STAMP_1:
return getTextStamp1Description();
case TAG_TEXT_STAMP_2:
return getTextStamp2Description();
case TAG_TEXT_STAMP_3:
return getTextStamp3Description();
case TAG_MAKERNOTE_VERSION:
return getMakernoteVersionDescription();
case TAG_EXIF_VERSION:
return getExifVersionDescription();
case TAG_INTERNAL_SERIAL_NUMBER:
return getInternalSerialNumberDescription();
case TAG_TITLE:
return getTitleDescription();
case TAG_BRACKET_SETTINGS:
return getBracketSettingsDescription();
case TAG_FLASH_CURTAIN:
return getFlashCurtainDescription();
case TAG_LONG_EXPOSURE_NOISE_REDUCTION:
return getLongExposureNoiseReductionDescription();
case TAG_BABY_NAME:
return getBabyNameDescription();
case TAG_LOCATION:
return getLocationDescription();
case TAG_LENS_FIRMWARE_VERSION:
return getLensFirmwareVersionDescription();
case TAG_INTELLIGENT_D_RANGE:
return getIntelligentDRangeDescription();
case TAG_CLEAR_RETOUCH:
return getClearRetouchDescription();
case TAG_PHOTO_STYLE:
return getPhotoStyleDescription();
case TAG_SHADING_COMPENSATION:
return getShadingCompensationDescription();
case TAG_ACCELEROMETER_Z:
return getAccelerometerZDescription();
case TAG_ACCELEROMETER_X:
return getAccelerometerXDescription();
case TAG_ACCELEROMETER_Y:
return getAccelerometerYDescription();
case TAG_CAMERA_ORIENTATION:
return getCameraOrientationDescription();
case TAG_ROLL_ANGLE:
return getRollAngleDescription();
case TAG_PITCH_ANGLE:
return getPitchAngleDescription();
case TAG_SWEEP_PANORAMA_DIRECTION:
return getSweepPanoramaDirectionDescription();
case TAG_TIMER_RECORDING:
return getTimerRecordingDescription();
case TAG_HDR:
return getHDRDescription();
case TAG_SHUTTER_TYPE:
return getShutterTypeDescription();
case TAG_TOUCH_AE:
return getTouchAeDescription();
case TAG_BABY_AGE:
return getBabyAgeDescription();
case TAG_BABY_AGE_1:
return getBabyAge1Description();
default:
return super.getDescription(tagType);
}
}
@Nullable
public String getTextStampDescription()
{
return getIndexedDescription(TAG_TEXT_STAMP, 1, "Off", "On");
}
@Nullable
public String getTextStamp1Description()
{
return getIndexedDescription(TAG_TEXT_STAMP_1, 1, "Off", "On");
}
@Nullable
public String getTextStamp2Description()
{
return getIndexedDescription(TAG_TEXT_STAMP_2, 1, "Off", "On");
}
@Nullable
public String getTextStamp3Description()
{
return getIndexedDescription(TAG_TEXT_STAMP_3, 1, "Off", "On");
}
@Nullable
public String getMacroModeDescription()
{
return getIndexedDescription(TAG_MACRO_MODE, 1, "Off", "On");
}
@Nullable
public String getFlashFiredDescription()
{
return getIndexedDescription(TAG_FLASH_FIRED, 1, "Off", "On");
}
@Nullable
public String getImageStabilizationDescription()
{
return getIndexedDescription(TAG_IMAGE_STABILIZATION,
2,
"On, Mode 1",
"Off",
"On, Mode 2"
);
}
@Nullable
public String getAudioDescription()
{
return getIndexedDescription(TAG_AUDIO, 1, "Off", "On");
}
@Nullable
public String getTransformDescription()
{
return getTransformDescription(TAG_TRANSFORM);
}
@Nullable
public String getTransform1Description()
{
return getTransformDescription(TAG_TRANSFORM_1);
}
@Nullable
private String getTransformDescription(int tag)
{
byte[] values = _directory.getByteArray(tag);
if (values == null)
return null;
RandomAccessReader reader = new ByteArrayReader(values);
try
{
int val1 = reader.getUInt16(0);
int val2 = reader.getUInt16(2);
if (val1 == -1 && val2 == 1)
return "Slim Low";
if (val1 == -3 && val2 == 2)
return "Slim High";
if (val1 == 0 && val2 == 0)
return "Off";
if (val1 == 1 && val2 == 1)
return "Stretch Low";
if (val1 == 3 && val2 == 2)
return "Stretch High";
return "Unknown (" + val1 + " " + val2 + ")";
} catch (IOException e) {
return null;
}
}
@Nullable
public String getIntelligentExposureDescription()
{
return getIndexedDescription(TAG_INTELLIGENT_EXPOSURE,
"Off", "Low", "Standard", "High");
}
@Nullable
public String getFlashWarningDescription()
{
return getIndexedDescription(TAG_FLASH_WARNING,
"No", "Yes (Flash required but disabled)");
}
@Nullable
private static String trim(@Nullable String s)
{
return s == null ? null : s.trim();
}
@Nullable
public String getCountryDescription()
{
return trim(getStringFromBytes(TAG_COUNTRY, Charsets.UTF_8));
}
@Nullable
public String getStateDescription()
{
return trim(getStringFromBytes(TAG_STATE, Charsets.UTF_8));
}
@Nullable
public String getCityDescription()
{
return trim(getStringFromBytes(TAG_CITY, Charsets.UTF_8));
}
@Nullable
public String getLandmarkDescription()
{
return trim(getStringFromBytes(TAG_LANDMARK, Charsets.UTF_8));
}
@Nullable
public String getTitleDescription()
{
return trim(getStringFromBytes(TAG_TITLE, Charsets.UTF_8));
}
@Nullable
public String getBracketSettingsDescription()
{
return getIndexedDescription(TAG_BRACKET_SETTINGS,
"No Bracket", "3 Images, Sequence 0/-/+", "3 Images, Sequence -/0/+", "5 Images, Sequence 0/-/+",
"5 Images, Sequence -/0/+", "7 Images, Sequence 0/-/+", "7 Images, Sequence -/0/+");
}
@Nullable
public String getFlashCurtainDescription()
{
return getIndexedDescription(TAG_FLASH_CURTAIN,
"n/a", "1st", "2nd");
}
@Nullable
public String getLongExposureNoiseReductionDescription()
{
return getIndexedDescription(TAG_LONG_EXPOSURE_NOISE_REDUCTION, 1,
"Off", "On");
}
@Nullable
public String getLensFirmwareVersionDescription()
{
// lens version has 4 parts separated by periods
byte[] bytes = _directory.getByteArray(TAG_LENS_FIRMWARE_VERSION);
if (bytes == null)
return null;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(bytes[i]);
if (i < bytes.length - 1)
sb.append(".");
}
return sb.toString();
//return string.Join(".", bytes.Select(b => b.ToString()).ToArray());
}
@Nullable
public String getIntelligentDRangeDescription()
{
return getIndexedDescription(TAG_INTELLIGENT_D_RANGE,
"Off", "Low", "Standard", "High");
}
@Nullable
public String getClearRetouchDescription()
{
return getIndexedDescription(TAG_CLEAR_RETOUCH,
"Off", "On");
}
@Nullable
public String getPhotoStyleDescription()
{
return getIndexedDescription(TAG_PHOTO_STYLE,
"Auto", "Standard or Custom", "Vivid", "Natural", "Monochrome", "Scenery", "Portrait");
}
@Nullable
public String getShadingCompensationDescription()
{
return getIndexedDescription(TAG_SHADING_COMPENSATION,
"Off", "On");
}
@Nullable
public String getAccelerometerZDescription()
{
Integer value = _directory.getInteger(TAG_ACCELEROMETER_Z);
if (value == null)
return null;
// positive is acceleration upwards
return String.valueOf(value.shortValue());
}
@Nullable
public String getAccelerometerXDescription()
{
Integer value = _directory.getInteger(TAG_ACCELEROMETER_X);
if (value == null)
return null;
// positive is acceleration to the left
return String.valueOf(value.shortValue());
}
@Nullable
public String getAccelerometerYDescription()
{
Integer value = _directory.getInteger(TAG_ACCELEROMETER_Y);
if (value == null)
return null;
// positive is acceleration backwards
return String.valueOf(value.shortValue());
}
@Nullable
public String getCameraOrientationDescription()
{
return getIndexedDescription(TAG_CAMERA_ORIENTATION,
"Normal", "Rotate CW", "Rotate 180", "Rotate CCW", "Tilt Upwards", "Tile Downwards");
}
@Nullable
public String getRollAngleDescription()
{
Integer value = _directory.getInteger(TAG_ROLL_ANGLE);
if (value == null)
return null;
DecimalFormat format = new DecimalFormat("0.#");
// converted to degrees of clockwise camera rotation
return format.format(value.shortValue() / 10.0);
}
@Nullable
public String getPitchAngleDescription()
{
Integer value = _directory.getInteger(TAG_PITCH_ANGLE);
if (value == null)
return null;
DecimalFormat format = new DecimalFormat("0.#");
// converted to degrees of upward camera tilt
return format.format(-value.shortValue() / 10.0);
}
@Nullable
public String getSweepPanoramaDirectionDescription()
{
return getIndexedDescription(TAG_SWEEP_PANORAMA_DIRECTION,
"Off", "Left to Right", "Right to Left", "Top to Bottom", "Bottom to Top");
}
@Nullable
public String getTimerRecordingDescription()
{
return getIndexedDescription(TAG_TIMER_RECORDING,
"Off", "Time Lapse", "Stop-motion Animation");
}
@Nullable
public String getHDRDescription()
{
Integer value = _directory.getInteger(TAG_HDR);
if (value == null)
return null;
switch (value)
{
case 0:
return "Off";
case 100:
return "1 EV";
case 200:
return "2 EV";
case 300:
return "3 EV";
case 32868:
return "1 EV (Auto)";
case 32968:
return "2 EV (Auto)";
case 33068:
return "3 EV (Auto)";
default:
return String.format("Unknown (%d)", value);
}
}
@Nullable
public String getShutterTypeDescription()
{
return getIndexedDescription(TAG_SHUTTER_TYPE,
"Mechanical", "Electronic", "Hybrid");
}
@Nullable
public String getTouchAeDescription()
{
return getIndexedDescription(TAG_TOUCH_AE,
"Off", "On");
}
@Nullable
public String getBabyNameDescription()
{
return trim(getStringFromBytes(TAG_BABY_NAME, Charsets.UTF_8));
}
@Nullable
public String getLocationDescription()
{
return trim(getStringFromBytes(TAG_LOCATION, Charsets.UTF_8));
}
@Nullable
public String getIntelligentResolutionDescription()
{
return getIndexedDescription(TAG_INTELLIGENT_RESOLUTION,
"Off", null, "Auto", "On");
}
@Nullable
public String getContrastDescription()
{
return getIndexedDescription(TAG_CONTRAST, "Normal");
}
@Nullable
public String getWorldTimeLocationDescription()
{
return getIndexedDescription(TAG_WORLD_TIME_LOCATION,
1, "Home", "Destination");
}
@Nullable
public String getAdvancedSceneModeDescription()
{
return getIndexedDescription(TAG_ADVANCED_SCENE_MODE,
1,
"Normal",
"Outdoor/Illuminations/Flower/HDR Art",
"Indoor/Architecture/Objects/HDR B&W",
"Creative",
"Auto",
null,
"Expressive",
"Retro",
"Pure",
"Elegant",
null,
"Monochrome",
"Dynamic Art",
"Silhouette"
);
}
@Nullable
public String getUnknownDataDumpDescription()
{
return getByteLengthDescription(TAG_UNKNOWN_DATA_DUMP);
}
@Nullable
public String getColorEffectDescription()
{
return getIndexedDescription(TAG_COLOR_EFFECT,
1, "Off", "Warm", "Cool", "Black & White", "Sepia"
);
}
@Nullable
public String getUptimeDescription()
{
Integer value = _directory.getInteger(TAG_UPTIME);
if (value == null)
return null;
return value / 100f + " s";
}
@Nullable
public String getBurstModeDescription()
{
return getIndexedDescription(TAG_BURST_MODE,
"Off", null, "On", "Indefinite", "Unlimited"
);
}
@Nullable
public String getContrastModeDescription()
{
Integer value = _directory.getInteger(TAG_CONTRAST_MODE);
if (value == null)
return null;
switch (value) {
case 0x0: return "Normal";
case 0x1: return "Low";
case 0x2: return "High";
case 0x6: return "Medium Low";
case 0x7: return "Medium High";
case 0x100: return "Low";
case 0x110: return "Normal";
case 0x120: return "High";
default:
return "Unknown (" + value + ")";
}
}
@Nullable
public String getNoiseReductionDescription()
{
return getIndexedDescription(TAG_NOISE_REDUCTION,
"Standard (0)", "Low (-1)", "High (+1)", "Lowest (-2)", "Highest (+2)"
);
}
@Nullable
public String getSelfTimerDescription()
{
return getIndexedDescription(TAG_SELF_TIMER,
1, "Off", "10 s", "2 s"
);
}
@Nullable
public String getRotationDescription()
{
Integer value = _directory.getInteger(TAG_ROTATION);
if (value == null)
return null;
switch (value) {
case 1: return "Horizontal";
case 3: return "Rotate 180";
case 6: return "Rotate 90 CW";
case 8: return "Rotate 270 CW";
default:
return "Unknown (" + value + ")";
}
}
@Nullable
public String getAfAssistLampDescription()
{
return getIndexedDescription(TAG_AF_ASSIST_LAMP,
1, "Fired", "Enabled but not used", "Disabled but required", "Disabled and not required"
);
}
@Nullable
public String getColorModeDescription()
{
return getIndexedDescription(TAG_COLOR_MODE,
"Normal", "Natural", "Vivid"
);
}
@Nullable
public String getOpticalZoomModeDescription()
{
return getIndexedDescription(TAG_OPTICAL_ZOOM_MODE,
1, "Standard", "Extended"
);
}
@Nullable
public String getConversionLensDescription()
{
return getIndexedDescription(TAG_CONVERSION_LENS,
1, "Off", "Wide", "Telephoto", "Macro"
);
}
@Nullable
public String getDetectedFacesDescription()
{
return buildFacesDescription(_directory.getDetectedFaces());
}
@Nullable
public String getRecognizedFacesDescription()
{
return buildFacesDescription(_directory.getRecognizedFaces());
}
@Nullable
private String buildFacesDescription(@Nullable Face[] faces)
{
if (faces == null)
return null;
StringBuilder result = new StringBuilder();
for (int i = 0; i < faces.length; i++)
result.append("Face ").append(i + 1).append(": ").append(faces[i].toString()).append("\n");
return result.length() > 0 ? result.substring(0, result.length() - 1) : null;
}
private static final String[] _sceneModes = new String[] {
"Normal", // 1
"Portrait",
"Scenery",
"Sports",
"Night Portrait",
"Program",
"Aperture Priority",
"Shutter Priority",
"Macro",
"Spot", // 10
"Manual",
"Movie Preview",
"Panning",
"Simple",
"Color Effects",
"Self Portrait",
"Economy",
"Fireworks",
"Party",
"Snow", // 20
"Night Scenery",
"Food",
"Baby",
"Soft Skin",
"Candlelight",
"Starry Night",
"High Sensitivity",
"Panorama Assist",
"Underwater",
"Beach", // 30
"Aerial Photo",
"Sunset",
"Pet",
"Intelligent ISO",
"Clipboard",
"High Speed Continuous Shooting",
"Intelligent Auto",
null,
"Multi-aspect",
null, // 40
"Transform",
"Flash Burst",
"Pin Hole",
"Film Grain",
"My Color",
"Photo Frame",
null,
null,
null,
null, // 50
"HDR"
};
@Nullable
public String getRecordModeDescription()
{
return getIndexedDescription(TAG_RECORD_MODE, 1, _sceneModes);
}
@Nullable
public String getSceneModeDescription()
{
return getIndexedDescription(TAG_SCENE_MODE, 1, _sceneModes);
}
@Nullable
public String getFocusModeDescription()
{
return getIndexedDescription(TAG_FOCUS_MODE, 1,
"Auto", "Manual", null, "Auto, Focus Button", "Auto, Continuous");
}
@Nullable
public String getAfAreaModeDescription()
{
int[] value = _directory.getIntArray(TAG_AF_AREA_MODE);
if (value == null || value.length < 2)
return null;
switch (value[0]) {
case 0:
switch (value[1]) {
case 1: return "Spot Mode On";
case 16: return "Spot Mode Off";
default: return "Unknown (" + value[0] + " " + value[1] + ")";
}
case 1:
switch (value[1]) {
case 0: return "Spot Focusing";
case 1: return "5-area";
default: return "Unknown (" + value[0] + " " + value[1] + ")";
}
case 16:
switch (value[1]) {
case 0: return "1-area";
case 16: return "1-area (high speed)";
default: return "Unknown (" + value[0] + " " + value[1] + ")";
}
case 32:
switch (value[1]) {
case 0: return "Auto or Face Detect";
case 1: return "3-area (left)";
case 2: return "3-area (center)";
case 3: return "3-area (right)";
default: return "Unknown (" + value[0] + " " + value[1] + ")";
}
case 64: return "Face Detect";
default: return "Unknown (" + value[0] + " " + value[1] + ")";
}
}
@Nullable
public String getQualityModeDescription()
{
return getIndexedDescription(TAG_QUALITY_MODE,
2,
"High", // 2
"Normal",
null,
null,
"Very High",
"Raw",
null,
"Motion Picture" // 9
);
}
@Nullable
public String getVersionDescription()
{
return getVersionBytesDescription(TAG_FIRMWARE_VERSION, 2);
}
@Nullable
public String getMakernoteVersionDescription()
{
return getVersionBytesDescription(TAG_MAKERNOTE_VERSION, 2);
}
@Nullable
public String getExifVersionDescription()
{
return getVersionBytesDescription(TAG_EXIF_VERSION, 2);
}
@Nullable
public String getInternalSerialNumberDescription()
{
return get7BitStringFromBytes(TAG_INTERNAL_SERIAL_NUMBER);
}
@Nullable
public String getWhiteBalanceDescription()
{
return getIndexedDescription(TAG_WHITE_BALANCE,
1,
"Auto", // 1
"Daylight",
"Cloudy",
"Incandescent",
"Manual",
null,
null,
"Flash",
null,
"Black & White", // 10
"Manual",
"Shade" // 12
);
}
@Nullable
public String getBabyAgeDescription()
{
final Age age = _directory.getAge(TAG_BABY_AGE);
return age == null ? null : age.toFriendlyString();
}
@Nullable
public String getBabyAge1Description()
{
final Age age = _directory.getAge(TAG_BABY_AGE_1);
return age == null ? null : age.toFriendlyString();
}
}