3

The censor package censors text but keeps space tokens and periods to keep the uncensored document parts similar in position to those in uncensored document. But it doesn't match uncensored output because ligatures and hyphenation affect the box construction and subsequently the paragraph breaking into lines. It is not the case that the censored text is removed from the document and the document appears otherwise identical. The example below shows this. Is it is possible to load a null font that has all the same characters and parameters for them visible to TeX, but simply doesn't draw them, and to use this font inside a macro (or to add to a font such null characters and use them only inside a macro)? Then TeX would run effectively unaware of the censoring and guarantee match of uncensored content in the censored document and the content in the uncensored document.

EDIT: censor replaces with black boxes, but for the purpose of censoring it is sufficient to have blank (white space). Then one doesn't have to worry about making censor bars overreach the box height, width, depth to prevent information leak, like in accented characters. The censor can be indicated by zero width, height, and depth boxes which contain rules, if necessary. See related posts:

  • How to replace a large block of text by an empty block of the same size?. The accepted answer uses \phantom, which only replaces an hbox with blank space. It has the same problem as \blackout from \censor for hyphenation and ligatures.
  • Generate a “blank” font using the metrics of another font. See egreg's answer that a solution would keep the character data, defeating the purpose for the easier and insecure color change censoring. It would be required to change the characters to a null equivalent, but if the null equivalent has the same font metrics and those are kept in output source the censored information would be easily decoded.
  • Multilines, multipages \phantom analog macro. Has the same stated purpose of not changing layout based on censored content. LuaTeX solution is to replace at shipout all horizontal and vertical boxes with boxes of the same dimension containing nothing.
\documentclass{article}
\usepackage{censor}

\begin{document}

\begin{minipage}[t]{.5\textwidth} Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim rutrum. \end{minipage} \begin{minipage}[t]{.5\textwidth} \blackout{Lorem} ipsum \blackout{dolor} sit \blackout{amet}, consectetuer \blackout{adipiscing} elit. \blackout{Ut} purus \blackout{elit}, vestibulum \blackout{ut}, \blackout{placerat} ac, \blackout{adipiscing} vitae, \blackout{felis}. Curabitur \blackout{dictum} gravida \blackout{mauris}. Nam \blackout{arcu} libero, \blackout{nonummy} eget, \blackout{consectetuer} id, \blackout{vulputate} a, \blackout{magna}. Donec \blackout{vehicula} augue \blackout{eu} neque. \blackout{Pellentesque} habitant \blackout{morbi} tristique \blackout{senectus} et \blackout{netus} et \blackout{malesuada} fames \blackout{ac} turpis \blackout{egestas}. Mauris \blackout{ut} leo. \blackout{Cras} viverra \blackout{metus} rhoncus \blackout{sem}. Nulla \blackout{et} lectus \blackout{vestibulum} urna \blackout{fringilla} ultrices. \blackout{Phasellus} eu \blackout{tellus} sit \blackout{amet} tortor \blackout{gravida} placerat. \blackout{Integer} sapien \blackout{est}, iaculis \blackout{in}, pretium \blackout{quis}, viverra \blackout{ac}, nunc. \blackout{Praesent} eget \blackout{sem} vel \blackout{leo} ultrices \blackout{bibendum}. Aenean \blackout{faucibus}. Morbi \blackout{dolor} nulla, \blackout{malesuada} eu, \blackout{pulvinar} at, \blackout{mollis} ac, \blackout{nulla}. Curabitur \blackout{auctor} semper \blackout{nulla}. Donec \blackout{varius} orci \blackout{eget} risus. \blackout{Duis} nibh \blackout{mi}, congue \blackout{eu}, accumsan \blackout{eleifend}, sagittis \blackout{quis}, diam. \blackout{Duis} eget \blackout{orci} sit \blackout{amet} orci \blackout{dignissim} rutrum. \end{minipage}

\newpage \begin{minipage}[t]{.5\textwidth} Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim rutrum. \end{minipage} \begin{minipage}[t]{.5\textwidth} \blackout{Lorem ipsum} dolor sit \blackout{amet, consectetuer} adipiscing elit. \blackout{Ut purus} elit, vestibulum \blackout{ut, placerat} ac, adipiscing \blackout{vitae, felis.} Curabitur dictum \blackout{gravida mauris.} Nam arcu \blackout{libero, nonummy} eget, consectetuer \blackout{id, vulputate} a, magna. \blackout{Donec vehicula} augue eu \blackout{neque. Pellentesque} habitant morbi \blackout{tristique senectus} et netus \blackout{et malesuada} fames ac \blackout{turpis egestas.} Mauris ut \blackout{leo. Cras} viverra metus \blackout{rhoncus sem.} Nulla et \blackout{lectus vestibulum} urna fringilla \blackout{ultrices. Phasellus} eu tellus \blackout{sit amet} tortor gravida \blackout{placerat. Integer} sapien est, \blackout{iaculis in,} pretium quis, \blackout{viverra ac,} nunc. Praesent \blackout{eget sem} vel leo \blackout{ultrices bibendum.} Aenean faucibus. \blackout{Morbi dolor} nulla, malesuada \blackout{eu, pulvinar} at, mollis \blackout{ac, nulla.} Curabitur auctor \blackout{semper nulla.} Donec \blackout{varius orci} eget risus. \blackout{Duis nibh} mi, congue \blackout{eu, accumsan} eleifend, sagittis \blackout{quis, diam.} Duis eget \blackout{orci sit} amet orci \blackout{dignissim rutrum.} \end{minipage}

\newpage \begin{minipage}[t]{.5\textwidth} Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim rutrum. \end{minipage} \begin{minipage}[t]{.5\textwidth} \blackout{Lorem ipsum dolor} sit amet, consectetuer \blackout{adipiscing elit. Ut} purus elit, vestibulum \blackout{ut, placerat ac,} adipiscing vitae, felis. \blackout{Curabitur dictum gravida} mauris. Nam arcu \blackout{libero, nonummy eget,} consectetuer id, vulputate \blackout{a, magna. Donec} vehicula augue eu \blackout{neque. Pellentesque habitant} morbi tristique senectus \blackout{et netus et} malesuada fames ac \blackout{turpis egestas. Mauris} ut leo. Cras \blackout{viverra metus rhoncus} sem. Nulla et \blackout{lectus vestibulum urna} fringilla ultrices. Phasellus \blackout{eu tellus sit} amet tortor gravida \blackout{placerat. Integer sapien} est, iaculis in, \blackout{pretium quis, viverra} ac, nunc. Praesent \blackout{eget sem vel} leo ultrices bibendum. \blackout{Aenean faucibus. Morbi} dolor nulla, malesuada \blackout{eu, pulvinar at,} mollis ac, nulla. \blackout{Curabitur auctor semper} nulla. Donec \blackout{varius orci eget} risus. Duis nibh \blackout{mi, congue eu,} accumsan eleifend, sagittis \blackout{quis, diam. Duis} eget orci sit \blackout{amet orci dignissim} rutrum. \end{minipage}

\newpage \begin{minipage}[t]{.5\textwidth} Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim rutrum. \end{minipage} \begin{minipage}[t]{.5\textwidth} \blackout{Lorem ipsum dolor sit} amet, consectetuer adipiscing elit. \blackout{Ut purus elit, vestibulum} ut, placerat ac, adipiscing \blackout{vitae, felis. Curabitur dictum} gravida mauris. Nam arcu \blackout{libero, nonummy eget, consectetuer} id, vulputate a, magna. \blackout{Donec vehicula augue eu} neque. Pellentesque habitant morbi \blackout{tristique senectus et netus} et malesuada fames ac \blackout{turpis egestas. Mauris ut} leo. Cras viverra metus \blackout{rhoncus sem. Nulla et} lectus vestibulum urna fringilla \blackout{ultrices. Phasellus eu tellus} sit amet tortor gravida \blackout{placerat. Integer sapien est,} iaculis in, pretium quis, \blackout{viverra ac, nunc. Praesent} eget sem vel leo \blackout{ultrices bibendum. Aenean faucibus.} Morbi dolor nulla, malesuada \blackout{eu, pulvinar at, mollis} ac, nulla. Curabitur auctor \blackout{semper nulla. Donec} varius orci eget risus. \blackout{Duis nibh mi, congue} eu, accumsan eleifend, sagittis \blackout{quis, diam. Duis eget} orci sit amet orci \blackout{dignissim rutrum.} \end{minipage}

\end{document}

  • It is theoretically possible, what you suggest, but of course, the hypothetical null font you name would require the exact same font metrics as the original for this to work as desired. – Steven B. Segletes May 14 '21 at 04:00
  • 2
    I would only note that a clever decoder could (pretty easily, I think, maybe even via copy/paste) uncensor your document. Thus, it would only appear censored. – Steven B. Segletes May 14 '21 at 04:06

2 Answers2

2

Could a custom Open Type font feature help?

Because of glue's stretchiness, though, lines and paragraph become de-linked in terms of shape. Judicious choice (and/or adjustment) of glyph will be needed.

Proof of concept: only lowercase letters and a few punctuation marks are substituted here; hyphens (which are characters, too) can also be substituted (see linked question).

Random glyph as "black square":

attempt1

The black square, from another font:

attempt2

Scaled down a bit:

attempt3

MWE

\documentclass{article}
\usepackage{fontspec}
\usepackage{lipsum}

\newcommand\anycxchar{uniEBA3} \newcommand\anycxcharb{uni2580} \newcommand\anycxcharc{circlecopyrt}

\directlua { luaotfload.add_colorscheme("cxscheme", { ["FF200080"] = {"\anycxchar"}, }) }

\directlua { luaotfload.add_colorscheme("cyscheme", { ["FF20A090"] = {"\anycxcharb"}, }) }

\directlua { luaotfload.add_colorscheme("czscheme", { ["FF0000"] = {"T_h"}, }) }

\directlua{ fonts.handlers.otf.addfeature { name = "anycx", type = "substitution", data = { ["a"] = "\anycxchar", ["b"] = "\anycxchar", ["c"] = "\anycxchar", ["d"] = "\anycxchar", ["e"] = "\anycxchar", ["f"] = "\anycxchar", ["g"] = "\anycxchar", ["h"] = "\anycxchar", ["i"] = "\anycxchar", ["j"] = "\anycxchar", ["k"] = "\anycxchar", ["l"] = "\anycxchar", ["m"] = "\anycxchar", ["n"] = "\anycxchar", ["o"] = "\anycxchar", ["p"] = "\anycxchar", ["q"] = "\anycxchar", ["r"] = "\anycxchar", ["s"] = "\anycxchar", ["t"] = "\anycxchar", ["u"] = "\anycxchar", ["v"] = "\anycxchar", ["w"] = "\anycxchar", ["x"] = "\anycxchar", ["y"] = "\anycxchar", ["z"] = "\anycxchar", ["0"] = "\anycxchar", ["1"] = "\anycxchar", ["2"] = "\anycxchar", ["3"] = "\anycxchar", ["4"] = "\anycxchar", ["5"] = "\anycxchar", ["6"] = "\anycxchar", ["7"] = "\anycxchar", ["8"] = "\anycxchar", ["9"] = "\anycxchar", ["r"] = "\anycxchar", [","] = "\anycxchar", ["."] = "\anycxchar", ["/"] = "\anycxchar", ["<"] = "\anycxchar", [">"] = "\anycxchar", ["?"] = "\anycxchar", } } }

\directlua{ fonts.handlers.otf.addfeature { name = "anycy", type = "substitution", data = { ["hyphen"] = "\anycxcharb", ["a"] = "\anycxcharb", ["b"] = "\anycxcharb", ["c"] = "\anycxcharb", ["d"] = "\anycxcharb", ["e"] = "\anycxcharb", ["f"] = "\anycxcharb", ["g"] = "\anycxcharb", ["h"] = "\anycxcharb", ["i"] = "\anycxcharb", ["j"] = "\anycxcharb", ["k"] = "\anycxcharb", ["l"] = "\anycxcharb", ["m"] = "\anycxcharb", ["n"] = "\anycxcharb", ["o"] = "\anycxcharb", ["p"] = "\anycxcharb", ["q"] = "\anycxcharb", ["r"] = "\anycxcharb", ["s"] = "\anycxcharb", ["t"] = "\anycxcharb", ["u"] = "\anycxcharb", ["v"] = "\anycxcharb", ["w"] = "\anycxcharb", ["x"] = "\anycxcharb", ["y"] = "\anycxcharb", ["z"] = "\anycxcharb", ["0"] = "\anycxcharb", ["1"] = "\anycxcharb", ["2"] = "\anycxcharb", ["3"] = "\anycxcharb", ["4"] = "\anycxcharb", ["5"] = "\anycxcharb", ["6"] = "\anycxcharb", ["7"] = "\anycxcharb", ["8"] = "\anycxcharb", ["9"] = "\anycxcharb", [32] = "\anycxcharb", ["r"] = "\anycxcharb", [","] = "\anycxcharb", ["."] = "\anycxcharb", ["/"] = "\anycxcharb", ["<"] = "\anycxcharb", [">"] = "\anycxcharb", ["?"] = "\anycxcharb", } } }

\directlua{ fonts.handlers.otf.addfeature { name = "anycz2", type = "substitution", data = { ["T_h"] = "\anycxcharc", } }}

\directlua{ fonts.handlers.otf.addfeature { name = "anycz", type = "substitution", data = { ["hyphen"] = "\anycxcharc", ["a"] = "\anycxcharc", ["b"] = "\anycxcharc", ["c"] = "\anycxcharc", ["d"] = "\anycxcharc", ["e"] = "\anycxcharc", ["f"] = "\anycxcharc", ["g"] = "\anycxcharc", ["h"] = "\anycxcharc", ["i"] = "\anycxcharc", ["j"] = "\anycxcharc", ["k"] = "\anycxcharc", ["l"] = "\anycxcharc", ["m"] = "\anycxcharc", ["n"] = "\anycxcharc", ["o"] = "\anycxcharc", ["p"] = "\anycxcharc", ["q"] = "\anycxcharc", ["r"] = "\anycxcharc", ["s"] = "\anycxcharc", ["t"] = "\anycxcharc", ["u"] = "\anycxcharc", ["v"] = "\anycxcharc", ["w"] = "\anycxcharc", ["x"] = "\anycxcharc", ["y"] = "\anycxcharc", ["z"] = "\anycxcharc", ["0"] = "\anycxcharc", ["1"] = "\anycxcharc", ["2"] = "\anycxcharc", ["3"] = "\anycxcharc", ["4"] = "\anycxcharc", ["5"] = "\anycxcharc", ["6"] = "\anycxcharc", ["7"] = "\anycxcharc", ["8"] = "\anycxcharc", ["9"] = "\anycxcharc", [32] = "\anycxcharc", [","] = "\anycxcharc", ["."] = "\anycxcharc", ["/"] = "\anycxcharc", ["<"] = "\anycxcharc", [">"] = "\anycxcharc", ["?"] = "\anycxcharc", } } }

\newfontfamily\fany{Clara}[ RawFeature=+anycx, Colour=cxscheme, ]

\newfontfamily\fancy{FiraMath}[ RawFeature=+anycy, Colour=cyscheme, Scale=0.75, ]

\newfontfamily\fancz{AntykwaTorunska}[ RawFeature=+anycz, ]

\newfontfamily\fancza{AntykwaTorunska}[ Ligatures=TeX, Colour=czscheme, ]

\newfontfamily\fanczb{AntykwaTorunska}[ RawFeature=+anycz;+anycz2, ]

\newcommand\blackout[1]{{\fancy#1}}

\begin{document}

abcde fghij klmnop qrstu wxyz 1234567890 ,./<>?

\fany

abcde fghij klmnop qrstu wxyz 1234567890 ,./<>?

\lipsum

\newpage \fancy

abcde fghij klmnop qrstu wxyz 1234567890 ,./<>?

\lipsum

\newpage \normalfont Q: What is the question to $1+1=1$?

A: {\fancz The cat sat on the mat.}

\fancza ``Th'' is a ligature: \fanczb The cat sat on the mat.

\newpage \normalfont

\begin{minipage}[t]{.5\textwidth} Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim rutrum. \end{minipage} \begin{minipage}[t]{.5\textwidth} \blackout{Lorem} ipsum \blackout{dolor} sit \blackout{amet}, consectetuer \blackout{adipiscing} elit. \blackout{Ut} purus \blackout{elit}, vestibulum \blackout{ut}, \blackout{placerat} ac, \blackout{adipiscing} vitae, \blackout{felis}. Curabitur \blackout{dictum} gravida \blackout{mauris}. Nam \blackout{arcu} libero, \blackout{nonummy} eget, \blackout{consectetuer} id, \blackout{vulputate} a, \blackout{magna}. Donec \blackout{vehicula} augue \blackout{eu} neque. \blackout{Pellentesque} habitant \blackout{morbi} tristique \blackout{senectus} et \blackout{netus} et \blackout{malesuada} fames \blackout{ac} turpis \blackout{egestas}. Mauris \blackout{ut} leo. \blackout{Cras} viverra \blackout{metus} rhoncus \blackout{sem}. Nulla \blackout{et} lectus \blackout{vestibulum} urna \blackout{fringilla} ultrices. \blackout{Phasellus} eu \blackout{tellus} sit \blackout{amet} tortor \blackout{gravida} placerat. \blackout{Integer} sapien \blackout{est}, iaculis \blackout{in}, pretium \blackout{quis}, viverra \blackout{ac}, nunc. \blackout{Praesent} eget \blackout{sem} vel \blackout{leo} ultrices \blackout{bibendum}. Aenean \blackout{faucibus}. Morbi \blackout{dolor} nulla, \blackout{malesuada} eu, \blackout{pulvinar} at, \blackout{mollis} ac, \blackout{nulla}. Curabitur \blackout{auctor} semper \blackout{nulla}. Donec \blackout{varius} orci \blackout{eget} risus. \blackout{Duis} nibh \blackout{mi}, congue \blackout{eu}, accumsan \blackout{eleifend}, sagittis \blackout{quis}, diam. \blackout{Duis} eget \blackout{orci} sit \blackout{amet} orci \blackout{dignissim} rutrum. \end{minipage}

\end{document}

See also: Hiding informations

Cicada
  • 10,129
1

Assuming that you have a font that has an associated tfm file, I could see a route to doing this using virtual fonts.

The basic strategy would be to take the original tfm and run tftopl on the file to get a pl file. This is a human-readable version of the TeX font metrics.

Copy that file to, e.g., xcmr10.vpl (or whatever you want to name your blackout font).

The vpl format is an extended version of the pl format, documented in the vptovf source code (texdoc vptovf to see the details). The short version is that we want to take each character description that looks like:

(CHARACTER O 13
   (CHARWD R 0.583336)
   (CHARHT R 0.694445)
   (CHARIC R 0.077779)
   (COMMENT
      (LIG C i O 16)
      (LIG C l O 17)
      (KRN O 47 R 0.077779)
      (KRN O 77 R 0.077779)
      (KRN O 41 R 0.077779)
      (KRN O 51 R 0.077779)
      (KRN O 135 R 0.077779)
      )
   )

and modify it to add a MAP instruction before the COMMENT (which may or may not be present) which will set a rule. We don't need to worry about font mapping since all we'll do is set rules. The transformed character would look like

(CHARACTER O 13
   (CHARWD R 0.583336)
   (CHARHT R 0.694445)
   (CHARIC R 0.077779)
   (MAP
      (SETRULE 0.683332 0.583336)
   )
   (COMMENT
      (LIG C i O 16)
      (LIG C l O 17)
      (KRN O 47 R 0.077779)
      (KRN O 77 R 0.077779)
      (KRN O 41 R 0.077779)
      (KRN O 51 R 0.077779)
      (KRN O 135 R 0.077779)
      )
   )

The SETRULE command takes height and width in terms of design size. I used the width of the character and picked the height of a capital letter for the height. You could put a MOVEDOWN before the rule and make it taller to simulate covering descenders but that's probably not necessary for your purposes.

I would not recommend doing this by hand. You will want to write a program to parse the VPL file and add the MAP automatically. Perhaps someone here eager to help will write such a program.

The final step would be to run vptovf on the final vpl file and place the resulting vf and tfm files in appropriate locations for your TeX install. Then you can use the resulting fonts like any other TeX font and get nice black boxes for your censored text. Note that we're keeping all the kerns and ligatures in the original font so there will be little gotchas when there are positive kerns (so for my example character from cmr10, it might be best to add an extra 0.077779 onto the width of the rule to keep those from being apparent.

You could also go ahead and add the original font as a MAPFONT into the VPL file you generate and set any characters you don't want to censor (perhaps you only censor letters and numerals but leave punctuation printing).

Don Hosek
  • 14,078
  • I'd probably also not do anything with the various accent characters in the font. If you don't add MAP directive to a character, it will just leave a blank space where the character would be, and given how accents get shifted vertically, you may leak information if you print a black box for, say ´ and then print a censored Á. – Don Hosek May 14 '21 at 04:01
  • Correct me if I'm wrong. If I have the blacked out PDF that you create, could I not highlight the blackout and immediately copy/paste it into an editor, recovering the original text? – Steven B. Segletes May 14 '21 at 04:09
  • I don't think you'd be able to recover the original text. You could from the DVI file, but I would be surprised if any of the dvipdf translators do anything other than set rules. That said, a determined decrypter could try to recover the text from the rule dimensions in the output PDF, so there is some entropy leakage with this scheme, but from the OPs desire to retain line breaks etc., I imagine security is not the prime objective of their use case. – Don Hosek May 14 '21 at 04:21
  • (I'd also add that even adding a fuzz onto the rule width would not be sufficient to prevent entropy leakage since it should be possible to still gather character width information from the typeset output. – Don Hosek May 14 '21 at 04:22
  • What I am thinking is that, in censor, whole words are replaced with equivalent rules, which helps to occlude original meaning. Is it not the case for your situation that a letter, lets say "e", is replaced with a glyph that looks like a black box of exactly or approximately the width of an "e"? Furthermore, doesn't the glyph still identify as slot "65 of the blackout font? If so, then it still possesses intrinsic "e"-ness in the PDF meta-data. In fact, why would it not so identify as an "e" that a copy/paste would reveal it as such? – Steven B. Segletes May 14 '21 at 11:58
  • It's been a long time since I've dealt with low-level DVI and VF mapping (as in my workflow was emTeX -> dvips -> ghostscript for preview), but when setting a character with a VF mapping, if there was no VF, put65 would send A to the output device, but if there was, then set_char_65 would be replaced with the instructions in the MAP in the VF. The naïve approach would be to act as if the set_char_65 in the DVI file was instead push, set_rule, pop, right. Smarter code could do either put_rule, right or set_rule if the rule width and right move are the same. – Don Hosek May 14 '21 at 14:15
  • I don't think it would make sense, especially when writing PDF, to create a device font that would emulate the map between “A” and the rule. – Don Hosek May 14 '21 at 14:16
  • Your knowledge far exceeds mine on these matters, and it seems like you have the situation well in hand. – Steven B. Segletes May 14 '21 at 14:32
  • Instead of black boxes I would like to only omit the drawing instructions for the characters (I can imply a redaction has started with a zero-width hbox containing a vertical rule). Then there would just be a mapping CHARACTER O -> CHARACTER NULL_O, which would have no glyph but the same font metrics. In the output from TeX, any O which is typeset in a censor macro has its character changed to NULL_O. Problems are if NULL_O is kept in pdf source it implies the original character, and the character kerning would have to include other character nulls. – David Ollodart May 14 '21 at 17:38
  • @DavidOllodart If you just want empty space, then the contents of the map for each character should just be (MAP (MOVERIGHT R 0.0)) – Don Hosek May 14 '21 at 19:04