mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-14 22:42:46 +00:00
Add shared format capability catalog
This commit is contained in:
3 files changed
+391
-48
No files matched your search
Generated
+6
-5
@@ -1572,6 +1572,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"craft-eps",
|
||||
"craft-idml",
|
||||
"craft-image-codecs",
|
||||
"craft-svg",
|
||||
"craft-zip",
|
||||
"serde",
|
||||
@@ -4941,17 +4942,17 @@ version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65b27460c2c92b037f3f94c538ed9a3342f3fdf923606781629ccb35f82d042a"
|
||||
|
||||
[[package]]
|
||||
name = "indd"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/indd-utils?rev=7f3060e5bce78d21ea70e0d5eacb96edce15dfbe#7f3060e5bce78d21ea70e0d5eacb96edce15dfbe"
|
||||
|
||||
[[package]]
|
||||
name = "imgref"
|
||||
version = "1.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e44b0a4eaa4c82f441d50a963f2d5f05a787240aeee097597033e72accfd22f"
|
||||
|
||||
[[package]]
|
||||
name = "indd"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/indd-utils?rev=7f3060e5bce78d21ea70e0d5eacb96edce15dfbe#7f3060e5bce78d21ea70e0d5eacb96edce15dfbe"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.2"
|
||||
|
||||
@@ -9,11 +9,35 @@ rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
craft-eps = { workspace = true }
|
||||
craft-image-codecs = { workspace = true, optional = true }
|
||||
craft-idml = { workspace = true }
|
||||
craft-svg = { workspace = true }
|
||||
craft-zip = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# These flags report which shared parser/codec families a client builds. The application still
|
||||
# selects the corresponding shared crates in its dependency graph.
|
||||
raster-codecs = ["dep:craft-image-codecs"]
|
||||
heif = ["raster-codecs", "craft-image-codecs/heif"]
|
||||
avif = ["raster-codecs", "craft-image-codecs/avif"]
|
||||
pdf = []
|
||||
svg = []
|
||||
ora = []
|
||||
kra = []
|
||||
xcf = []
|
||||
pdn = []
|
||||
raw = []
|
||||
psd = []
|
||||
affinity = []
|
||||
pcraft = []
|
||||
ase = []
|
||||
office = []
|
||||
designcraft = []
|
||||
stencilcraft = []
|
||||
plotter = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
+361
-43
@@ -23,6 +23,22 @@ pub enum Format {
|
||||
Tiff,
|
||||
WebP,
|
||||
Heif,
|
||||
Tga,
|
||||
Ico,
|
||||
Pnm,
|
||||
Pcx,
|
||||
Xpm,
|
||||
Dds,
|
||||
Qoi,
|
||||
OpenExr,
|
||||
Hdr,
|
||||
Avif,
|
||||
Fits,
|
||||
Dpx,
|
||||
Jxl,
|
||||
Cineon,
|
||||
Dicom,
|
||||
Iff,
|
||||
Ase,
|
||||
Psd,
|
||||
Affinity,
|
||||
@@ -54,6 +70,349 @@ pub enum Format {
|
||||
StencilCraft,
|
||||
}
|
||||
|
||||
/// Availability of one operation in the current client's shared-format build.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Availability {
|
||||
/// The shared reader or writer is included in this build.
|
||||
Available,
|
||||
/// This format is known, but the corresponding shared operation is not implemented.
|
||||
Unsupported,
|
||||
/// The operation exists behind a Cargo feature that this client did not enable.
|
||||
BuildDisabled,
|
||||
}
|
||||
|
||||
/// Shared reader/writer capability and sequence behavior for a known format.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Capabilities {
|
||||
pub read: Availability,
|
||||
pub write: Availability,
|
||||
/// Input may contain multiple frames/pages that the shared reader can expose individually.
|
||||
pub multiple_frames: bool,
|
||||
/// This format can be opened as an ordered sequence of files by an application adapter.
|
||||
pub file_sequence: bool,
|
||||
}
|
||||
|
||||
const fn capability(feature: bool, read: bool, write: bool, multiple_frames: bool, file_sequence: bool) -> Capabilities {
|
||||
Capabilities { read: availability(feature, read), write: availability(feature, write), multiple_frames, file_sequence }
|
||||
}
|
||||
|
||||
const fn availability(feature: bool, supported: bool) -> Availability {
|
||||
if !supported {
|
||||
Availability::Unsupported
|
||||
} else if feature {
|
||||
Availability::Available
|
||||
} else {
|
||||
Availability::BuildDisabled
|
||||
}
|
||||
}
|
||||
|
||||
impl Format {
|
||||
/// Every known format, including formats whose reader or writer is not enabled in this build.
|
||||
pub const ALL: [Format; 56] = [
|
||||
Self::Pdf,
|
||||
Self::Eps,
|
||||
Self::PostScript,
|
||||
Self::Illustrator,
|
||||
Self::Dxf,
|
||||
Self::Svg,
|
||||
Self::Svgz,
|
||||
Self::Png,
|
||||
Self::Jpeg,
|
||||
Self::Bmp,
|
||||
Self::Gif,
|
||||
Self::Tiff,
|
||||
Self::WebP,
|
||||
Self::Heif,
|
||||
Self::Tga,
|
||||
Self::Ico,
|
||||
Self::Pnm,
|
||||
Self::Pcx,
|
||||
Self::Xpm,
|
||||
Self::Dds,
|
||||
Self::Qoi,
|
||||
Self::OpenExr,
|
||||
Self::Hdr,
|
||||
Self::Avif,
|
||||
Self::Fits,
|
||||
Self::Dpx,
|
||||
Self::Jxl,
|
||||
Self::Cineon,
|
||||
Self::Dicom,
|
||||
Self::Iff,
|
||||
Self::Ase,
|
||||
Self::Psd,
|
||||
Self::Affinity,
|
||||
Self::Ora,
|
||||
Self::Kra,
|
||||
Self::Xcf,
|
||||
Self::Pdn,
|
||||
Self::Raw,
|
||||
Self::Pcraft,
|
||||
Self::Idml,
|
||||
Self::DesignCraft,
|
||||
Self::DesignCraftJson,
|
||||
Self::Indd,
|
||||
Self::Docx,
|
||||
Self::LegacyDoc,
|
||||
Self::Rtf,
|
||||
Self::Xlsx,
|
||||
Self::TaggedText,
|
||||
Self::Pptx,
|
||||
Self::PlainText,
|
||||
Self::Csv,
|
||||
Self::Tsv,
|
||||
Self::LegacyExcel,
|
||||
Self::Studio,
|
||||
Self::StencilCraft,
|
||||
Self::Gcode,
|
||||
];
|
||||
|
||||
/// Known extensions in lowercase form, in preferred-output order.
|
||||
pub fn extensions(self) -> &'static [&'static str] {
|
||||
match self {
|
||||
Self::Pdf => &["pdf"],
|
||||
Self::Eps => &["eps"],
|
||||
Self::PostScript => &["ps"],
|
||||
Self::Illustrator => &["ai"],
|
||||
Self::Dxf => &["dxf"],
|
||||
Self::Svg => &["svg"],
|
||||
Self::Svgz => &["svgz"],
|
||||
Self::Png => &["png", "apng"],
|
||||
Self::Jpeg => &["jpg", "jpeg", "jpe", "jfif"],
|
||||
Self::Bmp => &["bmp", "dib"],
|
||||
Self::Gif => &["gif"],
|
||||
Self::Tiff => &["tif", "tiff"],
|
||||
Self::WebP => &["webp"],
|
||||
Self::Heif => &["heic", "heif", "hif"],
|
||||
Self::Tga => &["tga", "icb", "vda", "vst"],
|
||||
Self::Ico => &["ico"],
|
||||
Self::Pnm => &["pnm", "pbm", "pgm", "ppm", "pam", "pfm"],
|
||||
Self::Pcx => &["pcx"],
|
||||
Self::Xpm => &["xpm"],
|
||||
Self::Dds => &["dds"],
|
||||
Self::Qoi => &["qoi"],
|
||||
Self::OpenExr => &["exr"],
|
||||
Self::Hdr => &["hdr"],
|
||||
Self::Avif => &["avif"],
|
||||
Self::Fits => &["fits", "fit", "fts"],
|
||||
Self::Dpx => &["dpx"],
|
||||
Self::Jxl => &["jxl"],
|
||||
Self::Cineon => &["cin"],
|
||||
Self::Dicom => &["dcm", "dicom", "dc3"],
|
||||
Self::Iff => &["iff", "lbm", "ilbm"],
|
||||
Self::Ase => &["ase"],
|
||||
Self::Psd => &["psd", "psb"],
|
||||
Self::Affinity => &["afdesign", "afphoto", "afpub"],
|
||||
Self::Ora => &["ora"],
|
||||
Self::Kra => &["kra"],
|
||||
Self::Xcf => &["xcf"],
|
||||
Self::Pdn => &["pdn"],
|
||||
Self::Raw => &[
|
||||
"dng", "3fr", "ari", "arw", "bay", "cap", "cr2", "cr3", "dcs", "dcr", "drf", "eip", "erf", "fff", "gpr", "iiq", "k25", "kdc", "mdc",
|
||||
"mef", "mos", "mrw", "nef", "nrw", "obm", "orf", "pef", "ptx", "pxn", "r3d", "raf", "raw", "rwl", "rw2", "rwz", "sr2", "srf", "sti",
|
||||
"x3f",
|
||||
],
|
||||
Self::Pcraft => &["pcraft"],
|
||||
Self::Idml => &["idml"],
|
||||
Self::DesignCraft => &["designcraft", "dcdoc"],
|
||||
Self::DesignCraftJson => &[],
|
||||
Self::Indd => &["indd", "indt"],
|
||||
Self::Docx => &["docx"],
|
||||
Self::LegacyDoc => &["doc"],
|
||||
Self::Rtf => &["rtf"],
|
||||
Self::Xlsx => &["xlsx"],
|
||||
Self::TaggedText => &[],
|
||||
Self::Pptx => &["pptx"],
|
||||
Self::PlainText => &["txt", "text", "md"],
|
||||
Self::Csv => &["csv"],
|
||||
Self::Tsv => &["tsv", "tab"],
|
||||
Self::LegacyExcel => &["xls", "xlsm"],
|
||||
Self::Studio => &["studio", "studio3"],
|
||||
Self::StencilCraft => &["stencilcraft"],
|
||||
Self::Gcode => &["gcode", "nc"],
|
||||
}
|
||||
}
|
||||
|
||||
/// Preferred extension for creating a new file of this type, if one is defined.
|
||||
pub fn preferred_extension(self) -> Option<&'static str> {
|
||||
self.extensions().first().copied()
|
||||
}
|
||||
|
||||
/// Registered MIME type, where the format has a stable MIME registration.
|
||||
pub fn mime_type(self) -> Option<&'static str> {
|
||||
Some(match self {
|
||||
Self::Pdf => "application/pdf",
|
||||
Self::Eps => "application/postscript",
|
||||
Self::PostScript => "application/postscript",
|
||||
Self::Illustrator => "application/illustrator",
|
||||
Self::Dxf => "image/vnd.dxf",
|
||||
Self::Svg | Self::Svgz => "image/svg+xml",
|
||||
Self::Png => "image/png",
|
||||
Self::Jpeg => "image/jpeg",
|
||||
Self::Bmp => "image/bmp",
|
||||
Self::Gif => "image/gif",
|
||||
Self::Tiff => "image/tiff",
|
||||
Self::WebP => "image/webp",
|
||||
Self::Heif => "image/heif",
|
||||
Self::Tga => "image/x-tga",
|
||||
Self::Ico => "image/vnd.microsoft.icon",
|
||||
Self::Pnm => "image/x-portable-anymap",
|
||||
Self::Pcx => "image/vnd.zbrush.pcx",
|
||||
Self::Xpm => "image/x-xpixmap",
|
||||
Self::Dds => "image/vnd-ms.dds",
|
||||
Self::Qoi => "image/qoi",
|
||||
Self::OpenExr => "image/x-exr",
|
||||
Self::Hdr => "image/vnd.radiance",
|
||||
Self::Avif => "image/avif",
|
||||
Self::Fits => "image/fits",
|
||||
Self::Dpx => "image/dpx",
|
||||
Self::Jxl => "image/jxl",
|
||||
Self::Cineon => "image/x-cineon",
|
||||
Self::Dicom => "application/dicom",
|
||||
Self::Iff => "image/ilbm",
|
||||
Self::Ase => "application/x-adobe-swatch-exchange",
|
||||
Self::Psd => "image/vnd.adobe.photoshop",
|
||||
Self::Affinity => "application/x-affinity",
|
||||
Self::Ora => "image/openraster",
|
||||
Self::Kra => "application/x-krita",
|
||||
Self::Xcf => "image/x-xcf",
|
||||
Self::Pdn => "application/x-paint.net",
|
||||
Self::Raw => "image/x-camera-raw",
|
||||
Self::Pcraft => "application/vnd.photocraft+zip",
|
||||
Self::Idml => "application/vnd.adobe.indesign-idml-package",
|
||||
Self::DesignCraft => "application/vnd.designcraft+zip",
|
||||
Self::DesignCraftJson => "application/json",
|
||||
Self::Indd => "application/x-indesign",
|
||||
Self::Docx => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
Self::LegacyDoc => "application/msword",
|
||||
Self::Rtf => "application/rtf",
|
||||
Self::Xlsx => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
Self::TaggedText => "text/plain",
|
||||
Self::Pptx => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
Self::PlainText => "text/plain",
|
||||
Self::Csv => "text/csv",
|
||||
Self::Tsv => "text/tab-separated-values",
|
||||
Self::LegacyExcel => "application/vnd.ms-excel",
|
||||
Self::Studio => "application/x-silhouette-studio",
|
||||
Self::StencilCraft => "application/vnd.stencilcraft+json",
|
||||
Self::Gcode => "text/x.gcode",
|
||||
})
|
||||
}
|
||||
|
||||
/// The corresponding flat-raster codec, when this format is handled by `craft-image-codecs`.
|
||||
#[cfg(feature = "raster-codecs")]
|
||||
pub fn raster_codec(self) -> Option<craft_image_codecs::Format> {
|
||||
use craft_image_codecs::Format as Codec;
|
||||
Some(match self {
|
||||
Self::Png => Codec::Png,
|
||||
Self::Jpeg => Codec::Jpeg,
|
||||
Self::Bmp => Codec::Bmp,
|
||||
Self::Gif => Codec::Gif,
|
||||
Self::Tiff => Codec::Tiff,
|
||||
Self::WebP => Codec::WebP,
|
||||
Self::Heif => Codec::Heif,
|
||||
Self::Tga => Codec::Tga,
|
||||
Self::Ico => Codec::Ico,
|
||||
Self::Pnm => Codec::Pnm,
|
||||
Self::Pcx => Codec::Pcx,
|
||||
Self::Xpm => Codec::Xpm,
|
||||
Self::Dds => Codec::Dds,
|
||||
Self::Qoi => Codec::Qoi,
|
||||
Self::OpenExr => Codec::OpenExr,
|
||||
Self::Hdr => Codec::Hdr,
|
||||
Self::Avif => Codec::Avif,
|
||||
Self::Fits => Codec::Fits,
|
||||
Self::Dpx => Codec::Dpx,
|
||||
Self::Jxl => Codec::Jxl,
|
||||
Self::Cineon => Codec::Cineon,
|
||||
Self::Dicom => Codec::Dicom,
|
||||
Self::Iff => Codec::Iff,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Operations exposed by this build's shared parser/codec features.
|
||||
pub fn capabilities(self) -> Capabilities {
|
||||
#[cfg(feature = "raster-codecs")]
|
||||
if let Some(format) = self.raster_codec() {
|
||||
let codec = format.caps();
|
||||
let read = if codec.read {
|
||||
Availability::Available
|
||||
} else if matches!(self, Self::Heif) && !cfg!(feature = "heif") {
|
||||
Availability::BuildDisabled
|
||||
} else {
|
||||
Availability::Unsupported
|
||||
};
|
||||
let write = if codec.write {
|
||||
Availability::Available
|
||||
} else if matches!(self, Self::Avif) && !cfg!(feature = "avif") {
|
||||
Availability::BuildDisabled
|
||||
} else {
|
||||
Availability::Unsupported
|
||||
};
|
||||
return Capabilities { read, write, multiple_frames: codec.animation, file_sequence: false };
|
||||
}
|
||||
let raster = cfg!(feature = "raster-codecs");
|
||||
match self {
|
||||
Self::Png | Self::Jpeg | Self::Bmp | Self::Gif | Self::Tiff | Self::WebP => {
|
||||
capability(raster, true, true, matches!(self, Self::Png | Self::Gif | Self::WebP), false)
|
||||
}
|
||||
Self::Heif => Capabilities {
|
||||
read: availability(cfg!(feature = "heif"), true),
|
||||
write: Availability::Unsupported,
|
||||
multiple_frames: true,
|
||||
file_sequence: false,
|
||||
},
|
||||
Self::Avif => Capabilities {
|
||||
read: Availability::Unsupported,
|
||||
write: availability(cfg!(feature = "avif"), true),
|
||||
multiple_frames: false,
|
||||
file_sequence: false,
|
||||
},
|
||||
Self::Jxl => capability(raster, false, true, false, false),
|
||||
Self::Pcx | Self::Xpm | Self::Dicom => capability(raster, true, false, false, false),
|
||||
Self::Tga
|
||||
| Self::Ico
|
||||
| Self::Pnm
|
||||
| Self::Dds
|
||||
| Self::Qoi
|
||||
| Self::OpenExr
|
||||
| Self::Hdr
|
||||
| Self::Fits
|
||||
| Self::Dpx
|
||||
| Self::Cineon
|
||||
| Self::Iff => capability(raster, true, true, false, false),
|
||||
Self::Pdf => capability(cfg!(feature = "pdf"), true, true, false, false),
|
||||
Self::Eps | Self::PostScript | Self::Illustrator => capability(cfg!(feature = "pdf"), true, false, false, false),
|
||||
Self::Svg | Self::Svgz => capability(cfg!(feature = "svg"), true, false, false, false),
|
||||
Self::Dxf | Self::Gcode => capability(cfg!(feature = "plotter"), true, false, false, false),
|
||||
Self::Ora => capability(cfg!(feature = "ora"), true, true, false, false),
|
||||
Self::Kra => capability(cfg!(feature = "kra"), true, false, false, false),
|
||||
Self::Xcf => capability(cfg!(feature = "xcf"), true, false, false, false),
|
||||
Self::Pdn => capability(cfg!(feature = "pdn"), true, false, false, false),
|
||||
Self::Raw => capability(cfg!(feature = "raw"), true, false, true, true),
|
||||
Self::Psd => capability(cfg!(feature = "psd"), true, true, false, false),
|
||||
Self::Affinity => capability(cfg!(feature = "affinity"), true, false, false, false),
|
||||
Self::Pcraft => capability(cfg!(feature = "pcraft"), true, true, false, false),
|
||||
Self::Ase => capability(cfg!(feature = "ase"), true, true, false, false),
|
||||
Self::Studio => capability(cfg!(feature = "stencilcraft"), true, false, false, false),
|
||||
Self::Idml | Self::Indd => capability(cfg!(feature = "designcraft"), true, false, false, false),
|
||||
Self::DesignCraft | Self::DesignCraftJson => capability(cfg!(feature = "designcraft"), true, true, false, false),
|
||||
Self::StencilCraft => capability(cfg!(feature = "stencilcraft"), true, true, false, false),
|
||||
Self::Docx
|
||||
| Self::LegacyDoc
|
||||
| Self::Rtf
|
||||
| Self::Xlsx
|
||||
| Self::Pptx
|
||||
| Self::TaggedText
|
||||
| Self::PlainText
|
||||
| Self::Csv
|
||||
| Self::Tsv
|
||||
| Self::LegacyExcel => capability(cfg!(feature = "office"), true, true, false, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<Format> {
|
||||
@@ -183,49 +542,8 @@ fn is_designcraft_json(bytes: &[u8]) -> bool {
|
||||
|
||||
/// Resolve a file extension to a family, case-insensitively.
|
||||
pub fn from_extension(ext: &str) -> Option<Format> {
|
||||
match ext.trim_start_matches('.').to_ascii_lowercase().as_str() {
|
||||
"pdf" => Some(Format::Pdf),
|
||||
"eps" => Some(Format::Eps),
|
||||
"ps" => Some(Format::PostScript),
|
||||
"ai" => Some(Format::Illustrator),
|
||||
"dxf" => Some(Format::Dxf),
|
||||
"svg" => Some(Format::Svg),
|
||||
"svgz" => Some(Format::Svgz),
|
||||
"png" => Some(Format::Png),
|
||||
"jpg" | "jpeg" => Some(Format::Jpeg),
|
||||
"bmp" => Some(Format::Bmp),
|
||||
"gif" => Some(Format::Gif),
|
||||
"tif" | "tiff" => Some(Format::Tiff),
|
||||
"webp" => Some(Format::WebP),
|
||||
"heic" | "heif" => Some(Format::Heif),
|
||||
"ase" => Some(Format::Ase),
|
||||
"psd" | "psb" => Some(Format::Psd),
|
||||
"afdesign" | "afphoto" | "afpub" => Some(Format::Affinity),
|
||||
"ora" => Some(Format::Ora),
|
||||
"kra" => Some(Format::Kra),
|
||||
"xcf" => Some(Format::Xcf),
|
||||
"pdn" => Some(Format::Pdn),
|
||||
"dng" | "3fr" | "ari" | "arw" | "bay" | "cap" | "cr2" | "cr3" | "dcs" | "dcr" | "drf" | "eip" | "erf" | "fff" | "gpr" | "iiq" | "k25"
|
||||
| "kdc" | "mdc" | "mef" | "mos" | "mrw" | "nef" | "nrw" | "obm" | "orf" | "pef" | "ptx" | "pxn" | "r3d" | "raf" | "raw" | "rwl" | "rw2"
|
||||
| "rwz" | "sr2" | "srf" | "sti" | "x3f" => Some(Format::Raw),
|
||||
"pcraft" => Some(Format::Pcraft),
|
||||
"idml" => Some(Format::Idml),
|
||||
"designcraft" | "dcdoc" => Some(Format::DesignCraft),
|
||||
"indd" | "indt" => Some(Format::Indd),
|
||||
"docx" => Some(Format::Docx),
|
||||
"doc" => Some(Format::LegacyDoc),
|
||||
"rtf" => Some(Format::Rtf),
|
||||
"xlsx" => Some(Format::Xlsx),
|
||||
"pptx" => Some(Format::Pptx),
|
||||
"txt" | "text" | "md" => Some(Format::PlainText),
|
||||
"csv" => Some(Format::Csv),
|
||||
"tsv" | "tab" => Some(Format::Tsv),
|
||||
"xls" | "xlsm" => Some(Format::LegacyExcel),
|
||||
"studio" | "studio3" => Some(Format::Studio),
|
||||
"stencilcraft" => Some(Format::StencilCraft),
|
||||
"gcode" | "nc" => Some(Format::Gcode),
|
||||
_ => None,
|
||||
}
|
||||
let ext = ext.trim_start_matches('.');
|
||||
Format::ALL.into_iter().find(|format| format.extensions().iter().any(|candidate| candidate.eq_ignore_ascii_case(ext)))
|
||||
}
|
||||
|
||||
const INDD_SIGNATURE: [u8; 16] = [0x06, 0x06, 0xED, 0xF5, 0xD8, 0x1D, 0x46, 0xE5, 0xBD, 0x31, 0xEF, 0xE7, 0xFE, 0x74, 0xB7, 0x1D];
|
||||
|
||||
Reference in new issue
Block a user