As far as If I understand, there are several flavors of JPEG files. The details needed to change DPI metadata of JFIF flavor are explained here. Based on that I wrote my own Python script which allows to change DPI setting of a JFIF flavor JPEG without reencoding:
import sys,os
filename = sys.argv[1]
x_density = int(sys.argv[2])
y_density = int(sys.argv[3])
echo = True
if len(sys.argv) > 4:
if sys.argv[4] == 'quiet':
echo = False
assert x_density > 0 and x_density < 65536
assert y_density > 0 and y_density < 65536
# JPEG markers
APP0 = bytes.fromhex('FFD8FFE0') # JFIF
APP1 = bytes.fromhex('FFD8FFE1') # EXIF
with open(filename, 'rb+') as f: # 'w+b'
chunk = f.read(4)
if chunk == APP0:
f.seek(2,1) # relative seek
chunk = f.read(5)
if chunk == bytes.fromhex('4A46494600'): # JFIF indentfier
f.seek(2,1) # relative seek
print('Setting density of ' + os.path.split(filename)[1] + ' to ' + str(x_density) + 'x' + str(y_density) + ' dpi.') if echo else None
f.write(bytes.fromhex('01'))
f.write(x_density.to_bytes(2,'big'))
f.write(y_density.to_bytes(2,'big'))
else:
print('File hasn''t got the JFIF indentifier, nothing was done.')
elif chunk == APP1:
f.close() # needed otherwise exiftool cannot operate on file
print('This is an EXIF-JPEG, using exiftool to set DPI...')
os.system('exiftool -P -overwrite_original -XResolution={} -YResolution={} "{}"'.format(x_density,y_density,filename))
else:
print('File is not JFIF nor EXIF, cannot set DPI, nothing was done.')
print('Done.') if echo else None
Usage:
python this_script.py some-image.jpg Xdpi Ydpi [quiet]
The script does not read the full image nor change the file length, it just modifies a few bytes directly on the JPEG file.
Moreover, no temporary/backup copy is made, because I wanted the script to work on hard-linked files, so the overall process is quite fast for JFIF JPEGs.
The script is able to identify EXIF JPEGs and use exiftool to change DPI. If you don't have exiftool installed in your computer remember to adjust the script accordingly. A reason to use this script even if you have exiftool installed is speed; in my test this script is much faster than exiftool.
JFIF and EXIF are the most common flavors of JPEG files, but I hope someone is able to improve this script or report a way to set DPI (without reencoding) also for Adobe JPEGs with APP14 marker, which are not so rare.