Skip to content

Instantly share code, notes, and snippets.

@eldar
Last active June 2, 2022 19:39
Show Gist options
  • Save eldar/4be8c630a93a1680121c3304f71ff78c to your computer and use it in GitHub Desktop.
Save eldar/4be8c630a93a1680121c3304f71ff78c to your computer and use it in GitHub Desktop.
The script parses latex file, finds the \includegraphics commands with trim and crops the images producing a new latex document without trims.
from pathlib import Path
import re
import argparse
import imageio
import numpy as np
from tqdm import tqdm
def crop_or_pad(img, crop):
"""
crop: [left bottom right top]
if crop is negative then we pad instead of crop
"""
# left
cr = crop[0]
sh = img.shape
if cr >= 0:
img = img[:, cr:, :]
else:
pad = np.ones((sh[0], -cr, sh[2]), dtype=img.dtype) * 255
img = np.concatenate([pad, img], axis=1)
# right
cr = crop[2]
sh = img.shape
if cr >= 0:
img = img[:, :sh[1]-cr, :]
else:
pad = np.ones((sh[0], -cr, sh[2]), dtype=img.dtype) * 255
img = np.concatenate([img, pad], axis=1)
# top
cr = crop[3]
sh = img.shape
if cr >= 0:
img = img[cr:, :, :]
else:
pad = np.ones((-cr, sh[1], sh[2]), dtype=img.dtype) * 255
img = np.concatenate([pad, img], axis=0)
# bottom
cr = crop[1]
sh = img.shape
if cr >= 0:
img = img[:sh[0]-cr, :, :]
else:
pad = np.ones((-cr, sh[1], sh[2]), dtype=img.dtype) * 255
img = np.concatenate([img, pad], axis=0)
return img
def main(args):
filename = args.filename
root = args.figure_dir
out_filename = str(Path(filename).stem) + "_trimmed.tex"
fig_dir = Path(root)
with open(filename) as f:
lines = f.readlines()
out_f = open(out_filename, "w")
for line in tqdm(lines):
# match crop parameters and filename
match = re.search(r'.*includegraphics\[.*trim=(.*),\s*clip.*\]\s*\{(.*)\}', line)
if match is None:
out_f.write(line)
continue
img_file_src = match.group(2)
img_file = Path(img_file_src)
crop_str = match.group(1)
# parse trim specification into a list of integers
m = re.search(r'^\s*([-?0-9]+)pt\s*([-?0-9]+)pt\s*([-?0-9]+)pt\s*([-?0-9]+)pt\s*.*', crop_str)
crop = [int(m.group(i+1)) for i in range(4)]
if not img_file.exists():
img_file = fig_dir.joinpath(img_file)
if not args.skip_write_images:
img = imageio.imread(img_file)
img = crop_or_pad(img, crop)
imageio.imwrite(img_file, img)
# completely remove trim=..., clip section
match = re.search(r'.*includegraphics\[.*(,+\s*trim=.*,\s*clip).*\]\s*\{(.*)\}', line)
new_line = line.replace(match.group(1), "")
new_path = list(img_file.parts)
new_path.remove(root)
if args.remove_ext:
new_path = new_path[:-1] + [Path(new_path[-1]).stem]
new_path = str(Path(*new_path))
new_line = new_line.replace(img_file_src, new_path)
print(new_line)
out_f.write(new_line)
out_f.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("filename")
parser.add_argument("--figure-dir", type=str, default="figures")
parser.add_argument("--remove-ext", action='store_true')
parser.add_argument("--skip-write-images", action='store_true')
args = parser.parse_args()
main(args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment