Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Change contrast of pdf using python
"""
# 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)
@akhil-rana
Copy link

I modified this code to use a little less memory for larger files..

from argparse import ArgumentParser
from PIL import ImageEnhance, Image
import img2pdf
import pdf2image
from tqdm import tqdm
import os


def modify_contrast(image_path, contrast, tile_size=(256, 256)):
    """
    Modify the contrast of an image using tiles.
    
    Parameters
    ----------
    image_path : str
        Path to the image
    contrast : float
        Contrast multiplier. 1 corresponds to no change.
    tile_size : tuple
        Tuple specifying the size of each tile (width, height).
        
    Returns
    -------
    Image object
        An image object representing the modified image.
    """
    with Image.open(image_path) as img:
        img_width, img_height = img.size
        enhanced_img = Image.new("RGB", (img_width, img_height))

        for i in range(0, img_height, tile_size[1]):
            for j in range(0, img_width, tile_size[0]):
                box = (j, i, j + tile_size[0], i + tile_size[1])
                tile = img.crop(box)
                enhancer = ImageEnhance.Contrast(tile)
                tile = enhancer.enhance(contrast)
                enhanced_img.paste(tile, box)

        return enhanced_img


def images_to_pdf(image_paths, output_file):
    """
    Convert a list of images to a single pdf.
    
    Parameters
    ----------
    image_paths : list
        List of path to the images.
    output_file : str
        Path to the output pdf file.
        
    Returns
    -------
    None
    """
    with open(output_file, "wb") as outf:
        img2pdf.convert(*[open(img, "rb")
                        for img in image_paths], outputstream=outf)


def pdf_contrast(input_file: str, contrast: float):
    """
    Modify the contrast of a pdf.
    
    Parameters
    ----------
    input_file : str
        Path to the input pdf file.
    contrast : float
        Contrast multiplier. 1 corresponds to no change.
        
    Returns
    -------
    None
    """
    temp_folder = "temp"
    if not os.path.exists(temp_folder):
        os.makedirs(temp_folder)

    print(f'Loading pdf {input_file}')

    pdf2image.convert_from_path(
        input_file, output_folder=temp_folder, fmt='jpeg')

    image_paths = [os.path.join(temp_folder, f)
                   for f in os.listdir(temp_folder)]
    modified_images = [modify_contrast(img, contrast) for img in tqdm(
        image_paths, desc="Modifying images")]

    for i, img in enumerate(modified_images):
        img.save(image_paths[i])
    # Generate the output pdf filename
    output_file = (input_file.split('.pdf'))[0] + "_modified_contrast.pdf"

    # Convert the modified images to a pdf
    images_to_pdf(image_paths, output_file)

    # Remove the temporary images
    for img in image_paths:
        os.remove(img)

    print(f'Saving pdf to {output_file}')


if __name__ == "__main__":
    # Set up the argument parser
    parser = ArgumentParser(description="Modify contrast of pdfs")
    parser.add_argument('-i', '--input',
                        help="Input filename",
                        dest="input_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).
                             """)

    # Parse the arguments
    args = parser.parse_args()

    # Call the `pdf_contrast` function
    pdf_contrast(args.input_file, args.contrast)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment