Skip to content

Commit e04f759

Browse files
committed
zig build!
1 parent abe4575 commit e04f759

20 files changed

+139
-240
lines changed

.github/workflows/ci.yaml

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,9 @@ jobs:
1919
with:
2020
node-version: ${{ matrix.node }}
2121
- uses: actions/checkout@v4
22-
- name: Install Dependencies
23-
run: |
24-
sudo apt update
25-
sudo apt install -y libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev librsvg2-dev
22+
- uses: mlugg/setup-zig@v2
2623
- name: Install
27-
run: npm install --build-from-source
24+
run: npm install
2825
- name: Test
2926
run: npm test
3027

@@ -39,17 +36,9 @@ jobs:
3936
with:
4037
node-version: ${{ matrix.node }}
4138
- uses: actions/checkout@v4
42-
- name: Install Dependencies
43-
run: |
44-
Invoke-WebRequest "https://ftp.gnome.org/pub/GNOME/binaries/win64/gtk+/2.22/gtk+-bundle_2.22.1-20101229_win64.zip" -OutFile "gtk.zip"
45-
Expand-Archive gtk.zip -DestinationPath "C:\GTK"
46-
Invoke-WebRequest "https://downloads.sourceforge.net/project/libjpeg-turbo/2.0.4/libjpeg-turbo-2.0.4-vc64.exe" -OutFile "libjpeg.exe" -UserAgent NativeHost
47-
.\libjpeg.exe /S
48-
winget install --accept-source-agreements --id=Microsoft.VCRedist.2010.x64 -e
49-
npm install -g node-gyp@8
50-
npm prefix -g | % {npm config set node_gyp "$_\node_modules\node-gyp\bin\node-gyp.js"}
39+
- uses: mlugg/setup-zig@v2
5140
- name: Install
52-
run: npm install --build-from-source
41+
run: npm install
5342
- name: Test
5443
run: npm test
5544

@@ -64,12 +53,9 @@ jobs:
6453
with:
6554
node-version: ${{ matrix.node }}
6655
- uses: actions/checkout@v4
67-
- name: Install Dependencies
68-
run: |
69-
brew update
70-
brew install python-setuptools pkg-config cairo pango libpng jpeg giflib librsvg
56+
- uses: mlugg/setup-zig@v2
7157
- name: Install
72-
run: npm install --build-from-source
58+
run: npm install
7359
- name: Test
7460
run: npm test
7561

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
build
1+
bin
22
.DS_Store
33
.lock-wscript
44
test/images/*.png
@@ -19,3 +19,5 @@ package-lock.json
1919
npm-debug.log
2020

2121
.idea
22+
23+
.zig-cache/

build.zig

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const std = @import("std");
2+
3+
pub fn build(b: *std.Build) void {
4+
const target = b.standardTargetOptions(.{});
5+
const optimize = b.standardOptimizeOption(.{});
6+
const cairo = b.dependency("cairo", .{
7+
.use_spectre = false,
8+
.use_xlib = false,
9+
.use_xcb = false,
10+
.use_png = true,
11+
.use_glib = false,
12+
.use_dwrite = false,
13+
.use_fontconfig = false,
14+
.use_freetype = false,
15+
.use_quartz = false,
16+
.target = target,
17+
.optimize = optimize,
18+
}).artifact("cairo");
19+
20+
const libjpeg_turbo = b.dependency("libjpeg_turbo", .{
21+
.target = target,
22+
.optimize = optimize,
23+
}).artifact("libjpeg_turbo");
24+
25+
const giflib = b.dependency("giflib", .{
26+
.target = target,
27+
.optimize = optimize,
28+
}).artifact("giflib");
29+
30+
const libpng = b.dependency("libpng", .{
31+
.target = target,
32+
.optimize = optimize,
33+
}).artifact("png");
34+
35+
const canvas = b.addLibrary(.{
36+
.name = "canvas",
37+
.linkage = .dynamic,
38+
.root_module = b.createModule(.{
39+
.target = target,
40+
.optimize = optimize,
41+
})
42+
});
43+
44+
const node_api = b.dependency("node_api", .{
45+
.target = target,
46+
.optimize = optimize,
47+
}).artifact("node_api");
48+
49+
canvas.addCSourceFiles(.{
50+
.files = &.{
51+
"src/bmp/BMPParser.cc",
52+
"src/Canvas.cc",
53+
"src/CanvasGradient.cc",
54+
"src/CanvasPattern.cc",
55+
"src/CanvasRenderingContext2d.cc",
56+
"src/closure.cc",
57+
"src/color.cc",
58+
"src/Image.cc",
59+
"src/ImageData.cc",
60+
"src/init.cc",
61+
"src/FontParser.cc"
62+
} ,
63+
.flags = &.{
64+
"-DNAPI_DISABLE_CPP_EXCEPTIONS",
65+
"-DNODE_ADDON_API_ENABLE_MAYBE",
66+
if (target.result.os.tag == .windows) "-DCAIRO_WIN32_STATIC_BUILD" else "",
67+
}
68+
});
69+
70+
canvas.linker_allow_shlib_undefined = true;
71+
72+
if (optimize != .Debug) {
73+
canvas.root_module.strip = true;
74+
}
75+
76+
canvas.linkLibC();
77+
canvas.linkLibCpp();
78+
canvas.addObject(node_api);
79+
canvas.linkLibrary(cairo);
80+
canvas.linkLibrary(libjpeg_turbo);
81+
canvas.linkLibrary(libpng);
82+
canvas.linkLibrary(giflib);
83+
84+
const move = b.addInstallFile(canvas.getEmittedBin(), "../bin/canvas.node");
85+
move.step.dependOn(&canvas.step);
86+
b.getInstallStep().dependOn(&move.step);
87+
}

build.zig.zon

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
.{
2+
.name = .canvas,
3+
.fingerprint = 0xa59f6c18a5521654,
4+
.version = "0.0.0",
5+
.paths = .{""},
6+
.minimum_zig_version = "0.15.1",
7+
.dependencies = .{
8+
.node_api = .{
9+
.url = "https://github.com/chearon/node-api-zig/archive/44210ae903fbfa3491cddc0260d468796213e4c8.tar.gz",
10+
.hash = "node_api-0.0.0-AAAAAAQgAAB-W9HyzJg5Vhja3uNMMcDiFaCJvBLt41GD",
11+
},
12+
.cairo = .{
13+
.url = "https://github.com/chearon/cairo.zig/archive/6b4c3e269483200576b17c160d2511e1e75e0c26.tar.gz",
14+
.hash = "cairo_zig-1.18.4-GbxI8fJhAQD27f7GkMyojP0v6K8DlNxetysEyAcu1qDD",
15+
},
16+
.libpng = .{
17+
.url = "https://github.com/allyourcodebase/libpng/archive/d512607515687aa60b975d6a191aef9a692dac87.zip",
18+
.hash = "libpng-1.6.50-oiaFGt4qAAB_vzrtvz9hA7_UiBW4arSaMVGc7ekKMCZ2",
19+
},
20+
.libjpeg_turbo = .{
21+
.url = "https://github.com/chearon/libjpeg-turbo/archive/8b323deee8527cf5053417b66ce8d13c81772b99.tar.gz",
22+
.hash = "libjpeg_turbo-3.1.1-1-iiYWshOCSQAUOo5zsLPqfjJMOLgpkJvcFTf6Cyn_AvkA",
23+
},
24+
.giflib = .{
25+
.url = "https://github.com/chearon/giflib/archive/986b2816254c3cebf7f9f735eb32564e4600cc66.tar.gz",
26+
.hash = "giflib-5.2.2-TakyOnIKIwCYvNoi8kEaGj5KYEc9hZ900YBld700u-PM",
27+
},
28+
},
29+
}

lib/bindings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const bindings = require('../build/Release/canvas.node')
3+
const bindings = require('../bin/canvas.node')
44

55
module.exports = bindings
66

lib/jpegstream.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ class JPEGStream extends Readable {
1313
constructor (canvas, options) {
1414
super()
1515

16-
if (canvas.streamJPEGSync === undefined) {
17-
throw new Error('node-canvas was built without JPEG support.')
18-
}
19-
2016
this.options = options
2117
this.canvas = canvas
2218
}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@
2424
"homepage": "https://github.com/Automattic/node-canvas",
2525
"repository": "git://github.com/Automattic/node-canvas.git",
2626
"scripts": {
27-
"prebenchmark": "node-gyp build",
27+
"prebenchmark": "zig build",
2828
"benchmark": "node benchmarks/run.js",
2929
"lint": "standard examples/*.js test/server.js test/public/*.js benchmarks/run.js lib/context2d.js util/has_lib.js browser.js index.js",
3030
"test": "mocha test/*.test.js",
31-
"pretest-server": "node-gyp build",
31+
"pretest-server": "zig build",
3232
"test-server": "node test/server.js",
3333
"generate-wpt": "node ./test/wpt/generate.js",
3434
"test-wpt": "mocha test/wpt/generated/*.js",
35-
"install": "prebuild-install -r napi || node-gyp rebuild",
35+
"install": "zig build",
3636
"tsd": "tsd"
3737
},
3838
"files": [

src/Canvas.cc

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,15 @@
1111
#include <cstring>
1212
#include <cctype>
1313
#include <ctime>
14-
#include <glib.h>
1514
#include "PNG.h"
1615
#include <sstream>
1716
#include <stdlib.h>
1817
#include <string>
1918
#include <unordered_set>
2019
#include "Util.h"
2120
#include <vector>
22-
#include "node_buffer.h"
2321
#include "FontParser.h"
24-
25-
#ifdef HAVE_JPEG
2622
#include "JPEGStream.h"
27-
#endif
2823

2924
#define CAIRO_MAX_SIZE 32767
3025

@@ -44,9 +39,7 @@ Canvas::Initialize(Napi::Env& env, Napi::Object& exports) {
4439
InstanceMethod<&Canvas::ToBuffer>("toBuffer", napi_default_method),
4540
InstanceMethod<&Canvas::StreamPNGSync>("streamPNGSync", napi_default_method),
4641
InstanceMethod<&Canvas::StreamPDFSync>("streamPDFSync", napi_default_method),
47-
#ifdef HAVE_JPEG
4842
InstanceMethod<&Canvas::StreamJPEGSync>("streamJPEGSync", napi_default_method),
49-
#endif
5043
InstanceAccessor<&Canvas::GetType>("type", napi_default_jsproperty),
5144
InstanceAccessor<&Canvas::GetStride>("stride", napi_default_jsproperty),
5245
InstanceAccessor<&Canvas::GetWidth, &Canvas::SetWidth>("width", napi_default_jsproperty),
@@ -212,13 +205,11 @@ Canvas::ToPngBufferAsync(Closure* base) {
212205
closure);
213206
}
214207

215-
#ifdef HAVE_JPEG
216208
void
217209
Canvas::ToJpegBufferAsync(Closure* base) {
218210
JpegClosure* closure = static_cast<JpegClosure*>(base);
219211
write_to_jpeg_buffer(closure->canvas->ensureSurface(), closure);
220212
}
221-
#endif
222213

223214
static void
224215
parsePNGArgs(Napi::Value arg, PngClosure& pngargs) {
@@ -263,7 +254,6 @@ parsePNGArgs(Napi::Value arg, PngClosure& pngargs) {
263254
}
264255
}
265256

266-
#ifdef HAVE_JPEG
267257
static void parseJPEGArgs(Napi::Value arg, JpegClosure& jpegargs) {
268258
// "If Type(quality) is not Number, or if quality is outside that range, the
269259
// user agent must use its default quality value, as if the quality argument
@@ -295,9 +285,6 @@ static void parseJPEGArgs(Napi::Value arg, JpegClosure& jpegargs) {
295285
}
296286
}
297287
}
298-
#endif
299-
300-
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
301288

302289
static inline void setPdfMetaStr(cairo_surface_t* surf, Napi::Object opts,
303290
cairo_pdf_metadata_t t, const char* propName) {
@@ -331,8 +318,6 @@ static void setPdfMetadata(Canvas* canvas, Napi::Object opts) {
331318
setPdfMetaDate(surf, opts, CAIRO_PDF_METADATA_MOD_DATE, "modDate");
332319
}
333320

334-
#endif // CAIRO 16+
335-
336321
/*
337322
* Converts/encodes data to a Buffer. Async when a callback function is passed.
338323
@@ -368,11 +353,9 @@ Canvas::ToBuffer(const Napi::CallbackInfo& info) {
368353
// mime type may be present, but it's not checked
369354
PdfSvgClosure* closure = static_cast<PdfSvgClosure*>(_closure);
370355
if (isPDF()) {
371-
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
372356
if (info[1].IsObject()) { // toBuffer("application/pdf", config)
373357
setPdfMetadata(this, info[1].As<Napi::Object>());
374358
}
375-
#endif // CAIRO 16+
376359
}
377360

378361
cairo_surface_t *surf = ensureSurface();
@@ -391,10 +374,6 @@ Canvas::ToBuffer(const Napi::CallbackInfo& info) {
391374
if (info[0].StrictEquals(Napi::String::New(env, "raw"))) {
392375
cairo_surface_t *surface = ensureSurface();
393376
cairo_surface_flush(surface);
394-
if (nBytes() > node::Buffer::kMaxLength) {
395-
Napi::Error::New(env, "Data exceeds maximum buffer length.").ThrowAsJavaScriptException();
396-
return env.Undefined();
397-
}
398377
return Napi::Buffer<uint8_t>::Copy(env, cairo_image_surface_get_data(surface), nBytes());
399378
}
400379

@@ -455,7 +434,6 @@ Canvas::ToBuffer(const Napi::CallbackInfo& info) {
455434
return env.Undefined();
456435
}
457436

458-
#ifdef HAVE_JPEG
459437
// Sync JPEG
460438
Napi::Value jpegStr = Napi::String::New(env, "image/jpeg");
461439
if (info[0].StrictEquals(jpegStr)) {
@@ -491,7 +469,6 @@ Canvas::ToBuffer(const Napi::CallbackInfo& info) {
491469
worker->Queue();
492470
return env.Undefined();
493471
}
494-
#endif
495472

496473
return env.Undefined();
497474
}
@@ -596,11 +573,9 @@ Canvas::StreamPDFSync(const Napi::CallbackInfo& info) {
596573
return;
597574
}
598575

599-
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
600576
if (info[1].IsObject()) {
601577
setPdfMetadata(this, info[1].As<Napi::Object>());
602578
}
603-
#endif
604579

605580
cairo_surface_finish(ensureSurface());
606581

@@ -626,7 +601,6 @@ Canvas::StreamPDFSync(const Napi::CallbackInfo& info) {
626601
* Stream JPEG data synchronously.
627602
*/
628603

629-
#ifdef HAVE_JPEG
630604
static uint32_t getSafeBufSize(Canvas* canvas) {
631605
// Don't allow the buffer size to exceed the size of the canvas (#674)
632606
// TODO not sure if this is really correct, but it fixed #674
@@ -647,7 +621,6 @@ Canvas::StreamJPEGSync(const Napi::CallbackInfo& info) {
647621
uint32_t bufsize = getSafeBufSize(this);
648622
write_to_jpeg_stream(ensureSurface(), bufsize, &closure);
649623
}
650-
#endif
651624

652625
char *
653626
str_value(Napi::Maybe<Napi::Value> maybe, const char *fallback, bool can_be_number) {
@@ -708,10 +681,8 @@ Canvas::approxBytesPerPixel() {
708681
case CAIRO_FORMAT_ARGB32:
709682
case CAIRO_FORMAT_RGB24:
710683
return 4;
711-
#ifdef CAIRO_FORMAT_RGB30
712684
case CAIRO_FORMAT_RGB30:
713685
return 3;
714-
#endif
715686
case CAIRO_FORMAT_RGB16_565:
716687
return 2;
717688
case CAIRO_FORMAT_A8:

src/Canvas.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ struct PdfSvgClosure;
77

88
#include "closure.h"
99
#include <cairo.h>
10-
#include "dll_visibility.h"
1110
#include <napi.h>
1211
#include <vector>
1312
#include <cstddef>
1413

14+
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
15+
#define DLL_LOCAL __attribute__ ((visibility ("hidden")))
16+
1517
/*
1618
* Canvas types.
1719
*/

0 commit comments

Comments
 (0)