feat: custom option setter

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2025-10-18 17:05:18 +01:00
parent a1668bb277
commit 0f5997042c
6 changed files with 621 additions and 139 deletions

View File

@@ -216,7 +216,7 @@ pub trait PtpDeserialize: Sized {
fn try_read_ptp<R: Read>(cur: &mut R) -> io::Result<Self>;
}
macro_rules! impl_ptp {
macro_rules! impl_ptp_ser {
($ty:ty, $read_fn:ident, $write_fn:ident) => {
impl PtpSerialize for $ty {
fn try_into_ptp(&self) -> io::Result<Vec<u8>> {
@@ -229,7 +229,11 @@ macro_rules! impl_ptp {
buf.$write_fn(self)
}
}
};
}
macro_rules! impl_ptp_de {
($ty:ty, $read_fn:ident, $write_fn:ident) => {
impl PtpDeserialize for $ty {
fn try_from_ptp(buf: &[u8]) -> io::Result<Self> {
let mut cur = Cursor::new(buf);
@@ -245,20 +249,38 @@ macro_rules! impl_ptp {
};
}
impl_ptp!(u8, read_ptp_u8, write_ptp_u8);
impl_ptp!(i8, read_ptp_i8, write_ptp_i8);
impl_ptp!(u16, read_ptp_u16, write_ptp_u16);
impl_ptp!(i16, read_ptp_i16, write_ptp_i16);
impl_ptp!(u32, read_ptp_u32, write_ptp_u32);
impl_ptp!(i32, read_ptp_i32, write_ptp_i32);
impl_ptp!(u64, read_ptp_u64, write_ptp_u64);
impl_ptp!(i64, read_ptp_i64, write_ptp_i64);
impl_ptp!(String, read_ptp_str, write_ptp_str);
impl_ptp!(Vec<u8>, read_ptp_u8_vec, write_ptp_u8_vec);
impl_ptp!(Vec<i8>, read_ptp_i8_vec, write_ptp_i8_vec);
impl_ptp!(Vec<u16>, read_ptp_u16_vec, write_ptp_u16_vec);
impl_ptp!(Vec<i16>, read_ptp_i16_vec, write_ptp_i16_vec);
impl_ptp!(Vec<u32>, read_ptp_u32_vec, write_ptp_u32_vec);
impl_ptp!(Vec<i32>, read_ptp_i32_vec, write_ptp_i32_vec);
impl_ptp!(Vec<u64>, read_ptp_u64_vec, write_ptp_u64_vec);
impl_ptp!(Vec<i64>, read_ptp_i64_vec, write_ptp_i64_vec);
impl_ptp_ser!(u8, read_ptp_u8, write_ptp_u8);
impl_ptp_de!(u8, read_ptp_u8, write_ptp_u8);
impl_ptp_ser!(i8, read_ptp_i8, write_ptp_i8);
impl_ptp_de!(i8, read_ptp_i8, write_ptp_i8);
impl_ptp_ser!(u16, read_ptp_u16, write_ptp_u16);
impl_ptp_de!(u16, read_ptp_u16, write_ptp_u16);
impl_ptp_ser!(i16, read_ptp_i16, write_ptp_i16);
impl_ptp_de!(i16, read_ptp_i16, write_ptp_i16);
impl_ptp_ser!(u32, read_ptp_u32, write_ptp_u32);
impl_ptp_de!(u32, read_ptp_u32, write_ptp_u32);
impl_ptp_ser!(i32, read_ptp_i32, write_ptp_i32);
impl_ptp_de!(i32, read_ptp_i32, write_ptp_i32);
impl_ptp_ser!(u64, read_ptp_u64, write_ptp_u64);
impl_ptp_de!(u64, read_ptp_u64, write_ptp_u64);
impl_ptp_ser!(i64, read_ptp_i64, write_ptp_i64);
impl_ptp_de!(i64, read_ptp_i64, write_ptp_i64);
impl_ptp_ser!(&str, read_ptp_str, write_ptp_str);
impl_ptp_ser!(String, read_ptp_str, write_ptp_str);
impl_ptp_de!(String, read_ptp_str, write_ptp_str);
impl_ptp_ser!(Vec<u8>, read_ptp_u8_vec, write_ptp_u8_vec);
impl_ptp_de!(Vec<u8>, read_ptp_u8_vec, write_ptp_u8_vec);
impl_ptp_ser!(Vec<i8>, read_ptp_i8_vec, write_ptp_i8_vec);
impl_ptp_de!(Vec<i8>, read_ptp_i8_vec, write_ptp_i8_vec);
impl_ptp_ser!(Vec<u16>, read_ptp_u16_vec, write_ptp_u16_vec);
impl_ptp_de!(Vec<u16>, read_ptp_u16_vec, write_ptp_u16_vec);
impl_ptp_ser!(Vec<i16>, read_ptp_i16_vec, write_ptp_i16_vec);
impl_ptp_de!(Vec<i16>, read_ptp_i16_vec, write_ptp_i16_vec);
impl_ptp_ser!(Vec<u32>, read_ptp_u32_vec, write_ptp_u32_vec);
impl_ptp_de!(Vec<u32>, read_ptp_u32_vec, write_ptp_u32_vec);
impl_ptp_ser!(Vec<i32>, read_ptp_i32_vec, write_ptp_i32_vec);
impl_ptp_de!(Vec<i32>, read_ptp_i32_vec, write_ptp_i32_vec);
impl_ptp_ser!(Vec<u64>, read_ptp_u64_vec, write_ptp_u64_vec);
impl_ptp_de!(Vec<u64>, read_ptp_u64_vec, write_ptp_u64_vec);
impl_ptp_ser!(Vec<i64>, read_ptp_i64_vec, write_ptp_i64_vec);
impl_ptp_de!(Vec<i64>, read_ptp_i64_vec, write_ptp_i64_vec);

View File

@@ -11,10 +11,10 @@ use ptp::{
Ptp,
hex::{
CommandCode, DevicePropCode, FujiClarity, FujiColor, FujiColorChromeEffect,
FujiColorChromeFXBlue, FujiCustomSetting, FujiDynamicRange, FujiFilmSimulation,
FujiGrainEffect, FujiHighISONR, FujiHighlightTone, FujiImageQuality, FujiImageSize,
FujiShadowTone, FujiSharpness, FujiStillDynamicRangePriority, FujiWhiteBalance,
FujiWhiteBalanceShift, FujiWhiteBalanceTemperature, UsbMode,
FujiColorChromeFXBlue, FujiCustomSetting, FujiCustomSettingName, FujiDynamicRange,
FujiDynamicRangePriority, FujiFilmSimulation, FujiGrainEffect, FujiHighISONR,
FujiHighlightTone, FujiImageQuality, FujiImageSize, FujiShadowTone, FujiSharpness,
FujiWhiteBalance, FujiWhiteBalanceShift, FujiWhiteBalanceTemperature, UsbMode,
},
structs::DeviceInfo,
};
@@ -158,81 +158,172 @@ impl Camera {
self.r#impl.set_custom_setting_slot(&mut self.ptp, slot)
}
pub fn get_custom_setting_name(&mut self) -> anyhow::Result<String> {
pub fn get_custom_setting_name(&mut self) -> anyhow::Result<FujiCustomSettingName> {
self.r#impl.get_custom_setting_name(&mut self.ptp)
}
pub fn set_custom_setting_name(&mut self, value: &str) -> anyhow::Result<()> {
self.r#impl.set_custom_setting_name(&mut self.ptp, value)
}
pub fn get_image_size(&mut self) -> anyhow::Result<FujiImageSize> {
self.r#impl.get_image_size(&mut self.ptp)
}
pub fn set_image_size(&mut self, value: FujiImageSize) -> anyhow::Result<()> {
self.r#impl.set_image_size(&mut self.ptp, value)
}
pub fn get_image_quality(&mut self) -> anyhow::Result<FujiImageQuality> {
self.r#impl.get_image_quality(&mut self.ptp)
}
pub fn set_image_quality(&mut self, value: FujiImageQuality) -> anyhow::Result<()> {
self.r#impl.set_image_quality(&mut self.ptp, value)
}
pub fn get_dynamic_range(&mut self) -> anyhow::Result<FujiDynamicRange> {
self.r#impl.get_dynamic_range(&mut self.ptp)
}
pub fn get_dynamic_range_priority(&mut self) -> anyhow::Result<FujiStillDynamicRangePriority> {
pub fn set_dynamic_range(&mut self, value: FujiDynamicRange) -> anyhow::Result<()> {
self.r#impl.set_dynamic_range(&mut self.ptp, value)
}
pub fn get_dynamic_range_priority(&mut self) -> anyhow::Result<FujiDynamicRangePriority> {
self.r#impl.get_dynamic_range_priority(&mut self.ptp)
}
pub fn set_dynamic_range_priority(
&mut self,
value: FujiDynamicRangePriority,
) -> anyhow::Result<()> {
self.r#impl.set_dynamic_range_priority(&mut self.ptp, value)
}
pub fn get_film_simulation(&mut self) -> anyhow::Result<FujiFilmSimulation> {
self.r#impl.get_film_simulation(&mut self.ptp)
}
pub fn set_film_simulation(&mut self, value: FujiFilmSimulation) -> anyhow::Result<()> {
self.r#impl.set_film_simulation(&mut self.ptp, value)
}
pub fn get_grain_effect(&mut self) -> anyhow::Result<FujiGrainEffect> {
self.r#impl.get_grain_effect(&mut self.ptp)
}
pub fn set_grain_effect(&mut self, value: FujiGrainEffect) -> anyhow::Result<()> {
self.r#impl.set_grain_effect(&mut self.ptp, value)
}
pub fn get_white_balance(&mut self) -> anyhow::Result<FujiWhiteBalance> {
self.r#impl.get_white_balance(&mut self.ptp)
}
pub fn set_white_balance(&mut self, value: FujiWhiteBalance) -> anyhow::Result<()> {
self.r#impl.set_white_balance(&mut self.ptp, value)
}
pub fn get_high_iso_nr(&mut self) -> anyhow::Result<FujiHighISONR> {
self.r#impl.get_high_iso_nr(&mut self.ptp)
}
pub fn set_high_iso_nr(&mut self, value: FujiHighISONR) -> anyhow::Result<()> {
self.r#impl.set_high_iso_nr(&mut self.ptp, value)
}
pub fn get_highlight_tone(&mut self) -> anyhow::Result<FujiHighlightTone> {
self.r#impl.get_highlight_tone(&mut self.ptp)
}
pub fn set_highlight_tone(&mut self, value: FujiHighlightTone) -> anyhow::Result<()> {
self.r#impl.set_highlight_tone(&mut self.ptp, value)
}
pub fn get_shadow_tone(&mut self) -> anyhow::Result<FujiShadowTone> {
self.r#impl.get_shadow_tone(&mut self.ptp)
}
pub fn set_shadow_tone(&mut self, value: FujiShadowTone) -> anyhow::Result<()> {
self.r#impl.set_shadow_tone(&mut self.ptp, value)
}
pub fn get_color(&mut self) -> anyhow::Result<FujiColor> {
self.r#impl.get_color(&mut self.ptp)
}
pub fn set_color(&mut self, value: FujiColor) -> anyhow::Result<()> {
self.r#impl.set_color(&mut self.ptp, value)
}
pub fn get_sharpness(&mut self) -> anyhow::Result<FujiSharpness> {
self.r#impl.get_sharpness(&mut self.ptp)
}
pub fn set_sharpness(&mut self, value: FujiSharpness) -> anyhow::Result<()> {
self.r#impl.set_sharpness(&mut self.ptp, value)
}
pub fn get_clarity(&mut self) -> anyhow::Result<FujiClarity> {
self.r#impl.get_clarity(&mut self.ptp)
}
pub fn get_wb_shift_red(&mut self) -> anyhow::Result<FujiWhiteBalanceShift> {
self.r#impl.get_wb_shift_red(&mut self.ptp)
pub fn set_clarity(&mut self, value: FujiClarity) -> anyhow::Result<()> {
self.r#impl.set_clarity(&mut self.ptp, value)
}
pub fn get_wb_shift_blue(&mut self) -> anyhow::Result<FujiWhiteBalanceShift> {
self.r#impl.get_wb_shift_blue(&mut self.ptp)
pub fn get_white_balance_shift_red(&mut self) -> anyhow::Result<FujiWhiteBalanceShift> {
self.r#impl.get_white_balance_shift_red(&mut self.ptp)
}
pub fn get_wb_temperature(&mut self) -> anyhow::Result<FujiWhiteBalanceTemperature> {
self.r#impl.get_wb_temperature(&mut self.ptp)
pub fn set_white_balance_shift_red(
&mut self,
value: FujiWhiteBalanceShift,
) -> anyhow::Result<()> {
self.r#impl
.set_white_balance_shift_red(&mut self.ptp, value)
}
pub fn get_white_balance_shift_blue(&mut self) -> anyhow::Result<FujiWhiteBalanceShift> {
self.r#impl.get_white_balance_shift_blue(&mut self.ptp)
}
pub fn set_white_balance_shift_blue(
&mut self,
value: FujiWhiteBalanceShift,
) -> anyhow::Result<()> {
self.r#impl
.set_white_balance_shift_blue(&mut self.ptp, value)
}
pub fn get_white_balance_temperature(&mut self) -> anyhow::Result<FujiWhiteBalanceTemperature> {
self.r#impl.get_white_balance_temperature(&mut self.ptp)
}
pub fn set_white_balance_temperature(
&mut self,
value: FujiWhiteBalanceTemperature,
) -> anyhow::Result<()> {
self.r#impl
.set_white_balance_temperature(&mut self.ptp, value)
}
pub fn get_color_chrome_effect(&mut self) -> anyhow::Result<FujiColorChromeEffect> {
self.r#impl.get_color_chrome_effect(&mut self.ptp)
}
pub fn set_color_chrome_effect(&mut self, value: FujiColorChromeEffect) -> anyhow::Result<()> {
self.r#impl.set_color_chrome_effect(&mut self.ptp, value)
}
pub fn get_color_chrome_fx_blue(&mut self) -> anyhow::Result<FujiColorChromeFXBlue> {
self.r#impl.get_color_chrome_fx_blue(&mut self.ptp)
}
pub fn set_color_chrome_fx_blue(&mut self, value: FujiColorChromeFXBlue) -> anyhow::Result<()> {
self.r#impl.set_color_chrome_fx_blue(&mut self.ptp, value)
}
}
impl Drop for Camera {
@@ -370,10 +461,16 @@ pub trait CameraImpl<P: rusb::UsbContext> {
Ok(())
}
fn get_custom_setting_name(&self, ptp: &mut Ptp) -> anyhow::Result<String> {
fn get_custom_setting_name(&self, ptp: &mut Ptp) -> anyhow::Result<FujiCustomSettingName> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingName)?;
let name = String::try_from_ptp(&bytes)?;
Ok(name)
let result = FujiCustomSettingName::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_custom_setting_name(&self, ptp: &mut Ptp, value: &str) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingName, &bytes)?;
Ok(())
}
fn get_image_size(&self, ptp: &mut Ptp) -> anyhow::Result<FujiImageSize> {
@@ -382,30 +479,70 @@ pub trait CameraImpl<P: rusb::UsbContext> {
Ok(result)
}
fn set_image_size(&self, ptp: &mut Ptp, value: FujiImageSize) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingImageSize, &bytes)?;
Ok(())
}
fn get_image_quality(&self, ptp: &mut Ptp) -> anyhow::Result<FujiImageQuality> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingImageQuality)?;
let result = FujiImageQuality::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_image_quality(&self, ptp: &mut Ptp, value: FujiImageQuality) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingImageQuality,
&bytes,
)?;
Ok(())
}
fn get_dynamic_range(&self, ptp: &mut Ptp) -> anyhow::Result<FujiDynamicRange> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingDynamicRange)?;
let result = FujiDynamicRange::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_dynamic_range(&self, ptp: &mut Ptp, value: FujiDynamicRange) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingDynamicRange,
&bytes,
)?;
Ok(())
}
fn get_dynamic_range_priority(
&self,
ptp: &mut Ptp,
) -> anyhow::Result<FujiStillDynamicRangePriority> {
) -> anyhow::Result<FujiDynamicRangePriority> {
let bytes = self.get_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingDynamicRangePriority,
)?;
let result = FujiStillDynamicRangePriority::try_from_ptp(&bytes)?;
let result = FujiDynamicRangePriority::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_dynamic_range_priority(
&self,
ptp: &mut Ptp,
value: FujiDynamicRangePriority,
) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingDynamicRangePriority,
&bytes,
)?;
Ok(())
}
fn get_film_simulation(&self, ptp: &mut Ptp) -> anyhow::Result<FujiFilmSimulation> {
let bytes =
self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingFilmSimulation)?;
@@ -413,24 +550,60 @@ pub trait CameraImpl<P: rusb::UsbContext> {
Ok(result)
}
fn set_film_simulation(&self, ptp: &mut Ptp, value: FujiFilmSimulation) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingFilmSimulation,
&bytes,
)?;
Ok(())
}
fn get_grain_effect(&self, ptp: &mut Ptp) -> anyhow::Result<FujiGrainEffect> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingGrainEffect)?;
let result = FujiGrainEffect::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_grain_effect(&self, ptp: &mut Ptp, value: FujiGrainEffect) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingGrainEffect,
&bytes,
)?;
Ok(())
}
fn get_white_balance(&self, ptp: &mut Ptp) -> anyhow::Result<FujiWhiteBalance> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingWhiteBalance)?;
let result = FujiWhiteBalance::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_white_balance(&self, ptp: &mut Ptp, value: FujiWhiteBalance) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingWhiteBalance,
&bytes,
)?;
Ok(())
}
fn get_high_iso_nr(&self, ptp: &mut Ptp) -> anyhow::Result<FujiHighISONR> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingHighISONR)?;
let result = FujiHighISONR::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_high_iso_nr(&self, ptp: &mut Ptp, value: FujiHighISONR) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingHighISONR, &bytes)?;
Ok(())
}
fn get_highlight_tone(&self, ptp: &mut Ptp) -> anyhow::Result<FujiHighlightTone> {
let bytes =
self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingHighlightTone)?;
@@ -438,45 +611,118 @@ pub trait CameraImpl<P: rusb::UsbContext> {
Ok(result)
}
fn set_highlight_tone(&self, ptp: &mut Ptp, value: FujiHighlightTone) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingHighlightTone,
&bytes,
)?;
Ok(())
}
fn get_shadow_tone(&self, ptp: &mut Ptp) -> anyhow::Result<FujiShadowTone> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingShadowTone)?;
let result = FujiShadowTone::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_shadow_tone(&self, ptp: &mut Ptp, value: FujiShadowTone) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingShadowTone,
&bytes,
)?;
Ok(())
}
fn get_color(&self, ptp: &mut Ptp) -> anyhow::Result<FujiColor> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingColor)?;
let result = FujiColor::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_color(&self, ptp: &mut Ptp, value: FujiColor) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingColor, &bytes)?;
Ok(())
}
fn get_sharpness(&self, ptp: &mut Ptp) -> anyhow::Result<FujiSharpness> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingSharpness)?;
let result = FujiSharpness::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_sharpness(&self, ptp: &mut Ptp, value: FujiSharpness) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingSharpness, &bytes)?;
Ok(())
}
fn get_clarity(&self, ptp: &mut Ptp) -> anyhow::Result<FujiClarity> {
let bytes = self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingClarity)?;
let result = FujiClarity::try_from_ptp(&bytes)?;
Ok(result)
}
fn get_wb_shift_red(&self, ptp: &mut Ptp) -> anyhow::Result<FujiWhiteBalanceShift> {
let bytes =
self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingWhiteBalanceRed)?;
fn set_clarity(&self, ptp: &mut Ptp, value: FujiClarity) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(ptp, DevicePropCode::FujiStillCustomSettingClarity, &bytes)?;
Ok(())
}
fn get_white_balance_shift_red(&self, ptp: &mut Ptp) -> anyhow::Result<FujiWhiteBalanceShift> {
let bytes = self.get_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftRed,
)?;
let result = FujiWhiteBalanceShift::try_from_ptp(&bytes)?;
Ok(result)
}
fn get_wb_shift_blue(&self, ptp: &mut Ptp) -> anyhow::Result<FujiWhiteBalanceShift> {
let bytes =
self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingWhiteBalanceBlue)?;
fn set_white_balance_shift_red(
&self,
ptp: &mut Ptp,
value: FujiWhiteBalanceShift,
) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftRed,
&bytes,
)?;
Ok(())
}
fn get_white_balance_shift_blue(&self, ptp: &mut Ptp) -> anyhow::Result<FujiWhiteBalanceShift> {
let bytes = self.get_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftBlue,
)?;
let result = FujiWhiteBalanceShift::try_from_ptp(&bytes)?;
Ok(result)
}
fn get_wb_temperature(&self, ptp: &mut Ptp) -> anyhow::Result<FujiWhiteBalanceTemperature> {
fn set_white_balance_shift_blue(
&self,
ptp: &mut Ptp,
value: FujiWhiteBalanceShift,
) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingWhiteBalanceShiftBlue,
&bytes,
)?;
Ok(())
}
fn get_white_balance_temperature(
&self,
ptp: &mut Ptp,
) -> anyhow::Result<FujiWhiteBalanceTemperature> {
let bytes = self.get_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingWhiteBalanceTemperature,
@@ -485,6 +731,20 @@ pub trait CameraImpl<P: rusb::UsbContext> {
Ok(result)
}
fn set_white_balance_temperature(
&self,
ptp: &mut Ptp,
value: FujiWhiteBalanceTemperature,
) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingWhiteBalanceTemperature,
&bytes,
)?;
Ok(())
}
fn get_color_chrome_effect(&self, ptp: &mut Ptp) -> anyhow::Result<FujiColorChromeEffect> {
let bytes =
self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingColorChromeEffect)?;
@@ -492,10 +752,38 @@ pub trait CameraImpl<P: rusb::UsbContext> {
Ok(result)
}
fn set_color_chrome_effect(
&self,
ptp: &mut Ptp,
value: FujiColorChromeEffect,
) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingColorChromeEffect,
&bytes,
)?;
Ok(())
}
fn get_color_chrome_fx_blue(&self, ptp: &mut Ptp) -> anyhow::Result<FujiColorChromeFXBlue> {
let bytes =
self.get_prop_value(ptp, DevicePropCode::FujiStillCustomSettingColorChromeFXBlue)?;
let result = FujiColorChromeFXBlue::try_from_ptp(&bytes)?;
Ok(result)
}
fn set_color_chrome_fx_blue(
&self,
ptp: &mut Ptp,
value: FujiColorChromeFXBlue,
) -> anyhow::Result<()> {
let bytes = value.try_into_ptp()?;
self.set_prop_value(
ptp,
DevicePropCode::FujiStillCustomSettingColorChromeFXBlue,
&bytes,
)?;
Ok(())
}
}

View File

@@ -1,6 +1,7 @@
use std::{
fmt,
io::{self, Cursor},
ops::{Deref, DerefMut},
str::FromStr,
};
@@ -146,8 +147,8 @@ pub enum DevicePropCode {
FujiStillCustomSettingColorChromeFXBlue = 0xD197,
// TODO: 0xD198 All 1s
FujiStillCustomSettingWhiteBalance = 0xD199,
FujiStillCustomSettingWhiteBalanceRed = 0xD19A,
FujiStillCustomSettingWhiteBalanceBlue = 0xD19B,
FujiStillCustomSettingWhiteBalanceShiftRed = 0xD19A,
FujiStillCustomSettingWhiteBalanceShiftBlue = 0xD19B,
FujiStillCustomSettingWhiteBalanceTemperature = 0xD19C,
FujiStillCustomSettingHighlightTone = 0xD19D,
FujiStillCustomSettingShadowTone = 0xD19E,
@@ -181,7 +182,7 @@ where
}
}
println!("{}", best_score);
println!("{best_score}");
if best_score <= SIMILARITY_THRESHOLD {
best_match
} else {
@@ -231,7 +232,7 @@ impl Serialize for FujiCustomSetting {
where
S: Serializer,
{
serializer.serialize_u16(*self as u16)
serializer.serialize_u16((*self).into())
}
}
@@ -256,6 +257,52 @@ impl FromStr for FujiCustomSetting {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, PtpSerialize, PtpDeserialize)]
pub struct FujiCustomSettingName(String);
impl FujiCustomSettingName {
pub const MAX_LEN: usize = 25;
}
impl Deref for FujiCustomSettingName {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for FujiCustomSettingName {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl TryFrom<String> for FujiCustomSettingName {
type Error = anyhow::Error;
fn try_from(value: String) -> Result<Self, anyhow::Error> {
if value.len() > Self::MAX_LEN {
bail!("Value '{}' exceeds max length of {}", value, Self::MAX_LEN);
}
Ok(Self(value))
}
}
impl FromStr for FujiCustomSettingName {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, anyhow::Error> {
if s.len() > Self::MAX_LEN {
bail!("Value '{}' exceeds max length of {}", s, Self::MAX_LEN);
}
Ok(Self(s.to_string()))
}
}
impl std::fmt::Display for FujiCustomSettingName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[repr(u16)]
#[derive(
Debug,
@@ -329,8 +376,8 @@ impl FromStr for FujiImageSize {
_ => {}
}
let resolution_input = s.replace(' ', "x").replace("by", "x");
if let Some((w_str, h_str)) = resolution_input.split_once('x')
let input = s.replace(' ', "x").replace("by", "x");
if let Some((w_str, h_str)) = input.split_once('x')
&& let (Ok(w), Ok(h)) = (w_str.trim().parse::<u32>(), h_str.trim().parse::<u32>())
{
match (w, h) {
@@ -489,14 +536,14 @@ impl FromStr for FujiDynamicRange {
PtpDeserialize,
EnumIter,
)]
pub enum FujiStillDynamicRangePriority {
pub enum FujiDynamicRangePriority {
Auto = 0x8000,
Strong = 0x2,
Weak = 0x1,
Off = 0x0,
}
impl fmt::Display for FujiStillDynamicRangePriority {
impl fmt::Display for FujiDynamicRangePriority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Auto => write!(f, "Auto"),
@@ -507,7 +554,7 @@ impl fmt::Display for FujiStillDynamicRangePriority {
}
}
impl FromStr for FujiStillDynamicRangePriority {
impl FromStr for FujiDynamicRangePriority {
type Err = anyhow::Error;
fn from_str(s: &str) -> anyhow::Result<Self> {
@@ -705,10 +752,10 @@ impl FromStr for FujiGrainEffect {
.replace(['+', '-', ',', ' '].as_ref(), "");
match input.as_str() {
"stronglarge" => return Ok(Self::StrongLarge),
"weaklarge" => return Ok(Self::WeakLarge),
"strongsmall" => return Ok(Self::StrongSmall),
"weaksmall" => return Ok(Self::WeakSmall),
"stronglarge" | "largestrong" => return Ok(Self::StrongLarge),
"weaklarge" | "largeweak" => return Ok(Self::WeakLarge),
"strongsmall" | "smallstrong" => return Ok(Self::StrongSmall),
"weaksmall" | "smallweak" => return Ok(Self::WeakSmall),
"off" => return Ok(Self::Off),
_ => {}
}
@@ -999,10 +1046,22 @@ macro_rules! define_fuji_i16 {
pub struct $name(i16);
impl $name {
pub const MIN: i16 = $min;
pub const MAX: i16 = $max;
pub const STEP: i16 = $step;
pub const SCALE: f32 = $scale;
pub const MIN: f32 = $min;
pub const MAX: f32 = $max;
pub const STEP: f32 = $step;
pub const SCALE: f32 = $scale as f32;
#[allow(clippy::cast_possible_truncation)]
pub const RAW_MIN: i16 = ($min * $scale as f32) as i16;
#[allow(clippy::cast_possible_truncation)]
pub const RAW_MAX: i16 = ($max * $scale as f32) as i16;
#[allow(clippy::cast_possible_truncation)]
pub const RAW_STEP: i16 = ($step * $scale as f32) as i16;
pub const unsafe fn new_unchecked(value: i16) -> Self {
Self(value)
}
}
impl std::ops::Deref for $name {
@@ -1022,12 +1081,12 @@ macro_rules! define_fuji_i16 {
type Error = anyhow::Error;
fn try_from(value: i16) -> anyhow::Result<Self> {
if !(Self::MIN..=Self::MAX).contains(&value) {
if !(Self::RAW_MIN..=Self::RAW_MAX).contains(&value) {
anyhow::bail!("Value {} is out of range", value);
}
#[allow(clippy::modulo_one)]
if (value - Self::MIN) % Self::STEP != 0 {
anyhow::bail!("Value {} is not aligned to step {}", value, Self::STEP);
if (value - Self::RAW_MIN) % Self::RAW_STEP != 0 {
anyhow::bail!("Value {} is not aligned to step {}", value, Self::RAW_STEP);
}
Ok(Self(value))
}
@@ -1035,18 +1094,8 @@ macro_rules! define_fuji_i16 {
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if (Self::SCALE - 1.0).abs() < f32::EPSILON {
write!(f, "{}", self.0)
} else {
let val = f32::from(self.0) * Self::SCALE;
if val.fract().abs() < f32::EPSILON {
#[allow(clippy::cast_possible_truncation)]
let val = val as i32;
write!(f, "{}", val as i32)
} else {
write!(f, "{:.1}", val)
}
}
let value = (f32::from(self.0) / Self::SCALE);
write!(f, "{}", value)
}
}
@@ -1061,9 +1110,18 @@ macro_rules! define_fuji_i16 {
.parse::<f32>()
.with_context(|| format!("Invalid numeric value '{s}'"))?;
if !(Self::MIN..=Self::MAX).contains(&input) {
anyhow::bail!("Value {} is out of range", input);
}
#[allow(clippy::modulo_one)]
if (input - Self::MIN) % Self::STEP != 0.0 {
anyhow::bail!("Value {} is not aligned to step {}", input, Self::STEP);
}
#[allow(clippy::cast_possible_truncation)]
let raw = (input / Self::SCALE).round() as i16;
Self::try_from(raw)
let raw = (input * Self::SCALE).round() as i16;
unsafe { Ok(Self::new_unchecked(raw)) }
}
}
@@ -1072,24 +1130,20 @@ macro_rules! define_fuji_i16 {
where
S: serde::Serializer,
{
let val = f32::from(self.0) * Self::SCALE;
if (val.fract().abs() < f32::EPSILON) {
serializer.serialize_i32(val as i32)
} else {
let val = f32::from(self.0) / Self::SCALE;
serializer.serialize_f32(val)
}
}
}
};
}
define_fuji_i16!(FujiWhiteBalanceShift, -9, 9, 1, 1.0);
define_fuji_i16!(FujiWhiteBalanceTemperature, 2500, 10000, 10, 1.0);
define_fuji_i16!(FujiHighlightTone, -40, 20, 5, 0.1);
define_fuji_i16!(FujiShadowTone, -20, 40, 5, 0.1);
define_fuji_i16!(FujiColor, -40, 40, 10, 0.1);
define_fuji_i16!(FujiSharpness, -40, 40, 10, 0.1);
define_fuji_i16!(FujiClarity, -50, 50, 10, 0.1);
define_fuji_i16!(FujiWhiteBalanceShift, -9.0, 9.0, 1.0, 1i16);
define_fuji_i16!(FujiWhiteBalanceTemperature, 2500.0, 10000.0, 10.0, 1i16);
define_fuji_i16!(FujiHighlightTone, -2.0, 4.0, 0.5, 10i16);
define_fuji_i16!(FujiShadowTone, -2.0, 4.0, 0.5, 10i16);
define_fuji_i16!(FujiColor, -4.0, 4.0, 1.0, 10i16);
define_fuji_i16!(FujiSharpness, -4.0, 4.0, 1.0, 10i16);
define_fuji_i16!(FujiClarity, -5.0, 5.0, 1.0, 10i16);
#[repr(u16)]
#[derive(

View File

@@ -1,87 +1,87 @@
use clap::Args;
use crate::camera::ptp::hex::{
FujiClarity, FujiColor, FujiColorChromeEffect, FujiColorChromeFXBlue, FujiDynamicRange,
FujiFilmSimulation, FujiGrainEffect, FujiHighISONR, FujiHighlightTone, FujiImageQuality,
FujiImageSize, FujiShadowTone, FujiSharpness, FujiStillDynamicRangePriority, FujiWhiteBalance,
FujiWhiteBalanceShift, FujiWhiteBalanceTemperature,
FujiClarity, FujiColor, FujiColorChromeEffect, FujiColorChromeFXBlue, FujiCustomSettingName,
FujiDynamicRange, FujiDynamicRangePriority, FujiFilmSimulation, FujiGrainEffect, FujiHighISONR,
FujiHighlightTone, FujiImageQuality, FujiImageSize, FujiShadowTone, FujiSharpness,
FujiWhiteBalance, FujiWhiteBalanceShift, FujiWhiteBalanceTemperature,
};
#[derive(Args, Debug)]
pub struct FilmSimulationOptions {
/// The name of the slot
#[clap(long)]
pub name: Option<String>,
pub name: Option<FujiCustomSettingName>,
/// The Fujifilm film simulation to use
#[clap(long)]
pub simulation: Option<FujiFilmSimulation>,
/// The output image resolution
#[clap(long, alias = "size")]
pub resolution: Option<FujiImageSize>,
#[clap(long)]
pub size: Option<FujiImageSize>,
/// The output image quality (JPEG compression level)
#[clap(long, value_parser)]
#[clap(long)]
pub quality: Option<FujiImageQuality>,
/// Highlight Tone
#[clap(long, value_parser)]
pub highlights: Option<FujiHighlightTone>,
#[clap(long, allow_hyphen_values(true))]
pub highlight: Option<FujiHighlightTone>,
/// Shadow Tone
#[clap(long, value_parser)]
pub shadows: Option<FujiShadowTone>,
#[clap(long, allow_hyphen_values(true))]
pub shadow: Option<FujiShadowTone>,
/// Color
#[clap(long, value_parser)]
#[clap(long, allow_hyphen_values(true))]
pub color: Option<FujiColor>,
/// Sharpness
#[clap(long, value_parser)]
#[clap(long, allow_hyphen_values(true))]
pub sharpness: Option<FujiSharpness>,
/// Clarity
#[clap(long, value_parser)]
#[clap(long, allow_hyphen_values(true))]
pub clarity: Option<FujiClarity>,
/// White Balance
#[clap(long, value_parser)]
#[clap(long)]
pub white_balance: Option<FujiWhiteBalance>,
/// White Balance Shift Red
#[clap(long, value_parser)]
#[clap(long, allow_hyphen_values(true))]
pub white_balance_shift_red: Option<FujiWhiteBalanceShift>,
/// White Balance Shift Blue
#[clap(long, value_parser)]
#[clap(long, allow_hyphen_values(true))]
pub white_balance_shift_blue: Option<FujiWhiteBalanceShift>,
/// White Balance Temperature (Only used if WB is set to 'Temperature')
#[clap(long, value_parser)]
#[clap(long)]
pub white_balance_temperature: Option<FujiWhiteBalanceTemperature>,
/// Dynamic Range
#[clap(long, value_parser)]
#[clap(long)]
pub dynamic_range: Option<FujiDynamicRange>,
/// Dynamic Range Priority
#[clap(long, value_parser)]
pub dynamic_ranga_priority: Option<FujiStillDynamicRangePriority>,
#[clap(long)]
pub dynamic_range_priority: Option<FujiDynamicRangePriority>,
/// High ISO Noise Reduction
#[clap(long, value_parser)]
#[clap(long, allow_hyphen_values(true))]
pub noise_reduction: Option<FujiHighISONR>,
/// Grain Effect
#[clap(long, value_parser)]
#[clap(long)]
pub grain: Option<FujiGrainEffect>,
/// Color Chrome Effect
#[clap(long, value_parser)]
#[clap(long)]
pub color_chrome_effect: Option<FujiColorChromeEffect>,
/// Color Chrome FX Blue
#[clap(long, value_parser)]
#[clap(long)]
pub color_chrome_fx_blue: Option<FujiColorChromeFXBlue>,
}

View File

@@ -3,9 +3,9 @@ use std::fmt;
use crate::{
camera::ptp::hex::{
FujiClarity, FujiColor, FujiColorChromeEffect, FujiColorChromeFXBlue, FujiCustomSetting,
FujiDynamicRange, FujiFilmSimulation, FujiGrainEffect, FujiHighISONR, FujiHighlightTone,
FujiImageQuality, FujiImageSize, FujiShadowTone, FujiSharpness,
FujiStillDynamicRangePriority, FujiWhiteBalance, FujiWhiteBalanceShift,
FujiCustomSettingName, FujiDynamicRange, FujiDynamicRangePriority, FujiFilmSimulation,
FujiGrainEffect, FujiHighISONR, FujiHighlightTone, FujiImageQuality, FujiImageSize,
FujiShadowTone, FujiSharpness, FujiWhiteBalance, FujiWhiteBalanceShift,
FujiWhiteBalanceTemperature,
},
usb,
@@ -16,6 +16,7 @@ use super::common::{
film::FilmSimulationOptions,
};
use clap::Subcommand;
use log::warn;
use serde::Serialize;
use strum::IntoEnumIterator;
@@ -67,7 +68,7 @@ pub enum SimulationCmd {
#[serde(rename_all = "camelCase")]
pub struct CustomSettingRepr {
pub slot: FujiCustomSetting,
pub name: String,
pub name: FujiCustomSettingName,
}
fn handle_list(json: bool, device_id: Option<&str>) -> anyhow::Result<()> {
@@ -97,12 +98,12 @@ fn handle_list(json: bool, device_id: Option<&str>) -> anyhow::Result<()> {
#[serde(rename_all = "camelCase")]
pub struct FilmSimulationRepr {
pub slot: FujiCustomSetting,
pub name: String,
pub name: FujiCustomSettingName,
pub simulation: FujiFilmSimulation,
pub resolution: FujiImageSize,
pub size: FujiImageSize,
pub quality: FujiImageQuality,
pub highlights: FujiHighlightTone,
pub shadows: FujiShadowTone,
pub highlight: FujiHighlightTone,
pub shadow: FujiShadowTone,
pub color: FujiColor,
pub sharpness: FujiSharpness,
pub clarity: FujiClarity,
@@ -111,7 +112,7 @@ pub struct FilmSimulationRepr {
pub white_balance_shift_blue: FujiWhiteBalanceShift,
pub white_balance_temperature: FujiWhiteBalanceTemperature,
pub dynamic_range: FujiDynamicRange,
pub dynamic_range_priority: FujiStillDynamicRangePriority,
pub dynamic_range_priority: FujiDynamicRangePriority,
pub noise_reduction: FujiHighISONR,
pub grain: FujiGrainEffect,
pub color_chrome_effect: FujiColorChromeEffect,
@@ -123,10 +124,10 @@ impl fmt::Display for FilmSimulationRepr {
writeln!(f, "Slot: {}", self.slot)?;
writeln!(f, "Name: {}", self.name)?;
writeln!(f, "Simulation: {}", self.simulation)?;
writeln!(f, "Resolution: {}", self.resolution)?;
writeln!(f, "Size: {}", self.size)?;
writeln!(f, "Quality: {}", self.quality)?;
writeln!(f, "Highlights: {}", self.highlights)?;
writeln!(f, "Shadows: {}", self.shadows)?;
writeln!(f, "Highlights: {}", self.highlight)?;
writeln!(f, "Shadows: {}", self.shadow)?;
writeln!(f, "Color: {}", self.color)?;
writeln!(f, "Sharpness: {}", self.sharpness)?;
writeln!(f, "Clarity: {}", self.clarity)?;
@@ -136,7 +137,11 @@ impl fmt::Display for FilmSimulationRepr {
"White Balance Shift (R/B): {} / {}",
self.white_balance_shift_red, self.white_balance_shift_blue
)?;
writeln!(f, "White Balance Temperature: {}K", self.white_balance_temperature)?;
writeln!(
f,
"White Balance Temperature: {}K",
self.white_balance_temperature
)?;
writeln!(f, "Dynamic Range: {}", self.dynamic_range)?;
writeln!(f, "Dynamic Range Priority: {}", self.dynamic_range_priority)?;
writeln!(f, "Noise Reduction: {}", self.noise_reduction)?;
@@ -154,17 +159,17 @@ fn handle_get(json: bool, device_id: Option<&str>, slot: FujiCustomSetting) -> a
slot,
name: camera.get_custom_setting_name()?,
simulation: camera.get_film_simulation()?,
resolution: camera.get_image_size()?,
size: camera.get_image_size()?,
quality: camera.get_image_quality()?,
highlights: camera.get_highlight_tone()?,
shadows: camera.get_shadow_tone()?,
highlight: camera.get_highlight_tone()?,
shadow: camera.get_shadow_tone()?,
color: camera.get_color()?,
sharpness: camera.get_sharpness()?,
clarity: camera.get_clarity()?,
white_balance: camera.get_white_balance()?,
white_balance_shift_red: camera.get_wb_shift_red()?,
white_balance_shift_blue: camera.get_wb_shift_blue()?,
white_balance_temperature: camera.get_wb_temperature()?,
white_balance_shift_red: camera.get_white_balance_shift_red()?,
white_balance_shift_blue: camera.get_white_balance_shift_blue()?,
white_balance_temperature: camera.get_white_balance_temperature()?,
dynamic_range: camera.get_dynamic_range()?,
dynamic_range_priority: camera.get_dynamic_range_priority()?,
noise_reduction: camera.get_high_iso_nr()?,
@@ -183,11 +188,118 @@ fn handle_get(json: bool, device_id: Option<&str>, slot: FujiCustomSetting) -> a
}
fn handle_set(
_device_id: Option<&str>,
_slot: FujiCustomSetting,
_opts: &FilmSimulationOptions,
device_id: Option<&str>,
slot: FujiCustomSetting,
options: &FilmSimulationOptions,
) -> anyhow::Result<()> {
todo!();
let mut camera = usb::get_camera(device_id)?;
camera.set_active_custom_setting(slot)?;
// General
if let Some(name) = &options.name {
camera.set_custom_setting_name(name)?;
}
if let Some(size) = &options.size {
camera.set_image_size(*size)?;
}
if let Some(quality) = &options.quality {
camera.set_image_quality(*quality)?;
}
// Style
if let Some(simulation) = &options.simulation {
camera.set_film_simulation(*simulation)?;
}
if let Some(color) = &options.color {
camera.set_color(*color)?;
}
if let Some(sharpness) = &options.sharpness {
camera.set_sharpness(*sharpness)?;
}
if let Some(clarity) = &options.clarity {
camera.set_clarity(*clarity)?;
}
if let Some(noise_reduction) = &options.noise_reduction {
camera.set_high_iso_nr(*noise_reduction)?;
}
if let Some(grain) = &options.grain {
camera.set_grain_effect(*grain)?;
}
if let Some(color_chrome_effect) = &options.color_chrome_effect {
camera.set_color_chrome_effect(*color_chrome_effect)?;
}
if let Some(color_chrome_fx_blue) = &options.color_chrome_fx_blue {
camera.set_color_chrome_fx_blue(*color_chrome_fx_blue)?;
}
// White Balance
let white_balance = match &options.white_balance {
Some(white_balance) => {
camera.set_white_balance(*white_balance)?;
white_balance
}
None => &camera.get_white_balance()?,
};
if let Some(temperature) = &options.white_balance_temperature {
if *white_balance != FujiWhiteBalance::Temperature {
warn!("White Balance mode is not set to 'Temperature', refusing to set temperature")
} else {
camera.set_white_balance_temperature(*temperature)?;
}
}
if let Some(shift_red) = &options.white_balance_shift_red {
camera.set_white_balance_shift_red(*shift_red)?;
}
if let Some(shift_blue) = &options.white_balance_shift_blue {
camera.set_white_balance_shift_blue(*shift_blue)?;
}
// Exposure
let dynamic_range_priority = match &options.dynamic_range_priority {
Some(dynamic_range_priority) => {
camera.set_dynamic_range_priority(*dynamic_range_priority)?;
dynamic_range_priority
}
None => &camera.get_dynamic_range_priority()?,
};
if let Some(dynamic_range) = &options.dynamic_range {
if *dynamic_range_priority != FujiDynamicRangePriority::Off {
warn!("Dynamic Range Priority is enabled, refusing to set dynamic range")
} else {
camera.set_dynamic_range(*dynamic_range)?;
}
}
if let Some(highlights) = &options.highlight {
if *dynamic_range_priority != FujiDynamicRangePriority::Off {
warn!("Dynamic Range Priority is enabled, refusing to set highlight tone")
} else {
camera.set_highlight_tone(*highlights)?;
}
}
if let Some(shadows) = &options.shadow {
if *dynamic_range_priority != FujiDynamicRangePriority::Off {
warn!("Dynamic Range Priority is enabled, refusing to set shadow tone")
} else {
camera.set_shadow_tone(*shadows)?;
}
}
Ok(())
}
fn handle_export(

View File

@@ -14,7 +14,13 @@ pub fn init(verbose: u8) -> anyhow::Result<()> {
_ => LevelFilter::Trace,
};
let encoder = Box::new(PatternEncoder::new("{d} {h({l})} {M}::{L} - {m}{n}"));
let pattern = if verbose > 0 {
"{d} {h({l})} {M}::{L} - {m}{n}"
} else {
"{h({l})} - {m}{n}"
};
let encoder = Box::new(PatternEncoder::new(pattern));
let console = ConsoleAppender::builder()
.encoder(encoder)