-
Notifications
You must be signed in to change notification settings - Fork 7
/
main.go
104 lines (91 loc) · 3.38 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package lazypdf
/*
#cgo CFLAGS: -I ${SRCDIR}/misc/mupdf/include -I ${SRCDIR}/misc/mupdf/include/mupdf -I ${SRCDIR}/misc/jemalloc/include -I ${SRCDIR}/misc/jemalloc/include/jemalloc
#cgo linux,amd64 LDFLAGS: -L ${SRCDIR}/misc/mupdf/lib/x86-64-linux -lmupdf -lmupdf-third -L ${SRCDIR}/misc/jemalloc/lib/x86-64-linux -ljemalloc -lm -lpthread -ldl
#include <jemalloc/jemalloc.h>
#include "main.h"
*/
import "C"
import (
"context"
"errors"
"fmt"
"io"
"unsafe"
ddTracer "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
)
const defaultDPI = 96
func init() {
C.init()
}
// SaveToPNG is used to convert a page from a PDF file to PNG. Internally everything is based on the scale factor and
// this value is used to determine the actual output size based on the original size of the page.
// If none is set we'll use a default scale factor of 1.5. When using the default value, 1.5, there is a special case
// when we detect that the page is a landscape and it has a 0 or 180 degree rotation, on those cases we set the scale
// factor of 1.
// If width is set then we'll calculate the scale factor by dividing the width by the page horizontal size.
// If both width and scale are set we'll use only the scale as it takes precedence.
func SaveToPNG(
ctx context.Context, page, width uint16, scale float32, dpi int, rawPayload io.Reader, output io.Writer,
) (err error) {
span, _ := ddTracer.StartSpanFromContext(ctx, "lazypdf.SaveToPNG")
defer func() { span.Finish(ddTracer.WithError(err)) }()
if rawPayload == nil {
return errors.New("payload can't be nil")
}
if output == nil {
return errors.New("output can't be nil")
}
payload, err := io.ReadAll(rawPayload)
if err != nil {
return fmt.Errorf("fail to read the payload: %w", err)
}
input := C.save_to_png_input{
page: C.int(page),
width: C.int(width),
scale: C.float(scale),
dpi: C.int(dpi),
payload: (*C.char)(unsafe.Pointer(&payload[0])),
payload_length: C.size_t(len(payload)),
cookie: &C.fz_cookie{abort: 0},
}
if dpi < defaultDPI {
input.dpi = C.int(defaultDPI)
}
go func() {
<-ctx.Done()
input.cookie.abort = 1
}()
result := C.save_to_png(input) // nolint: gocritic
defer C.je_free(unsafe.Pointer(result.payload))
if result.error != nil {
defer C.je_free(unsafe.Pointer(result.error))
return fmt.Errorf("failure at the C/MuPDF layer: %s", C.GoString(result.error))
}
if _, err := output.Write([]byte(C.GoStringN(result.payload, C.int(result.payload_length)))); err != nil {
return fmt.Errorf("fail to write to the output: %w", err)
}
return nil
}
// PageCount is used to return the page count of the document.
func PageCount(ctx context.Context, rawPayload io.Reader) (_ int, err error) {
span, _ := ddTracer.StartSpanFromContext(ctx, "lazypdf.PageCount")
defer func() { span.Finish(ddTracer.WithError(err)) }()
if rawPayload == nil {
return 0, errors.New("payload can't be nil")
}
payload, err := io.ReadAll(rawPayload)
if err != nil {
return 0, fmt.Errorf("fail to read the payload: %w", err)
}
input := C.page_count_input{
payload: (*C.char)(unsafe.Pointer(&payload[0])),
payload_length: C.size_t(len(payload)),
}
output := C.page_count(input) // nolint: gocritic
if output.error != nil {
defer C.je_free(unsafe.Pointer(output.error))
return 0, fmt.Errorf("failure at the C/MuPDF layer: %s", C.GoString(output.error))
}
return int(output.count), nil
}