This complements the entry API of the encoder with the byte slice based
method. Note we don't provide it for writing raw data, here a
`std::io::Write` would be more appropriate and we should not attempt to
make it `write_all`, nor compress. You'd get all the benefits of the
other API through `[u8]: TiffValue` since that interface is otherwise
type agnostic and `u8` specifically is endian agnostic.
We have not released this yet, let's align these names before it is too
late. The decoder adopted the `_buf` suffix and I find it more
convincing than the more generic `_value` (that also confusingly shares
it with `TiffValue`).
Implement the encoder's `TiffValue` trait for the tags commonly defined
and represented as separate types in our own code. We don't tie the
tag for an entry of these to the value type (yet). This lets us keep the
trait exactly as-is and we avoid unnecessary churn. We can always add a
separate trait on top.
We have a fundamental choice here: We could add more proxy
implementations for `Vec` and `Box` to follow `&'_ T`, for some types
that indirections is clear. Vec and arrays are also both very natural
ways of expressing a repeated value. However, passing an allocated value
to the interface forces us to drop it inside. We might be able to
utilize the allocation for an in-place byteswap in a future increment
but not with the current design.
So, overall, I think that inherently `Drop`-y types should be avoided in
these implementations. Instead, we can use the amazing diagnostic tools
in the compiler to just help the users navigate the type system. We can
still provide the impl for arrays.
For context, see: https://users.rust-lang.org/t/what-type-is-u16/137395
Now they see:
|
38 | .write_tag(tiff::tags::Tag::GeoKeyDirectoryTag, &geokey);
| ^^^^^^ the trait `TiffValue` is not implemented for `&Vec<u16>`
|
= note: the trait is implemented for primitive types (`u8`, `i16`, `f32`, etc.)
= note: the trait is implemented for shared references to values
= note: the trait is implemented for slices, pass them by reference (e.g. `&[u8]`)
= note: the trait is implemented for arrays if it is implemented for a slice
= note: values in a `Vec` or `Box` should be dereferenced, e.g. `&vec[..]`
= help: the following other types implement trait `TiffValue`:
Previously the compiler would both strip the `&` in its first message
(due to our forwarding impl) and not list any way of getting a
reference-to-slice.
These samples are normal bits in the encoded (e.g. compressed) stream of
each tile or row of the image. However, when considering the photometric
interpretation of an image these samples should be discarded. They are
only relevant for multiband.
For the most part we previously rejected these images due to a mismatch
between sample count and the color as indicated by the interpretation.
Only, for alpha we never really verified if the extra channel is indeed
alpha or something unrelated. We don't have a perfect solution as
GeoTiff motivates us having a MultiBand pseudo-color output
configuration that has no related photometric interpretation and borrows
the usual gray tone instead. We can only really distinguish this from a
gray-alpha image through looking at the values of the ExtraSamples
vector. Then again we do not yet support GrayAlpha anyways.
As a simplification for the discarding process we only support full-byte
extra samples and require all samples to be the same bit-depth, not only
those which we return. This is blessed by Tiff's recommendations for
baseline decoding as well as libtiff.
There are two kinds of directories: those that are image directories
directly in the TIFF file's main sequence, and directories that follow
the structure but represent auxiliary data. The method will link the
directory into the main sequence but those images have additional
requirement on their IFDs which is not clear to the caller. We make that
explicit and also provide a way to write auxiliary directories.
This currently avoids buffering the collection, but not buffering them
individually where we still format it into a byte vector.
The main drive here is making the DirectoryEncoder less dependent on the
values. That is, it should be concerned with the Entry representation of
values only. A few decoders expect all values to strictly follow the
image directory and the data layout of such files should be controllable
by the user. This could be achieved by encoding dummy entries which are
later corrected once the actual item is known by seeking back and
writing the directory anew.
By no longer assuming values to be available on finishing a directory we
also prepare an interface that encodes an existing directory.
This is just the implementation details. In the DirectoryEncoder we did
not differentiate between different directories that should go into the
main image chain and other directories. This is now possible by storing
the prior offset as an explicit Option<NonZeroU64>.
Additionally, the whole encoder did not allow any intermediate data
between its last directory and new directories on the chain. The offset
of the relevant `next` field was not stored explicitly but derived from
the current stream position at the moment of starting the directory.
This would not allow any padding data or data written outside the
returned `DirectoryEncoder` object.
This relaxed both requirements by turning the offsets into attributes.