Skip to content

Commit 39cbd95

Browse files
authored
feat: PdfDocument, SvgCanvas (#13)
* feat: PdfDocument * feat: SvgCanvas
1 parent ecbea7b commit 39cbd95

File tree

18 files changed

+571
-9
lines changed

18 files changed

+571
-9
lines changed

deno.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
"tasks": {
77
"build": "cd native/build && CC=clang CXX=clang++ cmake .. && cmake --build . --config Release",
88
"build-win": "rm -rf native/build && mkdir native/build && cd native/build && cmake .. -G \"Visual Studio 17 2022\" -T ClangCL && cmake --build . --config Release",
9-
"test": "deno run -A --unstable test.ts",
9+
"test": "deno run -A --unstable ./test/test.ts",
10+
"test-pdf": "deno run -A --unstable ./test/pdf.ts",
11+
"test-svg": "deno run -A --unstable ./test/svg.ts",
1012
"bench": "deno bench -A --unstable bench/deno.js",
1113
"bench-node": "node bench/node.mjs",
1214
"build-skia": "deno run -A --unstable scripts/build_skia.ts"

mod.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ export * from "./src/font.ts";
77
export * from "./src/dommatrix.ts";
88
export * from "./src/gradient.ts";
99
export * from "./src/pattern.ts";
10+
export * from "./src/pdfdocument.ts";
11+
export * from "./src/svgcanvas.ts";

native/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ add_library(native_canvas SHARED
1616
src/path2d.cpp
1717
src/image.cpp
1818
src/gradient.cpp
19-
src/pattern.cpp)
19+
src/pattern.cpp
20+
src/pdfdocument.cpp
21+
src/svgcanvas.cpp)
2022

2123
if (UNIX)
2224
target_compile_options(native_canvas PRIVATE

native/include/pdfdocument.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include "include/common.hpp"
2+
#include "include/context2d.hpp"
3+
#include "include/docs/SkPDFDocument.h"
4+
5+
typedef struct sk_pdf_document {
6+
SkDynamicMemoryWStream* stream;
7+
SkDocument* pdf;
8+
} sk_pdf_document;
9+
10+
extern "C" {
11+
SKIA_EXPORT sk_pdf_document* sk_pdf_new(
12+
char* title,
13+
char* author,
14+
char* subject,
15+
char* keywords,
16+
char* creator,
17+
char* producer,
18+
SkTime::DateTime creation,
19+
SkTime::DateTime modified,
20+
bool pdfa,
21+
int encodingQuality
22+
);
23+
24+
SKIA_EXPORT sk_context* sk_pdf_begin_page(
25+
sk_pdf_document* doc,
26+
float width,
27+
float height,
28+
float x,
29+
float y,
30+
float w,
31+
float h
32+
);
33+
34+
SKIA_EXPORT void sk_pdf_end_page(sk_pdf_document* doc);
35+
36+
SKIA_EXPORT int sk_pdf_write_file(sk_pdf_document* doc, char* path);
37+
38+
SKIA_EXPORT SkData* sk_pdf_get_buffer(sk_pdf_document* doc, void** buffer, unsigned int* size);
39+
40+
SKIA_EXPORT void sk_pdf_destroy(sk_pdf_document* doc);
41+
}

native/include/svgcanvas.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include "include/common.hpp"
2+
#include "include/core/SkStream.h"
3+
#include "include/svg/SkSVGCanvas.h"
4+
#include "include/context2d.hpp"
5+
6+
typedef struct sk_svg {
7+
SkDynamicMemoryWStream* stream;
8+
SkCanvas* canvas;
9+
} sk_svg;
10+
11+
extern "C" {
12+
SKIA_EXPORT sk_svg* sk_svg_new(int width, int height, int flags);
13+
14+
SKIA_EXPORT void sk_svg_destroy(sk_svg* svg);
15+
16+
SKIA_EXPORT sk_context* sk_svg_get_context(sk_svg* svg);
17+
18+
SKIA_EXPORT int sk_svg_write_file(sk_svg* svg, char* path);
19+
20+
SKIA_EXPORT SkData* sk_svg_get_buffer(sk_svg* svg, void** buffer, unsigned int* size);
21+
}

native/src/context2d.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ void free_context_state(sk_context_state* state) {
8282
delete state->paint;
8383
delete state->transform;
8484
free(state->font);
85-
delete state;
8685
}
8786

8887
// Utility
@@ -1273,7 +1272,11 @@ extern "C" {
12731272
/// CONTEXT_FINALIZER callback
12741273
void sk_context_destroy(sk_context* context) {
12751274
delete context->path;
1275+
free_context_state(context->state);
12761276
delete context->state;
1277+
for (auto state : context->states) {
1278+
free_context_state(&state);
1279+
}
12771280
delete context;
12781281
}
12791282
}

native/src/pdfdocument.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "include/pdfdocument.hpp"
2+
3+
extern "C" {
4+
sk_pdf_document* sk_pdf_new(
5+
char* title,
6+
char* author,
7+
char* subject,
8+
char* keywords,
9+
char* creator,
10+
char* producer,
11+
SkTime::DateTime creation,
12+
SkTime::DateTime modified,
13+
bool pdfa,
14+
int encodingQuality
15+
) {
16+
sk_pdf_document* doc = new sk_pdf_document();
17+
doc->stream = new SkDynamicMemoryWStream();
18+
SkPDF::Metadata metadata;
19+
metadata.fTitle = SkString(title);
20+
metadata.fAuthor = SkString(author);
21+
metadata.fSubject = SkString(subject);
22+
metadata.fKeywords = SkString(keywords);
23+
metadata.fCreator = SkString(creator);
24+
metadata.fProducer = SkString(producer);
25+
metadata.fCreation = creation;
26+
metadata.fModified = modified;
27+
metadata.fPDFA = pdfa;
28+
metadata.fEncodingQuality = encodingQuality;
29+
doc->pdf = SkPDF::MakeDocument(doc->stream, metadata).release();
30+
return doc;
31+
}
32+
33+
sk_context* sk_pdf_begin_page(
34+
sk_pdf_document* doc,
35+
float width,
36+
float height,
37+
float x,
38+
float y,
39+
float w,
40+
float h
41+
) {
42+
sk_context* ctx = new sk_context();
43+
auto rect = SkRect::MakeXYWH(x, y, w, h);
44+
ctx->canvas = doc->pdf->beginPage(width, height, &rect);
45+
ctx->path = new SkPath();
46+
ctx->state = create_default_state();
47+
ctx->states = std::vector<sk_context_state>();
48+
return ctx;
49+
}
50+
51+
void sk_pdf_end_page(sk_pdf_document* doc) {
52+
doc->pdf->endPage();
53+
}
54+
55+
int sk_pdf_write_file(sk_pdf_document* doc, char* path) {
56+
doc->pdf->close();
57+
SkFILEWStream stream(path);
58+
return doc->stream->writeToStream(&stream);
59+
}
60+
61+
SkData* sk_pdf_get_buffer(sk_pdf_document* doc, void** buffer, unsigned int* size) {
62+
doc->pdf->close();
63+
auto data = doc->stream->detachAsData().release();
64+
*buffer = (void*) data->data();
65+
*size = data->size();
66+
return data;
67+
}
68+
69+
void sk_pdf_destroy(sk_pdf_document* doc) {
70+
delete doc->stream;
71+
doc->pdf->unref();
72+
delete doc;
73+
}
74+
}

native/src/svgcanvas.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include "include/svgcanvas.hpp"
2+
3+
extern "C" {
4+
SKIA_EXPORT sk_svg* sk_svg_new(int width, int height, int flags) {
5+
sk_svg* svg = new sk_svg();
6+
svg->stream = new SkDynamicMemoryWStream();
7+
svg->canvas = SkSVGCanvas::Make(SkRect::MakeWH(width, height), svg->stream, flags).release();
8+
if (svg->canvas == nullptr) {
9+
delete svg;
10+
return nullptr;
11+
}
12+
return svg;
13+
}
14+
15+
SKIA_EXPORT void sk_svg_destroy(sk_svg* svg) {
16+
delete svg->canvas;
17+
delete svg->stream;
18+
delete svg;
19+
}
20+
21+
SKIA_EXPORT sk_context* sk_svg_get_context(sk_svg* svg) {
22+
sk_context* ctx = new sk_context();
23+
ctx->canvas = svg->canvas;
24+
ctx->path = new SkPath();
25+
ctx->state = create_default_state();
26+
ctx->states = std::vector<sk_context_state>();
27+
return ctx;
28+
}
29+
30+
SKIA_EXPORT int sk_svg_write_file(sk_svg* svg, char* path) {
31+
SkFILEWStream file(path);
32+
return svg->stream->writeToStream(&file);
33+
}
34+
35+
SKIA_EXPORT SkData* sk_svg_get_buffer(sk_svg* svg, void** buffer, unsigned int* size) {
36+
SkData* data = svg->stream->detachAsData().release();
37+
*buffer = data->writable_data();
38+
*size = data->size();
39+
return data;
40+
}
41+
}

src/canvas.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const {
99
sk_canvas_read_pixels,
1010
sk_canvas_encode_image,
1111
sk_data_free,
12+
sk_canvas_get_context,
1213
} = ffi;
1314

1415
const CANVAS_FINALIZER = new FinalizationRegistry((ptr: Deno.PointerValue) => {
@@ -148,8 +149,10 @@ export class Canvas {
148149
getContext(type: "2d"): CanvasRenderingContext2D;
149150
getContext(type: string): CanvasRenderingContext2D | null {
150151
switch (type) {
151-
case "2d":
152-
return new CanvasRenderingContext2D(this);
152+
case "2d": {
153+
const ptr = sk_canvas_get_context(this.#ptr);
154+
return new CanvasRenderingContext2D(this, ptr);
155+
}
153156
default:
154157
return null;
155158
}

src/context2d.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
} from "./pattern.ts";
1414

1515
const {
16-
sk_canvas_get_context,
1716
sk_context_destroy,
1817
sk_context_clear_rect,
1918
sk_context_set_fill_style,
@@ -244,9 +243,9 @@ export class CanvasRenderingContext2D {
244243
return this.#ptr;
245244
}
246245

247-
constructor(canvas: Canvas) {
246+
constructor(canvas: Canvas, ptr: Deno.PointerValue) {
248247
this.#canvas = canvas;
249-
this.#ptr = sk_canvas_get_context(canvas._unsafePointer);
248+
this.#ptr = ptr;
250249
if (this.#ptr === 0) {
251250
throw new Error("Failed to create context");
252251
}
@@ -995,6 +994,9 @@ export class CanvasRenderingContext2D {
995994
}
996995

997996
getImageData(sx: number, sy: number, sw: number, sh: number) {
997+
if (!(this.#canvas instanceof Canvas)) {
998+
throw new Error("getImageData is only supported on Canvas");
999+
}
9981000
const data = new Uint8Array(sw * sh * 4);
9991001
this.#canvas.readPixels(sx, sy, sh, sh, data, "srgb");
10001002
return new ImageData(data, sw, sh);

0 commit comments

Comments
 (0)