Page MenuHomec4science

main.go
No OneTemporary

File Metadata

Created
Sun, Dec 22, 19:18
// Copyright (C) 2018 Alexandre Tuleu
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version.
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// <https://www.gnu.org/licenses/>.
package main
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
const (
aciCols int = 2
aciRows = 8
myCols = 2
myRows = 6
)
type Page struct {
Width, Height float64
}
func ParseData(pdffile string) ([]Page, error) {
cmd := exec.Command("pdftk", pdffile, "dump_data")
out := bytes.NewBuffer(nil)
cmd.Stdout = out
if err := cmd.Run(); err != nil {
return nil, err
}
s := bufio.NewScanner(out)
nbPages := 0
var res []Page = nil
for s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
l := s.Text()
if strings.HasPrefix(l, "NumberOfPages") {
if _, err := fmt.Sscanf(l, "NumberOfPages: %d", &nbPages); err != nil {
return nil, err
}
res = make([]Page, 0, nbPages)
}
if strings.HasPrefix(l, "PageMediaDimensions:") {
if nbPages == 0 {
return nil, fmt.Errorf("Missing a number of pages")
}
w, h := 0.0, 0.0
if _, err := fmt.Sscanf(l, "PageMediaDimensions: %f %f", &w, &h); err != nil {
return nil, err
}
res = append(res, Page{Width: w, Height: h})
}
}
return res, nil
}
type Label struct {
Filename string
Left, Lower, Right, Upper float64
}
func BurstImages(filename string, pages []Page) ([]Label, error) {
burstCmd := exec.Command("pdftk", filename, "burst")
if err := burstCmd.Run(); err != nil {
return nil, err
}
res := make([]Label, 0, len(pages)*aciCols*aciRows)
for i, p := range pages {
width := p.Width / float64(aciCols)
height := p.Height / float64(aciRows)
cutFile := fmt.Sprintf("pg_%04d.pdf", i+1)
for i := 0; i < aciRows; i++ {
for j := 0; j < aciCols; j++ {
l := Label{
Filename: cutFile,
Left: float64(j) * width,
Lower: float64(aciRows-i-1) * height,
Right: float64(aciCols-j-1) * width,
Upper: float64(i) * height,
}
res = append(res, l)
}
}
}
return res, nil
}
const (
TEXFILE string = "layout.tex"
)
func GenerateTexfile(labels []Label) error {
texfile, err := os.Create(TEXFILE)
if err != nil {
return err
}
defer texfile.Close()
fmt.Fprintf(texfile, `%generated automatically
\documentclass[a4paper]{article}
\usepackage[paperwidth=21cm, paperheight=29.7cm, margin=0mm,tmargin=4mm,bmargin=4mm,centering,bindingoffset=0mm,marginparsep=0mm,marginparwidth=0mm,layouthoffset=-5.5mm]{geometry}
\usepackage{graphicx}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\begin{document}
\pagestyle{empty}
`)
closed := true
for i, l := range labels {
if i%(myCols*myRows) == 0 {
fmt.Fprintf(texfile, `\begin{tikzpicture}[
label/.style={
minimum width =%f\paperwidth,
minimum height = %f\paperheight
}
]
`, 1.0/float64(myCols)-0.01, 1.0/float64(myRows)-0.01)
closed = false
}
ii := (i % myCols)
jj := ((i - ii) / myCols) % myRows
fmt.Fprintf(texfile, `
\node[label] at (%f\textwidth,-%f\textheight) {
\includegraphics[trim={%fpt %fpt %fpt %fpt} ,clip, width=0.49\paperwidth]{%s}
};
`, float64(ii)/float64(myCols), float64(jj)/float64(myRows), l.Left, l.Lower, l.Right, l.Upper, l.Filename)
if i%(myCols*myRows) == (myCols*myRows - 1) {
fmt.Fprintf(texfile, `\end{tikzpicture}
\clearpage
`)
closed = true
}
}
if closed == false {
fmt.Fprintf(texfile, `\end{tikzpicture}
`)
}
fmt.Fprintf(texfile, `
\end{document}
`)
return nil
}
func GeneratePDF(destination string) error {
latexCmd := exec.Command("latexmk", "-pdf", "-interaction=nonstopmode", "-shell-escape", TEXFILE)
if err := latexCmd.Run(); err != nil {
return err
}
resname := strings.TrimSuffix(TEXFILE, ".tex") + ".pdf"
if err := os.Rename(resname, destination); err != nil {
return nil
}
return nil
}
func Execute() error {
if len(os.Args) != 2 {
return fmt.Errorf("Input file required")
}
filename, err := filepath.Abs(os.Args[1])
if err != nil {
return err
}
destination := strings.TrimSuffix(filename, filepath.Ext(filename)) + "-formatted.pdf"
cdir, err := os.Getwd()
if err != nil {
return err
}
tmpdir, err := ioutil.TempDir("", "converter")
if err != nil {
return err
}
os.Chdir(tmpdir)
defer func() {
os.Chdir(cdir)
os.RemoveAll(tmpdir)
}()
pages, err := ParseData(filename)
if err != nil {
return err
}
labels, err := BurstImages(filename, pages)
if err != nil {
return err
}
if err = GenerateTexfile(labels); err != nil {
return err
}
if err = GeneratePDF(destination); err != nil {
return err
}
return nil
}
func main() {
if err := Execute(); err != nil {
log.Printf("Got unexpected error: %s", err)
os.Exit(1)
}
}

Event Timeline