Skip to content

Commit ae792e7

Browse files
committed
Extend Sony makernote handling
Decodes the ciphered data stored within the 9050B tag into its own directory.
1 parent 2fd3f66 commit ae792e7

File tree

5 files changed

+296
-8
lines changed

5 files changed

+296
-8
lines changed

Source/com/drew/metadata/exif/ExifTiffHandler.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,12 @@ public boolean tryEnterSubIfd(int tagId)
100100
pushDirectory(GpsDirectory.class);
101101
return true;
102102
}
103-
}
104-
105-
if (_currentDirectory instanceof ExifSubIFDDirectory) {
103+
} else if (_currentDirectory instanceof ExifSubIFDDirectory) {
106104
if (tagId == ExifSubIFDDirectory.TAG_INTEROP_OFFSET) {
107105
pushDirectory(ExifInteropDirectory.class);
108106
return true;
109107
}
110-
}
111-
112-
if (_currentDirectory instanceof OlympusMakernoteDirectory) {
108+
} else if (_currentDirectory instanceof OlympusMakernoteDirectory) {
113109
// Note: these also appear in customProcessTag because some are IFD pointers while others begin immediately
114110
// for the same directories
115111
switch(tagId) {
@@ -336,6 +332,16 @@ public boolean customProcessTag(final int tagOffset,
336332
}
337333
}
338334

335+
if (_currentDirectory instanceof SonyType1MakernoteDirectory) {
336+
if (tagId == SonyType1MakernoteDirectory.TAG_9050B) {
337+
byte[] bytes = reader.getBytes(tagOffset, byteCount);
338+
SonyTag9050bDirectory directory = SonyTag9050bDirectory.read(bytes);
339+
directory.setParent(_currentDirectory);
340+
_metadata.addDirectory(directory);
341+
return true;
342+
}
343+
}
344+
339345
return false;
340346
}
341347

@@ -878,8 +884,6 @@ private static void processReconyxHyperFire2Makernote(@NotNull final ReconyxHype
878884
// two unread bytes: the serial number's terminating null
879885
}
880886

881-
882-
883887
private static void processReconyxUltraFireMakernote(@NotNull final ReconyxUltraFireMakernoteDirectory directory, final int makernoteOffset, @NotNull final RandomAccessReader reader) throws IOException
884888
{
885889
directory.setString(ReconyxUltraFireMakernoteDirectory.TAG_LABEL, reader.getString(makernoteOffset, 9, Charsets.UTF_8));
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.drew.metadata.exif.makernotes;
2+
3+
import com.drew.metadata.Directory;
4+
5+
public abstract class SonyEncodedDataDirectoryBase extends Directory
6+
{
7+
private static final byte[] _substitution = new byte[]
8+
{
9+
0, 1, 50, (byte)177, 10, 14, (byte)135, 40, 2, (byte)204, (byte)202, (byte)173, 27, (byte)220, 8, (byte)237, 100,
10+
(byte)134, (byte)240, 79, (byte)140, 108, (byte)184, (byte)203, 105, (byte)196, 44, 3, (byte)151, (byte)182,
11+
(byte)147, 124, 20, (byte)243, (byte)226, 62, 48, (byte)142, (byte)215, 96, 28, (byte)161, (byte)171, 55,
12+
(byte)236, 117, (byte)190, 35, 21, 106, 89, 63, (byte)208, (byte)185, (byte)150, (byte)181, 80, 39, (byte)136,
13+
(byte)227, (byte)129, (byte)148, (byte)224, (byte)192, 4, 92, (byte)198, (byte)232, 95, 75, 112, 56, (byte)159,
14+
(byte)130, (byte)128, 81, 43, (byte)197, 69, 73, (byte)155, 33, 82, 83, 84, (byte)133, 11, 93, 97, (byte)218,
15+
123, 85, 38, 36, 7, 110, 54, 91, 71, (byte)183, (byte)217, 74, (byte)162, (byte)223, (byte)191, 18, 37,
16+
(byte)188, 30, 127, 86, (byte)234, 16, (byte)230, (byte)207, 103, 77, 60, (byte)145, (byte)131, (byte)225, 49,
17+
(byte)179, 111, (byte)244, 5, (byte)138, 70, (byte)200, 24, 118, 104, (byte)189, (byte)172, (byte)146, 42, 19,
18+
(byte)233, 15, (byte)163, 122, (byte)219, 61, (byte)212, (byte)231, 58, 26, 87, (byte)175, 32, 66, (byte)178,
19+
(byte)158, (byte)195, (byte)139, (byte)242, (byte)213, (byte)211, (byte)164, 126, 31, (byte)152, (byte)156,
20+
(byte)238, 116, (byte)165, (byte)166, (byte)167, (byte)216, 94, (byte)176, (byte)180, 52, (byte)206, (byte)168,
21+
121, 119, 90, (byte)193, (byte)137, (byte)174, (byte)154, 17, 51, (byte)157, (byte)245, 57, 25, 101, 120, 22,
22+
113, (byte)210, (byte)169, 68, 99, 64, 41, (byte)186, (byte)160, (byte)143, (byte)228, (byte)214, 59, (byte)132,
23+
13, (byte)194, 78, 88, (byte)221, (byte)153, 34, 107, (byte)201, (byte)187, 23, 6, (byte)229, 125, 102, 67, 98,
24+
(byte)246, (byte)205, 53, (byte)144, 46, 65, (byte)141, 109, (byte)170, 9, 115, (byte)149, 12, (byte)241, 29,
25+
(byte)222, 76, 47, 45, (byte)247, (byte)209, 114, (byte)235, (byte)239, 72, (byte)199, (byte)248, (byte)249,
26+
(byte)250, (byte)251, (byte)252, (byte)253, (byte)254, (byte)255
27+
};
28+
29+
protected static void decipherInPlace(byte[] bytes)
30+
{
31+
for (int i = 0; i < bytes.length; i++) {
32+
bytes[i] = _substitution[bytes[i] & 0xFF];
33+
}
34+
}
35+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.drew.metadata.exif.makernotes;
2+
3+
import com.drew.lang.annotations.NotNull;
4+
import com.drew.lang.annotations.Nullable;
5+
import com.drew.metadata.TagDescriptor;
6+
7+
public class SonyTag9050bDescriptor extends TagDescriptor<SonyTag9050bDirectory>
8+
{
9+
public SonyTag9050bDescriptor(@NotNull SonyTag9050bDirectory directory)
10+
{
11+
super(directory);
12+
}
13+
14+
@Override
15+
@Nullable
16+
public String getDescription(int tagType)
17+
{
18+
switch (tagType) {
19+
case SonyTag9050bDirectory.TAG_FLASH_STATUS:
20+
return getFlashStatusDescription();
21+
case SonyTag9050bDirectory.TAG_SONY_EXPOSURE_TIME:
22+
return getSonyExposureTimeDescription();
23+
case SonyTag9050bDirectory.TAG_INTERNAL_SERIAL_NUMBER:
24+
return getInternalSerialNumberDescription();
25+
default:
26+
return super.getDescription(tagType);
27+
}
28+
}
29+
30+
@Nullable
31+
public String getInternalSerialNumberDescription()
32+
{
33+
int[] values = _directory.getIntArray(SonyTag9050bDirectory.TAG_INTERNAL_SERIAL_NUMBER);
34+
if (values == null)
35+
return null;
36+
StringBuilder sn = new StringBuilder();
37+
for (int value : values) {
38+
sn.append(String.format("%02x", value));
39+
}
40+
return sn.toString();
41+
}
42+
43+
@Nullable
44+
public String getSonyExposureTimeDescription()
45+
{
46+
Float value = _directory.getFloatObject(SonyTag9050bDirectory.TAG_SONY_EXPOSURE_TIME);
47+
if (value == null)
48+
return null;
49+
if (value == 0)
50+
return "0";
51+
return String.format("1/%s", (int)(0.5 + (1 / value)));
52+
}
53+
54+
@Nullable
55+
public String getFlashStatusDescription()
56+
{
57+
58+
Integer value = _directory.getInteger(SonyTag9050bDirectory.TAG_FLASH_STATUS);
59+
if (value == null)
60+
return null;
61+
switch (value) {
62+
case 0x00:
63+
return "No flash present";
64+
case 0x02:
65+
return "Flash inhibited";
66+
case 0x40:
67+
return "Built-in flash present";
68+
case 0x41:
69+
return "Built-in flash fired";
70+
case 0x42:
71+
return "Built-in flash inhibited";
72+
case 0x80:
73+
return "External flash present";
74+
case 0x81:
75+
return "External flash fired";
76+
default:
77+
return "Unknown (" + value + ")";
78+
}
79+
}
80+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package com.drew.metadata.exif.makernotes;
2+
3+
import com.drew.lang.ByteArrayReader;
4+
import com.drew.lang.annotations.NotNull;
5+
6+
import java.io.IOException;
7+
import java.math.RoundingMode;
8+
import java.text.DecimalFormat;
9+
import java.util.HashMap;
10+
11+
public class SonyTag9050bDirectory extends SonyEncodedDataDirectoryBase
12+
{
13+
public static final int TAG_SHUTTER = 0x0026;
14+
public static final int TAG_FLASH_STATUS = 0x0039;
15+
public static final int TAG_SHUTTER_COUNT = 0x003a;
16+
public static final int TAG_SONY_EXPOSURE_TIME = 0x0046;
17+
public static final int TAG_SONY_F_NUMBER = 0x0048;
18+
public static final int TAG_RELEASE_MODE_2 = 0x006d;
19+
public static final int TAG_INTERNAL_SERIAL_NUMBER = 0x0088;
20+
public static final int TAG_LENS_MOUNT = 0x0105;
21+
public static final int TAG_LENS_FORMAT = 0x0106;
22+
public static final int TAG_LENS_TYPE_2 = 0x0107;
23+
public static final int TAG_DISTORTION_CORR_PARAMS_PRESENT = 0x010b;
24+
public static final int TAG_APS_C_SIZE_CAPTURE = 0x0114;
25+
public static final int TAG_LENS_SPEC_FEATURES = 0x0116;
26+
public static final int TAG_SHUTTER_COUNT_3 = 0x019f;
27+
28+
@NotNull
29+
private static final HashMap<Integer, String> _tagNameMap = new HashMap<Integer, String>();
30+
31+
static {
32+
_tagNameMap.put(TAG_SHUTTER, "Shutter");
33+
_tagNameMap.put(TAG_FLASH_STATUS, "Flash Status");
34+
_tagNameMap.put(TAG_SHUTTER_COUNT, "Shutter Count");
35+
_tagNameMap.put(TAG_SONY_EXPOSURE_TIME, "Sony Exposure Time");
36+
_tagNameMap.put(TAG_SONY_F_NUMBER, "Sony F Number");
37+
_tagNameMap.put(TAG_RELEASE_MODE_2, "Release Mode 2");
38+
_tagNameMap.put(TAG_INTERNAL_SERIAL_NUMBER, "Internal Serial Number");
39+
_tagNameMap.put(TAG_LENS_MOUNT, "Lens Mount");
40+
_tagNameMap.put(TAG_LENS_FORMAT, "Lens Format");
41+
_tagNameMap.put(TAG_LENS_TYPE_2, "Lens Type 2");
42+
_tagNameMap.put(TAG_DISTORTION_CORR_PARAMS_PRESENT, "Distortion Corr Params Present");
43+
_tagNameMap.put(TAG_APS_C_SIZE_CAPTURE, "APS-C Size Capture");
44+
_tagNameMap.put(TAG_LENS_SPEC_FEATURES, "Lens Spec Features");
45+
_tagNameMap.put(TAG_SHUTTER_COUNT_3, "Shutter Count 3");
46+
}
47+
48+
public SonyTag9050bDirectory()
49+
{
50+
this.setDescriptor(new SonyTag9050bDescriptor(this));
51+
}
52+
53+
@Override
54+
@NotNull
55+
public String getName()
56+
{
57+
return "Sony 9050B";
58+
}
59+
60+
@Override
61+
@NotNull
62+
protected HashMap<Integer, String> getTagNameMap()
63+
{
64+
return _tagNameMap;
65+
}
66+
67+
public static SonyTag9050bDirectory read(byte[] bytes)
68+
{
69+
SonyTag9050bDirectory dir = new SonyTag9050bDirectory();
70+
71+
try {
72+
// First, decipher the bytes
73+
decipherInPlace(bytes);
74+
75+
ByteArrayReader reader = new ByteArrayReader(bytes);
76+
reader.setMotorolaByteOrder(false);
77+
78+
// Shutter
79+
int offset = TAG_SHUTTER;
80+
int shutter0 = reader.getUInt16(offset);
81+
int shutter1 = reader.getUInt16(offset + 2);
82+
int shutter2 = reader.getUInt16(offset + 4);
83+
dir.setIntArray(TAG_SHUTTER, new int[]{shutter0, shutter1, shutter2});
84+
85+
// FlashStatus
86+
offset = TAG_FLASH_STATUS;
87+
int flashStatus = reader.getUInt8(offset);
88+
dir.setInt(TAG_FLASH_STATUS, flashStatus);
89+
90+
// ShutterCount
91+
offset = TAG_SHUTTER_COUNT;
92+
long shutterCount = reader.getUInt32(offset);
93+
dir.setLong(TAG_SHUTTER_COUNT, shutterCount);
94+
95+
// SonyExposureTime
96+
offset = TAG_SONY_EXPOSURE_TIME;
97+
int expTime = reader.getUInt16(offset);
98+
float expTimeFlt = (float)Math.pow(2, 16 - (expTime / 256));
99+
DecimalFormat format = new DecimalFormat("0.#############");
100+
format.setRoundingMode(RoundingMode.HALF_UP);
101+
dir.setFloat(TAG_SONY_EXPOSURE_TIME, expTimeFlt);
102+
103+
// SonyFNumber
104+
offset = TAG_SONY_F_NUMBER;
105+
int fNumber = reader.getUInt16(offset);
106+
dir.setInt(TAG_SONY_F_NUMBER, fNumber);
107+
108+
// ReleaseMode2
109+
// ReleaseMode2
110+
111+
offset = TAG_INTERNAL_SERIAL_NUMBER;
112+
int serialNum0 = reader.getUInt8(offset);
113+
int serialNum1 = reader.getUInt8(offset + 1);
114+
int serialNum2 = reader.getUInt8(offset + 2);
115+
int serialNum3 = reader.getUInt8(offset + 3);
116+
int serialNum4 = reader.getUInt8(offset + 4);
117+
int serialNum5 = reader.getUInt8(offset + 5);
118+
int[] serialNumber =
119+
new int[]{serialNum0, serialNum1, serialNum2, serialNum3, serialNum4, serialNum5};
120+
dir.setIntArray(TAG_INTERNAL_SERIAL_NUMBER, serialNumber);
121+
122+
// LensMount
123+
offset = TAG_LENS_MOUNT;
124+
int lensMount = reader.getUInt8(offset);
125+
dir.setInt(TAG_LENS_MOUNT, lensMount);
126+
127+
// LensFormat
128+
offset = TAG_LENS_FORMAT;
129+
int lensFormat = reader.getUInt8(offset);
130+
dir.setInt(TAG_LENS_FORMAT, lensFormat);
131+
132+
// LensType2
133+
offset = TAG_LENS_TYPE_2;
134+
int lensType2 = reader.getUInt16(offset);
135+
dir.setInt(TAG_LENS_TYPE_2, lensType2);
136+
137+
// DistortionCorrParamsPresent
138+
offset = TAG_DISTORTION_CORR_PARAMS_PRESENT;
139+
int distortCorrParamsPresent = reader.getUInt8(offset);
140+
dir.setInt(TAG_DISTORTION_CORR_PARAMS_PRESENT, distortCorrParamsPresent);
141+
142+
// APS-CSizeCapture
143+
offset = TAG_APS_C_SIZE_CAPTURE;
144+
int apsCSizeCapture = reader.getUInt8(offset);
145+
dir.setInt(TAG_APS_C_SIZE_CAPTURE, apsCSizeCapture);
146+
147+
// LensSpecFeatures
148+
offset = TAG_LENS_SPEC_FEATURES;
149+
byte[] lensSpecFeatures = reader.getBytes(offset, 2);
150+
dir.setByteArray(TAG_APS_C_SIZE_CAPTURE, lensSpecFeatures);
151+
152+
// ShutterCount3
153+
// APS-CSizeCapture
154+
// LensSpecFeatures
155+
156+
} catch (IOException e) {
157+
dir.addError(e.getMessage());
158+
}
159+
160+
return dir;
161+
}
162+
}

Source/com/drew/metadata/exif/makernotes/SonyType1MakernoteDirectory.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ public class SonyType1MakernoteDirectory extends Directory
3636
public static final int TAG_CAMERA_INFO = 0x0010;
3737
public static final int TAG_FOCUS_INFO = 0x0020;
3838

39+
// https://exiftool.org/TagNames/Sony.html#Tag9050a
40+
public static final int TAG_9050A = 0x0030;
41+
// https://exiftool.org/TagNames/Sony.html#Tag9050b
42+
public static final int TAG_9050B = 0x9050;
43+
// https://exiftool.org/TagNames/Sony.html#Tag9050c
44+
public static final int TAG_9050C = 0x0040;
45+
3946
public static final int TAG_IMAGE_QUALITY = 0x0102;
4047
public static final int TAG_FLASH_EXPOSURE_COMP = 0x0104;
4148
public static final int TAG_TELECONVERTER = 0x0105;

0 commit comments

Comments
 (0)