To be run from the QGIS Python Console.
The new raster will be in the same folder and with the same extension (tested only with tif), to the name shift by x and by y will be added, e.g. in.tif -> in_10_20.tif.
After the first run, later just call shift_layer(100, -3050), by default the active layer will be used.
Edit 2023.12.19: change default value of layer parameter of shift_layer function from iface.activeLayer() to iface.activeLayer, so active layer woulb be recalculated each time the function is called with the default parameter
import pathlib
from pathlib import Path
from typing import Union, Callable
def shift_layer(
shift_x: float = 0, shift_y: float = 0,
layer: Union[
QgsMapLayer, Callable[[None], QgsMapLayer]] = iface.activeLayer,
add_layer: bool = True) -> None:
# if iface.activeLayer() is used as default value for layer,
# the active layer at the moment of declaration will be used
if isinstance(layer, QgsMapLayer):
_layer = layer
else:
_layer = layer()
src = pathlib.Path(_layer.source())
stem_suffix = f'{shift_x}_{shift_y}'
target: Path = src.with_stem(src.stem + stem_suffix)
shifted_extent_gdal_order: tuple[float, float, float, float] = (
get_shifted_extent_ggal_order(_layer, shift_x, shift_y)
)
shifted_raster: str = shift_raster(
_layer, shifted_extent_gdal_order, target
)['OUTPUT']
if not add_layer:
return None
iface.addRasterLayer(shifted_raster, _layer.name() + stem_suffix)
def shift_raster(
layer: QgsRasterLayer,
new_extent_gdal_order: tuple[float, float, float, float],
target: Path) -> dict[str, str]:
assert isinstance(layer, QgsRasterLayer), 'not raster layer'
return processing.run('gdal:translate', {
'INPUT': layer.source(),
'EXTRA': f"-a_ullr {' '.join(map(str, new_extent_gdal_order))}",
'OUTPUT': str(target)
})
def get_shifted_extent_gdal_order(
layer: QgsMapLayer,
shift_x: float = 0,
shift_y: float = 0) -> tuple[float, float, float, float]:
return (
layer.extent().xMinimum() + shift_x,
layer.extent().yMaximum() + shift_y,
layer.extent().xMaximum() + shift_x,
layer.extent().yMinimum() + shift_y
)
if name == 'console':
shift_layer(100, -3050)