Skip to content

Commit 3c94267

Browse files
authored
Merge pull request #19 from hivesolutions/file_formats
feat: add support for more file formats
2 parents c259409 + 812394c commit 3c94267

File tree

3 files changed

+70
-128
lines changed

3 files changed

+70
-128
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# [Headless](https://headless.hive.pt)
22

3-
Simple headless browser API to render images (PNG, JPEG, WebP, etc.) and PDFs from plain HTML.
3+
Simple headless browser API to render images (PNG, JPEG, WebP, TIFF, BMP, etc.) and PDFs from plain HTML.
44

55
## Features
66

lib/engines/puppeteer.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,21 @@ class Puppeteer extends engine.Engine {
140140
res.type("pdf");
141141
res.send(data);
142142
} else {
143+
// checks if the format is natively supported by puppeteer
144+
// and if that's not the case re-encoding is needed, uses
145+
// PNG format as the base one when doing re-encoding
146+
const reEncode = ["png", "jpeg", "webp"].indexOf(format) === -1;
147+
const baseFormat = reEncode ? "png" : format;
148+
143149
let data = await page.screenshot({
144150
fullPage: fullPage,
145-
type: format
151+
type: baseFormat
146152
});
147-
if (trim) {
153+
if (trim || reEncode) {
148154
const image = await jimp.read(data);
149-
image.autocrop();
155+
if (trim) {
156+
image.autocrop();
157+
}
150158
data = await image.getBufferAsync(`image/${format}`);
151159
}
152160
res.type(format);

test/engines/puppeteer.js

Lines changed: 58 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -15,137 +15,86 @@ describe("Puppeteer", function() {
1515
});
1616

1717
it("should render a PDF", async () => {
18-
const engine = new puppeteer.Puppeteer();
19-
await engine.init();
20-
21-
try {
22-
const req = {
23-
query: {
24-
url: "https://example.com/",
25-
format: "pdf"
26-
},
27-
body: {}
28-
};
29-
const res = {
30-
send: function(data) {
31-
this.data = data;
32-
},
33-
type: function(file) {
34-
this.file = file;
35-
}
36-
};
37-
await engine.render(req, res);
38-
assert.ok(res.data);
39-
assert.strictEqual(res.file, "pdf");
40-
assert.ok(res.data.slice(0, 5).equals(Buffer.from([0x25, 0x50, 0x44, 0x46, 0x2d])));
41-
} finally {
42-
await engine.destroy();
43-
}
18+
const res = await tryRenderPage("pdf");
19+
assert.ok(res.data);
20+
assert.strictEqual(res.file, "pdf");
21+
assert.ok(res.data.slice(0, 5).equals(Buffer.from([0x25, 0x50, 0x44, 0x46, 0x2d])));
4422
});
4523

4624
it("should render a PNG by default", async () => {
47-
const engine = new puppeteer.Puppeteer();
48-
await engine.init();
49-
50-
try {
51-
const req = {
52-
query: {
53-
url: "https://example.com/"
54-
},
55-
body: {}
56-
};
57-
const res = {
58-
send: function(data) {
59-
this.data = data;
60-
},
61-
type: function(file) {
62-
this.file = file;
63-
}
64-
};
65-
await engine.render(req, res);
66-
assert.ok(res.data);
67-
assert.strictEqual(res.file, "png");
68-
assert.ok(
69-
res.data
70-
.slice(0, 8)
71-
.equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
72-
);
73-
} finally {
74-
await engine.destroy();
75-
}
25+
const res = await tryRenderPage("png");
26+
assert.ok(res.data);
27+
assert.strictEqual(res.file, "png");
28+
assert.ok(
29+
res.data
30+
.slice(0, 8)
31+
.equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
32+
);
7633
});
7734

7835
it("should render a PNG", async () => {
79-
const engine = new puppeteer.Puppeteer();
80-
await engine.init();
81-
82-
try {
83-
const req = {
84-
query: {
85-
url: "https://example.com/",
86-
format: "png"
87-
},
88-
body: {}
89-
};
90-
const res = {
91-
send: function(data) {
92-
this.data = data;
93-
},
94-
type: function(file) {
95-
this.file = file;
96-
}
97-
};
98-
await engine.render(req, res);
99-
assert.ok(res.data);
100-
assert.strictEqual(res.file, "png");
101-
assert.ok(
102-
res.data
103-
.slice(0, 8)
104-
.equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
105-
);
106-
} finally {
107-
await engine.destroy();
108-
}
36+
const res = await tryRenderPage("png");
37+
assert.ok(res.data);
38+
assert.strictEqual(res.file, "png");
39+
assert.ok(
40+
res.data
41+
.slice(0, 8)
42+
.equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
43+
);
10944
});
11045

11146
it("should render a JPEG", async () => {
47+
const res = await tryRenderPage("jpeg");
48+
assert.ok(res.data);
49+
assert.strictEqual(res.file, "jpeg");
50+
assert.ok(res.data.slice(0, 3).equals(Buffer.from([0xff, 0xd8, 0xff])));
51+
});
52+
53+
it("should render a WebP", async () => {
54+
const res = await tryRenderPage("webp");
55+
assert.ok(res.data);
56+
assert.strictEqual(res.file, "webp");
57+
assert.ok(res.data.slice(0, 4).equals(Buffer.from([0x52, 0x49, 0x46, 0x46])));
58+
assert.ok(res.data.slice(8, 12).equals(Buffer.from([0x57, 0x45, 0x42, 0x50])));
59+
});
60+
61+
it("should render a TIFF", async () => {
62+
const res = await tryRenderPage("tiff");
63+
assert.ok(res.data);
64+
assert.strictEqual(res.file, "tiff");
65+
const littleEndian = res.data.slice(0, 4).equals(Buffer.from([0x49, 0x49, 0x2a, 0x00]));
66+
const bigEndian = res.data.slice(0, 4).equals(Buffer.from([0x4d, 0x4d, 0x00, 0x2a]));
67+
assert.ok(littleEndian || bigEndian);
68+
});
69+
70+
it("should render a BMP", async () => {
71+
const res = await tryRenderPage("bmp");
72+
assert.ok(res.data);
73+
assert.strictEqual(res.file, "bmp");
74+
assert.ok(res.data.slice(0, 2).equals(Buffer.from([0x42, 0x4d])));
75+
});
76+
77+
it("should open new page", async () => {
11278
const engine = new puppeteer.Puppeteer();
11379
await engine.init();
114-
11580
try {
116-
const req = {
117-
query: {
118-
url: "https://example.com/",
119-
format: "jpeg"
120-
},
121-
body: {}
122-
};
123-
const res = {
124-
send: function(data) {
125-
this.data = data;
126-
},
127-
type: function(file) {
128-
this.file = file;
129-
}
130-
};
131-
await engine.render(req, res);
132-
assert.ok(res.data);
133-
assert.strictEqual(res.file, "jpeg");
134-
assert.ok(res.data.slice(0, 3).equals(Buffer.from([0xff, 0xd8, 0xff])));
81+
await engine._newPage();
82+
const pages = await engine.instance.pages();
83+
assert.strictEqual(2, pages.length);
13584
} finally {
13685
await engine.destroy();
13786
}
13887
});
13988

140-
it("should render a WebP", async () => {
89+
const tryRenderPage = async (format = null) => {
14190
const engine = new puppeteer.Puppeteer();
14291
await engine.init();
14392

14493
try {
14594
const req = {
14695
query: {
14796
url: "https://example.com/",
148-
format: "webp"
97+
format: format
14998
},
15099
body: {}
151100
};
@@ -158,24 +107,9 @@ describe("Puppeteer", function() {
158107
}
159108
};
160109
await engine.render(req, res);
161-
assert.ok(res.data);
162-
assert.strictEqual(res.file, "webp");
163-
assert.ok(res.data.slice(0, 4).equals(Buffer.from([0x52, 0x49, 0x46, 0x46])));
164-
assert.ok(res.data.slice(8, 12).equals(Buffer.from([0x57, 0x45, 0x42, 0x50])));
110+
return res;
165111
} finally {
166112
await engine.destroy();
167113
}
168-
});
169-
170-
it("should open new page", async () => {
171-
const engine = new puppeteer.Puppeteer();
172-
await engine.init();
173-
try {
174-
await engine._newPage();
175-
const pages = await engine.instance.pages();
176-
assert.strictEqual(2, pages.length);
177-
} finally {
178-
await engine.destroy();
179-
}
180-
});
114+
};
181115
});

0 commit comments

Comments
 (0)