forked from dtonon/papiro
-
Notifications
You must be signed in to change notification settings - Fork 0
/
papiro.sh
executable file
·233 lines (192 loc) · 9.53 KB
/
papiro.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/bin/bash
# Project: https://github.com/dtonon/papiro
# Idea from https://www.grant-trebbin.com/2015/05/encode-and-decode-file-backed-up-as.html
function show_help {
echo -e "Papiro encodes and decodes file(s) to/from QR Codes, to print and store them phisically."
echo -e "You can encode a single file or a full directory, in this latter case the data are zipped before the encoding."
echo -e "The qrcodes are saved in a single pdf, ready to print; the rebuild process is done on a group of acquired photos."
echo -e "\nUsage"
echo -e "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
echo -e "\033[1mEncode a file in qrcodes\033[0m\n./papiro.sh -c file|directory [-za] [-l L|M|Q|H] [-o file.pdf]\n"
echo -e "\033[1mRebuild file from photos\033[0m\n./papiro.sh -r source_directory [-o rebuild_file]\n"
echo -e "\033[1mCreate an encrypted txt\033[0m\n./papiro.sh -x [-o rebuild_file]\n"
echo -e "Options"
echo -e "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
echo -e "\033[1m-z\033[0m\tZip the file(s) to reduce the number of QR Codes"
echo -e "\033[1m-l\033[0m\tSet the QR Codes error correction level (L|M|Q|H); default is L(ow)"
echo -e "\033[1m-o\033[0m\tSet the output filename"
echo -e "\033[1m-a\033[0m\tAnonymous mode, don't annotate the original filename"
echo -e "\033[1m-s\033[0m\tCreate a papiro of the script itself, useful for archiving with the encoded data"
echo -e "\033[1m-h\033[0m\tShow this help"
echo -e "\033[1m-d\033[0m\tDebug mode"
echo -e "\nExamples"
echo -e "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
echo "Encode a file to qrcodes: ./papiro.sh -c myfile.jpg"
echo "Zip and encode a file to qrcodes: ./papiro.sh -c divina-commedia.txt -z"
echo "Encode a file with the best error correction: ./papiro.sh -c important-data.xml -lH "
echo "Encode a directory to qrcodes (using a zip file): ./papiro.sh -c mydata/"
echo "Decode a group of images to rebuild a file: ./papiro.sh -r photos/ -o myfile.jpg"
}
function show_help_hint {
echo -e "Try ./papiro -h to see the help and some examples"
}
# Create a tmp dir
work_dir=`mktemp -d`
if [[ ! "$work_dir" || ! -d "$work_dir" ]]; then echo "Could not create the temp dir"; exit 1; fi
echo "" # Blank line for readibility
# Parse the flags
while getopts "c:azl:xr:o:sdh" flag
do
case "${flag}" in
c) encode_source=${OPTARG};;
a) anonymous="ON";;
z) zip="ON";;
l) error_correction_level=${OPTARG};;
x) new_secret="ON";;
r) decode_dir=${OPTARG};;
o) decode_output=${OPTARG};;
s) encode_myself="ON";;
d) debug="ON";;
h) help="ON";;
esac
done
# If invoked with the debug (-d) flag create a temp directory or empty if it alredy exists
if [ -n "$debug" ]; then
debug_dir="papiro-debug"
echo -e "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -";
echo "=> Debug mode is active";
mkdir -p $PWD/$debug_dir;
rm -rf $PWD/$debug_dir/*;
echo -e " Work_dir: $work_dir\n \033[1mRemember to clear it manually\033[0m"
echo -e "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n";
else
# The work temp dir will be cleared automatically on the exit
trap "rm -rf "$work_dir"" EXIT
fi
date_human=$(date "+%Y-%m-%d %H:%M")
date_file=$(date "+%Y%m%d-%H%M%S")
# If invoked with the -x flag, create a new encrypted vim file, then use it for the encoding
if [ -n "$encode_myself" ]; then
echo -e "=> Papiro self mode: I'm going to generate a papiro of myself!"
encode_source=`basename $0`
# Disable the zip in self mode
if [ -n "$zip" ]; then
echo -e "=> \033[1mWarning\033[0m: using the self mode with Zip is technically possibile but not very useful, because it is hard to rebuild a binary file. Let's go on with a plain txt :)"
unset zip
fi
fi
# If invoked with the -x flag, create a new encrypted vim file, then use it for the encoding
if [ -n "$new_secret" ]; then
encode_source="secret-$date_file"
vim -xn $encode_source
fi
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
#
# ENCONDE
# If invoked with the -c flag process the file to create the qrcodes-papiro pdf
#
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
if [ -n "$encode_source" ]; then
if ! [[ -f "$encode_source" || -d "$encode_source" ]]; then echo -e "Error: file not found"; show_help_hint; exit 2; fi
# If the source is a directory automatically activate the zip mode
if [ -d "$encode_source" ]; then echo "=> Directory detected: automatically activate the Zip mode"; zip="ON"; fi
# If invoked with the anonymous flag (-a) set the label_file and pdf_file accor accordingly to avoid to store the filename
if [ -n "$anonymous" ]; then
echo "=> Anonymous mode"
output_file="xxxxxxxxxxxxxxxx"
label_file="***************"
else
output_file=$(basename -- $encode_source)
label_file=$output_file
fi
# Set the split chunk size according to the error correction, default is L(ow)
case $error_correction_level in
"L" | "")
error_correction_level="L"
split_chunk=2953;;
"M")
split_chunk=2331;;
"Q")
split_chunk=1663;;
"H")
split_chunk=1273;;
*)
echo "Error: bad correction level code, valid values are L, M, Q, and H"; show_help_hint;
exit 2
;;
esac
echo "=> Error correction level: $error_correction_level"
if [ -n "$decode_output" ]; then
pdf_file=$decode_output
elif [ -n "$anonymous" ]; then
pdf_file="qrcodes-$date_file.pdf"
else
pdf_file=$PWD/qrcodes-$label_file.pdf
fi
work_file="$work_dir/$output_file"
cp -R $encode_source $work_file
if [ -n "$zip" ]; then
echo "=> Zip mode"
# Cannot use the split (-s -sp) option because 64k is the minimum split size
# TODO add -q optin for suppress output
current_position=$PWD
cd $work_dir
zip -r -9 "$(basename -- $work_file.zip)" "$(basename -- $work_file)"
work_file=$work_file.zip
encode_source=$work_file
cd "$current_position"
fi
# Calculate the checksum, it is included in the pdf for a future integrity check
checksum=$(shasum -a 256 $encode_source | cut -f 1 -d ' ')
echo "=> SHA256 signature: $checksum"
echo "=> Encoding $encode_source to qrcodes"
# Split the file in chunks of 1273 bytes. This is the max size for a qrcode v40 (177x177) with hight (H) error correction code level (ECC)
# Check https://www.qrcode.com/en/about/version.html for more details
split -b $split_chunk $work_file $work_file.split
# Encode the files in a qrcode 177x177, hight correction mode
for file in $work_file.split*; do qrencode --8bit -v 40 -l $error_correction_level -o $file.png -r $file; done
# Get the qrcodes count
total_files=`ls $work_file.split*.png | wc -l | sed "s/ *//g"`
# Add a label to every qrcode
counter=1; for file in $work_file.split*.png; do convert -comment "$label_file\n$date_human | $counter of $total_files parts" $file $file; counter=$((counter+1)); done
if [ -n "$debug" ]; then cp $work_dir/*.png $PWD/$debug_dir/; fi
# Create a multipage pdf and optimize its size
title="\n\n$label_file | $date_human\nsha256: $checksum"
if [ -n "$encode_myself" ]; then title="$title\nScan the qrcodes and merge the content in a unique text file, rename it to papiro.sh, run it"; fi
montage -pointsize 20 -label '%c' $work_dir/*.png -title "$title" -geometry "1x1<" -tile 3x4 $pdf_file
convert $pdf_file -border 40 -type bilevel -compress fax $pdf_file
echo -e "\nYour Papiro is ready to print: $pdf_file"
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
#
# DECODE
# If invoked with the -r flag process the photos' dir to rebuild the original file
#
# ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
elif [ -n "$decode_dir" ]; then
if ! [[ -d "$decode_dir" ]]; then echo -e "Error: directory not found"; show_help_hint; exit 2; fi
echo "Decoding $decode_dir/*"
if [ -n "$decode_output" ]; then decode_output=$decode_output; else decode_output="decoded_file"; fi
# Optimize the scanned images
mkdir $work_dir/pics
for file in $decode_dir/*; do convert "$file" -quiet -morphology open square:1 -threshold 50% "$work_dir/pics/$(basename -- $file).png"; done
if [ -n "$debug" ]; then cp $work_dir/pics/* $PWD/$debug_dir/; fi
# Scan optimized qrcodes and concatenate data to a unique file
counter=1; for file in $work_dir/pics/*
do
zbar_output=$( (zbarimg --raw --oneshot -Sbinary -Sdisable -Sqr.enable "$file" >> $work_dir/restore) 2>&1 > /dev/null)
if [[ $zbar_output == *"not detected"* ]]; then echo "Error: no content found in the qrcode #$counter, check the image quality"; exit 1; fi
counter=$((counter+1))
done
cp "$work_dir/restore" "$decode_output"
# Add zip extension automatically
file_type=`file -b $decode_output`
if [[ $file_type == *"Zip"* ]] && [[ ! $decode_output == *"zip" ]]; then
echo "=> Detected a Zip file: add the extension"
mv "$decode_output" "$decode_output.zip"
decode_output="$decode_output.zip"
fi
echo -e "\n=> File rebuild from papiro: $decode_output"
echo -e "=> SHA256 signature: $(shasum -a 256 $decode_output | cut -f 1 -d ' ')"
else
show_help
fi