Skip to content

Commit

Permalink
version 1.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jonclayden authored and cran-robot committed May 17, 2023
1 parent 8bf2efe commit 061833b
Show file tree
Hide file tree
Showing 23 changed files with 773 additions and 395 deletions.
10 changes: 5 additions & 5 deletions DESCRIPTION
@@ -1,6 +1,6 @@
Package: RNifti
Version: 1.4.5
Date: 2023-01-30
Version: 1.5.0
Date: 2023-05-17
Title: Fast R and C++ Access to NIfTI Images
Authors@R: c(person("Jon", "Clayden", role=c("cre","aut"),
email="code@clayden.org", comment=c(ORCID="0000-0002-6608-0619")),
Expand All @@ -25,9 +25,9 @@ License: GPL-2
URL: https://github.com/jonclayden/RNifti
BugReports: https://github.com/jonclayden/RNifti/issues
Encoding: UTF-8
RoxygenNote: 7.1.1
RoxygenNote: 7.2.3
NeedsCompilation: yes
Packaged: 2023-01-30 12:16:52 UTC; jon
Packaged: 2023-05-17 17:28:07 UTC; jon
Author: Jon Clayden [cre, aut] (<https://orcid.org/0000-0002-6608-0619>),
Bob Cox [aut],
Mark Jenkinson [aut],
Expand All @@ -38,4 +38,4 @@ Author: Jon Clayden [cre, aut] (<https://orcid.org/0000-0002-6608-0619>),
Mark Adler [cph]
Maintainer: Jon Clayden <code@clayden.org>
Repository: CRAN
Date/Publication: 2023-01-30 15:00:23 UTC
Date/Publication: 2023-05-17 18:40:02 UTC
42 changes: 22 additions & 20 deletions MD5
@@ -1,11 +1,11 @@
501ad9d93dc4640ab08dd100b01b6134 *DESCRIPTION
030b755d82fad1dbd63bd41eb66ec31c *DESCRIPTION
b94d5d2bf459e2903296147cf718349d *NAMESPACE
e29b44d29b4be4e021252388db636a95 *NEWS
07e12ab4e8595ed8041b38e48745b9db *NEWS
48127c25699df64079656e5eb7fcd1d2 *R/extensions.R
a45b6c1b24ab18fa3818f783bf93a84c *R/image.R
1ccc6cc2864f9b51e267aa0965586087 *R/nifti.R
0f3541bd599edbfd113439d69b5f693b *R/nifti.R
72db1a838f07adbc2f834ec36dd21f32 *R/rgb.R
7b690373ee13f331e6659aacf969dc6e *R/viewer.R
81e0d85d15f23b2f3d102d6760a36bc3 *R/viewer.R
3a52b438782f0fc4f0a005012ee2cba5 *R/xform.R
0b6222eb8972506a715ac81c6cce2c33 *R/zzz.R
670e72fe47adc1d9545f4fe4dfc46b21 *README.md
Expand All @@ -17,22 +17,24 @@ fb6ea71c285b8fc5d86bf53c4e104348 *inst/COPYRIGHTS
bad67894bda1a1b3b135369d6c07df6a *inst/extdata/example.nii.gz
e8547f4bc7609814adfbab6fe9c1c288 *inst/extdata/example_4d.nii.gz
c26818fcb45b7b7a9d4154d5487230e1 *inst/extdata/example_rgb.nii.gz
84e1b4e8cafbfa7cf9fa29df7391178a *inst/include/RNifti.h
f7ecf8fecfae4af654a775f645beb9c7 *inst/include/RNifti/NiftiImage.h
fca64f7adf5edf33953181e26fddf3cb *inst/include/RNifti/NiftiImage_impl.h
bdc38ee7810c9f6b00579488566ee382 *inst/include/RNifti.h
8a7db70b8aab356698e6bbb339354fda *inst/include/RNifti/NiftiImage.h
6efb974693e3c5533abf69be0662286b *inst/include/RNifti/NiftiImage_impl.h
f80b24dc1fac288092c6758dfe0b36f3 *inst/include/RNifti/NiftiImage_matrix.h
f930d3f1090d3f9bb525ebc114e3410d *inst/include/RNifti/NiftiImage_print.h
f4977d022d20116ad6de603a6eae33f8 *inst/include/RNiftiAPI.h
5c27ee344ffd98bbc8247bb98eab5707 *inst/include/niftilib/nifti1.h
18fdbf10622d5791d3d7d9fa904926d4 *inst/include/niftilib/nifti1_io.h
1e78c6fe8591ba1351347637b471aa4f *inst/include/niftilib/nifti2.h
409773045b5711a7c6e64c03b7fc9502 *inst/include/RNiftiAPI.h
362304addec3a503d8fd3813c4bbb661 *inst/include/niftilib/nifti1.h
1ca71b52a4f8fdf28c29f58ffebbfb0a *inst/include/niftilib/nifti1_io.h
dcb17e044c762a6a753b7cbef3d8e63c *inst/include/niftilib/nifti1_io_version.h
f3b89c12d91297deee7a2b1cf27d41d7 *inst/include/niftilib/nifti2.h
4e373c9b99d88d0019a2ea3da10e7330 *inst/include/niftilib/nifti2_image.h
6a4912a66ba9826d046a309fd38b13b9 *inst/include/niftilib/nifti2_io.h
59a3d4d90a3c6f2f1577e59b130850fb *inst/include/niftilib/nifti2_io.h
d3ab930e9ad209cc857a839d2e080ebc *inst/include/niftilib/nifti2_io_version.h
5407d4c937d8f925665f71aad35c12fa *inst/include/zlib/zconf.h
1c128a3b0a0fd84c1224754170ee7756 *inst/include/zlib/zlib.h
e51db52b9a30fa3dcf02389ffc59e481 *inst/include/znzlib/znzlib.h
b832290b2ff8ffe44114b4e86475f301 *inst/include/znzlib/znzlib.h
ee8949e3b781480b0201286063b5c2ac *man/ExtensionCodes.Rd
6311555f9c2515dcf499e724444cefc0 *man/asNifti.Rd
8ecefba81cb4bce311f77e0cb0e7d865 *man/asNifti.Rd
89095e599895dbb1547cfc9159d447f1 *man/channels.Rd
be666b838be37f46f6f12bffc58768c9 *man/defaultInfoPanel.Rd
f62cda6e04dc9e2216c24227eac3c1c0 *man/extensions.Rd
Expand All @@ -46,13 +48,13 @@ bdff7a46d55ff74e148f797da7af245a *man/readNifti.Rd
c358d9190aa467ec5318fd93c8053ffb *man/rgbArray.Rd
dfef27c9fc33dc654e3e1cb2cdbb1464 *man/view.Rd
7f366aa4296dae452fb39f3131e3cf38 *man/voxelToWorld.Rd
6308599804fe32d47684fd143cddfbf7 *man/writeNifti.Rd
d1e37db347a3cdf2329fe98282c554d5 *man/writeNifti.Rd
cd7905d91c416d05dc58c980254711fb *man/xform.Rd
8e06de557abf2608ef1d50c13753683c *src/Makevars.in
49abe6af876df7ba9299e3eda904dc59 *src/Makevars.win
111c7df0b4b0ddeb4d3fefd905ccb7e4 *src/main.cpp
fd7b7f93e99af66ae44bc1d9bce4fa38 *src/niftilib/nifti1_io.c
0d0cb01180820b5c362be311ead29f23 *src/niftilib/nifti2_io.c
e4dfc0209ead15da5a16e1adc10c691d *src/main.cpp
aab0540996c17f146a7934001c8fab54 *src/niftilib/nifti1_io.c
824ae11a61b2cd5d07e4e39e62e8a346 *src/niftilib/nifti2_io.c
ae3bbb54820e1d49fb90cbba222e973f *src/zlib/adler32.c
7a734598f9792fee943b70b6da8d932f *src/zlib/compress.c
1339c92938d2594a6eecfa21c374d1b6 *src/zlib/crc32.c
Expand All @@ -77,8 +79,8 @@ bc195d555c24fecff56af6c06bd55b1d *src/zlib/trees.c
eabe905cdd27f5b935e6378cd0253418 *src/zlib/uncompr.c
fff257bc1656eb60fc585a7dc35f963d *src/zlib/zutil.c
de91a463004fd5b944c3d37eab0c1794 *src/zlib/zutil.h
4a10f0020c941e296f9d46b65562e06e *src/znzlib/znzlib.c
5b232f6f0c0a89b39f22120a70ba5ebe *src/zzz.c
420a0b8e9d75cd936a6d08acd1e7bf34 *src/znzlib/znzlib.c
2960da031fea46eaffe3e3abedb78f29 *src/zzz.c
d4a2abbb6217055b8900c8d86ac6aa53 *tests/testthat.R
9b78b59582b4b2dfdab2c3124c705535 *tests/testthat/test-05-nifti.R
923f10fc2c56863736b67257909b4e19 *tests/testthat/test-08-composite.R
Expand Down
17 changes: 17 additions & 0 deletions NEWS
Expand Up @@ -2,6 +2,23 @@ Significant changes to the RNifti package are laid out below for each release.

===============================================================================

VERSION 1.5.0

- The `writeNifti()` and `writeAnalyze()` functions gain a "compression"
argument to control the compression level used when writing gzipped images.
- The viewer will now show 4D images with fourth dimension 3 as vectors if the
`RNifti.d4vectors` option is `TRUE`. This is off by default (following the
previous behaviour) as it's less explicit than an image with a vector intent.
- The `niftiHeader()` function will no longer call `asNifti()` on an argument
that looks like a path, as this will wastefully read in the pixel data when
only the metadata is needed.
- Support for `MriImage` objects with complex or RGB types has been added.
- `cfloat` and `cdouble` are now additionally accepted as datatypes for 32-bit
and 64-bit floating-point complex types, respectively.
- The upstream NIfTI libraries have been updated.

===============================================================================

VERSION 1.4.5

- The package now works around the deprecation of `std::iterator` in C++17.
Expand Down
27 changes: 20 additions & 7 deletions R/nifti.R
Expand Up @@ -54,8 +54,14 @@ readNifti <- readAnalyze <- function (file, internal = FALSE, volumes = NULL)
#' using the standard NIfTI C library.
#'
#' @param image An image, in any acceptable form (see \code{\link{asNifti}}).
#' @param file A character string containing a file name.
#' @param template An optional template object to derive NIfTI-1 properties
#' @param file A character string containing a file name. If this has no file
#' extension suffix, or ends with \code{"nii"}, the single-file NIfTI format
#' is used; if the suffix is \code{"nii.gz"}, the compressed single-file
#' format is used; if the suffix is \code{"hdr"} or \code{"img"}, the NIfTI
#' pair two-file format is used; if it's \code{"hdr.gz"} or \code{"img.gz"},
#' the compressed pair format is used. If any other extension is present it
#' will be ignored, and \code{".nii"} appended.
#' @param template An optional template object to derive NIfTI properties
#' from. Passed to \code{\link{asNifti}} if \code{image} is an array.
#' @param datatype The NIfTI datatype to use when writing the data out. The
#' default, \code{"auto"} uses the R type or, for internal images, the
Expand All @@ -66,6 +72,9 @@ readNifti <- readAnalyze <- function (file, internal = FALSE, volumes = NULL)
#' use. Version 2 is usually only needed for very large images or where
#' metadata needs to be stored with high precision. The types available for
#' storing the pixel data are the same in both cases.
#' @param compression The gzip compression level to use, an integer between 0
#' (none) and 9 (maximum). Ignored if an uncompressed format is implied by
#' the requested file name.
#' @return An invisible, named character vector giving the image and header
#' file names written to.
#'
Expand All @@ -80,16 +89,16 @@ readNifti <- readAnalyze <- function (file, internal = FALSE, volumes = NULL)
#' @seealso \code{\link{readNifti}}, \code{\link{asNifti}}
#' @references The NIfTI-1 standard (\url{https://www.nitrc.org/docman/view.php/26/64/nifti1.h}).
#' @export
writeNifti <- function (image, file, template = NULL, datatype = "auto", version = 1)
writeNifti <- function (image, file, template = NULL, datatype = "auto", version = 1, compression = 6)
{
invisible(.Call("writeNifti", asNifti(image,template,internal=TRUE), file, tolower(datatype), switch(version,"nifti1","nifti2"), PACKAGE="RNifti"))
invisible(.Call("writeNifti", asNifti(image,template,internal=TRUE), file, tolower(datatype), switch(version,"nifti1","nifti2"), compression, PACKAGE="RNifti"))
}

#' @rdname writeNifti
#' @export
writeAnalyze <- function (image, file, template = NULL, datatype = "auto")
writeAnalyze <- function (image, file, template = NULL, datatype = "auto", compression = 6)
{
invisible(.Call("writeNifti", asNifti(image,template,internal=TRUE), file, tolower(datatype), "analyze", PACKAGE="RNifti"))
invisible(.Call("writeNifti", asNifti(image,template,internal=TRUE), file, tolower(datatype), "analyze", compression, PACKAGE="RNifti"))
}

#' Create or modify an NIfTI image object
Expand Down Expand Up @@ -239,7 +248,11 @@ updateNifti <- function (image, template = NULL, datatype = "auto")
#' @export niftiHeader dumpNifti
niftiHeader <- dumpNifti <- function (image = list())
{
.Call("niftiHeader", asNifti(image,internal=TRUE), PACKAGE="RNifti")
# Special case to avoid expensively reading image data from file when only metadata is needed
if (is.character(image) && length(image) == 1 && !inherits(image,"internalImage"))
.Call("niftiHeader", image, PACKAGE="RNifti")
else
.Call("niftiHeader", asNifti(image,internal=TRUE), PACKAGE="RNifti")
}

#' @rdname niftiHeader
Expand Down
24 changes: 13 additions & 11 deletions R/viewer.R
@@ -1,31 +1,33 @@
.State <- new.env()

.is3DVector <- function (image)
.vector3Dim <- function (image)
{
return (image$intent_code == 1007L && ndim(image) == 5L && dim(image)[5] == 3L)
if (image$intent_code == 1007L && ndim(image) == 5L && dim(image)[5] == 3L)
return (5L)
else if (getOption("RNifti.d4vectors",FALSE) && ndim(image) == 4L && dim(image)[4] == 3L)
return (4L)
else
return (NA_integer_)
}

.plotLayer <- function (layer, loc, asp = NULL, add = FALSE)
{
is3DVector <- .is3DVector(layer$image)
vector3Dim <- .vector3Dim(layer$image)

# Extract the data for the appropriate plane
axis <- which(!is.na(loc))
indices <- alist(i=, j=, k=, t=1, u=1, v=1, w=1)
if (is3DVector)
indices[[5]] <- 1:3
if (!is.na(vector3Dim))
indices[[vector3Dim]] <- 1:3
indices[[axis]] <- loc[axis]
data <- do.call("[", c(layer["image"], indices[seq_len(ndim(layer$image))], list(drop=FALSE)))
if (is3DVector)
dims <- dim(data)[-c(axis,4,6,7)]
else
dims <- dim(data)[-c(axis,4:7)]
dims <- dim(data)[-c(axis, setdiff(4:7,vector3Dim))]
dim(data) <- dims

if (is.null(asp))
asp <- dims[2] / dims[1]

if (is3DVector)
if (!is.na(vector3Dim))
{
# Show 3D vector data as coloured line segments
if (!add)
Expand Down Expand Up @@ -326,7 +328,7 @@ lyr <- function (image, scale = "grey", min = NULL, max = NULL, mask = NULL)
message("Setting window to (", signif(window[1],4), ", ", signif(window[2],4), ")")
}

if (!.is3DVector(image))
if (is.na(.vector3Dim(image)))
{
image[image < window[1]] <- window[1]
image[image > window[2]] <- window[2]
Expand Down
2 changes: 1 addition & 1 deletion inst/include/RNifti.h
Expand Up @@ -8,7 +8,7 @@

// Defined since RNifti v0.10.0, and equal to 100 * (major version) + (minor version). May not
// change if the API does not change, and in particular never changes with patch level
#define RNIFTI_VERSION 104
#define RNIFTI_VERSION 105

// Versions 1 and 2 of the NIfTI reference library are mutually incompatible, but RNifti does some
// work to get them to play nicely:
Expand Down
8 changes: 6 additions & 2 deletions inst/include/RNifti/NiftiImage.h
Expand Up @@ -1907,19 +1907,23 @@ class NiftiImage
* @param datatype The datatype to use when writing the file
* @param filetype The file type to create: a \c NIFTI_FTYPE constant or -1. In the latter case
* the file name is used to determine the file type
* @param compression The \c zlib compression level to use, if appropriate. Valid values are
* between 0 and 9
* @return A pair of strings, giving the final header and image paths in that order
**/
std::pair<std::string,std::string> toFile (const std::string fileName, const int datatype = DT_NONE, const int filetype = -1) const;
std::pair<std::string,std::string> toFile (const std::string fileName, const int datatype = DT_NONE, const int filetype = -1, const int compression = 6) const;

/**
* Write the image to a NIfTI-1 file
* @param fileName The file name to write to, with appropriate suffix (e.g. ".nii.gz")
* @param datatype The datatype to use when writing the file, or "auto"
* @param filetype The file type to create: a \c NIFTI_FTYPE constant or -1. In the latter case
* the file name is used to determine the file type
* @param compression The \c zlib compression level to use, if appropriate. Valid values are
* between 0 and 9
* @return A pair of strings, giving the final header and image paths in that order
**/
std::pair<std::string,std::string> toFile (const std::string fileName, const std::string &datatype, const int filetype = -1) const;
std::pair<std::string,std::string> toFile (const std::string fileName, const std::string &datatype, const int filetype = -1, const int compression = 6) const;

#ifdef USING_R

Expand Down
39 changes: 30 additions & 9 deletions inst/include/RNifti/NiftiImage_impl.h
Expand Up @@ -76,7 +76,9 @@ inline int stringToDatatype (const std::string &datatype)
datatypeCodes["uint32"] = DT_UINT32;
datatypeCodes["int64"] = DT_INT64;
datatypeCodes["uint64"] = DT_UINT64;
datatypeCodes["cfloat"] = DT_COMPLEX64;
datatypeCodes["complex64"] = DT_COMPLEX64;
datatypeCodes["cdouble"] = DT_COMPLEX128;
datatypeCodes["complex128"] = DT_COMPLEX128;
datatypeCodes["complex"] = DT_COMPLEX128;
datatypeCodes["rgb24"] = DT_RGB24;
Expand Down Expand Up @@ -933,7 +935,12 @@ inline void NiftiImage::initFromMriImage (const Rcpp::RObject &object, const boo
data = call.eval();
}

const int datatype = (Rf_isNull(data) ? DT_INT32 : sexpTypeToNiftiType(data.sexp_type()));
int datatype = (Rf_isNull(data) ? DT_INT32 : sexpTypeToNiftiType(data.sexp_type()));
if (data.inherits("rgbArray"))
{
const int channels = (data.hasAttribute("channels") ? data.attr("channels") : 3);
datatype = (channels == 4 ? DT_RGBA32 : DT_RGB24);
}

dim_t dims[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
const std::vector<dim_t> dimVector = mriImage.field("imageDims");
Expand Down Expand Up @@ -966,8 +973,15 @@ inline void NiftiImage::initFromMriImage (const Rcpp::RObject &object, const boo
// NB: nifti_get_volsize() will not be right here if there were tags
const size_t dataSize = nVoxels * image->nbyper;
this->image->data = calloc(1, dataSize);
if (datatype == DT_INT32)
if (datatype == DT_INT32 || datatype == DT_RGBA32)
memcpy(this->image->data, INTEGER(data), dataSize);
else if (datatype == DT_RGB24)
{
NiftiImageData newData(image);
std::copy(INTEGER(data), INTEGER(data)+nVoxels, newData.begin());
}
else if (datatype == DT_COMPLEX128)
memcpy(this->image->data, COMPLEX(data), dataSize);
else
memcpy(this->image->data, REAL(data), dataSize);
}
Expand Down Expand Up @@ -1792,7 +1806,7 @@ inline NiftiImage & NiftiImage::replaceData (const NiftiImageData &data)
return *this;
}

inline std::pair<std::string,std::string> NiftiImage::toFile (const std::string fileName, const int datatype, const int filetype) const
inline std::pair<std::string,std::string> NiftiImage::toFile (const std::string fileName, const int datatype, const int filetype, const int compression) const
{
const bool changingDatatype = (datatype != DT_NONE && !this->isNull() && datatype != image->datatype);

Expand All @@ -1804,24 +1818,31 @@ inline std::pair<std::string,std::string> NiftiImage::toFile (const std::string
if (filetype >= 0 && filetype <= NIFTI_MAX_FTYPE)
imageToWrite->nifti_type = filetype;

const char *path = internal::stringToPath(fileName);

// If we're writing a gzipped file (only), append a compression level to the mode string
std::string mode = "wb";
if (nifti_is_gzfile(path) && compression >= 0 && compression <= 9)
mode += std::to_string(compression);

#if RNIFTI_NIFTILIB_VERSION == 1
const int status = nifti_set_filenames(imageToWrite, internal::stringToPath(fileName), false, true);
const int status = nifti_set_filenames(imageToWrite, path, false, true);
if (status != 0)
throw std::runtime_error("Failed to set filenames for NIfTI object");
nifti_image_write(imageToWrite);
nifti_image_write_hdr_img(imageToWrite, 1, mode.c_str());
#elif RNIFTI_NIFTILIB_VERSION == 2
const int status = nifti2_set_filenames(imageToWrite, internal::stringToPath(fileName), false, true);
const int status = nifti2_set_filenames(imageToWrite, path, false, true);
if (status != 0)
throw std::runtime_error("Failed to set filenames for NIfTI object");
nifti2_image_write(imageToWrite);
nifti2_image_write_hdr_img(imageToWrite, 1, mode.c_str());
#endif

return std::pair<std::string,std::string>(std::string(imageToWrite->fname), std::string(imageToWrite->iname));
}

inline std::pair<std::string,std::string> NiftiImage::toFile (const std::string fileName, const std::string &datatype, const int filetype) const
inline std::pair<std::string,std::string> NiftiImage::toFile (const std::string fileName, const std::string &datatype, const int filetype, const int compression) const
{
return toFile(fileName, internal::stringToDatatype(datatype), filetype);
return toFile(fileName, internal::stringToDatatype(datatype), filetype, compression);
}

#ifdef USING_R
Expand Down

0 comments on commit 061833b

Please sign in to comment.