use std::collections::HashMap;
use log::{info, error};
use crate::tiff::errors::{TiffError, TiffResult};
use crate::tiff::ifd::IFD;
use crate::utils::logger::Logger;
use crate::extractor::Region;
use crate::tiff::builders::basic_tags::BasicTagsBuilder;
use crate::tiff::builders::geo_tags::GeoTagsBuilder;
use crate::tiff::builders::metadata_tags::MetadataBuilder;
use crate::tiff::builders::writer::WriterBuilder;
pub struct TiffBuilder<'a> {
logger: &'a Logger,
is_big_tiff: bool,
pub ifds: Vec<IFD>,
image_data: HashMap<usize, Vec<u8>>,
external_data: HashMap<(usize, u16), Vec<u8>>,
}
impl<'a> TiffBuilder<'a> {
pub fn new(logger: &'a Logger, is_big_tiff: bool) -> Self {
info!("Creating new TiffBuilder (is_big_tiff: {})", is_big_tiff);
TiffBuilder {
logger,
is_big_tiff,
ifds: Vec::new(),
image_data: HashMap::new(),
external_data: HashMap::new(),
}
}
pub fn add_ifd(&mut self, ifd: IFD) -> usize {
let ifd_index = self.ifds.len();
info!("Adding IFD #{} to TiffBuilder", ifd_index);
self.ifds.push(ifd);
ifd_index
}
pub fn set_image_data(&mut self, ifd_index: usize, data: Vec<u8>) {
info!("Setting image data for IFD #{}: {} bytes", ifd_index, data.len());
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
self.image_data.insert(ifd_index, data);
}
pub fn set_external_data(&mut self, ifd_index: usize, tag: u16, data: Vec<u8>) {
info!("Setting external data for IFD #{}, tag {}: {} bytes", ifd_index, tag, data.len());
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
self.external_data.insert((ifd_index, tag), data);
}
pub fn add_bits_per_sample(&mut self, ifd_index: usize, bits_per_channel: &[u16]) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
BasicTagsBuilder::add_bits_per_sample(
&mut self.ifds[ifd_index],
&mut self.external_data,
ifd_index,
bits_per_channel
);
}
pub fn setup_single_strip(&mut self, ifd_index: usize, strip_data: Vec<u8>) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
BasicTagsBuilder::setup_single_strip(
&mut self.ifds[ifd_index],
&mut self.image_data,
ifd_index,
strip_data
);
}
pub fn add_basic_rgb_tags(&mut self, ifd_index: usize, width: u32, height: u32) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
BasicTagsBuilder::add_basic_rgb_tags(
&mut self.ifds[ifd_index],
&mut self.external_data,
ifd_index,
width,
height
);
}
pub fn add_basic_gray_tags(&mut self, ifd_index: usize, width: u32, height: u32, bits_per_sample: u16) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
BasicTagsBuilder::add_basic_gray_tags(
&mut self.ifds[ifd_index],
width,
height,
bits_per_sample
);
}
pub fn add_color_map(&mut self, ifd_index: usize, color_map: &[u16]) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
BasicTagsBuilder::add_color_map(
&mut self.ifds[ifd_index],
&mut self.external_data,
ifd_index,
color_map
);
}
pub fn copy_geotiff_tags(&mut self, ifd_index: usize, source_ifd: &IFD, reader: &mut crate::tiff::TiffReader) -> TiffResult<()> {
if ifd_index >= self.ifds.len() {
return Err(TiffError::GenericError(format!(
"Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len())));
}
GeoTagsBuilder::copy_geotiff_tags(
&mut self.ifds[ifd_index],
&mut self.external_data,
ifd_index,
source_ifd,
reader
)
}
pub fn adjust_geotiff_for_region(
&mut self,
ifd_index: usize,
region: &Region,
pixel_scale: &[f64],
tiepoint: &[f64]
) -> TiffResult<()> {
if ifd_index >= self.ifds.len() {
return Err(TiffError::GenericError(format!(
"Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len())));
}
GeoTagsBuilder::adjust_geotiff_for_region(
&mut self.ifds[ifd_index],
&mut self.external_data,
ifd_index,
region,
pixel_scale,
tiepoint
)
}
pub fn copy_appearance_tags(&mut self, ifd_index: usize, source_ifd: &IFD) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
GeoTagsBuilder::copy_appearance_tags(
&mut self.ifds[ifd_index],
source_ifd
);
}
pub fn copy_tags_from(&mut self, ifd_index: usize, source_ifd: &IFD, exclude_tags: &[u16]) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
GeoTagsBuilder::copy_tags_from(
&mut self.ifds[ifd_index],
source_ifd,
exclude_tags
);
}
pub fn add_nodata_tag(&mut self, ifd_index: usize, nodata_value: &str) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
MetadataBuilder::add_nodata_tag(
&mut self.ifds[ifd_index],
&mut self.external_data,
ifd_index,
nodata_value
);
}
pub fn add_gdal_metadata_tag(&mut self, ifd_index: usize, existing_metadata: Option<&str>, nodata_value: &str) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
MetadataBuilder::add_gdal_metadata_tag(
&mut self.ifds[ifd_index],
&mut self.external_data,
ifd_index,
existing_metadata,
nodata_value
);
}
pub fn copy_statistics_tags(&mut self, ifd_index: usize, source_ifd: &IFD) {
if ifd_index >= self.ifds.len() {
error!("Invalid IFD index {}, only have {} IFDs", ifd_index, self.ifds.len());
return;
}
MetadataBuilder::copy_statistics_tags(
&mut self.ifds[ifd_index],
source_ifd
);
}
pub fn write(&self, output_path: &str) -> TiffResult<()> {
info!("Writing TIFF to {}", output_path);
self.logger.log(&format!("Writing TIFF to {}", output_path))?;
WriterBuilder::write(
self.is_big_tiff,
&self.ifds,
&self.image_data,
&self.external_data,
output_path
)
}
}