elvish_config/aliases/pdf.elv

558 lines
13 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.

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
}