def _merge_pdfs(self, in_dir, out_file): """Merges PDFs in a given directory and outputs it to a single PDF file. If `same_page_number` is set to true in the config file, all tests will have `max_pages` number of pages. Parameters: in_dir (str): Path to the input directory containing the PDF files to be merged. out_file (str): Path to the merged PDF. """ pw = PdfFileWriter() firstPDF = True for f in sorted(listdir(in_dir)): if isfile(join(in_dir, f)) and regex.match( '^test.*\.pdf$', f, flags=regex.IGNORECASE): pr = PdfFileReader(join(in_dir, f), strict=False) form = pr.trailer["/Root"][ "/AcroForm"] # see: https://stackoverflow.com/questions/47288578/pdf-form-filled-with-pypdf2-does-not-show-in-print pw.appendPagesFromReader(pr) if self.config['same_page_number'] and pr.getNumPages( ) < self.config['max_pages']: for i in range(self.config['max_pages'] - pr.getNumPages()): # pylint: disable=unused-variable pw.addBlankPage() if firstPDF: pw._root_object.update({NameObject("/AcroForm"): form}) firstPDF = False else: pw._root_object["/AcroForm"]["/Fields"].extend( form["/Fields"]) pw._root_object["/AcroForm"].update( {NameObject("/NeedAppearances"): BooleanObject(True)}) f = codecs.open(out_file, 'wb') pw.write(f) f.close()
def draw_rectangles_for_solution(self, f_in, f_out, solution, points): """Drawing green filled rectangles near the correct answers for every problem, in order to indicate the correct solution. It calculates and writes the total score achieved too. Parameters: f_in (str): Path to the input PDF file. f_out (str): Path to the output PDF file. solution (dict): The solution (correct answers) corresponding to the input PDF file (f_in). points (float): Total points achieved. """ pr = PdfFileReader(f_in) dest = pr.getNamedDestinations() fields = pr.getFields() # """IT IS NOT WORKING IF THIS COMES FIRST:""" # a = PdfAnnotator(f_in) # for p in range(pr.getNumPages()): # for dk, dv in dest.items(): # if pr.getDestinationPageNumber(dv) == p and dk.startswith('ht_'): # inds = [int(ind) for ind in dk[3:].split(':')] # # if inds[2] in solution[inds[1]][1]: # if inds[4] in solution[inds[1]][1]: # # using some hard-coded values: # a.add_annotation('square', # Location(x1=float(dv['/Left']), y1=float(dv['/Top']), x2=float(dv['/Left'])+5, y2=float(dv['/Top'])+5, page=p), # Appearance(stroke_color=(0, 1, 0), stroke_width=5),) # a.write(f_out) pw = PdfFileWriter() # pr = PdfFileReader(f_out, strict=False) pr = PdfFileReader(f_in, strict=False) pw.appendPagesFromReader(pr) pw._root_object.update( {NameObject("/AcroForm"): pr.trailer["/Root"]["/AcroForm"]}) pw._root_object["/AcroForm"].update( {NameObject("/NeedAppearances"): BooleanObject(True)}) for p in range(pr.getNumPages()): self._update_page_form_checkbox_values(pw.getPage(p), { fk: fv['/V'] for fk, fv in fields.items() if '/V' in fv.keys() }) # sometimes '/V' disappears from the keys self._update_page_form_checkbox_values(pw.getPage(0), {'points': str(points)}) f = codecs.open(f_out, 'wb') pw.write(f) f.close() a = PdfAnnotator(f_out) for p in range(pr.getNumPages()): for dk, dv in dest.items(): if pr.getDestinationPageNumber(dv) == p and dk.startswith( 'ht_'): inds = [int(ind) for ind in dk[3:].split(':')] # if inds[2] in solution[inds[1]][1]: if inds[4] in solution[inds[1]][1]: # using some hard-coded values: a.add_annotation( 'square', Location(x1=float(dv['/Left']), y1=float(dv['/Top']), x2=float(dv['/Left']) + 5, y2=float(dv['/Top']) + 5, page=p), Appearance(stroke_color=(0, 1, 0), stroke_width=5), ) a.write(f_out)