I compiled one .tex file, read the resulting PDF with three different extractors, and got three different papers back.
Not wildly different. mutool 1.25.6 and PyMuPDF 1.26.0 each returned 694 whitespace-delimited words. pypdf 6.4.0 returned 692. Same file, same machine, same moment.
A two-word gap sounds like nothing. It is enough to kill the assumption most of us are quietly running on: that the text layer in a PDF is a fixed object, and that whatever reads it sees what you wrote.
The fixture, so you can argue with it: standard article class, twocolumn, 10pt. Abstract, four numbered sections, inline and display maths, an itemize list, an algorithm environment with numbered pseudocode, a table float, a figure float whose caption is a full sentence, and one footnote long enough to wrap. Compiled with pdfTeX 3.141592653-2.6-1.40.26, TeX Live 2024.
First surprise: the thing everyone warns you about did not happen.
The standard advice about two-column PDFs is that extractors read straight across both columns and turn your paper into interleaved nonsense. It didn't. The last sentence of the abstract, at the foot of column one, arrived immediately before the first sentence of the Introduction, at the head of column two. Broad section order held in all three streams.
One layout, one class, three extractors, one machine — that is the size of that claim. But it held.
Something else broke instead, and I have seen almost nobody mention it.
Here is a verbatim run from the PyMuPDF stream, whitespace normalised, nothing removed between the endpoints:
"…justification for treating a visually correct page as a reliable 1This footnote is deliberately long enough to wrap onto a second line so that its position in the extracted stream can be observed and compared with nearby prose. 1 Table 1: Primary o…"
In the source, reliable text stream is one phrase. In the extraction, a footnote, a bare page number, a table caption and its cells all land between the two words. The bare 1 is the page number — nobody reading the PDF sees it as part of either passage.
Nothing is visibly wrong with that page. It renders perfectly. But "the sentence before" and "the sentence after" are not stable concepts until you know which extractor is reading.
Then the layout switch, which is the result I found most useful.
LaTeX hyphenates at line breaks, and a narrow column creates more chances to do it. In the two-column build, PyMuPDF found 22 split tokens. Six of them:
ex- poses · differ- ences · specifica- tions · observa- tions · justifica- tion · partici- pants
I then compiled the identical source as a single column, changing only the class option. PyMuPDF returned 678 words and five splits: or- dinary, extrac- tion, jus- tification, partici- pants, par- ticular.
Same source. One option. A different set of words has stopped being words.
And then the compiler itself. I compiled the same source a third time with XeLaTeX — same two-column layout, same words on the page.
In the pdfLaTeX build, all three tools exposed zero ligature codepoints. In the XeLaTeX build, PyMuPDF and pypdf each exposed six — affiliated, affiliation, difficult, efficiency, insufficient, office — while mutool exposed zero, because it normalised those glyphs back to ordinary letters.
The maths went the other way. In the pdfTeX file, mutool returned a Unicode replacement character for the summation sign; PyMuPDF and pypdf returned a capital X. In the XeLaTeX file, all three returned an actual ∑.
So: the compiler shapes the characters, and then the extractor shapes them again.
One more, and this one has practical consequences beyond curiosity.
\cite{smith2019,jones2020} arrived in the extraction as four characters: [1, 2]. \ref{sec:method} arrived as 2. \label left nothing at all. Section headings arrived as number and title separated, so 2 Method sits in the stream directly after the previous sentence.
Which means any plan you have that depends on citation formatting is acting on something that isn't there. There is no citation object in the extracted text. There are brackets and digits.
You do not need any of the tools I used to check your own paper. Open your compiled PDF in whatever viewer you have, select all, paste into a plain text editor. That is one more extraction path, not a proxy for anything official — but it shows you problems in the text layer you are actually shipping.
Read it for these four, in this order:
- Split words. Search for a hyphen followed by a line break. Every hit is a word that has stopped being one word.
- Where your floats landed. Find a table caption and read the two sentences around it. If the caption and cells have landed inside a paragraph, that is the reading order for that paragraph.
- Your captions. If a caption is a full grammatical sentence, it reads as prose, because it is prose.
- The maths. Read one display equation in the pasted text. Whatever you see is what an extractor got. Missing or wrong characters are a fact about your font embedding.
If your .tex lives in Git or Overleaf, do this once per major revision rather than once at the end.
The boundary on all of the above, stated plainly: this is one fixture, one class file, one machine, three named local extractors with pinned versions. It says nothing about what any particular service's private extraction chain sees, and I am not claiming it moves any number anywhere. The narrow, checkable claim is the one worth carrying: the text layer is a product of the compile, and different extractors expose different characters from the same PDF.
And if sentences have to change, the answer for a LaTeX paper is boring and correct — change the source, recompile, never edit the PDF. The sentence lives in the .tex. Everything else is a rendering of it.
Originally published at HumanPen: https://humanpen.net/blog/overleaf-latex-turnitin-ai-detection?utm_source=devto&utm_medium=article&utm_campaign=D211
Top comments (0)