...
 
Commits (4)
......@@ -7,11 +7,51 @@ License, version 2.0.
Heavily “inspired” by intra2net's version:
https://github.com/intra2net/paperbackup
Most settings can be customised: paper size, font size, code size,
chunk size (bytes per code).
**See a demo here: [demo.pdf](./demo.pdf). Should you successfully
restore that data, you should recognise a well-known test image.**
Dependencies
============
* PHP ≥ 7.2
* dmtx-utils (`dmtxread`, `dmtxwrite`)
* Inkscape
* poppler (`pdfunite`)
* poppler (`pdfunite`, `pdftoppm`)
* parallel
Usage
=====
Generate DataMatrix codes:
~~~
./gen-paper-dmtx codes-foo.pdf < foo
~~~
Generate a line-by-line listing:
~~~
./gen-paper-listing listing-foo.pdf < foo
~~~
Restore data from scanned DataMatrix codes:
~~~
./restore-dmtx SCAN*.JPG > restored-foo
~~~
Restore data when some codes couldn't be automatically decoded:
~~~
./restore-dmtx-raw SCAN*.JPG | sort > restored-foo.txt
# Check restored-foo.txt for missing code numbers, fill these by hand
# either by scanning manually or by reading the matching line in the
# listing.
cut -d' ' -f2 restored-foo.txt | base64 -d > restored-foo
# Check file integrity compared to the printed hash in the listing:
sha3-512sum -b restored-foo | base64
~~~
File added
......@@ -15,13 +15,22 @@
* limitations under the License.
*/
if($argc !== 2) {
fprintf(STDERR, "Usage: %s <out.pdf> < <input-file>\n", $argv[0]);
die(1);
}
register_shutdown_function(function() {
passthru('find . -maxdepth 1 -name ".'.getmypid().'-*.*" -delete');
});
const PAPER_W = 210;
const PAPER_H = 297;
const PAPER_MARGIN = 5;
const CODE_MARGIN = 0;
const FONT = "monospace";
const FONT_SIZE = 8 / 72.0 * 25.4;
const CODE_SIZE = 50;
const CODE_SIZE = 20;
const CHUNK_SIZE = 4;
$nx = (int)((PAPER_W - 2.0 * PAPER_MARGIN) / (CODE_SIZE + CODE_MARGIN));
......@@ -35,7 +44,7 @@ $offset = 0;
$idxcode = 0;
while(($chunk = fread(STDIN, $ncodes * 3 * CHUNK_SIZE)) !== false && $chunk !== '') {
$f = fopen($fn = sprintf('codes-%02d.svg', $npage++), 'w');
$f = fopen($fn = sprintf('.%d-%08d.svg', getmypid(), $npage++), 'w');
fwrite($f, '<?xml version="1.0" encoding="utf-8" standalone="no" ?>');
fprintf($f, '<svg width="%fmm" height="%fmm" viewBox="0 0 %f %f" xmlns="http://www.w3.org/2000/svg">', PAPER_W, PAPER_H, PAPER_W, PAPER_H);
......@@ -63,4 +72,8 @@ while(($chunk = fread(STDIN, $ncodes * 3 * CHUNK_SIZE)) !== false && $chunk !==
fwrite($f, '</svg>');
fclose($f);
echo $fn, PHP_EOL;
passthru(sprintf('inkscape -A %s.pdf %s', $fn, $fn));
}
passthru('pdfunite .'.getmypid().'-*.pdf '.escapeshellarg($argv[1]));
......@@ -15,13 +15,22 @@
* limitations under the License.
*/
const PAPER_W = 297;
const PAPER_H = 210;
if($argc !== 2) {
fprintf(STDERR, "Usage: %s <out.pdf> < <input-file>\n", $argv[0]);
die(1);
}
register_shutdown_function(function() {
passthru('find . -maxdepth 1 -name ".'.getmypid().'-*.*" -delete');
});
const PAPER_W = 210;
const PAPER_H = 297;
const PAPER_MARGIN = 5;
const FONT = "monospace";
const FONT_SIZE = 11 / 72.0 * 25.4;
const CHUNK_SIZE = 4;
const HASH_SIZE = 86;
const FONT_SIZE = 8 / 72.0 * 25.4;
const CHUNK_SIZE = 24;
const HASH_SIZE = 8;
$nlines = (int)((PAPER_H - 2.0 * PAPER_MARGIN) / FONT_SIZE);
$npage = 0;
......@@ -30,12 +39,12 @@ $offset = 0;
$hctx = hash_init('sha3-512');
while(($chunk = fread(STDIN, ($nlines - 4) * 3 * CHUNK_SIZE)) !== false && $chunk !== '') {
$f = fopen($fn = sprintf('listing-%02d.svg', $npage++), 'w');
$f = fopen($fn = sprintf('.%d-%08d.svg', getmypid(), $npage++), 'w');
fwrite($f, '<?xml version="1.0" encoding="utf-8" standalone="no" ?>');
fprintf($f, '<svg width="%fmm" height="%fmm" viewBox="0 0 %f %f" xmlns="http://www.w3.org/2000/svg">', PAPER_W, PAPER_H, PAPER_W, PAPER_H);
fprintf($f, '<g transform="translate(%f %f)"><text font-family="%s" font-size="%f" style="font-weight: bold; white-space: pre;">', PAPER_MARGIN, PAPER_MARGIN, FONT, FONT_SIZE);
fprintf($f, '<tspan x="0" dy="1em">%s | %s | %s</tspan>', str_pad('OFFSET', 8), str_pad('DATA', $linelen), str_pad('BASE64(BLAKE2)', HASH_SIZE));
fprintf($f, '<tspan x="0" dy="1em">%s | %s | %s</tspan>', str_pad('OFFSET', 8), str_pad('DATA', $linelen), str_pad('SHA3-512', HASH_SIZE));
fprintf($f, '<tspan x="0" dy="1em">%s-|-%s-|-%s</tspan>', str_repeat('-', 8), str_repeat('-', $linelen), str_repeat('-', HASH_SIZE));
while($chunk !== '' && $chunk !== false) {
......@@ -47,7 +56,7 @@ while(($chunk = fread(STDIN, ($nlines - 4) * 3 * CHUNK_SIZE)) !== false && $chun
$f, '<tspan x="0" dy="1em">%08x | %s | %s</tspan>',
$offset,
str_pad($l, $linelen),
substr(base64_encode(pack('H*', substr(shell_exec('echo -n '.escapeshellarg($l).' | b2sum'), 0, 128))), 0, HASH_SIZE)
substr(base64_encode(hash('sha3-512', $l, true)), 0, HASH_SIZE)
);
$chunk = substr($chunk, 3 * CHUNK_SIZE);
......@@ -58,4 +67,8 @@ while(($chunk = fread(STDIN, ($nlines - 4) * 3 * CHUNK_SIZE)) !== false && $chun
fwrite($f, '</text></g></svg>');
fclose($f);
echo $fn, PHP_EOL;
passthru(sprintf('inkscape -A %s.pdf %s', $fn, $fn));
}
passthru('pdfunite .'.getmypid().'-*.pdf '.escapeshellarg($argv[1]));
#!/bin/sh
parallel --lb ./restore-dmtx-raw ::: "$@" | sort | cut -d' ' -f2 | base64 -d
#!/bin/sh
./gen-paper-dmtx test-$$.pdf < "$1"
pdftoppm -jpeg test-$$.pdf test-$$
./restore-dmtx test-$$-*.jpg > test-$$-restored
b2sum "$1" test-$$-restored
rm -f test-$$-* test-$$.pdf