Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nikon PictureControl directory extraction #634

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Source/com/drew/lang/SequentialReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@ public StringValue getNullTerminatedStringValue(int maxLengthBytes, Charset char

/**
* Returns the sequence of bytes punctuated by a <code>\0</code> value.
* It will place the cursor after the first occurrence of <code>\0</code>.
* <br/>
* Use <code>getNullTerminatedStringAndSkipToNextPosition</code> if you want the cursor to move moved at the end of <code>maxLengthBytes</code>.
*
* @param maxLengthBytes The maximum number of bytes to read. If a <code>\0</code> byte is not reached within this limit,
* the returned array will be <code>maxLengthBytes</code> long.
Expand All @@ -386,4 +389,19 @@ public byte[] getNullTerminatedBytes(int maxLengthBytes) throws IOException
System.arraycopy(buffer, 0, bytes, 0, length);
return bytes;
}

/**
* Read until the null terminated byte and automatically move the end of the requested position.
* @param maxLengthBytes
* @param charset
* @return
* @throws IOException
*/
public StringValue getNullTerminatedStringAndSkipToNextPosition(int maxLengthBytes, Charset charset) throws IOException {
byte[] bytes = this.getNullTerminatedBytes(maxLengthBytes);
if (bytes.length < maxLengthBytes - 1) {
this.trySkip(maxLengthBytes - bytes.length - 1);
}
return new StringValue(bytes, charset);
}
}
3 changes: 3 additions & 0 deletions Source/com/drew/lang/StreamReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
package com.drew.lang;

import com.drew.lang.annotations.NotNull;
import com.drew.metadata.StringValue;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

/**
*
Expand Down Expand Up @@ -141,4 +143,5 @@ private long skipInternal(long n) throws IOException
_pos += skippedTotal;
return skippedTotal;
}

}
20 changes: 20 additions & 0 deletions Source/com/drew/metadata/exif/ExifTiffHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,26 @@ public boolean customProcessTag(final int tagOffset,
}
}

if (_currentDirectory instanceof NikonType2MakernoteDirectory) {
if (tagId == NikonType2MakernoteDirectory.TAG_PICTURE_CONTROL || tagId == NikonType2MakernoteDirectory.TAG_PICTURE_CONTROL_2) {
if (byteCount == 58) {
byte[] bytes = reader.getBytes(tagOffset, byteCount);
NikonPictureControl1Directory directory = NikonPictureControl1Directory.read(bytes);
directory.setParent(_currentDirectory);
_metadata.addDirectory(directory);
return true;
} else if (byteCount == 68) {
byte[] bytes = reader.getBytes(tagOffset, byteCount);
NikonPictureControl2Directory directory = NikonPictureControl2Directory.read(bytes);
directory.setParent(_currentDirectory);
_metadata.addDirectory(directory);
return true;
} else if (byteCount == 74) {
//TODO:
}
}
}

return false;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.drew.metadata.exif.makernotes;

import com.drew.metadata.TagDescriptor;

import static com.drew.metadata.exif.makernotes.NikonPictureControl1Directory.TAG_FILTER_EFFECT;
import static com.drew.metadata.exif.makernotes.NikonPictureControl1Directory.TAG_PICTURE_CONTROL_ADJUST;
import static com.drew.metadata.exif.makernotes.NikonPictureControl1Directory.TAG_TONING_EFFECT;

public final class NikonPictureControl1Descriptor extends TagDescriptor<NikonPictureControl1Directory> {
public NikonPictureControl1Descriptor(NikonPictureControl1Directory directory) {
super(directory);
}

@Override
public String getDescription(int tagType) {
switch (tagType) {
case TAG_PICTURE_CONTROL_ADJUST:
return getPictureControlAdjustDescription();
case TAG_FILTER_EFFECT:
return getFilterEffectDescription();
case TAG_TONING_EFFECT:
return getToningEffectDescription();
default:
return super.getDescription(tagType);
}
}

public String getPictureControlAdjustDescription() {
return getIndexedDescription(
TAG_PICTURE_CONTROL_ADJUST,
"Default Settings",
"Quick Adjust",
"Full Control"
);
}

public String getFilterEffectDescription() {
byte[] value = _directory.getByteArray(TAG_FILTER_EFFECT);
if (value == null) {
return null;
}

switch (value[0]) {
case (byte) 0x80:
return "Off";
case (byte) 0x81:
return "Yellow";
case (byte) 0x82:
return "Orange";
case (byte) 0x83:
return "Red";
case (byte) 0x84:
return "Green";
case (byte) 0xFF:
return "N/A";
default:
return super.getDescription(TAG_FILTER_EFFECT);
}
}

public String getToningEffectDescription() {
byte[] value = _directory.getByteArray(TAG_TONING_EFFECT);
if (value == null) {
return null;
}

switch (value[0]) {
case (byte) 0x80:
return "B&W";
case (byte) 0x81:
return "Sepia";
case (byte) 0x82:
return "Cyanotype";
case (byte) 0x83:
return "Red";
case (byte) 0x84:
return "Yellow";
case (byte) 0x85:
return "Green";
case (byte) 0x86:
return "Blue-green";
case (byte) 0x87:
return "Blue";
case (byte) 0x88:
return "Purple-blue";
case (byte) 0x89:
return "Red-purple";
case (byte) 0xFF:
return "N/A";
default:
return super.getDescription(TAG_TONING_EFFECT);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.drew.metadata.exif.makernotes;

import com.drew.lang.Charsets;
import com.drew.lang.SequentialByteArrayReader;
import com.drew.metadata.Directory;

import java.io.IOException;
import java.util.HashMap;

public final class NikonPictureControl1Directory extends Directory {
public static final int TAG_PICTURE_CONTROL_VERSION = 0;
public static final int TAG_PICTURE_CONTROL_NAME = 4;
public static final int TAG_PICTURE_CONTROL_BASE = 24;
public static final int TAG_PICTURE_CONTROL_ADJUST = 48;
public static final int TAG_PICTURE_CONTROL_QUICK_ADJUST = 49;
public static final int TAG_SHARPNESS = 50;
public static final int TAG_CONTRAST = 51;
public static final int TAG_BRIGHTNESS = 52;
public static final int TAG_SATURATION = 53;
public static final int TAG_HUE_ADJUSTMENT = 54;
public static final int TAG_FILTER_EFFECT = 55;
public static final int TAG_TONING_EFFECT = 56;
public static final int TAG_TONING_SATURATION = 57;

private static final HashMap<Integer, String> TAG_NAME_MAP = new HashMap<>();

static {
TAG_NAME_MAP.put(TAG_PICTURE_CONTROL_VERSION, "Picture Control Version");
TAG_NAME_MAP.put(TAG_PICTURE_CONTROL_NAME, "Picture Control Name");
TAG_NAME_MAP.put(TAG_PICTURE_CONTROL_BASE, "Picture Control Base");
TAG_NAME_MAP.put(TAG_PICTURE_CONTROL_ADJUST, "Picture Control Adjust");
TAG_NAME_MAP.put(TAG_PICTURE_CONTROL_QUICK_ADJUST, "Picture Control Quick Adjust");
TAG_NAME_MAP.put(TAG_SHARPNESS, "Sharpness");
TAG_NAME_MAP.put(TAG_CONTRAST, "Contrast");
TAG_NAME_MAP.put(TAG_BRIGHTNESS, "Brightness");
TAG_NAME_MAP.put(TAG_SATURATION, "Saturation");
TAG_NAME_MAP.put(TAG_HUE_ADJUSTMENT, "Hue Adjustment");
TAG_NAME_MAP.put(TAG_FILTER_EFFECT, "Filter Effect");
TAG_NAME_MAP.put(TAG_TONING_EFFECT, "Toning Effect");
TAG_NAME_MAP.put(TAG_TONING_SATURATION, "Toning Saturation");
}

public NikonPictureControl1Directory() {
setDescriptor(new NikonPictureControl1Descriptor(this));
}

@Override
public String getName() {
return "Nikon PictureControl 1";
}

@Override
protected HashMap<Integer, String> getTagNameMap() {
return TAG_NAME_MAP;
}

public static NikonPictureControl1Directory read(byte[] bytes) throws IOException {
int EXPECTED_LENGTH = 58;

if (bytes.length != EXPECTED_LENGTH) {
throw new IllegalArgumentException("Must have " + EXPECTED_LENGTH + " bytes.");
}

SequentialByteArrayReader reader = new SequentialByteArrayReader(bytes);

NikonPictureControl1Directory directory = new NikonPictureControl1Directory();

directory.setString(TAG_PICTURE_CONTROL_VERSION, reader.getNullTerminatedStringAndSkipToNextPosition(4, Charsets.UTF_8).toString());
directory.setString(TAG_PICTURE_CONTROL_NAME, reader.getNullTerminatedStringAndSkipToNextPosition(20, Charsets.UTF_8).toString());
directory.setString(TAG_PICTURE_CONTROL_BASE, reader.getNullTerminatedStringAndSkipToNextPosition(20, Charsets.UTF_8).toString());

reader.skip(4);
directory.setObject(TAG_PICTURE_CONTROL_ADJUST, reader.getByte());
directory.setObject(TAG_PICTURE_CONTROL_QUICK_ADJUST, reader.getByte());
directory.setObject(TAG_SHARPNESS, reader.getByte());
directory.setObject(TAG_CONTRAST, reader.getByte());
directory.setObject(TAG_BRIGHTNESS, reader.getByte());
directory.setObject(TAG_SATURATION, reader.getByte());
directory.setObject(TAG_HUE_ADJUSTMENT, reader.getByte());
directory.setObject(TAG_FILTER_EFFECT, reader.getByte());
directory.setObject(TAG_TONING_EFFECT, reader.getByte());
directory.setObject(TAG_TONING_SATURATION, reader.getByte());

assert (reader.getPosition() == EXPECTED_LENGTH);

return directory;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.drew.metadata.exif.makernotes;

import com.drew.metadata.TagDescriptor;

import static com.drew.metadata.exif.makernotes.NikonPictureControl2Directory.TAG_FILTER_EFFECT;
import static com.drew.metadata.exif.makernotes.NikonPictureControl2Directory.TAG_PICTURE_CONTROL_ADJUST;
import static com.drew.metadata.exif.makernotes.NikonPictureControl2Directory.TAG_TONING_EFFECT;

public final class NikonPictureControl2Descriptor extends TagDescriptor<NikonPictureControl2Directory> {
public NikonPictureControl2Descriptor(NikonPictureControl2Directory directory) {
super(directory);
}

@Override
public String getDescription(int tagType) {
switch (tagType) {
case TAG_PICTURE_CONTROL_ADJUST:
return getPictureControlAdjustDescription();
case TAG_FILTER_EFFECT:
return getFilterEffectDescription();
case TAG_TONING_EFFECT:
return getToningEffectDescription();
default:
return super.getDescription(tagType);
}
}

public String getPictureControlAdjustDescription() {
return getIndexedDescription(
TAG_PICTURE_CONTROL_ADJUST,
"Default Settings",
"Quick Adjust",
"Full Control"
);
}

public String getFilterEffectDescription() {
byte[] value = _directory.getByteArray(TAG_FILTER_EFFECT);
if (value == null) {
return null;
}

switch (value[0]) {
case (byte) 0x80:
return "Off";
case (byte) 0x81:
return "Yellow";
case (byte) 0x82:
return "Orange";
case (byte) 0x83:
return "Red";
case (byte) 0x84:
return "Green";
case (byte) 0xFF:
return "N/A";
default:
return super.getDescription(TAG_FILTER_EFFECT);
}
}

public String getToningEffectDescription() {
byte[] value = _directory.getByteArray(TAG_TONING_EFFECT);
if (value == null) {
return null;
}

switch (value[0]) {
case (byte) 0x80:
return "B&W";
case (byte) 0x81:
return "Sepia";
case (byte) 0x82:
return "Cyanotype";
case (byte) 0x83:
return "Red";
case (byte) 0x84:
return "Yellow";
case (byte) 0x85:
return "Green";
case (byte) 0x86:
return "Blue-green";
case (byte) 0x87:
return "Blue";
case (byte) 0x88:
return "Purple-blue";
case (byte) 0x89:
return "Red-purple";
case (byte) 0xFF:
return "N/A";
default:
return super.getDescription(TAG_TONING_EFFECT);
}
}
}
Loading
Loading