diff --git a/aliases/qpdf.elv b/aliases/qpdf.elv index fdf2c48..7c58188 100644 --- a/aliases/qpdf.elv +++ b/aliases/qpdf.elv @@ -131,6 +131,234 @@ fn -merge {|&collate=$nil selection out| $cmd $@args } +fn -date {|raw| + var y m d = $raw[2..6] $raw[6..8] $raw[8..10] + var h n s = $raw[10..12] $raw[12..14] $raw[14..16] + var tz @_ = (str:split "'" $raw[16..]) + var date = (printf ^ + '%s-%s-%sT%s:%s:%s%s' ^ + $y $m $d ^ + $h $n $s ^ + $tz) + date --date $date +} + +fn -pts2cm {|v| + / (math:round (* $v 3.52778)) 100 +} + +fn -size {|size| + var u = 0 + var m = [ + &10=Kio + &20=Mio + &30=Gio + ] + while (< $u 30) { + var p = (math:pow 2 (+ $u 10)) + if (< $size $p) { + break + } + set u = (to-string (+ $u 10)) + } + if (== $u 0) { + put $size + } else { + var p = (math:pow 2 (+ $u 10)) + var e = (/ $size $p) + printf '%.1f%s' $e $m[$u] + } +} + +fn -b2str {|b| + if $b { + put 'Oui' + } else { + put 'Non' + } +} + +fn -props {|input json| + var objects = $json[objects] + var trailer = $objects[trailer] + var iid = $trailer[/Info] + var rid = $trailer[/Root] + var info = $objects[$iid] + var root = $objects[$rid] + var pages = $objects[$root[/Pages]] + var p1 = $objects[$pages[/Kids][0]][/MediaBox] + + var w = (-pts2cm $p1[2]) + var h = (-pts2cm $p1[3]) + var layout = 'Portrait' + if (> $w $h) { + set layout = 'Paysage' + } + + var props = [ + &path=(path:abs $input) + &fsize=(-size (stat -c '%s' $input)) + &version='' + &psize=(printf '%sx%s cm (%s)' $w $h $layout) + &pages=$pages[/Count] + &title='' + &subject='' + &author='' + &producer=$info[/Producer] + &creator=$info[/Creator] + &cdate=(-date $info[/CreationDate]) + &mdate='' + &acroform=(-b2str $json[acroform][hasacroform]) + &encrypted=(-b2str $json[encrypt][encrypted]) + ] + + #@TODO: version pdf + if (has-key $info '/Title') { + set props[title] = $info[/Title] + } + if (has-key $info '/Subject') { + set props[subject] = $info[/Subject] + } + if (has-key $info '/Author') { + set props[author] = $info[/Author] + } + if (has-key $info '/ModDate') { + set props[mdate] = (-date $info[/ModDate]) + } + + put $props +} + +fn -list-attachments {|in| + $cmd $in --list-attachments | eawk {|_ f @_| + put $f + } +} + +fn -list-fonts {|in| + var objects = ($cmd $in --json | from-json)[objects] + keys $objects | each {|k| + var o = $objects[$k] + if (kind-of $o map) { + put $o + } + } | each {|o| + if (has-key $o /Type) { + put $o + } + } | each {|o| + if (eq $o[/Type] /FontDescriptor) { + var f = [ + &name=$o[/FontName][1..] + &embedded=(has-key $o /FontFile2) + ] + if $f[embedded] { + set f[file] = $o[/FontFile2] + } + put $f + } + } +} + +fn -list-imgs {|in| + var objects = ($cmd $in --json | from-json)[objects] + keys $objects | each {|k| + var o = $objects[$k] + if (kind-of $o map) { + put $o + } + } | each {|o| + if (has-key $o /Type) { + put $o + } + } | each {|o| + if (eq $o[/Type] /FontDescriptor) { + var f = [ + &name=$o[/FontName][1..] + &embedded=(has-key $o /FontFile2) + ] + if $f[embedded] { + set f[file] = $o[/FontFile2] + } + put $f + } + } +} + +fn -extract-attachments {|in out| + -list-attachments $in | each {|f| + $cmd $in --show-attachment=$f > $out'/'$f + } +} + +fn -extract-fonts {|in out| + -list-fonts $in | each {|f| + if $f[embedded] { + $cmd $in --show-object=$f[file] --filtered-data-stream > $out'/'$f[name]'.ttf' + } + } +} + +fn -extract-imgs {|in out| +} + +fn -repeat {|c arg| + str:join '' [ (range $c | each {|_| + put $arg + }) ] +} + +fn -to-string {|v| + if (eq (kind-of $v) bool) { + if $v { + put X + } else { + put '' + } + } else { + to-string $v + } +} + +fn -format-list {|columns data| + set @columns = (each {|c| + set c[size] = (count $c[label]) + put $c + } $columns) + each {|d| + set @columns = (each {|c| + var n = $c[name] + if (has-key $d $n) { + var label = (-to-string $d[$n]) + var l = (count $label) + if (> $l $c[size]) { + set c[size] = $l + } + } + put $c + } $columns) + } $data + var size = 0 + var @raw = (each {|c| + var cl l = (count $c[label]) $c[size] + set size = (+ $size $l 1) + str:join '' [ (-repeat (- $l $cl) ' ') $c[label] ] + } $columns) + echo (str:join ' ' $raw) + echo (-repeat $size '-') + each {|d| + var @raw = (each {|c| + var n v = $c[name] '' + if (has-key $d $n) { + set v = (-to-string $d[$n]) + } + var l lc = (count $v) $c[size] + str:join '' [ (-repeat (- $lc $l) ' ') $v ] + } $columns) + echo (str:join ' ' $raw) + } $data +} + fn merge {|@args| var l = (- (count $args) 1) if (< $l 1) { @@ -299,108 +527,28 @@ fn decrypt {|@args| } } +fn rotate {|@args| + var l = (- (count $args) 1) + if (< $l 1) { + fail "rotate doit contenir au moins 2 paramètres" + } + var in = $args[0] + -must-pdf $in + -must-exist $in + var out = (-out $in _rotated) + if (-is-pdf $args[$l]) { + set out = $args[$l] + set args = $args[..$l] + } + -must-not-exist $out + var @rotate = (each {|r| put --rotate=$r } $args[1..]) + $cmd $in $out $@rotate +} + fn help {|@args| cat $E:HOME/.config/elvish/aliases/qpdf.help } -fn -date {|raw| - var y m d = $raw[2..6] $raw[6..8] $raw[8..10] - var h n s = $raw[10..12] $raw[12..14] $raw[14..16] - var tz @_ = (str:split "'" $raw[16..]) - var date = (printf ^ - '%s-%s-%sT%s:%s:%s%s' ^ - $y $m $d ^ - $h $n $s ^ - $tz) - date --date $date -} - -fn -pts2cm {|v| - / (math:round (* $v 3.52778)) 100 -} - -fn -size {|size| - var u = 0 - var m = [ - &10=Kio - &20=Mio - &30=Gio - ] - while (< $u 30) { - var p = (math:pow 2 (+ $u 10)) - if (< $size $p) { - break - } - set u = (to-string (+ $u 10)) - } - if (== $u 0) { - put $size - } else { - var p = (math:pow 2 (+ $u 10)) - var e = (/ $size $p) - printf '%.1f%s' $e $m[$u] - } -} - -fn -b2str {|b| - if $b { - put 'Oui' - } else { - put 'Non' - } -} - -fn -props {|input json| - var objects = $json[objects] - var trailer = $objects[trailer] - var iid = $trailer[/Info] - var rid = $trailer[/Root] - var info = $objects[$iid] - var root = $objects[$rid] - var pages = $objects[$root[/Pages]] - var p1 = $objects[$pages[/Kids][0]][/MediaBox] - - var w = (-pts2cm $p1[2]) - var h = (-pts2cm $p1[3]) - var layout = 'Portrait' - if (> $w $h) { - set layout = 'Paysage' - } - - var props = [ - &path=(path:abs $input) - &fsize=(-size (stat -c '%s' $input)) - &version='' - &psize=(printf '%sx%s cm (%s)' $w $h $layout) - &pages=$pages[/Count] - &title='' - &subject='' - &author='' - &producer=$info[/Producer] - &creator=$info[/Creator] - &cdate=(-date $info[/CreationDate]) - &mdate='' - &acroform=(-b2str $json[acroform][hasacroform]) - &encrypted=(-b2str $json[encrypt][encrypted]) - ] - - #@TODO: version pdf - if (has-key $info '/Title') { - set props[title] = $info[/Title] - } - if (has-key $info '/Subject') { - set props[subject] = $info[/Subject] - } - if (has-key $info '/Author') { - set props[author] = $info[/Author] - } - if (has-key $info '/ModDate') { - set props[mdate] = (-date $info[/ModDate]) - } - - put $props -} - fn info {|@args| var input = $args[0] var json = ($cmd --json $input | from-json) @@ -424,6 +572,70 @@ fn info {|@args| echo ' Acroform: '$props[acroform] } +fn list {|@args| + if (!= (count $args) 2) { + fail 'list doit comporter 2 paramètres' + } + var types in = $@args + -must-pdf $in + -must-exist $in + var fl = [ + &a=$-list-attachments~ + &i=$-list-imgs~ + &f=$-list-fonts~ + ] + var ff = [ + &a={|data| + each {|d| echo $d } $data + } + &i={|data| + -format-list [ + [&name=name &label=Nom] + [&name=embedded &label=Inclus] + ] $data + } + &f={|data| + -format-list [ + [&name=name &label=Nom] + [&name=embedded &label=Inclus] + ] $data + } + ] + str:split , $types | each {|t| + set t = (str:to-lower $t[0]) + if (not (has-key $fl $t)) { + continue + } + var @data = ($fl[$t] $in) + echo (count $data)' donnée(s) trouvée(s)' + echo + $ff[$t] $data + } +} + +fn extract {|@args| + if (!= (count $args) 3) { + fail 'extract doit comporter 3 paramètres' + } + var types in out = $@args + -must-pdf $in + -must-exist $in + -must-not-exist $out + var fe = [ + &a=$-extract-attachments~ + &i=$-extract-imgs~ + &f=$-extract-fonts~ + ] + mkdir $out + str:split , $types | each {|t| + set t = (str:to-lower $t[0]) + if (not (has-key $fe $t)) { + continue + } + $fe[$t] $in $out + } +} + edit:add-var epdf~ {|action @args| var actions = [ &merge=$merge~ @@ -434,6 +646,9 @@ edit:add-var epdf~ {|action @args| &decrypt=$decrypt~ &help=$help~ &info=$info~ + &rotate=$rotate~ + &list=$list~ + &extract=$extract~ ] if (not (has-key $actions $action)) { fail $action': action inconnue' diff --git a/aliases/qpdf.help b/aliases/qpdf.help index 23e0364..c8a0351 100644 --- a/aliases/qpdf.help +++ b/aliases/qpdf.help @@ -16,10 +16,17 @@ Commandes: Sépare alternativement chaque page dans les fichiers /{1,2,…}.pdf Le nombre de fichiers créé est indiqué par le modulo. Défauts : = 2 + rotate: ... + Copie le fichier en tournant les pages demandées + Fichier de sortie : _rotated.pdf decrypt: [] Retourne un fichier déchiffré. Si aucun mot de passe n’est donné, tente le déchiffrement avec un mot de passe à blanc Fichier de sortie : _decrypted.pdf + list: (a(ttachments)|i(mages)|f(onts)) + Affiche la liste des fichiers inclus en filtrant selon le type (pièce-jointe, image ou police) + extract: (a(ttachments)|i(mages)|f(onts)) + Extrait les types de documents demandés dans le dossier info: [ ...] Affiche les propriétés du document