Significant changes to the RNifti package are laid out below for each release.

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

VERSION 1.10.0

R interface

- Methods for `asNifti()` are now discoverable by the package's C++ core, which
  significantly reduces the need to call the function explicitly, which in turn
  can save some data copying. The `reference` argument is no longer part of the
  generic's signature. Conversion of `"nifti"` and `"MriImage"` objects, from
  the `oro.nifti` and `tractor.base` packages, respectively, is now performed
  by pure-R methods rather than being hardcoded into the C++ layer, a change
  which ends up being performance-neutral (or even an improvement) due to fewer
  calls into the R API.
- `lyr()` gains new `label`, `alpha` and `dict` arguments, for naming a layer
  explicitly (rather than relying on argument deparsing), setting layer opacity
  and mapping intensity values to arbitrary text, respectively. Its `scale`
  argument may now be a named vector, which is used as a discrete colour lookup
  table keyed by intensity value, rather than a continuous colour scale.
- Assigning pixel dimensions with `pixdim<-` now produces an error if the
  replacement value's length doesn't match the image's dimensionality, rather
  than silently applying it incorrectly.
- Setting the world-coordinate transformation of a `niftiHeader` object with
  `qform<-` or `sform<-` no longer has the side effect of overwriting its pixel
  dimensions, except for the sign of the first element (the "qfac").
- `writeNifti()`'s `version` argument is now validated, and may be given as a
  string (`"1"` or `"2"`) as well as numerically.
- Assigning to `imageAttributes()` now produces a warning, rather than
  silently doing nothing, if the assignment would overwrite a core NIfTI
  attribute. It also now works correctly when the target object has no
  pre-existing attributes.
- The `mean()` method for internal images now uses the same C++ back-end as the
  `Summary` group generic, thereby avoiding first converting the image to a
  full array.

API changes

- A bug in the `acquire()`/`release()` reference-counting cycle in the
  `NiftiImage` C++ class has been fixed. Previously, changing the pointer
  wrapped by a `NiftiImage` object by copy-assignment could decrement the wrong
  reference counter, risking a premature deallocation. `acquire()` now takes an
  optional existing reference counter to take over, rather than relying on it
  having already been set as a side effect by the caller.
- Converting a NIfTI-2 image containing more voxels than a NIfTI-1 image can
  represent now fails with an informative error, rather than silently
  overflowing.

Other changes

- Reading corrupt or truncated image data now produces clearer, more
  informative errors.
- A memory leak affecting the internal per-datatype handler on copy
  assignment of a `NiftiImage`, and undefined behaviour arising from use of
  an iterator after erasing the element it points to, have both been fixed.
- C++ exceptions are now consistently raised using `Rcpp::stop()` rather than
  `Rf_error()`, ensuring correct stack unwinding.

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

VERSION 1.9.0

- Methods for the `Math`, `Ops`, `Complex` and `Summary` group generics have
  been added for the `internalImage` class, as well as `is.na()` and `mean()`.
  This prevents R from falling back on the `character` methods, which aren't
  helpful. In most cases these implementations simply call the relevant generic
  on the array version of the image; the exception is `Summary`, which calls a
  C++ implementation to avoid allocating memory for an R array when only a
  summary value is needed. (Reported by Martin Wilson, issue #39 and `divest`
  issue #6.)
- Image value range calculation and NA handling in the core C++ code has been
  improved, particularly for the 32-bit integer datatype.

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

VERSION 1.8.0

- It is now possible to read, write and manipulate additional image metadata
  fields stored in JSON "sidecar" files like those used by the [Brain Imaging
  Data Structure](https://bids.neuroimaging.io). `readNifti` and `writeNifti`
  each gain a "json" argument, and the new `imageAttributes` function can be
  used to get and set attributes for images. Conversion to or from JSON
  requires the [`jsonlite`](https://github.com/jeroen/jsonlite) package; this
  is an R-only feature for now.
- If a plain string is passed to `lyr` as the "scale" argument and doesn't
  match a known scale name from the `shades` package, it is now assumed to be
  a single literal colour name. (Prompted by Ellyn Butler, issue #36.)
- Initialisation of the complex `NA` value in C++ code has been simplified to
  avoid remaining compilation problems on some platforms. (Issues #35 and #38.)

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

VERSION 1.7.0

- Indexing into an `rgbArray` or an RGB-valued `internalImage` now produces a
  result of type `rgbArray`, to maintain the special interpretation of these
  values, and facilitate conversion to strings.
- `rgbArray` now also gains an `as.raster` method.
- The test suite has been moved from `testthat` to `tinytest`.
- An API accommodation for versions of R before 3.1.0 has now been removed, as
  it produces a note in the current R-devel.

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

VERSION 1.6.1

- A misaligned memory read caught by clang-UBSan has been corrected.

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

VERSION 1.6.0

R interface

- The `niftiHeader()` function gains an "unused" argument. If `TRUE`, the
  function's return value includes those legacy ANALYZE-7.5 fields that are
  formally unused by the NIfTI-1 standard (or the last few bytes of a NIfTI-2
  header). These fields cannot be set, however, as the `niftilib` I/O functions
  discard them, and the core `nifti_image` structure does not represent them.
  They also cannot be accessed with the `$` operator shorthand. The option is
  therefore only useful to inspect file headers created by other software.

API changes

- The `NiftiImage` class now has constructors taking a NIfTI header structure.

Other changes

- The `NiftiImageData::Iterator` inner class now holds a pointer, not a
  reference, to its parent. This doesn't really change the API, but ensures
  that iterator objects are mutable, which is formally required by the C++
  standard. (Prompted by Timothy Anderson, issue #31.)
- There is now support for standalone use on Windows with the Visual C++
  toolchain, including an `nmake`-compatible makefile, and this is now tested
  as part of package CI. The package also no longer includes symlinks, for
  better portability. (Prompted by Timothy Anderson, issue #31.)
- The bundled `zlib` is now version 1.3. The included `zlib` headers are no
  longer exposed to client packages if the system `zlib` is used for linkage,
  as the two may be incompatible.

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

VERSION 1.5.1

- Several warnings from recent compilers relating to printf-style format
  strings have been resolved.

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

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.

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

VERSION 1.4.4

- Calls to the unsafe C function `sprintf()` have been removed or worked
  around, as required for the next minor R release.

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

VERSION 1.4.3

- Resolved one further non-prototype function declaration warning.

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

VERSION 1.4.2

- Warnings about non-prototype function declarations (in clang 15+) have been
  resolved.

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

VERSION 1.4.1

- A formatting oversight would previously lead to an invalid `Makevars` file on
  systems without a (findable) system `zlib`. This has been corrected.
  (Reported by @casparms, issue #26).
- Package `cleanup` scripts now also remove the derived `Makevars` file.
- Performance data in the package README has been updated to use newer package
  versions.

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

VERSION 1.4.0

- xform matrices now have an `imagedim` attribute containing the image
  dimensions. This allows the origin to be preserved accurately through
  reorientation without reference to the rest of the header.
- The package now uses a `configure` script to check for and find the system
  `zlib`, which will be used in preference to the bundled version where
  available.
- Additional documentation of standalone use of the code (without R) has been
  added to the package repository. (Suggested by Rashid Kratou.)

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

VERSION 1.3.1

- The API version number RNIFTI_VERSION was erroneously not updated in v1.3.0.
  This has been corrected.
- The `nifti2_image_to_ascii()` `niftilib` function has been made unavailable to
  client R packages for now, while a portability issue is explored. Calling it
  will now produce an R error. This does not affect the version of the function
  from version 1 of `niftilib`, as it relates only to NIfTI-2 wide types.
- A new hidden function has been added for reading data elements directly from
  a file. This is currently experimental, is not (yet) meant for downstream
  use.

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

VERSION 1.3.0

R interface

- There are new functions for working with NIfTI extensions, either wholesale
  or one by one. These allow extended metadata to be stored within a NIfTI-1 or
  NIfTI-2 format file, but are weakly specified. Their "native" representation
  in R is a raw byte stream, but the package performs some conversion to/from
  other atomic vector types for convenience. See `?extensions` for details.

API changes

- There is a new inner class, `NiftiImage::Extension`, which represents a NIfTI
  extension. New methods to `NiftiImage` can be used to add, remove and replace
  extensions for a given image.

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

VERSION 1.2.3

- Compiler warnings from some API functions have been resolved.

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

VERSION 1.2.2

- The distinction between `NaN` and `NA` double values is now preserved more
  reliably when copying voxel data from one blob to another. (Reported by John
  Muschelli, issue #21.)
- It is now possible to use the `initFromDims()` C++ method in non-R API
  clients, which was previously unavailable because of an oversight. (Patch
  from Tom Wilkinson, PR #20.)
- `niftiVersion()` should once again return -1 for missing and invalid files,
  as documented. There are now also regression tests for this behaviour.
- Image xforms created from `MriImage` objects will no longer be implicitly
  transposed in the process.
- The special treatment of character-mode arguments to `analyzeHeader()` has
  been reinstated, but is now more careful to avoid misinterpreting internal
  images. More details of its behaviour may be found in the documentation.
- A header required on some platforms was not previously included, which could
  lead to API client packages failing to compile. This has been corrected.

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

VERSION 1.2.1

- A type inconsistency that could lead to segmentation faults in client
  packages on certain platforms has been resolved.
- Other compiler and sanitiser warnings have been resolved.

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

VERSION 1.2.0

General

- With this release, `RNifti`'s core code moves over to the NIfTI-2 library.
  Reading and writing NIfTI-2 format files is therefore supported. API clients
  may use either version of the NIfTI library.

R interface

- The `asNifti()` function is now S3 generic, with the default method handling
  all objects that the package has supported to date. Packages can therefore
  define additional methods for their objects.
- The `writeNifti()` function gains a version argument, which allows NIfTI-2 to
  be used as the output file format if required. (NIfTI-1 remains the default.)
- A new `writeAnalyze()` function has been added, for writing to the legacy
  ANALYZE-7.5 format (although this is not recommended, except where needed for
  compatibility). A corresponding `readAnalyze()` function has also been added
  for symmetry, but this is just an alias for `readNifti()`.

API changes

- The NIfTI-2 library is now included with the package, and available through
  the API. A number of patches have been made to this version of the library
  to ensure that it can generate valid NIfTI-2 format files upon request (see
  <https://github.com/NIFTI-Imaging/nifti_clib/pull/124> for details of the
  upstream pull request).
- The package goes to some lengths to allow the mutually incompatible NIfTI-1
  and NIfTI-2 libraries to coexist. The library version that API clients will
  see depends on the value of the `RNIFTI_NIFTILIB_VERSION` compile-time
  constant (default 1), which should be set before including `RNifti.h`.
  See the comments in that header file for fuller documentation. Stub clients
  using each version of the `niftilib` library are included in the `clients`
  subdirectory for illustration (and for testing).
- The API now makes the full set of public `niftilib` functions available to
  clients. Previously only a group of the most commonly used were included.
- C++ classes `Vector` and `SquareMatrix` have been created to provide an
  object-oriented wrapper around some of the `niftilib` matrix functions, and
  to abstract away the type width differences between the two versions of the
  library.
- Type aliases which handle the differences between `niftilib` versions, such
  as `NiftiImage::dim_t` and `NiftiImage::pixdim_t`, are now used in various
  places in the API.
- An `Xform` inner class within `NiftiImage` now encapsulates an xform, and
  provides a number of conveniences. The `xform()` method of `NiftiImage` now
  returns this type rather than a `niftilib`-native type (although `Xform` can
  be implicitly converted and hence treated as before), and new `sform()` and
  `qform()` methods have been added, which allow the image sform/qform to be
  specifically obtained or replaced.
- The static `xformToRotation()` and `xformToString()` methods of `NiftiImage`
  have been removed and replaced by methods of `NiftiImage::Xform`.
- The `headerToList()` method of `NiftiImage` has been removed, since its
  functionality was rather specific to the `RNifti` R package.

Bug fixes

- The `niftiHeader()` and `analyzeHeader()` functions will now return `NULL`
  for `NULL` input, rather than potentially segfaulting.
- The `analyzeHeader()` R function no longer misinterprets internal image
  objects as file paths.
- `Rcpp` no longer throws an exception when an invalid image pointer is seen,
  which prevented `RNifti` from handling this scenario in its own way.

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

VERSION 1.1.0

- An alternative info panel for showing time series data (`timeSeriesPanel`) is
  now available for use with suitable 4D images.
- The info panel no longer prompts to leave interactive mode when that mode is
  not in use. The info panel may now also be suppressed entirely by specifying
  `NULL` instead of a panel function.
- The viewer will now display 3D vector fields (specifically, 5D images with
  fifth dimension equal to 3 and intent code equal to 1007) as a series of line
  segments, colour-coded by orientation.
- The `lyr()` function gains a mask argument, which masks the zero-valued
  pixels in the mask out of that layer by setting their values to `NA`.
- The `rgbArray()` function now always sets the `dim` attribute of its return
  value, using the length of its first argument if it has no `dim` attribute
  of its own (and the `dim` argument is not specified).

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

VERSION 1.0.1

- The package no longer has an undeclared requirement for C++11 support.
  (Reported by John Muschelli, issue #16.)
- String manipulation performed within the `view()` function is now compatible
  with versions of R older than 3.6.0.

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

VERSION 1.0.0

R interface

- A basic image viewer with optional interactivity has been added to the
  package, and is accessible through the new `view()` function.
- The package now supports complex and RGB NIfTI datatypes. Complex values
  are transformed to the built in complex R type, while RGB values are
  represented in a byte-packed integer form, with new functions to convert to
  and from this form. See `?rgbArray` for details.
- The `retrieveNifti()` and `updateNifti()` functions have been soft-deprecated
  in favour of the new `asNifti()`, which does the work of both of them.
- Standard (non-internal) images no longer retain a copy of their data
  internally as well as in the R-visible array, to save memory. This is safe
  because the latter always overrides the former anyway. (Inspired by issue
  #14.)
- The list returned by `niftiHeader()` now includes attributes describing the
  meanings of metadata codes such as xform codes, and these are now shown by
  the `print` method for these objects.
- The `xform()` function now attaches a `code` attribute to its return value.
- `writeNifti()` now return the final header and image paths written,
  invisibly. (Suggested by John Muschelli, PR #15.)
- The R path expansion API is now used in the C++ code, so tilde expansion (for
  example) should now be universally supported.

API changes

- Complex and RGB datatype support is now available through the API. As a
  result, the `isComplex()` and `isRgb()` methods of the `NiftiImageData` class
  no longer always return `false`.
- A basic `NiftiImage` constructor that initialises an image from a vector of
  dimensions and a datatype has been added.
- New `nChannels()` (for number of colour channels; 1 except for RGB/RGBA
  images) and `nVoxels()` methods have been added to the `NiftiImage` class.
- The `toFile()` methods now return a pair of strings giving the final header
  and image file names, rather than nothing.

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

VERSION 0.11.1

- Attempting to update image header fields with values of the wrong length
  (e.g. through `updateNifti`) now results in a warning or error. See the
  documentation for that R function for further details.

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

VERSION 0.11.0

R interface

- It is now possible to index directly into objects of class `internalImage`,
  meaning that individual elements or arbitrary blocks may be converted to R
  vectors or arrays, without needing to convert everything. This can save
  significant amounts of memory for large images.

API changes

- This release introduces the `NiftiImageData` C++ class as the main way to
  encapsulate the data in a NIfTI image. This class handles datatypes and data
  scaling, and provides indexing, iterators and other niceties. The doxygen
  documentation has full details.
- As a result of this new introduction, the templated `getData()` method within
  `NiftiImage` is deprecated in favour of `data()`, which returns a (constant
  or mutable) object of class `NiftiImageData` rather than a standard `vector`.

Bug fixes

- The slope and intercept fields in `nifti` objects (from the `oro.nifti`
  package) are now ignored, since that package does its own scaling. (Reported
  by John Muschelli, issue #13.)

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

VERSION 0.10.0

R interface

- Objects of class `niftiHeader`, created by the function of the same name,
  now also have core attributes such as `pixdim` and `pixunits`.
- Passing objects without a `dim` or `class` attribute to functions expecting
  an image will now produce a more informative error message.

API changes

- The `NiftiImage` class now uses a reference counting scheme, rather than
  relying on a simple persistence flag. (See the doxygen documentation for more
  details.) The `isPersistent` and `setPersistence` methods are therefore
  deprecated, with the former replaced by `isShared`.
- Images are no longer internally duplicated when being passed back to R. This
  improves the package's memory footprint, but performing an explicit copy may
  now be necessary in some circumstances, e.g., if the image's memory will be
  freed elsewhere.
- The `RNIFTI_VERSION` constant is now defined, as 100 * (major version) +
  (minor version). Its current value is therefore 10.
- The `niftilib` function `nifti_strdup` is now part of the package API.

Bug fixes

- The `pixdim()` and `pixunits()` functions will now work properly for path
  strings and other objects acceptable to `niftiHeader()`. (Reported by John
  Muschelli.)
- Other, smaller memory leaks have been resolved.

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

VERSION 0.9.0

- When writing an image using an integer datatype, the scale and slope fields
  will now be set if the original values are outside the representable range of
  that datatype. This ensures that the voxel values are accurate when read back
  from the file (although some precision may, necessarily, be lost). This makes
  the datatype argument to writeNifti() more generally useful for file size
  reduction.
- The dumpNifti() function has been soft-deprecated in favour of niftiHeader(),
  which works the same way. There is also a new analyzeHeader() function, which
  returns a list giving the header elements when interpreted according to the
  ANALYZE-7.5 format. Both functions now return a default header when given no
  argument.
- The $ operator can now be used on "niftiImage" objects as a shorthand way to
  get or set individual header fields.
- The qform and sform replacement functions now work on lists of class
  "niftiHeader".
- The new rotation() function extracts just a pure 3x3 rotation matrix from an
  image xform or general affine.
- Functions such as origin() and orientation() now also work directly on xform-
  like numeric matrices.
- The offset part of an image's xform matrix (the fourth column) is now
  properly updated when the image is reoriented. Reorientation should also now
  work correctly for all possible permutations.
- NA and NaN values are no longer removed from images on reading.
- The pixdim attribute should now always contain the absolute values of the
  pixdim for each dimension.

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

VERSION 0.8.1

- A C-level namespace clash on certain platforms has been corrected.

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

VERSION 0.8.0

- The new niftiVersion() function identifies the NIfTI format variant used by
  files on disk.
- The readNifti() function gains an option which allows only certain volumes
  to be read from disk.
- The updateNifti() function gains an option to set the internal datatype, for
  advanced usage only (issue #8).
- Calling updateNifti() with a list containing only a few fields could
  previously reset the remaining metadata to the defaults. This has been
  corrected.
- It is now possible to change the cal_min and cal_max fields with the
  updateNifti() function (issue #9). The scl_slope and scl_inter fields cannot
  be changed, but this is now documented.
- R packages using the RNifti API must now ensure that the USING_R symbol is
  defined (which it is by the main R header, R.h). Conversely, standalone use
  of RNifti as a C++ library no longer requires _NO_R__ to be defined.

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

VERSION 0.7.1

- The package is now more careful about handling NaNs when converting to
  integer types.
- Usage of the R API has been updated for forwards compatibility.

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

VERSION 0.7.0

- The new orientation() function can be used to identify the approximate
  storage orientation of an image. A replacement version allows the image
  data and metadata dimensions to be permuted and/or reversed.
- Image reorientation is similarly available through the C++ API.
- The sform and qform replacement methods should now follow R's usual
  semantics, and no longer modify the object in place if it is referred to by
  more than one name.
- The NiftiImage class is now suitable for use in standalone C++ projects.
  (Thanks to Matt Hall.)

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

VERSION 0.6.0

- Slope and intercept values in a NIfTI-1 header are now applied to the image
  data when converting it to an R array (which will in this case always be of
  mode double), or a C++ vector.
- The slope and intercept will be reset to zero when updating the data in an
  internal image object.

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

VERSION 0.5.1

- A potential crash and/or memory leak in the C++ NiftiImage copy assignment
  methods has been fixed.

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

VERSION 0.5.0

- The NiftiImage class gains methods to drop or replace the image data, and to
  mutate its datatype in-place. A datatype no longer needs to be specified when
  writing an image to file using the toFile() C++ method.
- The niftilib functions nifti_image_unload() and nifti_mat44_to_orientation()
  are now exposed through the RNifti API.
- Some minor compiler warnings that would affect packages linking to RNifti
  have been resolved.
- Additional tests have been added, to exercise the package more thoroughly.

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

VERSION 0.4.0

- Additional public methods have been added to the NiftiImage C++ class. Please
  see the API documentation at <http://doxygen.flakery.org/RNifti/> for
  details.
- The new origin() R function is a convenience wrapper for worldToVoxel(),
  which returns the voxel coordinates of the image origin.
- The package now produces an error when passed an "anlz" class object (from
  package "oro.nifti"), rather than mishandling it.

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

VERSION 0.3.0

- C++ API change: the NiftiImage class is now defined within an RNifti
  namespace. This will break existing uses of the class, but compatibility with
  older versions of the package can be preserved if desired, by checking for
  the compile-time constant HAVE_RNIFTI_NAMESPACE, which will be defined from
  now on.
- Additional niftilib functions for calculating matrix norms and byte swapping
  are now exposed through the RNifti API.
- Calling the C/C++ function niftilib_register_all() more than once should no
  longer result in repeated re-registration of functions.

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

VERSION 0.2.2

- The voxelToWorld() and worldToVoxel() functions now handle 2D points, rather
  than producing an error. (Reported by Takeo Katsuki.)

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

VERSION 0.2.1

- Examples have been added to the R-level documentation.
- Image pixel dimensions are now used to return a more sensible xform matrix in
  the case where the NIfTI-1 sform and qform are both marked unknown.

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

VERSION 0.2.0

- The writeNifti() function now performs path expansion on its argument,
  matching the behaviour of readNifti(). (Reported by John Muschelli.)
- Calling as.array() on an internal image containing no data now returns an
  array full of NAs (with a warning), rather than crashing R. (Reported by Tim
  Tierney.)
- The package should now work correctly with sparse MriImage objects, from
  first-party package "tractor.base".
- Images with invalid internal pointers are now handled (with a warning) by
  attempting to reconstruct the missing data structure. This should not happen
  in regular use, but can occur when external pointers are handed back to the
  main thread by worker threads when working in parallel. (Reported by Takeo
  Katsuki.)
- Calling the RNifti API from within OpenMP threads could previously lead to a
  stack imbalance. This is now guarded against, and a new C function,
  niftilib_register_all(), has been added as the recommended way to preregister
  all NIfTI-1 library functions wrapped by RNifti, particularly in threaded
  applications.
- Doxygen comments have been added to the C++ code to document the low-level
  API. A Doxyfile has also been added to the package root directory.

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

VERSION 0.1.0

- First public release. Package code has been split off from "RNiftyReg".

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