@@ -12,8 +12,8 @@ use crate::{
1212 decoder:: ifd:: Entry ,
1313 error:: { TiffResult , UsageError } ,
1414 tags:: {
15- CompressionMethod , ExtraSamples , IfdPointer , PhotometricInterpretation , ResolutionUnit ,
16- SampleFormat , Tag , Type ,
15+ ByteOrder , CompressionMethod , ExtraSamples , IfdPointer , PhotometricInterpretation ,
16+ ResolutionUnit , SampleFormat , Tag , Type , ValueBuffer ,
1717 } ,
1818 Directory , TiffError , TiffFormatError ,
1919} ;
@@ -291,6 +291,21 @@ impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
291291 } )
292292 }
293293
294+ /// Write a tag-value pair with prepared byte data.
295+ ///
296+ /// Note that the library will _not_ attempt to verify that the data type or the count of the
297+ /// buffered value is permissible for the given tag. The data will be associated with the tag
298+ /// exactly as-is.
299+ ///
300+ /// An error is returned if the byte order of the presented value does not match the byte order
301+ /// of the underlying file (i.e. the [native byte order](`crate::tags::ByteOrder::native`)).
302+ pub fn write_tag_value ( & mut self , tag : Tag , value : & ValueBuffer ) -> TiffResult < ( ) > {
303+ let entry = self . write_entry_buf ( value) ?;
304+ self . directory . extend ( [ ( tag, entry) ] ) ;
305+
306+ Ok ( ( ) )
307+ }
308+
294309 /// Write a single ifd tag.
295310 pub fn write_tag < T : TiffValue > ( & mut self , tag : Tag , value : T ) -> TiffResult < ( ) > {
296311 // Encodes the value if necessary. In the current bytes all integers are taken as native
@@ -301,12 +316,12 @@ impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
301316 value. write ( & mut writer) ?;
302317 }
303318
304- let entry = Self :: write_value (
319+ let entry = Self :: write_entry_inner (
305320 self . writer ,
306- & DirectoryEntry {
321+ DirectoryEntry {
307322 data_type : <T >:: FIELD_TYPE ,
308323 count : value. count ( ) . try_into ( ) ?,
309- data : bytes,
324+ data : bytes. into ( ) ,
310325 } ,
311326 ) ?;
312327
@@ -317,13 +332,70 @@ impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
317332
318333 /// Write some data to the tiff file, the offset of the data is returned.
319334 ///
320- /// This could be used to write tiff strips.
335+ /// This could be used to write tiff strips. All of the data will be written into the file as a
336+ /// slice of bytes. It can not be used as an entry in a directory directly, where very short
337+ /// values are instead represented in the offset field directly. Use [`Self::write_entry`]
338+ /// instead.
321339 pub fn write_data < T : TiffValue > ( & mut self , value : T ) -> TiffResult < u64 > {
322340 let offset = self . writer . offset ( ) ;
323341 value. write ( self . writer ) ?;
324342 Ok ( offset)
325343 }
326344
345+ /// Write some data directly to the tiff file, the offset of the data is returned.
346+ ///
347+ /// All of the data will be written into the file as a slice of bytes. It can not be used as an
348+ /// entry in a directory directly, where very short values are instead represented in the
349+ /// offset field directly. Use [`Self::write_entry_buf`] instead.
350+ ///
351+ /// An error is returned if the byte order of the presented value does not match the byte order
352+ /// of the underlying file (i.e. the [native byte order](`crate::tags::ByteOrder::native`)).
353+ pub fn write_data_buf ( & mut self , value : & ValueBuffer ) -> TiffResult < u64 > {
354+ self . check_value_byteorder ( value) ?;
355+ let offset = self . writer . offset ( ) ;
356+ self . writer . write_bytes ( value. as_bytes ( ) ) ?;
357+ Ok ( offset)
358+ }
359+
360+ /// Write a directory value into the file.
361+ ///
362+ /// Returns an [`Entry`]. If the value is short enough it will *not* be written in the file but
363+ /// stored in the entry's offset field.
364+ pub fn write_entry < T : TiffValue > ( & mut self , value : T ) -> TiffResult < Entry > {
365+ Self :: write_entry_inner (
366+ self . writer ,
367+ DirectoryEntry {
368+ data_type : T :: FIELD_TYPE ,
369+ count : K :: convert_offset ( value. count ( ) as u64 ) ?,
370+ // FIXME: not optimal we always allocate here. But the only other method we have
371+ // available is `T::write(&mut TiffWriter<W>)` and we must pass that into
372+ // `write_entry_inner` but then have a combinatorial explosion of instantiations
373+ // which is absurd.
374+ data : value. data ( ) ,
375+ } ,
376+ )
377+ }
378+
379+ /// Write a directory value into the file.
380+ ///
381+ /// An error is returned if the byte order of the presented value does not match the byte order
382+ /// of the underlying file (i.e. the [native byte order](`crate::tags::ByteOrder::native`)).
383+ ///
384+ /// Returns an [`Entry`]. If the value is short enough it will *not* be written in the file but
385+ /// stored in the entry's offset field.
386+ pub fn write_entry_buf ( & mut self , value : & ValueBuffer ) -> TiffResult < Entry > {
387+ self . check_value_byteorder ( value) ?;
388+
389+ Self :: write_entry_inner (
390+ self . writer ,
391+ DirectoryEntry {
392+ data_type : value. data_type ( ) ,
393+ count : K :: convert_offset ( value. count ( ) ) ?,
394+ data : value. as_bytes ( ) . into ( ) ,
395+ } ,
396+ )
397+ }
398+
327399 /// Insert previously written key-value entries.
328400 ///
329401 /// It is the caller's responsibility to ensure that the data referred to by the entries is
@@ -377,17 +449,21 @@ impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
377449 Ok ( offset)
378450 }
379451
380- fn write_value (
452+ // Does it really make sense that this would be a (potentially) compressible write? For actual
453+ // directory values their size must match the data written so there's going to be a silent
454+ // problem if that actually occurs.
455+ fn write_entry_inner (
381456 writer : & mut TiffWriter < W > ,
382- value : & DirectoryEntry < K :: OffsetType > ,
457+ value : DirectoryEntry < K :: OffsetType > ,
383458 ) -> TiffResult < Entry > {
384- let & DirectoryEntry {
459+ let DirectoryEntry {
385460 data : ref bytes,
386461 ref count,
387462 data_type,
388463 } = value;
389464
390465 let in_entry_bytes = mem:: size_of :: < K :: OffsetType > ( ) ;
466+
391467 let mut offset_bytes = [ 0 ; 8 ] ;
392468
393469 if bytes. len ( ) > in_entry_bytes {
@@ -406,6 +482,7 @@ impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
406482 // and some oversight, we can not clone the `count: K::OffsetType` and thus not convert it.
407483 // Instead, write it to a buffer...
408484 let mut count_bytes = [ 0 ; 8 ] ;
485+ debug_assert ! ( in_entry_bytes == 4 || in_entry_bytes == 8 ) ;
409486 // Nominally Cow but we only expect `Cow::Borrowed`.
410487 count_bytes[ ..count. bytes ( ) ] . copy_from_slice ( & count. data ( ) ) ;
411488
@@ -419,6 +496,15 @@ impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
419496 } )
420497 }
421498
499+ fn check_value_byteorder ( & self , value : & ValueBuffer ) -> TiffResult < ( ) > {
500+ // FIXME: we should enable writing files with any chosen byte order.
501+ if value. byte_order ( ) != ByteOrder :: native ( ) {
502+ Err ( TiffError :: UsageError ( UsageError :: ByteOrderMismatch ) )
503+ } else {
504+ Ok ( ( ) )
505+ }
506+ }
507+
422508 /// Provides the number of bytes written by the underlying TiffWriter during the last call.
423509 fn last_written ( & self ) -> u64 {
424510 self . writer . last_written ( )
@@ -824,10 +910,10 @@ impl<'a, W: Write + Seek, C: ColorType, K: TiffKind> Drop for ImageEncoder<'a, W
824910 }
825911}
826912
827- struct DirectoryEntry < S > {
913+ struct DirectoryEntry < ' data , S > {
828914 data_type : Type ,
829915 count : S ,
830- data : Vec < u8 > ,
916+ data : std :: borrow :: Cow < ' data , [ u8 ] > ,
831917}
832918
833919/// Trait to abstract over Tiff/BigTiff differences.
0 commit comments