mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-14 22:42:46 +00:00
image-codecs: list InkSet and ExtraSamples on TiffPage (#1307)
* image-codecs: list InkSet and ExtraSamples on TiffPage * image-codecs: TiffPage InkSet and ExtraSamples as enums * image-codecs: InkSet::InkNames, and Invalid for undefined tag values
This commit is contained in:
1 parent
1118899c28
commit
ea1c84290d
4 files changed
+78
-3
No files matched your search
@@ -250,8 +250,9 @@ embedded table (and a PNG's transparent entry) so `photocraft-io` can open them
|
||||
the image: when the image fits but its extra samples don't, it opens without them and carries
|
||||
`DecodeWarning::ExtraSamplesDropped`.
|
||||
* Every directory is reachable: `tiff_info` lists the main IFD chain and its SubIFDs (tag 330)
|
||||
with each page's size, kind (page, reduced-resolution copy, mask) and storage, walked with a
|
||||
seen-set, a depth limit and a 10 000-directory cap; `decode_tiff_page` opens any of them.
|
||||
with each page's size, kind (page, reduced-resolution copy, mask), storage, InkSet and
|
||||
ExtraSamples, walked with a seen-set, a depth limit and a 10 000-directory cap;
|
||||
`decode_tiff_page` opens any of them.
|
||||
`decode` opens the first full-resolution page, like Photoshop (thumbnails are skipped).
|
||||
* Banded decoding: the image is allocated once at its final size and each strip or row of
|
||||
tiles is decoded straight into it, in parallel on native targets, with at most one
|
||||
|
||||
@@ -41,6 +41,7 @@ pub(crate) const TAG_TILE_WIDTH: u16 = 322;
|
||||
pub(crate) const TAG_TILE_LENGTH: u16 = 323;
|
||||
pub(crate) const TAG_TILE_OFFSETS: u16 = 324;
|
||||
pub(crate) const TAG_SUB_IFDS: u16 = 330;
|
||||
pub(crate) const TAG_INK_SET: u16 = 332;
|
||||
pub(crate) const TAG_EXTRA_SAMPLES: u16 = 338;
|
||||
pub(crate) const TAG_SAMPLE_FORMAT: u16 = 339;
|
||||
|
||||
@@ -349,6 +350,56 @@ pub struct TiffPage {
|
||||
pub tiled: bool,
|
||||
/// `PlanarConfiguration` 2: each sample in its own plane.
|
||||
pub planar: bool,
|
||||
/// TIFF `InkSet` (tag 332), when present. Only meaningful for photometric 5 (Separated).
|
||||
pub ink_set: Option<InkSet>,
|
||||
/// TIFF `ExtraSamples` (tag 338), one per extra sample. Empty when the tag is absent or
|
||||
/// unreadable.
|
||||
pub extra_samples: Vec<ExtraSampleKind>,
|
||||
}
|
||||
|
||||
/// The TIFF `InkSet` tag (332) of a separated image.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum InkSet {
|
||||
/// 1: the samples are cyan, magenta, yellow and black.
|
||||
Cmyk,
|
||||
/// 2: the samples are the inks listed in the `InkNames` tag.
|
||||
InkNames,
|
||||
/// Any other value; TIFF 6.0 defines only 1 and 2.
|
||||
Invalid(u16),
|
||||
}
|
||||
|
||||
impl InkSet {
|
||||
fn from_tag(value: u16) -> Self {
|
||||
match value {
|
||||
1 => Self::Cmyk,
|
||||
2 => Self::InkNames,
|
||||
v => Self::Invalid(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// What one extra sample of a TIFF holds, from the `ExtraSamples` tag (338).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ExtraSampleKind {
|
||||
/// 0: unspecified data.
|
||||
Unspecified,
|
||||
/// 1: associated (premultiplied) alpha.
|
||||
AssociatedAlpha,
|
||||
/// 2: unassociated (straight) alpha.
|
||||
UnassociatedAlpha,
|
||||
/// Any other value; TIFF 6.0 defines only 0, 1 and 2.
|
||||
Invalid(u16),
|
||||
}
|
||||
|
||||
impl ExtraSampleKind {
|
||||
fn from_tag(value: u16) -> Self {
|
||||
match value {
|
||||
0 => Self::Unspecified,
|
||||
1 => Self::AssociatedAlpha,
|
||||
2 => Self::UnassociatedAlpha,
|
||||
v => Self::Invalid(v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The directory structure of a TIFF file: its byte order, BigTIFF or not, and every image
|
||||
@@ -405,6 +456,14 @@ fn describe(f: &File<'_>, ifd: &Ifd, parent: Option<usize>) -> TiffPage {
|
||||
compression: u16_of(TAG_COMPRESSION, 1),
|
||||
tiled: ifd.get(TAG_TILE_OFFSETS).is_some(),
|
||||
planar: f.tag_uint(ifd, TAG_PLANAR) == Some(2),
|
||||
ink_set: f.tag_uint(ifd, TAG_INK_SET).map(|v| InkSet::from_tag(u16::try_from(v).unwrap_or(u16::MAX))),
|
||||
// Capped at the sample count: a file cannot have more extra samples than samples.
|
||||
extra_samples: f
|
||||
.tag_uints(ifd, TAG_EXTRA_SAMPLES, u64::from(u16_of(TAG_SAMPLES, 1)))
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|v| ExtraSampleKind::from_tag(u16::try_from(v).unwrap_or(u16::MAX)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ pub use crate::codecs::png::{
|
||||
pub use crate::codecs::tiff::{
|
||||
PhotoshopTags as TiffPhotoshopTags, TiffBands, photoshop_tags as tiff_photoshop_tags, writes_little_endian as tiff_writes_little_endian,
|
||||
};
|
||||
pub use crate::codecs::tiff_ifd::{TiffInfo, TiffPage, TiffPageKind};
|
||||
pub use crate::codecs::tiff_ifd::{ExtraSampleKind, InkSet, TiffInfo, TiffPage, TiffPageKind};
|
||||
pub use crate::error::CodecError;
|
||||
pub use crate::exif_color::{EXIF_COLOR_SPACE_SRGB, exif_color_space};
|
||||
pub use crate::fidelity::{FidelityWarning, fidelity_warnings, fidelity_warnings_with};
|
||||
|
||||
@@ -382,6 +382,21 @@ fn associated_alpha_is_made_straight() {
|
||||
assert_eq!(img.to_u16_samples().unwrap(), [32768, 32768]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ink_set_and_extra_samples_are_listed() {
|
||||
let px = [10u8, 20, 30, 40, 17, 128];
|
||||
let d = strips(1, 1, 8, 6, 5, 1, &px).tag(332, SHORT, &[2]).tag(338, SHORT, &[0, 1]);
|
||||
let info = tiff_info(&build(true, false, &[d], &[0]).bytes).unwrap();
|
||||
use ExtraSampleKind::*;
|
||||
assert_eq!((info.pages[0].ink_set, &info.pages[0].extra_samples[..]), (Some(InkSet::InkNames), &[Unspecified, AssociatedAlpha][..]));
|
||||
let d = strips(1, 1, 8, 6, 5, 1, &px).tag(332, SHORT, &[7]).tag(338, SHORT, &[2, 5]);
|
||||
let info = tiff_info(&build(true, false, &[d], &[0]).bytes).unwrap();
|
||||
assert_eq!((info.pages[0].ink_set, &info.pages[0].extra_samples[..]), (Some(InkSet::Invalid(7)), &[UnassociatedAlpha, Invalid(5)][..]));
|
||||
let d = strips(1, 1, 8, 4, 5, 1, &px[..4]);
|
||||
let info = tiff_info(&build(true, false, &[d], &[0]).bytes).unwrap();
|
||||
assert_eq!((info.pages[0].ink_set, &info.pages[0].extra_samples[..]), (None, &[][..]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn white_is_zero_opens_with_the_right_tones() {
|
||||
// #691: 00 FF 00 in a WhiteIsZero file is white, black, white.
|
||||
|
||||
Reference in new issue
Block a user