docs: def save(self, filename, tags=None, **kwargs):
          """
          Save GeoRaster to a file.
  
          :param filename: url
          :param tags: tags to add to default namespace
  
          optional parameters:
  
          * GDAL_TIFF_INTERNAL_MASK: specifies whether mask is within image file, or additional .msk
          * overviews: if True, will save with previews. default: True
          * factors: list of factors for the overview, default: calculated based on raster width and height
          * resampling: to build overviews. default: cubic
          * tiled: if True raster will be saved tiled, default: False
          * compress: any supported rasterio.enums.Compression value, default to LZW
          * blockxsize: int, tile x size, default:256
          * blockysize: int, tile y size, default:256
          * creation_options: dict, key value of additional creation options
          * nodata: if passed, will save with nodata value (e.g. useful for qgis)
  
          """
          if not filename.startswith("/vsi"):
              folder = os.path.abspath(os.path.join(filename, os.pardir))
              os.makedirs(folder, exist_ok=True)
  
          internal_mask = kwargs.get('GDAL_TIFF_INTERNAL_MASK', True)
          nodata_value = kwargs.get('nodata', None)
          compression = kwargs.get('compression', Compression.lzw)
          rasterio_envs = {'GDAL_TIFF_INTERNAL_MASK': internal_mask}
          if os.environ.get('DEBUG', False):
              rasterio_envs['CPL_DEBUG'] = True
          with rasterio.Env(**rasterio_envs):
              try:
                  size = self.shape
                  extension = os.path.splitext(filename)[1].lower()[1:]
                  driver = gdal_drivers[extension]
  
                  # tiled
                  tiled = kwargs.get('tiled', False)
                  blockxsize = kwargs.get('blockxsize', 256)
                  blockysize = kwargs.get('blockysize', 256)
  
                  params = {
                      'mode': "w", 'transform': self.affine, 'crs': self.crs,
                      'driver': driver, 'width': size[2], 'height': size[1], 'count': size[0],
                      'dtype': dtype_map[self.dtype.type],
                      'nodata': nodata_value,
                      'masked': True,
                      'blockxsize': min(blockxsize, size[2]),
                      'blockysize': min(blockysize, size[1]),
                      'tiled': tiled,
                      'compress': compression.name if compression in Compression else compression,
                  }
                  # additional creation options
                  # -co COPY_SRC_OVERVIEWS=YES  -co COMPRESS=DEFLATE -co PHOTOMETRIC=MINISBLACK
                  creation_options = kwargs.get('creation_options', {})
                  if creation_options:
                      params.update(**creation_options)
  
                  if self._image is None and self._filename is not None:
                      creation_options["blockxsize"] = params["blockxsize"]
                      creation_options["blockysize"] = params["blockysize"]
                      creation_options["tiled"] = params["tiled"]
                      creation_options["compress"] = params["compress"]
                      rasterio.shutil.copy(self.source_file, filename, creation_options=creation_options)
                      self._cleanup()
                      with GeoRaster2._raster_opener(filename, "r+",) as r:
                          self._add_overviews_and_tags(r, tags, kwargs)
  
                  else:
                      with GeoRaster2._raster_opener(filename, **params) as r:
  
                          # write data:
                          for band in range(self.shape[0]):
                              img = self.image.data
                              r.write_band(1 + band, img[band, :, :])
  
                          # write mask:
                          if not (
                              np.ma.getmaskarray(self.image) ==
                              np.ma.getmaskarray(self.image)[0]
                          ).all():
                              warnings.warn(
                                  "Saving different masks per band is not supported, "
                                  "the union of the masked values will be performed.", GeoRaster2Warning
                              )
  
                          if params.get('masked'):
                              mask = _mask_from_masked_array(self.image)
                              r.write_mask(mask)
  
                          self._add_overviews_and_tags(r, tags, kwargs)
  
                  return GeoRaster2.open(filename)
  
              except (rasterio.errors.RasterioIOError, rasterio._err.CPLE_BaseError, KeyError) as e:
                  raise GeoRaster2IOError(e)