Skip to content

Commit dc533e7

Browse files
Render PDF page to HTML
Add the feature to render a PDF page to HTML. Issue: CW-1504
1 parent 1829ea1 commit dc533e7

17 files changed

+4039
-227
lines changed

main.c

+345-227
Large diffs are not rendered by default.

main.go

+47
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,53 @@ func SaveToPNG(
7979
return nil
8080
}
8181

82+
func SaveToHTML(
83+
ctx context.Context, page, width uint16, scale float32, dpi int, rawPayload io.Reader, output io.Writer,
84+
) (err error) {
85+
span, _ := ddTracer.StartSpanFromContext(ctx, "lazypdf.SaveToHTML")
86+
defer func() { span.Finish(ddTracer.WithError(err)) }()
87+
88+
if rawPayload == nil {
89+
return errors.New("payload can't be nil")
90+
}
91+
if output == nil {
92+
return errors.New("output can't be nil")
93+
}
94+
95+
payload, err := io.ReadAll(rawPayload)
96+
if err != nil {
97+
return fmt.Errorf("fail to read the payload: %w", err)
98+
}
99+
100+
input := C.save_to_html_input{
101+
page: C.int(page),
102+
width: C.int(width),
103+
scale: C.float(scale),
104+
dpi: C.int(dpi),
105+
payload: (*C.char)(unsafe.Pointer(&payload[0])),
106+
payload_length: C.size_t(len(payload)),
107+
cookie: &C.fz_cookie{abort: 0},
108+
}
109+
if dpi < defaultDPI {
110+
input.dpi = C.int(defaultDPI)
111+
}
112+
go func() {
113+
<-ctx.Done()
114+
input.cookie.abort = 1
115+
}()
116+
result := C.save_to_html(input) // nolint: gocritic
117+
defer C.je_free(unsafe.Pointer(result.payload))
118+
if result.error != nil {
119+
defer C.je_free(unsafe.Pointer(result.error))
120+
return fmt.Errorf("failure at the C/MuPDF layer: %s", C.GoString(result.error))
121+
}
122+
123+
if _, err := output.Write([]byte(C.GoStringN(result.payload, C.int(result.payload_length)))); err != nil {
124+
return fmt.Errorf("fail to write to the output: %w", err)
125+
}
126+
return nil
127+
}
128+
82129
// PageCount is used to return the page count of the document.
83130
func PageCount(ctx context.Context, rawPayload io.Reader) (_ int, err error) {
84131
span, _ := ddTracer.StartSpanFromContext(ctx, "lazypdf.PageCount")

main.h

+17
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,26 @@ typedef struct {
2929
char *error;
3030
} save_to_png_output;
3131

32+
typedef struct {
33+
int page;
34+
int width;
35+
float scale;
36+
int dpi;
37+
char *payload;
38+
size_t payload_length;
39+
fz_cookie *cookie;
40+
} save_to_html_input;
41+
42+
typedef struct {
43+
char *payload;
44+
size_t payload_length;
45+
char *error;
46+
} save_to_html_output;
47+
3248
void init();
3349

3450
page_count_output page_count(page_count_input input);
3551
save_to_png_output save_to_png(save_to_png_input input);
52+
save_to_html_output save_to_html(save_to_html_input input);
3653

3754
#endif

main_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,34 @@ import (
1111
"github.com/stretchr/testify/require"
1212
)
1313

14+
func TestSaveToHTMLOK(t *testing.T) {
15+
for i := uint16(0); i < 13; i++ {
16+
file, err := os.Open("testdata/sample.pdf")
17+
require.NoError(t, err)
18+
defer func() { require.NoError(t, file.Close()) }()
19+
20+
buf := bytes.NewBuffer([]byte{})
21+
err = SaveToHTML(context.Background(), i, 0, 0, 0, file, buf)
22+
require.NoError(t, err)
23+
24+
expectedPage, err := os.ReadFile(fmt.Sprintf("testdata/sample_page%d.html", i))
25+
require.NoError(t, err)
26+
resultPage, err := io.ReadAll(buf)
27+
require.NoError(t, err)
28+
require.Equal(t, expectedPage, resultPage)
29+
}
30+
}
31+
32+
func TestSaveToHTMLFail(t *testing.T) {
33+
file, err := os.Open("testdata/sample-invalid.pdf")
34+
require.NoError(t, err)
35+
defer func() { require.NoError(t, file.Close()) }()
36+
37+
err = SaveToHTML(context.Background(), 0, 0, 0, 0, file, bytes.NewBuffer([]byte{}))
38+
require.Error(t, err)
39+
require.Equal(t, "failure at the C/MuPDF layer: no objects found", err.Error())
40+
}
41+
1442
func TestSaveToPNGOK(t *testing.T) {
1543
for i := uint16(0); i < 13; i++ {
1644
file, err := os.Open("testdata/sample.pdf")

testdata/sample_page0.html

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<style>
5+
p{position:absolute;white-space:pre;margin:0}
6+
</style>
7+
</head>
8+
<body>
9+
<div id="page0" style="width:1190.6pt;height:841.9pt">
10+
<p style="top:805.8pt;left:1143.0pt;line-height:9.0pt"><span style="font-family:Arial,serif;font-size:9.0pt;color:#ffffff">7</span></p>
11+
<p style="top:805.8pt;left:42.5pt;line-height:9.0pt"><span style="font-family:Arial,serif;font-size:9.0pt;color:#ffffff">6</span></p>
12+
<p style="top:18.1pt;left:163.8pt;line-height:15.0pt"><b><span style="font-family:Frutiger,serif;font-size:15.0pt;color:#ffffff">P a r t N u m b e r G u i d e</span></b></p>
13+
<p style="top:152.0pt;left:51.0pt;line-height:10.0pt"><b><span style="font-family:Frutiger,serif;font-size:10.0pt;color:#231f20">N C 3 FA H 1 - B - 0 - D</span></b></p>
14+
<p style="top:168.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Packaging:</span></b></p>
15+
<p style="top:168.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">D</span></b></p>
16+
<p style="top:168.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Cable connector: Bulk packed</span></p>
17+
<p style="top:180.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Assembly:</span></b></p>
18+
<p style="top:180.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">D</span></b></p>
19+
<p style="top:180.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Chassis connector: Disassembled Push latch</span></p>
20+
<p style="top:192.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Retention:</span></b></p>
21+
<p style="top:192.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">w/o</span></b></p>
22+
<p style="top:192.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Latch Lock</span></p>
23+
<p style="top:204.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">-0</span></b></p>
24+
<p style="top:204.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Retention Spring</span></p>
25+
<p style="top:216.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Shell:</span></b></p>
26+
<p style="top:216.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">B</span></b></p>
27+
<p style="top:216.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Black shell, gold contacts</span></p>
28+
<p style="top:228.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">BAG</span></b></p>
29+
<p style="top:228.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Black shell, silver contacts</span></p>
30+
<p style="top:240.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Grounding:</span></b></p>
31+
<p style="top:240.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">0</span></b></p>
32+
<p style="top:240.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Separate ground contact connected to shell, male only</span></p>
33+
<p style="top:252.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">1</span></b></p>
34+
<p style="top:252.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Pin 1 &amp; Panel &amp; Shell connected, no separate ground contact</span></p>
35+
<p style="top:264.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">2</span></b></p>
36+
<p style="top:264.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Separate ground contact connected to shell &amp; panel, separate Pin 1</span></p>
37+
<p style="top:276.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">E</span></b></p>
38+
<p style="top:276.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Additional ground contacts</span></p>
39+
<p style="top:288.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">w/o number</span></b></p>
40+
<p style="top:288.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">No ground / Shell contact (except 4 / 5 pole), female only</span></p>
41+
<p style="top:300.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Termination:</span></b></p>
42+
<p style="top:300.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">H</span></b></p>
43+
<p style="top:300.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Horizontal PCB mount</span></p>
44+
<p style="top:312.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">HL</span></b></p>
45+
<p style="top:312.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Laterial left PCB mount</span></p>
46+
<p style="top:324.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">HR</span></b></p>
47+
<p style="top:324.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Laterial right PCB mount</span></p>
48+
<p style="top:336.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">L</span></b></p>
49+
<p style="top:336.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Solder Cups</span></p>
50+
<p style="top:348.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">V</span></b></p>
51+
<p style="top:348.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Verticale PCB mount</span></p>
52+
<p style="top:360.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Y</span></b></p>
53+
<p style="top:360.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">IDC for wires (no ground)</span></p>
54+
<p style="top:372.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">M3</span></b></p>
55+
<p style="top:372.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Mounting holes with M3 thread</span></p>
56+
<p style="top:384.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">M25</span></b></p>
57+
<p style="top:384.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Mounting holes with M2.5 thread</span></p>
58+
<p style="top:396.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">-</span></b></p>
59+
<p style="top:396.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Not applicable</span></p>
60+
<p style="top:408.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Series:</span></b></p>
61+
<p style="top:408.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">A, AA, B, BA, D, DL, DLX, MPR, P, PX, RX, X, XX</span></b></p>
62+
<p style="top:420.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Gender:</span></b></p>
63+
<p style="top:420.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">F</span></b></p>
64+
<p style="top:420.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Female</span></p>
65+
<p style="top:432.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">M</span></b></p>
66+
<p style="top:432.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Male</span></p>
67+
<p style="top:444.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Number of Contacts: 3, 4, 5, 6, 7, 8, 12</span></b></p>
68+
<p style="top:456.0pt;left:150.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Connector Type:</span></b></p>
69+
<p style="top:456.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">A</span></b></p>
70+
<p style="top:456.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Adapter</span></p>
71+
<p style="top:468.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">AC</span></b></p>
72+
<p style="top:468.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">PowerCon</span></p>
73+
<p style="top:468.4pt;left:343.4pt;line-height:2.6pt"><span style="font-family:Frutiger,serif;font-size:2.6pt;color:#231f20">&#xae;</span></p>
74+
<p style="top:480.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">B</span></b></p>
75+
<p style="top:480.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">BNC</span></p>
76+
<p style="top:492.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">C</span></b></p>
77+
<p style="top:492.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">XLR</span></p>
78+
<p style="top:504.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">E</span></b></p>
79+
<p style="top:504.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">RJ45</span></p>
80+
<p style="top:516.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">F</span></b></p>
81+
<p style="top:516.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">RCA / CINCH</span></p>
82+
<p style="top:528.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">J (MJ, RJ, SJ)</span></b></p>
83+
<p style="top:528.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Jack</span></p>
84+
<p style="top:540.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">K</span></b></p>
85+
<p style="top:540.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Cable Assemblies</span></p>
86+
<p style="top:552.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">L</span></b></p>
87+
<p style="top:552.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Loudspeaker</span></p>
88+
<p style="top:564.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">M</span></b></p>
89+
<p style="top:564.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Modules</span></p>
90+
<p style="top:576.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">O</span></b></p>
91+
<p style="top:576.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Fiber Connector</span></p>
92+
<p style="top:588.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">P</span></b></p>
93+
<p style="top:588.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Plugs</span></p>
94+
<p style="top:600.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">PP</span></b></p>
95+
<p style="top:600.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Patch Panel</span></p>
96+
<p style="top:612.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">R</span></b></p>
97+
<p style="top:612.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Circular Connector</span></p>
98+
<p style="top:624.0pt;left:236.2pt;line-height:7.5pt"><b><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">T</span></b></p>
99+
<p style="top:624.0pt;left:308.2pt;line-height:7.5pt"><span style="font-family:Frutiger,serif;font-size:7.5pt;color:#231f20">Transformer</span></p>
100+
<p style="top:116.3pt;left:151.2pt;line-height:11.0pt"><b><span style="font-family:Frutiger,serif;font-size:11.0pt;color:#ffffff">N e u t r i k</span></b></p>
101+
<p style="top:116.2pt;left:232.1pt;line-height:3.5pt"><span style="font-family:Frutiger,serif;font-size:3.5pt;color:#ffffff">&#xae;</span><b><span style="font-family:Frutiger,serif;font-size:11.0pt;color:#ffffff"> </span></b></p>
102+
<p style="top:116.3pt;left:247.6pt;line-height:11.0pt"><b><span style="font-family:Frutiger,serif;font-size:11.0pt;color:#ffffff">P a r t N u m b e r G u i d e</span></b></p>
103+
<p style="top:214.3pt;left:805.0pt;line-height:24.0pt"><b><span style="font-family:Frutiger,serif;font-size:24.0pt;color:#231f20">XLR Connectors</span></b></p>
104+
<p style="top:806.0pt;left:130.4pt;line-height:9.0pt"><b><span style="font-family:Frutiger,serif;font-size:9.0pt;color:#ffffff">look for the logo</span></b></p>
105+
</div>
106+
</body></html>

0 commit comments

Comments
 (0)