Add heic2date and mov2date
This commit is contained in:
parent
355dc0b75e
commit
dfb37d1db4
4 changed files with 129 additions and 0 deletions
1
Pipfile
1
Pipfile
|
@ -7,6 +7,7 @@ name = "pypi"
|
||||||
pyheif = "*"
|
pyheif = "*"
|
||||||
Pillow = "*"
|
Pillow = "*"
|
||||||
piexif = "*"
|
piexif = "*"
|
||||||
|
exifread = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
|
|
13
README.md
13
README.md
|
@ -21,6 +21,19 @@ Usage
|
||||||
|
|
||||||
It will save the picture in the same directory, with the same name but as a JPEG and the ending `.jpg`.
|
It will save the picture in the same directory, with the same name but as a JPEG and the ending `.jpg`.
|
||||||
|
|
||||||
|
./heic2date.py original.heic
|
||||||
|
|
||||||
|
This will get the date out of your .HEIC EXIF data and rename the file into IMG_YYYYMMDD_HHMMSS.heic
|
||||||
|
|
||||||
|
./mov2date.py original.mov
|
||||||
|
|
||||||
|
This will get the date out of your .mov file and rename the file into IMG_YYYYMMDD_HHMMSS.mov
|
||||||
|
|
||||||
|
You can automate it to do it for every specific file in a directory like this:
|
||||||
|
|
||||||
|
for i in `ls *.HEIC -1 | grep -v 2022`; do ~/Projects/heic2jpeg/heic2date.py $i; done
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
41
heic2date.py
Executable file
41
heic2date.py
Executable file
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
#import exifread
|
||||||
|
import io
|
||||||
|
import pyheif
|
||||||
|
import piexif
|
||||||
|
#from PIL import Image
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
class Heic2Date:
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = Path(path)
|
||||||
|
self.img = None
|
||||||
|
|
||||||
|
def exif(self):
|
||||||
|
himage = pyheif.read_heif(self.path)
|
||||||
|
for metadata in himage.metadata or []:
|
||||||
|
if metadata['type'] == 'Exif':
|
||||||
|
return piexif.load(metadata['data'])
|
||||||
|
|
||||||
|
def date(self):
|
||||||
|
dto = self.exif()["Exif"][piexif.ExifIFD.DateTimeOriginal].decode('utf-8')
|
||||||
|
return datetime.datetime.strptime(dto, "%Y:%m:%d %H:%M:%S")
|
||||||
|
|
||||||
|
def rename(self, prefix='', postfix=''):
|
||||||
|
with open(self.path, 'rb') as image:
|
||||||
|
name = prefix + self.date().strftime("%Y%m%d_%H%M%S") + postfix
|
||||||
|
new_path = self.path.with_name(name).with_suffix(self.path.suffix)
|
||||||
|
print(new_path)
|
||||||
|
os.rename(self.path, new_path)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("Usage: heic2date.py path/to/picture.heic")
|
||||||
|
else:
|
||||||
|
img_path = sys.argv[1]
|
||||||
|
h2d = Heic2Date(img_path)
|
||||||
|
h2d.rename(prefix='IMG_', postfix='')
|
74
mov2date.py
Executable file
74
mov2date.py
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
class Mov2Date:
|
||||||
|
def __init__(self, path):
|
||||||
|
self.path = Path(path)
|
||||||
|
|
||||||
|
def date(self):
|
||||||
|
creation_time, _ = get_mov_timestamps(self.path)
|
||||||
|
return creation_time
|
||||||
|
|
||||||
|
def rename(self, prefix='', postfix=''):
|
||||||
|
name = prefix + self.date().strftime("%Y%m%d_%H%M%S") + postfix
|
||||||
|
new_path = self.path.with_name(name).with_suffix(self.path.suffix)
|
||||||
|
print(new_path)
|
||||||
|
os.rename(self.path, new_path)
|
||||||
|
|
||||||
|
def get_mov_timestamps(filename):
|
||||||
|
''' Get the creation and modification date-time from .mov metadata.
|
||||||
|
|
||||||
|
Returns None if a value is not available.
|
||||||
|
'''
|
||||||
|
from datetime import datetime as DateTime
|
||||||
|
import struct
|
||||||
|
|
||||||
|
ATOM_HEADER_SIZE = 8
|
||||||
|
# difference between Unix epoch and QuickTime epoch, in seconds
|
||||||
|
EPOCH_ADJUSTER = 2082844800
|
||||||
|
|
||||||
|
creation_time = modification_time = None
|
||||||
|
|
||||||
|
# search for moov item
|
||||||
|
with open(filename, "rb") as f:
|
||||||
|
while True:
|
||||||
|
atom_header = f.read(ATOM_HEADER_SIZE)
|
||||||
|
#~ print('atom header:', atom_header) # debug purposes
|
||||||
|
if atom_header[4:8] == b'moov':
|
||||||
|
break # found
|
||||||
|
else:
|
||||||
|
atom_size = struct.unpack('>I', atom_header[0:4])[0]
|
||||||
|
f.seek(atom_size - 8, 1)
|
||||||
|
|
||||||
|
# found 'moov', look for 'mvhd' and timestamps
|
||||||
|
atom_header = f.read(ATOM_HEADER_SIZE)
|
||||||
|
if atom_header[4:8] == b'cmov':
|
||||||
|
raise RuntimeError('moov atom is compressed')
|
||||||
|
elif atom_header[4:8] != b'mvhd':
|
||||||
|
raise RuntimeError('expected to find "mvhd" header.')
|
||||||
|
else:
|
||||||
|
f.seek(4, 1)
|
||||||
|
creation_time = struct.unpack('>I', f.read(4))[0] - EPOCH_ADJUSTER
|
||||||
|
creation_time = DateTime.fromtimestamp(creation_time)
|
||||||
|
if creation_time.year < 1990: # invalid or censored data
|
||||||
|
creation_time = None
|
||||||
|
|
||||||
|
modification_time = struct.unpack('>I', f.read(4))[0] - EPOCH_ADJUSTER
|
||||||
|
modification_time = DateTime.fromtimestamp(modification_time)
|
||||||
|
if modification_time.year < 1990: # invalid or censored data
|
||||||
|
modification_time = None
|
||||||
|
|
||||||
|
return creation_time, modification_time
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("Usage: mov2date.py path/to/movie.mov")
|
||||||
|
else:
|
||||||
|
mov_path = sys.argv[1]
|
||||||
|
m2d = Mov2Date(mov_path)
|
||||||
|
m2d.rename(prefix='IMG_', postfix='')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue