diff --git a/aliases/pdf.elv b/aliases/pdf.elv index 6ff745b..c004ef5 100644 --- a/aliases/pdf.elv +++ b/aliases/pdf.elv @@ -343,6 +343,195 @@ fn info {|@args| } $part } +fn -list-attachments {|in| + all (pdf:attachments $in) +} + +fn -display-attachments {|in| + var @data = (-list-attachments $in) + printf "%d pièce(s)-jointe(s) trouvée(s):\n\n" (count $data) + all $data | each $echo~ + echo +} + +fn -extract-attachments {|in out| + -list-attachments $in | each {|f| + pdf:attachment $in $out/$f $f + } +} + +fn -list-fonts {|in| + pdf:fonts $in | each {|f| + if (has-key $f /FontDescriptor) { + put [&font=$f &fd=$f[/FontDescriptor]] + } + } | each {|f| + if (has-key $f[fd] /FontName) { + assoc $f name $f[fd][/FontName] + } + } | each {|f| + var @_ n = (str:split '+' $f[name]) + var font = $f[font] + var fd = $f[fd] + var embed = (has-key $fd /FontFile2) + var file = '' + set n = (str:trim-prefix $n '/') + if $embed { + set file = $fd[/FontFile2] + } + put [ + &id=$font[id] + &name=$n + &embed=$embed + &file=$file + &type=(str:trim-prefix $font[/Subtype] '/') + &encoding=(str:trim-prefix $font[/Encoding] '/') + ] + } +} + +fn -display-fonts {|in| + var @data = (-list-fonts $in) + printf "%d police(s) trouvée(s):\n\n" (count $data) + var props = [ + (format:column &align=center id ID) + (format:column name Nom) + (format:column type Type) + (format:column encoding Encodage) + (format:column &align=center embed Téléchargeable) + (format:column &align=center file Fichier) + ] + format:list $props $data + echo +} + +fn -extract-fonts {|in out| + -list-fonts $in | each {|f| + if $f[embed] { + pdf:filtered-stream $in (printf '%s/%s.ttf' $out $f[name]) $f[file] + } + } +} + +fn -list-images {|in| + pdf:images $in | each {|i| + var c = '' + var w = (format:int $i[/Width]) + var h = (format:int $i[/Height]) + if (has-key $i /ColorSpace) { + set c = $i[/ColorSpace][0] + } + put [ + &id=$i[id] + &page=(format:int $i[page]) + &name=(str:trim-prefix $i[name] '/') + &width=$w + &height=$h + &dim=(printf '%dx%d' $w $h) + &filter=(str:trim-prefix $i[/Filter] '/') + &size=(format:size $i[/Length]) + &bpc=(format:int $i[/BitsPerComponent]) + &color=(str:trim-prefix $c '/') + ] + } + var objects = (pdf:objects $in) + all (pdf:pages $in) | each {|p| + var pn = (format:int $p[pageposfrom1]) + all $p[images] | each {|img| + var id = $img[object] + var o = (pdf:-object &extend=$true $objects $id) + var s = $o[/Length] + var c = '' + var w = (format:int $o[/Width]) + var h = (format:int $o[/Height]) + if (has-key $o /ColorSpace) { + set c = $o[/ColorSpace][0] + } + put [ + &id=$id + &page=$pn + &name=(str:trim-prefix $img[name] '/') + &width=$w + &height=$h + &dim=(printf '%dx%d' $w $h) + &filter=(str:trim-prefix $o[/Filter] '/') + &size=(format:size $s) + &bpc=(format:int $o[/BitsPerComponent]) + &color=(str:trim-prefix $c '/') + ] + } + } +} + +fn -display-images {|in| + var @data = (-list-images $in) + printf "%d image(s) trouvée(s):\n\n" (count $data) + var props = [ + (format:column &align=right page Page) + (format:column &align=center id ID) + (format:column name Nom) + (format:column &align=right size Taille) + (format:column &align=right dim Dimensions) + (format:column color Couleur) + (format:column &align=right bpc BPC) + (format:column &align=center filter Filtre) + ] + format:list $props $data + echo +} + +fn -extract-images {|in out| + # En attendant de savoir décoder correctement les images, on utilise poppler + pdfimages -all $in $out/Im +} + +fn list {|@args| + if (!= (count $args) 2) { + fail 'list doit comporter 2 paramètres' + } + var types in = $@args + -must-pdf-exist $in + var display = [ + &a=$-display-attachments~ + &f=$-display-fonts~ + &i=$-display-images~ + ] + str:split ',' $types | each {|t| + set t = (str:to-lower $t) + -must-valid $t {|e| + and (> (count $e) 0) (has-key $display $e[0]) + } + $display[$t[0]] $in + } +} + +fn extract {|@args| + if (!= (count $args) 3) { + fail 'extract doit comporter 3 paramètres' + } + var types in out = $@args + -must-pdf-exist $in + -must-not-exist $out + var extr = [ + &a=$-extract-attachments~ + &f=$-extract-fonts~ + &i=$-extract-images~ + ] + try { + mkdir $out + str:split ',' $types | each {|t| + set t = (str:to-lower $t) + -must-valid $t {|e| + and (> (count $e) 0) (has-key $extr $e[0]) + } + $extr[$t[0]] $in $out + } + } except e { + rm -rf $out + fail $e + } +} + edit:add-var pdf~ {|action @args| var actions = [ &help=$help~ @@ -358,8 +547,8 @@ edit:add-var pdf~ {|action @args| &zip=$zip~ &unzip=$unzip~ &info=$info~ - #&list=$list~ - #&extract=$extract~ + &list=$list~ + &extract=$extract~ ] if (not (has-key $actions $action)) { fail (printf '%s: action inconnue' $action) diff --git a/lib/moi/util/format.elv b/lib/moi/util/format.elv index bc5d2e5..542494a 100644 --- a/lib/moi/util/format.elv +++ b/lib/moi/util/format.elv @@ -195,7 +195,7 @@ fn size {|size| if (== $u 0) { put $size } else { - var p = (math:pow 2 (+ $u 10)) + var p = (math:pow 2 $u) var e = (/ $size $p) printf '%.1f%s' $e $m[$u] } diff --git a/lib/moi/util/pdf.elv b/lib/moi/util/pdf.elv index 16a0644..bbd1957 100644 --- a/lib/moi/util/pdf.elv +++ b/lib/moi/util/pdf.elv @@ -30,6 +30,10 @@ fn is-rotate-selection {|v| re:match '^(\+|-)?\d+(:(r?\d+|z)(-(r?\d+|z))?(,(r?\d+|z)(-(r?\d+|z))?)*(:(even|odd))?)?$' (to-string $v) } +fn is-object {|v| + re:match '^ \d+\ 0\ R$' $v +} + fn is-selection {|v| or (is-page-selection $v) (is-rotate-selection $v) } @@ -59,39 +63,185 @@ fn objects {|in| put $json[objects] } -fn -object {|extend objects key| - if (not (has-key $objects $key)) { - put $nil - return - } - var o = $objects[$key] - if (and $extend (eq (kind-of $o) 'map')) { - keys $o | each {|k| - var v = $o[$k] - if (has-key $objects $v) { - set o[$k] = (-object $extend $objects $v) +fn -format {|dict o| + var t = (kind-of $o) + if (eq $t string) { + if (has-key $dict $o) { + set o = $dict[$o] + } + } elif (eq $t list) { + set @o = (all $o | each {|e| + if (has-key $dict $e) { + put $dict[$e] + } else { + put $e } + }) + } elif (eq $t map) { + keys $o | each {|k| + set o[$k] = (-format $dict $o[$k]) } } put $o } + +fn -deep {|&dict=$nil objects @keys| + if (== (count $keys) 0) { + if (not-eq $dict $nil) { + put (-format $dict $objects) $true + } else { + put $objects $true + } + return + } + if (not-eq $dict $nil) { + set objects = (-format $dict $objects) + } + var id @next = $@keys + var t = (kind-of $objects) + if (eq $t map) { + if (has-key $objects $id) { + -deep &dict=$dict $objects[$id] $@next + } + } elif (eq $t list) { + if (and (is-number $id) (< $id (count $objects))) { + -deep &dict=$dict $objects[$id] $@next + } + } else { + put $nil $false + } +} + +fn -object {|&extend=$false objects id| + var dict = $nil + if $extend { + set dict = $objects + } + var o _ = (-deep &dict=$dict $objects $id) + put $o +} + +fn deep {|&extend=$false in @keys| + var dict = (objects $in) + if $extend { + -deep &dict=$dict $dict $@keys + } else { + -deep $dict $@keys + } +} + +fn contains {|in @keys| + var _ ok = (deep $in $@keys) + put $ok +} + +fn value {|&extend=$false in @keys| + var v _ = (deep &extend=$extend $in $@keys) + put $v +} + fn object {|&extend=$false in key| - -object $extend (objects $in) $key + -object &extend=$extend (objects $in) $key +} + +fn -filter {|&extend=$false objects cond| + var out = [&] + keys $objects | each {|k| + var o = (-object &extend=$extend $objects $k) + if ($cond $o) { + set out[$k] = $o + } + } + put $out } fn filter {|&extend=$false in cond| - var objects = (objects $in) - keys $objects | each {|k| - var o = (-object $extend $objects $k) - if ($cond $o) { - put [&id=$k &object=$o] + -filter &extend=$extend (objects $in) $cond +} + +fn font-filter {|o| + and ^ + (eq (kind-of $o) map) ^ + (has-key $o /Type) ^ + (eq $o[/Type] /Font) +} + +fn fonts {|in| + var dict = (objects $in) + var fonts = (-filter $dict $font-filter~) + keys $fonts | each {|id| + var f = $fonts[$id] + keys $f | each {|k| + var v = $f[$k] + if (has-key $dict $v) { + set f[$k] = $dict[$v] + } + } + var fd = $f[/FontDescriptor] + keys $fd | each {|k| + var v = $fd[$k] + if (and (not-eq $k /FontFile2) (has-key $dict $v)) { + set fd[$k] = $dict[$v] + } + } + set f[/FontDescriptor] = $fd + set f[id] = $id + put $f + } +} + +fn image-filter {|o| + and ^ + (eq (kind-of $o) map) ^ + (has-key $o /Subtype) ^ + (eq $o[/Subtype] /Image) +} + +fn images {|in| + var json = (json $in) + var dict = $json[objects] + all $json[pages] | each {|p| + var n = $p[pageposfrom1] + all $p[images] | each {|i| + var id = $i[object] + var img = (-object $dict $id) + keys $img | each {|k| + var v = $img[$k] + if (has-key $dict $v) { + set img[$k] = $dict[$v] + } + } + if (has-key $img /ColorSpace) { + var @cs = (all $img[/ColorSpace] | each {|v| + if (has-key $dict $v) { + put $dict[$v] + } else { + put $v + } + }) + set img[/ColorSpace] = $cs + } + if (has-key $img /DecodeParms) { + var dp = $img[/DecodeParms] + keys $dp | each {|k| + var v = $dp[$k] + if (has-key $dict $v) { + set dp[$k] = $dict[$v] + } + } + set img[/DecodeParms] = $dp + } + set img[id] = $id + set img[page] = $n + set img[name] = $i[name] + put $img } } } -fn trailer {|in| - object $in 'trailer' +fn trailer {|&extend=$false in| + object &extend=$extend $in 'trailer' } fn pages {|in| @@ -107,6 +257,18 @@ fn nb-pages {|in| qpdf --show-npages $in } +fn attachments {|in| + var data = [] + var json = (json $in) + var attachments = $json[attachments] + if (> (count $attachments) 0) { + set @data = (qpdf --list-attachments $in | eawk {|_ f @_| + put $f + }) + } + put $data +} + fn parse-selection {|@selection| var out = [] var in = $nil @@ -291,3 +453,7 @@ fn raw-stream {|in out id| fn filtered-stream {|in out id| qpdf $in --show-object=$id --filtered-stream-data --normalize-content=n --stream-data=uncompress --decode-level=all > $out } + +fn attachment {|in out id| + qpdf $in --show-attachment=$id > $out +} diff --git a/rc.elv b/rc.elv index 3940203..27fca51 100644 --- a/rc.elv +++ b/rc.elv @@ -3,6 +3,7 @@ set-env BAT_PAGER 'less -RF' set-env EDITOR vim set-env VIEW 'vim -R' set-env CURRENT_SHELL 'elvish' +set-env STARSHIP_CONFIG ~/.config/starship/starship.toml set paths = [$@paths /home/benjamin/bin /home/benjamin/Go/bin ] { @@ -19,13 +20,21 @@ set edit:insert:binding[Ctrl-H] = $edit:histlist:start~ set edit:prompt = { go-prompt } set edit:rprompt = { nop } +#eval (starship init elvish) +eval (starship init elvish --print-full-init | upgrade-scripts-for-0.17 -lambda | slurp) # Carapace completion : https://github.com/rsteube/carapace-bin eval (carapace _carapace|slurp) +# On ajoute les modules natifs que j’utilise beaucoup +use str +use re +use math + use moi/completion use moi/alias use moi/util/common +use moi/util/format { use ./aliases/get-uid uid