451 lines
12 KiB
Text
451 lines
12 KiB
Text
edit:add-var pdf~ {|action @args|
|
||
use flag
|
||
use math
|
||
use os
|
||
use path
|
||
use re
|
||
use str
|
||
use framagit.org/benjamin.vaudour/elv-lib/mods/list
|
||
use framagit.org/benjamin.vaudour/elv-lib/mods/map
|
||
use framagit.org/benjamin.vaudour/elv-lib/mods/pdf
|
||
|
||
fn -parse {|rest specs|
|
||
var flags = [&]
|
||
var @spec = (each {|s|
|
||
var d = (map:value-of &default=$false $s 'default')
|
||
var sh = $s['short']
|
||
var lg = $s['long']
|
||
if (has-key $s 'default') {
|
||
assoc $s 'arg-required' $true
|
||
} else {
|
||
set d = $false
|
||
assoc $s 'arg-optional' $true
|
||
}
|
||
set flags[$sh] = $d
|
||
set flags[$lg] = $d
|
||
} $specs)
|
||
|
||
var parsed argv = (flag:parse-getopt $rest $spec)
|
||
each {|p|
|
||
var v = $p['arg']
|
||
var s = $p['spec']
|
||
var sh = $s['short']
|
||
var lg = $s['long']
|
||
|
||
if (map:value-of &default=$false $s 'arg-optional') {
|
||
set v = $true
|
||
}
|
||
set flags[$sh] = $v
|
||
set flags[$lg] = $v
|
||
} $parsed
|
||
|
||
put $flags $argv
|
||
}
|
||
|
||
fn -size {|s|
|
||
var b = (num 1024.0)
|
||
var u = ['' K M G]
|
||
var i = 0
|
||
|
||
while (and (< $i 3) (>= $s $b)) {
|
||
set s i = (/ $s $b) (+ $i 1)
|
||
}
|
||
|
||
if (> $i 0) {
|
||
set s = (/ (math:round (* $s 10.0)) 10.0)
|
||
}
|
||
|
||
str:join '' [ (echo $s) $u[$i] ]
|
||
}
|
||
|
||
fn -f {|arg|
|
||
if (eq $arg $nil) {
|
||
put ''
|
||
} elif (pdf:is-string $arg) {
|
||
put $arg
|
||
} elif (==s (kind-of $arg) 'bool') {
|
||
if $arg {
|
||
put 'Oui'
|
||
} else {
|
||
put 'Non'
|
||
}
|
||
} else {
|
||
echo $arg
|
||
}
|
||
}
|
||
|
||
fn -format {|title header data|
|
||
var size = [&]
|
||
each {|c| set size[$c] = (wcswidth $c) } $header
|
||
each {|line|
|
||
keys $line | each {|k|
|
||
var v = $line[$k]
|
||
var l = (wcswidth $v)
|
||
if (> $l $size[$k]) {
|
||
set size[$k] = $l
|
||
}
|
||
}
|
||
} $data
|
||
|
||
echo (styled $title bold yellow)
|
||
if (== (count $data) 0) {
|
||
echo 'Aucune donnée…'
|
||
} else {
|
||
echo (styled (each {|c| pdf:align $c $size[$c] } $header | str:join ' ') bold underlined)
|
||
each {|line|
|
||
echo (each {|c| pdf:align $line[$c] $size[$c] } $header | str:join ' ')
|
||
} $data
|
||
}
|
||
echo
|
||
}
|
||
|
||
fn help {|@args| e:cat $E:HOME/.config/elvish/aliases/pdf.help }
|
||
|
||
fn compress {|@rest|
|
||
var flags rest = (-parse $rest [
|
||
[&short=r &long=resolution &default=$nil]
|
||
[&short=t &long=type &default='screen']
|
||
])
|
||
var input output = (list:value-of $rest 0) (list:value-of $rest 1)
|
||
var type resolution = $flags[t] &$flags[r]
|
||
|
||
pdf:must ¬=$true $input {|arg| eq $arg $nil } 'Le fichier d’entrée est obligatoire'
|
||
pdf:must-pdf-exist $input
|
||
|
||
if (eq $output $nil) {
|
||
set output = (pdf:output $input '_compressed.pdf')
|
||
}
|
||
pdf:must-pdf-not-exist $output
|
||
|
||
pdf:must ['default' 'screen' 'ebook' 'printer' 'prepress'] {|arg| has-value $arg $type} (printf '%s: type invalide' $type)
|
||
|
||
if (not-eq $resolution $nil) {
|
||
pdf:must $resolution {|arg| and (pdf:is-number $arg) (>= $arg 72) (<= $arg 300) } 'La résolution doit être comprise entre 72 et 300'
|
||
}
|
||
|
||
pdf:compress &resolution=$resolution &type=$type $input $output
|
||
}
|
||
|
||
fn decrypt {|input @rest|
|
||
var output password = (list:value-of &default=(pdf:output $input '_decrypted.pdf') $rest 1) (list:value-of $rest 0)
|
||
|
||
pdf:must-pdf-exist $input
|
||
pdf:must-pdf-not-exist $output
|
||
|
||
pdf:decrypt &output=$output &password=$password $input
|
||
}
|
||
|
||
fn gray {|input @rest|
|
||
var output = (list:value-of &default=(pdf:output $input '_gray.pdf') $rest 0)
|
||
|
||
pdf:must-pdf-exist $input
|
||
pdf:must-pdf-not-exist $output
|
||
|
||
pdf:gray $input $output
|
||
}
|
||
|
||
fn info {|input|
|
||
pdf:must-pdf-exist $input
|
||
|
||
var json = (pdf:json $input)
|
||
var dict = (pdf:objects $json)
|
||
var infos = (pdf:object &fmt=$true &rec=$true $dict 'trailer' '/Info')
|
||
var page = (pdf:page $json 1)
|
||
var dim = (pdf.deep &dict=$dict $page 'object' '/MediaBox')
|
||
set dim = [
|
||
&w= (pdf:pts2cm $dim[2])
|
||
&h= (pdf:pts2cm $dim[3])
|
||
]
|
||
if (> $dim[w] $dim[h]) {
|
||
set dim[l] = 'Paysage'
|
||
} else {
|
||
set dim[l] = 'Portrait'
|
||
}
|
||
|
||
var encrypted form = 'Non' 'Non'
|
||
if (pdf:encryption $json)['encrypted'] {
|
||
set encrypted = 'Oui'
|
||
}
|
||
if (pdf:form $json)['hasacroform'] {
|
||
set form = 'Oui'
|
||
}
|
||
|
||
var title = (map:value-of &default='' $infos '/Title')
|
||
var subject = (map:value-of &default='' $infos '/Subject')
|
||
var author = (map:value-of &default='' $infos '/Author')
|
||
var creator = (map:value-of &default='' $infos '/Creator')
|
||
var producer = (map:value-of &default='' $infos '/Producer')
|
||
var cdate = (map:value-of &default='' $infos '/CreationDate')
|
||
var mdate = (map:value-of &default='' $infos '/ModDate')
|
||
|
||
var result = [
|
||
&'Chemin'= (path:abs $input)
|
||
&'Version'= (pdf:Version $json)
|
||
&'Nombre de pages'= (pdf:nb-pages $input)
|
||
&'Format des pages'= (printf '%s×%s cm (%s)' $dim[w] $dim[h] $dim[l])
|
||
&'Titre'= $title
|
||
&'Sujet'= $subject
|
||
&'Auteur'= $author
|
||
&'Créateur'= $creator
|
||
&'Producteur'= $producer
|
||
&'Date de création'= $cdate
|
||
&'Date de modification'= $mdate
|
||
&'Chiffré'= $encrypted
|
||
&'Acroform'= $form
|
||
]
|
||
|
||
var l = 1
|
||
keys $result | each {|k|
|
||
var w = (+ (wcswidth $k) 1)
|
||
if (> $w $l) {
|
||
set l = $w
|
||
}
|
||
}
|
||
|
||
keys $result each {|k|
|
||
var v = $result[$k]
|
||
echo (styled (pdf:align $k':' $l)) $v
|
||
}
|
||
}
|
||
|
||
fn mono {|@rest|
|
||
var flags rest = (-parse $rest [
|
||
[&short=d &long=density &default=600]
|
||
])
|
||
var input output = (list:value-of $rest 0) (list:value-of $rest 1)
|
||
var density = $flags[d]
|
||
|
||
pdf:must ¬=$true $input {|arg| eq $arg $nil } 'Le fichier d’entrée est obligatoire'
|
||
pdf:must-pdf-exist $input
|
||
|
||
if (eq $output $nil) {
|
||
set output = (pdf:output $input '_mono.pdf')
|
||
}
|
||
pdf:must-pdf-not-exist $output
|
||
|
||
pdf:must $density {|d| and (pdf:is-number $d) (>= $d 72) (<= $d 1200) } 'La densité doit être comprise entre 72 et 1200'
|
||
|
||
pdf:mono &density=$density $input $output
|
||
}
|
||
|
||
fn merge {|@selection output|
|
||
pdf:must (count $selection) {|c| > $c 0 } 'La commande doit contenir au moins deux paramètres'
|
||
pdf:must-pdf-not-exist $output
|
||
|
||
pdf:merge &output=$output $@selection
|
||
}
|
||
|
||
fn unmerge {|input @selection output|
|
||
pdf:must {count $selection} {|c| > $c 0} 'La commande doit contenir au moins trois paramètres'
|
||
pdf:must-pdf-exist $input
|
||
pdf:must-not-exist $output
|
||
|
||
pdf:unmerge $input $@selection $output
|
||
}
|
||
|
||
fn split {|@rest input output|
|
||
var flags _ = (-parse $rest [
|
||
[&short=s &long=size &default=1]
|
||
])
|
||
var size = $flags[s]
|
||
|
||
pdf:must-valid $size {|arg |and (pdf:is-number $arg) (> $arg 0) }
|
||
pdf:must-pdf-exist $input
|
||
pdf:must-not-exist $output
|
||
|
||
pdf:split &size=$size $input $output
|
||
}
|
||
|
||
fn split-at {|rg input output|
|
||
pdf:must-valid $rg {|arg| re:match '^\d+(,\d+)*$' }
|
||
var @pages = (str:split ',' $rg | order | compact)
|
||
var last = 1
|
||
var selection = []
|
||
each {|p|
|
||
if (== $p $last) {
|
||
set @selection = $@selection $p
|
||
} elif (> $p $last) {
|
||
set @selection = $@selection (printf '%d-%d' $last $p)
|
||
}
|
||
set last = (+ $p 1)
|
||
} $pages
|
||
|
||
set @selection = $@selection (printf '%d-z' $last)
|
||
|
||
unmerge $input $@selection $output
|
||
}
|
||
|
||
fn zip {|@rest output|
|
||
var flags selection = (-parse $rest [
|
||
[&short=c &long=collate &default=0]
|
||
])
|
||
var collate = $flags[c]
|
||
|
||
pdf:must-pdf-not-exist $output
|
||
pdf:must-valid $collate $pdf:is-number~
|
||
|
||
pdf:merge &collate &output=$output $@selection
|
||
}
|
||
|
||
fn unzip {|@rest output|
|
||
var flags selection = (-parse rest [
|
||
[&short=m &long=modulo &default=2]
|
||
])
|
||
var modulo = $flags[m]
|
||
|
||
pdf:must-valid $modulo {|arg| and (pdf:is-number $arg) (> $arg 2) }
|
||
pdf:must-not-exist $output
|
||
|
||
var t = (pdf:tmp-pdf)
|
||
|
||
try {
|
||
pdf:merge &output=$t $@selection
|
||
|
||
var n = (pdf:nb-pages $t)
|
||
var @sel = (range $modulo | each {|_| put [] })
|
||
|
||
range $n {|i|
|
||
var s = (% $i $modulo)
|
||
set sel[$s] = (conj $sel[$s] (+ $i 1) )
|
||
}
|
||
set @sel = (each {|s| str:join ',' $s } $sel)
|
||
|
||
unmerge $t $@sel $output
|
||
} catch err {
|
||
}
|
||
|
||
os:remove-all $t
|
||
}
|
||
|
||
fn list {|@rest input|
|
||
pdf:must-pdf-exist $input
|
||
|
||
var flags _ = (-parse $rest [
|
||
[&short=a &long=attachments]
|
||
[&short=f &long=fonts]
|
||
[&short=i &long=images]
|
||
])
|
||
|
||
var json = (pdf:json $input)
|
||
|
||
if $flags[a] {
|
||
var data = (pdf:attachments &fmt=$true &rec=$true $json)
|
||
var @attachments = (keys $data | each {|id|
|
||
var a = $data[$id]
|
||
var name = (pdf:deep $a 'filespec' '/F')
|
||
var size = (pdf:deep $a 'filespec' '/EF' '/F' 'dict' '/Params' '/Size')
|
||
var mime = (pdf:deep $a 'streams' '/F' 'mimetype')
|
||
var desc = (pdf:deep $a 'description')
|
||
put [
|
||
&'ID'= $id
|
||
&'Nom'= $name
|
||
&'Taille'= (-size $size)
|
||
&'Mimetype'= (-f $mime)
|
||
&'Description'= (-f $desc)
|
||
]
|
||
})
|
||
|
||
-format 'PIÈCES-JOINTES:' ['ID' 'Nom' 'Taille' 'Mimetype' 'Description'] $attachments
|
||
}
|
||
|
||
if $flags[f] {
|
||
var data = (pdf:fonts &fmt=$true &rec=$true $json)
|
||
var @fonts = (each {|f|
|
||
if (has-key $f '/FontDescriptor') {
|
||
put $f
|
||
}
|
||
} $data | each {|f|
|
||
var fd = (pdf:deep $f '/FontDescriptor')
|
||
var id = (pdf:deep $fd '/FontFile2' 'object_id')
|
||
var file = (pdf:deep $fd '/FontFile2' 'dict')
|
||
var name = (pdf:deep $fd '/FontName')
|
||
|
||
if (not-eq $name $nil) {
|
||
set name = (re:replace '^.*\+' '' $name)
|
||
}
|
||
var basename type encoding = (put '/BaseFont' '/Subtype' '/Encoding' | each {|k|
|
||
var v = (pdf:deep $f $k)
|
||
if (==s (kind-of $v) 'string') {
|
||
str:trim-left $v '/'
|
||
} else {
|
||
put $v
|
||
}
|
||
})
|
||
|
||
put [
|
||
&'ID'= $id
|
||
&'Nom'= (-f $name)
|
||
&'Nom de base'= (-f $basename)
|
||
&'Embarqué'= (-f (not-eq $file $nil))
|
||
&'Type'= (-f $type)
|
||
&'Encodage'= (-f $encoding)
|
||
]
|
||
})
|
||
|
||
-format 'POLICES:' ['ID' 'Nom' 'Nom de base' 'Embarqué' 'Type' 'Encodage'] $fonts
|
||
}
|
||
|
||
if $flags[i] {
|
||
var data = (pdf:images &fmt=$true &rec=$true $json)
|
||
var @images = (each {|i|
|
||
var dict = (pdf:deep $i 'object' 'dict')
|
||
var id = (pdf:deep $i 'object' 'object_id')
|
||
var page = (pdf:deep $i 'page')
|
||
var w = (pdf:deep $dict '/Width')
|
||
var h = (pdf:deep $dict '/Height')
|
||
var size = (pdf:deep $dict '/Length')
|
||
var bpc = (pdf:deep $dict '/BitsPerComponent')
|
||
var name = (pdf:deep $i 'name')
|
||
|
||
if (not-eq $name $nil) {
|
||
set name = (str:trim-left $name '/')
|
||
}
|
||
|
||
var filter color = (put '/Filter' '/ColorSpace' | each {|k|
|
||
var v = (pdf:deep $dict $k)
|
||
if (==s (kind-of $v) 'string') {
|
||
str:trim-left $v '/'
|
||
} else {
|
||
put $v
|
||
}
|
||
})
|
||
|
||
put [
|
||
&'ID'= $id
|
||
&'Page'= (-f $page)
|
||
&'Nom'= (-f $name)
|
||
&'Dimensions'= (printf '%d×%d px' $w $h)
|
||
&'Filtre'= (-f $filter)
|
||
&'Couleur'= (-f $color)
|
||
&'BPC'= (-f $bpc)
|
||
&'Taille'= (-size $size)
|
||
]
|
||
} $data)
|
||
|
||
-format 'IMAGES:' ['ID' 'Page' 'Nom' 'Dimensions' 'Filtre' 'Couleur' 'BPC' 'Taille'] $images
|
||
}
|
||
}
|
||
|
||
var actions = [
|
||
&help=$help~
|
||
&cat=$merge~
|
||
&compress=$compress~
|
||
&cut=$split-at~
|
||
&decrypt=$decrypt~
|
||
#&extract=$extract~
|
||
&gray=$gray~
|
||
&info=$info~
|
||
&list=$list~
|
||
&merge=$merge~
|
||
&mono=$mono~
|
||
&split=$split~
|
||
&split-at=$split-at~
|
||
&uncat=$unmerge~
|
||
&unmerge=$unmerge~
|
||
&unzip=$unzip~
|
||
&zip=$zip~
|
||
]
|
||
|
||
pdf:must $actions {|arg| has-key $arg $action } (printf '%s: action inconnue' $action)
|
||
$actions[$action] $@args
|
||
}
|