Since we last looked at this topic a couple of months have gone by with everything working as expected when the duplicate script is used, both for duplicating sidecar files for layers that are the same size as the original and ones where the destination layer has been increased in size. The former is the most common usage although the latter case was the original reason the script was devised, but being able to carry out simple duplication for layers that are the same size as the original has proved extremely useful as this was originally a manual task requiring copying the files and renaming them which was tedious even allowing for Thunar's built in bulk renaming.
There has now been one refinement added to the original script which is an additional command line parameter -o or --overwrite which is for the purpose of specifying that existing files can be overwritten. If this parameter is included in one of the forms shown (no value required) then overwriting will be allowed, otherwise it will not be allowed.
To implement this in Python we have to add an extra line to the argument parser initialisation code block:
parser = argparse.ArgumentParser(prog='duplicate')
parser.add_argument('-s', '--source', required=True)
parser.add_argument('-d', '--dest', required=True)
parser.add_argument('-o','--overwrite', action = 'store_true')
parser.add_argument('-m', '--multisuffix', type=str, default="")
parser.add_argument('-p', '--pixelsize', type=float, default=None)
parser.add_argument('-s', '--source', required=True)
parser.add_argument('-d', '--dest', required=True)
parser.add_argument('-o','--overwrite', action = 'store_true')
parser.add_argument('-m', '--multisuffix', type=str, default="")
parser.add_argument('-p', '--pixelsize', type=float, default=None)
(the new line being the one in italics, the rest are existing)
The difference being that as no parameter value is passed with the command line parameter, an action must be specified, which is 'store_true'. The way this works is that if the parameter is specified then its value is set to True, otherwise it is set to False. (I am not sure how it comes to be False but this must be some sort of default or something ???)
Then we collect the parameter value with all of the others:
overWrite = args.overwrite
Since there is a block of a number of lines of code used to write the world file that would have to be duplicated, we put this block into a function and then call it as required by function name. So at the top of the script there is this function definition:
# function to write new world file
def writeWorldFile(wFPName,wFLines,pSize):
# write new world file
wFile = open(wFPName, "w+")
if pSize is None:
wFile.write(wFLines[0] + "\n")
else:
wFile.write(str(pSize) + "\n")
wFile.write(wFLines[1] + "\n")
wFile.write(wFLines[2] + "\n")
if pSize is None:
wFile.write(wFLines[3] + "\n")
else:
wFile.write("-" + str(pSize) + "\n")
wFile.write(wFLines[4] + "\n")
wFile.write(wFLines[5] + "\n")
wFile.close()
def writeWorldFile(wFPName,wFLines,pSize):
# write new world file
wFile = open(wFPName, "w+")
if pSize is None:
wFile.write(wFLines[0] + "\n")
else:
wFile.write(str(pSize) + "\n")
wFile.write(wFLines[1] + "\n")
wFile.write(wFLines[2] + "\n")
if pSize is None:
wFile.write(wFLines[3] + "\n")
else:
wFile.write("-" + str(pSize) + "\n")
wFile.write(wFLines[4] + "\n")
wFile.write(wFLines[5] + "\n")
wFile.close()
Then when we are going to write the world file it looks like this:
# copy world file
# first read existing world file
worldFileName = fileNameBase + ".jgw"
worldFilePath = os.path.normpath(rootPath + "/" + worldFileName)
worldFile = open(worldFilePath, "r")
worldFileLines = worldFile.readlines()
worldFile.close()
WFNNew = fileNameNew + ".jgw"
WFPNew = os.path.normpath(rootPath + "/" + WFNNew)
if overWrite:
print worldFileName + " -> " + WFNNew
writeWorldFile(WFPNew,worldFileLines,pixelSize)
elif not os.path.exists(WFPNew):
print worldFileName + " -> " + WFNNew
writeWorldFile(WFPNew,worldFileLines,pixelSize)
else:
print WFNNew + " exists --------------------"
# first read existing world file
worldFileName = fileNameBase + ".jgw"
worldFilePath = os.path.normpath(rootPath + "/" + worldFileName)
worldFile = open(worldFilePath, "r")
worldFileLines = worldFile.readlines()
worldFile.close()
WFNNew = fileNameNew + ".jgw"
WFPNew = os.path.normpath(rootPath + "/" + WFNNew)
if overWrite:
print worldFileName + " -> " + WFNNew
writeWorldFile(WFPNew,worldFileLines,pixelSize)
elif not os.path.exists(WFPNew):
print worldFileName + " -> " + WFNNew
writeWorldFile(WFPNew,worldFileLines,pixelSize)
else:
print WFNNew + " exists --------------------"
That could be simplified and made more efficient by putting the read operation into another function and only calling it when actually needed. At the moment the read is performed even if the write is not performed.
The code for duplicating the two xml files is basically the same for both and the code block looks like this:
# copy xml files
auxFileName = fileNameBase + ".jpg.aux.xml"
auxFilePath = os.path.normpath(rootPath + "/" + auxFileName)
AFNNew = fileNameNew + ".jpg.aux.xml"
AFPNew = os.path.normpath(rootPath + "/" + AFNNew)
if overWrite:
print auxFileName + " -> " + AFNNew
shutil.copyfile(auxFilePath,AFPNew)
elif not os.path.exists(AFPNew):
print auxFileName + " -> " + AFNNew
shutil.copyfile(auxFilePath,AFPNew)
else:
print AFNNew + " exists --------------------"
auxFileName = fileNameBase + ".jpg.aux.xml"
auxFilePath = os.path.normpath(rootPath + "/" + auxFileName)
AFNNew = fileNameNew + ".jpg.aux.xml"
AFPNew = os.path.normpath(rootPath + "/" + AFNNew)
if overWrite:
print auxFileName + " -> " + AFNNew
shutil.copyfile(auxFilePath,AFPNew)
elif not os.path.exists(AFPNew):
print auxFileName + " -> " + AFNNew
shutil.copyfile(auxFilePath,AFPNew)
else:
print AFNNew + " exists --------------------"
The same block is duplicated in the script with the .xml extension instead of .jpg.aux.xml
This could be made more efficient by putting this entire block of code into a function and simply passing the two different file extensions to it in two separate function calls.
Probably after doing more testing I will tidy the code up further along the suggested lines.
There is also an issue with some of the aux files possibly not being copied because every so often I will see a "CRS was undefined" message from Qgis when I load a duplicated layer. I have not yet tried to work out what is happening but the information about the CRS is stored in one of the xml files and there must be an issue happening with the file copy operation or something else happening that I haven't worked out yet.