def test_name_equality(): # Who needs transitivity? # While this is less than ideal ('/Foo' != b'/Foo') it allows for slightly # sloppy tests like if colorspace == '/Indexed' without requiring # Name('/Indexed') everywhere assert Name('/Foo') == '/Foo' assert Name('/Foo') == b'/Foo'
def _from_pil_image(cls, *, pdf, page, name, image): # pragma: no cover """Insert a PIL image into a PDF (rudimentary) Args: pdf (pikepdf.Pdf): the PDF to attach the image to page (pikepdf.Object): the page to attach the image to name (str or pikepdf.Name): the name to set the image image (PIL.Image.Image): the image to insert """ data = image.tobytes() imstream = Stream(pdf, data) imstream.Type = Name('/XObject') imstream.Subtype = Name('/Image') if image.mode == 'RGB': imstream.ColorSpace = Name('/DeviceRGB') elif image.mode in ('1', 'L'): imstream.ColorSpace = Name('/DeviceGray') imstream.BitsPerComponent = 1 if image.mode == '1' else 8 imstream.Width = image.width imstream.Height = image.height page.Resources.XObject[name] = imstream return cls(imstream)
def test_image_roundtrip(outdir, w, h, pixeldata, cs, bpc): pdf = Pdf.new() image_data = pixeldata * (w * h) image = Stream(pdf, image_data) image.Type = Name('/XObject') image.Subtype = Name('/Image') image.ColorSpace = Name(cs) image.BitsPerComponent = bpc image.Width = w image.Height = h xobj = {'/Im1': image} resources = {'/XObject': xobj} mediabox = [0, 0, 100, 100] stream = b'q 100 0 0 100 0 0 cm /Im1 Do Q' contents = Stream(pdf, stream) page_dict = { '/Type': Name('/Page'), '/MediaBox': mediabox, '/Contents': contents, '/Resources': resources, } page = pdf.make_indirect(page_dict) pdf.pages.append(page) outfile = outdir / f'test{w}{h}{cs[1:]}{bpc}.pdf' pdf.save( outfile, compress_streams=False, stream_decode_level=StreamDecodeLevel.none ) with Pdf.open(outfile) as p2: pim = PdfImage(p2.pages[0].Resources.XObject['/Im1']) assert pim.bits_per_component == bpc assert pim.colorspace == cs assert pim.width == w assert pim.height == h if cs == '/DeviceRGB': assert pim.mode == 'RGB' elif cs == '/DeviceGray' and bpc == 8: assert pim.mode == 'L' elif cs == '/DeviceCMYK': assert pim.mode == 'CMYK' elif bpc == 1: assert pim.mode == '1' assert not pim.palette assert pim.filters == [] assert pim.read_bytes() == pixeldata outstream = BytesIO() pim.extract_to(stream=outstream) outstream.seek(0) im = Image.open(outstream) assert pim.mode == im.mode
def test_image_replace(congress, outdir): pdfimage = PdfImage(congress[0]) pillowimage = pdfimage.as_pil_image() grayscale = pillowimage.convert('L') congress[0].write(zlib.compress(grayscale.tobytes()), Name("/FlateDecode"), Null()) congress[0].ColorSpace = Name("/DeviceGray") pdf = congress[1] pdf.save(outdir / 'congress_gray.pdf')
def test_image_replace(congress, outdir): pdfimage = PdfImage(congress[0]) pillowimage = pdfimage.as_pil_image() grayscale = pillowimage.convert('L') grayscale = grayscale.resize((4, 4)) # So it is not obnoxious on error congress[0].write(zlib.compress(grayscale.tobytes()), filter=Name("/FlateDecode")) congress[0].ColorSpace = Name("/DeviceGray") pdf = congress[1] pdf.save(outdir / 'congress_gray.pdf')
def test_lowlevel_replace_jpeg(congress, outdir): # This test will modify the PDF so needs its own image raw_bytes = congress[0].read_raw_bytes() im = Image.open(BytesIO(raw_bytes)) grayscale = im.convert('L') congress[0].write(zlib.compress(grayscale.tobytes()), Name("/FlateDecode"), Null()) congress[0].ColorSpace = Name('/DeviceGray') pdf = congress[1] pdf.save(outdir / 'congress_gray.pdf')
def test_bytes(): b = b'\x79\x78\x77\x76' qs = String(b) assert bytes(qs) == b s = 'é' qs = String(s) assert str(qs) == s assert Name('/xyz') == b'/xyz' with pytest.raises(TypeError, match='should be str'): Name(b'/bytes')
def test_lowlevel_replace_jpeg(congress, outdir): # This test will modify the PDF so needs its own image raw_bytes = congress[0].read_raw_bytes() im = Image.open(BytesIO(raw_bytes)) grayscale = im.convert('L') grayscale = grayscale.resize((4, 4)) # So it is not obnoxious on error congress[0].write(zlib.compress(grayscale.tobytes()[:10]), filter=Name("/FlateDecode")) congress[0].ColorSpace = Name('/DeviceGray') pdf = congress[1] pdf.save(outdir / 'congress_gray.pdf')
def test_new_item(resources, title, page_num, page_loc): doc = Pdf.open(resources / 'outlines.pdf') kwargs = dict.fromkeys(ALL_PAGE_LOCATION_KWARGS, 100) page_ref = doc.pages[page_num] new_item = OutlineItem(title, page_num, page_loc, **kwargs) with doc.open_outline() as outline: outline.root.append(new_item) if isinstance(page_loc, PageLocation): loc_str = page_loc.name else: loc_str = page_loc if loc_str == 'FitR': kwarg_len = 4 elif loc_str == 'XYZ': kwarg_len = 3 elif loc_str in ('FitH', 'FitV', 'FitBH', 'FitBV'): kwarg_len = 1 else: kwarg_len = 0 expected_dest = [page_ref, Name('/{0}'.format(loc_str))] expected_dest.extend(repeat(100, kwarg_len)) assert new_item.destination == expected_dest new_obj = new_item.obj assert new_obj.Title == title assert new_obj.Dest == expected_dest assert new_obj.is_indirect is True
def test_new_item(resources, title, page_num, page_loc): # @given precludes use of outlines_doc fixture - causes hypothesis health check to # fail with Pdf.open(resources / 'outlines.pdf') as doc: kwargs = dict.fromkeys(ALL_PAGE_LOCATION_KWARGS, 100) page_ref = doc.pages[page_num] new_item = OutlineItem(title, page_num, page_loc, **kwargs) with doc.open_outline() as outline: outline.root.append(new_item) if isinstance(page_loc, PageLocation): loc_str = page_loc.name else: loc_str = page_loc if loc_str == 'FitR': kwarg_len = 4 elif loc_str == 'XYZ': kwarg_len = 3 elif loc_str in ('FitH', 'FitV', 'FitBH', 'FitBV'): kwarg_len = 1 else: kwarg_len = 0 expected_dest = [page_ref, Name(f'/{loc_str}')] expected_dest.extend(repeat(100, kwarg_len)) assert new_item.destination == expected_dest new_obj = new_item.obj assert new_obj.Title == title assert new_obj.Dest == expected_dest assert new_obj.is_indirect is True
def test_page_destination(resources, page_num, page_loc, kwargs): # @given precludes use of outlines_doc fixture - causes hypothesis health check to # fail with Pdf.open(resources / 'outlines.pdf') as doc: page_ref = doc.pages[page_num] if page_loc == 'invalid': with pytest.raises(ValueError, match='unsupported page location'): make_page_destination(doc, page_num, page_loc, **kwargs) return dest = make_page_destination(doc, page_num, page_loc, **kwargs) if isinstance(page_loc, PageLocation): loc_str = page_loc.name else: loc_str = page_loc if loc_str == 'XYZ': args = 'left', 'top', 'zoom' elif loc_str == 'FitH': args = ('top', ) elif loc_str == 'FitV': args = ('left', ) elif loc_str == 'FitR': args = 'left', 'bottom', 'right', 'top' elif loc_str == 'FitBH': args = ('top', ) elif loc_str == 'FitBV': args = ('left', ) else: args = () expected_dest = [page_ref, Name(f'/{loc_str}')] expected_dest.extend(kwargs.get(k, 0) for k in args) assert dest == expected_dest
def make_page_destination( pdf: Pdf, page_num: int, page_location: Optional[Union[PageLocation, str]] = None, **kwargs, ) -> Array: """ Creates a destination ``Array`` with reference to a Pdf document's page number. Arguments: pdf: PDF document object. page_num: Page number (zero-based). page_location: Optional page location, as a string or :enum:`PageLocation`. kwargs: Optional keyword arguments for the page location, e.g. ``top``. """ res = [pdf.pages[page_num]] if page_location: if isinstance(page_location, PageLocation): loc_key = page_location loc_str = loc_key.name else: loc_str = page_location try: loc_key = PageLocation[loc_str] except KeyError: raise ValueError( f"Invalid or unsupported page location type {loc_str}") res.append(Name(f'/{loc_str}')) dest_arg_names = PAGE_LOCATION_ARGS.get(loc_key) if dest_arg_names: res.extend(kwargs.get(k, 0) for k in dest_arg_names) else: res.append(Name.Fit) return Array(res)
def _make_page_destination( pdf: Pdf, page_num: int, page_location: Optional[Union[PageLocation, str]] = None, **kwargs, ) -> Array: kwargs = {k: v for k, v in kwargs.items() if v is not None} res = [pdf.pages[page_num]] if page_location: if isinstance(page_location, PageLocation): loc_key = page_location loc_str = loc_key.name else: loc_str = page_location try: loc_key = PageLocation[loc_str] except KeyError: raise ValueError( f"Invalid or unsupported page location type {loc_str}" ) from None res.append(Name(f'/{loc_str}')) dest_arg_names = PAGE_LOCATION_ARGS.get(loc_key) if dest_arg_names: res.extend(kwargs.get(k, 0) for k in dest_arg_names) else: res.append(Name.Fit) return Array(res)
def test_page_destination(resources, page_num, page_loc, kwargs): doc = Pdf.open(resources / 'outlines.pdf') page_ref = doc.pages[page_num] dest = make_page_destination(doc, page_num, page_loc, **kwargs) if isinstance(page_loc, PageLocation): loc_str = page_loc.name else: loc_str = page_loc if loc_str == 'XYZ': args = 'left', 'top', 'zoom' elif loc_str == 'FitH': args = ('top', ) elif loc_str == 'FitV': args = ('left', ) elif loc_str == 'FitR': args = 'left', 'bottom', 'right', 'top' elif loc_str == 'FitBH': args = ('top', ) elif loc_str == 'FitBV': args = ('left', ) else: args = () expected_dest = [page_ref, Name('/{0}'.format(loc_str))] expected_dest.extend(kwargs.get(k, 0) for k in args) assert dest == expected_dest
def test_list_apis(): a = pikepdf.Array([1, 2, 3]) a[1] = None assert a[1] is None assert len(a) == 3 del a[1] assert len(a) == 2 a[-1] = Name('/Foo')
def test_create_pdf(outdir): pdf = Pdf.new() font = pdf.make_indirect( Object.parse(b""" << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>""")) width, height = 100, 100 image_data = b"\xff\x7f\x00" * (width * height) image = Stream(pdf, image_data) image.stream_dict = Object.parse(b""" << /Type /XObject /Subtype /Image /ColorSpace /DeviceRGB /BitsPerComponent 8 /Width 100 /Height 100 >>""") rfont = {'/F1': font} xobj = {'/Im1': image} resources = { '/Font': rfont, '/XObject': xobj } mediabox = [0, 0, 612, 792] stream = b""" BT /F1 24 Tf 72 720 Td (Hi there) Tj ET q 144 0 0 144 234 324 cm /Im1 Do Q """ contents = Stream(pdf, stream) page_dict = { '/Type': Name('/Page'), '/MediaBox': mediabox, '/Contents': contents, '/Resources': resources } qpdf_page_dict = page_dict page = pdf.make_indirect(qpdf_page_dict) pdf.pages.append(page) pdf.save(outdir / 'hi.pdf')
def test_list_apis(): a = pikepdf.Array([1, 2, 3]) a[1] = None assert a[1] is None assert len(a) == 3 del a[1] assert len(a) == 2 a[-1] = Name('/Foo') with pytest.raises(IndexError): a[-5555] = Name.Foo
def test_bytes(): b = b'\x79\x78\x77\x76' qs = String(b) assert bytes(qs) == b s = 'é' qs = String(s) assert str(qs) == s assert Name('/xyz') == b'/xyz'
def test_repr_scalar(self): scalars = [ False, 666, Decimal('3.14'), String('scalar'), Name('/Bob'), Operator('Q') ] for s in scalars: assert eval(repr(s)) == s
def test_list_apis(): a = pikepdf.Array([1, 2, 3]) a[1] = None assert a[1] is None assert len(a) == 3 del a[1] assert len(a) == 2 a[-1] = Name('/Foo') with pytest.raises(IndexError): a[-5555] = Name.Foo assert a == pikepdf.Array([1, Name.Foo]) a.append(4) assert a == pikepdf.Array([1, Name.Foo, 4]) a.extend([42, 666]) assert a == pikepdf.Array([1, Name.Foo, 4, 42, 666])
def set_pagelabels(doc, page_labels): arr = [] for label in page_labels: pn = label['start'] - 1 # page index 1-based -> 0-based d = {} if 'style' in label and label['style'] != 'none': d['/S'] = Name('/' + label['style']) if 'prefix' in label: d['/P'] = label['prefix'] if 'initial_count' in label: d['/St'] = label['initial_count'] obj = Dictionary(d) arr.append(pn) arr.append(obj) obj = Dictionary({'/Nums': Array(arr)}) doc.root[Name.PageLabels] = obj
def test_list_apis(): a = pikepdf.Array([1, 2, 3]) a[1] = None assert a[1] is None assert len(a) == 3 del a[1] assert len(a) == 2 a[-1] = Name('/Foo') with pytest.raises(IndexError): a[-5555] = Name.Foo assert a == pikepdf.Array([1, Name.Foo]) a.append(4) assert a == pikepdf.Array([1, Name.Foo, 4]) a.extend([42, 666]) assert a == pikepdf.Array([1, Name.Foo, 4, 42, 666]) with pytest.raises(ValueError, match='object is not a dictionary'): del a.ImaginaryKey with pytest.raises(TypeError, match=r"items\(\) not available"): a.items()
def _remove_simple_filters(obj, filters): """Remove simple lossless compression where it appears. Args: obj (pikepdf.Stream): the compressed object filters (list of str): all files on the data """ COMPLEX_FILTERS = { '/DCTDecode', '/JPXDecode', '/JBIG2Decode', '/CCITTFaxDecode', } idx = [n for n, item in enumerate(filters) if item in COMPLEX_FILTERS] if idx: if len(idx) > 1: raise NotImplementedError( f"Object {obj.objgen} has compound complex filters: {filters}. " "We cannot decompress this." ) simple_filters = filters[: idx[0]] complex_filters = filters[idx[0] :] else: simple_filters = filters complex_filters = [] if not simple_filters: return obj.read_raw_bytes(), complex_filters original_filters = obj.Filter try: obj.Filter = Array([Name(s) for s in simple_filters]) data = obj.read_bytes(StreamDecodeLevel.specialized) finally: obj.Filter = original_filters return data, complex_filters
def test_contains(self): d = Dictionary({'/Monty': 'Python', '/Flying': 'Circus'}) assert Name.Flying in d assert Name('/Monty') in d assert Name.Brian not in d
def test_name(self): self.check(Name.This, Name('/This'))
def test_unequal_but_similar(self): assert Name('/Foo') != String('/Foo')
def test_empty_name(): with pytest.raises(ValueError): Name('') with pytest.raises(ValueError): Name('/')
def test_unslashed_name(): with pytest.raises(ValueError, match='must begin with'): Name('Monty') not in [] # pylint: disable=expression-not-assigned
def test_wrap_array(): assert Name('/Foo').wrap_in_array() == Array([Name('/Foo')]) assert Array([42]).wrap_in_array() == Array([42])
def get_pdf(): form = UserForm() if form.validate_on_submit(): profile = {} profile["firstname"] = form.firstname.data profile["lastname"] = form.lastname.data profile["birthday"] = form.birthday.data.strftime("%d/%m/%Y") profile["address"] = form.address.data profile["city"] = form.city.data profile["zipcode"] = form.zipcode.data profile["reason"] = form.reason.data profile["delay"] = form.delay.data now, date, hour = get_date(profile["delay"]) if profile["reason"] == "sport" and (19 <= now.hour or now.hour < 6): profile["reason"] = "animaux" elif profile["reason"] == "animaux" and (19 > now.hour or now.hour >= 6): profile["reason"] = "sport" if profile["reason"] == "achats_culte_culturel" and (19 <= now.hour or now.hour < 6): flash("Des achats pendant le couvre-feu ? T'es magique toi !") return redirect("/") fp = webdriver.FirefoxProfile() fp.set_preference("browser.download.folderList", 2) fp.set_preference("browser.download.dir", str(PureWindowsPath(ATTEST_PATH)) if platform.system() == "Windows" else ATTEST_PATH) fp.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/pdf, attachment/pdf") fp.set_preference("browser.download.manager.showWhenStarting",False) fp.set_preference("browser.helperApps.neverAsk.openFile","application/pdf") fp.set_preference("browser.helperApps.alwaysAsk.force", False) fp.set_preference("browser.download.manager.useWindow", False) fp.set_preference("browser.download.manager.focusWhenStarting", False) fp.set_preference("browser.download.manager.alertOnEXEOpen", False) fp.set_preference("browser.download.manager.showAlertOnComplete", False) fp.set_preference("browser.download.manager.closeWhenDone", True) fp.set_preference("pdfjs.disabled", True) options = webdriver.firefox.options.Options() options.add_argument("--headless") try: driver = webdriver.Firefox(options=options, firefox_profile=fp) except Exception as e: app.logger.error("Error: %s" % str(e)) flash("Woopsy, une erreur s'est produite...") return redirect("/") # get page driver.get("https://media.interieur.gouv.fr/attestation-deplacement-derogatoire-covid-19/") html = driver.page_source soup = BeautifulSoup(html, features="lxml") # pass the update button wait = WebDriverWait(driver, DELAY) try: update_button = wait.until(EC.element_to_be_clickable((By.ID, 'reload-btn'))) update_button = driver.find_element_by_id("reload-btn").click() except: pass files_nb = len(os.listdir(ATTEST_PATH)) # fill form fill_form(driver, profile, now, date, hour) # wait file to get there i = 5 while i: if len(os.listdir(ATTEST_PATH)) <= files_nb: i -= 1 time.sleep(DELAY) else: break if i == 0: app.logger.error("Error: file not downloaded.") flash("Woopsy, une erreur s'est produite...") return redirect("/") # rename file to avoid duplicates between users try: filepath = max([os.path.join(ATTEST_PATH, f) for f in os.listdir(ATTEST_PATH)], key=os.path.getctime) filename = profile["lastname"] + "_" + profile["firstname"] + os.path.basename(filepath) new_filename = os.path.join(ATTEST_PATH, filename) shutil.move(filepath, new_filename) except Exception as e: app.logger.error("Error: %s" % str(e)) flash("Woopsy, une erreur s'est produite...") return redirect("/") # make QRcode and edit PDF img = make_qr_code(profile, now, date, hour).convert('RGB').resize((590, 590)) pdf_file = Pdf.open(new_filename, allow_overwriting_input=True) page = pdf_file.pages[1] page_image = list(page.images.keys()) rawimage = page.images[page_image[0]] rawimage.write(zlib.compress(img.tobytes()), filter=Name("/FlateDecode")) rawimage.Width, rawimage.Height = 590, 590 page.Resources.XObject[page_image[0]] = rawimage pdf_file.save(new_filename) # program file cleaner file_handle = open(new_filename, 'rb') # This *replaces* the `remove_file` + @after_this_request code above def stream_and_remove_file(): yield from file_handle file_handle.close() os.remove(new_filename) return app.response_class( stream_and_remove_file(), mimetype='application/pdf', headers={'Content-Disposition': 'attachment', 'filename': filename} ) return redirect("/")