From c8c438a98cedd0b7e47920b63f2db82deaec8de5 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Thu, 5 Dec 2024 06:24:02 +0800 Subject: [PATCH 1/2] Use custom rustfmt config --- .rustfmt.toml | 5 +- src/exif.rs | 398 ++++++++++------------------------- src/exifpost.rs | 21 +- src/exifreadable.rs | 424 ++++++++++++++++++++------------------ src/ifdformat.rs | 24 +-- src/image.rs | 4 +- src/lib.rs | 13 +- src/lowlevel.rs | 24 +-- src/main.rs | 4 +- src/tiff.rs | 56 ++--- src/types.rs | 70 +++---- src/types_impl.rs | 3 +- tests/integration_test.rs | 32 ++- 13 files changed, 423 insertions(+), 655 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index df66ea2..b981b97 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,2 +1,3 @@ -# Output of rustfmt causes too many inconsistencies to be used unconditionally -disable-all-formatting = true +max_width = 120 +use_small_heuristics = "Max" +combine_control_expr = false diff --git a/src/exif.rs b/src/exif.rs index 53c7952..82bf50c 100644 --- a/src/exif.rs +++ b/src/exif.rs @@ -11,400 +11,214 @@ type ReadableFn = fn(u16, &TagValue) -> Option>; /// Returns (tag, unit, format, `min_count`, `max_count`, `more_readable`) pub(crate) fn tag_to_exif(f: u16) -> (ExifTag, &'static str, IfdFormat, i32, i32, ReadableFn) { match f { - 0x010e => - (ExifTag::ImageDescription, "none", IfdFormat::Ascii, - -1i32, -1i32, strpass), + 0x010e => (ExifTag::ImageDescription, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x010f => - (ExifTag::Make, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x010f => (ExifTag::Make, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x013c => - (ExifTag::HostComputer, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x013c => (ExifTag::HostComputer, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x0110 => - (ExifTag::Model, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x0110 => (ExifTag::Model, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x0112 => - (ExifTag::Orientation, "none", IfdFormat::U16, 1, 1, orientation), + 0x0112 => (ExifTag::Orientation, "none", IfdFormat::U16, 1, 1, orientation), - 0x011a => - (ExifTag::XResolution, "pixels per res unit", - IfdFormat::URational, 1, 1, rational_value), + 0x011a => (ExifTag::XResolution, "pixels per res unit", IfdFormat::URational, 1, 1, rational_value), - 0x011b => - (ExifTag::YResolution, "pixels per res unit", - IfdFormat::URational, 1, 1, rational_value), + 0x011b => (ExifTag::YResolution, "pixels per res unit", IfdFormat::URational, 1, 1, rational_value), - 0x0128 => - (ExifTag::ResolutionUnit, "none", IfdFormat::U16, 1, 1, resolution_unit), + 0x0128 => (ExifTag::ResolutionUnit, "none", IfdFormat::U16, 1, 1, resolution_unit), - 0x0131 => - (ExifTag::Software, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x0131 => (ExifTag::Software, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x0132 => - (ExifTag::DateTime, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x0132 => (ExifTag::DateTime, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x013e => - (ExifTag::WhitePoint, "CIE 1931 coordinates", - IfdFormat::URational, 2, 2, rational_values), + 0x013e => (ExifTag::WhitePoint, "CIE 1931 coordinates", IfdFormat::URational, 2, 2, rational_values), - 0x013f => - (ExifTag::PrimaryChromaticities, "CIE 1931 coordinates", - IfdFormat::URational, 6, 6, rational_values), + 0x013f => (ExifTag::PrimaryChromaticities, "CIE 1931 coordinates", IfdFormat::URational, 6, 6, rational_values), - 0x0211 => - (ExifTag::YCbCrCoefficients, "none", - IfdFormat::URational, 3, 3, rational_values), + 0x0211 => (ExifTag::YCbCrCoefficients, "none", IfdFormat::URational, 3, 3, rational_values), - 0x0214 => - (ExifTag::ReferenceBlackWhite, "RGB or YCbCr", - IfdFormat::URational, 6, 6, rational_values), + 0x0214 => (ExifTag::ReferenceBlackWhite, "RGB or YCbCr", IfdFormat::URational, 6, 6, rational_values), - 0x8298 => - (ExifTag::Copyright, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x8298 => (ExifTag::Copyright, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x8769 => - (ExifTag::ExifOffset, "byte offset", - IfdFormat::U32, 1, 1, strpass), + 0x8769 => (ExifTag::ExifOffset, "byte offset", IfdFormat::U32, 1, 1, strpass), - 0x8825 => - (ExifTag::GPSOffset, "byte offset", - IfdFormat::U32, 1, 1, strpass), + 0x8825 => (ExifTag::GPSOffset, "byte offset", IfdFormat::U32, 1, 1, strpass), - 0x829a => - (ExifTag::ExposureTime, "s", - IfdFormat::URational, 1, 1, exposure_time), + 0x829a => (ExifTag::ExposureTime, "s", IfdFormat::URational, 1, 1, exposure_time), - 0x829d => - (ExifTag::FNumber, "f-number", - IfdFormat::URational, 1, 1, f_number), + 0x829d => (ExifTag::FNumber, "f-number", IfdFormat::URational, 1, 1, f_number), - 0x8822 => - (ExifTag::ExposureProgram, "none", - IfdFormat::U16, 1, 1, exposure_program), + 0x8822 => (ExifTag::ExposureProgram, "none", IfdFormat::U16, 1, 1, exposure_program), - 0x8824 => - (ExifTag::SpectralSensitivity, "ASTM string", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x8824 => (ExifTag::SpectralSensitivity, "ASTM string", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x8830 => - (ExifTag::SensitivityType, "none", - IfdFormat::U16, 1, 1, sensitivity_type), + 0x8830 => (ExifTag::SensitivityType, "none", IfdFormat::U16, 1, 1, sensitivity_type), - 0x8827 => - (ExifTag::ISOSpeedRatings, "ISO", - IfdFormat::U16, 1, 3, iso_speeds), + 0x8827 => (ExifTag::ISOSpeedRatings, "ISO", IfdFormat::U16, 1, 3, iso_speeds), - 0x8828 => - (ExifTag::OECF, "none", - IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), + 0x8828 => (ExifTag::OECF, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), - 0x9000 => - (ExifTag::ExifVersion, "none", - IfdFormat::Undefined, -1i32, -1i32, undefined_as_ascii), + 0x9000 => (ExifTag::ExifVersion, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_ascii), - 0x9003 => - (ExifTag::DateTimeOriginal, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x9003 => (ExifTag::DateTimeOriginal, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x9004 => - (ExifTag::DateTimeDigitized, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x9004 => (ExifTag::DateTimeDigitized, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x9201 => - (ExifTag::ShutterSpeedValue, "APEX", - IfdFormat::IRational, 1, 1, apex_tv), + 0x9201 => (ExifTag::ShutterSpeedValue, "APEX", IfdFormat::IRational, 1, 1, apex_tv), - 0x9202 => - (ExifTag::ApertureValue, "APEX", - IfdFormat::URational, 1, 1, apex_av), + 0x9202 => (ExifTag::ApertureValue, "APEX", IfdFormat::URational, 1, 1, apex_av), - 0x9203 => - (ExifTag::BrightnessValue, "APEX", - IfdFormat::IRational, 1, 1, apex_brightness), + 0x9203 => (ExifTag::BrightnessValue, "APEX", IfdFormat::IRational, 1, 1, apex_brightness), - 0x9204 => - (ExifTag::ExposureBiasValue, "APEX", - IfdFormat::IRational, 1, 1, apex_ev), + 0x9204 => (ExifTag::ExposureBiasValue, "APEX", IfdFormat::IRational, 1, 1, apex_ev), - 0x9205 => - (ExifTag::MaxApertureValue, - "APEX", IfdFormat::URational, 1, 1, apex_av), + 0x9205 => (ExifTag::MaxApertureValue, "APEX", IfdFormat::URational, 1, 1, apex_av), - 0x9206 => - (ExifTag::SubjectDistance, "m", - IfdFormat::URational, 1, 1, meters), + 0x9206 => (ExifTag::SubjectDistance, "m", IfdFormat::URational, 1, 1, meters), - 0x9207 => - (ExifTag::MeteringMode, "none", - IfdFormat::U16, 1, 1, metering_mode), + 0x9207 => (ExifTag::MeteringMode, "none", IfdFormat::U16, 1, 1, metering_mode), - 0x9208 => - (ExifTag::LightSource, "none", - IfdFormat::U16, 1, 1, light_source), + 0x9208 => (ExifTag::LightSource, "none", IfdFormat::U16, 1, 1, light_source), - 0x9209 => (ExifTag::Flash, "none", - IfdFormat::U16, 1, 2, flash), + 0x9209 => (ExifTag::Flash, "none", IfdFormat::U16, 1, 2, flash), - 0x920a => - (ExifTag::FocalLength, "mm", - IfdFormat::URational, 1, 1, focal_length), + 0x920a => (ExifTag::FocalLength, "mm", IfdFormat::URational, 1, 1, focal_length), - 0x9214 => - (ExifTag::SubjectArea, "px", - IfdFormat::U16, 2, 4, subject_area), + 0x9214 => (ExifTag::SubjectArea, "px", IfdFormat::U16, 2, 4, subject_area), - 0x927c => - (ExifTag::MakerNote, "none", - IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), + 0x927c => (ExifTag::MakerNote, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), - 0x9286 => - (ExifTag::UserComment, "none", - IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), + 0x9286 => (ExifTag::UserComment, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), - 0xa000 => - (ExifTag::FlashPixVersion, "none", - IfdFormat::Undefined, -1i32, -1i32, undefined_as_ascii), + 0xa000 => (ExifTag::FlashPixVersion, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_ascii), - 0xa001 => - (ExifTag::ColorSpace, "none", - IfdFormat::U16, 1, 1, color_space), + 0xa001 => (ExifTag::ColorSpace, "none", IfdFormat::U16, 1, 1, color_space), - 0xa004 => - (ExifTag::RelatedSoundFile, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0xa004 => (ExifTag::RelatedSoundFile, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0xa20b => (ExifTag::FlashEnergy, "BCPS", - IfdFormat::URational, 1, 1, flash_energy), + 0xa20b => (ExifTag::FlashEnergy, "BCPS", IfdFormat::URational, 1, 1, flash_energy), - 0xa20e => - (ExifTag::FocalPlaneXResolution, "@FocalPlaneResolutionUnit", - IfdFormat::URational, 1, 1, rational_value), + 0xa20e => { + (ExifTag::FocalPlaneXResolution, "@FocalPlaneResolutionUnit", IfdFormat::URational, 1, 1, rational_value) + } - 0xa20f => - (ExifTag::FocalPlaneYResolution, "@FocalPlaneResolutionUnit", - IfdFormat::URational, 1, 1, rational_value), + 0xa20f => { + (ExifTag::FocalPlaneYResolution, "@FocalPlaneResolutionUnit", IfdFormat::URational, 1, 1, rational_value) + } - 0xa210 => - (ExifTag::FocalPlaneResolutionUnit, "none", - IfdFormat::U16, 1, 1, resolution_unit), + 0xa210 => (ExifTag::FocalPlaneResolutionUnit, "none", IfdFormat::U16, 1, 1, resolution_unit), - 0xa214 => - (ExifTag::SubjectLocation, "X,Y", - IfdFormat::U16, 2, 2, subject_location), + 0xa214 => (ExifTag::SubjectLocation, "X,Y", IfdFormat::U16, 2, 2, subject_location), // TODO check if rational as decimal value is the best for this one - 0xa215 => - (ExifTag::ExposureIndex, "EI", - IfdFormat::URational, 1, 1, rational_value), + 0xa215 => (ExifTag::ExposureIndex, "EI", IfdFormat::URational, 1, 1, rational_value), - 0xa217 => - (ExifTag::SensingMethod, "none", - IfdFormat::U16, 1, 1, sensing_method), + 0xa217 => (ExifTag::SensingMethod, "none", IfdFormat::U16, 1, 1, sensing_method), - 0xa300 => - (ExifTag::FileSource, "none", - IfdFormat::Undefined, 1, 1, file_source), + 0xa300 => (ExifTag::FileSource, "none", IfdFormat::Undefined, 1, 1, file_source), - 0xa301 => - (ExifTag::SceneType, "none", - IfdFormat::Undefined, 1, 1, scene_type), + 0xa301 => (ExifTag::SceneType, "none", IfdFormat::Undefined, 1, 1, scene_type), - 0xa302 => - (ExifTag::CFAPattern, "none", - IfdFormat::Undefined, -1i32, -1i32, undefined_as_u8), + 0xa302 => (ExifTag::CFAPattern, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_u8), - 0xa401 => - (ExifTag::CustomRendered, "none", - IfdFormat::U16, 1, 1, custom_rendered), + 0xa401 => (ExifTag::CustomRendered, "none", IfdFormat::U16, 1, 1, custom_rendered), - 0xa402 => - (ExifTag::ExposureMode, "none", - IfdFormat::U16, 1, 1, exposure_mode), + 0xa402 => (ExifTag::ExposureMode, "none", IfdFormat::U16, 1, 1, exposure_mode), - 0xa403 => - (ExifTag::WhiteBalanceMode, "none", - IfdFormat::U16, 1, 1, white_balance_mode), + 0xa403 => (ExifTag::WhiteBalanceMode, "none", IfdFormat::U16, 1, 1, white_balance_mode), - 0xa404 => - (ExifTag::DigitalZoomRatio, "none", - IfdFormat::URational, 1, 1, rational_value), + 0xa404 => (ExifTag::DigitalZoomRatio, "none", IfdFormat::URational, 1, 1, rational_value), - 0xa405 => - (ExifTag::FocalLengthIn35mmFilm, "mm", - IfdFormat::U16, 1, 1, focal_length_35), + 0xa405 => (ExifTag::FocalLengthIn35mmFilm, "mm", IfdFormat::U16, 1, 1, focal_length_35), - 0xa406 => - (ExifTag::SceneCaptureType, "none", - IfdFormat::U16, 1, 1, scene_capture_type), + 0xa406 => (ExifTag::SceneCaptureType, "none", IfdFormat::U16, 1, 1, scene_capture_type), - 0xa407 => - (ExifTag::GainControl, "none", - IfdFormat::U16, 1, 1, gain_control), + 0xa407 => (ExifTag::GainControl, "none", IfdFormat::U16, 1, 1, gain_control), - 0xa408 => - (ExifTag::Contrast, "none", - IfdFormat::U16, 1, 1, contrast), + 0xa408 => (ExifTag::Contrast, "none", IfdFormat::U16, 1, 1, contrast), - 0xa409 => - (ExifTag::Saturation, "none", - IfdFormat::U16, 1, 1, saturation), + 0xa409 => (ExifTag::Saturation, "none", IfdFormat::U16, 1, 1, saturation), - 0xa40a => - (ExifTag::Sharpness, "none", - IfdFormat::U16, 1, 1, sharpness), + 0xa40a => (ExifTag::Sharpness, "none", IfdFormat::U16, 1, 1, sharpness), - 0xa432 => - (ExifTag::LensSpecification, "none", - IfdFormat::URational, 4, 4, lens_spec), + 0xa432 => (ExifTag::LensSpecification, "none", IfdFormat::URational, 4, 4, lens_spec), - 0xa433 => - (ExifTag::LensMake, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0xa433 => (ExifTag::LensMake, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0xa434 => - (ExifTag::LensModel, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0xa434 => (ExifTag::LensModel, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0xa500 => - (ExifTag::Gamma, "none", - IfdFormat::URational, 1, 1, rational_value), + 0xa500 => (ExifTag::Gamma, "none", IfdFormat::URational, 1, 1, rational_value), // collaborate if you have any idea how to interpret this - 0xa40b => - (ExifTag::DeviceSettingDescription, "none", - IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), + 0xa40b => (ExifTag::DeviceSettingDescription, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), - 0xa40c => - (ExifTag::SubjectDistanceRange, "none", - IfdFormat::U16, 1, 1, subject_distance_range), + 0xa40c => (ExifTag::SubjectDistanceRange, "none", IfdFormat::U16, 1, 1, subject_distance_range), - 0xa420 => - (ExifTag::ImageUniqueID, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0xa420 => (ExifTag::ImageUniqueID, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x0 => - (ExifTag::GPSVersionID, "none", - IfdFormat::U8, 4, 4, strpass), + 0x0 => (ExifTag::GPSVersionID, "none", IfdFormat::U8, 4, 4, strpass), - 0x1 => - (ExifTag::GPSLatitudeRef, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x1 => (ExifTag::GPSLatitudeRef, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x2 => - (ExifTag::GPSLatitude, "D/M/S", - IfdFormat::URational, 3, 3, dms), + 0x2 => (ExifTag::GPSLatitude, "D/M/S", IfdFormat::URational, 3, 3, dms), - 0x3 => - (ExifTag::GPSLongitudeRef, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x3 => (ExifTag::GPSLongitudeRef, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x4 => - (ExifTag::GPSLongitude, "D/M/S", - IfdFormat::URational, 3, 3, dms), + 0x4 => (ExifTag::GPSLongitude, "D/M/S", IfdFormat::URational, 3, 3, dms), - 0x5 => - (ExifTag::GPSAltitudeRef, "none", - IfdFormat::U8, 1, 1, gps_alt_ref), + 0x5 => (ExifTag::GPSAltitudeRef, "none", IfdFormat::U8, 1, 1, gps_alt_ref), - 0x6 => - (ExifTag::GPSAltitude, "m", - IfdFormat::URational, 1, 1, meters), + 0x6 => (ExifTag::GPSAltitude, "m", IfdFormat::URational, 1, 1, meters), - 0x7 => - (ExifTag::GPSTimeStamp, "UTC time", - IfdFormat::URational, 3, 3, gpstimestamp), + 0x7 => (ExifTag::GPSTimeStamp, "UTC time", IfdFormat::URational, 3, 3, gpstimestamp), - 0x8 => (ExifTag::GPSSatellites, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x8 => (ExifTag::GPSSatellites, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x9 => (ExifTag::GPSStatus, "none", - IfdFormat::Ascii, -1i32, -1i32, gpsstatus), + 0x9 => (ExifTag::GPSStatus, "none", IfdFormat::Ascii, -1i32, -1i32, gpsstatus), - 0xa => (ExifTag::GPSMeasureMode, "none", - IfdFormat::Ascii, -1i32, -1i32, gpsmeasuremode), + 0xa => (ExifTag::GPSMeasureMode, "none", IfdFormat::Ascii, -1i32, -1i32, gpsmeasuremode), - 0xb => - (ExifTag::GPSDOP, "none", - IfdFormat::URational, 1, 1, rational_value), + 0xb => (ExifTag::GPSDOP, "none", IfdFormat::URational, 1, 1, rational_value), - 0xc => - (ExifTag::GPSSpeedRef, "none", - IfdFormat::Ascii, -1i32, -1i32, gpsspeedref), + 0xc => (ExifTag::GPSSpeedRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsspeedref), - 0xd => - (ExifTag::GPSSpeed, "@GPSSpeedRef", - IfdFormat::URational, 1, 1, gpsspeed), + 0xd => (ExifTag::GPSSpeed, "@GPSSpeedRef", IfdFormat::URational, 1, 1, gpsspeed), - 0xe => - (ExifTag::GPSTrackRef, "none", - IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), + 0xe => (ExifTag::GPSTrackRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), - 0xf => - (ExifTag::GPSTrack, "deg", - IfdFormat::URational, 1, 1, gpsbearing), + 0xf => (ExifTag::GPSTrack, "deg", IfdFormat::URational, 1, 1, gpsbearing), - 0x10 => - (ExifTag::GPSImgDirectionRef, "none", - IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), + 0x10 => (ExifTag::GPSImgDirectionRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), - 0x11 => - (ExifTag::GPSImgDirection, "deg", - IfdFormat::URational, 1, 1, gpsbearing), + 0x11 => (ExifTag::GPSImgDirection, "deg", IfdFormat::URational, 1, 1, gpsbearing), - 0x12 => - (ExifTag::GPSMapDatum, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x12 => (ExifTag::GPSMapDatum, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x13 => - (ExifTag::GPSDestLatitudeRef, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x13 => (ExifTag::GPSDestLatitudeRef, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x14 => - (ExifTag::GPSDestLatitude, "D/M/S", - IfdFormat::URational, 3, 3, dms), + 0x14 => (ExifTag::GPSDestLatitude, "D/M/S", IfdFormat::URational, 3, 3, dms), - 0x15 => - (ExifTag::GPSDestLongitudeRef, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x15 => (ExifTag::GPSDestLongitudeRef, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x16 => - (ExifTag::GPSDestLongitude, "D/M/S", - IfdFormat::URational, 3, 3, dms), + 0x16 => (ExifTag::GPSDestLongitude, "D/M/S", IfdFormat::URational, 3, 3, dms), - 0x17 => - (ExifTag::GPSDestBearingRef, "none", - IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), + 0x17 => (ExifTag::GPSDestBearingRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), - 0x18 => - (ExifTag::GPSDestBearing, "deg", - IfdFormat::URational, 1, 1, gpsbearing), + 0x18 => (ExifTag::GPSDestBearing, "deg", IfdFormat::URational, 1, 1, gpsbearing), - 0x19 => - (ExifTag::GPSDestDistanceRef, "none", - IfdFormat::Ascii, -1i32, -1i32, gpsdestdistanceref), + 0x19 => (ExifTag::GPSDestDistanceRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsdestdistanceref), - 0x1a => - (ExifTag::GPSDestDistance, "@GPSDestDistanceRef", - IfdFormat::URational, 1, 1, gpsdestdistance), + 0x1a => (ExifTag::GPSDestDistance, "@GPSDestDistanceRef", IfdFormat::URational, 1, 1, gpsdestdistance), - 0x1b => - (ExifTag::GPSProcessingMethod, "none", - IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), + 0x1b => (ExifTag::GPSProcessingMethod, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), - 0x1c => (ExifTag::GPSAreaInformation, - "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), + 0x1c => (ExifTag::GPSAreaInformation, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), - 0x1d => - (ExifTag::GPSDateStamp, "none", - IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x1d => (ExifTag::GPSDateStamp, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), - 0x1e => - (ExifTag::GPSDifferential, "none", - IfdFormat::U16, 1, 1, gpsdiff), + 0x1e => (ExifTag::GPSDifferential, "none", IfdFormat::U16, 1, 1, gpsdiff), - _ => - (ExifTag::UnknownToMe, "Unknown unit", - IfdFormat::Unknown, -1i32, -1i32, unknown) + _ => (ExifTag::UnknownToMe, "Unknown unit", IfdFormat::Unknown, -1i32, -1i32, unknown), } } diff --git a/src/exifpost.rs b/src/exifpost.rs index f4cd50f..5785bac 100644 --- a/src/exifpost.rs +++ b/src/exifpost.rs @@ -2,8 +2,7 @@ use super::types::{ExifEntry, ExifTag, TagValue}; /// Find a tag of given type fn other_tag<'a>(tag: ExifTag, entries1: &'a [ExifEntry], entries2: &'a [ExifEntry]) -> Option<&'a ExifEntry> { - entries1.iter().find(|entry| entry.tag == tag) - .or_else(|| entries2.iter().find(|entry| entry.tag == tag)) + entries1.iter().find(|entry| entry.tag == tag).or_else(|| entries2.iter().find(|entry| entry.tag == tag)) } /// Does postprocessing in tags that depend on other tags to have a complete interpretation @@ -17,7 +16,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], v.push_str(" pixels per "); v.push_str(&f.value_more_readable); } - }, + } ExifTag::FocalPlaneXResolution | ExifTag::FocalPlaneYResolution => { if let Some(f) = other_tag(ExifTag::FocalPlaneResolutionUnit, entries1, entries2) { @@ -26,7 +25,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], v.push_str(" pixels per "); v.push_str(&f.value_more_readable); } - }, + } ExifTag::GPSLatitude => { if let Some(f) = other_tag(ExifTag::GPSLatitudeRef, entries1, entries2) { @@ -34,7 +33,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], v.push(' '); v.push_str(&f.value_more_readable); } - }, + } ExifTag::GPSLongitude => { if let Some(f) = other_tag(ExifTag::GPSLongitudeRef, entries1, entries2) { @@ -42,7 +41,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], v.push(' '); v.push_str(&f.value_more_readable); } - }, + } ExifTag::GPSAltitude => { if let Some(f) = other_tag(ExifTag::GPSAltitudeRef, entries1, entries2) { @@ -55,7 +54,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], entry.value_more_readable.to_mut().push_str(" below sea level"); } } - }, + } ExifTag::GPSDestLatitude => { if let Some(f) = other_tag(ExifTag::GPSDestLatitudeRef, entries1, entries2) { @@ -63,7 +62,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], v.push(' '); v.push_str(&f.value_more_readable); } - }, + } ExifTag::GPSDestLongitude => { if let Some(f) = other_tag(ExifTag::GPSDestLongitudeRef, entries1, entries2) { @@ -71,7 +70,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], v.push(' '); v.push_str(&f.value_more_readable); } - }, + } ExifTag::GPSDestDistance => { if let Some(f) = other_tag(ExifTag::GPSDestDistanceRef, entries1, entries2) { @@ -80,7 +79,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], v.push(' '); v.push_str(&f.value_more_readable); } - }, + } ExifTag::GPSSpeed => { if let Some(f) = other_tag(ExifTag::GPSSpeedRef, entries1, entries2) { @@ -89,7 +88,7 @@ pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], v.push(' '); v.push_str(&f.value_more_readable); } - }, + } _ => (), } } diff --git a/src/exifreadable.rs b/src/exifreadable.rs index ae37113..79ef024 100644 --- a/src/exifreadable.rs +++ b/src/exifreadable.rs @@ -18,64 +18,71 @@ pub(crate) fn strpass(_tag: u16, e: &TagValue) -> Option> { /// Indicates which one of the parameters of ISO12232 is used for `PhotographicSensitivity` pub(crate) fn sensitivity_type(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => Some(match v.first()? { - 0 => "Unknown", - 1 => "Standard output sensitivity (SOS)", - 2 => "Recommended exposure index (REI)", - 3 => "ISO speed", - 4 => "Standard output sensitivity (SOS) and recommended exposure index (REI)", - 5 => "Standard output sensitivity (SOS) and ISO speed", - 6 => "Recommended exposure index (REI) and ISO speed", - 7 => "Standard output sensitivity (SOS) and recommended exposure index (REI) and ISO speed", - n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()), + TagValue::U16(ref v) => Some( + match v.first()? { + 0 => "Unknown", + 1 => "Standard output sensitivity (SOS)", + 2 => "Recommended exposure index (REI)", + 3 => "ISO speed", + 4 => "Standard output sensitivity (SOS) and recommended exposure index (REI)", + 5 => "Standard output sensitivity (SOS) and ISO speed", + 6 => "Recommended exposure index (REI) and ISO speed", + 7 => "Standard output sensitivity (SOS) and recommended exposure index (REI) and ISO speed", + n => return Some(format!("Unknown ({tag:04x}={n})").into()), + } + .into(), + ), _ => None, } } pub(crate) fn orientation(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 1 => "Straight", 3 => "Upside down", 6 => "Rotated to left", 8 => "Rotated to right", 9 => "Undefined", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn rational_value(_tag: u16, e: &TagValue) -> Option> { - Some(match e { - TagValue::URational(v) => v.first()?.value(), - TagValue::IRational(v) => v.first()?.value(), - _ => return None, - }.to_string().into()) + Some( + match e { + TagValue::URational(v) => v.first()?.value(), + TagValue::IRational(v) => v.first()?.value(), + _ => return None, + } + .to_string() + .into(), + ) } pub(crate) fn rational_values(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::URational(ref v) => { - Some(NumArray::new(v.iter().map(|&x| x.value())).to_string().into()) - }, + TagValue::URational(ref v) => Some(NumArray::new(v.iter().map(|&x| x.value())).to_string().into()), _ => None, } } pub(crate) fn resolution_unit(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 1 => "Unitless", 2 => "in", 3 => "cm", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } @@ -84,17 +91,20 @@ pub(crate) fn exposure_time(_tag: u16, e: &TagValue) -> Option match *e { TagValue::URational(ref v) => { let r = v.first()?; - Some(if r.numerator == 1 && r.denominator > 1 { - // traditional 1/x exposure time - format!("{r} s") - } else if r.value() < 0.1 { - format!("1/{:.0} s", 1.0 / r.value()) - } else if r.value() < 1.0 { - format!("1/{:.1} s", 1.0 / r.value()) - } else { - format!("{:.1} s", r.value()) - }.into()) - }, + Some( + if r.numerator == 1 && r.denominator > 1 { + // traditional 1/x exposure time + format!("{r} s") + } else if r.value() < 0.1 { + format!("1/{:.0} s", 1.0 / r.value()) + } else if r.value() < 1.0 { + format!("1/{:.1} s", 1.0 / r.value()) + } else { + format!("{:.1} s", r.value()) + } + .into(), + ) + } _ => None, } } @@ -108,8 +118,8 @@ pub(crate) fn f_number(_tag: u16, e: &TagValue) -> Option> { pub(crate) fn exposure_program(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 1 => "Manual control", 2 => "Program control", 3 => "Aperture priority", @@ -119,8 +129,9 @@ pub(crate) fn exposure_program(tag: u16, e: &TagValue) -> Option "Portrait mode", 8 => "Landscape mode", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } @@ -148,15 +159,16 @@ pub(crate) fn meters(_tag: u16, e: &TagValue) -> Option> { pub(crate) fn iso_speeds(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(if v.len() == 1 { + TagValue::U16(ref v) => Some( + if v.len() == 1 { format!("ISO {}", v[0]) } else if v.len() == 2 || v.len() == 3 { format!("ISO {} latitude {}", v[0], v[1]) } else { format!("Unknown ({})", NumArray::new(v)) - }.into()) - }, + } + .into(), + ), _ => None, } } @@ -167,39 +179,40 @@ pub(crate) fn dms(_tag: u16, e: &TagValue) -> Option> { let deg = v[0]; let min = v[1]; let sec = v[2]; - Some(if deg.denominator == 1 && min.denominator == 1 { - format!("{}°{}'{:.2}\"", deg.value(), min.value(), sec.value()) - } else if deg.denominator == 1 { - format!("{}°{:.4}'", deg.value(), min.value() + sec.value() / 60.0) - } else { - // untypical format - format!( - "{:.7}°", - deg.value() + min.value() / 60.0 + sec.value() / 3600.0 - ) - }.into()) - }, + Some( + if deg.denominator == 1 && min.denominator == 1 { + format!("{}°{}'{:.2}\"", deg.value(), min.value(), sec.value()) + } else if deg.denominator == 1 { + format!("{}°{:.4}'", deg.value(), min.value() + sec.value() / 60.0) + } else { + // untypical format + format!("{:.7}°", deg.value() + min.value() / 60.0 + sec.value() / 3600.0) + } + .into(), + ) + } _ => None, } } pub(crate) fn gps_alt_ref(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U8(ref v) => { - Some(match v.first()? { + TagValue::U8(ref v) => Some( + match v.first()? { 0 => "Above sea level", 1 => "Below sea level", n => return Some(format!("Unknown, assumed below sea level ({n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn gpsdestdistanceref(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::Ascii(ref v) => { - Some(if v == "N" { + TagValue::Ascii(ref v) => Some( + if v == "N" { "kn".into() } else if v == "K" { "km".into() @@ -207,8 +220,8 @@ pub(crate) fn gpsdestdistanceref(_tag: u16, e: &TagValue) -> Option None, } } @@ -222,8 +235,8 @@ pub(crate) fn gpsdestdistance(_tag: u16, e: &TagValue) -> Option Option> { match *e { - TagValue::Ascii(ref v) => { - Some(if v == "N" { + TagValue::Ascii(ref v) => Some( + if v == "N" { "kn".into() } else if v == "K" { "km/h".into() @@ -231,8 +244,8 @@ pub(crate) fn gpsspeedref(_tag: u16, e: &TagValue) -> Option> "mi/h".into() } else { format!("Unknown ({v})").into() - }) - }, + }, + ), _ => None, } } @@ -246,15 +259,15 @@ pub(crate) fn gpsspeed(_tag: u16, e: &TagValue) -> Option> { pub(crate) fn gpsbearingref(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::Ascii(ref v) => { - Some(if v == "T" { + TagValue::Ascii(ref v) => Some( + if v == "T" { "True bearing".into() } else if v == "M" { "Magnetic bearing".into() } else { format!("Unknown ({v})").into() - }) - }, + }, + ), _ => None, } } @@ -272,56 +285,49 @@ pub(crate) fn gpstimestamp(_tag: u16, e: &TagValue) -> Option> let sec = v.get(2)?; let hour = v.first()?; let min = v.get(1)?; - Some(format!( - "{:02.0}:{:02.0}:{:04.1} UTC", - hour.value(), - min.value(), - sec.value() - ).into()) - }, + Some(format!("{:02.0}:{:02.0}:{:04.1} UTC", hour.value(), min.value(), sec.value()).into()) + } _ => None, } } pub(crate) fn gpsdiff(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { - 0 => "Measurement without differential correction".into(), - 1 => "Differential correction applied".into(), - n => format!("Unknown ({tag:04x}={n})").into(), - }) - }, + TagValue::U16(ref v) => Some(match v.first()? { + 0 => "Measurement without differential correction".into(), + 1 => "Differential correction applied".into(), + n => format!("Unknown ({tag:04x}={n})").into(), + }), _ => None, } } pub(crate) fn gpsstatus(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::Ascii(ref v) => { - Some(if v == "A" { + TagValue::Ascii(ref v) => Some( + if v == "A" { "Measurement in progress".into() } else if v == "V" { "Measurement is interoperability".into() } else { format!("Unknown ({v})").into() - }) - }, + }, + ), _ => None, } } pub(crate) fn gpsmeasuremode(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::Ascii(ref v) => { - Some(if v == "2" { + TagValue::Ascii(ref v) => Some( + if v == "2" { "2-dimension".into() } else if v == "3" { "3-dimension".into() } else { format!("Unknown ({v})").into() - }) - }, + }, + ), _ => None, } } @@ -358,22 +364,25 @@ pub(crate) fn undefined_as_encoded_string(_tag: u16, e: &TagValue) -> Option { - Some(if v.len() < 8 { - format!("String w/ truncated preamble {}", NumArray::new(v)) - } else if v[0..8] == ASC[..] { - String::from_utf8_lossy(&v[8..]).into_owned() - } else if v[0..8] == JIS[..] { - format!("JIS string {}", NumArray::new(&v[8..])) - } else if v[0..8] == UNICODE[..] { - let v8 = &v[8..]; - // reinterpret as vector of u16 - let v16_size = (v8.len() / 2) as u32; - let v16 = read_u16_array(le, v16_size, v8)?; - String::from_utf16_lossy(&v16) - } else { - format!("String w/ undefined encoding {}", NumArray::new(v)) - }.into()) - }, + Some( + if v.len() < 8 { + format!("String w/ truncated preamble {}", NumArray::new(v)) + } else if v[0..8] == ASC[..] { + String::from_utf8_lossy(&v[8..]).into_owned() + } else if v[0..8] == JIS[..] { + format!("JIS string {}", NumArray::new(&v[8..])) + } else if v[0..8] == UNICODE[..] { + let v8 = &v[8..]; + // reinterpret as vector of u16 + let v16_size = (v8.len() / 2) as u32; + let v16 = read_u16_array(le, v16_size, v8)?; + String::from_utf16_lossy(&v16) + } else { + format!("String w/ undefined encoding {}", NumArray::new(v)) + } + .into(), + ) + } _ => None, } } @@ -404,12 +413,14 @@ pub(crate) fn apex_brightness(_tag: u16, e: &TagValue) -> Option { // numerator 0xffffffff = unknown - Some(if v.first()?.numerator == -1 { - "Unknown".into() - } else { - format!("{:.1} APEX", v.first()?.value()).into() - }) - }, + Some( + if v.first()?.numerator == -1 { + "Unknown".into() + } else { + format!("{:.1} APEX", v.first()?.value()).into() + }, + ) + } _ => None, } } @@ -423,13 +434,7 @@ pub(crate) fn apex_ev(_tag: u16, e: &TagValue) -> Option> { pub(crate) fn file_source(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::Undefined(ref v, _) => { - Some(if !v.is_empty() && v[0] == 3 { - "DSC" - } else { - "Unknown" - }.into()) - }, + TagValue::Undefined(ref v, _) => Some(if !v.is_empty() && v[0] == 3 { "DSC" } else { "Unknown" }.into()), _ => None, } } @@ -443,8 +448,8 @@ pub(crate) fn flash_energy(_tag: u16, e: &TagValue) -> Option> pub(crate) fn metering_mode(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Unknown", 1 => "Average", 2 => "Center-weighted average", @@ -454,16 +459,17 @@ pub(crate) fn metering_mode(tag: u16, e: &TagValue) -> Option> 6 => "Partial", 255 => "Other", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn light_source(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Unknown", 1 => "Daylight", 2 => "Fluorescent", @@ -486,21 +492,23 @@ pub(crate) fn light_source(tag: u16, e: &TagValue) -> Option> 24 => "ISO studio tungsten", 255 => "Other", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn color_space(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 1 => "sRGB", 65535 => "Uncalibrated", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } @@ -546,22 +554,22 @@ pub(crate) fn flash(_tag: u16, e: &TagValue) -> Option> { } Some(format!("{b0}{b12}{b34}{b6}").into()) - }, + } _ => None, } } pub(crate) fn subject_area(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => Some(match v.len() { - 2 => format!("at pixel {},{}", v[0], v[1]), - 3 => format!("at center {},{} radius {}", v[0], v[1], v[2]), - 4 => format!( - "at rectangle {},{} width {} height {}", - v[0], v[1], v[2], v[3] - ), - _ => format!("Unknown ({}) ", NumArray::new(v)), - }.into()), + TagValue::U16(ref v) => Some( + match v.len() { + 2 => format!("at pixel {},{}", v[0], v[1]), + 3 => format!("at center {},{} radius {}", v[0], v[1], v[2]), + 4 => format!("at rectangle {},{} width {} height {}", v[0], v[1], v[2], v[3]), + _ => format!("Unknown ({}) ", NumArray::new(v)), + } + .into(), + ), _ => None, } } @@ -575,120 +583,128 @@ pub(crate) fn subject_location(_tag: u16, e: &TagValue) -> Option Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Normal", 1 => "Soft", 2 => "Hard", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn saturation(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Normal", 1 => "Low", 2 => "High", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn contrast(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Normal", 1 => "Soft", 2 => "Hard", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn gain_control(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "None", 1 => "Low gain up", 2 => "High gain up", 3 => "Low gain down", 4 => "High gain down", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn exposure_mode(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Auto exposure", 1 => "Manual exposure", 2 => "Auto bracket", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn scene_capture_type(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Standard", 1 => "Landscape", 2 => "Portrait", 3 => "Night scene", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn scene_type(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::Undefined(ref v, _) => { - Some(match v.first()? { + TagValue::Undefined(ref v, _) => Some( + match v.first()? { 1 => "Directly photographed image", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn white_balance_mode(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Auto", 1 => "Manual", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn sensing_method(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 1 => "Not defined", 2 => "One-chip color area sensor", 3 => "Two-chip color area sensor", @@ -697,36 +713,39 @@ pub(crate) fn sensing_method(tag: u16, e: &TagValue) -> Option 7 => "Trilinear sensor", 8 => "Color sequential linear sensor", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn custom_rendered(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Normal", 1 => "Custom", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } pub(crate) fn subject_distance_range(tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::U16(ref v) => { - Some(match v.first()? { + TagValue::U16(ref v) => Some( + match v.first()? { 0 => "Unknown", 1 => "Macro", 2 => "Close view", 3 => "Distant view", n => return Some(format!("Unknown ({tag:04x}={n})").into()), - }.into()) - }, + } + .into(), + ), _ => None, } } @@ -739,18 +758,21 @@ pub(crate) fn lens_spec(_tag: u16, e: &TagValue) -> Option> { let a0 = v[2].value(); let a1 = v[3].value(); - Some(if v[0] == v[1] { - if a0.is_finite() { - format!("{f0} mm f/{a0:.1}") + Some( + if v[0] == v[1] { + if a0.is_finite() { + format!("{f0} mm f/{a0:.1}") + } else { + format!("{f0} mm f/unknown") + } + } else if a0.is_finite() && a1.is_finite() { + format!("{f0}-{f1} mm f/{a0:.1}-{a1:.1}") } else { - format!("{f0} mm f/unknown") + format!("{f0}-{f1} mm f/unknown") } - } else if a0.is_finite() && a1.is_finite() { - format!("{f0}-{f1} mm f/{a0:.1}-{a1:.1}") - } else { - format!("{f0}-{f1} mm f/unknown") - }.into()) - }, + .into(), + ) + } _ => None, } } diff --git a/src/ifdformat.rs b/src/ifdformat.rs index 8d6bfd1..79840fd 100644 --- a/src/ifdformat.rs +++ b/src/ifdformat.rs @@ -44,54 +44,54 @@ pub(crate) fn tag_value_new(f: &IfdEntry) -> Option { let s = String::from_utf8_lossy(data); let s = s.into_owned(); TagValue::Ascii(s) - }, + } IfdFormat::U16 => { let a = read_u16_array(f.le, f.count, &f.data)?; TagValue::U16(a) - }, + } IfdFormat::I16 => { let a = read_i16_array(f.le, f.count, &f.data)?; TagValue::I16(a) - }, + } IfdFormat::U8 => { if f.data.len() < f.count as usize { return None; } TagValue::U8(f.data.clone()) - }, + } IfdFormat::I8 => { let a = read_i8_array(f.count, &f.data)?; TagValue::I8(a) - }, + } IfdFormat::U32 => { let a = read_u32_array(f.le, f.count, &f.data)?; TagValue::U32(a) - }, + } IfdFormat::I32 => { let a = read_i32_array(f.le, f.count, &f.data)?; TagValue::I32(a) - }, + } IfdFormat::F32 => { let a = read_f32_array(f.count, &f.data)?; TagValue::F32(a) - }, + } IfdFormat::F64 => { let a = read_f64_array(f.count, &f.data)?; TagValue::F64(a) - }, + } IfdFormat::URational => { let a = read_urational_array(f.le, f.count, &f.data)?; TagValue::URational(a) - }, + } IfdFormat::IRational => { let a = read_irational_array(f.le, f.count, &f.data)?; TagValue::IRational(a) - }, + } IfdFormat::Undefined => { let a = f.data.clone(); TagValue::Undefined(a, f.le) - }, + } _ => TagValue::Unknown(f.data.clone(), f.le), }) } diff --git a/src/image.rs b/src/image.rs index 61ef46d..4891c49 100644 --- a/src/image.rs +++ b/src/image.rs @@ -73,7 +73,9 @@ pub fn find_embedded_tiff_in_jpeg(contents: &[u8]) -> Result<(usize, usize), Exi let size = (contents[offset] as usize) * 256 + (contents[offset + 1] as usize); if size < 2 { - return Err(ExifError::JpegWithoutExif("JPEG marker size must be at least 2 (because of the size word)".into())); + return Err(ExifError::JpegWithoutExif( + "JPEG marker size must be at least 2 (because of the size word)".into(), + )); } if contents.len() < (offset + size) { return Err(ExifError::JpegWithoutExif("JPEG truncated in marker body".into())); diff --git a/src/lib.rs b/src/lib.rs index 58a211d..1886f47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,21 +75,16 @@ pub fn parse_buffer_quiet(contents: &[u8]) -> (ExifResult, Vec) { FileType::Unknown => return (Err(ExifError::FileTypeUnknown), warnings), FileType::TIFF => parse_tiff(contents, &mut warnings), FileType::JPEG => { - match find_embedded_tiff_in_jpeg(contents).map(|(offset, size)| parse_tiff(&contents[offset..offset + size], &mut warnings)) { + match find_embedded_tiff_in_jpeg(contents) + .map(|(offset, size)| parse_tiff(&contents[offset..offset + size], &mut warnings)) + { Ok(r) => r, Err(e) => return (Err(e), warnings), } } }; - ( - entries.map(|entries| ExifData { - mime: mime.as_str(), - entries, - le, - }), - warnings, - ) + (entries.map(|entries| ExifData { mime: mime.as_str(), entries, le }), warnings) } /// Try to read and parse an open file that is expected to contain an image diff --git a/src/lowlevel.rs b/src/lowlevel.rs index 275bdb4..668b981 100644 --- a/src/lowlevel.rs +++ b/src/lowlevel.rs @@ -5,44 +5,28 @@ use std::convert::TryInto; #[inline(always)] pub(crate) fn read_u16(le: bool, raw: &[u8]) -> Option { let bytes = raw.get(..2)?.try_into().ok()?; - Some(if le { - u16::from_le_bytes(bytes) - } else { - u16::from_be_bytes(bytes) - }) + Some(if le { u16::from_le_bytes(bytes) } else { u16::from_be_bytes(bytes) }) } /// Read value from a stream of bytes #[inline(always)] pub(crate) fn read_i16(le: bool, raw: &[u8]) -> Option { let bytes = raw.get(..2)?.try_into().ok()?; - Some(if le { - i16::from_le_bytes(bytes) - } else { - i16::from_be_bytes(bytes) - }) + Some(if le { i16::from_le_bytes(bytes) } else { i16::from_be_bytes(bytes) }) } /// Read value from a stream of bytes #[inline(always)] pub(crate) fn read_u32(le: bool, raw: &[u8]) -> Option { let bytes = raw.get(..4)?.try_into().ok()?; - Some(if le { - u32::from_le_bytes(bytes) - } else { - u32::from_be_bytes(bytes) - }) + Some(if le { u32::from_le_bytes(bytes) } else { u32::from_be_bytes(bytes) }) } /// Read value from a stream of bytes #[inline(always)] pub(crate) fn read_i32(le: bool, raw: &[u8]) -> Option { let bytes = raw.get(..4)?.try_into().ok()?; - Some(if le { - i32::from_le_bytes(bytes) - } else { - i32::from_be_bytes(bytes) - }) + Some(if le { i32::from_le_bytes(bytes) } else { i32::from_be_bytes(bytes) }) } /// Read value from a stream of bytes diff --git a/src/main.rs b/src/main.rs index 829be7a..b9753e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,10 +23,10 @@ fn main() { println!("\t{}: {}", entry.tag, entry.value_more_readable); } } - }, + } Err(e) => { eprintln!("Error in {}: {}", &arg, e); - }, + } } } } diff --git a/src/tiff.rs b/src/tiff.rs index bc48ca8..f5926cc 100644 --- a/src/tiff.rs +++ b/src/tiff.rs @@ -38,9 +38,7 @@ pub(crate) fn parse_exif_entry(ifd: IfdEntry, warnings: &mut Vec, kind: // 3) Str type must not have a definite length if (((tag as u32) & 0xffff) as u16) != e.ifd.tag || (min_count == -1 - && (format != IfdFormat::Ascii - && format != IfdFormat::Undefined - && format != IfdFormat::Unknown)) + && (format != IfdFormat::Ascii && format != IfdFormat::Undefined && format != IfdFormat::Unknown)) || (min_count != -1 && format == IfdFormat::Ascii) { panic!("Internal error {:x}", e.ifd.tag); @@ -63,12 +61,7 @@ pub(crate) fn parse_exif_entry(ifd: IfdEntry, warnings: &mut Vec, kind: } /// Superficial parse of IFD that can't fail -pub fn parse_ifd( - subifd: bool, - le: bool, - count: u16, - contents: &[u8] -) -> Option<(Vec, usize)> { +pub fn parse_ifd(subifd: bool, le: bool, count: u16, contents: &[u8]) -> Option<(Vec, usize)> { let mut entries: Vec = Vec::new(); for i in 0..count { @@ -94,11 +87,7 @@ pub fn parse_ifd( entries.push(entry); } - let next_ifd = if subifd { - 0 - } else { - read_u32(le, &contents[count as usize * 12..])? as usize - }; + let next_ifd = if subifd { 0 } else { read_u32(le, &contents[count as usize * 12..])? as usize }; Some((entries, next_ifd)) } @@ -115,17 +104,15 @@ fn parse_exif_ifd( let mut offset = ioffset; if contents.len() < (offset + 2) { - return Err(ExifError::ExifIfdTruncated( - format!("Truncated {:?} at dir entry count ({} < {})", kind, contents.len(), (offset + 2)), - )); + return Err(ExifError::ExifIfdTruncated(format!( + "Truncated {:?} at dir entry count ({} < {})", + kind, + contents.len(), + (offset + 2) + ))); } - let count = read_u16( - le, - contents - .get(offset..) - .ok_or(ExifError::IfdTruncated)?, - ).ok_or(ExifError::IfdTruncated)?; + let count = read_u16(le, contents.get(offset..).ok_or(ExifError::IfdTruncated)?).ok_or(ExifError::IfdTruncated)?; let ifd_length = (count as usize) * 12; offset += 2; @@ -133,9 +120,7 @@ fn parse_exif_ifd( return Err(ExifError::ExifIfdTruncated("Truncated at dir listing".into())); } - let ifd_content = &contents - .get(offset..offset + ifd_length) - .ok_or(ExifError::IfdTruncated)?; + let ifd_content = &contents.get(offset..offset + ifd_length).ok_or(ExifError::IfdTruncated)?; let (ifd, _) = parse_ifd(true, le, count, ifd_content).ok_or(ExifError::IfdTruncated)?; for mut entry in ifd { @@ -151,12 +136,7 @@ fn parse_exif_ifd( } /// Parses IFD0 and looks for `SubIFD` or GPS IFD within IFD0 -pub fn parse_ifds( - le: bool, - ifd0_offset: usize, - contents: &[u8], - warnings: &mut Vec, -) -> ExifEntryResult { +pub fn parse_ifds(le: bool, ifd0_offset: usize, contents: &[u8], warnings: &mut Vec) -> ExifEntryResult { let mut offset = ifd0_offset; let mut exif_entries: Vec = Vec::new(); @@ -170,18 +150,12 @@ pub fn parse_ifds( // at this point we knot that IFD0 is good // looks for SubIFD (EXIF) - let count = read_u16( - le, - contents - .get(offset..offset + 2) - .ok_or(ExifError::IfdTruncated)?, - ).ok_or(ExifError::IfdTruncated)?; + let count = read_u16(le, contents.get(offset..offset + 2).ok_or(ExifError::IfdTruncated)?) + .ok_or(ExifError::IfdTruncated)?; let ifd_length = (count as usize) * 12 + 4; offset += 2; - let ifd_content = &contents - .get(offset..offset + ifd_length) - .ok_or(ExifError::IfdTruncated)?; + let ifd_content = &contents.get(offset..offset + ifd_length).ok_or(ExifError::IfdTruncated)?; let (ifd, _) = parse_ifd(false, le, count, ifd_content).ok_or(ExifError::IfdTruncated)?; for entry in &ifd { diff --git a/src/types.rs b/src/types.rs index ae31b7f..226af0e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -34,11 +34,7 @@ impl ExifData { /// through the `le` attribute). pub fn serialize(&self) -> Result, ExifError> { // Select the right TIFF header based on the endianness. - let tiff_header = if self.le { - INTEL_TIFF_HEADER - } else { - MOTOROLA_TIFF_HEADER - }; + let tiff_header = if self.le { INTEL_TIFF_HEADER } else { MOTOROLA_TIFF_HEADER }; // The result buffer. let mut serialized = vec![]; @@ -68,7 +64,7 @@ impl ExifData { IfdKind::Gps => gps.push(e), _ => { // XXX Silently ignore Makernote and Interoperability IFDs - }, + } } } @@ -119,11 +115,8 @@ impl ExifData { // Patch the offsets serialized above. for patch in &data_patches { // The position of the data pointed to by the IFD entries serialized above. - let bytes = if self.le { - (serialized.len() as u32).to_le_bytes() - } else { - (serialized.len() as u32).to_be_bytes() - }; + let bytes = + if self.le { (serialized.len() as u32).to_le_bytes() } else { (serialized.len() as u32).to_be_bytes() }; serialized.extend(patch.data); for (place, byte) in serialized.iter_mut().skip(patch.offset_pos as usize).zip(bytes.iter()) { @@ -141,11 +134,7 @@ impl ExifData { // TODO Makernote, Interoperability IFD, Thumbnail image - Ok(if self.mime == "image/jpeg" { - [EXIF_HEADER, &serialized].concat() - } else { - serialized - }) + Ok(if self.mime == "image/jpeg" { [EXIF_HEADER, &serialized].concat() } else { serialized }) } /// Serialize GPS/Exif IFD entries. @@ -155,11 +144,8 @@ impl ExifData { entries: Vec<&ExifEntry>, pos: Option, ) -> Result<(), ExifError> { - let bytes = if self.le { - (serialized.len() as u32).to_le_bytes() - } else { - (serialized.len() as u32).to_be_bytes() - }; + let bytes = + if self.le { (serialized.len() as u32).to_le_bytes() } else { (serialized.len() as u32).to_be_bytes() }; // Serialize the number of directory entries in this IFD if self.le { @@ -183,11 +169,8 @@ impl ExifData { serialized.extend(&[0, 0, 0, 0]); for patch in &data_patches { // The position of the data pointed to by the IFD entries serialized above. - let bytes = if self.le { - (serialized.len() as u32).to_le_bytes() - } else { - (serialized.len() as u32).to_be_bytes() - }; + let bytes = + if self.le { (serialized.len() as u32).to_le_bytes() } else { (serialized.len() as u32).to_be_bytes() }; serialized.extend(patch.data); for (place, byte) in serialized.iter_mut().skip(patch.offset_pos as usize).zip(bytes.iter()) { *place = *byte; @@ -207,10 +190,7 @@ pub(super) struct Patch<'a> { impl Patch<'_> { #[must_use] pub const fn new(offset_pos: u32, data: &[u8]) -> Patch { - Patch { - offset_pos, - data, - } + Patch { offset_pos, data } } } @@ -264,14 +244,18 @@ pub struct IfdEntry { // entries should still be considered equal. impl PartialEq for IfdEntry { fn eq(&self, other: &Self) -> bool { - let data_eq = if self.in_ifd() && !self.tag == ExifTag::ExifOffset as u16 && !self.tag == ExifTag::GPSOffset as u16 { - self.data == other.data && self.ifd_data == other.ifd_data && self.ext_data == other.ext_data - } else { - true - }; + let data_eq = + if self.in_ifd() && !self.tag == ExifTag::ExifOffset as u16 && !self.tag == ExifTag::GPSOffset as u16 { + self.data == other.data && self.ifd_data == other.ifd_data && self.ext_data == other.ext_data + } else { + true + }; - self.namespace == other.namespace && self.tag == other.tag && self.count == other.count && - data_eq && self.le == other.le + self.namespace == other.namespace + && self.tag == other.tag + && self.count == other.count + && data_eq + && self.le == other.le } } @@ -625,13 +609,15 @@ impl PartialEq for ExifEntry { // Two entries can be equal even if they do not point to the same offset. let value_eq = match self.tag { ExifTag::ExifOffset | ExifTag::GPSOffset => true, - _ => { - self.value_more_readable == other.value_more_readable && tag_value_eq(&self.value, &other.value) - }, + _ => self.value_more_readable == other.value_more_readable && tag_value_eq(&self.value, &other.value), }; - self.namespace == other.namespace && self.ifd == other.ifd && self.tag == other.tag && - self.unit == other.unit && self.kind == other.kind && value_eq + self.namespace == other.namespace + && self.ifd == other.ifd + && self.tag == other.tag + && self.unit == other.unit + && self.kind == other.kind + && value_eq } } diff --git a/src/types_impl.rs b/src/types_impl.rs index a8104e2..bff7faa 100644 --- a/src/types_impl.rs +++ b/src/types_impl.rs @@ -114,8 +114,7 @@ impl IfdEntry { } } -impl Error for ExifError { -} +impl Error for ExifError {} impl Display for ExifError { #[cold] diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 69fcf42..2d54950 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -36,8 +36,10 @@ fn test_parse_simple_morotola_jpeg() { ]; check_tags(&exif.entries, expected_tags); - assert!(exif.entries.iter().all(|e| e.namespace == Namespace::Standard), - "Expected all tags to be from the standard namespace"); + assert!( + exif.entries.iter().all(|e| e.namespace == Namespace::Standard), + "Expected all tags to be from the standard namespace" + ); } #[test] @@ -109,15 +111,10 @@ fn cmp_serialized_exif_with_original>(file: P) -> Result<(), std: #[test] fn test_jpeg_exif_serialization() -> Result<(), std::io::Error> { - let jpegs = glob( - Path::new(JPEG_TEST_DIR) - .join(JPEG_PATTERN) - .to_str() - .expect("Path is not valid unicode."), - ) - .expect("Failed to read glob pattern") - .filter_map(Result::ok) - .collect::>(); + let jpegs = glob(Path::new(JPEG_TEST_DIR).join(JPEG_PATTERN).to_str().expect("Path is not valid unicode.")) + .expect("Failed to read glob pattern") + .filter_map(Result::ok) + .collect::>(); for jpeg in jpegs { cmp_serialized_exif_with_original(&jpeg)?; @@ -128,15 +125,10 @@ fn test_jpeg_exif_serialization() -> Result<(), std::io::Error> { #[test] fn test_tiff_exif_serialization() -> Result<(), std::io::Error> { - let tiffs = glob( - Path::new(TIFF_TEST_DIR) - .join(TIFF_PATTERN) - .to_str() - .expect("Path is not valid unicode."), - ) - .expect("Failed to read glob pattern") - .filter_map(Result::ok) - .collect::>(); + let tiffs = glob(Path::new(TIFF_TEST_DIR).join(TIFF_PATTERN).to_str().expect("Path is not valid unicode.")) + .expect("Failed to read glob pattern") + .filter_map(Result::ok) + .collect::>(); for tiff in tiffs { cmp_serialized_exif_with_original(&tiff)?; From eaecc359813afaf7aaeb7dd2781027bcd58cbee7 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Thu, 5 Dec 2024 06:51:02 +0800 Subject: [PATCH 2/2] Use imports in exif.rs to allow width 100 --- .rustfmt.toml | 2 +- src/exif.rs | 209 +++++++++++++++++++------------------- src/exifpost.rs | 17 +++- src/exifreadable.rs | 13 ++- src/lowlevel.rs | 7 +- src/tiff.rs | 35 +++++-- src/types.rs | 50 ++++++--- src/types_impl.rs | 8 +- tests/integration_test.rs | 20 ++-- 9 files changed, 218 insertions(+), 143 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index b981b97..2dcb397 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,3 +1,3 @@ -max_width = 120 +max_width = 100 use_small_heuristics = "Max" combine_control_expr = false diff --git a/src/exif.rs b/src/exif.rs index 82bf50c..30a35f7 100644 --- a/src/exif.rs +++ b/src/exif.rs @@ -1,6 +1,9 @@ +use std::borrow::Cow; + use super::exifreadable::*; use super::types::*; -use std::borrow::Cow; +use ExifTag::*; +use IfdFormat::{Ascii, URational, Undefined}; type ReadableFn = fn(u16, &TagValue) -> Option>; @@ -11,214 +14,214 @@ type ReadableFn = fn(u16, &TagValue) -> Option>; /// Returns (tag, unit, format, `min_count`, `max_count`, `more_readable`) pub(crate) fn tag_to_exif(f: u16) -> (ExifTag, &'static str, IfdFormat, i32, i32, ReadableFn) { match f { - 0x010e => (ExifTag::ImageDescription, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x010e => (ImageDescription, "none", Ascii, -1i32, -1i32, strpass), - 0x010f => (ExifTag::Make, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x010f => (Make, "none", Ascii, -1i32, -1i32, strpass), - 0x013c => (ExifTag::HostComputer, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x013c => (HostComputer, "none", Ascii, -1i32, -1i32, strpass), - 0x0110 => (ExifTag::Model, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x0110 => (Model, "none", Ascii, -1i32, -1i32, strpass), - 0x0112 => (ExifTag::Orientation, "none", IfdFormat::U16, 1, 1, orientation), + 0x0112 => (Orientation, "none", IfdFormat::U16, 1, 1, orientation), - 0x011a => (ExifTag::XResolution, "pixels per res unit", IfdFormat::URational, 1, 1, rational_value), + 0x011a => (XResolution, "pixels per res unit", URational, 1, 1, rational_value), - 0x011b => (ExifTag::YResolution, "pixels per res unit", IfdFormat::URational, 1, 1, rational_value), + 0x011b => (YResolution, "pixels per res unit", URational, 1, 1, rational_value), - 0x0128 => (ExifTag::ResolutionUnit, "none", IfdFormat::U16, 1, 1, resolution_unit), + 0x0128 => (ResolutionUnit, "none", IfdFormat::U16, 1, 1, resolution_unit), - 0x0131 => (ExifTag::Software, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x0131 => (Software, "none", Ascii, -1i32, -1i32, strpass), - 0x0132 => (ExifTag::DateTime, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x0132 => (DateTime, "none", Ascii, -1i32, -1i32, strpass), - 0x013e => (ExifTag::WhitePoint, "CIE 1931 coordinates", IfdFormat::URational, 2, 2, rational_values), + 0x013e => (WhitePoint, "CIE 1931 coordinates", URational, 2, 2, rational_values), - 0x013f => (ExifTag::PrimaryChromaticities, "CIE 1931 coordinates", IfdFormat::URational, 6, 6, rational_values), + 0x013f => (PrimaryChromaticities, "CIE 1931 coordinates", URational, 6, 6, rational_values), - 0x0211 => (ExifTag::YCbCrCoefficients, "none", IfdFormat::URational, 3, 3, rational_values), + 0x0211 => (YCbCrCoefficients, "none", URational, 3, 3, rational_values), - 0x0214 => (ExifTag::ReferenceBlackWhite, "RGB or YCbCr", IfdFormat::URational, 6, 6, rational_values), + 0x0214 => (ReferenceBlackWhite, "RGB or YCbCr", URational, 6, 6, rational_values), - 0x8298 => (ExifTag::Copyright, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x8298 => (Copyright, "none", Ascii, -1i32, -1i32, strpass), - 0x8769 => (ExifTag::ExifOffset, "byte offset", IfdFormat::U32, 1, 1, strpass), + 0x8769 => (ExifOffset, "byte offset", IfdFormat::U32, 1, 1, strpass), - 0x8825 => (ExifTag::GPSOffset, "byte offset", IfdFormat::U32, 1, 1, strpass), + 0x8825 => (GPSOffset, "byte offset", IfdFormat::U32, 1, 1, strpass), - 0x829a => (ExifTag::ExposureTime, "s", IfdFormat::URational, 1, 1, exposure_time), + 0x829a => (ExposureTime, "s", URational, 1, 1, exposure_time), - 0x829d => (ExifTag::FNumber, "f-number", IfdFormat::URational, 1, 1, f_number), + 0x829d => (FNumber, "f-number", URational, 1, 1, f_number), - 0x8822 => (ExifTag::ExposureProgram, "none", IfdFormat::U16, 1, 1, exposure_program), + 0x8822 => (ExposureProgram, "none", IfdFormat::U16, 1, 1, exposure_program), - 0x8824 => (ExifTag::SpectralSensitivity, "ASTM string", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x8824 => (SpectralSensitivity, "ASTM string", Ascii, -1i32, -1i32, strpass), - 0x8830 => (ExifTag::SensitivityType, "none", IfdFormat::U16, 1, 1, sensitivity_type), + 0x8830 => (SensitivityType, "none", IfdFormat::U16, 1, 1, sensitivity_type), - 0x8827 => (ExifTag::ISOSpeedRatings, "ISO", IfdFormat::U16, 1, 3, iso_speeds), + 0x8827 => (ISOSpeedRatings, "ISO", IfdFormat::U16, 1, 3, iso_speeds), - 0x8828 => (ExifTag::OECF, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), + 0x8828 => (OECF, "none", Undefined, -1i32, -1i32, undefined_as_blob), - 0x9000 => (ExifTag::ExifVersion, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_ascii), + 0x9000 => (ExifVersion, "none", Undefined, -1i32, -1i32, undefined_as_ascii), - 0x9003 => (ExifTag::DateTimeOriginal, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x9003 => (DateTimeOriginal, "none", Ascii, -1i32, -1i32, strpass), - 0x9004 => (ExifTag::DateTimeDigitized, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x9004 => (DateTimeDigitized, "none", Ascii, -1i32, -1i32, strpass), - 0x9201 => (ExifTag::ShutterSpeedValue, "APEX", IfdFormat::IRational, 1, 1, apex_tv), + 0x9201 => (ShutterSpeedValue, "APEX", IfdFormat::IRational, 1, 1, apex_tv), - 0x9202 => (ExifTag::ApertureValue, "APEX", IfdFormat::URational, 1, 1, apex_av), + 0x9202 => (ApertureValue, "APEX", URational, 1, 1, apex_av), - 0x9203 => (ExifTag::BrightnessValue, "APEX", IfdFormat::IRational, 1, 1, apex_brightness), + 0x9203 => (BrightnessValue, "APEX", IfdFormat::IRational, 1, 1, apex_brightness), - 0x9204 => (ExifTag::ExposureBiasValue, "APEX", IfdFormat::IRational, 1, 1, apex_ev), + 0x9204 => (ExposureBiasValue, "APEX", IfdFormat::IRational, 1, 1, apex_ev), - 0x9205 => (ExifTag::MaxApertureValue, "APEX", IfdFormat::URational, 1, 1, apex_av), + 0x9205 => (MaxApertureValue, "APEX", URational, 1, 1, apex_av), - 0x9206 => (ExifTag::SubjectDistance, "m", IfdFormat::URational, 1, 1, meters), + 0x9206 => (SubjectDistance, "m", URational, 1, 1, meters), - 0x9207 => (ExifTag::MeteringMode, "none", IfdFormat::U16, 1, 1, metering_mode), + 0x9207 => (MeteringMode, "none", IfdFormat::U16, 1, 1, metering_mode), - 0x9208 => (ExifTag::LightSource, "none", IfdFormat::U16, 1, 1, light_source), + 0x9208 => (LightSource, "none", IfdFormat::U16, 1, 1, light_source), - 0x9209 => (ExifTag::Flash, "none", IfdFormat::U16, 1, 2, flash), + 0x9209 => (Flash, "none", IfdFormat::U16, 1, 2, flash), - 0x920a => (ExifTag::FocalLength, "mm", IfdFormat::URational, 1, 1, focal_length), + 0x920a => (FocalLength, "mm", URational, 1, 1, focal_length), - 0x9214 => (ExifTag::SubjectArea, "px", IfdFormat::U16, 2, 4, subject_area), + 0x9214 => (SubjectArea, "px", IfdFormat::U16, 2, 4, subject_area), - 0x927c => (ExifTag::MakerNote, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), + 0x927c => (MakerNote, "none", Undefined, -1i32, -1i32, undefined_as_blob), - 0x9286 => (ExifTag::UserComment, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), + 0x9286 => (UserComment, "none", Undefined, -1i32, -1i32, undefined_as_encoded_string), - 0xa000 => (ExifTag::FlashPixVersion, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_ascii), + 0xa000 => (FlashPixVersion, "none", Undefined, -1i32, -1i32, undefined_as_ascii), - 0xa001 => (ExifTag::ColorSpace, "none", IfdFormat::U16, 1, 1, color_space), + 0xa001 => (ColorSpace, "none", IfdFormat::U16, 1, 1, color_space), - 0xa004 => (ExifTag::RelatedSoundFile, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0xa004 => (RelatedSoundFile, "none", Ascii, -1i32, -1i32, strpass), - 0xa20b => (ExifTag::FlashEnergy, "BCPS", IfdFormat::URational, 1, 1, flash_energy), + 0xa20b => (FlashEnergy, "BCPS", URational, 1, 1, flash_energy), 0xa20e => { - (ExifTag::FocalPlaneXResolution, "@FocalPlaneResolutionUnit", IfdFormat::URational, 1, 1, rational_value) + (FocalPlaneXResolution, "@FocalPlaneResolutionUnit", URational, 1, 1, rational_value) } 0xa20f => { - (ExifTag::FocalPlaneYResolution, "@FocalPlaneResolutionUnit", IfdFormat::URational, 1, 1, rational_value) + (FocalPlaneYResolution, "@FocalPlaneResolutionUnit", URational, 1, 1, rational_value) } - 0xa210 => (ExifTag::FocalPlaneResolutionUnit, "none", IfdFormat::U16, 1, 1, resolution_unit), + 0xa210 => (FocalPlaneResolutionUnit, "none", IfdFormat::U16, 1, 1, resolution_unit), - 0xa214 => (ExifTag::SubjectLocation, "X,Y", IfdFormat::U16, 2, 2, subject_location), + 0xa214 => (SubjectLocation, "X,Y", IfdFormat::U16, 2, 2, subject_location), // TODO check if rational as decimal value is the best for this one - 0xa215 => (ExifTag::ExposureIndex, "EI", IfdFormat::URational, 1, 1, rational_value), + 0xa215 => (ExposureIndex, "EI", URational, 1, 1, rational_value), - 0xa217 => (ExifTag::SensingMethod, "none", IfdFormat::U16, 1, 1, sensing_method), + 0xa217 => (SensingMethod, "none", IfdFormat::U16, 1, 1, sensing_method), - 0xa300 => (ExifTag::FileSource, "none", IfdFormat::Undefined, 1, 1, file_source), + 0xa300 => (FileSource, "none", Undefined, 1, 1, file_source), - 0xa301 => (ExifTag::SceneType, "none", IfdFormat::Undefined, 1, 1, scene_type), + 0xa301 => (SceneType, "none", Undefined, 1, 1, scene_type), - 0xa302 => (ExifTag::CFAPattern, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_u8), + 0xa302 => (CFAPattern, "none", Undefined, -1i32, -1i32, undefined_as_u8), - 0xa401 => (ExifTag::CustomRendered, "none", IfdFormat::U16, 1, 1, custom_rendered), + 0xa401 => (CustomRendered, "none", IfdFormat::U16, 1, 1, custom_rendered), - 0xa402 => (ExifTag::ExposureMode, "none", IfdFormat::U16, 1, 1, exposure_mode), + 0xa402 => (ExposureMode, "none", IfdFormat::U16, 1, 1, exposure_mode), - 0xa403 => (ExifTag::WhiteBalanceMode, "none", IfdFormat::U16, 1, 1, white_balance_mode), + 0xa403 => (WhiteBalanceMode, "none", IfdFormat::U16, 1, 1, white_balance_mode), - 0xa404 => (ExifTag::DigitalZoomRatio, "none", IfdFormat::URational, 1, 1, rational_value), + 0xa404 => (DigitalZoomRatio, "none", URational, 1, 1, rational_value), - 0xa405 => (ExifTag::FocalLengthIn35mmFilm, "mm", IfdFormat::U16, 1, 1, focal_length_35), + 0xa405 => (FocalLengthIn35mmFilm, "mm", IfdFormat::U16, 1, 1, focal_length_35), - 0xa406 => (ExifTag::SceneCaptureType, "none", IfdFormat::U16, 1, 1, scene_capture_type), + 0xa406 => (SceneCaptureType, "none", IfdFormat::U16, 1, 1, scene_capture_type), - 0xa407 => (ExifTag::GainControl, "none", IfdFormat::U16, 1, 1, gain_control), + 0xa407 => (GainControl, "none", IfdFormat::U16, 1, 1, gain_control), - 0xa408 => (ExifTag::Contrast, "none", IfdFormat::U16, 1, 1, contrast), + 0xa408 => (Contrast, "none", IfdFormat::U16, 1, 1, contrast), - 0xa409 => (ExifTag::Saturation, "none", IfdFormat::U16, 1, 1, saturation), + 0xa409 => (Saturation, "none", IfdFormat::U16, 1, 1, saturation), - 0xa40a => (ExifTag::Sharpness, "none", IfdFormat::U16, 1, 1, sharpness), + 0xa40a => (Sharpness, "none", IfdFormat::U16, 1, 1, sharpness), - 0xa432 => (ExifTag::LensSpecification, "none", IfdFormat::URational, 4, 4, lens_spec), + 0xa432 => (LensSpecification, "none", URational, 4, 4, lens_spec), - 0xa433 => (ExifTag::LensMake, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0xa433 => (LensMake, "none", Ascii, -1i32, -1i32, strpass), - 0xa434 => (ExifTag::LensModel, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0xa434 => (LensModel, "none", Ascii, -1i32, -1i32, strpass), - 0xa500 => (ExifTag::Gamma, "none", IfdFormat::URational, 1, 1, rational_value), + 0xa500 => (Gamma, "none", URational, 1, 1, rational_value), // collaborate if you have any idea how to interpret this - 0xa40b => (ExifTag::DeviceSettingDescription, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_blob), + 0xa40b => (DeviceSettingDescription, "none", Undefined, -1i32, -1i32, undefined_as_blob), - 0xa40c => (ExifTag::SubjectDistanceRange, "none", IfdFormat::U16, 1, 1, subject_distance_range), + 0xa40c => (SubjectDistanceRange, "none", IfdFormat::U16, 1, 1, subject_distance_range), - 0xa420 => (ExifTag::ImageUniqueID, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0xa420 => (ImageUniqueID, "none", Ascii, -1i32, -1i32, strpass), - 0x0 => (ExifTag::GPSVersionID, "none", IfdFormat::U8, 4, 4, strpass), + 0x0 => (GPSVersionID, "none", IfdFormat::U8, 4, 4, strpass), - 0x1 => (ExifTag::GPSLatitudeRef, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x1 => (GPSLatitudeRef, "none", Ascii, -1i32, -1i32, strpass), - 0x2 => (ExifTag::GPSLatitude, "D/M/S", IfdFormat::URational, 3, 3, dms), + 0x2 => (GPSLatitude, "D/M/S", URational, 3, 3, dms), - 0x3 => (ExifTag::GPSLongitudeRef, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x3 => (GPSLongitudeRef, "none", Ascii, -1i32, -1i32, strpass), - 0x4 => (ExifTag::GPSLongitude, "D/M/S", IfdFormat::URational, 3, 3, dms), + 0x4 => (GPSLongitude, "D/M/S", URational, 3, 3, dms), - 0x5 => (ExifTag::GPSAltitudeRef, "none", IfdFormat::U8, 1, 1, gps_alt_ref), + 0x5 => (GPSAltitudeRef, "none", IfdFormat::U8, 1, 1, gps_alt_ref), - 0x6 => (ExifTag::GPSAltitude, "m", IfdFormat::URational, 1, 1, meters), + 0x6 => (GPSAltitude, "m", URational, 1, 1, meters), - 0x7 => (ExifTag::GPSTimeStamp, "UTC time", IfdFormat::URational, 3, 3, gpstimestamp), + 0x7 => (GPSTimeStamp, "UTC time", URational, 3, 3, gpstimestamp), - 0x8 => (ExifTag::GPSSatellites, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x8 => (GPSSatellites, "none", Ascii, -1i32, -1i32, strpass), - 0x9 => (ExifTag::GPSStatus, "none", IfdFormat::Ascii, -1i32, -1i32, gpsstatus), + 0x9 => (GPSStatus, "none", Ascii, -1i32, -1i32, gpsstatus), - 0xa => (ExifTag::GPSMeasureMode, "none", IfdFormat::Ascii, -1i32, -1i32, gpsmeasuremode), + 0xa => (GPSMeasureMode, "none", Ascii, -1i32, -1i32, gpsmeasuremode), - 0xb => (ExifTag::GPSDOP, "none", IfdFormat::URational, 1, 1, rational_value), + 0xb => (GPSDOP, "none", URational, 1, 1, rational_value), - 0xc => (ExifTag::GPSSpeedRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsspeedref), + 0xc => (GPSSpeedRef, "none", Ascii, -1i32, -1i32, gpsspeedref), - 0xd => (ExifTag::GPSSpeed, "@GPSSpeedRef", IfdFormat::URational, 1, 1, gpsspeed), + 0xd => (GPSSpeed, "@GPSSpeedRef", URational, 1, 1, gpsspeed), - 0xe => (ExifTag::GPSTrackRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), + 0xe => (GPSTrackRef, "none", Ascii, -1i32, -1i32, gpsbearingref), - 0xf => (ExifTag::GPSTrack, "deg", IfdFormat::URational, 1, 1, gpsbearing), + 0xf => (GPSTrack, "deg", URational, 1, 1, gpsbearing), - 0x10 => (ExifTag::GPSImgDirectionRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), + 0x10 => (GPSImgDirectionRef, "none", Ascii, -1i32, -1i32, gpsbearingref), - 0x11 => (ExifTag::GPSImgDirection, "deg", IfdFormat::URational, 1, 1, gpsbearing), + 0x11 => (GPSImgDirection, "deg", URational, 1, 1, gpsbearing), - 0x12 => (ExifTag::GPSMapDatum, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x12 => (GPSMapDatum, "none", Ascii, -1i32, -1i32, strpass), - 0x13 => (ExifTag::GPSDestLatitudeRef, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x13 => (GPSDestLatitudeRef, "none", Ascii, -1i32, -1i32, strpass), - 0x14 => (ExifTag::GPSDestLatitude, "D/M/S", IfdFormat::URational, 3, 3, dms), + 0x14 => (GPSDestLatitude, "D/M/S", URational, 3, 3, dms), - 0x15 => (ExifTag::GPSDestLongitudeRef, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x15 => (GPSDestLongitudeRef, "none", Ascii, -1i32, -1i32, strpass), - 0x16 => (ExifTag::GPSDestLongitude, "D/M/S", IfdFormat::URational, 3, 3, dms), + 0x16 => (GPSDestLongitude, "D/M/S", URational, 3, 3, dms), - 0x17 => (ExifTag::GPSDestBearingRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsbearingref), + 0x17 => (GPSDestBearingRef, "none", Ascii, -1i32, -1i32, gpsbearingref), - 0x18 => (ExifTag::GPSDestBearing, "deg", IfdFormat::URational, 1, 1, gpsbearing), + 0x18 => (GPSDestBearing, "deg", URational, 1, 1, gpsbearing), - 0x19 => (ExifTag::GPSDestDistanceRef, "none", IfdFormat::Ascii, -1i32, -1i32, gpsdestdistanceref), + 0x19 => (GPSDestDistanceRef, "none", Ascii, -1i32, -1i32, gpsdestdistanceref), - 0x1a => (ExifTag::GPSDestDistance, "@GPSDestDistanceRef", IfdFormat::URational, 1, 1, gpsdestdistance), + 0x1a => (GPSDestDistance, "@GPSDestDistanceRef", URational, 1, 1, gpsdestdistance), - 0x1b => (ExifTag::GPSProcessingMethod, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), + 0x1b => (GPSProcessingMethod, "none", Undefined, -1i32, -1i32, undefined_as_encoded_string), - 0x1c => (ExifTag::GPSAreaInformation, "none", IfdFormat::Undefined, -1i32, -1i32, undefined_as_encoded_string), + 0x1c => (GPSAreaInformation, "none", Undefined, -1i32, -1i32, undefined_as_encoded_string), - 0x1d => (ExifTag::GPSDateStamp, "none", IfdFormat::Ascii, -1i32, -1i32, strpass), + 0x1d => (GPSDateStamp, "none", Ascii, -1i32, -1i32, strpass), - 0x1e => (ExifTag::GPSDifferential, "none", IfdFormat::U16, 1, 1, gpsdiff), + 0x1e => (GPSDifferential, "none", IfdFormat::U16, 1, 1, gpsdiff), - _ => (ExifTag::UnknownToMe, "Unknown unit", IfdFormat::Unknown, -1i32, -1i32, unknown), + _ => (UnknownToMe, "Unknown unit", IfdFormat::Unknown, -1i32, -1i32, unknown), } } diff --git a/src/exifpost.rs b/src/exifpost.rs index 5785bac..a474362 100644 --- a/src/exifpost.rs +++ b/src/exifpost.rs @@ -1,13 +1,24 @@ use super::types::{ExifEntry, ExifTag, TagValue}; /// Find a tag of given type -fn other_tag<'a>(tag: ExifTag, entries1: &'a [ExifEntry], entries2: &'a [ExifEntry]) -> Option<&'a ExifEntry> { - entries1.iter().find(|entry| entry.tag == tag).or_else(|| entries2.iter().find(|entry| entry.tag == tag)) +fn other_tag<'a>( + tag: ExifTag, + entries1: &'a [ExifEntry], + entries2: &'a [ExifEntry], +) -> Option<&'a ExifEntry> { + entries1 + .iter() + .find(|entry| entry.tag == tag) + .or_else(|| entries2.iter().find(|entry| entry.tag == tag)) } /// Does postprocessing in tags that depend on other tags to have a complete interpretation /// e.g. when the unit of a tag is annotated on another tag -pub(crate) fn exif_postprocessing(entry: &mut ExifEntry, entries1: &[ExifEntry], entries2: &[ExifEntry]) { +pub(crate) fn exif_postprocessing( + entry: &mut ExifEntry, + entries1: &[ExifEntry], + entries2: &[ExifEntry], +) { match entry.tag { ExifTag::XResolution | ExifTag::YResolution => { if let Some(f) = other_tag(ExifTag::ResolutionUnit, entries1, entries2) { diff --git a/src/exifreadable.rs b/src/exifreadable.rs index 79ef024..b07beda 100644 --- a/src/exifreadable.rs +++ b/src/exifreadable.rs @@ -67,7 +67,9 @@ pub(crate) fn rational_value(_tag: u16, e: &TagValue) -> Option Option> { match *e { - TagValue::URational(ref v) => Some(NumArray::new(v.iter().map(|&x| x.value())).to_string().into()), + TagValue::URational(ref v) => { + Some(NumArray::new(v.iter().map(|&x| x.value())).to_string().into()) + } _ => None, } } @@ -285,7 +287,10 @@ pub(crate) fn gpstimestamp(_tag: u16, e: &TagValue) -> Option> let sec = v.get(2)?; let hour = v.first()?; let min = v.get(1)?; - Some(format!("{:02.0}:{:02.0}:{:04.1} UTC", hour.value(), min.value(), sec.value()).into()) + Some( + format!("{:02.0}:{:02.0}:{:04.1} UTC", hour.value(), min.value(), sec.value()) + .into(), + ) } _ => None, } @@ -434,7 +439,9 @@ pub(crate) fn apex_ev(_tag: u16, e: &TagValue) -> Option> { pub(crate) fn file_source(_tag: u16, e: &TagValue) -> Option> { match *e { - TagValue::Undefined(ref v, _) => Some(if !v.is_empty() && v[0] == 3 { "DSC" } else { "Unknown" }.into()), + TagValue::Undefined(ref v, _) => { + Some(if !v.is_empty() && v[0] == 3 { "DSC" } else { "Unknown" }.into()) + } _ => None, } } diff --git a/src/lowlevel.rs b/src/lowlevel.rs index 668b981..3594461 100644 --- a/src/lowlevel.rs +++ b/src/lowlevel.rs @@ -58,7 +58,12 @@ pub(crate) fn read_irational(le: bool, raw: &[u8]) -> Option { } #[inline(always)] -fn read_elements(size: u8, count: u32, raw: &[u8], convert: impl Fn(&[u8]) -> T) -> Option> { +fn read_elements( + size: u8, + count: u32, + raw: &[u8], + convert: impl Fn(&[u8]) -> T, +) -> Option> { let count = count as usize; let size = size as usize; let byte_size = size.checked_mul(count)?; diff --git a/src/tiff.rs b/src/tiff.rs index f5926cc..962a8ef 100644 --- a/src/tiff.rs +++ b/src/tiff.rs @@ -10,7 +10,11 @@ type InExifResult = Result<(), ExifError>; /// Parse of raw IFD entry into EXIF data, if it is of a known type, and returns /// an `ExifEntry` object. If the tag is unknown, the enumeration is set to `UnknownToMe`, /// but the raw information of tag is still available in the ifd member. -pub(crate) fn parse_exif_entry(ifd: IfdEntry, warnings: &mut Vec, kind: IfdKind) -> ExifEntry { +pub(crate) fn parse_exif_entry( + ifd: IfdEntry, + warnings: &mut Vec, + kind: IfdKind, +) -> ExifEntry { let (tag, unit, format, min_count, max_count, more_readable) = tag_to_exif(ifd.tag); let value = match tag_value_new(&ifd) { Some(v) => v, @@ -38,7 +42,9 @@ pub(crate) fn parse_exif_entry(ifd: IfdEntry, warnings: &mut Vec, kind: // 3) Str type must not have a definite length if (((tag as u32) & 0xffff) as u16) != e.ifd.tag || (min_count == -1 - && (format != IfdFormat::Ascii && format != IfdFormat::Undefined && format != IfdFormat::Unknown)) + && (format != IfdFormat::Ascii + && format != IfdFormat::Undefined + && format != IfdFormat::Unknown)) || (min_count != -1 && format == IfdFormat::Ascii) { panic!("Internal error {:x}", e.ifd.tag); @@ -61,7 +67,12 @@ pub(crate) fn parse_exif_entry(ifd: IfdEntry, warnings: &mut Vec, kind: } /// Superficial parse of IFD that can't fail -pub fn parse_ifd(subifd: bool, le: bool, count: u16, contents: &[u8]) -> Option<(Vec, usize)> { +pub fn parse_ifd( + subifd: bool, + le: bool, + count: u16, + contents: &[u8], +) -> Option<(Vec, usize)> { let mut entries: Vec = Vec::new(); for i in 0..count { @@ -87,7 +98,8 @@ pub fn parse_ifd(subifd: bool, le: bool, count: u16, contents: &[u8]) -> Option< entries.push(entry); } - let next_ifd = if subifd { 0 } else { read_u32(le, &contents[count as usize * 12..])? as usize }; + let next_ifd = + if subifd { 0 } else { read_u32(le, &contents[count as usize * 12..])? as usize }; Some((entries, next_ifd)) } @@ -112,7 +124,8 @@ fn parse_exif_ifd( ))); } - let count = read_u16(le, contents.get(offset..).ok_or(ExifError::IfdTruncated)?).ok_or(ExifError::IfdTruncated)?; + let count = read_u16(le, contents.get(offset..).ok_or(ExifError::IfdTruncated)?) + .ok_or(ExifError::IfdTruncated)?; let ifd_length = (count as usize) * 12; offset += 2; @@ -136,7 +149,12 @@ fn parse_exif_ifd( } /// Parses IFD0 and looks for `SubIFD` or GPS IFD within IFD0 -pub fn parse_ifds(le: bool, ifd0_offset: usize, contents: &[u8], warnings: &mut Vec) -> ExifEntryResult { +pub fn parse_ifds( + le: bool, + ifd0_offset: usize, + contents: &[u8], + warnings: &mut Vec, +) -> ExifEntryResult { let mut offset = ifd0_offset; let mut exif_entries: Vec = Vec::new(); @@ -197,7 +215,10 @@ pub fn parse_tiff(contents: &[u8], warnings: &mut Vec) -> (ExifEntryResu } else if contents[0] == b'M' && contents[1] == b'M' && contents[2] == 0 && contents[3] == 42 { /* TIFF big-endian */ } else { - let err = format!("Preamble is {:x} {:x} {:x} {:x}", contents[0], contents[1], contents[2], contents[3]); + let err = format!( + "Preamble is {:x} {:x} {:x} {:x}", + contents[0], contents[1], contents[2], contents[3] + ); return (Err(ExifError::TiffBadPreamble(err)), false); } diff --git a/src/types.rs b/src/types.rs index 226af0e..cef331f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -115,11 +115,16 @@ impl ExifData { // Patch the offsets serialized above. for patch in &data_patches { // The position of the data pointed to by the IFD entries serialized above. - let bytes = - if self.le { (serialized.len() as u32).to_le_bytes() } else { (serialized.len() as u32).to_be_bytes() }; + let bytes = if self.le { + (serialized.len() as u32).to_le_bytes() + } else { + (serialized.len() as u32).to_be_bytes() + }; serialized.extend(patch.data); - for (place, byte) in serialized.iter_mut().skip(patch.offset_pos as usize).zip(bytes.iter()) { + for (place, byte) in + serialized.iter_mut().skip(patch.offset_pos as usize).zip(bytes.iter()) + { *place = *byte; } } @@ -144,8 +149,11 @@ impl ExifData { entries: Vec<&ExifEntry>, pos: Option, ) -> Result<(), ExifError> { - let bytes = - if self.le { (serialized.len() as u32).to_le_bytes() } else { (serialized.len() as u32).to_be_bytes() }; + let bytes = if self.le { + (serialized.len() as u32).to_le_bytes() + } else { + (serialized.len() as u32).to_be_bytes() + }; // Serialize the number of directory entries in this IFD if self.le { @@ -169,10 +177,15 @@ impl ExifData { serialized.extend(&[0, 0, 0, 0]); for patch in &data_patches { // The position of the data pointed to by the IFD entries serialized above. - let bytes = - if self.le { (serialized.len() as u32).to_le_bytes() } else { (serialized.len() as u32).to_be_bytes() }; + let bytes = if self.le { + (serialized.len() as u32).to_le_bytes() + } else { + (serialized.len() as u32).to_be_bytes() + }; serialized.extend(patch.data); - for (place, byte) in serialized.iter_mut().skip(patch.offset_pos as usize).zip(bytes.iter()) { + for (place, byte) in + serialized.iter_mut().skip(patch.offset_pos as usize).zip(bytes.iter()) + { *place = *byte; } } @@ -244,12 +257,16 @@ pub struct IfdEntry { // entries should still be considered equal. impl PartialEq for IfdEntry { fn eq(&self, other: &Self) -> bool { - let data_eq = - if self.in_ifd() && !self.tag == ExifTag::ExifOffset as u16 && !self.tag == ExifTag::GPSOffset as u16 { - self.data == other.data && self.ifd_data == other.ifd_data && self.ext_data == other.ext_data - } else { - true - }; + let data_eq = if self.in_ifd() + && !self.tag == ExifTag::ExifOffset as u16 + && !self.tag == ExifTag::GPSOffset as u16 + { + self.data == other.data + && self.ifd_data == other.ifd_data + && self.ext_data == other.ext_data + } else { + true + }; self.namespace == other.namespace && self.tag == other.tag @@ -609,7 +626,10 @@ impl PartialEq for ExifEntry { // Two entries can be equal even if they do not point to the same offset. let value_eq = match self.tag { ExifTag::ExifOffset | ExifTag::GPSOffset => true, - _ => self.value_more_readable == other.value_more_readable && tag_value_eq(&self.value, &other.value), + _ => { + self.value_more_readable == other.value_more_readable + && tag_value_eq(&self.value, &other.value) + } }; self.namespace == other.namespace diff --git a/src/types_impl.rs b/src/types_impl.rs index bff7faa..6e53909 100644 --- a/src/types_impl.rs +++ b/src/types_impl.rs @@ -128,8 +128,12 @@ impl Display for ExifError { ExifError::IfdTruncated => f.write_str("TIFF IFD truncated"), ExifError::ExifIfdTruncated(ref s) => write!(f, "TIFF Exif IFD truncated: {s}"), ExifError::ExifIfdEntryNotFound => f.write_str("TIFF Exif IFD not found"), - ExifError::UnsupportedNamespace => f.write_str("Only standar namespace can be serialized"), - ExifError::MissingExifOffset => f.write_str("Expected to have seen ExifOffset tagin IFD0"), + ExifError::UnsupportedNamespace => { + f.write_str("Only standar namespace can be serialized") + } + ExifError::MissingExifOffset => { + f.write_str("Expected to have seen ExifOffset tagin IFD0") + } } } } diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 2d54950..ac8cee1 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -111,10 +111,12 @@ fn cmp_serialized_exif_with_original>(file: P) -> Result<(), std: #[test] fn test_jpeg_exif_serialization() -> Result<(), std::io::Error> { - let jpegs = glob(Path::new(JPEG_TEST_DIR).join(JPEG_PATTERN).to_str().expect("Path is not valid unicode.")) - .expect("Failed to read glob pattern") - .filter_map(Result::ok) - .collect::>(); + let jpegs = glob( + Path::new(JPEG_TEST_DIR).join(JPEG_PATTERN).to_str().expect("Path is not valid unicode."), + ) + .expect("Failed to read glob pattern") + .filter_map(Result::ok) + .collect::>(); for jpeg in jpegs { cmp_serialized_exif_with_original(&jpeg)?; @@ -125,10 +127,12 @@ fn test_jpeg_exif_serialization() -> Result<(), std::io::Error> { #[test] fn test_tiff_exif_serialization() -> Result<(), std::io::Error> { - let tiffs = glob(Path::new(TIFF_TEST_DIR).join(TIFF_PATTERN).to_str().expect("Path is not valid unicode.")) - .expect("Failed to read glob pattern") - .filter_map(Result::ok) - .collect::>(); + let tiffs = glob( + Path::new(TIFF_TEST_DIR).join(TIFF_PATTERN).to_str().expect("Path is not valid unicode."), + ) + .expect("Failed to read glob pattern") + .filter_map(Result::ok) + .collect::>(); for tiff in tiffs { cmp_serialized_exif_with_original(&tiff)?;