elvish_config/aliases/pdf.elv

462 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

edit:add-var pdf~ {|action @args|
use math
use path
use re
use str
use framagit.org/benjamin.vaudour/elv-lib/mods/common
use framagit.org/benjamin.vaudour/elv-lib/mods/format
use framagit.org/benjamin.vaudour/elv-lib/mods/map
use framagit.org/benjamin.vaudour/elv-lib/mods/pdf
var -c~ = $common:cexec~
var -cc~ = {|c f1| -c $c $f1 $nop~}
fn must-pdf {|file| -cc (not (pdf:is-pdf $file)) { fail (printf '%s nest pas un fichier pdf' $file) }}
fn must-exist {|file| -cc (pdf:not-exist $file) { fail (printf '%s nexiste pas' $file) }}
fn must-not-exist {|file| -cc (pdf:exist $file) { fail (printf '%s existe déjà' $file) }}
fn must-pdf-exist {|file|
must-pdf $file
must-exist $file
}
fn must-pdf-not-exist {|file|
must-pdf $file
must-not-exist $file
}
fn must-valid {|v cond| -cc (not ($cond $v)) { fail (printf '%s: paramètre invalide' $v) }}
fn out {|in suffix|
var out = (str:trim-suffix $in .pdf)
str:join '' [ $out $suffix ]
}
fn help {|@args| cat $E:HOME/.config/elvish/aliases/pdf.help}
fn decrypt {|@args|
var l = (count $args)
-cc (or (< $l 1) (> $l 3)) { fail 'decrypt doit contenir entre 1 et 3 paramètres' }
var in = $args[0]
var out = (out $in _decrypted.pdf)
var passwd = []
must-pdf-exist $in
if (> $l 1) {
set @passwd = $args[1]
if (> $l 2) {
set out = $args[2]
}
}
must-pdf-not-exist $out
pdf:decrypt &out=$out $in $@passwd
}
fn rotate {|@args|
var l = (- (count $args) 1)
-cc (< $l 1) { fail 'rotate doit contenir au moins 1 paramètres' }
var in = $args[0]
var out = (out $in _rotated.pdf)
if (pdf:is-pdf $args[$l]) {
set @args out = (all $args[1..])
}
must-pdf-exist $in
must-pdf-not-exist $out
each {|e|
must-valid $e $pdf:is-rotate-selection~
} $args
pdf:rotate &keep=$true &out=$out $in $@args
}
fn merge {|@args|
var l = (- (count $args) 1)
-cc (< $l 1) { fail 'merge doit contenir au moins 2 paramètres' }
var @selection out = $@args
must-pdf-not-exist $out
var has-in = $false
each {|e|
if (pdf:is-pdf $e) {
must-exist $e
set has-in = $true
} else {
-cc (not $has-in) { fail 'Une sélection doit être précédée dun fichier dentrée' }
must-valid $e $pdf:is-selection~
}
} $selection
pdf:cat &out=$out $@selection
}
fn unmerge {|@args|
var l = (- (count $args) 1)
-cc (< $l 1) { fail 'unmerge doit contenir au moins 2 paramètres' }
var in = $args[0]
var out = (out $in _unmerged)
if (not (pdf:is-selection $args[$l])) {
set @args out = (all $args[1..])
}
must-pdf-exist $in
must-not-exist $out
each {|e|
must-valid $e $pdf:is-selection~
} $args
pdf:uncat $in $out $@args
}
fn split {|@args|
var l = (- (count $args) 1)
-cc (< $l 1) { fail 'split doit contenir au moins 2 paramètres' }
var out = $args[$l]
set args = $args[..$l]
must-not-exist $out
var s = 1
if (pdf:is-number $args[0]) {
set s @args = $@args
}
var t = (pdf:-t)
try {
pdf:cat &out=$t $@args
pdf:split &size=$s $t $out
} finally {
rm -f $t
}
}
fn split-at {|@args|
var l = (count $args)
-cc (!= $l 3) { fail 'split-at doit contenir 3 paramètres' }
var rg in out = $@args
must-pdf-exist $in
must-not-exist $out
must-valid $rg {|e| re:match '^\d+(,\d+)*$' $e }
var b sel = 1 []
str:split ',' $rg | order | each {|s|
var e = (- $s 1)
if (== $b $e) {
set @sel = $@sel $b
set b = $s
} elif (< $b $e) {
set @sel = $@sel (printf '%d-%d' $b $e)
set b = $s
}
}
set @sel = $@sel (printf '%d-z' $b)
unmerge $in $@sel $out
}
fn zip {|@args|
var l = (- (count $args) 1)
-cc (< $l 1) { fail 'zip doit contenir au moins 2 paramètres' }
var @selection out = $@args
must-pdf-not-exist $out
var has-in = $false
each {|e|
if (pdf:is-pdf $e) {
must-exist $e
set has-in = $true
} else {
-cc (not $has-in) { fail 'Une sélection doit être précédée dun fichier dentrée' }
must-valid $e $pdf:is-selection~
}
} $selection
pdf:cat &collate=$true &out=$out $@selection
}
fn unzip {|@args|
var l = (- (count $args) 1)
-cc (< $l 1) { fail 'unzip doit contenir au moins 2 paramètres' }
var in @sel out = $@args
var mod = 2
if (pdf:is-number $in) {
set mod = $in
-cc (eq (count $sel) 0) { fail 'unzip doit contenir au moins 3 paramètres' }
set in @sel = $@sel
}
must-not-exist $out
var t = (pdf:-t)
try {
pdf:cat &out=$t $in $@sel
var n = (pdf:nb-pages $t)
mkdir $out
range 1 (+ 1 $mod) | each {|m|
var sel = (range 1 (+ $n 1) | each {|i|
var s = (% $i $mod)
-cc (== $s 0) { set s = $mod }
-cc (== $s $m) $i
} | each $to-string~ | str:join ',')
pdf:cat &out=(printf '%s/%d.pdf' $out $m) $t $sel
}
} finally {
rm -f $t
}
}
fn pts2cm {|v| / (math:round (* $v 3.52778)) 100}
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 rest = []
-cc (> (count $raw[16..]) 0) { set @rest = (str:split "'" $raw[16..]) }
var tz = '+00:00'
if (> (count $rest) 0) {
var tz = $rest[0]
-cc (eq $tz[0] 'Z') { set tz = $tz[1..] }
-cc (eq $tz '') { set tz = '00' }
-cc (and (not-eq $tz[0] '+') (not-eq $tz[0] '-')) { set tz = (printf '+%s' $tz) }
var mm = '00'
-cc (and (> (count $rest) 1) (pdf:is-number $rest[1])) { set mm = $rest[1] }
set tz = (printf '%s:%s' $tz $mm)
}
var date = (printf ^
'%s-%s-%sT%s:%s:%sZ%s' ^
$y $m $d ^
$h $n $s ^
$tz)
date --date $date
}
fn info {|@args|
-cc (!= (count $args) 1) { fail 'info doit contenir un paramètre' }
var in @_ = $@args
must-pdf-exist $in
var json = (pdf:json $in)
var objects = $json[objects]
var trailer = $objects[trailer]
var infos = $objects[$trailer[/Info]]
var pages = $json[pages]
var p1 = $objects[$pages[0][object]]
var w h = (all $p1[/MediaBox][2..] | each $pts2cm~)
var layout = (-c (> $w $h) 'Paysage' 'Portrait')
var title = (map:value-of $infos '/Title')
var subject = (map:value-of $infos '/Subject')
var author = (map:value-of $infos '/Author')
var creator = (map:value-of $infos '/Creator')
var producer = (map:value-of $infos '/Producer')
var mdate = (-c (has-key $infos '/ModDate') { -date $infos[/ModDate] } '')
var crypted = (-c (pdf:encryption $in)[encrypted] 'Oui' 'Non')
var hasform = ( -c (pdf:form $in)[hasacroform] 'Oui' 'Non')
var data = [
[&k='Chemin' &v=(path:abs $in)]
[&k='Taille' &v=(format:size (stat -c '%s' $in))]
[&k='Version PDF' &v=(pdf:version $in)]
[&k='Nombre de pages' &v=(count $pages)]
[&k='Format des pages' &v=(printf '%sx%s cm (%s)' $w $h $layout)]
[&k='Titre' &v=$title]
[&k='Subjet' &v=$subject]
[&k='Auteur' &v=$author]
[&k='Créateur' &v=$creator]
[&k='producteur' &v=$producer]
[&k='Date de création' &v=(-date $infos[/CreationDate])]
[&k='Date de modification' &v=$mdate]
[&k='Chiffré' &v=$crypted]
[&k='Acroform' &v=$hasform]
]
var label = (format:repeat 21 ' ')
var @props = (format:column &align=right k $label) (format:column v $label)
set props = (format:update-props $props $data)
var sep = (format:repeat (+ $props[0][size] $props[1][size] 3) '.')
var @part = $data[..5] $data[5..12] $data[12..]
each {|d|
format:list &with-header=$false &csep=' : ' &recompute=$false $props $@d
echo $sep
} $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)
each $echo~ $data
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|
-cc (has-key $f /FontDescriptor) { put [&font=$f &fd=$f[/FontDescriptor]] }
} | each {|f|
-cc (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 = (-c $embed $fd[/FontFile2] '')
set n = (str:trim-prefix $n '/')
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|
-cc $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 w = (format:int $i[/Width])
var h = (format:int $i[/Height])
var c = (-c (has-key $i /ColorSpace) { put $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 = (-c (has-key $o /ColorSpace) { put $o[/ColorSpace][0] } '')
var w = (format:int $o[/Width])
var h = (format:int $o[/Height])
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|
-cc (!= (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|
-cc (!= (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
}
}
fn gray {|@args|
-cc (!= (count $args) 2) { fail 'gray doit comporter 2 paramètres' }
var in out = $@args
must-pdf-exist $in
must-pdf-not-exist $out
convert -colorspace gray $in $out
}
fn mono {|@args|
var c = (count $args)
-cc (or (< $c 2) (> $c 3)) { fail 'mono doit comporter entre 2 et 3 paramètres' }
var t = $nil
if (pdf:is-number $args[0]) {
set t @args = $@args
-cc (or (< $t 0) (> $t 100)) { fail le taux doit être compris entre 0 et 100 }
-cc (< $c 2) { fail 'mono doit comporter 3 paramètres' }
}
var in out = $@args
must-pdf-exist $in
must-pdf-not-exist $out
if $t {
convert -colorspace gray -threshold $t'%' $in $out
} else {
convert -monochrome $in $out
}
}
var actions = [
&help=$help~
&decrypt=$decrypt~
&rotate=$rotate~
&merge=$merge~
&cat=$merge~
&unmerge=$unmerge~
&uncat=$unmerge~
&split=$split~
&split-at=$split-at~
&cut=$split-at~
&zip=$zip~
&unzip=$unzip~
&info=$info~
&list=$list~
&extract=$extract~
&gray=$gray~
&mono=$mono~
#&compress=$compress~
]
-cc (not (has-key $actions $action)) { fail (printf '%s: action inconnue' $action) }
$actions[$action] $@args
}