MIDDLE_POINT_DEPTH = 0.4 * POINTS_PER_CM
SPINE_LIMIT = 1 * POINTS_PER_CM
QUARTER_SCALE_FACTOR = 0.5
-PAGE_ORDER = (3,0,7,4,1,2,5,6)
+PAGE_ORDER_FOR_NUP4 = (3,0,7,4,1,2,5,6)
# some helpers
class HandledException(Exception):
pass
-def validate_page_range(p_string, err_msg_prefix):
- prefix = f"{err_msg_prefix}: page range string"
- if '-' not in p_string:
- raise HandledException(f"{prefix} lacks '-': {p_string}")
- tokens = p_string.split("-")
- if len(tokens) > 2:
- raise HandledException(f"{prefix} has too many '-': {p_string}")
- for i, token in enumerate(tokens):
- if token == "":
- continue
- if i == 0 and token == "start":
- continue
- if i == 1 and token == "end":
- continue
- try:
- int(token)
- except ValueError:
- raise HandledException(f"{prefix} carries value neither integer, nor 'start', nor 'end': {p_string}")
- if int(token) < 1:
- raise HandledException(f"{prefix} carries page number <1: {p_string}")
- start = -1
- end = -1
- try:
- start = int(tokens[0])
- end = int(tokens[1])
- except ValueError:
- pass
- if start > 0 and end > 0 and start > end:
- raise HandledException(f"{prefix} has higher start than end value: {p_string}")
-
-def split_crops_string(c_string):
- initial_split = c_string.split(':')
- if len(initial_split) > 1:
- page_range = initial_split[0]
- crops = initial_split[1]
- else:
- page_range = None
- crops = initial_split[0]
- return page_range, crops
-
-def parse_page_range(range_string, pages):
- start_page = 0
- end_page = len(pages)
- if range_string:
- start, end = range_string.split('-')
- if not (len(start) == 0 or start == "start"):
- start_page = int(start) - 1
- if not (len(end) == 0 or end == "end"):
- end_page = int(end)
- return start_page, end_page
-
-def draw_cut(canvas, x_spine_limit, direction):
- outer_start_x = x_spine_limit - 0.5 * CUT_WIDTH * direction
- inner_start_x = x_spine_limit + 0.5 * CUT_WIDTH * direction
- middle_point_y = A4_HALF_HEIGHT + MIDDLE_POINT_DEPTH * direction
- end_point_y = A4_HALF_HEIGHT + CUT_DEPTH * direction
- canvas.line(inner_start_x, A4_HALF_HEIGHT, x_spine_limit, end_point_y)
- canvas.line(x_spine_limit, end_point_y, x_spine_limit, middle_point_y)
- canvas.line(x_spine_limit, middle_point_y, outer_start_x, A4_HALF_HEIGHT)
-
def parse_args():
parser = argparse.ArgumentParser(description=__doc__, epilog=help_epilogue, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-i", "--input_file", action="append", required=True, help="input PDF file")
parser.add_argument("-n", "--nup4", action='store_true', help="puts 4 input pages onto 1 output page, adds binding cut stencil")
parser.add_argument("-a", "--analyze", action="store_true", help="in --nup4, print lines identifying spine, page borders")
parser.add_argument("-m", "--print_margin", type=float, default=0.43, help="print margin for --nup4 in cm (default 0.43)")
- args = parser.parse_args()
+ return parser.parse_args()
- # some basic input validation
+def validate_inputs_first_pass(args):
for filename in args.input_file:
if not os.path.isfile(filename):
raise HandledException(f"-i: {filename} is not a file")
except ValueError:
raise HandledException(f"-m: non-float value: {arg.print_margin}")
- return args
-
-def main():
- args = parse_args()
- if args.nup4:
+def validate_page_range(p_string, err_msg_prefix):
+ prefix = f"{err_msg_prefix}: page range string"
+ if '-' not in p_string:
+ raise HandledException(f"{prefix} lacks '-': {p_string}")
+ tokens = p_string.split("-")
+ if len(tokens) > 2:
+ raise HandledException(f"{prefix} has too many '-': {p_string}")
+ for i, token in enumerate(tokens):
+ if token == "":
+ continue
+ if i == 0 and token == "start":
+ continue
+ if i == 1 and token == "end":
+ continue
try:
- import reportlab.pdfgen.canvas
- except ImportError:
- raise HandledException("-n: need reportlab library installed for --nup4")
+ int(token)
+ except ValueError:
+ raise HandledException(f"{prefix} carries value neither integer, nor 'start', nor 'end': {p_string}")
+ if int(token) < 1:
+ raise HandledException(f"{prefix} carries page number <1: {p_string}")
+ start = -1
+ end = -1
+ try:
+ start = int(tokens[0])
+ end = int(tokens[1])
+ except ValueError:
+ pass
+ if start > 0 and end > 0 and start > end:
+ raise HandledException(f"{prefix} has higher start than end value: {p_string}")
+
+def split_crops_string(c_string):
+ initial_split = c_string.split(':')
+ if len(initial_split) > 1:
+ page_range = initial_split[0]
+ crops = initial_split[1]
+ else:
+ page_range = None
+ crops = initial_split[0]
+ return page_range, crops
+
+def parse_page_range(range_string, pages):
+ start_page = 0
+ end_page = len(pages)
+ if range_string:
+ start, end = range_string.split('-')
+ if not (len(start) == 0 or start == "start"):
+ start_page = int(start) - 1
+ if not (len(end) == 0 or end == "end"):
+ end_page = int(end)
+ return start_page, end_page
- # select pages from input files
+def read_inputs_to_pagelist(args_input_file, args_page_range):
pages_to_add = []
opened_files = []
new_page_num = 0
- for i, input_file in enumerate(args.input_file):
+ for i, input_file in enumerate(args_input_file):
file = open(input_file, 'rb')
opened_files += [file]
reader = pypdf.PdfReader(file)
range_string = None
- if args.page_range and len(args.page_range) > i:
- range_string = args.page_range[i]
+ if args_page_range and len(args_page_range) > i:
+ range_string = args_page_range[i]
start_page, end_page = parse_page_range(range_string, reader.pages)
if end_page > len(reader.pages): # no need to test start_page cause start_page > end_page is checked above
raise HandledException(f"-p: page range goes beyond pages of input file: {range_string}")
page = reader.pages[old_page_num]
pages_to_add += [page]
print(f"-i, -p: read in {input_file} page number {old_page_num+1} as new page {new_page_num}")
+ return pages_to_add, opened_files
- # we can do some more input validations now that we know how many pages output should have
+def validate_inputs_second_pass(args, pages_to_add):
if args.crops:
for c_string in args.crops:
page_range, _= split_crops_string(c_string)
if r > len(pages_to_add):
raise HandledException(f"-r: page number beyond number of pages we're building: {r}")
- # rotate page canvas (as opposed to using PDF's /Rotate command)
- if args.rotate_page:
- for rotate_page in args.rotate_page:
+def rotate_pages(args_rotate_page, pages_to_add):
+ if args_rotate_page:
+ for rotate_page in args_rotate_page:
page = pages_to_add[rotate_page - 1]
page.add_transformation(pypdf.Transformation().translate(tx=-A4_WIDTH/2, ty=-A4_HEIGHT/2))
page.add_transformation(pypdf.Transformation().rotate(-90))
page.add_transformation(pypdf.Transformation().translate(tx=A4_WIDTH/2, ty=A4_HEIGHT/2))
print(f"-r: rotating (by 90°) page {rotate_page}")
- # if necessary, pad pages to multiple of 8
- if args.nup4:
- mod_to_8 = len(pages_to_add) % 8
- if mod_to_8 > 0:
- print(f"-n: number of input pages {len(pages_to_add)} not multiple of 8, padding to that")
- for _ in range(8 - mod_to_8):
- new_page = pypdf.PageObject.create_blank_page(width=A4_WIDTH, height=A4_HEIGHT)
- pages_to_add += [new_page]
+def pad_pages_to_multiple_of_8(pages_to_add):
+ mod_to_8 = len(pages_to_add) % 8
+ if mod_to_8 > 0:
+ old_len = len(pages_to_add)
+ for _ in range(8 - mod_to_8):
+ new_page = pypdf.PageObject.create_blank_page(width=A4_WIDTH, height=A4_HEIGHT)
+ pages_to_add += [new_page]
+ print(f"-n: number of input pages {old_len} not required multiple of 8, padded to {len(pages_to_add)}")
- # normalize all pages to portrait A4
+def normalize_pages_to_A4(pages_to_add):
for page in pages_to_add:
- if "/Rotate" in page:
+ if "/Rotate" in page: # TODO: preserve rotation, but in canvas?
page.rotate(360 - page["/Rotate"])
page.mediabox.left = 0
page.mediabox.bottom = 0
page.mediabox.right = A4_WIDTH
page.cropbox = page.mediabox
- # determine page crops, zooms, crop symmetry
+def collect_per_page_crops_and_zooms(args_crops, args_symmetry, pages_to_add):
crops_at_page = [(0,0,0,0)]*len(pages_to_add)
zoom_at_page = [1]*len(pages_to_add)
- if args.crops:
- for c_string in args.crops:
+ if args_crops:
+ for c_string in args_crops:
page_range, crops = split_crops_string(c_string)
start_page, end_page = parse_page_range(page_range, pages_to_add)
crop_left_cm, crop_bottom_cm, crop_right_cm, crop_top_cm = [float(x) for x in crops.split(',')]
crop_bottom = crop_bottom_cm * POINTS_PER_CM
crop_right = crop_right_cm * POINTS_PER_CM
crop_top = crop_top_cm * POINTS_PER_CM
- prefix = "-c, -t" if args.symmetry else "-c"
- suffix = " (but alternating left and right crop between even and odd pages)" if args.symmetry else ""
+ prefix = "-c, -t" if args_symmetry else "-c"
+ suffix = " (but alternating left and right crop between even and odd pages)" if args_symmetry else ""
print(f"{prefix}: to pages {start_page + 1} to {end_page} applying crops: left {crop_left_cm}cm, bottom {crop_bottom_cm}cm, right {crop_right_cm}cm, top {crop_top_cm}cm{suffix}")
cropped_width = A4_WIDTH - crop_left - crop_right
cropped_height = A4_HEIGHT - crop_bottom - crop_top
else:
zoom = max(zoom_horizontal, zoom_vertical)
for page_num in range(start_page, end_page):
- if args.symmetry and page_num % 2:
+ if args_symmetry and page_num % 2:
crops_at_page[page_num] = (crop_right, crop_bottom, crop_left, crop_top)
else:
crops_at_page[page_num] = (crop_left, crop_bottom, crop_right, crop_top)
zoom_at_page[page_num] = zoom
+ return crops_at_page, zoom_at_page
+
+def build_single_pages_output(writer, pages_to_add, crops_at_page, zoom_at_page):
+ print("building 1-input-page-per-output-page book")
+ odd_page = True
+ for i, page in enumerate(pages_to_add):
+ crop_left, crop_bottom, crop_right, crop_top = crops_at_page[i]
+ zoom = zoom_at_page[i]
+ page.add_transformation(pypdf.Transformation().translate(tx=-crop_left, ty=-crop_bottom))
+ page.add_transformation(pypdf.Transformation().scale(zoom, zoom))
+ cropped_width = A4_WIDTH - crop_left - crop_right
+ cropped_height = A4_HEIGHT - crop_bottom - crop_top
+ page.mediabox.right = cropped_width * zoom
+ page.mediabox.top = cropped_height * zoom
+ writer.add_page(page)
+ odd_page = not odd_page
+ print(f"built page number {i+1} (of {len(pages_to_add)})")
+
+def resort_pages_for_nup4(pages_to_add):
+ new_page_order = []
+ new_i_order = []
+ eight_pack = []
+ i = 0
+ n_eights = 0
+ for page in pages_to_add:
+ if i == 0:
+ eight_pack = []
+ eight_pack += [page]
+ i += 1
+ if i == 8:
+ i = 0
+ for n in PAGE_ORDER_FOR_NUP4:
+ new_i_order += [8 * n_eights + n]
+ new_page_order += [eight_pack[n]]
+ n_eights += 1
+ return new_page_order, new_i_order
+
+def nup4_inner_page_transform(page, crops, zoom, bonus_shrink_factor, printable_margin, printable_scale, nup4_position):
+ crop_left, crop_bottom, crop_right, crop_top = crops
+ page.add_transformation(pypdf.Transformation().translate(ty=(A4_HEIGHT / zoom - (A4_HEIGHT - crop_top))))
+ if nup4_position == 0 or nup4_position == 2:
+ page.add_transformation(pypdf.Transformation().translate(tx=-crop_left))
+ elif nup4_position == 1 or nup4_position == 3:
+ page.add_transformation(pypdf.Transformation().translate(tx=(A4_WIDTH / zoom - (A4_WIDTH - crop_right))))
+ page.add_transformation(pypdf.Transformation().scale(zoom * bonus_shrink_factor, zoom * bonus_shrink_factor))
+ if nup4_position == 2 or nup4_position == 3:
+ page.add_transformation(pypdf.Transformation().translate(ty=-2*printable_margin/printable_scale))
+
+def nup4_outer_page_transform(page, bonus_shrink_factor, nup4_position):
+ page.add_transformation(pypdf.Transformation().translate(ty=(1-bonus_shrink_factor)*A4_HEIGHT))
+ if nup4_position == 0 or nup4_position == 1:
+ y_section = A4_HEIGHT
+ page.mediabox.bottom = A4_HALF_HEIGHT
+ page.mediabox.top = A4_HEIGHT
+ if nup4_position == 2 or nup4_position == 3:
+ y_section = 0
+ page.mediabox.bottom = 0
+ page.mediabox.top = A4_HALF_HEIGHT
+ if nup4_position == 0 or nup4_position == 2:
+ x_section = 0
+ page.mediabox.left = 0
+ page.mediabox.right = A4_HALF_WIDTH
+ if nup4_position == 1 or nup4_position == 3:
+ page.add_transformation(pypdf.Transformation().translate(tx=(1-bonus_shrink_factor)*A4_WIDTH))
+ x_section = A4_WIDTH
+ page.mediabox.left = A4_HALF_WIDTH
+ page.mediabox.right = A4_WIDTH
+ page.add_transformation(pypdf.Transformation().translate(tx=x_section, ty=y_section))
+ page.add_transformation(pypdf.Transformation().scale(QUARTER_SCALE_FACTOR, QUARTER_SCALE_FACTOR))
+
+def ornate_nup4(writer, args_analyze, is_front_page, new_page, printable_margin, printable_scale, bonus_shrink_factor, canvas_class):
+ if args_analyze:
+ # borders
+ packet = io.BytesIO()
+ c = canvas_class(packet, pagesize=A4)
+ c.setLineWidth(0.1)
+ c.line(0, A4_HEIGHT, A4_WIDTH, A4_HEIGHT)
+ c.line(0, A4_HALF_HEIGHT, A4_WIDTH, A4_HALF_HEIGHT)
+ c.line(0, 0, A4_WIDTH, 0)
+ c.line(0, A4_HEIGHT, 0, 0)
+ c.line(A4_HALF_WIDTH, A4_HEIGHT, A4_HALF_WIDTH, 0)
+ c.line(A4_WIDTH, A4_HEIGHT, A4_WIDTH, 0)
+ c.save()
+ new_pdf = pypdf.PdfReader(packet)
+ new_page.merge_page(new_pdf.pages[0])
+ printable_offset_x = printable_margin
+ printable_offset_y = printable_margin * A4_HEIGHT / A4_WIDTH
+ new_page.add_transformation(pypdf.Transformation().scale(printable_scale, printable_scale))
+ new_page.add_transformation(pypdf.Transformation().translate(tx=printable_offset_x, ty=printable_offset_y))
+ x_left_spine_limit = A4_HALF_WIDTH * bonus_shrink_factor
+ x_right_spine_limit = A4_WIDTH - x_left_spine_limit
+ if args_analyze or is_front_page:
+ packet = io.BytesIO()
+ c = canvas_class(packet, pagesize=A4)
+ if args_analyze:
+ # spine lines
+ c.setLineWidth(0.1)
+ c.line(x_left_spine_limit, A4_HEIGHT, x_left_spine_limit, 0)
+ c.line(x_right_spine_limit, A4_HEIGHT, x_right_spine_limit, 0)
+ if is_front_page:
+ c.setLineWidth(0.2)
+ draw_cut(c, x_left_spine_limit, (1))
+ draw_cut(c, x_right_spine_limit, (-1))
+ if args_analyze or is_front_page:
+ c.save()
+ new_pdf = pypdf.PdfReader(packet)
+ new_page.merge_page(new_pdf.pages[0])
+
+def draw_cut(canvas, x_spine_limit, direction):
+ outer_start_x = x_spine_limit - 0.5 * CUT_WIDTH * direction
+ inner_start_x = x_spine_limit + 0.5 * CUT_WIDTH * direction
+ middle_point_y = A4_HALF_HEIGHT + MIDDLE_POINT_DEPTH * direction
+ end_point_y = A4_HALF_HEIGHT + CUT_DEPTH * direction
+ canvas.line(inner_start_x, A4_HALF_HEIGHT, x_spine_limit, end_point_y)
+ canvas.line(x_spine_limit, end_point_y, x_spine_limit, middle_point_y)
+ canvas.line(x_spine_limit, middle_point_y, outer_start_x, A4_HALF_HEIGHT)
+def main():
+ args = parse_args()
+ validate_inputs_first_pass(args)
+ if args.nup4:
+ try:
+ from reportlab.pdfgen.canvas import Canvas
+ except ImportError:
+ raise HandledException("-n: need reportlab.pdfgen.canvas installed for --nup4")
+ pages_to_add, opened_files = read_inputs_to_pagelist(args.input_file, args.page_range)
+ validate_inputs_second_pass(args, pages_to_add)
+ rotate_pages(args.rotate_page, pages_to_add)
+ if args.nup4:
+ pad_pages_to_multiple_of_8(pages_to_add)
+ normalize_pages_to_A4(pages_to_add)
+ crops_at_page, zoom_at_page = collect_per_page_crops_and_zooms(args.crops, args.symmetry, pages_to_add)
writer = pypdf.PdfWriter()
if not args.nup4:
- # single-page output
- print("building 1-input-page-per-output-page book")
- odd_page = True
- for i, page in enumerate(pages_to_add):
- crop_left, crop_bottom, crop_right, crop_top = crops_at_page[i]
- zoom = zoom_at_page[i]
- page.add_transformation(pypdf.Transformation().translate(tx=-crop_left, ty=-crop_bottom))
- page.add_transformation(pypdf.Transformation().scale(zoom, zoom))
- cropped_width = A4_WIDTH - crop_left - crop_right
- cropped_height = A4_HEIGHT - crop_bottom - crop_top
- page.mediabox.right = cropped_width * zoom
- page.mediabox.top = cropped_height * zoom
- writer.add_page(page)
- odd_page = not odd_page
- print(f"built page number {i+1} (of {len(pages_to_add)})")
-
+ build_single_pages_output(writer, pages_to_add, crops_at_page, zoom_at_page)
else:
- # --nup4 output
print("-n: building 4-input-pages-per-output-page book")
print(f"-m: applying printable-area margin of {args.print_margin}cm")
if args.analyze:
printable_scale = (A4_WIDTH - 2 * printable_margin)/A4_WIDTH
spine_part_of_page = (SPINE_LIMIT / A4_HALF_WIDTH) / printable_scale
bonus_shrink_factor = 1 - spine_part_of_page
- new_page_order = []
- new_i_order = []
- eight_pack = []
- i = 0
- n_eights = 0
- for page in pages_to_add:
- if i == 0:
- eight_pack = []
- eight_pack += [page]
- i += 1
- if i == 8:
- i = 0
- for n in PAGE_ORDER:
- new_i_order += [8 * n_eights + n]
- new_page_order += [eight_pack[n]]
- n_eights += 1
+ pages_to_add, new_i_order = resort_pages_for_nup4(pages_to_add)
i = 0
page_count = 0
- front_page = True
- for j, page in enumerate(new_page_order):
+ is_front_page = True
+ for j, page in enumerate(pages_to_add):
if i == 0:
new_page = pypdf.PageObject.create_blank_page(width=A4_WIDTH, height=A4_HEIGHT)
-
- # in-section transformations: align pages on top, left-hand pages to left, right-hand to right
new_i = new_i_order[j]
- crop_left, crop_bottom, crop_right, crop_top = crops_at_page[new_i]
- zoom = zoom_at_page[new_i]
- page.add_transformation(pypdf.Transformation().translate(ty=(A4_HEIGHT / zoom - (A4_HEIGHT - crop_top))))
- if i == 0 or i == 2:
- page.add_transformation(pypdf.Transformation().translate(tx=-crop_left))
- elif i == 1 or i == 3:
- page.add_transformation(pypdf.Transformation().translate(tx=(A4_WIDTH / zoom - (A4_WIDTH - crop_right))))
- page.add_transformation(pypdf.Transformation().scale(zoom * bonus_shrink_factor, zoom * bonus_shrink_factor))
- if i == 2 or i == 3:
- page.add_transformation(pypdf.Transformation().translate(ty=-2*printable_margin/printable_scale))
-
- # outer section transformations
- page.add_transformation(pypdf.Transformation().translate(ty=(1-bonus_shrink_factor)*A4_HEIGHT))
- if i == 0 or i == 1:
- y_section = A4_HEIGHT
- page.mediabox.bottom = A4_HALF_HEIGHT
- page.mediabox.top = A4_HEIGHT
- if i == 2 or i == 3:
- y_section = 0
- page.mediabox.bottom = 0
- page.mediabox.top = A4_HALF_HEIGHT
- if i == 0 or i == 2:
- x_section = 0
- page.mediabox.left = 0
- page.mediabox.right = A4_HALF_WIDTH
- if i == 1 or i == 3:
- page.add_transformation(pypdf.Transformation().translate(tx=(1-bonus_shrink_factor)*A4_WIDTH))
- x_section = A4_WIDTH
- page.mediabox.left = A4_HALF_WIDTH
- page.mediabox.right = A4_WIDTH
- page.add_transformation(pypdf.Transformation().translate(tx=x_section, ty=y_section))
- page.add_transformation(pypdf.Transformation().scale(QUARTER_SCALE_FACTOR, QUARTER_SCALE_FACTOR))
+ nup4_inner_page_transform(page, crops_at_page[new_i], zoom_at_page[new_i], bonus_shrink_factor, printable_margin, printable_scale, i)
+ nup4_outer_page_transform(page, bonus_shrink_factor, i)
new_page.merge_page(page)
page_count += 1
print(f"merged page number {page_count} (of {len(pages_to_add)})")
i += 1
if i > 3:
- if args.analyze:
- # borders
- packet = io.BytesIO()
- c = reportlab.pdfgen.canvas.Canvas(packet, pagesize=A4)
- c.setLineWidth(0.1)
- c.line(0, A4_HEIGHT, A4_WIDTH, A4_HEIGHT)
- c.line(0, A4_HALF_HEIGHT, A4_WIDTH, A4_HALF_HEIGHT)
- c.line(0, 0, A4_WIDTH, 0)
- c.line(0, A4_HEIGHT, 0, 0)
- c.line(A4_HALF_WIDTH, A4_HEIGHT, A4_HALF_WIDTH, 0)
- c.line(A4_WIDTH, A4_HEIGHT, A4_WIDTH, 0)
- c.save()
- new_pdf = pypdf.PdfReader(packet)
- new_page.merge_page(new_pdf.pages[0])
- printable_offset_x = printable_margin
- printable_offset_y = printable_margin * A4_HEIGHT / A4_WIDTH
- new_page.add_transformation(pypdf.Transformation().scale(printable_scale, printable_scale))
- new_page.add_transformation(pypdf.Transformation().translate(tx=printable_offset_x, ty=printable_offset_y))
- x_left_spine_limit = A4_HALF_WIDTH * bonus_shrink_factor
- x_right_spine_limit = A4_WIDTH - x_left_spine_limit
- if args.analyze or front_page:
- packet = io.BytesIO()
- c = reportlab.pdfgen.canvas.Canvas(packet, pagesize=A4)
- if args.analyze:
- # spine lines
- c.setLineWidth(0.1)
- c.line(x_left_spine_limit, A4_HEIGHT, x_left_spine_limit, 0)
- c.line(x_right_spine_limit, A4_HEIGHT, x_right_spine_limit, 0)
- if front_page:
- c.setLineWidth(0.2)
- draw_cut(c, x_left_spine_limit, (1))
- draw_cut(c, x_right_spine_limit, (-1))
- if args.analyze or front_page:
- c.save()
- new_pdf = pypdf.PdfReader(packet)
- new_page.merge_page(new_pdf.pages[0])
+ ornate_nup4(writer, args.analyze, is_front_page, new_page, printable_margin, printable_scale, bonus_shrink_factor, Canvas)
writer.add_page(new_page)
i = 0
- front_page = not front_page
-
- # write and close
+ is_front_page = not is_front_page
for file in opened_files:
file.close()
with open(args.output_file, 'wb') as output_file: