We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Niftisaver doesn't save new voxelspacing
### Discussed in https://github.com/Project-MONAI/MONAI/discussions/3299 as well as https://github.com/Project-MONAI/MONAI/discussions/2029


<div type='discussions-op-text'>

<sup>Originally posted by **Gijz33** November 10, 2021</sup>
Hi,

I am changing the voxel spacing of my CT data using monai.transforms.Spacingd and saving the CT with new spacing into a .nii.gz-file using monai.data.NiftiSaver.
The voxel size transformation is succesful inside the python script. However, opening the .nii.gz file using different software (3D-slicer) the spacing of the old/orginal CT is used. Can someone help me out? A snippet of my code is shown below:


```python
train_images = sorted(glob.glob(os.path.join(data_folder, "*_ct.nii.gz")))
train_labels = sorted(glob.glob(os.path.join(data_folder, "*_seg.nii.gz")))

data_dicts = [    {"image": image_name, "label": label_name} for image_name, label_name in zip(train_images, train_labels)    ]

loader = LoadImaged(keys=("image","label"))
data_dict = loader(data_dicts[0])
     
add_channel = AddChanneld(keys=["image", "label"])
data_dict = add_channel(data_dict)

orientation = Orientationd(keys=["image", "label"], axcodes="LPS")
data_dict = orientation(data_dict)

spacing = Spacingd(keys=["image", "label"], pixdim=(0.8, 0.8, 3.0), mode=("bilinear")) 
data_dict = spacing(data_dict)


saver = NiftiSaver(output_dir="./", output_postfix="test" ,output_ext=".nii.gz",mode="nearest")
saver.save(data_dict["image"], data_dict['image_meta_dict'])
```



</div>

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `monai/data/nifti_saver.py`
Content:
```
1 # Copyright 2020 - 2021 MONAI Consortium
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 #     http://www.apache.org/licenses/LICENSE-2.0
6 # Unless required by applicable law or agreed to in writing, software
7 # distributed under the License is distributed on an "AS IS" BASIS,
8 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 # See the License for the specific language governing permissions and
10 # limitations under the License.
11 
12 from pathlib import Path
13 from typing import Dict, Optional, Union
14 
15 import numpy as np
16 import torch
17 
18 from monai.config import DtypeLike
19 from monai.data.nifti_writer import write_nifti
20 from monai.data.utils import create_file_basename
21 from monai.utils import GridSampleMode, GridSamplePadMode
22 from monai.utils import ImageMetaKey as Key
23 
24 
25 class NiftiSaver:
26     """
27     Save the data as NIfTI file, it can support single data content or a batch of data.
28     Typically, the data can be segmentation predictions, call `save` for single data
29     or call `save_batch` to save a batch of data together.
30     The name of saved file will be `{input_image_name}_{output_postfix}{output_ext}`,
31     where the input image name is extracted from the provided meta data dictionary.
32     If no meta data provided, use index from 0 as the filename prefix.
33 
34     Note: image should include channel dimension: [B],C,H,W,[D].
35 
36     """
37 
38     def __init__(
39         self,
40         output_dir: Union[Path, str] = "./",
41         output_postfix: str = "seg",
42         output_ext: str = ".nii.gz",
43         resample: bool = True,
44         mode: Union[GridSampleMode, str] = GridSampleMode.BILINEAR,
45         padding_mode: Union[GridSamplePadMode, str] = GridSamplePadMode.BORDER,
46         align_corners: bool = False,
47         dtype: DtypeLike = np.float64,
48         output_dtype: DtypeLike = np.float32,
49         squeeze_end_dims: bool = True,
50         data_root_dir: str = "",
51         separate_folder: bool = True,
52         print_log: bool = True,
53     ) -> None:
54         """
55         Args:
56             output_dir: output image directory.
57             output_postfix: a string appended to all output file names.
58             output_ext: output file extension name.
59             resample: whether to resample before saving the data array.
60             mode: {``"bilinear"``, ``"nearest"``}
61                 This option is used when ``resample = True``.
62                 Interpolation mode to calculate output values. Defaults to ``"bilinear"``.
63                 See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample
64             padding_mode: {``"zeros"``, ``"border"``, ``"reflection"``}
65                 This option is used when ``resample = True``.
66                 Padding mode for outside grid values. Defaults to ``"border"``.
67                 See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample
68             align_corners: Geometrically, we consider the pixels of the input as squares rather than points.
69                 See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample
70             dtype: data type for resampling computation. Defaults to ``np.float64`` for best precision.
71                 If None, use the data type of input data.
72             output_dtype: data type for saving data. Defaults to ``np.float32``.
73             squeeze_end_dims: if True, any trailing singleton dimensions will be removed (after the channel
74                 has been moved to the end). So if input is (C,H,W,D), this will be altered to (H,W,D,C), and
75                 then if C==1, it will be saved as (H,W,D). If D also ==1, it will be saved as (H,W). If false,
76                 image will always be saved as (H,W,D,C).
77             data_root_dir: if not empty, it specifies the beginning parts of the input file's
78                 absolute path. it's used to compute `input_file_rel_path`, the relative path to the file from
79                 `data_root_dir` to preserve folder structure when saving in case there are files in different
80                 folders with the same file names. for example:
81                 input_file_name: /foo/bar/test1/image.nii,
82                 postfix: seg
83                 output_ext: nii.gz
84                 output_dir: /output,
85                 data_root_dir: /foo/bar,
86                 output will be: /output/test1/image/image_seg.nii.gz
87             separate_folder: whether to save every file in a separate folder, for example: if input filename is
88                 `image.nii`, postfix is `seg` and folder_path is `output`, if `True`, save as:
89                 `output/image/image_seg.nii`, if `False`, save as `output/image_seg.nii`. default to `True`.
90             print_log: whether to print log about the saved NIfTI file path, etc. default to `True`.
91 
92         """
93         self.output_dir = output_dir
94         self.output_postfix = output_postfix
95         self.output_ext = output_ext
96         self.resample = resample
97         self.mode: GridSampleMode = GridSampleMode(mode)
98         self.padding_mode: GridSamplePadMode = GridSamplePadMode(padding_mode)
99         self.align_corners = align_corners
100         self.dtype = dtype
101         self.output_dtype = output_dtype
102         self._data_index = 0
103         self.squeeze_end_dims = squeeze_end_dims
104         self.data_root_dir = data_root_dir
105         self.separate_folder = separate_folder
106         self.print_log = print_log
107 
108     def save(self, data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:
109         """
110         Save data into a Nifti file.
111         The meta_data could optionally have the following keys:
112 
113             - ``'filename_or_obj'`` -- for output file name creation, corresponding to filename or object.
114             - ``'original_affine'`` -- for data orientation handling, defaulting to an identity matrix.
115             - ``'affine'`` -- for data output affine, defaulting to an identity matrix.
116             - ``'spatial_shape'`` -- for data output shape.
117             - ``'patch_index'`` -- if the data is a patch of big image, append the patch index to filename.
118 
119         When meta_data is specified, the saver will try to resample batch data from the space
120         defined by "affine" to the space defined by "original_affine".
121 
122         If meta_data is None, use the default index (starting from 0) as the filename.
123 
124         Args:
125             data: target data content that to be saved as a NIfTI format file.
126                 Assuming the data shape starts with a channel dimension and followed by spatial dimensions.
127             meta_data: the meta data information corresponding to the data.
128 
129         See Also
130             :py:meth:`monai.data.nifti_writer.write_nifti`
131         """
132         filename = meta_data[Key.FILENAME_OR_OBJ] if meta_data else str(self._data_index)
133         self._data_index += 1
134         original_affine = meta_data.get("original_affine", None) if meta_data else None
135         affine = meta_data.get("affine", None) if meta_data else None
136         spatial_shape = meta_data.get("spatial_shape", None) if meta_data else None
137         patch_index = meta_data.get(Key.PATCH_INDEX, None) if meta_data else None
138 
139         if isinstance(data, torch.Tensor):
140             data = data.detach().cpu().numpy()
141 
142         path = create_file_basename(
143             postfix=self.output_postfix,
144             input_file_name=filename,
145             folder_path=self.output_dir,
146             data_root_dir=self.data_root_dir,
147             separate_folder=self.separate_folder,
148             patch_index=patch_index,
149         )
150         path = f"{path}{self.output_ext}"
151         # change data shape to be (channel, h, w, d)
152         while len(data.shape) < 4:
153             data = np.expand_dims(data, -1)
154         # change data to "channel last" format and write to nifti format file
155         data = np.moveaxis(np.asarray(data), 0, -1)
156 
157         # if desired, remove trailing singleton dimensions
158         if self.squeeze_end_dims:
159             while data.shape[-1] == 1:
160                 data = np.squeeze(data, -1)
161 
162         write_nifti(
163             data,
164             file_name=path,
165             affine=affine,
166             target_affine=original_affine,
167             resample=self.resample,
168             output_spatial_shape=spatial_shape,
169             mode=self.mode,
170             padding_mode=self.padding_mode,
171             align_corners=self.align_corners,
172             dtype=self.dtype,
173             output_dtype=self.output_dtype,
174         )
175 
176         if self.print_log:
177             print(f"file written: {path}.")
178 
179     def save_batch(self, batch_data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:
180         """
181         Save a batch of data into Nifti format files.
182 
183         Spatially it supports up to three dimensions, that is, H, HW, HWD for
184         1D, 2D, 3D respectively (with resampling supports for 2D and 3D only).
185 
186         When saving multiple time steps or multiple channels `batch_data`,
187         time and/or modality axes should be appended after the batch dimensions.
188         For example, the shape of a batch of 2D eight-class
189         segmentation probabilities to be saved could be `(batch, 8, 64, 64)`;
190         in this case each item in the batch will be saved as (64, 64, 1, 8)
191         NIfTI file (the third dimension is reserved as a spatial dimension).
192 
193         Args:
194             batch_data: target batch data content that save into NIfTI format.
195             meta_data: every key-value in the meta_data is corresponding to a batch of data.
196 
197         """
198         for i, data in enumerate(batch_data):  # save a batch of files
199             self.save(data=data, meta_data={k: meta_data[k][i] for k in meta_data} if meta_data is not None else None)
200
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/monai/data/nifti_saver.py b/monai/data/nifti_saver.py
--- a/monai/data/nifti_saver.py
+++ b/monai/data/nifti_saver.py
@@ -56,7 +56,8 @@
             output_dir: output image directory.
             output_postfix: a string appended to all output file names.
             output_ext: output file extension name.
-            resample: whether to resample before saving the data array.
+            resample: whether to convert the data array to it's original coordinate system
+                based on `original_affine` in the `meta_data`.
             mode: {``"bilinear"``, ``"nearest"``}
                 This option is used when ``resample = True``.
                 Interpolation mode to calculate output values. Defaults to ``"bilinear"``.
@@ -107,7 +108,7 @@
 
     def save(self, data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:
         """
-        Save data into a Nifti file.
+        Save data into a NIfTI file.
         The meta_data could optionally have the following keys:
 
             - ``'filename_or_obj'`` -- for output file name creation, corresponding to filename or object.
@@ -116,7 +117,7 @@
             - ``'spatial_shape'`` -- for data output shape.
             - ``'patch_index'`` -- if the data is a patch of big image, append the patch index to filename.
 
-        When meta_data is specified, the saver will try to resample batch data from the space
+        When meta_data is specified and `resample=True`, the saver will try to resample batch data from the space
         defined by "affine" to the space defined by "original_affine".
 
         If meta_data is None, use the default index (starting from 0) as the filename.
@@ -131,7 +132,7 @@
         """
         filename = meta_data[Key.FILENAME_OR_OBJ] if meta_data else str(self._data_index)
         self._data_index += 1
-        original_affine = meta_data.get("original_affine", None) if meta_data else None
+        original_affine = meta_data.get("original_affine", None) if meta_data and self.resample else None
         affine = meta_data.get("affine", None) if meta_data else None
         spatial_shape = meta_data.get("spatial_shape", None) if meta_data else None
         patch_index = meta_data.get(Key.PATCH_INDEX, None) if meta_data else None
@@ -151,7 +152,7 @@
         # change data shape to be (channel, h, w, d)
         while len(data.shape) < 4:
             data = np.expand_dims(data, -1)
-        # change data to "channel last" format and write to nifti format file
+        # change data to "channel last" format and write to NIfTI format file
         data = np.moveaxis(np.asarray(data), 0, -1)
 
         # if desired, remove trailing singleton dimensions
@@ -164,7 +165,7 @@
             file_name=path,
             affine=affine,
             target_affine=original_affine,
-            resample=self.resample,
+            resample=True,
             output_spatial_shape=spatial_shape,
             mode=self.mode,
             padding_mode=self.padding_mode,
@@ -178,7 +179,7 @@
 
     def save_batch(self, batch_data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:
         """
-        Save a batch of data into Nifti format files.
+        Save a batch of data into NIfTI format files.
 
         Spatially it supports up to three dimensions, that is, H, HW, HWD for
         1D, 2D, 3D respectively (with resampling supports for 2D and 3D only).

{"golden_diff": "diff --git a/monai/data/nifti_saver.py b/monai/data/nifti_saver.py\n--- a/monai/data/nifti_saver.py\n+++ b/monai/data/nifti_saver.py\n@@ -56,7 +56,8 @@\n             output_dir: output image directory.\n             output_postfix: a string appended to all output file names.\n             output_ext: output file extension name.\n-            resample: whether to resample before saving the data array.\n+            resample: whether to convert the data array to it's original coordinate system\n+                based on `original_affine` in the `meta_data`.\n             mode: {``\"bilinear\"``, ``\"nearest\"``}\n                 This option is used when ``resample = True``.\n                 Interpolation mode to calculate output values. Defaults to ``\"bilinear\"``.\n@@ -107,7 +108,7 @@\n \n     def save(self, data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:\n         \"\"\"\n-        Save data into a Nifti file.\n+        Save data into a NIfTI file.\n         The meta_data could optionally have the following keys:\n \n             - ``'filename_or_obj'`` -- for output file name creation, corresponding to filename or object.\n@@ -116,7 +117,7 @@\n             - ``'spatial_shape'`` -- for data output shape.\n             - ``'patch_index'`` -- if the data is a patch of big image, append the patch index to filename.\n \n-        When meta_data is specified, the saver will try to resample batch data from the space\n+        When meta_data is specified and `resample=True`, the saver will try to resample batch data from the space\n         defined by \"affine\" to the space defined by \"original_affine\".\n \n         If meta_data is None, use the default index (starting from 0) as the filename.\n@@ -131,7 +132,7 @@\n         \"\"\"\n         filename = meta_data[Key.FILENAME_OR_OBJ] if meta_data else str(self._data_index)\n         self._data_index += 1\n-        original_affine = meta_data.get(\"original_affine\", None) if meta_data else None\n+        original_affine = meta_data.get(\"original_affine\", None) if meta_data and self.resample else None\n         affine = meta_data.get(\"affine\", None) if meta_data else None\n         spatial_shape = meta_data.get(\"spatial_shape\", None) if meta_data else None\n         patch_index = meta_data.get(Key.PATCH_INDEX, None) if meta_data else None\n@@ -151,7 +152,7 @@\n         # change data shape to be (channel, h, w, d)\n         while len(data.shape) < 4:\n             data = np.expand_dims(data, -1)\n-        # change data to \"channel last\" format and write to nifti format file\n+        # change data to \"channel last\" format and write to NIfTI format file\n         data = np.moveaxis(np.asarray(data), 0, -1)\n \n         # if desired, remove trailing singleton dimensions\n@@ -164,7 +165,7 @@\n             file_name=path,\n             affine=affine,\n             target_affine=original_affine,\n-            resample=self.resample,\n+            resample=True,\n             output_spatial_shape=spatial_shape,\n             mode=self.mode,\n             padding_mode=self.padding_mode,\n@@ -178,7 +179,7 @@\n \n     def save_batch(self, batch_data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:\n         \"\"\"\n-        Save a batch of data into Nifti format files.\n+        Save a batch of data into NIfTI format files.\n \n         Spatially it supports up to three dimensions, that is, H, HW, HWD for\n         1D, 2D, 3D respectively (with resampling supports for 2D and 3D only).\n", "issue": "Niftisaver doesn't save new voxelspacing\n### Discussed in https://github.com/Project-MONAI/MONAI/discussions/3299 as well as https://github.com/Project-MONAI/MONAI/discussions/2029\r\n\r\n\r\n<div type='discussions-op-text'>\r\n\r\n<sup>Originally posted by **Gijz33** November 10, 2021</sup>\r\nHi,\r\n\r\nI am changing the voxel spacing of my CT data using monai.transforms.Spacingd and saving the CT with new spacing into a .nii.gz-file using monai.data.NiftiSaver.\r\nThe voxel size transformation is succesful inside the python script. However, opening the .nii.gz file using different software (3D-slicer) the spacing of the old/orginal CT is used. Can someone help me out? A snippet of my code is shown below:\r\n\r\n\r\n```python\r\ntrain_images = sorted(glob.glob(os.path.join(data_folder, \"*_ct.nii.gz\")))\r\ntrain_labels = sorted(glob.glob(os.path.join(data_folder, \"*_seg.nii.gz\")))\r\n\r\ndata_dicts = [    {\"image\": image_name, \"label\": label_name} for image_name, label_name in zip(train_images, train_labels)    ]\r\n\r\nloader = LoadImaged(keys=(\"image\",\"label\"))\r\ndata_dict = loader(data_dicts[0])\r\n     \r\nadd_channel = AddChanneld(keys=[\"image\", \"label\"])\r\ndata_dict = add_channel(data_dict)\r\n\r\norientation = Orientationd(keys=[\"image\", \"label\"], axcodes=\"LPS\")\r\ndata_dict = orientation(data_dict)\r\n\r\nspacing = Spacingd(keys=[\"image\", \"label\"], pixdim=(0.8, 0.8, 3.0), mode=(\"bilinear\")) \r\ndata_dict = spacing(data_dict)\r\n\r\n\r\nsaver = NiftiSaver(output_dir=\"./\", output_postfix=\"test\" ,output_ext=\".nii.gz\",mode=\"nearest\")\r\nsaver.save(data_dict[\"image\"], data_dict['image_meta_dict'])\r\n```\r\n\r\n\r\n\r\n</div>\n", "before_files": [{"content": "# Copyright 2020 - 2021 MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom pathlib import Path\nfrom typing import Dict, Optional, Union\n\nimport numpy as np\nimport torch\n\nfrom monai.config import DtypeLike\nfrom monai.data.nifti_writer import write_nifti\nfrom monai.data.utils import create_file_basename\nfrom monai.utils import GridSampleMode, GridSamplePadMode\nfrom monai.utils import ImageMetaKey as Key\n\n\nclass NiftiSaver:\n    \"\"\"\n    Save the data as NIfTI file, it can support single data content or a batch of data.\n    Typically, the data can be segmentation predictions, call `save` for single data\n    or call `save_batch` to save a batch of data together.\n    The name of saved file will be `{input_image_name}_{output_postfix}{output_ext}`,\n    where the input image name is extracted from the provided meta data dictionary.\n    If no meta data provided, use index from 0 as the filename prefix.\n\n    Note: image should include channel dimension: [B],C,H,W,[D].\n\n    \"\"\"\n\n    def __init__(\n        self,\n        output_dir: Union[Path, str] = \"./\",\n        output_postfix: str = \"seg\",\n        output_ext: str = \".nii.gz\",\n        resample: bool = True,\n        mode: Union[GridSampleMode, str] = GridSampleMode.BILINEAR,\n        padding_mode: Union[GridSamplePadMode, str] = GridSamplePadMode.BORDER,\n        align_corners: bool = False,\n        dtype: DtypeLike = np.float64,\n        output_dtype: DtypeLike = np.float32,\n        squeeze_end_dims: bool = True,\n        data_root_dir: str = \"\",\n        separate_folder: bool = True,\n        print_log: bool = True,\n    ) -> None:\n        \"\"\"\n        Args:\n            output_dir: output image directory.\n            output_postfix: a string appended to all output file names.\n            output_ext: output file extension name.\n            resample: whether to resample before saving the data array.\n            mode: {``\"bilinear\"``, ``\"nearest\"``}\n                This option is used when ``resample = True``.\n                Interpolation mode to calculate output values. Defaults to ``\"bilinear\"``.\n                See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample\n            padding_mode: {``\"zeros\"``, ``\"border\"``, ``\"reflection\"``}\n                This option is used when ``resample = True``.\n                Padding mode for outside grid values. Defaults to ``\"border\"``.\n                See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample\n            align_corners: Geometrically, we consider the pixels of the input as squares rather than points.\n                See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample\n            dtype: data type for resampling computation. Defaults to ``np.float64`` for best precision.\n                If None, use the data type of input data.\n            output_dtype: data type for saving data. Defaults to ``np.float32``.\n            squeeze_end_dims: if True, any trailing singleton dimensions will be removed (after the channel\n                has been moved to the end). So if input is (C,H,W,D), this will be altered to (H,W,D,C), and\n                then if C==1, it will be saved as (H,W,D). If D also ==1, it will be saved as (H,W). If false,\n                image will always be saved as (H,W,D,C).\n            data_root_dir: if not empty, it specifies the beginning parts of the input file's\n                absolute path. it's used to compute `input_file_rel_path`, the relative path to the file from\n                `data_root_dir` to preserve folder structure when saving in case there are files in different\n                folders with the same file names. for example:\n                input_file_name: /foo/bar/test1/image.nii,\n                postfix: seg\n                output_ext: nii.gz\n                output_dir: /output,\n                data_root_dir: /foo/bar,\n                output will be: /output/test1/image/image_seg.nii.gz\n            separate_folder: whether to save every file in a separate folder, for example: if input filename is\n                `image.nii`, postfix is `seg` and folder_path is `output`, if `True`, save as:\n                `output/image/image_seg.nii`, if `False`, save as `output/image_seg.nii`. default to `True`.\n            print_log: whether to print log about the saved NIfTI file path, etc. default to `True`.\n\n        \"\"\"\n        self.output_dir = output_dir\n        self.output_postfix = output_postfix\n        self.output_ext = output_ext\n        self.resample = resample\n        self.mode: GridSampleMode = GridSampleMode(mode)\n        self.padding_mode: GridSamplePadMode = GridSamplePadMode(padding_mode)\n        self.align_corners = align_corners\n        self.dtype = dtype\n        self.output_dtype = output_dtype\n        self._data_index = 0\n        self.squeeze_end_dims = squeeze_end_dims\n        self.data_root_dir = data_root_dir\n        self.separate_folder = separate_folder\n        self.print_log = print_log\n\n    def save(self, data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:\n        \"\"\"\n        Save data into a Nifti file.\n        The meta_data could optionally have the following keys:\n\n            - ``'filename_or_obj'`` -- for output file name creation, corresponding to filename or object.\n            - ``'original_affine'`` -- for data orientation handling, defaulting to an identity matrix.\n            - ``'affine'`` -- for data output affine, defaulting to an identity matrix.\n            - ``'spatial_shape'`` -- for data output shape.\n            - ``'patch_index'`` -- if the data is a patch of big image, append the patch index to filename.\n\n        When meta_data is specified, the saver will try to resample batch data from the space\n        defined by \"affine\" to the space defined by \"original_affine\".\n\n        If meta_data is None, use the default index (starting from 0) as the filename.\n\n        Args:\n            data: target data content that to be saved as a NIfTI format file.\n                Assuming the data shape starts with a channel dimension and followed by spatial dimensions.\n            meta_data: the meta data information corresponding to the data.\n\n        See Also\n            :py:meth:`monai.data.nifti_writer.write_nifti`\n        \"\"\"\n        filename = meta_data[Key.FILENAME_OR_OBJ] if meta_data else str(self._data_index)\n        self._data_index += 1\n        original_affine = meta_data.get(\"original_affine\", None) if meta_data else None\n        affine = meta_data.get(\"affine\", None) if meta_data else None\n        spatial_shape = meta_data.get(\"spatial_shape\", None) if meta_data else None\n        patch_index = meta_data.get(Key.PATCH_INDEX, None) if meta_data else None\n\n        if isinstance(data, torch.Tensor):\n            data = data.detach().cpu().numpy()\n\n        path = create_file_basename(\n            postfix=self.output_postfix,\n            input_file_name=filename,\n            folder_path=self.output_dir,\n            data_root_dir=self.data_root_dir,\n            separate_folder=self.separate_folder,\n            patch_index=patch_index,\n        )\n        path = f\"{path}{self.output_ext}\"\n        # change data shape to be (channel, h, w, d)\n        while len(data.shape) < 4:\n            data = np.expand_dims(data, -1)\n        # change data to \"channel last\" format and write to nifti format file\n        data = np.moveaxis(np.asarray(data), 0, -1)\n\n        # if desired, remove trailing singleton dimensions\n        if self.squeeze_end_dims:\n            while data.shape[-1] == 1:\n                data = np.squeeze(data, -1)\n\n        write_nifti(\n            data,\n            file_name=path,\n            affine=affine,\n            target_affine=original_affine,\n            resample=self.resample,\n            output_spatial_shape=spatial_shape,\n            mode=self.mode,\n            padding_mode=self.padding_mode,\n            align_corners=self.align_corners,\n            dtype=self.dtype,\n            output_dtype=self.output_dtype,\n        )\n\n        if self.print_log:\n            print(f\"file written: {path}.\")\n\n    def save_batch(self, batch_data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:\n        \"\"\"\n        Save a batch of data into Nifti format files.\n\n        Spatially it supports up to three dimensions, that is, H, HW, HWD for\n        1D, 2D, 3D respectively (with resampling supports for 2D and 3D only).\n\n        When saving multiple time steps or multiple channels `batch_data`,\n        time and/or modality axes should be appended after the batch dimensions.\n        For example, the shape of a batch of 2D eight-class\n        segmentation probabilities to be saved could be `(batch, 8, 64, 64)`;\n        in this case each item in the batch will be saved as (64, 64, 1, 8)\n        NIfTI file (the third dimension is reserved as a spatial dimension).\n\n        Args:\n            batch_data: target batch data content that save into NIfTI format.\n            meta_data: every key-value in the meta_data is corresponding to a batch of data.\n\n        \"\"\"\n        for i, data in enumerate(batch_data):  # save a batch of files\n            self.save(data=data, meta_data={k: meta_data[k][i] for k in meta_data} if meta_data is not None else None)\n", "path": "monai/data/nifti_saver.py"}], "after_files": [{"content": "# Copyright 2020 - 2021 MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom pathlib import Path\nfrom typing import Dict, Optional, Union\n\nimport numpy as np\nimport torch\n\nfrom monai.config import DtypeLike\nfrom monai.data.nifti_writer import write_nifti\nfrom monai.data.utils import create_file_basename\nfrom monai.utils import GridSampleMode, GridSamplePadMode\nfrom monai.utils import ImageMetaKey as Key\n\n\nclass NiftiSaver:\n    \"\"\"\n    Save the data as NIfTI file, it can support single data content or a batch of data.\n    Typically, the data can be segmentation predictions, call `save` for single data\n    or call `save_batch` to save a batch of data together.\n    The name of saved file will be `{input_image_name}_{output_postfix}{output_ext}`,\n    where the input image name is extracted from the provided meta data dictionary.\n    If no meta data provided, use index from 0 as the filename prefix.\n\n    Note: image should include channel dimension: [B],C,H,W,[D].\n\n    \"\"\"\n\n    def __init__(\n        self,\n        output_dir: Union[Path, str] = \"./\",\n        output_postfix: str = \"seg\",\n        output_ext: str = \".nii.gz\",\n        resample: bool = True,\n        mode: Union[GridSampleMode, str] = GridSampleMode.BILINEAR,\n        padding_mode: Union[GridSamplePadMode, str] = GridSamplePadMode.BORDER,\n        align_corners: bool = False,\n        dtype: DtypeLike = np.float64,\n        output_dtype: DtypeLike = np.float32,\n        squeeze_end_dims: bool = True,\n        data_root_dir: str = \"\",\n        separate_folder: bool = True,\n        print_log: bool = True,\n    ) -> None:\n        \"\"\"\n        Args:\n            output_dir: output image directory.\n            output_postfix: a string appended to all output file names.\n            output_ext: output file extension name.\n            resample: whether to convert the data array to it's original coordinate system\n                based on `original_affine` in the `meta_data`.\n            mode: {``\"bilinear\"``, ``\"nearest\"``}\n                This option is used when ``resample = True``.\n                Interpolation mode to calculate output values. Defaults to ``\"bilinear\"``.\n                See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample\n            padding_mode: {``\"zeros\"``, ``\"border\"``, ``\"reflection\"``}\n                This option is used when ``resample = True``.\n                Padding mode for outside grid values. Defaults to ``\"border\"``.\n                See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample\n            align_corners: Geometrically, we consider the pixels of the input as squares rather than points.\n                See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample\n            dtype: data type for resampling computation. Defaults to ``np.float64`` for best precision.\n                If None, use the data type of input data.\n            output_dtype: data type for saving data. Defaults to ``np.float32``.\n            squeeze_end_dims: if True, any trailing singleton dimensions will be removed (after the channel\n                has been moved to the end). So if input is (C,H,W,D), this will be altered to (H,W,D,C), and\n                then if C==1, it will be saved as (H,W,D). If D also ==1, it will be saved as (H,W). If false,\n                image will always be saved as (H,W,D,C).\n            data_root_dir: if not empty, it specifies the beginning parts of the input file's\n                absolute path. it's used to compute `input_file_rel_path`, the relative path to the file from\n                `data_root_dir` to preserve folder structure when saving in case there are files in different\n                folders with the same file names. for example:\n                input_file_name: /foo/bar/test1/image.nii,\n                postfix: seg\n                output_ext: nii.gz\n                output_dir: /output,\n                data_root_dir: /foo/bar,\n                output will be: /output/test1/image/image_seg.nii.gz\n            separate_folder: whether to save every file in a separate folder, for example: if input filename is\n                `image.nii`, postfix is `seg` and folder_path is `output`, if `True`, save as:\n                `output/image/image_seg.nii`, if `False`, save as `output/image_seg.nii`. default to `True`.\n            print_log: whether to print log about the saved NIfTI file path, etc. default to `True`.\n\n        \"\"\"\n        self.output_dir = output_dir\n        self.output_postfix = output_postfix\n        self.output_ext = output_ext\n        self.resample = resample\n        self.mode: GridSampleMode = GridSampleMode(mode)\n        self.padding_mode: GridSamplePadMode = GridSamplePadMode(padding_mode)\n        self.align_corners = align_corners\n        self.dtype = dtype\n        self.output_dtype = output_dtype\n        self._data_index = 0\n        self.squeeze_end_dims = squeeze_end_dims\n        self.data_root_dir = data_root_dir\n        self.separate_folder = separate_folder\n        self.print_log = print_log\n\n    def save(self, data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:\n        \"\"\"\n        Save data into a NIfTI file.\n        The meta_data could optionally have the following keys:\n\n            - ``'filename_or_obj'`` -- for output file name creation, corresponding to filename or object.\n            - ``'original_affine'`` -- for data orientation handling, defaulting to an identity matrix.\n            - ``'affine'`` -- for data output affine, defaulting to an identity matrix.\n            - ``'spatial_shape'`` -- for data output shape.\n            - ``'patch_index'`` -- if the data is a patch of big image, append the patch index to filename.\n\n        When meta_data is specified and `resample=True`, the saver will try to resample batch data from the space\n        defined by \"affine\" to the space defined by \"original_affine\".\n\n        If meta_data is None, use the default index (starting from 0) as the filename.\n\n        Args:\n            data: target data content that to be saved as a NIfTI format file.\n                Assuming the data shape starts with a channel dimension and followed by spatial dimensions.\n            meta_data: the meta data information corresponding to the data.\n\n        See Also\n            :py:meth:`monai.data.nifti_writer.write_nifti`\n        \"\"\"\n        filename = meta_data[Key.FILENAME_OR_OBJ] if meta_data else str(self._data_index)\n        self._data_index += 1\n        original_affine = meta_data.get(\"original_affine\", None) if meta_data and self.resample else None\n        affine = meta_data.get(\"affine\", None) if meta_data else None\n        spatial_shape = meta_data.get(\"spatial_shape\", None) if meta_data else None\n        patch_index = meta_data.get(Key.PATCH_INDEX, None) if meta_data else None\n\n        if isinstance(data, torch.Tensor):\n            data = data.detach().cpu().numpy()\n\n        path = create_file_basename(\n            postfix=self.output_postfix,\n            input_file_name=filename,\n            folder_path=self.output_dir,\n            data_root_dir=self.data_root_dir,\n            separate_folder=self.separate_folder,\n            patch_index=patch_index,\n        )\n        path = f\"{path}{self.output_ext}\"\n        # change data shape to be (channel, h, w, d)\n        while len(data.shape) < 4:\n            data = np.expand_dims(data, -1)\n        # change data to \"channel last\" format and write to NIfTI format file\n        data = np.moveaxis(np.asarray(data), 0, -1)\n\n        # if desired, remove trailing singleton dimensions\n        if self.squeeze_end_dims:\n            while data.shape[-1] == 1:\n                data = np.squeeze(data, -1)\n\n        write_nifti(\n            data,\n            file_name=path,\n            affine=affine,\n            target_affine=original_affine,\n            resample=True,\n            output_spatial_shape=spatial_shape,\n            mode=self.mode,\n            padding_mode=self.padding_mode,\n            align_corners=self.align_corners,\n            dtype=self.dtype,\n            output_dtype=self.output_dtype,\n        )\n\n        if self.print_log:\n            print(f\"file written: {path}.\")\n\n    def save_batch(self, batch_data: Union[torch.Tensor, np.ndarray], meta_data: Optional[Dict] = None) -> None:\n        \"\"\"\n        Save a batch of data into NIfTI format files.\n\n        Spatially it supports up to three dimensions, that is, H, HW, HWD for\n        1D, 2D, 3D respectively (with resampling supports for 2D and 3D only).\n\n        When saving multiple time steps or multiple channels `batch_data`,\n        time and/or modality axes should be appended after the batch dimensions.\n        For example, the shape of a batch of 2D eight-class\n        segmentation probabilities to be saved could be `(batch, 8, 64, 64)`;\n        in this case each item in the batch will be saved as (64, 64, 1, 8)\n        NIfTI file (the third dimension is reserved as a spatial dimension).\n\n        Args:\n            batch_data: target batch data content that save into NIfTI format.\n            meta_data: every key-value in the meta_data is corresponding to a batch of data.\n\n        \"\"\"\n        for i, data in enumerate(batch_data):  # save a batch of files\n            self.save(data=data, meta_data={k: meta_data[k][i] for k in meta_data} if meta_data is not None else None)\n", "path": "monai/data/nifti_saver.py"}]}