use std::path::Path;
use fitsio::FitsFile;
use fitsio::errors::check_status;
use crate::error::{AtfitsError, Result};
use crate::keys::cstr;
pub fn resize_image(fptr: &mut FitsFile, bitpix: i64, dims: &[usize]) -> Result<()> {
let mut naxes: Vec<std::os::raw::c_long> =
dims.iter().map(|&d| d as std::os::raw::c_long).collect();
let mut status = 0;
unsafe {
fitsio::sys::ffrsim(
fptr.as_raw(),
bitpix as std::os::raw::c_int,
naxes.len() as std::os::raw::c_int,
naxes.as_mut_ptr(),
&mut status,
);
}
check_status(status)?;
Ok(())
}
pub fn is_structural_keyword(name: &str) -> bool {
matches!(
name,
"SIMPLE"
| "BITPIX"
| "NAXIS"
| "EXTEND"
| "PCOUNT"
| "GCOUNT"
| "END"
| "BSCALE"
| "BZERO"
| "BLANK"
) || (name.starts_with("NAXIS") && name[5..].chars().all(|c| c.is_ascii_digit()))
}
pub fn bitpix_to_image_type(bitpix: i64) -> fitsio::images::ImageType {
use fitsio::images::ImageType;
match bitpix {
8 => ImageType::UnsignedByte,
16 => ImageType::Short,
32 => ImageType::Long,
64 => ImageType::LongLong,
-64 => ImageType::Double,
_ => ImageType::Float, }
}
fn refuse_input_clobber(input: &Path, output: &Path) -> Result<()> {
if let (Ok(in_canon), Ok(out_canon)) = (input.canonicalize(), output.canonicalize())
&& in_canon == out_canon
{
return Err(AtfitsError::Other(format!(
"output {} resolves to the input image",
output.display()
)));
}
Ok(())
}
pub fn copy_header_only_open(input: &Path, output: &Path) -> Result<FitsFile> {
refuse_input_clobber(input, output)?;
let mut in_fptr = FitsFile::open(input.to_string_lossy().as_ref())?;
in_fptr.primary_hdu()?;
if output.exists() {
std::fs::remove_file(output)?;
}
let out_name = cstr(output.to_string_lossy().as_ref())?;
let mut status = 0;
let mut raw_out: *mut fitsio::sys::fitsfile = std::ptr::null_mut();
let handle = unsafe {
fitsio::sys::ffinit(&mut raw_out, out_name.as_ptr(), &mut status);
check_status(status)?;
fitsio::sys::ffcphd(in_fptr.as_raw(), raw_out, &mut status);
if let Err(e) = check_status(status) {
let mut close_status = 0;
fitsio::sys::ffclos(raw_out, &mut close_status);
return Err(e.into());
}
FitsFile::from_raw(raw_out, fitsio::FileOpenMode::READWRITE)?
};
Ok(handle)
}
pub fn copy_header_only(input: &Path, output: &Path) -> Result<()> {
copy_header_only_open(input, output).map(drop)
}
pub fn create_cube_open(
input: &Path,
output: &Path,
bitpix: i64,
dims: &[usize],
) -> Result<FitsFile> {
use fitsio::images::ImageDescription;
refuse_input_clobber(input, output)?;
if output.exists() {
std::fs::remove_file(output)?;
}
let c_dims: Vec<usize> = dims.iter().rev().copied().collect();
let desc = ImageDescription {
data_type: bitpix_to_image_type(bitpix),
dimensions: &c_dims,
};
let mut out = FitsFile::create(output)
.with_custom_primary(&desc)
.overwrite()
.open()?;
out.primary_hdu()?;
let mut in_fptr = FitsFile::open(input.to_string_lossy().as_ref())?;
in_fptr.primary_hdu()?;
let mut status = 0;
unsafe {
let mut nkeys: std::os::raw::c_int = 0;
let mut morekeys: std::os::raw::c_int = 0;
fitsio::sys::ffghsp(in_fptr.as_raw(), &mut nkeys, &mut morekeys, &mut status);
check_status(status)?;
let mut card = [0 as std::os::raw::c_char; 81];
for i in 1..=nkeys {
card.fill(0);
fitsio::sys::ffgrec(in_fptr.as_raw(), i, card.as_mut_ptr(), &mut status);
if check_status(status).is_err() {
break;
}
let card_str = std::ffi::CStr::from_ptr(card.as_ptr()).to_string_lossy();
let name = card_str.split([' ', '=']).next().unwrap_or("").trim();
if is_structural_keyword(name) {
continue;
}
fitsio::sys::ffprec(out.as_raw(), card.as_ptr(), &mut status);
check_status(status)?;
}
}
Ok(out)
}