38 个版本 (20 个破坏性更新)

0.21.5 2024 年 8 月 6 日
0.21.4 2024 年 7 月 27 日
0.21.2 2023 年 2 月 10 日
0.21.1 2022 年 12 月 23 日
0.1.1 2016 年 5 月 31 日

#14 in 科学

Download history 95/week @ 2024-04-28 190/week @ 2024-05-05 80/week @ 2024-05-12 108/week @ 2024-05-19 31/week @ 2024-05-26 43/week @ 2024-06-02 30/week @ 2024-06-09 75/week @ 2024-06-16 145/week @ 2024-06-23 12/week @ 2024-06-30 40/week @ 2024-07-07 58/week @ 2024-07-14 358/week @ 2024-07-21 111/week @ 2024-07-28 194/week @ 2024-08-04 245/week @ 2024-08-11

911 每月下载量
用于 12 个 Crates (10 个直接使用)

MIT/Apache 许可

11MB
143K SLoC

C 108K SLoC // 0.2% comments Rust 27K SLoC // 0.1% comments Happy 5K SLoC FORTRAN Legacy 2.5K SLoC // 0.3% comments Batch 85 SLoC Pan 58 SLoC // 0.4% comments Bitbake 25 SLoC Shell 12 SLoC // 0.1% comments

fitsio


lib.rs:

fitsio - 对 C 库 [cfitsio][cfitsio] 的薄包装。

此库包装了低级 cfitsio 绑定:[fitsio-sys][fitsio-sys],并为 Rust 用户提供了更本地的体验。

FITS 文件的主接口是 [FitsFile][fits-file]。所有文件操作和读取都从这个类开始。

文件访问

要打开现有文件,请使用 [open][fitsfile-open] 方法。

use fitsio::FitsFile;

// let filename = ...;
let fptr = FitsFile::open(filename)?;

或者,可以使用配套方法 [create][fits-file-create] 在磁盘上创建新文件

use fitsio::FitsFile;

// let filename = ...;
let fptr = FitsFile::create(filename).open()?;

[[code][src-rs]create[fits-file-create]] 方法返回一个 [[code][src-rs]NewFitsFile[新-fits-file]],它是磁盘上临时 FITS 文件的内部表示,在文件完全创建之前。

这种表示方法有两种方法:[open][new-fits-file-open] 和 [with_custom_primary][new-fits-file-with-custom-primary]。实际上,[open][new-fits-file-open] 方法会在磁盘上创建文件,但在调用此方法之前,可以使用 [with_custom_primary][new-fits-file-with-custom-primary] 方法添加自定义的 primary HDU。这对于图像来说非常有用。否则,会创建一个默认的 primary HDU。上面展示了不添加自定义 primary HDU 的示例。下面我们看到 [with_custom_primary][new-fits-file-with-custom-primary] 的示例。

use fitsio::FitsFile;
use fitsio::images::{ImageType, ImageDescription};

// let filename = ...;
let description = ImageDescription {
data_type: ImageType::Double,
dimensions: &[52, 103],
};

let fptr = FitsFile::create(filename)
.with_custom_primary(&description)
.open()?;

从这一点开始,可以查询和更改当前 HDU,或者读取 fits 头卡或文件内容。

要以读/写模式打开 fits 文件(以允许更改文件),必须使用 [edit][fits-file-edit]。这将打开一个已存在于磁盘上的文件以进行编辑。

use fitsio::FitsFile;

// let filename = ...;
let fptr = FitsFile::edit(filename)?;

格式化打印

可以使用 [pretty_print][pretty-print] 或其更强大的同类 [pretty_write][pretty-write] 来进行 fits 文件的 pretty-print。

use fitsio::FitsFile;

let mut fptr = FitsFile::open(filename)?;
fptr.pretty_print()?;
// or
fptr.pretty_write(&mut io::stdout())?;

遵循每次发布 fits 库时都发布 fits 摘要程序的传统,这个库包含一个二进制程序 fitssummary,可以使用 cargo install 安装。它接受命令行上的 fits 文件并打印它们的摘要到 stdout。

$ fitssummary ../testdata/full_example.fits

file: ../testdata/full_example.fits
mode: READONLY
extnum hdutype      hduname    details
0      IMAGE_HDU               dimensions: [100, 100], type: Long
1      BINARY_TBL   TESTEXT    num_cols: 4, num_rows: 50

HDU 访问

HDU 信息属于 [FitsHdu][fits-hdu] 对象。可以通过 String/str 或整数(0 索引)使用 [hdu][fitsfile-hdu] 方法获取 HDU。《HduInfo》对象包含有关当前 HDU 的信息。

#
use fitsio::hdu::HduInfo;

let hdu = fptr.hdu(0)?;
// image HDU
if let HduInfo::ImageInfo { shape, .. } = hdu.info {
println!("Image is {}-dimensional", shape.len());
println!("Found image with shape {:?}", shape);
}

// tables
if let HduInfo::TableInfo { column_descriptions, num_rows, .. } = hdu.info {
println!("Table contains {} rows", num_rows);
println!("Table has {} columns", column_descriptions.len());
}

始终可以使用 FitsFile::primary_hdu 方法访问主 HDU。

创建新的 HDU

创建新的图像

使用 [create_image][fits-file-create-image] 方法创建新的 fits 图像。此方法需要扩展名和一个 [ImageDescription][image-description] 对象,该对象定义所需图像的形状和类型。

use fitsio::images::{ImageDescription, ImageType};

let image_description = ImageDescription {
data_type: ImageType::Float,
dimensions: &[100, 100],
};
let hdu = fptr.create_image("EXTNAME".to_string(), &image_description)?;

与 cfitsio 不同,new_size 的维度顺序遵循 C 规范,即 行主序

创建新的表格

与创建新图像类似,使用 [create_table][fits-file-create-table] 方法创建新表。这需要扩展名和 [ColumnDescription][column-description]s 的切片。

use fitsio::tables::{ColumnDescription, ColumnDataType};

let first_description = ColumnDescription::new("A")
.with_type(ColumnDataType::Int)
.create()?;
let second_description = ColumnDescription::new("B")
.with_type(ColumnDataType::Long)
.create()?;
let descriptions = [first_description, second_description];
let hdu = fptr.create_table("EXTNAME".to_string(), &descriptions)?;

列描述

列使用 [ColumnDescription][column-description] 结构描述。这封装了:列的名称和数据格式。

fits 规范允许标量或向量列,数据格式由 [ColumnDataDescription][column-data-description] 结构描述,该结构又封装了每行元素的数量(通常是 1)、列的宽度(对于字符串)和数据类型,数据类型是 [ColumnDataType][column-data-type] 成员之一。

对于标量列的常见情况,可以使用 scalar 方法构造 ColumnDataDescription 对象。

use fitsio::tables::{ColumnDescription, ColumnDataDescription, ColumnDataType};

let desc = ColumnDataDescription::scalar(ColumnDataType::Int);
assert_eq!(desc.repeat, 1);
assert_eq!(desc.width, 1);

可以使用 vector 方法构造向量列。

use fitsio::tables::{ColumnDataDescription, ColumnDescription, ColumnDataType};

let desc = ColumnDataDescription::vector(ColumnDataType::Int, 100);
assert_eq!(desc.repeat, 100);
assert_eq!(desc.width, 1);

这些实现 From<...> for String,以便获得传统的 fits 列描述字符串。

use fitsio::tables::{ColumnDataDescription, ColumnDescription, ColumnDataType};

let desc = ColumnDataDescription::scalar(ColumnDataType::Int);
assert_eq!(String::from(desc), "1J".to_string());

将 HDU 复制到另一个文件

可以使用 [copy_to][fits-hdu-copy-to] 方法将 HDU 复制到另一个打开的文件。这需要一个打开的 [FitsFile][fits-file] 对象来复制到。

#
#
hdu.copy_to(&mut src_fptr, &mut dest_fptr)?;

删除 HDU

当前HDU可以使用[delete][fits-hdu-delete]方法进行删除。注意:此方法会接管self的所有权,因此在此调用之后,[FitsHdu][fits-hdu]对象将无法使用。

// let fptr = FitsFile::open(...)?;
// let hdu = fptr.hdu(0)?;
hdu.delete(&mut fptr)?;
// Cannot use hdu after this

遍历文件中的 HDU

[iter][fits-hdu-iter]方法允许遍历fits文件的HDU。

for hdu in fptr.iter() {
// Do something with hdu
}

一般调用行为

后续的所有数据访问都通过[FitsHdu][fits-hdu]对象进行。大多数方法将当前打开的[FitsFile][fits-file]作为第一个参数。

头部键

通过[read_key][fits-hdu-read-key]函数读取头键,对实现[ReadsKey][reads-key]特质的类型是通用的。

let int_value: i64 = fptr.hdu(0)?.read_key(&mut fptr, "INTTEST")?;

// Alternatively
let int_value = fptr.hdu(0)?.read_key::<i64>(&mut fptr, "INTTEST")?;


// Or let the compiler infer the types (if possible)

HeaderValue也实现了[ReadsKey][reads-key]特质,并允许读取注释

let int_value_with_comment: HeaderValue<i64> = fptr.hdu(0)?.read_key(&mut fptr, "INTTEST")?;
let HeaderValue { value, comment } = int_value_with_comment;

可以通过方法[write_key][fits-hdu-write-key]写入头卡。它接受键名和值,或键名和值-注释元组。有关支持的数据类型,请参阅[WritesKey][writes-key]特质。

fptr.hdu(0)?.write_key(&mut fptr, "foo", 1i64)?;
assert_eq!(fptr.hdu(0)?.read_key::<i64>(&mut fptr, "foo")?, 1i64);

// with comments
fptr.hdu(0)?.write_key(&mut fptr, "bar", (1i64, "bar comment"))?;

let HeaderValue { value, comment } = fptr.hdu(0)?.read_key::<HeaderValue<i64>>(&mut fptr, "bar")?;
assert_eq!(value, 1i64);
assert_eq!(comment, Some("bar comment".to_string()));

读取文件数据

接受范围的方法不包括上限值,这反映了Rust范围类型的本质。

读取图像

可以通过[read_section][fits-hdu-read-section]或[read_region][fits-hdu-read-region]读取图像数据,前者读取从起始索引到结束索引之间的连续像素,后者从图像中读取矩形块。

// Read the first 100 pixels
let first_row: Vec<i32> = hdu.read_section(&mut fptr, 0, 100)?;

// Read a square section of the image
let xcoord = 0..10;
let ycoord = 0..10;
let chunk: Vec<i32> = hdu.read_region(&mut fptr, &[&ycoord, &xcoord])?;

与cfitsio不同,区域范围的顺序遵循C约定,即行主序

提供了一些方便的方法来读取图像的行。这通常是有用的,因为它是一种高效的访问方法

let start_row = 0;
let num_rows = 10;
let first_few_rows: Vec<f32> = hdu.read_rows(&mut fptr, start_row, num_rows)?;

// 10 rows of 100 columns
assert_eq!(first_few_rows.len(), 1000);

也可以将整个图像读入内存

let image_data: Vec<f32> = hdu.read_image(&mut fptr, )?;

// 100 rows of 100 columns
assert_eq!(image_data.len(), 10_000);

[ndarray][ndarray]支持

fitsio使用array功能编译时,图像可以读入[ndarray::ArrayD][arrayd]类型

use fitsio::FitsFile;
use ndarray::ArrayD;

let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
let dim = data.dim();
assert_eq!(dim[0], 100);
assert_eq!(dim[1], 100);
assert_eq!(data[[20, 5]], 152);
#

有关更多详细信息,请参阅ndarray_compat文档(仅当编译了array功能时可用)。

读取表格

可以使用[read_col][fits-hdu-read-col]函数读取列,该函数可以即时转换数据类型。有关支持的数据类型,请参阅[ReadsCol][reads-col]特质。

let integer_data: Vec<i32> = hdu.and_then(|hdu| hdu.read_col(&mut fptr, "intcol"))?;

读取单元格值

可以从FITS表中读取单个单元格值

let result: i64 = tbl_hdu.read_cell_value(&mut f, "intcol", 4)?;
assert_eq!(result, 16);

let result: String = tbl_hdu.read_cell_value(&mut f, "strcol", 4)?;
assert_eq!(result, "value4".to_string());

读取行

可以使用[row][fits-hdu-row]方法从FITS表中读取单行。这需要使用[fitsio-derive][fitsio-derive] crate。

use fitsio::tables::FitsRow;
use fitsio_derive::FitsRow;

#[derive(Default, FitsRow)]
struct Row {
#[fitsio(colname = "intcol")]
intfoo: i32,
#[fitsio(colname = "strcol")]
foobar: String,
}
#

// Pick the 4th row
let row: Row = hdu.row(&mut f, 4)?;
assert_eq!(row.intfoo, 16);
assert_eq!(row.foobar, "value4");

遍历列

使用[columns][fits-hdu-columns]迭代列。

for column in hdu.columns(&mut fptr) {
// Do something with column
}

写入文件数据

接受范围的方法不包括上限值,这反映了Rust范围类型的本质。

写入图像

图像数据通过HDU对象上的三个方法写入:[write_section][fits-hdu-write-section],[write_region][fits-hdu-write-region],和[write_image][fits-hdu-write-image]。

[write_section][fits-hdu-write-section]需要一个起始索引、结束索引以及要写入的数据。数据参数需要是一个切片,这意味着任何连续内存存储方法(例如Vec)都可以传递。

#
let data_to_write: Vec<f64> = vec![1.0, 2.0, 3.0];
hdu.write_section(&mut fptr, 0, data_to_write.len(), &data_to_write)?;

[write_region][fits-hdu-write-region]接受一个范围切片,用于指定要写入的数据,以及要写入的数据。

#
let data_to_write: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];
let ranges = [&(0..1), &(0..1)];
hdu.write_region(&mut fptr, &ranges, &data_to_write)?;

与cfitsio不同,范围的顺序遵循C约定,即行主序

[write_image][fits-hdu-write-image]将传递的所有数据(如果可能)写入图像。如果传递的数据比图像中的像素多,该方法会返回错误。

#
// Image is 3x1
assert!(hdu.write_image(&mut fptr, &[1.0, 2.0, 3.0]).is_ok());
assert!(hdu.write_image(&mut fptr, &[1.0, 2.0, 3.0, 4.0]).is_err());

调整图像大小

可以使用[resize][fits-hdu-resize]方法将图像调整到新的形状。

该方法接收打开的 [FitsFile][fits-file] 和一个 usize 值的切片。注意:目前 fitsio 只支持长度为 2 的切片,即二维图像。[resize][fits-hdu-resize] 取得 self 的所有权,迫使用户再次获取 HDU 对象。这确保了图像更改反映在新的 HDU 对象中。

use fitsio::hdu::HduInfo;

hdu.resize(&mut fptr, &[1024, 1024])?;

// Have to get the HDU again, to reflect the latest changes
let hdu = fptr.hdu(0)?;
match hdu.info {
HduInfo::ImageInfo { shape, .. } => {
assert_eq!(shape, [1024, 1024]);
}
_ => panic!("Unexpected hdu type"),
}

与 cfitsio 不同,new_size 的维度顺序遵循 C 规范,即 行主序

写入表格

写入表格数据

表格数据可以由 [write_col][fits-hdu-write-col] 或 [write_col_range][fits-hdu-write-col-range] 编写。

[write_col][fits-hdu-write-col] 将整个列的数据写入文件。它不会检查文件中有多少行,但如果数据长度超过表长度,则会扩展表格。

let data_to_write: Vec<i32> = vec![10101; 5];
hdu.write_col(&mut fptr, "bar", &data_to_write)?;
let data: Vec<i32> = hdu.read_col(&mut fptr, "bar")?;
assert_eq!(data, vec![10101, 10101, 10101, 10101, 10101]);

[write_col_range][fits-hdu-write-col-range] 将数据写入表格中的行范围。范围包括上界和下界,因此 0..4 写入 5 个元素。

let data_to_write: Vec<i32> = vec![10101; 10];
hdu.write_col_range(&mut fptr, "bar", &data_to_write, &(0..5))?;
let data: Vec<i32> = hdu.read_col(&mut fptr, "bar")?;
assert_eq!(data, vec![10101, 10101, 10101, 10101, 10101]);

插入列

HDU 对象上的两种方法允许添加新列:[append_column][fits-hdu-append-column] 和 [insert_column][fits-hdu-insert-column]。 [append_column][fits-hdu-append-column] 将新列作为最后一个列成员添加,通常更受青睐,因为它不需要在文件内移动数据。

use fitsio::tables::{ColumnDescription, ColumnDataType};

let column_description = ColumnDescription::new("abcdefg")
.with_type(ColumnDataType::Int)
.create()?;
hdu.append_column(&mut fptr, &column_description)?;

删除列

HDU 对象具有 [delete_column][fits-hdu-delete-column] 方法,可删除列。列可以通过整数或名称访问

let newhdu = hdu.delete_column(&mut fptr, "bar")?;
// or
let newhdu = hdu.delete_column(&mut fptr, 0)?;

原始 FITS 文件访问

FitsFile 转换为原始 fitsio_sys::fitsfile 指针

如果此库不支持所需的特定用例,可以访问原始 fitsfile 指针

use fitsio::FitsFile;

let mut fptr = FitsFile::open(filename)?;

/* Find out the number of HDUs in the file 

依赖项