diff --git a/Cargo.lock b/Cargo.lock index a8d8480b0..22cf68c77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1573,6 +1573,10 @@ dependencies = [ "craft-eps", "craft-idml", "craft-image-codecs", + "craft-kra", + "craft-ora", + "craft-pcraft-bundle", + "craft-raw", "craft-svg", "craft-zip", "serde", diff --git a/crates/file-formats/Cargo.toml b/crates/file-formats/Cargo.toml index e7321f502..afe7c6391 100644 --- a/crates/file-formats/Cargo.toml +++ b/crates/file-formats/Cargo.toml @@ -10,6 +10,10 @@ rust-version.workspace = true [dependencies] craft-eps = { workspace = true } craft-image-codecs = { workspace = true, optional = true } +craft-raw = { workspace = true, optional = true } +craft-ora = { workspace = true, optional = true } +craft-kra = { workspace = true, optional = true } +craft-pcraft-bundle = { workspace = true, optional = true } craft-idml = { workspace = true } craft-svg = { workspace = true } craft-zip = { workspace = true } @@ -25,14 +29,14 @@ heif = ["raster-codecs", "craft-image-codecs/heif"] avif = ["raster-codecs", "craft-image-codecs/avif"] pdf = [] svg = [] -ora = [] -kra = [] +ora = ["dep:craft-ora"] +kra = ["dep:craft-kra"] xcf = [] pdn = [] -raw = [] +raw = ["dep:craft-raw"] psd = [] affinity = [] -pcraft = [] +pcraft = ["dep:craft-pcraft-bundle"] ase = [] office = [] designcraft = [] diff --git a/crates/file-formats/src/lib.rs b/crates/file-formats/src/lib.rs index d10c22b46..c71d0ff41 100644 --- a/crates/file-formats/src/lib.rs +++ b/crates/file-formats/src/lib.rs @@ -201,7 +201,7 @@ impl Format { Self::Dicom => &["dcm", "dicom", "dc3"], Self::Iff => &["iff", "lbm", "ilbm"], Self::Ase => &["ase"], - Self::Psd => &["psd", "psb"], + Self::Psd => &["psd", "psb", "psdt"], Self::Affinity => &["afdesign", "afphoto", "afpub"], Self::Ora => &["ora"], Self::Kra => &["kra"], @@ -416,6 +416,20 @@ impl Format { /// Resolve a name and file bytes to a format. Strong signatures take precedence over /// extension hints. Only format-specific bounded probes and extension tables live here. pub fn detect(name: &str, bytes: &[u8]) -> Option { + // Container identifiers are stronger than generic ZIP signatures and filenames. The shared + // readers own their bounded, format-specific directory/mimetype probes. + #[cfg(feature = "pcraft")] + if craft_pcraft_bundle::is_pcraft_zip(bytes) { + return Some(Format::Pcraft); + } + #[cfg(feature = "ora")] + if craft_ora::is_ora(bytes) { + return Some(Format::Ora); + } + #[cfg(feature = "kra")] + if craft_kra::is_kra(bytes) { + return Some(Format::Kra); + } if craft_idml::is_idml(bytes) { return Some(Format::Idml); } @@ -448,6 +462,13 @@ pub fn detect(name: &str, bytes: &[u8]) -> Option { if bytes.starts_with(b"gimp xcf ") || gzipped_xcf(name, bytes) { return Some(Format::Xcf); } + // Several camera formats use TIFF containers. Ask the shared RAW parser before the generic + // raster signature so TIFF-based RAW files reach the RAW adapter, while ordinary TIFF files + // retain the raster classification. + #[cfg(feature = "raw")] + if craft_raw::probe(bytes).is_some() { + return Some(Format::Raw); + } if bytes.starts_with(b"\0\xffKA") { return Some(Format::Affinity); }