Skip to content

Commit 45f617b

Browse files
committed
Construct tags::ValueBuffer from ifd::Value
Provides interaction between decoder and encoder values. Not sure about this commit yet, the implementation is a bit odd.
1 parent 170bd36 commit 45f617b

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ categories = ["multimedia::images", "multimedia::encoding"]
1717
exclude = ["tests/images/*", "tests/fuzz_images/*"]
1818

1919
[dependencies]
20+
bytemuck = "1.14"
2021
half = { version = "2.4.1" }
2122
quick-error = "2.0.1"
2223

src/tags.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::decoder::ifd;
2+
13
macro_rules! tags {
24
{
35
// Permit arbitrary meta items, which include documentation.
@@ -392,6 +394,111 @@ impl ValueBuffer {
392394
}
393395
}
394396

397+
/// Create a value with native endian byte order.
398+
impl TryFrom<ifd::Value> for ValueBuffer {
399+
type Error = crate::TiffError;
400+
401+
fn try_from(value: ifd::Value) -> Result<Self, Self::Error> {
402+
Self::try_from(&value)
403+
}
404+
}
405+
406+
/// Create a value with native endian byte order.
407+
impl TryFrom<&'_ ifd::Value> for ValueBuffer {
408+
type Error = crate::TiffError;
409+
410+
fn try_from(value: &'_ ifd::Value) -> Result<Self, Self::Error> {
411+
use std::borrow::Cow::{self, Borrowed, Owned};
412+
413+
fn bytes_of_value(
414+
value: &'_ ifd::Value,
415+
) -> Result<(Cow<'_, [u8]>, Type), crate::TiffError> {
416+
Ok(match value {
417+
ifd::Value::List(values) => {
418+
let mut type_ = None;
419+
let mut bytes = vec![];
420+
421+
// This is treated separately, also we rely on the caller being faithful in their
422+
// use of the ifd::Value enum.
423+
for item in values {
424+
let (value, newty) = bytes_of_value(item)?;
425+
426+
if type_.map_or(false, |ty| ty != newty) {
427+
return Err(crate::TiffError::UnsupportedError(
428+
crate::error::TiffUnsupportedError::UnsupportedDataType,
429+
));
430+
}
431+
432+
type_ = Some(newty);
433+
bytes.extend_from_slice(&value);
434+
}
435+
436+
let Some(ty) = type_ else {
437+
return Err(crate::TiffError::UnsupportedError(
438+
crate::error::TiffUnsupportedError::UnsupportedDataType,
439+
));
440+
};
441+
442+
(Owned(bytes), ty)
443+
}
444+
ifd::Value::Byte(val) => (Borrowed(bytemuck::bytes_of(val)), Type::BYTE),
445+
ifd::Value::Short(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SHORT),
446+
ifd::Value::SignedByte(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SBYTE),
447+
ifd::Value::SignedShort(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SSHORT),
448+
ifd::Value::Signed(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SLONG),
449+
ifd::Value::SignedBig(val) => (Borrowed(bytemuck::bytes_of(val)), Type::SLONG8),
450+
ifd::Value::Unsigned(val) => (Borrowed(bytemuck::bytes_of(val)), Type::LONG),
451+
ifd::Value::UnsignedBig(val) => (Borrowed(bytemuck::bytes_of(val)), Type::LONG8),
452+
ifd::Value::Float(val) => (Borrowed(bytemuck::bytes_of(val)), Type::FLOAT),
453+
ifd::Value::Double(val) => (Borrowed(bytemuck::bytes_of(val)), Type::DOUBLE),
454+
ifd::Value::Rational(num, denom) => (
455+
Owned([bytemuck::bytes_of(num), bytemuck::bytes_of(denom)].concat()),
456+
Type::RATIONAL,
457+
),
458+
#[expect(deprecated)]
459+
ifd::Value::RationalBig(..) | ifd::Value::SRationalBig(..) => {
460+
return Err(crate::TiffError::UnsupportedError(
461+
crate::error::TiffUnsupportedError::UnsupportedDataType,
462+
));
463+
}
464+
ifd::Value::SRational(num, denom) => (
465+
Owned([bytemuck::bytes_of(num), bytemuck::bytes_of(denom)].concat()),
466+
Type::SRATIONAL,
467+
),
468+
ifd::Value::Ascii(st) => (Borrowed(st.as_bytes()), Type::ASCII),
469+
ifd::Value::Ifd(val) => (Borrowed(bytemuck::bytes_of(val)), Type::IFD),
470+
ifd::Value::IfdBig(val) => (Borrowed(bytemuck::bytes_of(val)), Type::IFD8),
471+
})
472+
}
473+
474+
let byte_order = ByteOrder::native();
475+
476+
let (bytes, ty) = bytes_of_value(value)?;
477+
let bytes = bytes.into_owned();
478+
479+
// Check the count can be represented.
480+
if let ifd::Value::List(values) = value {
481+
let count =
482+
u64::try_from(values.len()).map_err(|_| crate::TiffError::LimitsExceeded)?;
483+
let expected = ty.value_bytes(count)?;
484+
485+
if bytes.len() != expected as usize {
486+
return Err(crate::TiffError::UnsupportedError(
487+
crate::TiffUnsupportedError::UnsupportedDataType,
488+
));
489+
}
490+
} else {
491+
debug_assert_eq!(bytes.len(), ty.byte_len().into());
492+
}
493+
494+
Ok(ValueBuffer {
495+
bytes,
496+
byte_order,
497+
ty,
498+
})
499+
}
500+
}
501+
395502
/// Byte order of the TIFF file.
396503
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
397504
pub enum ByteOrder {

0 commit comments

Comments
 (0)