Created
May 1, 2022 21:09
-
-
Save pystardust/48b36f358839d49a5c29509f4d40034c to your computer and use it in GitHub Desktop.
Change contrast of pdf using python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
# pdf_contrast.py | |
Modify contrast of pdf | |
## Install | |
``` | |
pip install Pillow pdf2image img2pdf tqdm | |
``` | |
> Save this file as pdf_contrast.py | |
## USAGE | |
``` | |
$ python pdf_contrast.py 2.3 -i in.pdf -o out.pdf | |
Loading pdf in.pdf | |
Pages: 48 | |
Contrast x2.3: 100%|███████████████████████| 48/48 [00:02<00:00, 18.42pages/s] | |
Saving pdf to out.pdf | |
``` | |
""" | |
from argparse import ArgumentParser | |
import io | |
from PIL import ImageEnhance | |
import img2pdf | |
import pdf2image | |
from tqdm import tqdm | |
def pdf_contrast(input_file: str, contrast: float, output_file: str): | |
""" | |
Create a new pdf corresponding to the contrast multiplier | |
`input_file`: name the of the input_file | |
`contrast`: contrast multiplier. 1 corresponds to no change | |
`output_file`: name of the file to be saved | |
""" | |
print(f'Loading pdf {input_file}') | |
input_images = pdf2image.convert_from_path(input_file) | |
print(f'Pages: {len(input_images)}') | |
output_images: list[bytes] = [] | |
for img in tqdm(input_images, | |
desc=f"Contrast x{contrast}", | |
unit="pages" | |
): | |
enhancer = ImageEnhance.Contrast(img) | |
out_im = enhancer.enhance(contrast) | |
out_img_bytes = io.BytesIO() | |
out_im.save(out_img_bytes, format="JPEG") | |
output_images.append(out_img_bytes.getvalue()) | |
print(f'Saving pdf to {output_file}') | |
with open(output_file, "wb") as outf: | |
img2pdf.convert(*output_images, outputstream=outf) | |
if __name__ == "__main__": | |
input_file = "in.pdf" | |
contrast = 1.2 | |
output_file = f"out_contrast{contrast}.pdf" | |
parser = ArgumentParser(description="Modify contrast of pdfs") | |
parser.add_argument('-i', '--input', | |
help="Input filename", | |
dest="input_file") | |
parser.add_argument('-o', '--output', | |
help="Output file name", | |
dest="output_file") | |
parser.add_argument('contrast', type=float, | |
help=""" | |
Contrast multipler, must be a float. | |
1 corresponds to no change (1x). | |
2 corresponds to double (2x). | |
0.5 corresponds to half (0.5x). | |
""") | |
args = parser.parse_args() | |
pdf_contrast(args.input_file, args.contrast, args.output_file) |
The problem with the tiled version is that it applies the transformation across each tile rather than the whole image so you end up with inconsistent, blocky output.
Contrast: Original image is blended with a gray image of the same size. Here's the only point, where some calculation takes place. The gray value is determined by the mean of the original image' grayscale version.
https://stackoverflow.com/questions/59166448/whats-the-formula-used-in-pil-imageenhance-enhance-feature-for-color-brightnes
I exposed the other PIL ImageEnhance methods:
#!/usr/bin/python3
import argparse
import io
import os
import img2pdf
import pdf2image
from PIL import ImageEnhance
from tqdm import tqdm
def pdf_contrast(args):
input_images = pdf2image.convert_from_path(args.input_path)
print(f'Loaded {len(input_images)} pages')
output_images: list[bytes] = []
for img in tqdm(input_images, unit="pages"):
for method in ['Brightness', 'Contrast', 'Color', 'Sharpness']:
val = getattr(args, method.lower())
if val != 100:
enhancer = getattr(ImageEnhance, method)(img)
img = enhancer.enhance(val / 100)
out_img_bytes = io.BytesIO()
img.save(out_img_bytes, format="JPEG")
output_images.append(out_img_bytes.getvalue())
print(f'Saving {args.output_path}')
with open(args.output_path, "wb") as outf:
img2pdf.convert(*output_images, outputstream=outf)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--brightness", "-b", type=int, default=100)
parser.add_argument("--contrast", "-c", type=int, default=100)
parser.add_argument("--color", "-C", type=int, default=100)
parser.add_argument("--sharpness", "-s", type=int, default=100)
parser.add_argument("input_path", help="Input PDF file")
parser.add_argument("output_path", nargs='?', help="Output PDF file")
args = parser.parse_args()
if args.output_path is None:
params = []
if args.contrast != 100:
params.append(f"c{args.contrast}")
if args.brightness != 100:
params.append(f"b{args.brightness}")
if args.color != 100:
params.append(f"C{args.color}")
if args.sharpness != 100:
params.append(f"s{args.sharpness}")
suffix = '.' + '.'.join(params) + '.pdf'
args.output_path = os.path.splitext(args.input_path)[0] + suffix
pdf_contrast(args)
$ pdf_contrast.py out.pdf -b 115 -c 120 -C 70 -s 80
Loaded 56 pages
100%|███████████████████| 56/56 [00:08<00:00, 6.82pages/s]
Saving out.c120.b115.C70.s80.pdf
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I modified this code to use a little less memory for larger files..