• Stars
    star
    128
  • Rank 281,044 (Top 6 %)
  • Language
    Python
  • License
    BSD 2-Clause "Sim...
  • Created almost 4 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A tool to detect whether a PDF has a bad redaction

Image of REDACTED STAMP

x-ray is a Python library for finding bad redactions in PDF documents.

Why?

At Free Law Project, we collect millions of PDFs. An ongoing problem is that people fail to properly redact things. Instead of doing it the right way, they just draw a black rectangle or a black highlight on top of black text and call it a day. Well, when that happens you just select the text under the rectangle, and you can read it again. Not great.

After witnessing this problem for years, we decided it would be good to figure out how common it is, so, with some help, we built this simple tool. You give the tool the path to a PDF. It tells you if it has worthless redactions in it.

What next?

Right now, x-ray works pretty well and we are using it to analyze documents in our collections. It could be better though. Bad redactions take many forms. See the issues tab for other examples we don't yet support. We'd love your help solving some of tougher cases.

Installation

With poetry, do:

poetry add x-ray

With pip, that'd be:

pip install x-ray

Usage

You can easily use this on the command line. Once installed, just:

% xray path/to/your/file.pdf
{
  "1": [
    {
      "bbox": [
        58.550079345703125,
        72.19873046875,
        75.65007781982422,
        739.3987426757812
      ],
      "text": "The Ring travels by way of Cirith Ungol"
    }
  ]
}

Or if you have the file on a server somewhere, give it a URL. If it starts with https://, it will be interpreted as a PDF to download:

% xray https://free.law/pdf/congressional-testimony-michael-lissner-free-law-project-hearing-on-ethics-and-transparency-2021-10-26.pdf
{}

A fun trick you can do is to make a file with one URL per line, call it urls.txt. Then you can run this to check each URL:

xargs -n 1 xray  < urls.txt

However you run xray on the command line, you'll get JSON as output. When you have that, you can use it with tools like jq. The format is as follows:

  • It's a dict.
  • The keys are page numbers.
  • Each page number maps to a list of dicts.
  • Each of those dicts maps to two keys.
  • The first key is bbox. This is a four-tuple that indicates the x,y positions of the upper left corner and then lower right corners of the bad redaction.
  • The second key is text. This is the text under the bad rectangle.

Simple enough.

You can also use it as a Python module, if you prefer the long-form:

% python -m xray some-file.pdf

But that's not as easy to remember.

If you want a bit more, you can, of course, use xray in Python:

from pprint import pprint
import xray
bad_redactions = xray.inspect("some/path/to/your/file.pdf")  # Pathlib works too
pprint(bad_redactions)
{1: [{'bbox': (58.550079345703125,
               72.19873046875,
               75.65007781982422,
               739.3987426757812),
      'text': 'Aragorn is the one true king.'}]}

The output is the same as above, except it's a Python object, not a JSON object.

If you already have the file contents as a bytes object, that'll work too:

some_bytes = requests.get("https://lotr-secrets.com/some-doc.pdf").content
bad_redactions = xray.inspect(some_bytes)

Note that because the inspect method uses the same signature no matter what, the type of the object you give it is essential:

Input xray's Assumption
str or Pathlib Path local file
str that starts with https:// URL to download
bytes PDF in memory

This means that if you provide the filename on disk as a bytes object instead of a str, it's not going to work. This will fail:

xray.inspect(b"some-file-path.pdf")

That's pretty much it. There are no configuration files or other variables to learn. You give it a file name. If there is a bad redaction in it, you'll soon find out.

How it works

Under the covers, xray uses the high-performant PyMuPDF project to parse PDFs. It has been a wonderful project to work with.

You can read the source to see how it works, but the general idea is to:

  1. Find rectangles in a PDF.

  2. Find letters in the same location

  3. Render the rectangle as an image

  4. Inspect the rectangle to see if it's all one color. If it is, then that's a bad redaction. If not, then we assume you can see a mix of text and drawings, indicating a redaction that's OK.

The PDF format is a big and complicated one, so it's difficult to do all this perfectly. We do our best, but there's always more to do to make it better. Donations and sponsored work help.

Contributions

Please see the issues list on Github for things we need, or start a conversation if you have questions. Before you do your first contribution, we'll need a signed contributor license agreement. See the template in the repo.

Deployment

Releases happen automatically via Github Actions. To trigger an automated build:

  1. Update CHANGES.md

  2. Update the version in pyproject.toml

  3. Tag the commit with something like "v0.0.0".

If you wish to create a new version manually, the process is:

  1. Update version info in pyproject.toml

  2. Configure your Pypi credentials with Poetry

  3. Build and publish the version:

poetry publish --build

License

This repository is available under the permissive BSD license, making it easy and safe to incorporate in your own libraries.

Pull and feature requests welcome. Online editing in GitHub is possible (and easy!).

More Repositories

1

courtlistener

A fully-searchable and accessible archive of court data including growing repositories of opinions, oral arguments, judges, judicial financial records, and federal filings.
Python
544
star
2

juriscraper

An API to scrape American court websites for metadata.
HTML
363
star
3

eyecite

Find legal citations in any block of text
Python
115
star
4

reporters-db

A database of court reporters, tests and other experiments
Python
92
star
5

courts-db

A database of courts, tests and other experiments
Python
59
star
6

doctor

A microservice for document conversion at scale
Python
56
star
7

recap-chrome

Home of the RECAP Chrome, Safari, and Firefox Extensions
JavaScript
56
star
8

free.law

The homepage for Free Law Project
MDX
41
star
9

citation-regexes

A collection of regular expressions for matching citations to state, federal, and even international law
JavaScript
33
star
10

judge-pics

A community-curated collection of judge profile pics that can be integrated anywhere
Python
23
star
11

related-literature

Want to learn more about Free Law Project technologies, policies and thinking? Get the literature here.
TeX
23
star
12

recap-old

Pacer Fixes
JavaScript
18
star
13

seal-rookery

A collection of all the court seals we can muster.
Python
18
star
14

bigcases2

The sequel to Big Cases Bot
Python
16
star
15

disclosure-extractor

A financial disclosure data extraction tool.
Python
13
star
16

recap

This repository is for filing issues on any RECAP-related effort.
12
star
17

recap-server

The original recap server in service from 2009-2017. Now deprecated.
HTML
12
star
18

court-listener-api-definition

This is the API definition and data models for the court listener api
11
star
19

bankruptcy-parser

A legal form document parser.
Python
9
star
20

pacer-issues

A place to discuss and track issues and improvements with PACER
8
star
21

hr

All things human resources
7
star
22

recap-firefox

Recap Firefox Extension
JavaScript
6
star
23

courtlistener-solr-server

Scripts and configurations for making Solr work in CourtListener
XSLT
6
star
24

opinionated

5
star
25

nomination-extractor

A machine learning project to extract nomination disclosures
Python
4
star
26

tesseract-docker

A repository to simplify compiling Tesseract
Dockerfile
4
star
27

florida-scrapers

TypeScript
3
star
28

logos

The hub for Free Law Project logos and branding guidelines
3
star
29

talks

A place to keep track of slides, notes and documents related to talks given by FLP
Python
3
star
30

fdsys-scraper

A scraper specifically for working with FdSys data.
Python
2
star
31

collection-projects

A repository of collection projects.
Python
2
star
32

new-project-template

A template repo for new CL projects
Python
2
star
33

courtlistener-static-failover

An S3 site to be loaded when CourtListener goes down
CSS
2
star
34

cleanup-scripts

A repository of one-off scripts and helper functions.
Python
1
star
35

awscloud

Cloudformation configs, lambda code, etc.
Python
1
star
36

bankruptcy

Python
1
star