Exemple #1
0
    def test_cmap_list(self):
        """Test that colors can be a list/tuple."""
        from satpy.enhancements import create_colormap
        colors = [
            [0, 0, 1],
            [1, 0, 1],
            [0, 1, 1],
            [1, 1, 1],
        ]
        values = [2, 4, 6, 8]
        cmap = create_colormap({'colors': colors, 'color_scale': 1})
        assert cmap.colors.shape[0] == 4
        np.testing.assert_equal(cmap.colors[0], [0.0, 0.0, 1.0])
        assert cmap.values.shape[0] == 4
        assert cmap.values[0] == 0
        assert cmap.values[-1] == 1.0

        cmap = create_colormap({
            'colors': colors,
            'color_scale': 1,
            'values': values
        })
        assert cmap.colors.shape[0] == 4
        np.testing.assert_equal(cmap.colors[0], [0.0, 0.0, 1.0])
        assert cmap.values.shape[0] == 4
        assert cmap.values[0] == 2
        assert cmap.values[-1] == 8
    def test_cmap_from_file_vrgb(self):
        """Test that colormaps can be loaded from a binary file with values."""
        from tempfile import NamedTemporaryFile

        from satpy.enhancements import create_colormap

        # create the colormap file on disk
        with NamedTemporaryFile(suffix='.npy', delete=False) as tmp_cmap:
            cmap_filename = tmp_cmap.name
            np.save(
                cmap_filename,
                np.array([
                    [128, 255, 0, 0],
                    [130, 255, 255, 0],
                    [132, 255, 255, 255],
                    [134, 0, 0, 255],
                ]))

        try:
            # default mode of VRGB
            cmap = create_colormap({'filename': cmap_filename})
            self.assertEqual(cmap.colors.shape[0], 4)
            np.testing.assert_equal(cmap.colors[0], [1.0, 0, 0])
            self.assertEqual(cmap.values.shape[0], 4)
            self.assertEqual(cmap.values[0], 128)
            self.assertEqual(cmap.values[-1], 134)

            cmap = create_colormap({
                'filename': cmap_filename,
                'colormap_mode': 'RGBA'
            })
            self.assertEqual(cmap.colors.shape[0], 4)
            self.assertEqual(cmap.colors.shape[1], 4)  # RGBA
            np.testing.assert_equal(cmap.colors[0], [128 / 255., 1.0, 0, 0])
            self.assertEqual(cmap.values.shape[0], 4)
            self.assertEqual(cmap.values[0], 0)
            self.assertEqual(cmap.values[-1], 1.0)

            cmap = create_colormap({
                'filename': cmap_filename,
                'min_value': 50,
                'max_value': 100
            })
            self.assertEqual(cmap.colors.shape[0], 4)
            np.testing.assert_equal(cmap.colors[0], [1.0, 0, 0])
            self.assertEqual(cmap.values.shape[0], 4)
            self.assertEqual(cmap.values[0], 50)
            self.assertEqual(cmap.values[-1], 100)

            self.assertRaises(
                ValueError, create_colormap, {
                    'filename': cmap_filename,
                    'colormap_mode': 'RGB',
                    'min_value': 50,
                    'max_value': 100
                })
        finally:
            os.remove(cmap_filename)
Exemple #3
0
 def test_cmap_bad_mode(self, real_mode, forced_mode, filename_suffix):
     """Test that reading colormaps with the wrong mode fails."""
     with closed_named_temp_file(suffix=filename_suffix) as cmap_filename:
         cmap_data = _generate_cmap_test_data(None, real_mode)
         _write_cmap_to_file(cmap_filename, cmap_data)
         # Force colormap_mode VRGBA to RGBA and we should see an exception
         with pytest.raises(ValueError):
             create_colormap({
                 'filename': cmap_filename,
                 'colormap_mode': forced_mode
             })
Exemple #4
0
    def test_cmap_from_file_bad_shape(self):
        """Test that unknown array shape causes an error."""
        from satpy.enhancements import create_colormap

        # create the colormap file on disk
        with closed_named_temp_file(suffix='.npy') as cmap_filename:
            np.save(cmap_filename, np.array([
                [0],
                [64],
                [128],
                [255],
            ]))

            with pytest.raises(ValueError):
                create_colormap({'filename': cmap_filename})
Exemple #5
0
 def test_cmap_from_trollimage(self):
     """Test that colormaps in trollimage can be loaded."""
     from satpy.enhancements import create_colormap
     cmap = create_colormap({'colors': 'pubu'})
     from trollimage.colormap import pubu
     np.testing.assert_equal(cmap.colors, pubu.colors)
     np.testing.assert_equal(cmap.values, pubu.values)
Exemple #6
0
    def test_cmap_from_file(self, color_scale, colormap_mode, extra_kwargs,
                            filename_suffix):
        """Test that colormaps can be loaded from a binary file."""
        # create the colormap file on disk
        with closed_named_temp_file(suffix=filename_suffix) as cmap_filename:
            cmap_data = _generate_cmap_test_data(color_scale, colormap_mode)
            _write_cmap_to_file(cmap_filename, cmap_data)

            unset_first_value = 128.0 / 255.0 if colormap_mode.startswith(
                "V") else 0.0
            unset_last_value = 134.0 / 255.0 if colormap_mode.startswith(
                "V") else 1.0
            if (color_scale is None
                    or color_scale == 255) and colormap_mode.startswith("V"):
                unset_first_value *= 255
                unset_last_value *= 255
            if "min_value" in extra_kwargs:
                unset_first_value = extra_kwargs["min_value"]
                unset_last_value = extra_kwargs["max_value"]

            first_color = [1.0, 0.0, 0.0]
            if colormap_mode == "VRGBA":
                first_color = [128.0 / 255.0] + first_color

            kwargs1 = {"filename": cmap_filename}
            kwargs1.update(extra_kwargs)
            if color_scale is not None:
                kwargs1["color_scale"] = color_scale

            cmap = create_colormap(kwargs1)
            assert cmap.colors.shape[0] == 4
            np.testing.assert_equal(cmap.colors[0], first_color)
            assert cmap.values.shape[0] == 4
            assert cmap.values[0] == unset_first_value
            assert cmap.values[-1] == unset_last_value
    def test_cmap_from_file_rgb_1(self):
        """Test that colormaps can be loaded from a binary file with 0-1 colors."""
        from tempfile import NamedTemporaryFile

        from satpy.enhancements import create_colormap

        # create the colormap file on disk
        with NamedTemporaryFile(suffix='.npy', delete=False) as tmp_cmap:
            cmap_filename = tmp_cmap.name
            np.save(cmap_filename,
                    np.array([
                        [1, 0, 0],
                        [1, 1, 0],
                        [1, 1, 1],
                        [0, 0, 1],
                    ]))

        try:
            cmap = create_colormap({
                'filename': cmap_filename,
                'color_scale': 1
            })
            self.assertEqual(cmap.colors.shape[0], 4)
            np.testing.assert_equal(cmap.colors[0], [1.0, 0, 0])
            self.assertEqual(cmap.values.shape[0], 4)
            self.assertEqual(cmap.values[0], 0)
            self.assertEqual(cmap.values[-1], 1.0)

            cmap = create_colormap({
                'filename': cmap_filename,
                'color_scale': 1,
                'min_value': 50,
                'max_value': 100
            })
            self.assertEqual(cmap.colors.shape[0], 4)
            np.testing.assert_equal(cmap.colors[0], [1.0, 0, 0])
            self.assertEqual(cmap.values.shape[0], 4)
            self.assertEqual(cmap.values[0], 50)
            self.assertEqual(cmap.values[-1], 100)
        finally:
            os.remove(cmap_filename)
Exemple #8
0
 def test_cmap_vrgb_as_rgba(self):
     """Test that data created as VRGB still reads as RGBA."""
     with closed_named_temp_file(suffix=".npy") as cmap_filename:
         cmap_data = _generate_cmap_test_data(None, "VRGB")
         np.save(cmap_filename, cmap_data)
         cmap = create_colormap({
             'filename': cmap_filename,
             'colormap_mode': "RGBA"
         })
         assert cmap.colors.shape[0] == 4
         assert cmap.colors.shape[1] == 4  # RGBA
         np.testing.assert_equal(cmap.colors[0], [128 / 255., 1.0, 0, 0])
         assert cmap.values.shape[0] == 4
         assert cmap.values[0] == 0
         assert cmap.values[-1] == 1.0
Exemple #9
0
def load_color_table_file_to_colormap(ct_file):
    """Load a text colormap file and create a trollimage.Colormap object.

    If the provided pathname includes ``$POLAR2GRID_HOME`` it will be replaced
    with the current environment variable value of ``POLAR2GRID_HOME``.

    """
    from trollimage.colormap import Colormap
    p2g_home = os.getenv('POLAR2GRID_HOME', '')
    ct_file = ct_file.replace("$POLAR2GRID_HOME", p2g_home)
    ct_file = ct_file.replace("$GEO2GRID_HOME", p2g_home)
    if ct_file.endswith('.npy') or ct_file.endswith('.npz'):
        # binary colormap files (RGB, RGBA, VRGB, VRGBA)
        from satpy.enhancements import create_colormap
        cmap = create_colormap({'filename': ct_file})
    else:
        # P2G style colormap text files
        ct = parse_color_table_file(ct_file)
        entries = ((e[0] / 255., [x / 255. for x in e[1:]]) for e in ct)
        cmap = Colormap(*entries)
    return cmap
Exemple #10
0
    def test_cmap_from_config_path(self, tmp_path):
        """Test loading a colormap relative to a config path."""
        import satpy
        from satpy.enhancements import create_colormap

        cmap_dir = tmp_path / "colormaps"
        cmap_dir.mkdir()
        cmap_filename = cmap_dir / "my_colormap.npy"
        cmap_data = _generate_cmap_test_data(None, "RGBA")
        np.save(cmap_filename, cmap_data)
        with satpy.config.set(config_path=[tmp_path]):
            rel_cmap_filename = os.path.join("colormaps", "my_colormap.npy")
            cmap = create_colormap({
                'filename': rel_cmap_filename,
                'colormap_mode': "RGBA"
            })
            assert cmap.colors.shape[0] == 4
            assert cmap.colors.shape[1] == 4  # RGBA
            np.testing.assert_equal(cmap.colors[0], [128 / 255., 1.0, 0, 0])
            assert cmap.values.shape[0] == 4
            assert cmap.values[0] == 0
            assert cmap.values[-1] == 1.0
Exemple #11
0
 def test_cmap_no_colormap(self):
     """Test that being unable to create a colormap raises an error."""
     from satpy.enhancements import create_colormap
     with pytest.raises(ValueError):
         create_colormap({})
Exemple #12
0
    def save_image(self,
                   img,
                   filename=None,
                   dtype=None,
                   fill_value=None,
                   compute=True,
                   keep_palette=False,
                   cmap=None,
                   tags=None,
                   overviews=None,
                   overviews_minsize=256,
                   overviews_resampling=None,
                   include_scale_offset=False,
                   scale_offset_tags=None,
                   driver=None,
                   tiled=True,
                   **kwargs):
        """Save the image to the given ``filename`` in geotiff_ format.

        Note for faster output and reduced memory usage the ``rasterio``
        library must be installed. This writer currently falls back to
        using ``gdal`` directly, but that will be deprecated in the future.

        Args:
            img (xarray.DataArray): Data to save to geotiff.
            filename (str): Filename to save the image to. Defaults to
                ``filename`` passed during writer creation. Unlike the
                creation ``filename`` keyword argument, this filename does not
                get formatted with data attributes.
            dtype (numpy.dtype): Numpy data type to save the image as.
                Defaults to 8-bit unsigned integer (``np.uint8``) or the data
                type of the data to be saved if ``enhance=False``. If the
                ``dtype`` argument is provided during writer creation then
                that will be used as the default.
            fill_value (int or float): Value to use where data values are
                NaN/null. If this is specified in the writer configuration
                file that value will be used as the default.
            compute (bool): Compute dask arrays and save the image
                immediately. If ``False`` then the return value can be passed
                to :func:`~satpy.writers.compute_writer_results` to do the
                computation. This is useful when multiple images may share
                input calculations where dask can benefit from not repeating
                them multiple times. Defaults to ``True`` in the writer by
                itself, but is typically passed as ``False`` by callers where
                calculations can be combined.
            keep_palette (bool): Save palette/color table to geotiff.
                To be used with images that were palettized with the
                "palettize" enhancement. Setting this to ``True`` will cause
                the colormap of the image to be written as a "color table" in
                the output geotiff and the image data values will represent
                the index values in to that color table. By default, this will
                use the colormap used in the "palettize" operation.
                See the ``cmap`` option for other options. This option defaults
                to ``False`` and palettized images will be converted to RGB/A.
            cmap (trollimage.colormap.Colormap or None): Colormap to save
                as a color table in the output geotiff. See ``keep_palette``
                for more information. Defaults to the palette of the provided
                ``img`` object. The colormap's range should be set to match
                the index range of the palette
                (ex. `cmap.set_range(0, len(colors))`).
            tags (dict): Extra metadata to store in geotiff.
            overviews (list): The reduction factors of the overviews to include
                in the image, eg::

                    scn.save_datasets(overviews=[2, 4, 8, 16])

                If provided as an empty list, then levels will be
                computed as powers of two until the last level has less
                pixels than `overviews_minsize`.
                Default is to not add overviews.
            overviews_minsize (int): Minimum number of pixels for the smallest
                overview size generated when `overviews` is auto-generated.
                Defaults to 256.
            overviews_resampling (str): Resampling method
                to use when generating overviews. This must be the name of an
                enum value from :class:`rasterio.enums.Resampling` and
                only takes effect if the `overviews` keyword argument is
                provided. Common values include `nearest` (default),
                `bilinear`, `average`, and many others. See the rasterio
                documentation for more information.
            scale_offset_tags (Tuple[str, str]): If set, include inclusion of
                scale and offset in the GeoTIFF headers in the GDALMetaData
                tag.  The value of this argument should be a keyword argument
                ``(scale_label, offset_label)``, for example, ``("scale",
                "offset")``, indicating the labels to be used.
            include_scale_offset (deprecated, bool): Deprecated.
                Use ``scale_offset_tags=("scale", "offset")`` to include scale
                and offset tags.
            tiled (bool): For performance this defaults to ``True``.
                Pass ``False`` to created striped TIFF files.

        .. _geotiff: http://trac.osgeo.org/geotiff/

        """
        filename = filename or self.get_filename(**img.data.attrs)

        gdal_options = self._get_gdal_options(kwargs)
        if fill_value is None:
            # fall back to fill_value from configuration file
            fill_value = self.info.get('fill_value')

        dtype = dtype if dtype is not None else self.dtype
        if dtype is None and self.enhancer is not False:
            dtype = np.uint8
        elif dtype is None:
            dtype = img.data.dtype.type

        if "alpha" in kwargs:
            raise ValueError(
                "Keyword 'alpha' is automatically set based on 'fill_value' "
                "and should not be specified")
        if np.issubdtype(dtype, np.floating):
            if img.mode != "L":
                raise ValueError("Image must be in 'L' mode for floating "
                                 "point geotiff saving")
            if fill_value is None:
                LOG.debug("Alpha band not supported for float geotiffs, "
                          "setting fill value to 'NaN'")
                fill_value = np.nan
        if keep_palette and cmap is None and img.palette is not None:
            from satpy.enhancements import create_colormap
            cmap = create_colormap({'colors': img.palette})
            cmap.set_range(0, len(img.palette) - 1)

        if tags is None:
            tags = {}
        tags.update(self.tags)

        return img.save(filename,
                        fformat='tif',
                        driver=driver,
                        fill_value=fill_value,
                        dtype=dtype,
                        compute=compute,
                        keep_palette=keep_palette,
                        cmap=cmap,
                        tags=tags,
                        include_scale_offset_tags=include_scale_offset,
                        scale_offset_tags=scale_offset_tags,
                        overviews=overviews,
                        overviews_resampling=overviews_resampling,
                        overviews_minsize=overviews_minsize,
                        tiled=tiled,
                        **gdal_options)
Exemple #13
0
    def save_image(self, img, filename=None, dtype=None, fill_value=None,
                   compute=True, keep_palette=False, cmap=None, tags=None,
                   include_scale_offset=False,
                   **kwargs):
        """Save the image to the given ``filename`` in geotiff_ format.

        Note for faster output and reduced memory usage the ``rasterio``
        library must be installed. This writer currently falls back to
        using ``gdal`` directly, but that will be deprecated in the future.

        Args:
            img (xarray.DataArray): Data to save to geotiff.
            filename (str): Filename to save the image to. Defaults to
                ``filename`` passed during writer creation. Unlike the
                creation ``filename`` keyword argument, this filename does not
                get formatted with data attributes.
            dtype (numpy.dtype): Numpy data type to save the image as.
                Defaults to 8-bit unsigned integer (``np.uint8``). If the
                ``dtype`` argument is provided during writer creation then
                that will be used as the default.
            fill_value (int or float): Value to use where data values are
                NaN/null. If this is specified in the writer configuration
                file that value will be used as the default.
            compute (bool): Compute dask arrays and save the image
                immediately. If ``False`` then the return value can be passed
                to :func:`~satpy.writers.compute_writer_results` to do the
                computation. This is useful when multiple images may share
                input calculations where dask can benefit from not repeating
                them multiple times. Defaults to ``True`` in the writer by
                itself, but is typically passed as ``False`` by callers where
                calculations can be combined.
            keep_palette (bool): Save palette/color table to geotiff.
                To be used with images that were palettized with the
                "palettize" enhancement. Setting this to ``True`` will cause
                the colormap of the image to be written as a "color table" in
                the output geotiff and the image data values will represent
                the index values in to that color table. By default, this will
                use the colormap used in the "palettize" operation.
                See the ``cmap`` option for other options. This option defaults
                to ``False`` and palettized images will be converted to RGB/A.
            cmap (trollimage.colormap.Colormap or None): Colormap to save
                as a color table in the output geotiff. See ``keep_palette``
                for more information. Defaults to the palette of the provided
                ``img`` object. The colormap's range should be set to match
                the index range of the palette
                (ex. `cmap.set_range(0, len(colors))`).
            tags (dict): Extra metadata to store in geotiff.
            include_scale_offset (bool): Activate inclusion of scale and offset
                factors in the geotiff to allow retrieving original values from
                the pixel values. ``False`` by default.

        .. _geotiff: http://trac.osgeo.org/geotiff/

        """
        filename = filename or self.get_filename(**img.data.attrs)

        # Update global GDAL options with these specific ones
        gdal_options = self.gdal_options.copy()
        for k in kwargs.keys():
            if k in self.GDAL_OPTIONS:
                gdal_options[k] = kwargs[k]
        if fill_value is None:
            # fall back to fill_value from configuration file
            fill_value = self.info.get('fill_value')

        dtype = dtype if dtype is not None else self.dtype
        if dtype is None:
            dtype = np.uint8

        if "alpha" in kwargs:
            raise ValueError(
                "Keyword 'alpha' is automatically set based on 'fill_value' "
                "and should not be specified")
        if np.issubdtype(dtype, np.floating):
            if img.mode != "L":
                raise ValueError("Image must be in 'L' mode for floating "
                                 "point geotiff saving")
            if fill_value is None:
                LOG.debug("Alpha band not supported for float geotiffs, "
                          "setting fill value to 'NaN'")
                fill_value = np.nan
        if keep_palette and cmap is None and img.palette is not None:
            from satpy.enhancements import create_colormap
            cmap = create_colormap({'colors': img.palette})
            cmap.set_range(0, len(img.palette) - 1)

        if tags is None:
            tags = {}
        tags.update(self.tags)
        return img.save(filename, fformat='tif', fill_value=fill_value,
                        dtype=dtype, compute=compute,
                        keep_palette=keep_palette, cmap=cmap,
                        tags=tags, include_scale_offset_tags=include_scale_offset,
                        **gdal_options)
Exemple #14
0
    def save_image(self,
                   img,
                   filename=None,
                   dtype=None,
                   fill_value=None,
                   floating_point=None,
                   compute=True,
                   keep_palette=False,
                   cmap=None,
                   **kwargs):
        """Save the image to the given ``filename`` in geotiff_ format.

        Note for faster output and reduced memory usage the ``rasterio``
        library must be installed. This writer currently falls back to
        using ``gdal`` directly, but that will be deprecated in the future.

        Args:
            img (xarray.DataArray): Data to save to geotiff.
            filename (str): Filename to save the image to. Defaults to
                ``filename`` passed during writer creation. Unlike the
                creation ``filename`` keyword argument, this filename does not
                get formatted with data attributes.
            dtype (numpy.dtype): Numpy data type to save the image as.
                Defaults to 8-bit unsigned integer (``np.uint8``). If the
                ``dtype`` argument is provided during writer creation then
                that will be used as the default.
            fill_value (int or float): Value to use where data values are
                NaN/null. If this is specified in the writer configuration
                file that value will be used as the default.
            floating_point (bool): Deprecated. Use ``dtype=np.float64``
                instead.
            compute (bool): Compute dask arrays and save the image
                immediately. If ``False`` then the return value can be passed
                to :func:`~satpy.writers.compute_writer_results` to do the
                computation. This is useful when multiple images may share
                input calculations where dask can benefit from not repeating
                them multiple times. Defaults to ``True`` in the writer by
                itself, but is typically passed as ``False`` by callers where
                calculations can be combined.
            keep_palette (bool): Save palette/color table to geotiff.
                To be used with images that were palettized with the
                "palettize" enhancement. Setting this to ``True`` will cause
                the colormap of the image to be written as a "color table" in
                the output geotiff and the image data values will represent
                the index values in to that color table. By default, this will
                use the colormap used in the "palettize" operation.
                See the ``cmap`` option for other options. This option defaults
                to ``False`` and palettized images will be converted to RGB/A.
            cmap (trollimage.colormap.Colormap or None): Colormap to save
                as a color table in the output geotiff. See ``keep_palette``
                for more information. Defaults to the palette of the provided
                ``img`` object. The colormap's range should be set to match
                the index range of the palette
                (ex. `cmap.set_range(0, len(colors))`).

        .. _geotiff: http://trac.osgeo.org/geotiff/

        """
        filename = filename or self.get_filename(**img.data.attrs)

        # Update global GDAL options with these specific ones
        gdal_options = self.gdal_options.copy()
        for k in kwargs.keys():
            if k in self.GDAL_OPTIONS:
                gdal_options[k] = kwargs[k]
        if fill_value is None:
            # fall back to fill_value from configuration file
            fill_value = self.info.get('fill_value')

        if floating_point is not None:
            import warnings
            warnings.warn(
                "'floating_point' is deprecated, use"
                "'dtype=np.float64' instead.", DeprecationWarning)
            dtype = np.float64
        dtype = dtype if dtype is not None else self.dtype
        if dtype is None:
            dtype = np.uint8

        if "alpha" in kwargs:
            raise ValueError(
                "Keyword 'alpha' is automatically set based on 'fill_value' "
                "and should not be specified")
        if np.issubdtype(dtype, np.floating):
            if img.mode != "L":
                raise ValueError("Image must be in 'L' mode for floating "
                                 "point geotiff saving")
            if fill_value is None:
                LOG.debug("Alpha band not supported for float geotiffs, "
                          "setting fill value to 'NaN'")
                fill_value = np.nan
        if keep_palette and cmap is None and img.palette is not None:
            from satpy.enhancements import create_colormap
            cmap = create_colormap({'colors': img.palette})
            cmap.set_range(0, len(img.palette) - 1)

        try:
            import rasterio  # noqa
            # we can use the faster rasterio-based save
            return img.save(filename,
                            fformat='tif',
                            fill_value=fill_value,
                            dtype=dtype,
                            compute=compute,
                            keep_palette=keep_palette,
                            cmap=cmap,
                            **gdal_options)
        except ImportError:
            LOG.warning("Using legacy/slower geotiff save method, install "
                        "'rasterio' for faster saving.")
            import warnings
            warnings.warn(
                "Using legacy/slower geotiff save method with 'gdal'."
                "This will be deprecated in the future. Install "
                "'rasterio' for faster saving and future "
                "compatibility.", PendingDeprecationWarning)

            # Map numpy data types to GDAL data types
            NP2GDAL = {
                np.float32: gdal.GDT_Float32,
                np.float64: gdal.GDT_Float64,
                np.uint8: gdal.GDT_Byte,
                np.uint16: gdal.GDT_UInt16,
                np.uint32: gdal.GDT_UInt32,
                np.int16: gdal.GDT_Int16,
                np.int32: gdal.GDT_Int32,
                np.complex64: gdal.GDT_CFloat32,
                np.complex128: gdal.GDT_CFloat64,
            }

            # force to numpy dtype object
            dtype = np.dtype(dtype)
            gformat = NP2GDAL[dtype.type]

            gdal_options['nbits'] = int(
                gdal_options.get('nbits', dtype.itemsize * 8))
            datasets, mode = img._finalize(fill_value=fill_value, dtype=dtype)
            LOG.debug("Saving to GeoTiff: %s", filename)
            g_opts = [
                "{0}={1}".format(k.upper(), str(v))
                for k, v in gdal_options.items()
            ]

            ensure_dir(filename)
            delayed = self._create_file(filename, img, gformat, g_opts,
                                        datasets, mode)
            if compute:
                return delayed.compute()
            return delayed