elvish_config/aliases/pdf.elv

558 lines
13 KiB
Plaintext
Raw Normal View History

use moi/util/format
use moi/util/pdf
use math
use path
use re
use str
fn -must-pdf {|file|
if (not (pdf:is-pdf $file)) {
fail (printf '%s nest pas un fichier pdf' $file)
}
}
fn -must-exist {|file|
if (pdf:not-exist $file) {
fail (printf '%s nexiste pas' $file)
}
}
fn -must-not-exist {|file|
if (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|
if (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)
if (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)
if (< $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)
if (< $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 {
if (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)
if (< $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)
if (< $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)
if (!= $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)
if (< $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 {
if (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)
if (< $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
if (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)
if (== $s 0) {
set s = $mod
}
if (== $s $m) {
put $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 = []
if (> (count $raw[16..]) 0) {
set @rest = (str:split "'" $raw[16..])
}
var tz = '+00:00'
if (> (count $rest) 0) {
var tz = $rest[0]
if (eq $tz[0] 'Z') {
set tz = $tz[1..]
}
if (eq $tz '') {
set tz = '00'
}
if (and (not-eq $tz[0] '+') (not-eq $tz[0] '-')) {
set tz = (printf '+%s' $tz)
}
var mm = '00'
if (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|
if (!= (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 = 'Portrait'
var title = ''
var subject = ''
var author = ''
var creator = ''
var producer = ''
var mdate = ''
var crypted = 'Non'
var hasform = 'Non'
if (> $w $h) {
set layout = 'Paysage'
}
if (has-key $infos '/Title') {
set title = $infos[/Title]
}
if (has-key $infos '/Subject') {
set subject = $infos[/Subject]
}
if (has-key $infos '/Author') {
set author = $infos[/Author]
}
if (has-key $infos '/Creator') {
set creator = $infos[/Creator]
}
if (has-key $infos '/Producer') {
set producer = $infos[/Producer]
}
if (has-key $infos '/ModDate') {
set mdate = (-date $infos[/ModDate])
}
if (pdf:encryption $in)[encrypted] {
set crypted = 'Oui'
}
if (pdf:form $in)[hasacroform] {
set hasform = 'Oui'
}
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)
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~
&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~
]
if (not (has-key $actions $action)) {
fail (printf '%s: action inconnue' $action)
}
$actions[$action] $@args
}