Here's a quickly hacked together idea of how you could copy forward the APP0
segment (which contains the dpi) from your input image to your output image. There is some pretty reasonable description of the anatomy of a JPEG here.
import cv2
import numpy as np
# Read input image with 300 dpi
im = cv2.imread('image.jpg')
# Grab its APP0 segment (with dpi) in first 18 bytes
with open('image.jpg', 'rb') as jpeg:
APP0 = jpeg.read(18)
# Process image ...
# Write result as JPEG to in-memory buffer
_, buffer = cv2.imencode(".jpg", im)
# Copy forward APP0 from original image
buffer[:18] = np.frombuffer(APP0, np.uint8)
# Write JPEG to disk with copied forward APP0
with open('result.jpg', 'wb') as out:
out.write(buffer)
Check file with exiftool
:
exiftool result.jpg
ExifTool Version Number : 12.30
File Name : result.jpg
Directory : .
File Size : 18 KiB
File Modification Date/Time : 2021:12:21 15:51:14+00:00
File Access Date/Time : 2021:12:21 15:51:23+00:00
File Inode Change Date/Time : 2021:12:21 15:51:22+00:00
File Permissions : -rw-r--r--
File Type : JPEG
File Type Extension : jpg
MIME Type : image/jpeg
JFIF Version : 1.01
Resolution Unit : inches
X Resolution : 300 <--- DPI HERE
Y Resolution : 300 <--- DPI HERE
Image Width : 640
Image Height : 480
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2)
Image Size : 640x480
Megapixels : 0.307
It is probably more professional to use PyExifTool, if you don't mind adding another dependency to your project.
import exiftool
# Get dpi from input image
with exiftool.ExifTool() as et:
res = et.get_tags(['JFIF:XResolution','JFIF:YResolution'], 'image.jpg')
That gives this as the value for res
:
{'SourceFile': 'image.jpg', 'JFIF:XResolution': 300, 'JFIF:YResolution': 300}
And you can set the dpi on the output file to 10 or whatever you want like this:
# You can probably omit the full path to exiftool if it is on your PATH
with exiftool.ExifTool("/opt/homebrew/bin/exiftool") as et:
et.execute(b"-JFIF:XResolution=10", b"result.jpg")
et.execute(b"-JFIF:YResolution=10", b"result.jpg")